2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2011 - DIGITEO - Vincent Couvert
5 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution. The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
13 package org.scilab.modules.graphic_objects.utils;
15 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_CALLBACKTYPE__;
16 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_CALLBACK__;
17 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_HIDDEN__;
18 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_ACCELERATOR__;
19 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_ENABLE__;
20 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_ICON__;
21 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_LABEL__;
22 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_MNEMONIC__;
23 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UI_SEPARATOR__;
24 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_UIMENU__;
25 import static org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties.__GO_VISIBLE__;
28 import java.io.IOException;
29 import java.lang.reflect.InvocationHandler;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.lang.reflect.Proxy;
33 import java.util.Collection;
34 import java.util.TreeSet;
36 import javax.xml.parsers.ParserConfigurationException;
38 import org.scilab.modules.commons.OS;
39 import org.scilab.modules.commons.ScilabConstants;
40 import org.scilab.modules.commons.xml.ScilabDocumentBuilderFactory;
41 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
42 import org.scilab.modules.graphic_objects.graphicObject.CallBack;
43 import org.scilab.modules.graphic_objects.graphicObject.GraphicObject.Type;
44 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
45 import org.scilab.modules.gui.SwingView;
46 import org.scilab.modules.localization.Messages;
47 import org.w3c.dom.Document;
48 import org.w3c.dom.NamedNodeMap;
49 import org.w3c.dom.Node;
50 import org.w3c.dom.NodeList;
51 import org.xml.sax.SAXException;
55 * Create a menuBar from an XML file
56 * @author Vincent COUVERT
58 public final class MenuBarBuilder {
60 private static final String MAINMENUBARXMLFILE = ScilabConstants.SCI + "/modules/gui/etc/main_menubar.xml";
61 private static final String GRAPHICSMENUBARXMLFILE = ScilabConstants.SCI + "/modules/gui/etc/graphics_menubar.xml";
63 private static final String FILE_NOT_FOUND = "Could not find file: ";
65 private static final String CANNOT_CREATE_MENUBAR = "Cannot create MenuBar.\n"
66 + "Check if file *_menubar.xml is available and valid.";
68 private static boolean isParentValid = true;;
73 private MenuBarBuilder() {
74 throw new UnsupportedOperationException();
78 * Create a proxy to access a XML file
79 * @param resultClass class for the return value
80 * @param fileToLoad XML file to load
81 * @return a proxy used to read the XML file
82 * @throws SAXException can be thrown when an error occurs while reading the file
83 * @throws IOException can be thrown when an error occurs while accessing the file
84 * @throws ParserConfigurationException can be thrown when an error occurs while parsing the file
86 public static Object buildMenuBar(Class[] resultClass, String fileToLoad) throws SAXException, IOException, ParserConfigurationException {
88 InvocationHandler invocationHandler = new MenuBarConfigurationHandler(fileToLoad);
90 return Proxy.newProxyInstance(invocationHandler.getClass().getClassLoader(), resultClass, invocationHandler);
94 * Create console menubar from data in a XML file
95 * @param consoleId the console
97 public static void buildConsoleMenuBar(String consoleId) {
98 buildMenuBar(MAINMENUBARXMLFILE, consoleId);
102 * Create graphic figure menubar from data in a XML file
103 * @param figureId the figure
105 public static void buildFigureMenuBar(String figureId) {
106 if (!SwingView.isHeadless()) {
107 MenuBarBuilder.isParentValid = false;
108 buildMenuBar(GRAPHICSMENUBARXMLFILE, figureId);
113 * Create children used in the menubar from data in a XML file
114 * @param fileToLoad XML file to load
115 * @param parentId the menubar parent
117 public static void buildMenuBar(String fileToLoad, String parentId) {
120 MenuBarConfiguration menuBarConfig =
121 (MenuBarConfiguration) buildMenuBar(new Class[] {MenuBarConfiguration.class}, fileToLoad);
122 menuBarConfig.addMenus(parentId);
123 } catch (IllegalArgumentException e) {
124 System.err.println(CANNOT_CREATE_MENUBAR);
125 System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
126 } catch (SAXException e) {
127 System.err.println(CANNOT_CREATE_MENUBAR);
128 System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
129 } catch (IOException e) {
130 System.err.println(CANNOT_CREATE_MENUBAR);
131 System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
132 } catch (ParserConfigurationException e) {
133 System.err.println(CANNOT_CREATE_MENUBAR);
134 System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
139 * Class used to read the XMl file
141 private static class MenuBarConfigurationHandler implements InvocationHandler {
142 protected static final String LABEL = "label";
143 protected static final String MENU = "menu";
144 protected static final String MNEMONIC = "mnemonic";
145 protected static final String SUBMENU = "submenu";
146 protected static final String SEPARATOR = "separator";
147 protected static final String ENABLED = "enabled";
148 protected static final String ACCELERATOR = "accelerator";
149 protected static final String CALLBACK = "callback";
150 protected static final String TYPE = "type";
151 protected static final String INSTRUCTION = "instruction";
152 protected static final String TRUE = "true";
153 protected static final String ICON = "icon";
154 protected static final String MACOSX = "macosx";
156 private Document dom;
157 private Collection<String> internalMethodNames;
162 * @param xmlFile XML file to load
163 * @throws SAXException can be thrown when an error occurs while reading the file
164 * @throws IOException can be thrown when an error occurs while accessing the file
165 * @throws ParserConfigurationException can be thrown when an error occurs while parsing the file
167 public MenuBarConfigurationHandler(String xmlFile) throws SAXException, IOException, ParserConfigurationException {
169 if (!new File(xmlFile).exists()) {
170 throw new java.io.IOException();
173 // Build dictionary for internal method
174 internalMethodNames = new TreeSet<String>();
175 Method[] internalMethodes = this.getClass().getMethods();
176 for (Method method : internalMethodes) {
177 internalMethodNames.add(method.getName());
180 // Build xml document for request
181 dom = ScilabDocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(xmlFile));
185 * Invoke a proxy to get data
186 * @param proxy the proxy to call
187 * @param method the method to call
188 * @param args the arguments for the method
189 * @return the object read
190 * @throws IllegalAccessException thrown when the method called is inaccessible
191 * @throws InvocationTargetException thorwn when the method called threw an exception
192 * @throws NoSuchMethodException thrown when invoking a non-existing method
193 * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
195 public Object invoke(Object proxy, Method method, Object[] args)
196 throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
197 if (internalMethodNames.contains(method.getName())) {
198 return getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(this, args);
205 * Add menus to a menubar using Scilab MVC
206 * @param parentId the tab ID to which the menus will be added to
207 * @see org.scilab.modules.MenuBarConfiguration.utils.MenuBarConfiguration#addMenus(org.scilab.modules.gui.menubar.MenuBar)
209 public void addMenus(String parentId) {
211 for (String childId : (String []) GraphicController.getController().getProperty(parentId, GraphicObjectProperties.__GO_CHILDREN__)) {
212 if (GraphicController.getController().getProperty(childId, GraphicObjectProperties.__GO_TYPE__).equals(__GO_UIMENU__))
213 GraphicController.getController().removeRelationShipAndDelete(childId);
216 NodeList menus = dom.getElementsByTagName(MENU);
218 for (int i = 0; i < menus.getLength(); i++) {
220 String menuId = null;
222 menuId = GraphicController.getController().askObject(Type.UIMENU);
224 menuId = GraphicController.getController().askObject(Type.UIMENUMODEL);
227 // The menu is not visible in Scilab view by default
228 GraphicController.getController().setProperty(menuId, __GO_HIDDEN__, true);
231 String menuLabel = Messages.gettext(menus.item(i).getAttributes().getNamedItem(LABEL).getNodeValue());
232 GraphicController.getController().setProperty(menuId, __GO_UI_LABEL__, menuLabel);
234 // Set the mnemonic if given
235 if (menus.item(i).getAttributes().getNamedItem(MNEMONIC) != null) {
236 String mnemonicString = menus.item(i).getAttributes().getNamedItem(MNEMONIC).getNodeValue();
237 GraphicController.getController().setProperty(menuId, __GO_UI_MNEMONIC__, mnemonicString);
240 // Set the icon if given
241 if (menus.item(i).getAttributes().getNamedItem(ICON) != null) {
242 String iconName = menus.item(i).getNodeValue();
243 GraphicController.getController().setProperty(menuId, __GO_UI_ICON__, iconName);
246 // Set the enable status if given
247 if (menus.item(i).getAttributes().getNamedItem(ENABLED) != null) {
248 boolean enabled = menus.item(i).getAttributes().getNamedItem(ENABLED).getNodeValue().equals(TRUE);
249 GraphicController.getController().setProperty(menuId, __GO_UI_ENABLE__, enabled);
251 // Set the menu parent
252 GraphicController.getController().setGraphicObjectRelationship(parentId, menuId);
253 addSubMenus(menuId, i);
258 * Read submenus data in the XML file and create them using Scilab MVC
259 * @param parentMenuId the parent menu UID for submenus
260 * @param index the index of the parent in menu list
262 public void addSubMenus(String parentMenuId, int index) {
263 Node submenu = dom.getElementsByTagName(MENU).item(index).getFirstChild();
265 boolean separator = false;
266 boolean macosx = true;
268 while (submenu != null) {
269 if (submenu.getNodeName() == SEPARATOR) {
272 } else if (submenu.getNodeName() == SUBMENU) {
274 String menuId = null;
276 menuId = GraphicController.getController().askObject(Type.UIMENU);
278 menuId = GraphicController.getController().askObject(Type.UIMENUMODEL);
281 // The menu is not visible in Scilab view by default
282 GraphicController.getController().setProperty(menuId, __GO_HIDDEN__, true);
284 // Set the menu parent
285 GraphicController.getController().setGraphicObjectRelationship(parentMenuId, menuId);
287 // First we have to read its attributes
288 NamedNodeMap attributes = submenu.getAttributes();
290 for (int i = 0; i < attributes.getLength(); i++) {
291 if (attributes.item(i).getNodeName() == LABEL) {
293 String menuLabel = Messages.gettext(attributes.item(i).getNodeValue());
294 GraphicController.getController().setProperty(menuId, __GO_UI_LABEL__, menuLabel);
295 } else if (attributes.item(i).getNodeName() == MNEMONIC) {
297 String mnemonicString = attributes.item(i).getNodeValue();
298 GraphicController.getController().setProperty(menuId, __GO_UI_MNEMONIC__, mnemonicString);
299 } else if (attributes.item(i).getNodeName() == ENABLED) {
300 // Set the enable status
301 boolean enabled = attributes.item(i).getNodeValue().equals(TRUE);
302 GraphicController.getController().setProperty(menuId, __GO_UI_ENABLE__, enabled);
303 } else if (attributes.item(i).getNodeName() == ICON) {
305 String iconName = attributes.item(i).getNodeValue();
306 GraphicController.getController().setProperty(menuId, __GO_UI_ICON__, iconName);
307 } else if (attributes.item(i).getNodeName() == ACCELERATOR) {
308 // Set the accelerator
309 String acceleratorString = attributes.item(i).getNodeValue();
310 GraphicController.getController().setProperty(menuId, __GO_UI_ACCELERATOR__, acceleratorString);
311 } else if (attributes.item(i).getNodeName() == MACOSX) {
312 macosx = attributes.item(i).getNodeValue().equals(TRUE);
313 if (!macosx && OS.get() == OS.MAC) {
314 GraphicController.getController().setProperty(menuId, __GO_VISIBLE__, false);
320 // Then we get its callback (if exists)
321 Node callback = submenu.getFirstChild();
322 while (callback != null) {
323 if (callback.getNodeName() == CALLBACK) {
324 NamedNodeMap cbAttributes = callback.getAttributes();
325 String command = null;
326 int commandType = CallBack.UNTYPED;
327 for (int j = 0; j < cbAttributes.getLength(); j++) {
328 if (cbAttributes.item(j).getNodeName() == INSTRUCTION) {
329 command = cbAttributes.item(j).getNodeValue();
330 } else if (cbAttributes.item(j).getNodeName() == TYPE) {
331 commandType = Integer.parseInt(cbAttributes.item(j).getNodeValue());
334 if (command != null && commandType != CallBack.UNTYPED) {
335 GraphicController.getController().setProperty(menuId, __GO_CALLBACK__, command);
336 GraphicController.getController().setProperty(menuId, __GO_CALLBACKTYPE__, commandType);
338 } else if (callback.getNodeName() == SUBMENU) {
339 addSubMenuItem(menuId, callback);
342 callback = callback.getNextSibling();
346 GraphicController.getController().setProperty(menuId, __GO_UI_SEPARATOR__, true);
351 submenu = submenu.getNextSibling();
356 * Add submenu for menu
357 * @param parentMenuItemId object with this id will become a menu with subMenuItems
358 * @param node to get attributs of the menu
360 public void addSubMenuItem(String parentMenuItemId, Node node) {
362 NamedNodeMap attributes = node.getAttributes();
365 String subMenuItemId = null;
367 subMenuItemId = GraphicController.getController().askObject(Type.UIMENU);
369 subMenuItemId = GraphicController.getController().askObject(Type.UIMENUMODEL);
372 // The menu is not visible in Scilab view by default
373 GraphicController.getController().setProperty(subMenuItemId, __GO_HIDDEN__, true);
375 // Set the menu parent
376 GraphicController.getController().setGraphicObjectRelationship(parentMenuItemId, subMenuItemId);
378 for (int i = 0; i < attributes.getLength(); i++) {
379 if (attributes.item(i).getNodeName() == LABEL) {
381 String menuLabel = Messages.gettext(attributes.item(i).getNodeValue());
382 GraphicController.getController().setProperty(subMenuItemId, __GO_UI_LABEL__, menuLabel);
383 } else if (attributes.item(i).getNodeName() == MNEMONIC) {
385 String mnemonicString = attributes.item(i).getNodeValue();
386 GraphicController.getController().setProperty(subMenuItemId, __GO_UI_MNEMONIC__, mnemonicString);
387 } else if (attributes.item(i).getNodeName() == ICON) {
388 String iconName = attributes.item(i).getNodeValue();
389 GraphicController.getController().setProperty(subMenuItemId, __GO_UI_ICON__, iconName);
390 } else if (attributes.item(i).getNodeName() == ENABLED) {
391 // Set the enable status
392 boolean enabled = attributes.item(i).getNodeValue().equals(TRUE);
393 GraphicController.getController().setProperty(subMenuItemId, __GO_UI_ENABLE__, enabled);
397 // Then we get its callback (if exists)
398 Node callback = node.getFirstChild();
399 while (callback != null) {
400 if (callback.getNodeName() == CALLBACK) {
401 NamedNodeMap cbAttributes = callback.getAttributes();
402 String command = null;
403 int commandType = CallBack.UNTYPED;
404 for (int j = 0; j < cbAttributes.getLength(); j++) {
405 if (cbAttributes.item(j).getNodeName() == INSTRUCTION) {
406 command = cbAttributes.item(j).getNodeValue();
407 } else if (cbAttributes.item(j).getNodeName() == TYPE) {
408 commandType = Integer.parseInt(cbAttributes.item(j).getNodeValue());
411 if (command != null && commandType != CallBack.UNTYPED) {
412 GraphicController.getController().setProperty(subMenuItemId, __GO_CALLBACK__, command);
413 GraphicController.getController().setProperty(subMenuItemId, __GO_CALLBACKTYPE__, commandType);
415 } else if (callback.getNodeName() == SUBMENU) {
416 addSubMenuItem(subMenuItemId, callback);
419 callback = callback.getNextSibling();