001 /* 002 Copyright (C) 2002-2003 Renaud Pawlak, Laurent Martelli. 003 004 This program is free software; you can redistribute it and/or modify 005 it under the terms of the GNU Lesser General Public License as 006 published by the Free Software Foundation; either version 2 of the 007 License, or (at your option) any later version. 008 009 This program is distributed in the hope that it will be useful, 010 but WITHOUT ANY WARRANTY; without even the implied warranty of 011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 GNU Lesser General Public License for more details. 013 014 You should have received a copy of the GNU Lesser General Public 015 License along with this program; if not, write to the Free Software 016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 017 USA */ 018 019 package org.objectweb.jac.aspects.gui; 020 021 import java.util.Collection; 022 import java.util.HashMap; 023 import java.util.Hashtable; 024 import java.util.List; 025 import java.util.Map; 026 import java.util.Vector; 027 import org.apache.log4j.Logger; 028 import org.objectweb.jac.core.rtti.AbstractMethodItem; 029 import org.objectweb.jac.core.rtti.ClassItem; 030 import org.objectweb.jac.core.rtti.MemberItem; 031 import org.objectweb.jac.core.rtti.MethodItem; 032 033 /** 034 * This interface allows the programmer to create simple customized GUIs. 035 * 036 * <p>The idea is to define sub-panels that can contain views on the 037 * objects of the application. The geometric placement of the 038 * sub-panel is defined by the <code>setSubPanesGeometry</code> method 039 * that has to be called at contruction-time. 040 * 041 * <p>Once the geometry is chosen, you can tell a pane to contain a 042 * view on a given object by using the <code>addReferenceToPane</code> 043 * method. 044 * 045 * <p>This class must be subclassed by the porgrammer of a JAC 046 * application to provide a customized GUI. 047 * 048 * @see GuiAC 049 * @see #setSubPanesGeometry(int,int,boolean[]) 050 * @see #addReferenceToPane(MemberItem,String,String[],String) */ 051 052 public class CustomizedGUI { 053 static Logger logger = Logger.getLogger("gui"); 054 055 //GuiAC guiAC = null; 056 057 // paneID -> {viewType,args[]} 058 Hashtable paneContents = new Hashtable(); 059 // paneID -> viewType 060 Hashtable paneContainers = new Hashtable(); 061 // (Integer)splitterID -> (Integer)location 062 Hashtable splitters = new Hashtable(); 063 // changed paneID -> invalid_paneID 064 Hashtable invalidPanes = new Hashtable(); 065 066 // WARNING: the following order is very important 067 /** The subpanes are separated by an horizontal splitter */ 068 public static final int HORIZONTAL = 0; 069 /** The upper subpanes are separated by a vertical splitter */ 070 public static final int HORIZONTAL_UP = 1; 071 /** The down subpanes are separated by a vertical splitter */ 072 public static final int HORIZONTAL_DOWN = 2; 073 /** The subpanes are separated by a vertical splitter */ 074 public static final int VERTICAL = 3; 075 /** The left subpanes are separated by an horizontal splitter */ 076 public static final int VERTICAL_LEFT = 4; 077 /** The right subpanes are separated by an horizontal splitter */ 078 public static final int VERTICAL_RIGHT = 5; 079 080 public static final String BOTTOM = "BOTTOM"; 081 public static final String TOP = "TOP"; 082 083 public void setInvalidPane(String changedPane, String invalidPane) { 084 invalidPanes.put(changedPane,invalidPane); 085 } 086 087 public String getInvalidPane(String changedPane) { 088 return (String)invalidPanes.get(changedPane); 089 } 090 091 /** 092 * Gets the number of sub-panes in the main window of the GUI. 093 * 094 * @return the number of panels 095 */ 096 int subPanesCount= 1; 097 public int getSubPanesCount() { 098 return subPanesCount; 099 } 100 101 int geometry = 0; 102 public int getGeometry() { 103 return geometry; 104 } 105 106 boolean[] scrollings = new boolean[] {false}; 107 public boolean[] getScrollings() { 108 return scrollings; 109 } 110 111 String application; 112 113 /** 114 * Get the value of application. 115 * @return value of application. 116 */ 117 public String getApplication() { 118 return application; 119 } 120 121 /** 122 * Set the value of application. 123 * @param v Value to assign to application. 124 */ 125 public void setApplication(String v) { 126 this.application = v; 127 } 128 129 130 /** 131 * Sets the geometric arrangement of the panes. 132 * 133 * <p><ul><li><code>subPanesCount == 4 && geometry == VERTICAL</code>: 134 * <pre> 135 * +-------+ 136 * | 0 | 2 | 137 * +---|---+ 138 * | 1 | 3 | 139 * +-------+ 140 * </pre> 141 * </li> 142 * <li><code>subPanesCount == 4 && geometry == HORIZONTAL</code>: 143 * <pre> 144 * +-------+ 145 * | 0 | 1 | 146 * +-------+ 147 * | 2 | 3 | 148 * +-------+ 149 * </pre> 150 * </li> 151 * <li><code>subPanesCount == 3 && geometry == HORIZONTAL_UP</code>: 152 * <pre> 153 * +-------+ 154 * | 0 | 1 | 155 * +-------+ 156 * | 2 | 157 * +-------+ 158 * </pre> 159 * </li> 160 * </li> 161 * <li><code>subPanesCount == 3 && geometry == HORIZONTAL_DOWN</code>: 162 * <pre> 163 * +-------+ 164 * | 2 | 165 * +-------+ 166 * | 0 | 1 | 167 * +-------+ 168 * </pre> 169 * </li> 170 * <li><code>subPanesCount == 3 && geometry == VERTICAL_LEFT</code>: 171 * <pre> 172 * +---+---+ 173 * | 0 | | 174 * +---| 2 | 175 * | 1 | | 176 * +---+---+ 177 * </pre> 178 * </li> 179 * <li><code>subPanesCount == 3 && geometry == VERTICAL_RIGHT</code>: 180 * <pre> 181 * +---+---+ 182 * | | 0 | 183 * | 2 |---+ 184 * | | 1 | 185 * +---+---+ 186 * </pre> 187 * </li> 188 * <li><code>subPanesCount == 2 && geometry == VERTICAL</code>: 189 * <pre> 190 * +---+---+ 191 * | | | 192 * | 0 | 1 | 193 * | | | 194 * +---+---+ 195 * </pre> 196 * </li> 197 * <li><code>subPanesCount == 2 && geometry == HORIZONTAL</code>: 198 * <pre> 199 * +-------+ 200 * | 0 | 201 * +-------+ 202 * | 1 | 203 * +-------+ 204 * </pre> 205 * </li> 206 * 207 * @param subPanesCount the number of subpanes in the window 208 * @param geometry the geometry = <code>VERTICAL || HORIZONTAL || 209 * VERTICAL_LEFT || VERTICAL_RIGHT || HORIZONTAL_UP || 210 * HORIZONTAL_DOWN</code> (see above) 211 * @param scrollings a set of string that tells if the sub-panes 212 * must be srollable or not 213 */ 214 public void setSubPanesGeometry(int subPanesCount, int geometry, 215 boolean[] scrollings) { 216 this.subPanesCount = subPanesCount; 217 this.geometry = geometry; 218 this.scrollings = scrollings; 219 } 220 221 /** 222 * Sets the object that should be opened in the given panel id. 223 * 224 * @param paneId the panel id (see the geometry to know its 225 * placement) 226 * @param viewType of the type of the view 227 * @param args parameters to pass to the view type constructor 228 * 229 * @see #setSubPanesGeometry(int,int,boolean[]) 230 */ 231 public void setPaneContent(String paneId, 232 String viewType, String[] args) { 233 paneContents.put(paneId,new PanelContent(viewType,args)); 234 } 235 236 /** 237 * Returns the type of the object to be displayed in a pane 238 */ 239 public String getPaneContentType(String paneID) { 240 return (String)((Object[])paneContents.get(paneID))[0]; 241 } 242 243 public String[] getPaneContentArgs(String paneID) { 244 return (String[])((Object[])paneContents.get(paneID))[1]; 245 } 246 247 public Map getPaneContents() { 248 return paneContents; 249 } 250 251 public void setPaneContainer(String paneId, String containerType) { 252 paneContainers.put(paneId,containerType); 253 } 254 255 public String getPaneContainer(String paneId) { 256 return (String)paneContainers.get(paneId); 257 } 258 259 public Map getPaneContainers() { 260 return paneContainers; 261 } 262 263 Hashtable subPaneContents = new Hashtable(); 264 265 public Map getSubPaneContents() { 266 return subPaneContents; 267 } 268 269 // PaneID -> Vector of FieldItem 270 HashMap targetContainers = new HashMap(); 271 272 /** 273 * Tells a referenced object to open in a given panel when a view 274 * is asked by the user (instead of opening in a popup). 275 * 276 * @param reference the reference (can be a method's result) 277 * @param viewType the type of the view that must be opened 278 * @param paneId the panel id where the view must be opened */ 279 280 public void addReferenceToPane(MemberItem reference, 281 String viewType, String[] viewParams, 282 String paneId) { 283 Vector containers = (Vector)targetContainers.get(reference); 284 if (containers==null) { 285 containers = new Vector(); 286 targetContainers.put(reference,containers); 287 } 288 containers.add(new Target(paneId,viewType,viewParams)); 289 } 290 291 public Map getTargetContainers() { 292 return targetContainers; 293 } 294 295 public List getFieldTargets(MemberItem reference) { 296 List result = null; 297 while (result==null && reference!=null) { 298 result = (List)targetContainers.get(reference); 299 ClassItem superClass = reference.getClassItem().getSuperclass(); 300 if (superClass!=null) 301 reference = superClass.getFieldNoError(reference.getName()); 302 else 303 reference = null; 304 } 305 return result; 306 } 307 308 int left; 309 int up; 310 int width; 311 int height; 312 313 public int getLeft() { 314 return left; 315 } 316 317 public int getUp() { 318 return up; 319 } 320 321 public int getWidth() { 322 return width; 323 } 324 325 public int getHeight() { 326 return height; 327 } 328 329 boolean geometrySet = false; 330 331 /** 332 * Returns true if the geometry of this GUI was set with 333 * <code>setPosition</code>. 334 * 335 * @see #setPosition(int,int,int,int) 336 */ 337 public boolean isGeometrySet() { 338 return geometrySet; 339 } 340 341 /** 342 * Sets the dimensions and position of the window regarding to the 343 * main screen. 344 * 345 * @param left left-border pixel 346 * @param up upper-border pixel 347 * @param width in percentage regarding the screen 348 * @param height in percentage regarding the screen 349 * @see #isGeometrySet() 350 */ 351 352 public void setPosition(int left, int up, int width, int height) { 353 this.up = up; 354 this.left = left; 355 this.width = width; 356 this.height = height; 357 geometrySet = true; 358 } 359 360 /** 361 * Sets a splitter location. 362 * 363 * <p>The splitter is referenced by its index going from the 364 * front-end splitter to the back-end splitters. For instance, in 365 * the case of a 3 sub-panel window, the 0 index references the 366 * splitter that splits the main window in two, the 1 index, the 367 * one that splits the half-window in two other smaller parts. 368 * 369 * @param splitterId the splitter's index 370 * @param location the position in pixel, regarding to the top/left 371 * component, a negative value means that the splitter should be 372 * set at the preferred sized of the inner components */ 373 374 public void setSplitterLocation(int splitterId, float location) { 375 splitters.put(new Integer(splitterId), new Float(location)); 376 } 377 378 public Map getSplitters() { 379 return splitters; 380 } 381 382 boolean hasStatusBar=false; 383 MethodItem statusBarMethod=null; 384 String statusPosition = BOTTOM; 385 386 public boolean hasStatusBar() { 387 return hasStatusBar; 388 } 389 390 public String getStatusPosition() { 391 return statusPosition; 392 } 393 394 public MethodItem getStatusBarMethod() { 395 return statusBarMethod; 396 } 397 398 /** 399 * Adds a status bar to the GUI. 400 */ 401 402 public void addStatusBar(MethodItem method,String position) { 403 hasStatusBar=true; 404 statusBarMethod = method; 405 statusPosition=position; 406 } 407 408 /* 409 public void showStatus(String message) { 410 if( statusBar == null ) { 411 System.out.println(message); 412 } else { 413 ((JLabel)statusBar.getComponent(0)).setText(message); 414 } 415 } 416 */ 417 418 /** 419 * Creates a new customized GUI. 420 * 421 * <p>When subclassing, a typical implementation of the constructor is: 422 * 423 * <pre class=code> 424 * super() 425 * // initialization calls such as setSubPanesGeometry 426 * // addReferenceToPane, setPosition 427 * ... 428 * show(); 429 * </pre> 430 * 431 * @see #setSubPanesGeometry(int,int,boolean[]) 432 * @see #addReferenceToPane(MemberItem,String,String[],String) 433 * @see #setPosition(int,int,int,int) 434 * @see #setSplitterLocation(int,float) 435 */ 436 public CustomizedGUI(String id) { 437 this.id = id; 438 } 439 440 String id; 441 public String getId() { 442 return id; 443 } 444 445 Hashtable menus = new Hashtable(); 446 447 public Hashtable getMenus() { 448 return menus; 449 } 450 451 public Menu getMenus(String name) { 452 Menu menu=(Menu)menus.get(name); 453 if(menu==null) { 454 menu=new Menu(); 455 menus.put(name,menu); 456 } 457 return menu; 458 } 459 460 public boolean hasMenuBar() { 461 return menus.size()>0; 462 } 463 464 /** 465 * Add an item in a menu 466 * 467 * @param menuPath the path of the menu where to add an item 468 * @param callback the method to call when this item is selected 469 * 470 * @see #addMenuSeparator(String,String[]) 471 */ 472 public void addMenuItem(String menuName, 473 String[] menuPath, 474 Callback callback) { 475 String[] path = new String[menuPath.length-1]; 476 System.arraycopy(menuPath,0,path,0,menuPath.length-1); 477 getMenu(menuName,path).put( 478 menuPath[menuPath.length-1],callback); 479 } 480 481 /** 482 * Add a separator in a menu 483 * 484 * @param menuName the name of the menu 485 * @param menuPath the path of the menu where to add a separator 486 * 487 * @see #addMenuItem(String,String[],Callback) 488 */ 489 public void addMenuSeparator(String menuName,String[] menuPath) { 490 getMenu(menuName,menuPath).addSeparator(); 491 } 492 493 Vector toolbar = new Vector(); 494 495 /** 496 * Add a button in the toolbar 497 * 498 * @param method the static method to call when the button is pressed 499 * 500 * @see #addToolbarSeparator() 501 * @see #addToolbarAction(String,AbstractMethodItem) 502 */ 503 public void addToolbarAction(AbstractMethodItem method) { 504 toolbar.add(new Callback(null,method, new Object [0])); 505 } 506 507 /** 508 * Add a button in the toolbar 509 * 510 * @param objectName name of the object on which to invoke the method 511 * @param method the method to call when the button is pressed 512 * 513 * @see #addToolbarSeparator() 514 * @see #addToolbarAction(AbstractMethodItem) 515 */ 516 public void addToolbarAction(String objectName, AbstractMethodItem method) { 517 toolbar.add(new Callback(objectName,method,new Object [0])); 518 } 519 520 /** 521 * Add a separator in the toolbar 522 * 523 * @see #addToolbarAction(AbstractMethodItem) 524 */ 525 public void addToolbarSeparator() { 526 toolbar.add(null); 527 } 528 529 /** 530 * Returns the toolbar of the customized GUI. 531 * 532 * @return a collection representing the tool. It contains 533 * AbstractMethodItem objects for buttons, and null for a 534 * separator. 535 */ 536 public Collection getToolbar() { 537 return toolbar; 538 } 539 540 public boolean hasToolBar() { 541 return toolbar.size()>0; 542 } 543 544 /** 545 * Find a menu defined by its path 546 */ 547 protected Menu getMenu(String menuName,String[] menuPath) { 548 Menu menu = getMenus(menuName); 549 for (int i=0; i<menuPath.length; i++) { 550 if (menu.containsKey(menuPath[i])) { 551 Object current = menu.get(menuPath[i]); 552 if (current instanceof Menu) { 553 menu = (Menu)current; 554 } else { 555 logger.warn("overriding menu item "+current); 556 Menu old = menu; 557 menu = new Menu(); 558 old.put(menuPath[i],menu); 559 } 560 } else { 561 Menu old = menu; 562 menu = new Menu(); 563 old.put(menuPath[i],menu); 564 } 565 } 566 return menu; 567 } 568 569 public void setMenuIcon(String menuName, 570 String[] menuPath, String icon) { 571 getMenu(menuName,menuPath).setIcon(icon); 572 } 573 574 public void setMenuPosition(String menuName,String position) { 575 getMenus(menuName).setPosition(position); 576 } 577 578 String welcomeTitle = "Welcome"; 579 String welcomeMessage = null; 580 String welcomeIcon = null; 581 582 public void setWelcomeMessage(String title,String message,String icon) { 583 this.welcomeTitle = title; 584 this.welcomeMessage = message; 585 this.welcomeIcon = icon; 586 } 587 588 String title; 589 public void setTitle(String title) { 590 this.title=title; 591 } 592 public String getTitle() { 593 return title; 594 } 595 596 Vector cssURLs=new Vector(); 597 public void addStyleSheetURL(String url) { 598 cssURLs.add(url); 599 } 600 601 public Vector getStyleSheetURLs() { 602 return cssURLs; 603 } 604 605 AbstractMethodItem onCloseHandler; 606 public void setOnCloseHandler(AbstractMethodItem handler) { 607 onCloseHandler = handler; 608 } 609 public AbstractMethodItem getOnCloseHandler() { 610 return onCloseHandler; 611 } 612 613 String icon; 614 public String getIcon() { 615 return icon; 616 } 617 public void setIcon(String icon) { 618 this.icon = icon; 619 } 620 }