]> git.argeo.org Git - gpl/argeo-slc.git/blob - org.argeo.slc.webapp/src/main/webapp/argeo-ria-src/class/org/argeo/ria/event/CommandsManager.js
Ability to define a submenu as disabled
[gpl/argeo-slc.git] / org.argeo.slc.webapp / src / main / webapp / argeo-ria-src / class / org / argeo / ria / event / CommandsManager.js
1 /**
2 * The main controller (in a standard MVC point of view) of the application. It is a singleton
3 * thus can be called by any part of the application.
4 * This will wire all the commands that can be defined dynamically by any IView, and add their
5 * corresponding buttons to the application menubar and toolbars.
6 * See the "definitions" property documentation below for more info on how to define new commands.
7 *
8 * @author Charles du Jeu
9 */
10 qx.Class.define("org.argeo.ria.event.CommandsManager",
11 {
12 type : "singleton",
13 extend : qx.core.Object,
14
15 construct : function(){
16 this.base(arguments);
17 this.setInitialDefinitions(qx.lang.Object.copy(this.getDefinitions()));
18 this.addListener("changedCommands", this.createCommands, this);
19 },
20
21 properties :
22 {
23 /**
24 * The commands definitions is a Map described as below
25 * <pre>
26 * {
27 * <b>label : "",</b>
28 * | The label of the action
29 *
30 * <b>icon : "",</b>
31 * | The icon image
32 *
33 * <b>shortcut : "",</b>
34 * | The keyboard shortcut, as defined in qooxdoo (Control+s, Alt+k, etc.). Warning, the letter must be lowercase.
35 *
36 * <b>enabled : true,</b>
37 * | Whether it is enabled or disabled at creation
38 *
39 * <b>menu : ""|null,</b>
40 * | The menu group to which the command will be added. If null, will not appear in the menus.
41 *
42 * <b>menuPosition : "first"|"last"</b>
43 * | Optional : force the menu group to be first or last in the menubar.
44 *
45 * <b>toolbar : ""|null,</b>
46 * | The toolbar group to which the command will be added. If null, will not appear in the toolbars.
47 *
48 * <b>init : function(){},</b>
49 * | Optional function called at command creation.
50 * | Function context : the command itself
51 *
52 * <b>callback : function(e){},</b>
53 * | The main callback to be triggered when command is executed.
54 * | Function context : the current class (not the command!)
55 *
56 * <b>selectionChange : function(viewPaneId, xmlNodes){},</b>
57 * | Optional function called each time a selectionChange is detected in one of the active viewPane.
58 * | The origin viewPaneId and the new selection as a map of nodes are passed as arguments.
59 * | Function context : the command itself.
60 *
61 * <b>submenu : [{label:"", icon:"", commandId:""}, ...],</b>
62 * | If set, the command will create a submenu, being in a menu or in the toolbar.
63 * | The submenu is created with the various array entries, and the submenuCallback function
64 * | will be called with the 'commandId' parameter when a submenu entry is selected.
65 *
66 * <b>submenuCallback : function(commandId){},</b>
67 * | Callback if command is a submenu (cf. above).
68 * | Function context : the current class/
69 *
70 * <b>command : null</b>
71 * | For internal use only, caching the actual org.argeo.ria.event.Command object.
72 * }
73 * </pre>
74 * @see org.argeo.ria.event.Command for the definition Map details.
75 */
76 definitions : {
77 init : {
78 "stop" : {
79 label : "Stop",
80 icon : "resource/slc/process-stop.png",
81 shortcut : "Control+s",
82 enabled : false,
83 menu : null,
84 toolbar : "list",
85 callback : function(e){},
86 command : null
87 },
88 /*
89 "quit" : {
90 label : "Quit",
91 icon : "resource/slc/system-shutdown.png",
92 shortcut : "Control+q",
93 enabled : true,
94 menu : "File",
95 toolbar : false,
96 callback : function(e){},
97 command : null
98 },
99 */
100 "log" : {
101 label : "Show Console",
102 icon : "resource/slc/help-contents.png",
103 shortcut : "",
104 enabled : true,
105 menu : "Help",
106 menuPosition: "last",
107 toolbar : false,
108 callback : function(e){
109 org.argeo.ria.components.Logger.getInstance().toggle();
110 },
111 command : null
112 },
113 "help" : {
114 label : "About...",
115 icon : "resource/slc/help-about.png",
116 shortcut : "Control+h",
117 enabled : true,
118 menu : "Help",
119 toolbar : false,
120 callback : function(e){
121 var win = new org.argeo.ria.components.Modal("About SLC", null, "SLC is a product from Argeo.");
122 win.attachAndShow();
123 },
124 command : null
125 }
126 }
127 },
128 /**
129 * For internal use
130 */
131 initialDefinitions : {
132 init : {}
133 }
134 },
135
136 events : {
137 /**
138 * Triggered when the whole commands list is changed. Mainly used internally by the manager.
139 */
140 "changedCommands" : "qx.event.type.Event"
141 },
142
143 /*
144 *****************************************************************************
145 MEMBERS
146 *****************************************************************************
147 */
148
149 members :
150 {
151 /**
152 * Creates all the objects (if they are not already existing) from the definitions maps.
153 */
154 createCommands : function(){
155 this.menus = {};
156 this.toolbars = {};
157 var defs = this.getDefinitions();
158 for(var key in defs){
159 var definition = defs[key];
160 var command;
161 if(!definition.command){
162 command = new org.argeo.ria.event.Command(key, definition.label, definition.icon, definition.shortcut);
163 if(definition.submenu){
164 command.setMenu(definition.submenu);
165 if(definition.submenuCallback){
166 command.setMenuCallback(definition.submenuCallback);
167 command.setMenuContext((definition.callbackContext?definition.callbackContext:null));
168 }
169 }
170 command.setEnabled(definition.enabled);
171 if(definition.toggle){
172 command.setToggle(true);
173 }
174 command.addListener("execute", definition.callback, (definition.callbackContext?definition.callbackContext:this));
175 if(definition.init){
176 var binded = qx.lang.Function.bind(definition.init, command);
177 binded();
178 }
179 definition.command = command;
180 }else{
181 command = definition.command;
182 }
183 if(definition.menu){
184 if(!this.menus[definition.menu]) this.menus[definition.menu] = [];
185 this.menus[definition.menu].push(definition);
186 }
187 if(definition.toolbar){
188 if(!this.toolbars[definition.toolbar]) this.toolbars[definition.toolbar] = [];
189 this.toolbars[definition.toolbar].push(command);
190 }
191 }
192 this.setDefinitions(defs);
193 },
194
195 /**
196 * Refresh the current commands status depending on the viewSelection.
197 * @param viewSelection {org.argeo.ria.components.ViewSelection} The current ViewSelection
198 */
199 refreshCommands : function(viewSelection){
200 var defs = this.getDefinitions();
201 var xmlNodes = null;
202 if(viewSelection.getCount() > 0){
203 var xmlNodes = viewSelection.getNodes();
204 }
205 for(var key in defs){
206 var definition = defs[key];
207 if(!definition.selectionChange) continue;
208 var binded = qx.lang.Function.bind(definition.selectionChange, definition.command);
209 binded(viewSelection.getViewId(), xmlNodes);
210 }
211 },
212
213 /**
214 * Record a menubar for the application
215 * @param menuBar {qx.ui.menubar.MenuBar} The application menubar
216 */
217 registerMenuBar : function(menuBar){
218 this.addListener("changedCommands", function(){
219 this.createMenuButtons(menuBar);
220 }, this);
221 this.createMenuButtons(menuBar);
222 },
223
224 /**
225 * Record a toolbar for the application
226 * @param toolBar {qx.ui.toolbar.ToolBar} The application toolbar
227 */
228 registerToolBar : function(toolBar){
229 this.addListener("changedCommands", function(){
230 this.createToolbarParts(toolBar);
231 }, this);
232 this.createToolbarParts(toolBar);
233 },
234
235 /**
236 * Creates the real buttons and add them to the passed menuBar.
237 * @param menuBar {qx.ui.menubar.MenuBar} The application menubar
238 */
239 createMenuButtons : function(menuBar){
240 menuBar.removeAll();
241 var anchors = {};
242 for(var key in this.menus){
243 var menu = new qx.ui.menu.Menu();
244 var button = new qx.ui.menubar.Button(key, null, menu);
245 var anchorDetected = false;
246 for(var i=0; i<this.menus[key].length;i++){
247 var def = this.menus[key][i];
248 menu.add(def.command.getMenuButton());
249 if(!anchorDetected && def.menuPosition){
250 anchorDetected = true;
251 anchors[def.menuPosition] = button;
252 }
253 }
254 if(!anchorDetected){
255 menuBar.add(button);
256 }
257 }
258 // Add specific anchored buttons
259 if(anchors.first) menuBar.addAt(anchors.first, 0);
260 else if(anchors.last){
261 menuBar.add(anchors.last);
262 }
263 },
264
265 /**
266 * Creates the real buttons and add them to the passed toolbar.
267 * @param toolbar {qx.ui.toolbar.ToolBar} The application toolbar
268 */
269 createToolbarParts : function(toolbar){
270 toolbar.removeAll();
271 for(var key in this.toolbars){
272 var tPart = new qx.ui.toolbar.Part();
273 toolbar.add(tPart);
274 this.toolbars[key].map(function(command){
275 tPart.add(command.getToolbarButton());
276 });
277 }
278 },
279 /**
280 * Creates a context menu from an array of commands ids.
281 * @param commandIdsArray {Array} An array of string
282 * @return {qx.ui.menu.Menu}
283 */
284 createMenuFromIds : function(commandIdsArray){
285 var defs = this.getDefinitions();
286 var contextMenu = new qx.ui.menu.Menu();
287 for(var i=0;i<commandIdsArray.length;i++){
288 var definition = defs[commandIdsArray[i]];
289 if(definition){
290 var command = definition.command;
291 contextMenu.add(command.getMenuButton());
292 }
293 }
294 return contextMenu;
295 },
296 /**
297 * Add a new set of commands definitions. See the definitions property of this class.
298 * @param definitions {Map} a set of commands definitions.
299 * @param callbackContext {qx.ui.core.Object} The context used inside the commands callbacks.
300 */
301 addCommands : function(definitions, callbackContext){
302 var crtDefs = this.getDefinitions();
303 for(var key in definitions){
304 if(callbackContext) definitions[key]['callbackContext'] = callbackContext;
305 crtDefs[key] = definitions[key];
306 }
307 this.setDefinitions(crtDefs);
308 this.fireEvent("changedCommands");
309 },
310 /**
311 * Removes a whole set of commands by their definitions maps.
312 * @param definitions {Map} a set of commands definitions
313 */
314 removeCommands : function(definitions){
315 var crtDefs = this.getDefinitions();
316 var initDefs = this.getInitialDefinitions();
317 for(var key in definitions){
318 if(!crtDefs[key]) continue;
319 if(initDefs[key]){
320 crtDefs[key] = initDefs[key];
321 }else{
322 delete crtDefs[key];
323 }
324 }
325 this.setDefinitions(crtDefs);
326 this.fireEvent("changedCommands");
327 },
328 /**
329 * Executes a command by its id.
330 * @param commandId {String} The command id.
331 */
332 executeCommand : function(commandId){
333 var defs = this.getDefinitions();
334 if(defs[commandId] && defs[commandId].command.getEnabled()){
335 defs[commandId].command.execute();
336 }
337 },
338 /**
339 * Retrieves a command by its id.
340 * @param commandId {String} The command id.
341 */
342 getCommandById : function(commandId){
343 var defs = this.getDefinitions();
344 if(defs[commandId] && defs[commandId].command){
345 return defs[commandId].command;
346 }
347 },
348 /**
349 * Add a standard context menu to a toolbar for button look and feel (show icon, text, both).
350 * @param toolbar {qx.ui.toolbar.ToolBar} The toolbar
351 */
352 addToolbarContextMenu : function(toolbar){
353 var menu = new qx.ui.menu.Menu();
354 var icon = new qx.ui.menu.RadioButton("Show Icons");
355 icon.setValue("icon");
356 var text = new qx.ui.menu.RadioButton("Show Text");
357 text.setValue("label");
358 var both = new qx.ui.menu.RadioButton("Show Both");
359 both.setValue("both");
360 var mgr = new qx.ui.form.RadioGroup(icon, text, both);
361 menu.add(icon);
362 menu.add(text);
363 menu.add(both);
364 mgr.setSelected(both);
365 toolbar.setContextMenu(menu);
366 mgr.addListener("changeValue", function(e){
367 this.setShow(e.getData());
368 }, toolbar);
369
370 }
371 }
372 });