What's new

Add on Testing

KageDev

Member
What are everybody's preferred way to test their add-on progress. I am currently using a symbolic link to reference my build output directly to the add-on folder and have no issues when creating a new part to see my progress. The one issue I am having is returning to a part I created and having my add-on grayed out. I'm not sure if this is due to my code or if it is because I am checking it out from M-Files but I seem to be missing something for my add-on to be enabled again.
I used Bolsover's Adventures as a reference. It has been great so far! Just this one small hiccup.
Here is my add-on code so far.

C#:
using AlibreAddOn;
using AlibreX;
using System;
using System.Windows;

namespace KageInnovation
{
    public class CADPackAutonesting : IAlibreAddOn
    {
        private const int MenuIdRoot = 402;
    
        private IADRoot _alibreRoot;
        private IntPtr _parentWinHandle;
        public CADPackAutonesting(IADRoot alibreRoot, IntPtr parentWinHandle)
        {
            this._alibreRoot = alibreRoot;
            this._parentWinHandle = parentWinHandle;
        }

        public int RootMenuItem => MenuIdRoot;

        public bool HasPersistentDataToSave(string sessionIdentifier)
        {
            return false;
        }

        public bool HasSubMenus(int menuID)
        {
            return false;
        }

        public IAlibreAddOnCommand InvokeCommand(int menuID, string sessionIdentifier)
        {
            var session = _alibreRoot.Sessions.Item(sessionIdentifier);
            MessageBox.Show(session.Name);
            return null;
        }

        public void LoadData(IStream pCustomData, string sessionIdentifier)
        {
        }

        public string MenuIcon(int menuID)
        {
            return string.Empty;
        }

        public ADDONMenuStates MenuItemState(int menuId, string sessionIdentifier)
        {
            var session = _alibreRoot.Sessions.Item(sessionIdentifier);

            switch (session)
            {
                case IADDrawingSession:
                    switch (menuId)
                    {
                        case MenuIdRoot: return ADDONMenuStates.ADDON_MENU_ENABLED;

                    }
                    break;

                case IADAssemblySession:
                    switch (menuId)
                    {
                        case MenuIdRoot: return ADDONMenuStates.ADDON_MENU_ENABLED;

                    }

                    break;
                case IADPartSession:
                    switch (menuId)
                    {
                        case MenuIdRoot: return ADDONMenuStates.ADDON_MENU_ENABLED;

                    }

                    break;
            }

            return ADDONMenuStates.ADDON_MENU_ENABLED;
        }

        public string MenuItemText(int menuID)
        {
            return "Autonest";
        }

        public string MenuItemToolTip(int menuID)
        {
            return "";
        }

        public bool PopupMenu(int menuID)
        {
            return false;
        }

        public void SaveData(IStream pCustomData, string sessionIdentifier)
        {
        }

        public void setIsAddOnLicensed(bool isLicensed)
        {
        }

        public Array SubMenuItems(int menuID)
        {
            return null;
        }

        public bool UseDedicatedRibbonTab()
        {
            return false;
        }
    }
}
 

stepalibre

Alibre Super User
The one issue I am having is returning to a part I created and having my add-on grayed out.

You can remove the switch statements to debug your code better. You don't need to follow the switch statement pattern you can implement your own code to determine what your menus should do in the different sessions.

Try using a dedicated ribbon tab and/or change the menuId.

I can only guess that code related to M-Files is changing the sessionIdentifier, confusing your addon defaulting to ADDON_MENU_GRAYED or there's some other conflicting code.

You can deactivate and reactivate your addon to troubleshoot.

1702571243107.png

I'm not familiar with how M-Files is integrated so more info would help.
 

KageDev

Member
I'm not familiar with how M-Files is integrated so more info would help.

I am opening part assemblies directly from M-Files. It seems the only time my add-on is active is when I create a new project. Below the switch statement I have it returning enable anyway. I added it to see if it would do anything since just having the return statement kept it grayed out.

Try using a dedicated ribbon tab and/or change the menuId.
This is something I feel I don't fully understand with the the menuID's. Is there specific ones I need to use or can it be anything? If I decide to to a dedicated ribbon tab, how can I have it invoke what I want my add-on to do instead of dropping down an options tab?

Edit: After trying to disable and re-enable my add-on I get this error:

An unexpected error has occured. Please try again. If the problem persists contact Alibre Customer Support and provide the following information:

Object reference not set to an instance of an object.

at com.objectspace.jgl.HashMap.get(Object key)
at com.alibre.ui.ToolbarContainerManager.clearAddOnMenus()
at com.alibre.design.app.DesignEditor.rebuildAddOnMenus()
at com.alibre.app.ClientShell.rebuildAddOnMenus()
at com.alibre.addon.ui.AddOnPage.AddOnPageDialogResultHandler.onOk()
at com.alibre.ui.StandardBaseDialog.showDialog(IWin32Window owner, DialogResultHandler handler)
at com.alibre.addon.ui.AddOnPage.show(Form owner)
at com.alibre.ui.BrowserCommandFactory.OpenAddOnManagerCommand.execute()

Thanks!
 
Last edited:

stepalibre

Alibre Super User
If you can share a copy of your project I can help troubleshoot everything minus the M-Files part.

I am opening part assemblies directly from M-Files. It seems the only time my add-on is active is when I create a new project. Below the switch statement I have it returning enable anyway. I added it to see if it would do anything since just having the return statement kept it grayed out.

Is M-Files an Addon now or an external application independent of Alibre? I had M-Files with my first license of Expert before Geomagic Design (I think) but don't remember how it was integrated.

I would rewrite MenuItemState() and go from there. It might be an internal session ID change from M-Files affecting your addon, an unhandled condition, or some other state/id issue.

This is something I feel I don't fully understand with the the menuID's. Is there specific ones I need to use or can it be anything?

I believe they're just integers that should be unique in your addon. In my addons I use them as pointers and I think that is how they should be thought of. Other APIs I use handle menuids internally or via a higher level API. Alibre don't provide an easier API for building menus or anything we have to do it oursleves.

Here is my menu manager build menus method.

Code:
        Private Sub BuildMenus()
            Dim groupA As New MenuItem(501, "Group A", "Group A")
            groupA.AddSubItem(New MenuItem(1001, "Item A1", "Description A1", "logo.ico", AddressOf groupA.FileMenuCmdA))
            groupA.AddSubItem(New MenuItem(1002, "Item A2", "Description A2", "logo_imgui_bundle.ico", AddressOf groupA.FileMenuCmdA))
            Dim groupB As New MenuItem(502, "Group B", "Group B")
            groupB.AddSubItem(New MenuItem(1003, "Item A3", "Description A3", "logo.ico", AddressOf groupB.FileMenuCmdA))
            groupB.AddSubItem(New MenuItem(1004, "Item A4", "Description A4", "favicon2.ico", AddressOf groupB.FileMenuCmdA))
            Dim groupC As New MenuItem(503, "Group C", "Group C")
            groupC.AddSubItem(New MenuItem(1005, "Item A5", "Description A5", "favicon.ico", AddressOf groupCBtn1))
            groupC.AddSubItem(New MenuItem(1006, "Item A6", "Description A6", "logo.ico", AddressOf groupCBtn2))
            _rootMenuItem.AddSubItem(groupA)
            _rootMenuItem.AddSubItem(groupB)
            _rootMenuItem.AddSubItem(groupC)
            RegisterMenuItem(_rootMenuItem)
        End Sub

You can implement your own logic to handle menus and commands. I share code across addons and commands so I have a layer on top to manage menuIds and related. I also use ribbon groups to group different tools on the ribbon.

If I decide to to a dedicated ribbon tab, how can I have it invoke what I want my add-on to do instead of dropping down an options tab?

C#:
public bool UseDedicatedRibbonTab()
 {
     return true;
 }

The above code should move you addon to it's own tab and everything else should work the same.

Try to use my example LauncherAddon.cs and see if there is a change.


The output should be this and it should stay ADDONMenuStates.ADDON_MENU_ENABLED if return ADDONMenuStates.ADDON_MENU_ENABLED:

1702577997131.png

Keep in mind the code on github and the forum are only examples and might not meet your needs. My menu manager is more thoughtful and I have other classes to handle and check things that is needed for my use case.
 

stepalibre

Alibre Super User
Edit: After trying to disable and re-enable my add-on I get this error:

An unexpected error has occured. Please try again. If the problem persists contact Alibre Customer Support and provide the following information:

Object reference not set to an instance of an object.

at com.objectspace.jgl.HashMap.get(Object key)
at com.alibre.ui.ToolbarContainerManager.clearAddOnMenus()
at com.alibre.design.app.DesignEditor.rebuildAddOnMenus()
at com.alibre.app.ClientShell.rebuildAddOnMenus()
at com.alibre.addon.ui.AddOnPage.AddOnPageDialogResultHandler.onOk()
at com.alibre.ui.StandardBaseDialog.showDialog(IWin32Window owner, DialogResultHandler handler)
at com.alibre.addon.ui.AddOnPage.show(Form owner)
at com.alibre.ui.BrowserCommandFactory.OpenAddOnManagerCommand.execute()
Check AlibreAddOn class and review Bolsover and my example addons.

You should be able to safely activate and deactivate addons.

What version of Alibre are you running? If Not Alibre Design 27.0.0.27038 then the code might not be compatible.
 

stepalibre

Alibre Super User
Managing IDs can be cumbersome. You can create a class to keep them organized in one place.

C#:
static class IDs
{
    // RHINO:
    public const int RhinoGroupHeader = 800;
    public const int StartRhino = 801;
    public const int KillRhino = 802;
    public const int BringRhinoToFront = 803;
    // LINQPAD:
    public const int LINQPadGroupHeader = 3000;
    public const int StartLINQPad = 3001;
    public const int KillLINQPad = 3002;
    public const int BringLINQPadToFront = 3003;
    // HEADERS:
    public const int AlibreAddOnForTestbed_GrpHeader_0 = 6000; // Group A
    public const int AlibreAddOnForTestbed_GrpHeader_1 = 6001; // Group C
    public const int AlibreAddOnForTestbed_GrpHeader_2 = 6002; // Group D
    public const int AlibreAddOnForTestbed_GrpHeader_3 = 6003;
    public const int AlibreAddOnForTestbed_GrpHeader_4 = 6004;
    public const int AlibreAddOnForTestbed_GrpHeader_5 = 6005;
    public const int AlibreAddOnForTestbed_GrpHeader_6 = 6006;
    public const int AlibreAddOnForTestbed_GrpHeader_7 = 6007;
    public const int AlibreAddOnForTestbed_GrpHeader_8 = 6008;
    public const int AlibreAddOnForTestbed_GrpHeader_9 = 6009;
    public const int AlibreAddOnForTestbed_GrpHeader_10 = 6010;
    // COMMANDS:
    public const int AlibreAddOnForTestbed_Cmd_0 = 5000; // Group A
    public const int AlibreAddOnForTestbed_Cmd_1 = 5001; // Group A
    public const int AlibreAddOnForTestbed_Cmd_2 = 5002;
    public const int AlibreAddOnForTestbed_Cmd_3 = 5003;
    public const int AlibreAddOnForTestbed_Cmd_4 = 5004;
    public const int AlibreAddOnForTestbed_Cmd_5 = 5005;
    public const int AlibreAddOnForTestbed_Cmd_6 = 5006;
    public const int AlibreAddOnForTestbed_Cmd_7 = 5007;
    public const int AlibreAddOnForTestbed_Cmd_8 = 5008;
    public const int AlibreAddOnForTestbed_Cmd_9 = 5009;
    public const int AlibreAddOnForTestbed_Cmd_10 = 5010;
    public const int AlibreAddOnForTestbed_Cmd_11 = 5011;
    public const int AlibreAddOnForTestbed_Cmd_12 = 5012;
    public const int AlibreAddOnForTestbed_Cmd_13 = 5013;
    public const int AlibreAddOnForTestbed_Cmd_14 = 5014;
    public const int AlibreAddOnForTestbed_Cmd_15 = 5015;
    public const int AlibreAddOnForTestbed_Cmd_16 = 5016;
    public const int AlibreAddOnForTestbed_Cmd_17 = 5017;
    public const int AlibreAddOnForTestbed_Cmd_18 = 5018;
    public const int AlibreAddOnForTestbed_Cmd_19 = 5019;
    public const int AlibreAddOnForTestbed_Cmd_20 = 5020;
}
 
Top