105dfb0a8cabf3fb00bdccf5d4446c68ae76f5cc
[scilab.git] / scilab / modules / graphic_objects / src / java / org / scilab / modules / graphic_objects / utils / MenuBarBuilder.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2011 - DIGITEO - Vincent Couvert
4  *
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
10  *
11  */
12
13 package org.scilab.modules.graphic_objects.utils;
14
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
26 import java.io.File;
27 import java.io.IOException;
28 import java.lang.reflect.InvocationHandler;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Proxy;
32 import java.util.Collection;
33 import java.util.TreeSet;
34
35 import javax.xml.parsers.ParserConfigurationException;
36
37 import org.scilab.modules.commons.ScilabConstants;
38 import org.scilab.modules.commons.xml.ScilabDocumentBuilderFactory;
39 import org.scilab.modules.graphic_objects.graphicController.GraphicController;
40 import org.scilab.modules.graphic_objects.graphicObject.CallBack;
41 import org.scilab.modules.graphic_objects.graphicObject.GraphicObject.Type;
42 import org.scilab.modules.graphic_objects.graphicObject.GraphicObjectProperties;
43 import org.scilab.modules.localization.Messages;
44 import org.w3c.dom.Document;
45 import org.w3c.dom.NamedNodeMap;
46 import org.w3c.dom.Node;
47 import org.w3c.dom.NodeList;
48 import org.xml.sax.SAXException;
49
50
51 /**
52  * Create a menuBar from an XML file
53  * @author Vincent COUVERT
54  */
55 public final class MenuBarBuilder {
56
57     private static final String MAINMENUBARXMLFILE = ScilabConstants.SCI + "/modules/gui/etc/main_menubar.xml";
58     private static final String GRAPHICSMENUBARXMLFILE = ScilabConstants.SCI + "/modules/gui/etc/graphics_menubar.xml";
59
60     private static final String FILE_NOT_FOUND = "Could not find file: ";
61
62     private static final String CANNOT_CREATE_MENUBAR = "Cannot create MenuBar.\n"
63             + "Check if file *_menubar.xml is available and valid.";
64
65     private static boolean isParentValid = true;;
66
67     /**
68      * Default constructor
69      */
70     private MenuBarBuilder() {
71         throw new UnsupportedOperationException();
72     }
73
74     /**
75      * Create a proxy to access a XML file
76      * @param resultClass class for the return value
77      * @param fileToLoad XML file to load
78      * @return a proxy used to read the XML file
79      * @throws SAXException can be thrown when an error occurs while reading the file
80      * @throws IOException can be thrown when an error occurs while accessing the file
81      * @throws ParserConfigurationException can be thrown when an error occurs while parsing the file
82      */
83     public static Object buildMenuBar(Class[] resultClass, String fileToLoad) throws SAXException, IOException, ParserConfigurationException {
84
85         InvocationHandler invocationHandler = new MenuBarConfigurationHandler(fileToLoad);
86
87         return Proxy.newProxyInstance(invocationHandler.getClass().getClassLoader(), resultClass, invocationHandler);
88     }
89
90     /**
91      * Create console menubar from data in a XML file
92      * @param consoleId the console
93      */
94     public static void buildConsoleMenuBar(String consoleId) {
95         buildMenuBar(MAINMENUBARXMLFILE, consoleId);
96     }
97
98     /**
99      * Create graphic figure menubar from data in a XML file
100      * @param figureId the figure
101      */
102     public static void buildFigureMenuBar(String figureId) {
103         MenuBarBuilder.isParentValid = false;
104         buildMenuBar(GRAPHICSMENUBARXMLFILE, figureId);
105     }
106
107     /**
108      * Create children used in the menubar from data in a XML file
109      * @param fileToLoad XML file to load
110      * @param parentId the menubar parent
111      */
112     public static void buildMenuBar(String fileToLoad, String parentId) {
113
114         try {
115             MenuBarConfiguration menuBarConfig =
116                 (MenuBarConfiguration) buildMenuBar(new Class[] {MenuBarConfiguration.class}, fileToLoad);
117             menuBarConfig.addMenus(parentId);
118         } catch (IllegalArgumentException e) {
119             System.err.println(CANNOT_CREATE_MENUBAR);
120             System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
121         } catch (SAXException e) {
122             System.err.println(CANNOT_CREATE_MENUBAR);
123             System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
124         } catch (IOException e) {
125             System.err.println(CANNOT_CREATE_MENUBAR);
126             System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
127         } catch (ParserConfigurationException e) {
128             System.err.println(CANNOT_CREATE_MENUBAR);
129             System.err.println(FILE_NOT_FOUND + e.getLocalizedMessage());
130         }
131     }
132
133     /**
134      * Class used to read the XMl file
135      */
136     private static class MenuBarConfigurationHandler implements InvocationHandler {
137         protected static final String LABEL = "label";
138         protected static final String MENU = "menu";
139         protected static final String MNEMONIC = "mnemonic";
140         protected static final String SUBMENU = "submenu";
141         protected static final String SEPARATOR = "separator";
142         protected static final String ENABLED = "enabled";
143         protected static final String ACCELERATOR = "accelerator";
144         protected static final String CALLBACK = "callback";
145         protected static final String TYPE = "type";
146         protected static final String INSTRUCTION = "instruction";
147         protected static final String TRUE = "true";
148         protected static final String ICON = "icon";
149
150         private Document dom;
151         private Collection<String> internalMethodNames;
152
153
154         /**
155          * Constructor
156          * @param xmlFile XML file to load
157          * @throws SAXException can be thrown when an error occurs while reading the file
158          * @throws IOException can be thrown when an error occurs while accessing the file
159          * @throws ParserConfigurationException can be thrown when an error occurs while parsing the file
160          */
161         public MenuBarConfigurationHandler(String xmlFile) throws SAXException, IOException, ParserConfigurationException {
162
163             if (!new File(xmlFile).exists()) {
164                 throw new java.io.IOException();
165             }
166
167             // Build dictionary for internal method
168             internalMethodNames = new TreeSet<String>();
169             Method[] internalMethodes = this.getClass().getMethods();
170             for (Method method : internalMethodes) {
171                 internalMethodNames.add(method.getName());
172             }
173
174             // Build xml document for request
175             dom = ScilabDocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(xmlFile));
176         }
177
178         /**
179          * Invoke a proxy to get data
180          * @param proxy the proxy to call
181          * @param method the method to call
182          * @param args the arguments for the method
183          * @return the object read
184          * @throws IllegalAccessException thrown when the method called is inaccessible
185          * @throws InvocationTargetException thorwn when the method called threw an exception
186          * @throws NoSuchMethodException thrown when invoking a non-existing method
187          * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
188          */
189         public Object invoke(Object proxy, Method method, Object[] args)
190         throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
191             if (internalMethodNames.contains(method.getName())) {
192                 return getClass().getMethod(method.getName(), method.getParameterTypes()).invoke(this, args);
193             } else {
194                 return null;
195             }
196         }
197
198         /**
199          * Add menus to a menubar using Scilab MVC
200          * @param parentId the tab ID to which the menus will be added to
201          * @see org.scilab.modules.MenuBarConfiguration.utils.MenuBarConfiguration#addMenus(org.scilab.modules.gui.menubar.MenuBar)
202          */
203         public void addMenus(String parentId) {
204
205             // delete old menus
206             for (String childId : (String []) GraphicController.getController().getProperty(parentId, GraphicObjectProperties.__GO_CHILDREN__)) {
207                 if (GraphicController.getController().getProperty(childId, GraphicObjectProperties.__GO_TYPE__).equals(__GO_UIMENU__))
208                     GraphicController.getController().removeRelationShipAndDelete(childId);
209             }
210
211             NodeList menus = dom.getElementsByTagName(MENU);
212
213             for (int i = 0; i < menus.getLength(); i++) {
214                 // Create the menu
215                 String menuId = null;
216                 if (isParentValid) {
217                     menuId = GraphicController.getController().askObject(Type.UIMENU);
218                 } else {
219                     menuId = GraphicController.getController().askObject(Type.UIMENUMODEL);
220                 }
221
222                 // The menu is not visible in Scilab view by default
223                 GraphicController.getController().setProperty(menuId, __GO_HIDDEN__, true);
224
225                 // Set the label
226                 String menuLabel = Messages.gettext(menus.item(i).getAttributes().getNamedItem(LABEL).getNodeValue());
227                 GraphicController.getController().setProperty(menuId, __GO_UI_LABEL__, menuLabel);
228
229                 // Set the mnemonic if given
230                 if (menus.item(i).getAttributes().getNamedItem(MNEMONIC) != null) {
231                     String mnemonicString = menus.item(i).getAttributes().getNamedItem(MNEMONIC).getNodeValue();
232                     GraphicController.getController().setProperty(menuId, __GO_UI_MNEMONIC__, mnemonicString);
233                 }
234
235                 // Set the icon if given
236                 if (menus.item(i).getAttributes().getNamedItem(ICON) != null) {
237                     String iconName = menus.item(i).getNodeValue();
238                     GraphicController.getController().setProperty(menuId, __GO_UI_ICON__, iconName);
239                 }
240
241                 // Set the enable status if given
242                 if (menus.item(i).getAttributes().getNamedItem(ENABLED) != null) {
243                     boolean enabled = menus.item(i).getAttributes().getNamedItem(ENABLED).getNodeValue().equals(TRUE);
244                     GraphicController.getController().setProperty(menuId, __GO_UI_ENABLE__, enabled);
245                 }
246                 // Set the menu parent
247                 GraphicController.getController().setGraphicObjectRelationship(parentId, menuId);
248                 addSubMenus(menuId, i);
249             }
250         }
251
252         /**
253          * Read submenus data in the XML file and create them using Scilab MVC
254          * @param parentMenuId the parent menu UID for submenus
255          * @param index the index of the parent in menu list
256          */
257         public void addSubMenus(String parentMenuId, int index) {
258             Node submenu = dom.getElementsByTagName(MENU).item(index).getFirstChild();
259
260             boolean separator = false;
261
262             while (submenu != null) {
263                 if (submenu.getNodeName() == SEPARATOR) {
264                     // Add a separator
265                     separator = true;
266                 } else if (submenu.getNodeName() == SUBMENU) {
267                     // Create the menu
268                     String menuId = null;
269                     if (isParentValid) {
270                         menuId = GraphicController.getController().askObject(Type.UIMENU);
271                     } else {
272                         menuId = GraphicController.getController().askObject(Type.UIMENUMODEL);
273                     }
274
275                     // The menu is not visible in Scilab view by default
276                     GraphicController.getController().setProperty(menuId, __GO_HIDDEN__, true);
277
278                     // Set the menu parent
279                     GraphicController.getController().setGraphicObjectRelationship(parentMenuId, menuId);
280
281                     // First we have to read its attributes
282                     NamedNodeMap attributes = submenu.getAttributes();
283
284                     for (int i = 0; i < attributes.getLength(); i++) {
285                         if (attributes.item(i).getNodeName() == LABEL) {
286                             // Set the label
287                             String menuLabel = Messages.gettext(attributes.item(i).getNodeValue());
288                             GraphicController.getController().setProperty(menuId, __GO_UI_LABEL__, menuLabel);
289                         } else if (attributes.item(i).getNodeName() == MNEMONIC) {
290                             // Set the mnemonic
291                             String mnemonicString = attributes.item(i).getNodeValue();
292                             GraphicController.getController().setProperty(menuId, __GO_UI_MNEMONIC__, mnemonicString);
293                         } else if (attributes.item(i).getNodeName() == ENABLED) {
294                             // Set the enable status
295                             boolean enabled = attributes.item(i).getNodeValue().equals(TRUE);
296                             GraphicController.getController().setProperty(menuId, __GO_UI_ENABLE__, enabled);
297                         } else if (attributes.item(i).getNodeName() == ICON) {
298                             // Set the icon
299                             String iconName = attributes.item(i).getNodeValue();
300                             GraphicController.getController().setProperty(menuId, __GO_UI_ICON__, iconName);
301                         } else if (attributes.item(i).getNodeName() == ACCELERATOR) {
302                             // Set the accelerator
303                             String acceleratorString = attributes.item(i).getNodeValue();
304                             GraphicController.getController().setProperty(menuId, __GO_UI_ACCELERATOR__, acceleratorString);
305                         }
306                     }
307
308                     // Then we get its callback (if exists)
309                     Node callback = submenu.getFirstChild();
310                     while (callback != null) {
311                         if (callback.getNodeName() == CALLBACK) {
312                             NamedNodeMap cbAttributes = callback.getAttributes();
313                             String command = null;
314                             int commandType = CallBack.UNTYPED;
315                             for (int j = 0; j < cbAttributes.getLength(); j++) {
316                                 if (cbAttributes.item(j).getNodeName() == INSTRUCTION) {
317                                     command = cbAttributes.item(j).getNodeValue();
318                                 } else if (cbAttributes.item(j).getNodeName() == TYPE) {
319                                     commandType = Integer.parseInt(cbAttributes.item(j).getNodeValue());
320                                 }
321                             }
322                             if (command != null && commandType != CallBack.UNTYPED) {
323                                 GraphicController.getController().setProperty(menuId, __GO_CALLBACK__, command);
324                                 GraphicController.getController().setProperty(menuId, __GO_CALLBACKTYPE__, commandType);
325                             }
326                         } else if (callback.getNodeName() == SUBMENU) {
327                             addSubMenuItem(menuId, callback);
328                         }
329                         // Read next child
330                         callback = callback.getNextSibling();
331                     }
332                     // Manage separators
333                     if (separator) {
334                         GraphicController.getController().setProperty(menuId, __GO_UI_SEPARATOR__, true);
335                         separator = false;
336                     }
337
338
339                 }
340                 // Read next child
341                 submenu = submenu.getNextSibling();
342             }
343         }
344
345         /**
346          * Add submenu for menu
347          * @param parentMenuItemId object with this id will become a menu with subMenuItems
348          * @param node to get attributs of the menu
349          */
350         public void addSubMenuItem(String parentMenuItemId, Node node) {
351
352             NamedNodeMap attributes = node.getAttributes();
353
354             // Create the menu
355             String subMenuItemId = null;
356             if (isParentValid) {
357                 subMenuItemId = GraphicController.getController().askObject(Type.UIMENU);
358             } else {
359                 subMenuItemId = GraphicController.getController().askObject(Type.UIMENUMODEL);
360             }
361
362             // The menu is not visible in Scilab view by default
363             GraphicController.getController().setProperty(subMenuItemId, __GO_HIDDEN__, true);
364
365             // Set the menu parent
366             GraphicController.getController().setGraphicObjectRelationship(parentMenuItemId, subMenuItemId);
367
368             for (int i = 0; i < attributes.getLength(); i++) {
369                 if (attributes.item(i).getNodeName() == LABEL) {
370                     // Set the label
371                     String menuLabel = Messages.gettext(attributes.item(i).getNodeValue());
372                     GraphicController.getController().setProperty(subMenuItemId, __GO_UI_LABEL__, menuLabel);
373                 } else if (attributes.item(i).getNodeName() == MNEMONIC) {
374                     // Set the mnemonic
375                     String mnemonicString = attributes.item(i).getNodeValue();
376                     GraphicController.getController().setProperty(subMenuItemId, __GO_UI_MNEMONIC__, mnemonicString);
377                 } else if (attributes.item(i).getNodeName() == ICON) {
378                     String iconName = attributes.item(i).getNodeValue();
379                     GraphicController.getController().setProperty(subMenuItemId, __GO_UI_ICON__, iconName);
380                 } else if (attributes.item(i).getNodeName() == ENABLED) {
381                     // Set the enable status
382                     boolean enabled = attributes.item(i).getNodeValue().equals(TRUE);
383                     GraphicController.getController().setProperty(subMenuItemId, __GO_UI_ENABLE__, enabled);
384                 }
385             }
386
387             // Then we get its callback (if exists)
388             Node callback = node.getFirstChild();
389             while (callback != null) {
390                 if (callback.getNodeName() == CALLBACK) {
391                     NamedNodeMap cbAttributes = callback.getAttributes();
392                     String command = null;
393                     int commandType = CallBack.UNTYPED;
394                     for (int j = 0; j < cbAttributes.getLength(); j++) {
395                         if (cbAttributes.item(j).getNodeName() == INSTRUCTION) {
396                             command = cbAttributes.item(j).getNodeValue();
397                         } else if (cbAttributes.item(j).getNodeName() == TYPE) {
398                             commandType = Integer.parseInt(cbAttributes.item(j).getNodeValue());
399                         }
400                     }
401                     if (command != null && commandType != CallBack.UNTYPED) {
402                         GraphicController.getController().setProperty(subMenuItemId, __GO_CALLBACK__, command);
403                         GraphicController.getController().setProperty(subMenuItemId, __GO_CALLBACKTYPE__, commandType);
404                     }
405                 } else if (callback.getNodeName() == SUBMENU) {
406                     addSubMenuItem(subMenuItemId, callback);
407                 }
408                 // Read next child
409                 callback = callback.getNextSibling();
410             }
411         }
412     }
413 }