Skip to content
This repository has been archived by the owner on Jun 2, 2022. It is now read-only.

AddingCommandsAndMenus

Steven T. Cramer edited this page Jul 6, 2015 · 10 revisions

Adding Commands and Menus

In this chapter, we're going to learn how to make commands and to add menu items in Menu Bar or in Context Menus.

Making a command

A command is an execution unit that can be called by menu item, keyboard shortcuts or subparts of applications. All menu items such as File > Open..., Edit > Copy have corresponding commands. So you must make a command first before to add a menu item. As shown in Getting Started, we will make a simple command showing a message in alert dialog.

First you have to defined an unique ID for a command. We will add a menu item under Tools menu, so we defined as "myextension.helloworld". If you make an extension supports PHP code generator, then "php.generate" or "myextension.php.generate" are good candidates for command ID.

var CMD_HELLOWORLD = "myextension.helloworld";

And then, we will define a handler function that will be executed when the command is called.

function handleHelloWorld() {
    window.alert("Hello, world!");
}

Finally, we need to register this command to CommandManager by calling register method. The first parameter is the name of the command which will be shown in menu item. The second and third are command ID and handler function respectively.

var CommandManager = app.getModule('command/CommandManager');
CommandManager.register("Hello World", CMD_HELLOWORLD, handleHelloWorld);

Calling a command

Now we have a new "Hello World" command. It can be called by manually as follow:

CommandManager.execute(CMD_HELLOWORLD);

The most of functionalities of StarUML are defined as commands so that you can call without defining duplicated functionality.

var Commands = app.getModule('command/Commands');
console.log(Commands); // you can see all predefined command IDs
CommandManager.execute(Commands.FILE_OPEN); // === CommandManager.execute("file.open");

Asynchronous command

Assume that you need to define a command that get some information by using HTTP request to a particular URL. This command is asynchronous. Waiting some actions from users or reading files using asynchronously APIs are also kinds of asynchronous commands. To define an asynchronous commmand, we have to use Promise provided by JQuery.

function handleAsynchronous() {
    var result = new $.Deferred(); // create Deferred object
    $.ajax({
        url: "...",
        success: function (data) {
            result.resolve(data); // call result.resolve when task complete
        },
        error: function (err) {
            result.reject(err); // call result.reject when task failed
        }
    });
    return result.promise(); // return Promise object
}

If you want to do something after an asynchronous command succeed or failed, use returned Promise object.

var promise = CommandManager.execute(Commands.FILE_OPEN);
promise.done(function () {
    console.log("command complete");
});
promise.fail(function () {
    console.log("command failed");
});

Adding menus and menu items in Menu Bar

Now we're going to add menus in Menu Bar with the commands we've defined. Menu Bar is typically placed in the top of the window of StarUML except Mac OS X which placing on the top of the entire screen.

Before we extending menus we need to distinguish Menu and Menu Item. Menu is top-level menu in the Menu Bar such as File, Edit, View while Menu Item is sub item of the menu such as File > New, Edit > Undo, Format > Font..., etc. Typically Menu Item have a corresponding command but Menu don't have.

Extending menus and menu items may be effected immediately when you run codes in console. It is better to run codes about menus in the form of an extension shown in Getting Started.

We will add a top-level menu Top Level Menu and two menu items Sub Menu Item 1, Sub Menu Item 2.

You can also assign shortcut keys to menu items. In here, a shortcut key (Ctrl+Shift+Q, Cmd+Shift+Q for Mac) will be assigned to Sub Menu Item 1.

define(function (require, exports, module) {
    "use strict";

    var Commands       = app.getModule("command/Commands"),
        CommandManager = app.getModule("command/CommandManager"),
        MenuManager    = app.getModule("menu/MenuManager");

    // Define commands
    var CMD_TOPLEVEL      = "myextension.top-level",
    	CMD_TOPLEVEL_SUB1 = "myextension.top-level.sub1",
    	CMD_TOPLEVEL_SUB2 = "myextension.top-level.sub2";

    CommandManager.register("Top Level Menu",  CMD_TOPLEVEL, CommandManager.doNothing);
    CommandManager.register("Sub Menu Item 1", CMD_TOPLEVEL_SUB1, function () { console.log("sub1 selected"); });
    CommandManager.register("Sub Menu Item 2", CMD_TOPLEVEL_SUB2, function () { console.log("sub2 selected"); });

    // Add a menu at top-level
    var topLevelMenu = MenuManager.addMenu(CMD_TOPLEVEL);

    // Add two menu items under the top-level
    topLevelMenu.addMenuItem(CMD_TOPLEVEL_SUB1, ["Ctrl-Shift-Q"]); // Assign shortcut key to the menu item
    topLevelMenu.addMenuDivider(); // Add a divider between the two sub menu items.
    topLevelMenu.addMenuItem(CMD_TOPLEVEL_SUB2);
});

Adding menu items to an existing menu

You can add menu items to an existing menu such as File, Edit, Tools, etc.

define(function (require, exports, module) {
    "use strict";

    var Commands       = app.getModule("command/Commands"),
        CommandManager = app.getModule("command/CommandManager"),
        MenuManager    = app.getModule("menu/MenuManager");

    // Define commands
    var CMD_SUB1 = "myextension.sub1";
    CommandManager.register("Sub Menu Item 1", CMD_SUB1, function () { console.log("sub1 selected"); });

    // Get the "File" menu
    var fileMenu = MenuManager.getMenu(Commands.FILE);

    // Add a menu item under "File" menu
    fileMenu.addMenuItem(CMD_SUB1);
});

Adding menu items at expected position

Typically new menu or menu items are appended to the last. How can we add menu or menu items at expected position? Here is an example adding a menu item at directly after File > Close. You may use other position parameters such as MenuManager.BEFORE, MenuManager.AFTER, MenuManager.FIRST, MenuManager.LAST.

define(function (require, exports, module) {
    "use strict";

    var Commands       = app.getModule("command/Commands"),
        CommandManager = app.getModule("command/CommandManager"),
        MenuManager    = app.getModule("menu/MenuManager");

    // Define commands
    var CMD_SUB1 = "myextension.sub1";
    CommandManager.register("Sub Menu Item 1", CMD_SUB1, function () { console.log("sub1 selected"); });

    // Get the "File" menu
    var fileMenu = MenuManager.getMenu(Commands.FILE);

    // Add a menu item after "File > Close" menu
    fileMenu.addMenuItem(CMD_SUB1, null, MenuManager.AFTER, Commands.FILE_CLOSE);
});

Changing status of menu items

Each menu item has status such as checked, enabled, and visible. Here we're going to show how to change the status of an existing menu item Edit > Select All. You will be able to see the changed status in the both Menu Bar and Context Menu.

Currently visible status may not be affected in Menu Bar. Instead, enabled status will be changed.

// Get the menu item "Edit > Select All"
var cmd = CommandManager.get(Commands.EDIT_SELECT_ALL); // or "edit.selectAll"

// Change checked status
cmd.setChecked(true); // cmd.setChecked(false);

// Change enabled status
cmd.setEnabled(false); // cmd.setEnabled(true);

// Change visible status
cmd.setVisible(false); // cmd.setVisible(true);

// Change the command name
cmd.setName("New Title");

Adding menu items in Context Menus

Basically extending Context Menu is same with Menu Bar. Only you need is to determine which Context Menu will be extended. There are three predefined Context Menus for Diagram area, Explorer view, and Working Diagrams view. We're going to add menu items to a predefined Context Menu.

Add an menu item to the Context Menu of Diagram area as follow:

define(function (require, exports, module) {
    "use strict";

    var CommandManager     = app.getModule("command/CommandManager"),
        DefaultMenus       = app.getModule("menu/DefaultMenus"),
        ContextMenuManager = app.getModule("menu/ContextMenuManager");

    // Define a command
    var CMD_CONTEXT_SUB1 = "myextension.sub1";
    CommandManager.register("Sub Menu Item 1", CMD_CONTEXT_SUB1, function () { console.log("sub1 selected"); });

    // Get the Context Menu of Diagram area
    var contextMenu = ContextMenuManager.getContextMenu(DefaultMenus.contextMenus.DIAGRAM);

    // Add a menu item to the Context Menu
    contextMenu.addMenuItem(CMD_CONTEXT_SUB1);
});

Click mouse right click on diagram area, you will see the added menu item in the Context Menu.

Adding a new Context Menu

StarUML even allows adding a new Context Menu for a specific HTML element. In here, instead of adding new HTML element we will use an existing HTML element, StatusBar, which doesn't have any Context Menu.

StatusBar is defined as a DIV element like as <div id="statusbar" ...></div>. You can find in Elements tab of DevTools (Debug > Show DevTools). We can add a new Context Menu having only one menu item for StatusBar as follow:

define(function (require, exports, module) {
    "use strict";

    var CommandManager = app.getModule("command/CommandManager"),
        ContextMenuManager = app.getModule("menu/ContextMenuManager");

    // Define a command
    var CMD_CONTEXT_SUB1 = "myextension.sub1";
    CommandManager.register("Sub Menu Item 1", CMD_CONTEXT_SUB1, function () { console.log("sub1 selected"); });

    // Define a new Context Menu for StatusBar
    var CONTEXT_MENU = "statusbar-context-menu";
    var contextMenu = ContextMenuManager.addContextMenu(CONTEXT_MENU, "#statusbar");

    // Add a menu item to the new Context Menu
    contextMenu.addMenuItem(CMD_CONTEXT_SUB1);
});

Click mouse right click on StatusBar, you will see the new Context Menu.