using System; using System.Collections.Generic; using System.Text; using AyaNova.PlugIn;//Required Plugin interface definition using GZTW.AyaNova.BLL;//Required to interact with the business object library //Required for icon and image handling even if you don't use them using System.Windows.Forms;//Required only if you want a Windows Forms UI for your plugin namespace CSSamplePlugin { /// /// This is an example to show the minimal required code to implement a plugin /// with a UI /// /// Your class must implement IAyaNovaPlugin defined in AyaNova.PlugIn.dll /// /// References that were added /// -------------------------- /// From the AyaNova program file directory: /// AyaNova.PlugIn.dll - Required plugin interface definition /// GZTW.AyaNova.BLL.dll - Required AyaNova business object library fully documented here: http://api.ayanova.com/ /// CSLA - required by the business object library /// CSLA.Core.Bindablebase- required by the business object library /// CSLA.Server.DataPortal- required by the business object library /// CSLA.Server.ServicedDataPortal- required by the business object library /// /// System.Windows.Forms - Required only if your plugin requires a windows user interface /// -------------------------- /// /// Distributing your plugin /// =-=-=-=-=-=-=-=-=-=-=-=- /// Note that *none* of the above referenced assemblies need to be included with your plugin when it is distributed /// as, at runtime, your plugin will use the assemblies installed with AyaNova. /// /// So, for example, this sample plugin will generate a file called CSSamplePlugin.dll. /// To use it in AyaNova, copy that single file anywhere in the plugins folder or in a subdirectory beneath (recommended) /// in the AyaNova program files folder. /// /// AyaNova will look for any files in the plugins folder and subfolders that end in .dll and check if they implement IAyaNovaPlugin /// /// If your plugin needs to persist data please note that the AyaNova business object library contains three objects for exactly that purpose /// you can use the "Integration" object to store overall data, you can use the IntegrationMaps object to map data between an external programs database /// and specific AyaNova objects and the IntegrationLog object is provided for logging purposes. /// /// public class Class1 : IAyaNovaPlugin { //Note: In Visual Studio, if you right click on IAyaNovaPlugin in the class declaration you can select Implement Interface and //all the stubs will be created for you of the entire interface, no need to type them in or copy and paste #region IAyaNovaPlugin Members #region Properties / general //OPTIONAL: Currently unused in AyaNova UI but may be in future //so you really should return a string here public string About { get { return "My plugin, copyright my company 2009 etc etc"; } } /// /// REQUIRED: This must be a unique Guid value and is required. /// /// Normally you would not change this value even upon new releases of your /// plugin, it's simply used to uniquely identify the plugin during runtime by /// AyaNova. /// /// (do not use Guid.Empty and don't use the sample value provided here /// that's just asking for trouble :) ) /// public Guid PluginID { get { return new Guid("{5B1D1F74-04E3-464a-88DA-FA9E207EB2A7}"); } } /// /// REQUIRED: Will be displayed in various areas but most importantly /// it's used to display the menu item in the root level Plugin menu /// for activating your plugin /// public string PluginName { get { return "My Plugin"; } } /// /// REQUIRED: Your plugin's version as a string /// for display only /// public string PluginVersion { get { return "1.0alpha"; } } /// /// OPTIONAL: 32px icon that will be displayed beside the plugin name /// on the root level plugin menu if the AyaNova User has chosen Large /// icons on menus /// public System.Drawing.Image PluginLargeIcon { //since this is meant to be a simple example //we'll return null, but generally speaking you would //add a resource to your plugin and embed your icons inside it //and return them here like: return Resource.MyIcon; get { return null; } } /// /// OPTIONAL: 16px icon that will be displayed beside the plugin name /// on the root level plugin menu if the AyaNova User has chosen Small /// icons on menus /// public System.Drawing.Image PluginSmallIcon { get { return null; } } /// /// OPTIONAL: This will be set by AyaNova when the plugin is initialized /// the resource manager contains the same icons and images used /// in AyaNova itself and is useful for consistency if you want /// your plugin's GUI to appear more integrated with AyaNova /// public System.Resources.ResourceManager AyaNovaResourceManager { //Since this is a simple example, we'll ignore it when set. //However if you wish to use it //you can set a class variable (for example "resman") of ResourceManger to the value passed in here //and get resources like this: //Image i=(Image)resman.GetObject("ServiceWorkorder24"); //or //Icon i=(Icon)resman.GetObject("Client16icon"); set { ; } } #endregion #region Initialize and close //this is a convenient way to deal with supported object types private static List ObjectsWeCanDealWith = null; /// /// OPTIONAL: you don't need to do anything here, but it's a good idea. /// /// This is called immediately after login and is the first opportunity your plugin gets access to the business object library /// to determine if it's prepared to work with the current AyaNova user / database / conditions /// it finds itself in. /// /// Note that this is called for all plugins found, be a good citizen and don't consume a lot of time here /// as it will block AyaNova between the moment the user has clicked login and they get the opening screen. /// /// Instead you should do "lazy" initialization; as late as possible, ideally only just in time to perform a user selected command /// and cache your intialization when it's done. /// /// If you are familiar with using the AyaNova business object library you can treat a plugin as /// all the code that takes place immediately after a user has initialized the AyaNova connection and logged in successfully. /// /// /// The version of AyaNova calling /// A localized text object if your plugin wants to /// use the same localized text as AyaNova itself /// False if you don't want your plugin to be accessible, true if you do public bool Initialize(Version AyaNovaVersion, GZTW.AyaNova.BLL.LocalizedTextTable localizedText) { //This is a good place to check if the version of AyaNova being used is one you want your plugin to work //with: //if (AyaNovaVersion.Major != 5) //{ // MessageBox.Show("My Plugin requires AyaNova version 5"); // return false; //} //or that the current user has sufficent rights to even use your plugin //if(AyaBizUtils.Right(RootObjectTypes.Client)< (int)SecurityLevelTypes.ReadWrite) return false; //or that the user is the right type to use your plugin //if(!User.IsAdmin) return false; //or that the environment your plugin finds itself in is suitable //or that there is a license for your plugin if it's licensed //etc //This is also an excellent time to build a list of AyaNova RootObjectTypes your plugin supports: //remember: Initialize might be called more than once if a user logs in and out if (ObjectsWeCanDealWith == null) ObjectsWeCanDealWith = new List(); if (ObjectsWeCanDealWith.Count == 0) { //AyaNova asks if a plugin can deal with the type Nothing //when it's about to display the Plugins menu option in the main AyaNova screen //This is useful for plugins that have commands that are not specific to a particular //type of object such as an About dialog or a general setup form or a utility that //acts in general on multiple AyaNova objects //for this example we'll have an About dialog that we want to display from the main AyaNova form ObjectsWeCanDealWith.Add(RootObjectTypes.Nothing); //For this example we want to deal with Client objects ObjectsWeCanDealWith.Add(RootObjectTypes.Client); } return true; } /// /// OPTIONAL: This is called after a user has just logged out of AyaNova. /// Note that this is often when they are closing AyaNova, but not necessarily, they may /// have logged out so another user can login. /// /// This is where you can release resources that are user specific if you have any. /// /// public void Close() { ; } #endregion #region Whether to particpate in a particular scenario //Note: these methods exist for the purposes of lazy initialization //just because your plugin can deal with a particular type of object //doesn't mean you have to necessarily do a time consuming startup for your //plugin yet because the user may not select your plugin from the plugin list //(99.9% of the time they are just opening a form to work in AyaNova) /// /// This is called by AyaNova when a single object is about to be opened in AyaNova /// Here is where you decide if you support that type of object /// or not. /// /// /// The RootObjectTypes AyaNova object type /// true - display this plugin in the plugins menu, false - don't display this plugin as an option public bool SingleObjectMenuShow(GZTW.AyaNova.BLL.RootObjectTypes objectType) { //You could have a giant switch statement here but it's easier to just check a collection return ObjectsWeCanDealWith.Contains(objectType); } /// /// This is called by AyaNova when a list object is about to be opened in AyaNova /// generally in a grid. /// /// Here is where you decide if you support that type of object /// or not in multiples. /// /// /// The RootObjectTypes AyaNova object type /// true - display this plugin in the plugins menu, false - don't display this plugin as an option public bool MultipleObjectsMenuShow(GZTW.AyaNova.BLL.RootObjectTypes objectType) { //for this example we'll deal with a selected list of client objects //from the Clients grid display return ObjectsWeCanDealWith.Contains(objectType); } #endregion #region What options to display //These methods are called when a user selects your plugin from the plugin menu //they are used to build the popup menu of options your plugin supports //If possible you should still defer initialization if it's time consuming //even at this point if possible because the user may not actually select an option //they may have just clicked on it in error or to see what's offered /// /// Here is where you provide a list of commands your plugin supports for the object type /// (and possibly even the exact object) in question. /// /// The items you provide here will be displayed to the end user in a popup menu list immediately after /// they have selected your plugin from the root plugins menu in a form in AyaNova where a single object /// is being viewed / edited /// /// RootObjectType /// A generic list of a type defined in AyaNova.PlugIn /// public List SingleObjectMenuOptions(GZTW.AyaNova.BLL.RootObjectTypes objectType, object ayaNovaObject) { //First off we can double check that this is an object type we support: if (!ObjectsWeCanDealWith.Contains(objectType)) return null; //Now we build the list: //AyaNovaPluginMenuItem is a structure defined in AyaNova.PlugIn assembly //and is the mechanism to convey your menu options to AyaNova so it //can use them to build a popup menu //Initialize a list of potential menu items List list = new List(); //Add items to the list based on the object type switch (objectType) { case RootObjectTypes.Nothing://Our main menu about box list.Add(new AyaNovaPluginMenuItem("ABOUT", "About MyPlugin", null,null)); break; case RootObjectTypes.Client://Our command when in a single client editing form list.Add(new AyaNovaPluginMenuItem("CLIENT_DO_SOMETHING", "Do something with this client", null, null)); break; } return list; } /// /// Same as single item, but the menu above a grid or list of AyaNova objects of the same type /// If your plugin can't deal with a list of items then return null; /// /// /// public List MultipleObjectsMenuOptions(GZTW.AyaNova.BLL.RootObjectTypes objectType) { //First off we can double check that this is an object type we support: if (!ObjectsWeCanDealWith.Contains(objectType)) return null; //Initialize a list of potential menu items List list = new List(); //Add items to the list based on the object type switch (objectType) { case RootObjectTypes.Client://Our command when in a list of clients list.Add(new AyaNovaPluginMenuItem("CLIENT_DO_SOMETHING", "Do something else with the selected Clients", null, null)); break; } return list; } #endregion #region Execute the chosen command //These methods are called when a user actually clicks on a command for your plugin from the popup menu //This is the ideal place to do time consuming initialization if necessary and cache it for later //because this is the first point you know the user actually needs to use your plugin /// /// A command was selected for a single object /// /// command key you provided when you built the menu options list /// the type of the object /// a pointer to the live object being edited or displayed public void CommandSelectedForSingleObject(string commandKey, GZTW.AyaNova.BLL.RootObjectTypes objectType, object ayaNovaObject) { //Since we have used unique commands we don't need to double check the //object type here switch (commandKey) { case "ABOUT": AboutBox1 dlgAbout = new AboutBox1(); dlgAbout.ShowDialog(); break; case "CLIENT_DO_SOMETHING": //We want to do something with the client being edited //we have the object in ayaNovaObject so we just need to cast it to //the type of object we expect. //let's do it defensively though; who knows what those crazy AyaNova programmers might have passed to us ;) ... //Is it null for some reason? if (ayaNovaObject == null) return;//Yes so ignore the command //Is it not the type of object we expected? if (!(ayaNovaObject is GZTW.AyaNova.BLL.Client)) return; //Ok, seems safe to deal with so let's get a reference to it we can work with //directly: GZTW.AyaNova.BLL.Client c = (GZTW.AyaNova.BLL.Client)ayaNovaObject; //Now we can operate on it using any of the Client object method's and properties //in the AyaNova business object API (http://api.ayanova.com/) c.Notes = c.Notes + "\r\nHello " + c.Name + " from " + PluginName + " @ " + DateTime.Now.ToString(); //You will notice that after your plugin exits the client's "General Notes" are immediately updated //in the AyaNova user interface, this is because your plugin is working with the live object //that is bound to the AyaNova edit form controls so changes are immediate. //NOTE: do not Save or Update a business object you modify here. Leave the regular AyaNova UI to deal with that //properly. break; } } /// /// A command was selected for a list of objects /// /// Your plugins command key from the menu item /// The RootObjectTypes object type /// A list of Guid's of the AyaNova object type selected by the user. May be empty or null or zero selected. /// The unederlying AyaNova List object that is being displayed to the user from which they made their selections /// true if you want to trigger a refresh of the display of the list in AyaNova, false if not necessary (i.e. you didn't modify any of the objects displayed) public bool CommandSelectedForList(string commandKey, GZTW.AyaNova.BLL.RootObjectTypes objectType, List objectIDList, object listObject) { //We only have one command that could display for a list but we'll leave room for expansion later: switch (commandKey) { case "CLIENT_DO_SOMETHING": //We want to do something with all the clients that were selected from the client list //We let's see if any are selected first if (objectIDList == null || objectIDList.Count == 0) { MessageBox.Show("Nothing to do, you didn't select any clients."); return false; } //Ok, we now know that 1 or more clients are selected and we have a list of their ID's //so let's do something (non destructive) with them System.Text.StringBuilder sb = new StringBuilder(); sb.Append("Selected clients website and email address\r\n"); foreach (Guid id in objectIDList) { //You don't want your plugin to crash right? //use appropriate exception handling try { Client c = Client.GetItem(id); sb.Append(c.Name); sb.Append(" Email: "); sb.Append(c.Email); sb.Append(" Website: "); sb.Append(c.WebAddress); sb.Append("\r\n"); } catch (Exception ex) { sb.Append("Client ID: "); sb.Append(id.ToString()); sb.Append(" Error: "); sb.Append(ex.Message); sb.Append("\r\n"); } } MessageBox.Show(sb.ToString()); break; } return false; } #endregion #endregion } }