001 package sale.multiwindow; 002 003 import java.io.*; 004 import java.awt.*; 005 import java.util.*; 006 007 import javax.swing.*; 008 import javax.swing.event.ChangeEvent; 009 import javax.swing.event.ChangeListener; 010 import resource.util.ResourceManager; 011 import sale.*; 012 013 /** 014 * A MultiWindow is a {@link JFrame} capable managing all kinds of {@link Display Displays}.<br><br> 015 * 016 * There are three view modes: 017 * <table> 018 * <tr> 019 * <td>FRAME:</td> 020 * <td>Displays are {@link DisplayFrame DisplayFrames}, that is, every Display has its own window (JFrame)</td> 021 * </tr> 022 * <tr> 023 * <td>TAB:</td> 024 * <td>Displays are {@link TabbedFrame TabbedFrames}. The MultiWindow contains a row of tabs, 025 * each of which is a Display</td> 026 * </tr> 027 * <tr> 028 * <td>DESKTOP:</td> 029 * <td>Displays are {@link DesktopFrame DesktopFrames}. These are Windows that can be moved within the 030 * frame borders of the MultiWindow. (see {@link JDesktopPane})</td> 031 * </tr> 032 * </table> 033 * 034 * <p>The view mode can be chosen by client programs by calling the {@link #setViewMode} method or by the 035 * user using the "MultiWindow" menu.</p> 036 * 037 * <p>Displays can be added via the {@link #addSalesPointDisplay(SalesPoint)} method and removed with 038 * {@link #removeSalesPointDisplay(SalesPoint)}. When a display is added it will be saved until it is 039 * explicitly {@link #closeSalesPointDisplay(SalesPoint) closed}. 040 * 041 * <p>The displays will be updated automatically when {@link FormSheet FormSheets} or {@link MenuSheet MenuSheets} 042 * are set.</p> 043 * 044 * @author Sven Matznick 045 * @author Stephan Gambke 046 * @author Andreas Bartho 047 * @version 3.1 048 * @since v2.0 049 */ 050 public class MultiWindow extends JFrame implements ChangeListener { 051 052 /** 053 * ID for Serialization. 054 */ 055 private static final long serialVersionUID = 4030715423451727493L; 056 057 058 /** 059 * <p>Special {@link sale.Action Actions} are necessary for 060 * {@link MultiWindow MultiWindow}-{@link sale.MenuSheet MenuSheets} in order for the serialization to work 061 * properly. Whenever creating Actions that refer a MultiWindow directly, always use this class instead of 062 * simply deriving Action and let it have a direct reference to the MultiWindow. The latter will result in 063 * a NotSerializationException in MultiWindow when trying to make the Shop persistent.</p> 064 * 065 * <p>Implementing the action as an anonymous inner class extending MultiWindowAction may still lead to 066 * NotSerializableExceptions being thrown. Therefore, attempt to implement the actions as static 067 * top-level classes derived from MultiWindowAction.</p> 068 */ 069 public static abstract class MultiWindowAction implements sale.Action { 070 071 /** 072 * Overriding the serialization behavior of Actions to avoid references to MultiWindow being 073 * serialized.<br> 074 * This method is not called directly but automatically on serialization. 075 */ 076 private void writeObject(ObjectOutputStream oos) throws IOException { 077 oos.defaultWriteObject(); 078 } 079 080 /** 081 * The MultiWindow referenced by this Action. {@link #doAction} must always use this reference instead of 082 * a reference created via the inner class mechanism. 083 */ 084 protected transient MultiWindow m_mwReference; 085 086 /** 087 * Create a new MultiWindowAction referencing the given MultiWindow. 088 */ 089 public MultiWindowAction(MultiWindow mwReference) { 090 super(); 091 m_mwReference = mwReference; 092 //register action, otherwise it will be lost after save/restore 093 m_mwReference.registerAction(this); 094 } 095 } 096 097 098 099 100 /** 101 * The main Component for this MultiWindow. Will be set according to view mode. 102 */ 103 private JComponent m_jcShopComponent; 104 105 /** 106 * The main Component for this MultiWindow in FRAME view mode, i.e. Displays are DisplayFrames. 107 */ 108 private JPanel m_jpFramePane; 109 110 /** 111 * The main Component for this MultiWindow in TAB view mode, i.e. Displays are TabbedFrames. 112 */ 113 private IconTabbedPane m_jtpTabPane; 114 115 /** 116 * The main Component for this MultiWindow in DESKTOP view mode, i.e. Displays are DesktopFrames. 117 */ 118 private JDesktopPane m_jdpDesktopPane; 119 120 /** 121 * Current view mode. 122 * 123 * @serial 124 */ 125 private int m_nViewMode = NONE; 126 127 /** 128 * Current frame arrangement. Frames can be arranged OVERLAPPED, HORIZONTALLY or VERTICALLY. 129 * 130 * @serial 131 */ 132 private int m_nArrangement = OVERLAPPED; 133 134 /** 135 * The map of currently open DisplayFrames. The keys are the frames' ID. 136 */ 137 private HashMap<Integer, JDisplayFrame> m_mpjdfDisplayFrames = new HashMap<Integer, JDisplayFrame>(); 138 139 /** 140 * The map of currently open TabbedFrames. The keys are the frames' ID. 141 */ 142 private HashMap<Integer, JTabDisplay> m_mpjtdTabDisplays = new HashMap<Integer, JTabDisplay>(); 143 144 /** 145 * The map of currently open DesktopFrames. The keys are the frames' ID. 146 */ 147 private HashMap<Integer, JInternalDisplay> m_mpjidInternalDisplays = new HashMap<Integer, JInternalDisplay>(); 148 149 /** 150 * The currently set global MenuSheet. 151 * 152 * @serial 153 */ 154 private MenuSheet m_msCurrentMenuSheet; 155 156 /** 157 * The ID of the currently selected frame. Used when arranging frames 158 * 159 * @see #arrangeFrames 160 * @serial 161 */ 162 private Integer m_nSelectedFrame; 163 164 /** 165 * The MultiWindowActions registered with this MultiWindow. Necessary to keep reference to the actions 166 * after save/restore 167 * 168 * @serial 169 */ 170 private LinkedList<MultiWindowAction> m_lActions = new LinkedList<MultiWindowAction>(); 171 172 /** 173 * Contains the tag of the MultiWindow's MenuSheet, in front of which the active SalesPoint's MenuSheet should be 174 * merged when in tabbed view mode.<br> 175 * The default implementation is <code>null</code>, so SalesPoint's menus appear behind all Shop's menus. 176 * It is also possible to use {@link #setMergeBefore(String)} to change this variable's value. 177 * 178 * @override Sometimes if you want SalesPoint's menus to be displayed at a different position. 179 * @see #setSecondMenuSheet 180 * 181 * @serial 182 */ 183 protected String m_sMergeBefore = null; 184 185 /** 186 * Reference to the Shop for which the MultiWindow was created. 187 */ 188 private Shop m_shShop; 189 190 /** 191 * The MultiWindow is not serializable. Instead, use the {@link #save} method. 192 * 193 * @override Never 194 * @throws IOException always 195 */ 196 197 private void writeObject(ObjectOutputStream oos) throws IOException { 198 throw new java.io.NotSerializableException("sale.multiwindow.MultiWindow"); 199 } 200 201 /** 202 * The MultiWindow is not serializable. Instead, use the {@link #load} method. 203 * 204 * @override Never 205 * @throws IOException always 206 */ 207 private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { 208 throw new java.io.NotSerializableException("sale.multiwindow.MultiWindow"); 209 } 210 211 /** 212 * Saves the current state of the MultiWindow. 213 * 214 * @param oos the stream into which to save the state. 215 * 216 * @override Sometimes Override this method whenever you added attributes that need to be saved when 217 * making the Shop persistent. Should be overridden along with load(). 218 * 219 * @exception IOException if an error occurs while saving. 220 */ 221 public void save(ObjectOutputStream oos) throws IOException { 222 oos.writeInt(m_nViewMode); 223 oos.writeInt(m_nArrangement); 224 oos.writeObject(m_sMergeBefore); 225 oos.writeObject(m_nSelectedFrame); 226 oos.writeObject(m_msCurrentMenuSheet); 227 oos.writeObject(m_lActions); 228 oos.writeObject(getTitle()); 229 oos.writeObject(getBounds()); 230 oos.writeBoolean(isVisible()); 231 } 232 233 /** 234 * Loads the state of the MultiWindow from a stream. 235 * 236 * @override Sometimes Override this method whenever you added attributes. Should be overridden along 237 * with save(). 238 * 239 * @param ois the input stream to restore the state from. 240 * 241 * @exception IOException if an error occurs while reading. 242 * @exception ClassNotFoundException if an error occurs while reading. 243 */ 244 @SuppressWarnings("unchecked") 245 public void load(ObjectInputStream ois) throws IOException, ClassNotFoundException { 246 //read values in the same order as they have been written in save() and assign them 247 final int nViewMode = ois.readInt(); 248 prepareNewContentPane(nViewMode); 249 m_nArrangement = ois.readInt(); 250 m_sMergeBefore = (String)ois.readObject(); 251 m_nSelectedFrame = (Integer)ois.readObject(); 252 m_msCurrentMenuSheet = (MenuSheet)ois.readObject(); 253 setMenuSheet(m_msCurrentMenuSheet); 254 m_lActions = (LinkedList<MultiWindowAction>)ois.readObject(); 255 setTitle((String)ois.readObject()); 256 try { 257 for (Iterator i = m_lActions.iterator(); i.hasNext(); ) { 258 ((MultiWindowAction)i.next()).m_mwReference = this; 259 } 260 } 261 catch (Throwable t) {} 262 263 final Rectangle rcBounds = (Rectangle)ois.readObject(); 264 final boolean fVisible = ois.readBoolean(); 265 //define actions to be executed after the Shop has been fully deserialized 266 ois.registerValidation(new ObjectInputValidation() { 267 public void validateObject() throws InvalidObjectException { 268 try { 269 m_nViewMode = nViewMode; 270 } 271 catch (Throwable t) { 272 throw new InvalidObjectException(t.toString()); 273 } 274 275 setBounds(rcBounds); 276 setVisible(fVisible); 277 validate(); 278 } 279 } 280 , OIV.MULTIWINDOW_PRIO); 281 } 282 283 /** 284 * Internal communications method: Register a MultiWindowAction so that it can be properly serialized. 285 * Externally implemented MultiWindowActions will otherwise be lost after save/restore. 286 * 287 * @param mwa the action to be registered 288 * 289 * @override Never 290 */ 291 void registerAction(MultiWindowAction mwa) { 292 m_lActions.add(mwa); 293 } 294 295 /** 296 * Creates a new MultiWindow for the given Shop and initializes the viewmode. The MultiWindow's caption 297 * will be the {@link Shop#getShopFrameTitle Shop's frame title}. 298 * 299 * @param sShop the Shop for which the MultiWindow is created 300 * @param nViewMode the initial view mode 301 */ 302 public MultiWindow(Shop sShop, int nViewMode) { 303 super(sShop.getShopFrameTitle()); 304 m_shShop = sShop; 305 m_nViewMode = nViewMode; 306 prepareNewContentPane(m_nViewMode); 307 setDefaultMenuSheet(); 308 pack(); 309 } 310 311 /** 312 * Returns the MultiWindow management MenuSheet for this MultiWindow. 313 * 314 * <p>The MultiWindow management MenuSheet contains the following items for managing the look of the 315 * MultiWindow:</p> 316 * 317 * <table border=1> 318 * <tr> 319 * <th>Item text</th> 320 * <th>Item tag</th> 321 * <th>Item action</th> 322 * <th>Comments</th> 323 * </tr> 324 * <tr> 325 * <td>Window</td> 326 * <td>{@link #WINDOW_MENU_TAG}</td> 327 * <td>Change to Window view. Executes <code>WindowAction</code>.</td> 328 * <td>All SalesPoints will have their displays converted to {@link DisplayFrame DisplayFrames}, i.e. 329 * all SalesPoints are shown in a separate window.</td> 330 * </tr> 331 * <tr> 332 * <td>Tabbed</td> 333 * <td>{@link #TABBED_MENU_TAG}</td> 334 * <td>Change to Tab view. Executes {@link TabAction}.</td> 335 * <td>All SalesPoints will have their displays converted to {@link TabbedFrame TabbedFrames}, i.e. 336 * the MultiFrame will contain a row of tabs each of which displays a SalesPoint. The SalesPoint's 337 * menus will be merged with the Shop's menu.<br> 338 * See also {@link #setSecondMenuSheet} 339 * </td> 340 * </tr> 341 * <tr> 342 * <td>Desktop</td> 343 * <td>{@link #DESKTOP_MENU_TAG}</td> 344 * <td>Change to Desktop view. Executes {@link DesktopAction}.</td> 345 * <td>All SalesPoints will have their displays converted to {@link DesktopFrame DesktopFrames}, 346 * i.e. all SalesPoints are shown in a separate window. But in contrast to Window view mode the 347 * SalesPoints cannot moved around the whole screen but only within the borders of the MultiWindow.</td> 348 * </tr> 349 * <tr> 350 * <td><i>Separator</i></td> 351 * <td>{@link #SEPARATOR_TAG}</td> 352 * <td>None.</td> 353 * <td> </td> 354 * </tr> 355 * <tr> 356 * <td>Cascade</td> 357 * <td>{@link #CASCADE_MENU_TAG}</td> 358 * <td>Cascade the Displays. Is ignored in tabbed view mode. Executes {@link CascadeAction}.</td> 359 * <td> </td> 360 * </tr> 361 * <tr> 362 * <td>Tile horizontally</td> 363 * <td>{@link #TILE_HORIZ_MENU_TAG}</td> 364 * <td>Tile internal frames horizontally. Is ignored in tabbed view mode. 365 * Executes {@link TileHorizontallyAction}.</td> 366 * <td> </td> 367 * </tr> 368 * <tr> 369 * <td>Tile vertically</td> 370 * <td>{@link #TILE_VERT_MENU_TAG}</td> 371 * <td>Tile internal frames vertically. Is ignored in tabbed view mode. 372 * Executes {@link TileVerticallyAction}.</td> 373 * <td> </td> 374 * </tr> 375 * </table> 376 * 377 * <p>This method is used by {@link #setDefaultMenuSheet}.</p> 378 * 379 * <p><stront>Note:</strong> When adding new MenuSheetItems make sure the {@link sale.Action Actions} are 380 * not implemented as anonymous inner classes as this causes problems on serialization. 381 * See {@link MultiWindow.MultiWindowAction MultiWindowAction} for details. 382 * 383 * @override Sometimes 384 * 385 * @return a MenuSheet representing the default MultiWindow menu 386 */ 387 public MenuSheet getMultiWindowMenuSheet() { 388 MenuSheet msMWMenu = new MenuSheet("MultiWindow", MULTIWINDOW_MENU_TAG); 389 /* 390 * anonymous implementation of Actions not possible, this causes MultiWindow to be serialized when 391 * saving the Shop, but serialization (i.e. executing writeObject() of class MultiWindow) is forbidden. 392 */ 393 MenuSheetItem msiWindow = new MenuSheetItem("Window", WINDOW_MENU_TAG, new WindowAction(this)); 394 MenuSheetItem msiTab = new MenuSheetItem("Tabbed", TABBED_MENU_TAG, new TabAction(this)); 395 MenuSheetItem msiDesktop = new MenuSheetItem("Desktop", DESKTOP_MENU_TAG, new DesktopAction(this)); 396 MenuSheetItem msiCascade = new MenuSheetItem("Cascade", CASCADE_MENU_TAG, new CascadeAction(this)); 397 MenuSheetItem msiHoriz = new MenuSheetItem("Tile horizontally", TILE_HORIZ_MENU_TAG, new TileHorizontallyAction(this)); 398 MenuSheetItem msiVert = new MenuSheetItem("Tile vertically", TILE_VERT_MENU_TAG, new TileVerticallyAction(this)); 399 400 msiCascade.setDefaultIcon(CASCADE_ICON); 401 msiHoriz.setDefaultIcon(HORIZONTAL_ICON); 402 msiVert.setDefaultIcon(VERTICAL_ICON); 403 404 msMWMenu.add(msiWindow); 405 msMWMenu.add(msiTab); 406 msMWMenu.add(msiDesktop); 407 msMWMenu.add(new MenuSheetSeparator(SEPARATOR_TAG)); 408 msMWMenu.add(msiCascade); 409 msMWMenu.add(msiHoriz); 410 msMWMenu.add(msiVert); 411 412 return msMWMenu; 413 } 414 415 /** 416 * Sets the default MenuSheet. 417 * 418 * <p>This method uses {@link #getMultiWindowMenuSheet} to get the MenuSheet to be set. The actual setting 419 * of the MenuSheet is performed by {@link #setMenuSheet}</p> 420 * 421 * @override Never 422 */ 423 public void setDefaultMenuSheet() { 424 MenuSheet msContainer = new MenuSheet("MWMenuBar", "__TAG:_MWMENUBAR_"); 425 msContainer.add(getMultiWindowMenuSheet()); 426 setMenuSheet(msContainer); 427 } 428 429 /** 430 * Sets the given MenuSheet as a global MenuSheet in the MultiWindow. 431 * 432 * @param msNewMenuSheet the MenuSheet to be set 433 * 434 * @override Never 435 */ 436 public void setMenuSheet(MenuSheet msNewMenuSheet) { 437 if (m_msCurrentMenuSheet != null) { 438 m_msCurrentMenuSheet.mergePeers(null, null); 439 m_msCurrentMenuSheet.setVisible(false); 440 } 441 442 m_msCurrentMenuSheet = msNewMenuSheet; 443 444 if (m_msCurrentMenuSheet != null) { 445 JMenuBar jmbNewMB = msNewMenuSheet.getMenuBar(); 446 m_msCurrentMenuSheet.setVisible(true); 447 setJMenuBar(jmbNewMB); 448 } else { 449 setJMenuBar(null); 450 } 451 452 validate(); 453 } 454 455 /** 456 * Merges the MultiWindow's MenuSheet with a second one. 457 * 458 * <p>The position of the inserted MenuSheet is 459 * determined from the {@link #m_sMergeBefore} variable. The MultiWindow's very MenuSheet object will 460 * not be changed, only the MenuSheet's view is altered.</p> 461 * 462 * <p>This method is used to insert SalesPoint's MenuSheets into the MultiFrame's MenuSheet when in tabbed 463 * view mode, because tabs cannot contain menus. The actual merging is done by 464 * {@link MenuSheet#mergePeers}.</p> 465 * 466 * @param ms The MenuSheet to be added. 467 * 468 * @see #setMergeBefore 469 * 470 * @override Never 471 */ 472 public void setSecondMenuSheet(MenuSheet ms) { 473 JMenuBar jmb = m_msCurrentMenuSheet.mergePeers(ms, null); 474 setJMenuBar(jmb); 475 m_msCurrentMenuSheet.setVisible(true); 476 validate(); 477 repaint(); 478 } 479 480 /** 481 * Sets the value of {@link #m_sMergeBefore}. 482 * <p>This variable contains a menu tag, in front of which a second MenuSheet will be added when executing 483 * {@link #setSecondMenuSheet} 484 * 485 * @param sMergeBefore the menu's tag in front of which a second MenuSheet should be added 486 * 487 * @override Never 488 */ 489 protected void setMergeBefore(String sMergeBefore) { 490 m_sMergeBefore = sMergeBefore; 491 } 492 493 /** 494 * Gets the current global MenuSheet. 495 * 496 * @override Never 497 */ 498 public MenuSheet getCurrentMenuSheet() { 499 return m_msCurrentMenuSheet; 500 } 501 502 /** 503 * Gets the current view mode. 504 * 505 * @return an int value representing the view mode 506 * 507 * @override Never 508 * 509 * @see #WINDOW_VIEW 510 * @see #TABBED_VIEW 511 * @see #DESKTOP_VIEW 512 */ 513 public int getViewMode() { 514 return m_nViewMode; 515 } 516 517 /** 518 * Sets a new view mode. 519 * 520 * <p>When setting a new view mode, all open displays are closed, the MultiWindow's content pane is prepared 521 * for the new view mode and all displays that have been closed are converted and added according to the 522 * new view mode. 523 * 524 * @param viewMode the view mode to be set 525 * 526 * @override Never 527 * 528 * @see #WINDOW_VIEW 529 * @see #TABBED_VIEW 530 * @see #DESKTOP_VIEW 531 */ 532 public void setViewMode(final int viewMode) { 533 try { 534 SwingUtilities.invokeAndWait(new Thread() { 535 public void run() { 536 removeAllDisplays(); 537 m_nViewMode = viewMode; 538 prepareNewContentPane(viewMode); 539 addAllDisplays(); 540 } 541 }); 542 } 543 catch (Exception e) { 544 e.printStackTrace(); 545 } 546 } 547 548 /** 549 * Prepares the MultiWindow's content pane for a new view mode. 550 * 551 * <p>In fact, not the content pane directly is set. Instead an appropriate JComponent is added to the 552 * content pane.</p> 553 * <table border=1> 554 * <tr> 555 * <th>View mode</th> 556 * <th>Set Component</th> 557 * </tr> 558 * <tr> 559 * <td>WINDOW_VIEW</td> 560 * <td>Adds the JComponent that is returned by {@link #getFramePane}, by default an empty JPanel.</td> 561 * </tr> 562 * <tr> 563 * <td>TABBED_VIEW</td> 564 * <td>Adds the JComponent that is returned by {@link #getTabbedPane}, by default a 565 * {@link IconTabbedPane}.</td> 566 * </tr> 567 * <tr> 568 * <td>DESKTOP_VIEW</td> 569 * <td>Adds the JComponent that is returned by {@link #getDesktopPane}, by default a 570 * {@link JDesktopPane}.</td> 571 * </tr> 572 * </table> 573 * @param viewMode the view mode to be prepared 574 * 575 * @override Never 576 */ 577 protected void prepareNewContentPane(int viewMode) { 578 getContentPane().removeAll(); 579 switch(viewMode) { 580 case WINDOW_VIEW: 581 m_jcShopComponent = getFramePane(); 582 break; 583 case TABBED_VIEW: 584 m_jcShopComponent = getTabbedPane(); 585 break; 586 case DESKTOP_VIEW: 587 m_jcShopComponent = getDesktopPane(); 588 } 589 getContentPane().add(m_jcShopComponent); 590 getContentPane().repaint(); 591 } 592 593 /** 594 * Returns the IconTabbedPane to be added to the content pane in TABBED_VIEW view mode. 595 * 596 * @override Never, override {@link #createTabbedPane} instead. 597 */ 598 protected IconTabbedPane getTabbedPane() { 599 if (m_jtpTabPane == null) { 600 m_jtpTabPane = createTabbedPane(); 601 m_jtpTabPane.addChangeListener(this); 602 } 603 return m_jtpTabPane; 604 } 605 606 /** 607 * Creates and returns the IconTabbedPane which is used as content pane in TABBED_VIEW view mode. 608 * 609 * @override Sometimes if you need a customized JPanel. 610 */ 611 protected IconTabbedPane createTabbedPane() { 612 return new IconTabbedPane() { 613 private static final long serialVersionUID = 2653068446177815812L; 614 public int getIconClicked() { 615 int i = super.getIconClicked(); 616 TabbedFrame tf = (TabbedFrame)m_jtpTabPane.getComponentAt(i); 617 tf.exitForm(); 618 return i; 619 } 620 }; 621 } 622 623 624 /** 625 * Returns the JDesktopPane to be added to the content pane in DESKTOP_VIEW view mode. 626 * 627 * @override Never, override {@link #createDesktopPane} instead. 628 */ 629 protected JDesktopPane getDesktopPane() { 630 if (m_jdpDesktopPane == null) { 631 m_jdpDesktopPane = createDesktopPane(); 632 } 633 return m_jdpDesktopPane; 634 } 635 636 /** 637 * Creates and returns the JPanel which is used as content pane in DESKTOP_VIEW view mode. 638 * 639 * @override Sometimes if you need a customized JPanel. 640 */ 641 protected JDesktopPane createDesktopPane() { 642 return new JDesktopPane(); 643 } 644 645 646 /** 647 * Returns the JPanel to be added to the content pane in WINDOW_VIEW view mode. 648 * 649 * @override Never, override {@link #createFramePane} instead. 650 */ 651 protected JPanel getFramePane() { 652 if (m_jpFramePane == null) { 653 m_jpFramePane = createFramePane(); 654 } 655 return m_jpFramePane; 656 } 657 658 /** 659 * Creates and returns the JPanel which is used as content pane in WINDOW_VIEW view mode. 660 * @override Sometimes if you need a customized JPanel. 661 */ 662 protected JPanel createFramePane() { 663 return new JPanel(); 664 } 665 666 667 /** 668 * Sets the displays of all open SalesPoints according to the current view mode. 669 * 670 * <p>This method iterates over the list of active SalesPoints (see {@link Shop#getSalesPoints}) and calls 671 * {@link #addSalesPointDisplay} for each one. 672 * 673 * @override Never 674 */ 675 protected void addAllDisplays() { 676 Iterator it = m_shShop.getSalesPoints().iterator(); 677 while (it.hasNext()) { 678 SalesPoint sp = (SalesPoint)it.next(); 679 addSalesPointDisplay(sp); 680 } 681 } 682 683 /** 684 * Closes the displays of all open SalesPoints. 685 * 686 * <p>This method iterates over the list of active SalesPoints (see {@link Shop#getSalesPoints}) and calls 687 * {@link #removeSalesPointDisplay} for each one. 688 * 689 * @override Never 690 */ 691 protected void removeAllDisplays() { 692 Iterator it = m_shShop.getSalesPoints().iterator(); 693 while (it.hasNext()) { 694 SalesPoint sp = (SalesPoint)it.next(); 695 removeSalesPointDisplay(sp); 696 } 697 } 698 699 /** 700 * Opens a display for a SalesPoint according to the current view mode. 701 * 702 * <p>Depending on the view mode set, this method calls {@link #addSalesPoint_Window}, 703 * {@link #addSalesPoint_Tab} or {@link #addSalesPoint_InternalFrame}.</p> 704 * 705 * @param sp the SalesPoint for which to add a Display. 706 * 707 * @override Sometimes if there are additional view modes that require a special add() method to be 708 * invoked for adding. 709 */ 710 public void addSalesPointDisplay(final SalesPoint sp) { 711 switch(getViewMode()) { 712 case WINDOW_VIEW: addSalesPoint_Window(sp); break; 713 case TABBED_VIEW: addSalesPoint_Tab(sp); break; 714 case DESKTOP_VIEW: addSalesPoint_InternalFrame(sp); break; 715 } 716 } 717 718 719 /** 720 * Closes a display for a SalesPoint. The SalesPoint itself will not be closed. 721 * 722 * <p>Depending on the view mode set, this method calls {@link #addSalesPoint_Window(SalesPoint)}, 723 * {@link #addSalesPoint_Tab(SalesPoint)} or {@link #addSalesPoint_InternalFrame(SalesPoint)}.</p> 724 * 725 * <p>This method assumes, that only displays that match the current view mode are set, e.g. no 726 * <code>JDisplayFrame</code> must be set if the view mode is tabbed view and <code>TabbedFrame</code>s 727 * are expected.</p> 728 * 729 * @param sp the SalesPoint for which to add a Display. 730 * 731 * @override Sometimes if there are additional view modes that require a special add() method to be 732 * invoked for removing. 733 */ 734 private void removeSalesPointDisplay(SalesPoint sp) { 735 switch(getViewMode()) { 736 case WINDOW_VIEW: removeSalesPoint_Window(sp); break; 737 case TABBED_VIEW: removeSalesPoint_Tab(sp); break; 738 case DESKTOP_VIEW: removeSalesPoint_InternalFrame(sp); break; 739 } 740 741 } 742 743 /** 744 * Closes a SalesPoint's display as {@link #removeSalesPointDisplay(SalesPoint)} does. Additionally 745 * all displays that have been saved for this SalesPoint will be deleted. 746 * @param sp the SalesPoint for which to close the display. 747 */ 748 public void closeSalesPointDisplay(SalesPoint sp) { 749 removeSalesPointDisplay(sp); 750 Integer key = new Integer(sp.getID()); 751 m_mpjdfDisplayFrames.remove(key); 752 m_mpjtdTabDisplays.remove(key); 753 m_mpjidInternalDisplays.remove(key); 754 } 755 756 /** 757 * Opens a {@link DisplayFrame DisplayFrame} for a SalesPoint. 758 * 759 * <p>This includes {@link #setAppropriateDisplay converting the Display} that is currently 760 * assigned to the SalesPoint and making it visible.</p> 761 * @param sp the SalesPoint for which to open a Display. 762 */ 763 private void addSalesPoint_Window(SalesPoint sp) { 764 try { 765 if (sp.getDisplay() != null) { 766 setAppropriateDisplay(sp, WINDOW_VIEW); 767 } 768 } 769 catch (InterruptedException ex) { 770 } 771 JDisplayFrame jdf = (JDisplayFrame)sp.getDisplay(); 772 if (jdf == null) { 773 jdf = (JDisplayFrame)getWindow(sp); 774 sp.attach(jdf); 775 } 776 777 if (sp.getSalesPointFrameBounds() != null) { 778 jdf.setBounds(sp.getSalesPointFrameBounds()); 779 } 780 781 if (m_shShop.getShopState() == Shop.RUNNING) { 782 jdf.setVisible(true); 783 } 784 m_mpjdfDisplayFrames.put(new Integer(sp.getID()), jdf); 785 } 786 787 /** 788 * Closes the {@link DisplayFrame} of a SalesPoint. 789 * 790 * @param sp the SalesPoint for which to close the display. 791 */ 792 private void removeSalesPoint_Window(SalesPoint sp) { 793 JDisplayFrame jdf = (JDisplayFrame)sp.getDisplay(); 794 jdf.setVisible(false); 795 } 796 797 /** 798 * Opens a {@link TabbedFrame TabbedFrame} for a SalesPoint. 799 * 800 * <p>This includes {@link #setAppropriateDisplay(SalesPoint, int) converting the Display} that is currently 801 * assigned to the SalesPoint, making it visible and attaching it to the MultiWindow which 802 * must be able to display tabs.</p> 803 * 804 * @param sp the SalesPoint for which to open a Display. 805 */ 806 private void addSalesPoint_Tab(SalesPoint sp) { 807 try { 808 if (sp.getDisplay() != null) { 809 setAppropriateDisplay(sp, TABBED_VIEW); 810 } 811 } 812 catch (InterruptedException ex) { 813 ex.printStackTrace(); 814 } 815 816 JTabDisplay jtd = (JTabDisplay)sp.getDisplay(); 817 if (jtd == null) { 818 jtd = (JTabDisplay)getTab(sp); 819 sp.attach(jtd); 820 } 821 if (sp.getSalesPointFrameBounds() != null) { 822 jtd.setBounds(sp.getSalesPointFrameBounds()); 823 } 824 825 JTabbedPane jtp = (JTabbedPane)getContentPane().getComponent(0); 826 827 jtp.add(jtd, jtd.getTitle()); 828 setSecondMenuSheet(jtd.getMenuSheet()); 829 m_mpjtdTabDisplays.put(new Integer(sp.getID()), jtd); 830 831 } 832 833 /** 834 * Closes the {@link TabbedFrame TabbedFrame} of a SalesPoint. 835 * 836 * @param sp the SalesPoint for which to close the display. 837 */ 838 private void removeSalesPoint_Tab(SalesPoint sp) { 839 final Component c = getContentPane().getComponent(0); 840 final Display d = sp.getDisplay(); 841 if (c instanceof JTabbedPane && d instanceof JTabDisplay) { 842 JTabDisplay jtd = (JTabDisplay)d; 843 JTabbedPane jtp = (JTabbedPane)c; 844 jtp.remove(jtd); 845 846 //jtp.setSelectedIndex(getComponentCount()-1); 847 //stateChanged(new ChangeEvent(getContentPane().getComponent(0))); 848 } 849 } 850 851 /** 852 * Opens a {@link DesktopFrame DesktopFrame} for a SalesPoint. 853 * 854 * <p>This includes {@link #setAppropriateDisplay(SalesPoint, int) converting the Display} that is currently 855 * assigned to the SalesPoint, making it visible and attaching it to the MultiWindow which 856 * must be able to display {@link JInternalFrame JInternalFrames}.</p> 857 * 858 * @param sp the SalesPoint for which to open a Display. 859 */ 860 private void addSalesPoint_InternalFrame(SalesPoint sp) { 861 try { 862 if (sp.getDisplay() != null) { 863 setAppropriateDisplay(sp, DESKTOP_VIEW); 864 } 865 } 866 catch (InterruptedException ex) { 867 } 868 JInternalDisplay jdd = (JInternalDisplay)sp.getDisplay(); 869 if (jdd == null) { 870 jdd = (JInternalDisplay)getInternalFrame(sp); 871 sp.attach(jdd); 872 } 873 if (sp.getSalesPointFrameBounds() != null) { 874 jdd.setBounds(sp.getSalesPointFrameBounds()); 875 } 876 JDesktopPane jdp = (JDesktopPane)getContentPane().getComponent(0); 877 jdp.add(jdd); 878 jdd.setVisible(true); 879 m_mpjidInternalDisplays.put(new Integer(sp.getID()), jdd); 880 } 881 882 /** 883 * Closes the {@link DesktopFrame DeskopFrame} of a SalesPoint. 884 * 885 * @param sp the SalesPoint for which to close the display. 886 */ 887 private void removeSalesPoint_InternalFrame(SalesPoint sp) { 888 Component c = getContentPane().getComponent(0); 889 Display d = sp.getDisplay(); 890 if (c instanceof JDesktopPane && d instanceof JInternalDisplay) { 891 ((JDesktopPane)c).remove((JInternalDisplay)d); 892 } 893 repaint(); 894 } 895 896 /** 897 * Prepares the SalesPoint's display according to a view mode. 898 * 899 * <p>Depending on the desired view mode, a {@link DisplayFrame DisplayFrame}, 900 * {@link TabbedFrame TabbedFrame} or {@link DesktopFrame DesktopFrame} for the SalesPoint is retrieved 901 * or created. Then the {@link FormSheet}, the {@link MenuSheet} and the bounds are copied from the 902 * old to the new display. Finally the new display is {@link SalesPoint#attach(Display) attached} 903 * to the SalesPoint.</p> 904 * 905 * @param sp the SalesPoint for which to change the display type 906 * @param mode the view mode to be prepared 907 * @throws InterruptedException 908 */ 909 private synchronized void setAppropriateDisplay(SalesPoint sp, int mode) throws InterruptedException { 910 // Integer key = new Integer(sp.getID()); 911 Display dOld = sp.getDisplay(); 912 Display dNew = null; 913 switch (mode) { 914 case WINDOW_VIEW: dNew = getWindow(sp); break; 915 case TABBED_VIEW: dNew = getTab(sp); break; 916 case DESKTOP_VIEW: dNew = getInternalFrame(sp); break; 917 } 918 FormSheet fs = dOld.getFormSheet(); 919 if (dNew == null) { 920 dNew = dOld; 921 } 922 //temporarily remove wait response, otherwise setFormSheet() will block and we don't want that here 923 if (fs.waitResponse()) { 924 fs.setWaitResponse(false); 925 dNew.setFormSheet(fs); 926 fs.setWaitResponse(true); 927 } else { 928 dNew.setFormSheet(fs); 929 } 930 dNew.setBounds(dOld.getBounds()); 931 dNew.setMenuSheet(dOld.getMenuSheet()); 932 sp.attach(dNew, false); 933 } 934 935 /** 936 * Sets the arrangement of the frames in the MultiWindow. 937 * 938 * <p>If in window or desktop viewing mode, the frames will be rearranged. 939 * In tabbed mode nothing happens.</p> 940 * 941 * @param nArrangement the new Arrangement 942 * 943 * @see #OVERLAPPED 944 * @see #TILED_HORIZONTALLY 945 * @see #TILED_VERTICALLY 946 * 947 * @override Never 948 */ 949 public void arrangeFrames(int nArrangement) { 950 //init variables according to current view mode 951 int x = 0; 952 int y = 0; 953 int nWidth = 0; 954 int nHeight = 0; 955 HashMap mpDisplays = null; 956 Display dSelected = null; 957 if (getViewMode() == WINDOW_VIEW && m_mpjdfDisplayFrames.size() > 0) { 958 x = 0; 959 y = 0; 960 nWidth = (int)Toolkit.getDefaultToolkit().getScreenSize(). 961 getWidth(); 962 nHeight = (int)Toolkit.getDefaultToolkit().getScreenSize(). 963 getHeight(); 964 mpDisplays = m_mpjdfDisplayFrames; 965 } 966 if (getViewMode() == DESKTOP_VIEW && m_mpjidInternalDisplays.size() > 0) { 967 x = 0; 968 y = 0; 969 nWidth = getContentPane().getWidth(); 970 nHeight = getContentPane().getHeight(); 971 mpDisplays = m_mpjidInternalDisplays; 972 } 973 974 //continue only if viewmode is not tabbed and there are visible displays (i.e. mpDisplays has been set) 975 if (mpDisplays != null) { 976 // Remember selected display; this one should be the selected display again after the arrangement 977 dSelected = (Display)mpDisplays.get(m_nSelectedFrame); 978 //set selected arrangement 979 switch (nArrangement) { 980 //set overlapped arrangement 981 case OVERLAPPED: 982 983 for (Iterator i = mpDisplays.values().iterator(); i.hasNext(); ) { 984 Display d = (Display)i.next(); 985 //leave out the selected frame for the moment, it is handled last 986 if (d != dSelected) { 987 Rectangle r = null; 988 //do case differentiation for correct casting of displays 989 switch (getViewMode()) { 990 case WINDOW_VIEW: 991 DisplayFrame df = (DisplayFrame)d; 992 r = df.getSalesPoint().getSalesPointFrameBounds(); 993 if (r != null) { 994 df.setBounds(r); 995 } 996 df.setLocation(x, y); 997 break; 998 case DESKTOP_VIEW: 999 DesktopFrame dtf = (DesktopFrame)d; 1000 r = dtf.getSalesPoint().getSalesPointFrameBounds(); 1001 if (r != null) { 1002 dtf.setBounds(r); 1003 } 1004 dtf.setLocation(x, y); 1005 break; 1006 1007 } 1008 d.toFront(); 1009 x += 30; // increase coordinates, to make sure we get overlapping frames. 1010 y += 30; 1011 if ((x > getWidth() - 100) || (y > getHeight() - 100)) { 1012 // Wrap around if frame left content pane / screen. 1013 x = 0; 1014 y = 0; 1015 } 1016 } 1017 } 1018 1019 // Handle selected frame 1020 if (dSelected != null) { 1021 Rectangle r = null; 1022 switch (getViewMode()) { 1023 //do case differentiation for correct casting of selected display 1024 case WINDOW_VIEW: 1025 DisplayFrame df = (DisplayFrame)dSelected; 1026 r = df.getSalesPoint().getSalesPointFrameBounds(); 1027 if (r != null) { 1028 df.setBounds(r); 1029 } 1030 df.setLocation(x, y); 1031 break; 1032 case DESKTOP_VIEW: 1033 DesktopFrame dtf = (DesktopFrame)dSelected; 1034 r = dtf.getSalesPoint().getSalesPointFrameBounds(); 1035 if (r != null) { 1036 dtf.setBounds(r); 1037 } 1038 dtf.setLocation(x, y); 1039 break; 1040 } 1041 } 1042 break; 1043 1044 //set horizontally tiled arrangement 1045 case TILED_HORIZONTALLY: 1046 nWidth /= mpDisplays.size(); // frame width 1047 1048 for (Iterator i = mpDisplays.values().iterator(); i.hasNext();) { 1049 Display d = (Display)i.next(); 1050 d.setBounds(new Rectangle(x, 0, nWidth, nHeight)); 1051 x += nWidth; 1052 } 1053 1054 break; 1055 1056 case TILED_VERTICALLY: 1057 nHeight /= mpDisplays.size(); // frame height 1058 for (Iterator i = mpDisplays.values().iterator(); i.hasNext();) { 1059 Display d = (Display)i.next(); 1060 d.setBounds(new Rectangle(0, y, nWidth, nHeight)); 1061 y += nHeight; 1062 } 1063 } 1064 validate(); 1065 getContentPane().getComponent(0).repaint(); 1066 m_nArrangement = nArrangement; 1067 if (dSelected != null) { 1068 dSelected.toFront(); 1069 } 1070 1071 } 1072 } 1073 1074 /** 1075 * Creates and returns a new {@link TabbedFrame TabbedFame} for a SalesPoint. 1076 * @param sp the SalesPoint for which to create the display 1077 * @return the created display 1078 */ 1079 public Display getNewTab(SalesPoint sp) { 1080 //Integer key = new Integer(sp.getID()); 1081 JTabDisplay jtdNew = new TabbedFrame(sp); 1082 return jtdNew; 1083 } 1084 1085 /** 1086 * Tries to retrieve a {@link TabbedFrame TabbedFrame} for a given SalesPoint. If no such display 1087 * exists a new one is created using {@link #getNewTab(SalesPoint)}. 1088 * @param sp the SalesPoint for which to retrieve the display 1089 * @return the retrieved display 1090 */ 1091 private Display getTab(SalesPoint sp) { 1092 Integer key = new Integer(sp.getID()); 1093 Display jtd = (Display)m_mpjtdTabDisplays.get(key); 1094 return jtd == null ? getNewTab(sp) : jtd; 1095 } 1096 1097 /** 1098 * Creates and returns a new {@link DesktopFrame DesktopFrame} for a SalesPoint. 1099 * @param sp the SalesPoint for which to create the display 1100 * @return the created display 1101 */ 1102 public Display getNewInternalFrame(SalesPoint sp) { 1103 //Integer key = new Integer(sp.getID()); 1104 JInternalDisplay jddNew = new DesktopFrame(sp); 1105 return jddNew; 1106 } 1107 1108 /** 1109 * Tries to retrieve a {@link DesktopFrame DesktopFrame} for a given SalesPoint. If no such 1110 * display exists a new one is created using {@link #getNewInternalFrame(SalesPoint)}. 1111 * @param sp the SalesPoint for which to retrieve the display 1112 * @return the retrieved display 1113 */ 1114 private Display getInternalFrame(SalesPoint sp) { 1115 Integer key = new Integer(sp.getID()); 1116 Display jdd = (Display)m_mpjidInternalDisplays.get(key); 1117 return jdd == null ? getNewInternalFrame(sp) : jdd; 1118 } 1119 1120 /** 1121 * Creates and returns a new {@link DisplayFrame DisplayFrame} for a SalesPoint. 1122 * @param sp the SalesPoint for which to create the display 1123 * @return the created display 1124 */ 1125 public Display getNewWindow(SalesPoint sp) { 1126 JDisplayFrame jdf = new DisplayFrame(sp); 1127 return jdf; 1128 } 1129 1130 /** 1131 * Tries to retrieve a {@link DisplayFrame DisplayFrame} for a given SalesPoint. 1132 * If no such display exists a new one is created using {@link #getNewWindow(SalesPoint)}. 1133 * @param sp the SalesPoint for which to retrieve the display 1134 * @return the retrieved display 1135 */ 1136 private Display getWindow(SalesPoint sp) { 1137 Integer key = new Integer(sp.getID()); 1138 Display jdf = (Display)m_mpjdfDisplayFrames.get(key); 1139 return jdf == null ? getNewWindow(sp) : jdf; 1140 } 1141 1142 /** 1143 * Implementation of the method in {@link javax.swing.event.ChangeListener}. 1144 * 1145 * <p>This method is invoked when Tabs in tabbed mode are changed. This is to ensure that always the 1146 * correct {@link #setSecondMenuSheet(MenuSheet) second MenuSheet is set}. 1147 * 1148 * <p><strong>ATTENTION</strong>: This method is public as an implementation detail and must not be called 1149 * directly!</p> 1150 * 1151 * @override Never 1152 */ 1153 public void stateChanged(ChangeEvent evt) { 1154 //if (m_nViewMode == TABBED_VIEW) { // only merge in tab view 1155 updateMenuBar(((JTabbedPane)evt.getSource()).getSelectedComponent()); 1156 //} 1157 } 1158 1159 private void updateMenuBar(Component cmpTab) { 1160 1161 MenuSheet msTab = null; 1162 m_nSelectedFrame = new Integer( -1); 1163 1164 // try to find the associated JTabDisplay and its MenuSheet 1165 for (Iterator i = m_mpjtdTabDisplays.values().iterator(); i.hasNext() && (msTab == null); ) { 1166 JTabDisplay jtd = (JTabDisplay)i.next(); 1167 if (jtd == cmpTab) { 1168 msTab = jtd.getMenuSheet(); 1169 } 1170 } 1171 1172 if (msTab == null) { 1173 if (m_msCurrentMenuSheet != null) { 1174 setJMenuBar(m_msCurrentMenuSheet.mergePeers(null, null)); 1175 } else { 1176 setJMenuBar(null); 1177 } 1178 } else { 1179 if (m_msCurrentMenuSheet != null) { 1180 JMenuBar ms = m_msCurrentMenuSheet.mergePeers(msTab, null); 1181 setJMenuBar(ms); 1182 } else { 1183 setJMenuBar(msTab.getMenuBar()); 1184 } 1185 } 1186 1187 if (m_msCurrentMenuSheet != null) { 1188 m_msCurrentMenuSheet.setVisible(true); 1189 } 1190 1191 if (msTab != null) { 1192 msTab.setVisible(true); 1193 } 1194 validate(); 1195 1196 /*if (cmpTab != null) { //becomes null when changing from tab view to any other view 1197 ((TabbedFrame)cmpTab).onDisplayFocusGained(); 1198 }*/ 1199 1200 } 1201 1202 1203 /** 1204 * Constant for the window view mode. 1205 * Should be used as parameter for {@link #setViewMode} and 1206 * for recognizing the return values of {@link #getViewMode}. 1207 */ 1208 public static final int WINDOW_VIEW = 0; 1209 1210 /** 1211 * Constant for the tabbed view mode. 1212 * Should be used as parameter for {@link #setViewMode} and 1213 * for recognizing the return values of {@link #getViewMode}. 1214 */ 1215 public static final int TABBED_VIEW = 1; 1216 1217 /** 1218 * Constant for the desktop view mode. 1219 * Should be used as parameter for {@link #setViewMode} and 1220 * for recognizing the return values of {@link #getViewMode}. 1221 */ 1222 public static final int DESKTOP_VIEW = 2; 1223 1224 /** 1225 * No view mode yet. 1226 */ 1227 private static final int NONE = -1; 1228 1229 /** 1230 * Constant for cascaded arrangement of the frames in window or desktop view mode. 1231 * Should be used as parameter for {@link #arrangeFrames}. 1232 */ 1233 public static final int OVERLAPPED = 1; 1234 1235 /** 1236 * Constant for vertically tiled arrangement of the frames in window or desktop view mode. 1237 * Should be used as parameter for {@link #arrangeFrames}. 1238 */ 1239 public static final int TILED_VERTICALLY = 2; 1240 1241 /** 1242 * Constant for horizontally tiled arrangement of the frames in window or desktop view mode. 1243 * Should be used as parameter for {@link #arrangeFrames}. 1244 */ 1245 public static final int TILED_HORIZONTALLY = 3; 1246 1247 /** 1248 * Constant used as tag for the MultiWindowMenu. 1249 * Use this constant to gain access to the menu and manipulate it. 1250 */ 1251 public static final String MULTIWINDOW_MENU_TAG = "__TAG:_MULTIWINDOW_MENU_"; 1252 1253 /** 1254 * Constant used as tag for the "Window" menu option. 1255 * Use this constant to gain access to the menu and manipulate it. 1256 */ 1257 public static final String WINDOW_MENU_TAG = "__TAG:_MULTIWINDOW_WINDOW_"; 1258 1259 /** 1260 * Constant used as tag for the "Tabbed" menu option. 1261 * Use this constant to gain access to the menu and manipulate it. 1262 */ 1263 public static final String TABBED_MENU_TAG = "__TAG:_MULTIWINDOW_TABBED_"; 1264 1265 /** 1266 * Constant used as tag for the "Desktop" menu option. 1267 * Use this constant to gain access to the menu and manipulate it. 1268 */ 1269 public static final String DESKTOP_MENU_TAG = "__TAG:_MULTIWINDOW_DESKTOP_"; 1270 1271 /** 1272 * Constant used as tag for the separator in the multi window menu. 1273 * Use this constant to gain access to the menu and manipulate it. 1274 */ 1275 public static final String SEPARATOR_TAG = "__TAG:_MULTIWINDOW_SEPARATOR_"; 1276 1277 /** 1278 * Constant used as tag for the "Cascade" option. 1279 * Use this constant to gain access to the menu and manipulate it. 1280 */ 1281 public static final String CASCADE_MENU_TAG = "__TAG:_MULTIWINDOW_CASCADE_"; 1282 1283 /** 1284 * Constant used as tag for the "Tile horizontally" option. 1285 * Use this constant to gain access to the menu and manipulate it. 1286 */ 1287 public static final String TILE_HORIZ_MENU_TAG = "__TAG:_MULTIWINDOW_TILE_HORIZ_"; 1288 1289 /** 1290 * Constant used as tag for the "Tile vertically" option. 1291 * Use this constant to gain access to the menu and manipulate it. 1292 */ 1293 public static final String TILE_VERT_MENU_TAG = "__TAG:_MULTIWINDOW_TILE_VERT_"; 1294 1295 /** 1296 * Icon MenuItem "Tile horizontally". 1297 */ 1298 private static final ImageIcon HORIZONTAL_ICON = new ImageIcon(ResourceManager.getInstance().getResource( 1299 ResourceManager.RESOURCE_GIF, "icon.icon_horizontal_16x16_1")); 1300 1301 /** 1302 * Icon MenuItem "Tile vertically". 1303 */ 1304 private static final ImageIcon VERTICAL_ICON = new ImageIcon(ResourceManager.getInstance().getResource( 1305 ResourceManager.RESOURCE_GIF, "icon.icon_vertical_16x16_1")); 1306 1307 /** 1308 * Icon MenuItem "Cascade". 1309 */ 1310 private static final ImageIcon CASCADE_ICON = new ImageIcon(ResourceManager.getInstance().getResource( 1311 ResourceManager.RESOURCE_GIF, "icon.icon_cascade_16x16_1")); 1312 1313 1314 /*private static final ImageIcon CLOSE_ICON = new ImageIcon(ResourceManager.getInstance().getResource( 1315 ResourceManager.RESOURCE_GIF, "icon.icon_closetab_16x16"));*/ 1316 1317 1318 /** 1319 * This class is actually used by MultiWindow to display SalesPoints in window view mode. In comparison 1320 * to a normal <code>JDisplayFrame</code> <code>DisplayFrame</code> has a reference to the SalesPoint 1321 * which it displays. 1322 */ 1323 public class DisplayFrame extends JDisplayFrame { 1324 1325 /** 1326 * ID for Serialization. 1327 */ 1328 private static final long serialVersionUID = -7573300276904045881L; 1329 /** 1330 * The belonging SalesPoint 1331 */ 1332 private SalesPoint m_spOwner; 1333 1334 /** 1335 * Creates the display and sets the title according to the SalesPoint's name. 1336 * @param spOwner the belonging SalesPoint 1337 */ 1338 public DisplayFrame(SalesPoint spOwner) { 1339 super(); 1340 setPrimaryTitle(spOwner.getName()); 1341 m_spOwner = spOwner; 1342 } 1343 1344 /** 1345 * The actions to be executed when closing the SalesPoint. By default a new thread is created 1346 * which runs {@link SalesPoint#quit}. 1347 */ 1348 protected void exitForm() { 1349 new Thread() { 1350 public void run() { 1351 m_spOwner.quit(); 1352 } 1353 }.start(); 1354 } 1355 1356 /** 1357 * Registers itself as open window after load. 1358 */ 1359 public void load(ObjectInputStream ois) throws IOException, ClassNotFoundException { 1360 super.load(ois); 1361 //define actions to be executed after the Shop has been fully deserialized 1362 ois.registerValidation(new ObjectInputValidation() { 1363 public void validateObject() { 1364 DisplayFrame df = DisplayFrame.this; 1365 m_mpjdfDisplayFrames.put(new Integer(getSalesPoint().getID()), df); 1366 } 1367 } 1368 , OIV.JDISPLAYFRAME_PRIO-1); //prio less than prio in superclass to ensure that these actions 1369 //are performed AFTER the superclass's validateObject() actions 1370 } 1371 1372 /** 1373 * @return the SalesPoint belonging to this display. 1374 */ 1375 public SalesPoint getSalesPoint() { 1376 return m_spOwner; 1377 } 1378 1379 /** 1380 * Helper Variable to avoid looping of {@link #onDisplayFocusGained} (called whenever the 1381 * window is set active) and {@link #toFront} (called indirectly by 1382 * <code>onDisplayFocusGained</code>).<br> 1383 * If <code>toFront</code> has been executed <code>onDisplayFocusGained</code> will not be executed. 1384 */ 1385 private boolean setToFront; 1386 1387 /** 1388 * The actions to be executed when the display is brought to front. By default the MultiWindow's 1389 * and the Shop's private variables that contain the currently active SalesPoint are being updated. 1390 */ 1391 protected void onDisplayFocusGained() { 1392 if (setToFront) { 1393 setToFront = false; 1394 } else { 1395 MultiWindow.this.m_shShop.setCurrentSalesPoint(m_spOwner); 1396 } 1397 } 1398 1399 /** 1400 * Sets the DisplayFrame to front. 1401 */ 1402 public void toFront() { 1403 super.toFront(); 1404 setToFront = true; 1405 } 1406 1407 /** 1408 * Overrides JDisplayFrame's {@link JDisplayFrame#formSheetClosed} method. Does nothing. 1409 */ 1410 protected void formSheetClosed() {} 1411 } 1412 1413 1414 1415 /** 1416 * This class is actually used by MultiWindow to display SalesPoints in tabbed view mode. In comparison 1417 * to a normal <code>JTabDisplay</code> <code>TabbedFrame</code> has a reference to the SalesPoint 1418 * which it displays. 1419 */ 1420 public class TabbedFrame extends JTabDisplay { 1421 1422 /** 1423 * ID for Serialization. 1424 */ 1425 private static final long serialVersionUID = 7007061469078645605L; 1426 1427 /** 1428 * The belonging SalesPoint 1429 */ 1430 private SalesPoint m_spOwner; 1431 1432 /** 1433 * Creates the display and sets the title according to the SalesPoint's name. 1434 * @param spOwner the belonging SalesPoint 1435 */ 1436 public TabbedFrame(SalesPoint spOwner) { 1437 super(MultiWindow.this.getTabbedPane()); 1438 setPrimaryTitle(spOwner.getName()); 1439 m_spOwner = spOwner; 1440 } 1441 1442 /** 1443 * The actions to be executed when closing the SalesPoint. By default a new thread is created 1444 * which runs {@link SalesPoint#quit}. 1445 */ 1446 protected void exitForm() { 1447 new Thread() { 1448 public void run() { 1449 m_spOwner.quit(); 1450 } 1451 }.start(); 1452 } 1453 1454 /** 1455 * Adds itself to the MultiWindow's JTabbedPane after load. 1456 */ 1457 public void load(ObjectInputStream ois) throws IOException, ClassNotFoundException { 1458 super.load(ois); 1459 //define actions to be executed after the Shop has been fully deserialized 1460 ois.registerValidation(new ObjectInputValidation() { 1461 public void validateObject() { 1462 TabbedFrame tf = TabbedFrame.this; 1463 getTabbedPane().add(tf, tf.getTitle()); 1464 m_mpjtdTabDisplays.put(new Integer(getSalesPoint().getID()), tf); 1465 setSecondMenuSheet(tf.getMenuSheet()); 1466 } 1467 } 1468 , OIV.JDISPLAYFRAME_PRIO-1); 1469 } 1470 1471 /** 1472 * Updates the MultiFrame's MenuSheet with a call to {@link MultiWindow#setSecondMenuSheet} when 1473 * the display's MenuSheet has changed. 1474 * 1475 * @param ms the MenuSheet that has been set. 1476 */ 1477 public void onMenuSheetSet(MenuSheet ms) { 1478 setSecondMenuSheet(ms); 1479 } 1480 1481 /** 1482 * @return the SalesPoint belonging to this display. 1483 */ 1484 public SalesPoint getSalesPoint() { 1485 return m_spOwner; 1486 } 1487 1488 /** 1489 * Helper Variable to avoid looping of {@link #onDisplayFocusGained} (called whenever the 1490 * window is set active) and {@link #toFront} (called indirectly by <code>onDisplayFocusGained</code>).<br> 1491 * If <code>toFront</code> has been executed <code>onDisplayFocusGained</code> will not be executed. 1492 */ 1493 private boolean setToFront; 1494 1495 /** 1496 * The actions to be executed when the display is brought to front. By default the MultiWindow's 1497 * and the Shop's private variables that contain the currently active SalesPoint are being updated. 1498 */ 1499 protected void onDisplayFocusGained() { 1500 //System.out.println("gained"); 1501 //super.getTabbedPane().statechanged 1502 if (setToFront) { 1503 setToFront = false; 1504 } else { 1505 MultiWindow.this.m_shShop.setCurrentSalesPoint(m_spOwner); 1506 } 1507 } 1508 1509 /** 1510 * Sets the DisplayFrame to front. 1511 */ 1512 public void toFront() { 1513 super.toFront(); 1514 //stateChanged(new ChangeEvent(getContentPane().getComponent(0))); 1515 setToFront = true; 1516 } 1517 1518 1519 /** 1520 * Overrides JTabDisplay's {@link JTabDisplay#formSheetClosed} method. Does nothing. 1521 */ 1522 protected void formSheetClosed() {} 1523 } 1524 1525 1526 /** 1527 * This class is actually used by MultiWindow to display SalesPoints in desktop view mode. In comparison 1528 * to a normal <code>JInternalDisplay</code> <code>DesktopFrame</code> has a reference to the SalesPoint 1529 * which it displays. 1530 */ 1531 public class DesktopFrame extends JInternalDisplay { 1532 1533 /** 1534 * ID for Serialization. 1535 */ 1536 private static final long serialVersionUID = 4267251867025717975L; 1537 1538 /** 1539 * The belonging SalesPoint 1540 */ 1541 private SalesPoint m_spOwner; 1542 1543 /** 1544 * Creates the display and sets the title according to the SalesPoint's name. 1545 * @param spOwner the belonging SalesPoint 1546 */ 1547 public DesktopFrame(SalesPoint spOwner) { 1548 super(); 1549 setPrimaryTitle(spOwner.getName()); 1550 m_spOwner = spOwner; 1551 } 1552 1553 /** 1554 * The actions to be executed when closing the SalesPoint. By default a new thread is created 1555 * which runs {@link SalesPoint#quit}. 1556 */ 1557 protected void exitForm() { 1558 new Thread() { 1559 public void run() { 1560 m_spOwner.quit(); 1561 } 1562 }.start(); 1563 } 1564 1565 /** 1566 * Adds itself to the MultiWindow's JDesktopPane after load. 1567 */ 1568 public void load(ObjectInputStream ois) throws IOException, ClassNotFoundException { 1569 super.load(ois); 1570 //define actions to be executed after the Shop has been fully deserialized 1571 ois.registerValidation(new ObjectInputValidation() { 1572 public void validateObject() { 1573 DesktopFrame df = DesktopFrame.this; 1574 MultiWindow.this.getDesktopPane().add(df); 1575 m_mpjidInternalDisplays.put(new Integer(getSalesPoint().getID()), df); 1576 } 1577 } 1578 , OIV.JDISPLAYFRAME_PRIO-1); 1579 } 1580 1581 1582 /** 1583 * @return the SalesPoint belonging to this display. 1584 */ 1585 public SalesPoint getSalesPoint() { 1586 return m_spOwner; 1587 } 1588 1589 /** 1590 * The actions to be executed when the display is brought to front. By default the MultiWindow's 1591 * and the Shop's private variables that contain the currently active SalesPoint are being updated. 1592 */ 1593 protected void onDisplayFocusGained() { 1594 MultiWindow.this.m_shShop.setCurrentSalesPoint(m_spOwner); 1595 } 1596 1597 /** 1598 * Overrides JInternalDisplay's {@link JInternalDisplay#formSheetClosed} method. Does nothing. 1599 */ 1600 protected void formSheetClosed() {} 1601 } 1602 1603 /** 1604 * As Swing is not threadsafe, removing a tab or an internal frame might cause an 1605 * ArrayIndexOutOfBoundsException. 1606 * Swing periodically starts a an event-dispatching thread, which might also affect the UI. 1607 * If a frame or tab is being removed when the event dispatch thread has already started, 1608 * Swing might try to access components that are not part of the Shop Window any more and 1609 * therefore causes the exception. 1610 * 1611 * To prevent this, invokeLater() is used. It causes the thread which it receives as argument to be 1612 * executed by the the event-dispatching thread. 1613 */ 1614 @SuppressWarnings("unused") 1615 private void runAndWait(Thread t) { 1616 if (SwingUtilities.isEventDispatchThread()) { 1617 t.run(); 1618 } else { 1619 try { 1620 SwingUtilities.invokeLater(t); 1621 } 1622 catch (Exception ex) { 1623 System.err.println("Exception during invokeLater"); 1624 ex.printStackTrace(); 1625 } 1626 } 1627 } 1628 } 1629 1630 1631 /** 1632 * The Actions executed via the MultiWindow menu sheet. 1633 */ 1634 class WindowAction extends MultiWindow.MultiWindowAction { 1635 private static final long serialVersionUID = 9076041163374660436L; 1636 public WindowAction(MultiWindow owner) { 1637 super(owner); 1638 } 1639 public void doAction(SaleProcess p, SalesPoint sp) { 1640 m_mwReference.setViewMode(MultiWindow.WINDOW_VIEW); 1641 } 1642 } 1643 1644 1645 class TabAction extends MultiWindow.MultiWindowAction { 1646 private static final long serialVersionUID = -2809559210614415541L; 1647 public TabAction(MultiWindow owner) { 1648 super(owner); 1649 } 1650 1651 public void doAction(SaleProcess p, SalesPoint sp) { 1652 m_mwReference.setViewMode(MultiWindow.TABBED_VIEW); 1653 } 1654 } 1655 1656 class DesktopAction extends MultiWindow.MultiWindowAction { 1657 private static final long serialVersionUID = 6811361110141777315L; 1658 public DesktopAction(MultiWindow owner) { 1659 super(owner); 1660 } 1661 1662 public void doAction(SaleProcess p, SalesPoint sp) { 1663 m_mwReference.setViewMode(MultiWindow.DESKTOP_VIEW); 1664 } 1665 } 1666 1667 1668 class CascadeAction extends MultiWindow.MultiWindowAction { 1669 private static final long serialVersionUID = 1194893300055840954L; 1670 public CascadeAction(MultiWindow owner) { 1671 super(owner); 1672 } 1673 1674 public void doAction(SaleProcess p, SalesPoint sp) { 1675 m_mwReference.arrangeFrames(MultiWindow.OVERLAPPED); 1676 } 1677 } 1678 1679 class TileHorizontallyAction extends MultiWindow.MultiWindowAction { 1680 private static final long serialVersionUID = 573097740792896688L; 1681 public TileHorizontallyAction(MultiWindow owner) { 1682 super(owner); 1683 } 1684 1685 public void doAction(SaleProcess p, SalesPoint sp) { 1686 m_mwReference.arrangeFrames(MultiWindow.TILED_HORIZONTALLY); 1687 } 1688 } 1689 1690 class TileVerticallyAction extends MultiWindow.MultiWindowAction { 1691 private static final long serialVersionUID = -6310991497003068509L; 1692 public TileVerticallyAction(MultiWindow owner) { 1693 super(owner); 1694 } 1695 1696 public void doAction(SaleProcess p, SalesPoint sp) { 1697 m_mwReference.arrangeFrames(MultiWindow.TILED_VERTICALLY); 1698 } 1699 1700 } 1701 1702 1703