001 // GraphLab Project: http://graphlab.sharif.edu 002 // Copyright (C) 2008 Mathematical Science Department of Sharif University of Technology 003 // Distributed under the terms of the GNU General Public License (GPL): http://www.gnu.org/licenses/ 004 package graphlab.ui.xml; 005 006 import graphlab.platform.core.AbstractAction; 007 import graphlab.platform.core.BlackBoard; 008 import graphlab.platform.extension.ExtensionLoader; 009 import graphlab.platform.lang.Pair; 010 import graphlab.platform.preferences.lastsettings.StorableOnExit; 011 import graphlab.ui.AbstractExtensionAction; 012 import graphlab.ui.UIUtils; 013 import graphlab.ui.actions.UIEventData; 014 import graphlab.ui.components.*; 015 import graphlab.ui.components.gmenu.GMenuBar; 016 import graphlab.ui.components.gmenu.GMenuItem; 017 import graphlab.ui.components.gmenu.KeyBoardShortCut; 018 import graphlab.ui.components.gmenu.KeyBoardShortCutProvider; 019 import graphlab.ui.components.gsidebar.GSidebar; 020 import graphlab.ui.extension.UIActionExtensionAction; 021 import org.xml.sax.Attributes; 022 import org.xml.sax.SAXException; 023 024 import javax.swing.*; 025 import java.awt.*; 026 import java.lang.reflect.Constructor; 027 import java.lang.reflect.InvocationTargetException; 028 import java.util.HashMap; 029 030 031 public class UIHandlerImpl implements UIHandler, StorableOnExit { 032 033 public static final boolean DEBUG = false; 034 public GToolbar toolbar; 035 public BlackBoard blackboard; 036 Class resourceClass; 037 HashMap<String, graphlab.platform.core.AbstractAction> actions = null; 038 /** 039 * determines the character which if put before a character in the string of the label, that character will be set to it's mnemonics 040 */ 041 public static final char menueIndexChar = '_'; 042 043 public UIHandlerImpl(GFrame gFrame, BlackBoard bb 044 , HashMap<String, graphlab.platform.core.AbstractAction> actions, Class resClass) { 045 this.blackboard = bb; 046 this.toolbar = gFrame.getToolbar(); 047 this.sidebar = gFrame.getSidebar(); 048 this.statusbar = gFrame.getStatusbar(); 049 //this.blackboard = gFrame.blackboard; 050 this.menubar = gFrame.getMenu(); 051 this.frame = gFrame; 052 this.actions = actions; 053 this.resourceClass = resClass; 054 // toolbar.add(lastToolbar); 055 } 056 057 //********** TOOLBARS handling --------------------- 058 private JToolBar lastToolbar = new JToolBar(); 059 private int lastToolbarPlace; 060 061 public void start_toolbar(final Attributes meta) throws SAXException { 062 // lastToolbar = new JToolBar(); 063 // lastToolbar.setFloatable(false); 064 lastToolbar = toolbar.createToolBar(); 065 lastToolbarPlace = extractPlace(meta); 066 if (DEBUG) System.err.println("start_toolbar: " + meta); 067 } 068 069 public void handle_tool(final Attributes meta) throws SAXException { 070 String label = meta.getValue("label"); 071 String icon = meta.getValue("image"); 072 String action = meta.getValue("action"); 073 String _place = meta.getValue("place"); 074 int place = -1; 075 if (_place != null) 076 place = Integer.parseInt(_place); 077 GButton b; 078 079 if (resourceClass != null && icon != null) 080 System.out.println("[handle_tool]" + icon + " : " + resourceClass.getResource(icon)); 081 082 if (icon == null || icon.equals("") || resourceClass == null || 083 resourceClass.getResource(icon) == null) 084 b = new GButton(label, icon, blackboard, action); 085 else 086 b = new GButton(label, resourceClass.getResource(icon), blackboard, action); 087 b.setBorderPainted(false); 088 // b.setBorder(new EmptyBorder(0, 1, 0, 2)); 089 090 lastToolbar.add(b); 091 if (DEBUG) System.err.println("handle_tool: " + meta); 092 } 093 094 public void end_toolbar() throws SAXException { 095 lastToolbar.add(new JSeparator(JSeparator.VERTICAL)); 096 toolbar.addIndexed(lastToolbar, lastToolbarPlace); 097 // toolbar.add(lastToolbar); 098 if (DEBUG) System.err.println("end_toolbar()"); 099 } 100 101 public void start_toolbars(Attributes meta) throws SAXException { 102 // lastToolbar = toolbar.getLastToolBar(); 103 } 104 105 public void end_toolbars() throws SAXException { 106 } 107 108 //***************** status handling -------------------- 109 public GStatusBar statusbar; 110 111 public void handle_bar(Attributes meta) throws SAXException { 112 String clazz = meta.getValue("class"); 113 String id = meta.getValue("id"); 114 System.out.println("Adding the Bar with id:" + id + " ,class:" + clazz); 115 Component _ = getComponent(clazz); 116 //we put the component in the blackboad and later (in Actions) we can fetch it if we like, i guess that it is the only way to do the loading of side bar and actions dynamically 117 UIUtils.setComponent(blackboard, id, _); 118 statusbar.addComponent(_); 119 } 120 121 //*****************menu handling------------------------ 122 public GMenuBar menubar; 123 private GFrame frame; 124 private JMenu currentMenu; 125 126 public void start_menues(Attributes meta) throws SAXException { 127 } 128 129 static HashMap<JMenuItem, Integer> places = new HashMap<JMenuItem, Integer>(); 130 131 private Pair<Integer, String> extractLabelInfo(String label) { 132 int index = Math.max(label.indexOf(menueIndexChar), 0); 133 label = label.replace(menueIndexChar + "", ""); 134 return new Pair<Integer, String>(index, label); 135 } 136 137 int lastMenuPlace; 138 139 public void start_submenu(final Attributes meta) throws SAXException { 140 String label = meta.getValue("label"); 141 String accel = meta.getValue("accelerator"); 142 Pair<Integer, String> lInfo = extractLabelInfo(label); 143 lastMenuPlace = extractPlace(meta); 144 int index = lInfo.first; 145 label = lInfo.second; 146 currentMenu = menubar.getUniqueMenu(label, lastMenuPlace); 147 // currentMenu = new JMenu(label); 148 149 KeyBoardShortCut shortcut = KeyBoardShortCutProvider.registerKeyBoardShortcut(accel, label, index); 150 if (shortcut != null) { 151 if (!shortcut.isAccelerator()) { 152 currentMenu.setMnemonic(shortcut.getKeyMnemonic()); 153 currentMenu.setDisplayedMnemonicIndex(shortcut.getKeyWordIndex()); 154 } 155 } 156 if (DEBUG) System.err.println("start_submenu: " + meta); 157 } 158 159 public void handle_menu(final Attributes meta) throws SAXException { 160 String label = meta.getValue("label"); 161 String action = meta.getValue("action"); 162 String accel = meta.getValue("accelerator"); 163 int place = extractPlace(meta); 164 if (label.equals("seperator_menu")) { 165 JSeparator js = new JSeparator(JSeparator.HORIZONTAL); 166 menubar.insert(currentMenu, js, place); 167 return; 168 } 169 Pair<Integer, String> lInfo = extractLabelInfo(label); 170 int index = lInfo.first; 171 label = lInfo.second; 172 173 174 GMenuItem item; 175 /** 176 * extension handling part: 177 * if the menu action was an extension removes the menu 178 * that the extension created in UI and set it to this menu. 179 */ 180 graphlab.platform.core.AbstractAction targetAction = actions.get(action); 181 if (targetAction instanceof AbstractExtensionAction) { 182 AbstractExtensionAction targetExt = (AbstractExtensionAction) targetAction; 183 // targetExt.removeCreatedUIComponents(); 184 // targetExt.listen4Event(UI.getUIEvent(action)); 185 item = targetExt.menuItem; 186 /** 187 * set the label properties according to XML 188 */ 189 // if (accel != null && !accel.equals("")) 190 // item.setAccelerator(accel); 191 // if (label != null && !label.equals("")) 192 item.setText(label); 193 //todo: BUG the mnemotic doesn't set 194 item.setMnemonic(index); 195 } else { 196 item = new GMenuItem(label, action, blackboard, accel, index); 197 } 198 199 menubar.insert(currentMenu, item, place); 200 if (DEBUG) System.err.println("handle_menu: " + meta); 201 } 202 203 private int extractPlace(Attributes meta) { 204 String _place = meta.getValue("place"); 205 int place = -1; //place -1 means no idea given for place, 206 try { 207 if (_place != null) 208 place = Integer.parseInt(_place); 209 } 210 catch (NumberFormatException e) { 211 System.err.println("the place given for menu " + meta.getValue("label") + " is not a valid number:" + _place); 212 } 213 return place; 214 } 215 216 public void end_submenu() throws SAXException { 217 // currentMenu.add(new JSeparator(JSeparator.VERTICAL)); 218 // GMenuBar.insert(currentMenu, new JSeparator(JSeparator.VERTICAL), -1); 219 //todo: add ability of adding JSeperator to UI 220 if (DEBUG) System.err.println("end_submenu()"); 221 } 222 223 public void end_menues() throws SAXException { 224 //pak kardan e menu e action e ezafe 225 GMenuBar menu = frame.getMenu(); 226 for (int i = 0; i < menu.getMenuCount(); i++) { 227 if (menu.getMenu(i).getText().equals("Actions") && menu.getMenu(i).getSubElements().length == 1) { 228 menu.remove(i); 229 return; 230 } 231 } 232 } 233 //***************** action handling ---------------------- 234 235 // If action has a group, then its default value for enable will be true, 236 // else it will true if enable property equals to true. 237 238 public void handle_action(Attributes meta) throws SAXException { 239 String clazz = meta.getValue("class"); 240 String id = meta.getValue("id"); 241 String group = meta.getValue("group"); 242 //todo: is it good to remove the action wich loaded twice, (2 of same action are working together) 243 System.err.println(" Adding action " + clazz + " (" + id + "," + group + ") ..."); 244 245 Class<?> clazzz = null; 246 try { 247 clazzz = Class.forName(clazz); 248 } catch (ClassNotFoundException e) { 249 System.err.println("the given class name can't be loaded: " + clazz); 250 e.printStackTrace(); 251 return; 252 } 253 boolean b = false; 254 graphlab.platform.core.AbstractAction x = loadAbstractAction(clazz); 255 256 /** 257 * handling extensions here 258 * they are not AbstractAction, but their handlers should 259 * return an AbstractAction(if it support the extension) 260 * and after that the program know the 261 * extension by that AbstractAction 262 */ 263 // if (clazzz.isAssignableFrom(Extension.class)) { 264 265 // for (ExtensionHandler s : ExtensionLoader.getRegisteredExtensionHandlers()) { 266 if (x == null) { 267 Object e = ExtensionLoader.loadExtension(clazzz); 268 // SETTINGS.registerSetting(e,"Extention Options"); //Moved to Extension Loader 269 if (e != null) 270 x = ExtensionLoader.handleExtension(blackboard, e); 271 } 272 // x = s.handle(blackboard, clazzz); 273 // b = b | x != null; 274 if (x != null) { 275 if (id == null) { 276 id = x.getLastListenedEventKey(); 277 id = id.replaceFirst(UIEventData.name(""), ""); 278 } 279 if (x instanceof UIActionExtensionAction) { 280 UIActionExtensionAction _ = (UIActionExtensionAction) x; 281 _.setUIEvent(id); 282 } 283 addAction(id, x, group); 284 // } 285 // } 286 // } 287 // if (b) { 288 // return; 289 } 290 if (x == null) { 291 System.err.println("Error while loading " + clazz + ". skiped."); 292 return; //error, skip it. 293 } 294 addAction(id, x, group); 295 } 296 297 private void addAction(String id, graphlab.platform.core.AbstractAction x, String group) { 298 if ((id != null) && !id.equals("")) 299 actions.put(id, x); 300 // if (group != null && !group.equals("")) { 301 // //configuration age group vojood nadashte bashe khodesh ijadesh mikone. inja be ghole omid "error prone hast" 302 // //todo: bara hamin be zehnam resid ke biaim bebinim esme gorooha masalan age kamtar az 2harf ekhtelaf daran, pas ehtemalan eshtebahe typi boode , ie jooraii kashf konim eroro :D 303 // conf.addToGroup(group, x); 304 // } 305 } 306 307 //****************** side bar handling ------------------------- 308 public GSidebar sidebar; 309 310 public void start_sidebar(Attributes meta) throws SAXException { 311 } 312 313 public void handle_sidebar(Attributes meta) throws SAXException { 314 String image = meta.getValue("image") + "";//to getting it not null 315 String clazz = meta.getValue("class"); 316 String id = meta.getValue("id"); 317 String label = meta.getValue("label"); 318 319 Component component = getComponent(clazz); 320 UIUtils.setComponent(blackboard, id, component); 321 if (resourceClass == null || resourceClass.getResource(image) == null) { 322 sidebar.addButton(image, component, label); 323 } else 324 sidebar.addButton(resourceClass.getResource(image), component, label); 325 } 326 327 public void end_sidebar() throws SAXException { 328 } 329 330 //************* body handling ------------------------------------ 331 332 public void handle_body(Attributes meta) throws SAXException { 333 String clazz = meta.getValue("class"); 334 String id = meta.getValue("id"); 335 Component gci = getComponent(clazz); 336 frame.getBody().setBodyPane(gci); 337 UIUtils.setComponent(blackboard, id, gci); 338 } 339 340 //************** utilities +++++++++++++++++++++ 341 342 AbstractAction loadAbstractAction(String abstractActionclazz) { 343 String clazz = abstractActionclazz; 344 if (!(clazz == null) && !(clazz.equals(""))) { 345 Class t = clazz2Class(clazz); 346 if (graphlab.platform.core.AbstractAction.class.isAssignableFrom(t)) { 347 Object[] o = {blackboard}; 348 try { 349 Constructor c = t.getConstructor(BlackBoard.class); 350 Object _ = c.newInstance(o); 351 return (graphlab.platform.core.AbstractAction) _; 352 } 353 catch (Exception e) { 354 // System.err.println("Error while loading " + clazz); 355 e.printStackTrace(); 356 } 357 } 358 } 359 // System.err.println("Error while loading " + clazz); 360 return null; 361 } 362 363 //todo: it is possible to also get a component from xml by it's direct class name, like javax.swing.JLabel . but i decided not to do it for cleaner codes! i am not sure is it good or not? 364 Component getComponent(String GComponentInterfaceClassName) { 365 String clazz = GComponentInterfaceClassName; 366 if (!(clazz == null) && !(clazz.equals(""))) { 367 Class t = clazz2Class(clazz); 368 Constructor c = null; 369 Object[] o = {blackboard}; 370 try { 371 c = t.getConstructor(BlackBoard.class); 372 } catch (NoSuchMethodException e) { 373 try { 374 c = t.getConstructor(new Class[]{}); 375 o = new Object[]{}; 376 } catch (NoSuchMethodException e1) { 377 System.err.println("the clazz " + clazz + "does not have a constructor(blackboard) or constructor(), how can i load it?"); 378 e1.printStackTrace(); 379 } 380 // e.printStackTrace(); 381 } 382 //if it had a constructor(blackboard) 383 try { 384 Object _ = c.newInstance(o); 385 if (_ instanceof GComponentInterface) { 386 //load was successfull 387 return ((GComponentInterface) _).getComponent(blackboard); 388 } else { 389 System.err.println("the class " + clazz + " doesn't implement the interface GComponentInterface, so it can't be put on the UI."); 390 } 391 } catch (InstantiationException e) { 392 System.err.println("There was an error while initializing the class" + clazz + "may be in it's constructor or in one of classes it instantiate in its constructor"); 393 e.printStackTrace(); 394 } catch (IllegalAccessException e) { 395 System.err.println("There was an error while initializing the class" + clazz + "may be in it's constructor or in one of classes it instantiate in its constructor"); 396 e.printStackTrace(); 397 } catch (InvocationTargetException e) { 398 System.err.println("There was an error while initializing the class" + clazz + "may be in it's constructor or in one of classes it instantiate in its constructor"); 399 e.getTargetException().printStackTrace(); 400 } 401 } 402 return null; 403 } 404 405 private Class clazz2Class(String clazz) { 406 Class t = null; 407 try { 408 t = Class.forName(clazz); 409 } catch (ClassNotFoundException e) { 410 System.err.println("the Class" + clazz + "didn't found in class path"); 411 e.printStackTrace(); 412 } 413 return t; 414 } 415 416 }