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