471 lines
22 KiB
C#
471 lines
22 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// 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.
|
|
///
|
|
/// </summary>
|
|
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"; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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 :) )
|
|
/// </summary>
|
|
public Guid PluginID
|
|
{
|
|
get { return new Guid("{5B1D1F74-04E3-464a-88DA-FA9E207EB2A7}"); }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public string PluginName
|
|
{
|
|
get { return "My Plugin"; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// REQUIRED: Your plugin's version as a string
|
|
/// for display only
|
|
/// </summary>
|
|
public string PluginVersion
|
|
{
|
|
get { return "1.0alpha"; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
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; }
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
public System.Drawing.Image PluginSmallIcon
|
|
{
|
|
get { return null; }
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
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<RootObjectTypes> ObjectsWeCanDealWith = null;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="AyaNovaVersion">The version of AyaNova calling</param>
|
|
/// <param name="localizedText">A localized text object if your plugin wants to
|
|
/// use the same localized text as AyaNova itself</param>
|
|
/// <returns>False if you don't want your plugin to be accessible, true if you do</returns>
|
|
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<RootObjectTypes>();
|
|
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
///
|
|
/// </summary>
|
|
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)
|
|
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="objectType">The RootObjectTypes AyaNova object type</param>
|
|
/// <returns>true - display this plugin in the plugins menu, false - don't display this plugin as an option</returns>
|
|
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);
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
///
|
|
/// </summary>
|
|
/// <param name="objectType">The RootObjectTypes AyaNova object type</param>
|
|
/// <returns>true - display this plugin in the plugins menu, false - don't display this plugin as an option</returns>
|
|
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
|
|
|
|
/// <summary>
|
|
/// 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
|
|
/// </summary>
|
|
/// <param name="objectType">RootObjectType</param>
|
|
/// <param name="ayaNovaObject">A generic list of a type defined in AyaNova.PlugIn</param>
|
|
/// <returns></returns>
|
|
public List<AyaNovaPluginMenuItem> 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<AyaNovaPluginMenuItem> list = new List<AyaNovaPluginMenuItem>();
|
|
|
|
//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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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;
|
|
/// </summary>
|
|
/// <param name="objectType"></param>
|
|
/// <returns></returns>
|
|
public List<AyaNovaPluginMenuItem> 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<AyaNovaPluginMenuItem> list = new List<AyaNovaPluginMenuItem>();
|
|
|
|
//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
|
|
|
|
/// <summary>
|
|
/// A command was selected for a single object
|
|
/// </summary>
|
|
/// <param name="commandKey">command key you provided when you built the menu options list</param>
|
|
/// <param name="objectType">the type of the object</param>
|
|
/// <param name="ayaNovaObject">a pointer to the live object being edited or displayed</param>
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// A command was selected for a list of objects
|
|
/// </summary>
|
|
/// <param name="commandKey">Your plugins command key from the menu item</param>
|
|
/// <param name="objectType">The RootObjectTypes object type</param>
|
|
/// <param name="objectIDList">A list of Guid's of the AyaNova object type selected by the user. May be empty or null or zero selected.</param>
|
|
/// <param name="listObject">The unederlying AyaNova List object that is being displayed to the user from which they made their selections</param>
|
|
/// <returns>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)</returns>
|
|
public bool CommandSelectedForList(string commandKey, GZTW.AyaNova.BLL.RootObjectTypes objectType, List<Guid> 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
|
|
}
|
|
}
|