A Plugin interface is an easy way to allow you to add your own extensions.
We have extended the Plugin with yet another interface to facilitate the addition of custom OCL operations. This way, the design time functions like CheckModel, ViewModels, and OclEditor can be made to recognize your custom operations.
namespace Modlr.Plugins { public interface IModlrPlugin { string GetName(); List<IModlrPluginMenuOperation> ProvideOperations(); } public interface IModlrPluginMenuOperation { string GetName(); void CheckEnableOrExecute(IEcoServiceProvider esp, bool execute, IEcoObject maincontext, IEcoObject subcontext,out bool enabled ); } public enum CallbackEventKind {CodeGen,ForcedCodeGen }; public interface IModlrPluginImportantEventCallbackHandler { void ImportantEventAboutToHappen(IEcoServiceProvider esp, CallbackEventKind eventkind, ref bool stop, ref string message); void ImportantEventHasHappend(IEcoServiceProvider esp, CallbackEventKind eventkind); } public interface IModlrPluginModelAccessOclType { /// <summary> /// Possible usage - add custom ocl operations that can then be correctly executed by WECPOF and correctly evaluated in OCL design time /// </summary> void RuntimeModelAccess(IOclTypeService ocl); } }
I added an example in the demos folder called ModlrPluginCodeGenEventsAndCustomOCLOperations.
I'm not going to repeat everything here, but a few key things to note:
namespace ModlrPluginCodeGenEventsAndCustomOCLOperations { public class Plugindemo : IModlrPlugin, IModlrPluginMenuOperation, IModlrPluginModelAccessOclType, IModlrPluginImportantEventCallbackHandler { public string GetName() { return "AnotherPlugin"; }
The IModlrPluginImportantEventCallback can do things on Codegen>
public void ImportantEventAboutToHappen(Eco.ObjectRepresentation.IEcoServiceProvider esp, CallbackEventKind eventkind, ref bool stop, ref string message) { // Here you can perform checks before codegen, and optionally stop the codegen System.Windows.Forms.MessageBox.Show("You are updating the code, this annoying message came from plugin ModlrPluginCodeGenEventsAndCustomOCLOperations"); }
The brand new interface is the IModlrPluginModelAccessOclType>
public void RuntimeModelAccess(IOclTypeService ocl) { ocl.InstallOperation(new CustomOCL_SplitAtSemi()); }
And the operation (really a different subject) looks like this:
public class CustomOCL_SplitAtSemi : OclOperationBase { public CustomOCL_SplitAtSemi() { } protected override void Init() { InternalInit("SplitAtSemi", new IOclType[] { Support.StringType }, Support.StringType); } public override void Evaluate(IOclOperationParameters __Params) { string s = Support.GetAsString(__Params.Values[0]); string[] ss=s.Split(';'); string first = ""; if (ss.Length > 0) first = ss[0]; Support.MakeNewString(__Params.Result, first); } }
This is exciting because my model validates in design time even if I use the custom operation:
ViewModel columns that use the custom expression are evaluated correctly:
CheckModel stays empty since everything is validated:
And of course, the prototyping actually executes your operations:
Modlr plugins
We added a plugin interface for Gaffr and ECO. We want to enable you to extend Modlr so that you can implement a special file format import or export, or do something other than that.
This is how it works.
Given these two interfaces:
namespace Modlr.Plugins { Public Interface IModlrPlugin { string GetName(); List<IModlrPluginMenuOperation> ProvideOperations(); } Public Interface IModlrPluginMenuOperation { string GetName(); void CheckEnableOrExecute(IEcoServiceProvider esp, bool execute, } }
You can implement a plugin in an assembly like this:
public class Class1 : IModlrPlugin { #region IModlrPlugin Members public string GetName() { return "Demo plugin"; } public List<IModlrPluginMenuOperation> ProvideOperations() { List<IModlrPluginMenuOperation> ops = new List<IModlrPluginMenuOperation>(); ops.Add(new OperationShowDialog()); ops.Add(new OperationActOnClass()); return ops; } #endregion }
The code above installs two Operations: OperationShowDialog and OperationActOnClass.
Looking closely at the operation ActOnClass:
public class OperationActOnClass : IModlrPluginMenuOperation { #region IModlrPluginMenuAction Members public void CheckEnableOrExecute(IEcoServiceProvider esp, { enabled = false; if (maincontext != null && maincontext.AsIObject().AsObject is Eco.ModelLayer.Class) { enabled = true; if (execute) { (maincontext.AsIObject().AsObject as Eco.ModelLayer.Class).Name += "X"; } } } public string GetName() { return "Operation on class"; } #endregion }
The code checks that the context is a class, and if it is, the code says that the operation should be enabled. If this was an “execute” call, we would perform the desired logic – in this case, I just add an “X” to the back of the class name.
You can do a lot of stuff in a plugin.
- You get access to the IEcoServerProvider for the EcoModelLayer. The Modlr application is a standard ECO-built application.
- You can use the IOCLService to get to any object of any class that builds up your model content.
- You can access Diagrams, PlacedClasses, StateMachines, etc.
- You can inspect and set TaggedValues.
- You can run through every Attribute and check for spelling errors.
- You can create reports that you share with other ECO/Gaffr users…
Even though the interface is very small and simple, it is very powerful.
When you build your Plugin, you will want to reference the following assemblies (found in the ECO or GAFFR install directory):
Compile your plugin and put the assembly in the folder %ProgramData%/CapableObjects/Plugins
Restart Gaffr.net or VisualStudio. You will find your plugin operations in the context menu:
Simple and powerful.