/** * The main controller (in a standard MVC point of view) of the application. It is a singleton * thus can be called by any part of the application. * This will wire all the commands that can be defined dynamically by any IView, and add their * corresponding buttons to the application menubar and toolbars. * See the "definitions" property documentation below for more info on how to define new commands. * * @author Charles du Jeu */ qx.Class.define("org.argeo.ria.event.CommandsManager", { type : "singleton", extend : qx.core.Object, construct : function(){ this.base(arguments); this.setInitialDefinitions(qx.lang.Object.copy(this.getDefinitions())); this.addListener("changedCommands", this.createCommands, this); }, properties : { /** * The commands definitions is a Map described as below *
* { * label : "", * | The label of the action * * icon : "", * | The icon image * * shortcut : "", * | The keyboard shortcut, as defined in qooxdoo (Control+s, Alt+k, etc.). Warning, the letter must be lowercase. * * enabled : true, * | Whether it is enabled or disabled at creation * * menu : ""|null, * | The menu group to which the command will be added. If null, will not appear in the menus. * * menuPosition : "first"|"last" * | Optional : force the menu group to be first or last in the menubar. * * toolbar : ""|null, * | The toolbar group to which the command will be added. If null, will not appear in the toolbars. * * init : function(){}, * | Optional function called at command creation. * | Function context : the command itself * * callback : function(e){}, * | The main callback to be triggered when command is executed. * | Function context : the current class (not the command!) * * selectionChange : function(viewPaneId, xmlNodes){}, * | Optional function called each time a selectionChange is detected in one of the active viewPane. * | The origin viewPaneId and the new selection as a map of nodes are passed as arguments. * | Function context : the command itself. * * submenu : [{label:"", icon:"", commandId:""}, ...], * | If set, the command will create a submenu, being in a menu or in the toolbar. * | The submenu is created with the various array entries, and the submenuCallback function * | will be called with the 'commandId' parameter when a submenu entry is selected. * * submenuCallback : function(commandId){}, * | Callback if command is a submenu (cf. above). * | Function context : the current class/ * * command : null * | For internal use only, caching the actual org.argeo.ria.event.Command object. * } ** @see org.argeo.ria.event.Command for the definition Map details. */ definitions : { init : {}, check : "Map" }, /** * For internal use */ initialDefinitions : { init : {}, check : "Map" }, /** * Special command definitions that are shared between focusable parts. */ sharedDefinitions : { init: {}, check: "Map" } }, events : { /** * Triggered when the whole commands list is changed. Mainly used internally by the manager. */ "changedCommands" : "qx.event.type.Event" }, /* ***************************************************************************** MEMBERS ***************************************************************************** */ members : { /** * Initialize the manager with basic definitions. * @param initDefinitions {Map} A map of commands definitions. */ init : function(initDefinitions){ this.setDefinitions(initDefinitions); this.setInitialDefinitions(qx.lang.Object.copy(initDefinitions)); }, /** * Creates all the objects (if they are not already existing) from the definitions maps. */ createCommands : function(){ this.menus = {}; this.toolbars = {}; var defs = this.getDefinitions(); var shared = this.getSharedDefinitions(); for(var key in defs){ var definition = defs[key]; var command; if(!definition.command){ command = new org.argeo.ria.event.Command(key, definition.label, definition.icon, definition.shortcut); if(definition.submenu){ command.setMenu(definition.submenu); if(definition.submenuCallback){ command.setMenuCallback(definition.submenuCallback); command.setMenuContext((definition.callbackContext?definition.callbackContext:null)); } } command.setEnabled(definition.enabled); if(definition.toggle){ command.setToggle(true); } this._attachListener(command, definition.callback, definition.callbackContext); if(definition.init){ var binded = qx.lang.Function.bind(definition.init, command); binded(); } definition.command = command; }else{ command = definition.command; if(shared[key]){ for(var focusPartId in shared[key]){ var sharedCommand = shared[key][focusPartId]; if(sharedCommand.callback){ var split = sharedCommand.callbackContext.split(":"); var focusPart = split[0]; var viewId = split[1]; command.registerCallback(sharedCommand.callback, split[1]); //this._attachListener(command, sharedCommand.callback, sharedCommand.callbackContext); } } } } if(definition.menu){ if(!this.menus[definition.menu]) this.menus[definition.menu] = []; this.menus[definition.menu].push(definition); } if(definition.toolbar){ if(!this.toolbars[definition.toolbar]) this.toolbars[definition.toolbar] = []; this.toolbars[definition.toolbar].push(command); } } this.setDefinitions(defs); }, /** * Refresh the current commands status depending on the viewSelection. * @param viewSelection {org.argeo.ria.components.ViewSelection} The current ViewSelection */ refreshCommands : function(viewSelection){ var defs = this.getDefinitions(); var shared = this.getSharedDefinitions(); var xmlNodes = null; if(viewSelection.getCount() > 0){ var xmlNodes = viewSelection.getNodes(); } for(var key in defs){ var definition = defs[key]; if(!definition.selectionChange) continue; if(shared[key]){ var currentFocus = org.argeo.ria.components.ViewsManager.getInstance().getCurrentFocus(); //this.debug(currentFocus); if(!currentFocus) continue; var sharedComm = shared[key][currentFocus.getViewId()]; if(sharedComm && sharedComm.selectionChange){ var binded = qx.lang.Function.bind(sharedComm.selectionChange, definition.command); binded(viewSelection.getViewId(), xmlNodes); } } var binded = qx.lang.Function.bind(definition.selectionChange, definition.command); binded(viewSelection.getViewId(), xmlNodes); } }, /** * Record a menubar for the application * @param menuBar {qx.ui.menubar.MenuBar} The application menubar */ registerMenuBar : function(menuBar){ this.addListener("changedCommands", function(){ this.createMenuButtons(menuBar); }, this); this.createMenuButtons(menuBar); }, /** * Record a toolbar for the application * @param toolBar {qx.ui.toolbar.ToolBar} The application toolbar */ registerToolBar : function(toolBar){ this.addListener("changedCommands", function(){ this.createToolbarParts(toolBar); }, this); this.createToolbarParts(toolBar); }, /** * Creates the real buttons and add them to the passed menuBar. * @param menuBar {qx.ui.menubar.MenuBar} The application menubar */ createMenuButtons : function(menuBar){ menuBar.removeAll(); var anchors = {}; for(var key in this.menus){ var menu = new qx.ui.menu.Menu(); var button = new qx.ui.menubar.Button(key, null, menu); var anchorDetected = false; for(var i=0; i