001 package sale; 002 003 import java.io.*; 004 import java.awt.event.*; 005 import javax.swing.*; 006 import java.awt.BorderLayout; 007 import sale.events.*; 008 import java.awt.Rectangle; 009 import util.ListenerHelper; 010 011 /** 012 * A JFrame that can display Form- and MenuSheets. 013 * 014 * <p>You can use this frame to pop up messages and dialogs in extra windows, while 015 * maintaining consistency with the rest of the GUI by using the familiar FormSheet 016 * look'n'feel.</p> 017 * 018 * <p>The frame will display one {@link FormSheet}. Closing the frame using the systems 019 * menu or any other OS dependent gesture will result in a call to {@link FormSheet#cancel()} 020 * on the FormSheet.</p> 021 * 022 * <p>Also, the frame may display a {@link MenuSheet}. It can therefore be used wherever a Display 023 * can be used.</p> 024 * 025 * <p><strong>Attention:</strong> This class is not meant to be serialized. See {@link Display#load load()} 026 * and {@link Display#save store()} for details.</p> 027 * 028 * @author Steffen Zschaler, Thomas Medack 029 * @version 3.0 12/01/2001 030 * @since v3.0 031 */ 032 public class JDisplayFrame extends javax.swing.JFrame implements Display { 033 034 /// BEGIN OF ATTRIBUTES TO BE SAVED/RESTORED BY save/load . 035 036 /** 037 * ID for serialization. 038 */ 039 private static final long serialVersionUID = -4700316380600886683L; 040 041 /** 042 * @serial to be stored/restored by save/load 043 */ 044 private String m_sPrimaryTitle; 045 046 /** 047 * @serial to be stored/restored by save/load 048 */ 049 private String m_sSecondaryTitle; 050 051 /** 052 * The current FormSheet. 053 * 054 * @serial to be stored/restored by save/load 055 */ 056 private FormSheet m_fsCurrent; 057 058 /** 059 * The current MenuSheet. 060 * 061 * @serial to be stored/restored by save/load 062 */ 063 private MenuSheet m_msCurrent; 064 065 /** 066 * The list of listeners. 067 * 068 * @serial to be stored/restored by save/load 069 */ 070 protected ListenerHelper m_lhListeners = new ListenerHelper(); 071 072 private static class DFFormSheetContainer implements FormSheetContainer, Serializable { 073 074 private static final long serialVersionUID = 5709845370831474407L; 075 076 private transient JDisplayFrame m_jdfOwner; 077 078 public DFFormSheetContainer(JDisplayFrame jdfOwner) { 079 super(); 080 setOwner(jdfOwner); 081 } 082 083 public void setOwner(JDisplayFrame jdfOwner) { 084 m_jdfOwner = jdfOwner; 085 } 086 087 /** 088 * Delegated to owner's method. 089 * 090 * @override Never 091 * 092 * @param fs the FormSheet whose button bar was cleared. 093 */ 094 public void onFormSheetButtonsCleared(FormSheet fs) { 095 m_jdfOwner.onFormSheetButtonsCleared(fs); 096 } 097 098 /** 099 * Delegated to owner's method. 100 * 101 * @override Never 102 * 103 * @param fs the FormSheet whose button bar changed. 104 * @param fb the button that was added to the FormSheet. 105 */ 106 public void onFormSheetButtonAdded(FormSheet fs, FormSheet.FormButton fb) { 107 m_jdfOwner.onFormSheetButtonAdded(fs, fb); 108 } 109 110 /** 111 * Delegated to owner's method. 112 * 113 * @override Never 114 * 115 * @param fs the FormSheet whose button bar changed. 116 * @param fb the button that was removed from the FormSheet. 117 */ 118 public void onFormSheetButtonRemoved(FormSheet fs, FormSheet.FormButton fb) { 119 m_jdfOwner.onFormSheetButtonRemoved(fs, fb); 120 } 121 122 /** 123 * Delegated to owner's method. 124 * 125 * @override Never 126 * 127 * @param fs the FormSheet to be closed. 128 */ 129 public void closeFormSheet(FormSheet fs) { 130 m_jdfOwner.closeFormSheet(fs); 131 } 132 133 /** 134 * Delegated to owner's method. 135 * 136 * @override Never 137 * 138 * @param fs the FormSheet whose component changed. 139 * @param jcmpNew the new component of the FormSheet. 140 */ 141 public void onFormSheetComponentChanged(FormSheet fs, JComponent jcmpNew) { 142 m_jdfOwner.onFormSheetComponentChanged(fs, jcmpNew); 143 } 144 145 /** 146 * Delegated to owner's method. 147 * 148 * @override Never 149 * 150 * @param fs the FormSheet whose caption changed. 151 * @param sNewCaption the new caption of the FormSheet. 152 */ 153 public void onFormSheetCaptionChanged(FormSheet fs, String sNewCaption) { 154 m_jdfOwner.onFormSheetCaptionChanged(fs, sNewCaption); 155 } 156 } 157 158 /** 159 * @serial to be stored/restored by save/load 160 */ 161 private DFFormSheetContainer m_dffscContainer = new DFFormSheetContainer(this); 162 163 /** 164 * If true, a Formsheet has been displayed on this display at least once. 165 * 166 * @serial to be stored/restored by save/load 167 */ 168 private boolean m_fHadFormSheet = false; 169 170 /// END OF ATTRIBUTES TO BE SAVED/RESTORED BY save/load . 171 172 /** 173 * Object used to block {@link #setFormSheet} when the FormSheet demands it. 174 */ 175 private transient Object m_oWaiter; 176 177 /** 178 * Return the object used to block {@link #setFormSheet} when the FormSheet demands it. 179 */ 180 private Object getWaiter() { 181 if (m_oWaiter == null) { 182 m_oWaiter = new Object(); 183 } 184 185 return m_oWaiter; 186 } 187 188 /** 189 * The currently displaying component. 190 */ 191 private transient JComponent m_jcmpComponent; 192 193 /** 194 * The currently displaying button bar panel. 195 */ 196 private transient JPanel m_jpButtonBar; 197 198 /** 199 * JDisplayFrames are not meant to be serialized this way! 200 */ 201 private void writeObject(ObjectOutputStream oos) throws IOException { 202 throw new NotSerializableException("JDisplayFrame"); 203 } 204 205 /** 206 * JDisplayFrames are not meant to be serialized this way! 207 */ 208 private void readObject(ObjectInputStream ois) throws IOException { 209 throw new NotSerializableException("JDisplayFrame"); 210 } 211 212 /** 213 * Create a new JDisplayFrame. 214 */ 215 public JDisplayFrame() { 216 super(); 217 218 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 219 220 addWindowListener(new java.awt.event.WindowAdapter() { 221 public void windowClosing(WindowEvent e) { 222 exitForm(); 223 } 224 225 public void windowActivated(WindowEvent e) { 226 onDisplayFocusGained(); 227 } 228 }); 229 230 pack(); 231 } 232 233 protected void onDisplayFocusGained() { 234 } 235 236 /** 237 * Save this display frame to the given output stream. The frame will only store information from which 238 * contents and layout can be restored later. The actual frame or any other Swing components will not 239 * be stored into the stream. 240 */ 241 public void save(ObjectOutputStream oos) throws IOException { 242 oos.writeObject(getClass()); 243 oos.writeObject(m_dffscContainer); 244 oos.writeObject(m_sPrimaryTitle); 245 oos.writeObject(m_sSecondaryTitle); 246 oos.writeObject(m_fsCurrent); 247 oos.writeObject(m_msCurrent); 248 oos.writeObject(m_lhListeners); 249 oos.writeBoolean(m_fHadFormSheet); 250 oos.writeObject(getBounds()); 251 oos.writeBoolean(isVisible()); 252 } 253 254 /** 255 * Restore this display frame from data in the given input stream. 256 */ 257 public void load(ObjectInputStream ois) throws IOException, ClassNotFoundException { 258 259 m_dffscContainer = (DFFormSheetContainer)ois.readObject(); 260 m_dffscContainer.setOwner(this); 261 setPrimaryTitle((String)ois.readObject()); 262 setSecondaryTitle((String)ois.readObject()); 263 final FormSheet fsCurrent = (FormSheet)ois.readObject(); 264 final MenuSheet msCurrent = (MenuSheet)ois.readObject(); 265 m_lhListeners = (ListenerHelper)ois.readObject(); 266 m_fHadFormSheet = ois.readBoolean(); 267 final Rectangle rcBounds = (Rectangle)ois.readObject(); 268 final boolean fVisible = ois.readBoolean(); 269 m_dffscContainer = new DFFormSheetContainer(this); 270 ois.registerValidation(new ObjectInputValidation() { 271 public void validateObject() { 272 setBounds(rcBounds); 273 try { 274 fsCurrent.setWaitResponse(false); 275 setFormSheet(fsCurrent); 276 setMenuSheet(msCurrent); 277 } 278 catch (InterruptedException ie) { 279 ie.printStackTrace(); 280 } 281 setVisible(fVisible); 282 } 283 } , OIV.JDISPLAYFRAME_PRIO); 284 } 285 286 public void setPrimaryTitle(String sPrimaryTitle) { 287 m_sPrimaryTitle = sPrimaryTitle; 288 setDisplayTitle(); 289 } 290 291 public String getPrimaryTitle() { 292 return m_sPrimaryTitle; 293 } 294 295 public void setSecondaryTitle(String sSecondaryTitle) { 296 m_sSecondaryTitle = sSecondaryTitle; 297 setDisplayTitle(); 298 } 299 300 public String getSecondaryTitle() { 301 return m_sSecondaryTitle; 302 } 303 304 public void setDisplayTitle() { 305 String sTitle = ""; 306 307 if (m_sPrimaryTitle != null && m_sPrimaryTitle != "") { 308 sTitle += m_sPrimaryTitle; 309 if (m_sSecondaryTitle != null && m_sSecondaryTitle != "") { 310 sTitle += " - "; 311 } 312 } 313 if (m_sSecondaryTitle != null && m_sSecondaryTitle != "") { 314 sTitle += m_sSecondaryTitle; 315 } 316 setTitle(sTitle); 317 } 318 319 320 /** 321 * Hook method called when the frame is about to be closed. 322 * 323 * <p>By default cancels any FormSheet being currently displayed and closes the frame.</p> 324 */ 325 protected void exitForm() { 326 setVisible(false); 327 dispose(); 328 } 329 330 // Display interface methods 331 332 /** Set and display a FormSheet. 333 * 334 * <p>This method should attach a FormSheetContainer as the FormSheet's display, 335 * get the FormSheet's caption, component and button bar and render them. The entire 336 * peer creation should be synchronized using {@link FormSheet#getComponentLock} 337 * and {@link FormSheet#getButtonsLock}, so as not to loose any events.</p> 338 * 339 * <p>If {@link FormSheet#waitResponse fs.waitResponse()} returns true, 340 * <code>setFormSheet()</code> should block, until the FormSheet is closed by a matching 341 * call to a <code>closeFormSheet()</code> method.</p> 342 * 343 * <p>If a FormSheet is already being displayed, <code>setFormSheet()</code> should cancel this 344 * FormSheet prior to setting the new FormSheet.</p> 345 * 346 * @override Always 347 * 348 * @param fs the FormSheet to be displayed. 349 * 350 * @exception InterruptedException if an interrupt occured while waiting for the 351 * FormSheet to be closed. 352 */ 353 public void setFormSheet(FormSheet fs) throws InterruptedException { 354 if (m_fsCurrent != null) { 355 FormSheet fsTemp = m_fsCurrent; 356 if (fs != null) { // setFormSheet (null) will be interpreted as an explicit close, too. 357 m_fsCurrent = null; // Set old formsheet to null so that closeFormSheet will correctly identify implicit closing of FormSheet. 358 } 359 fsTemp.cancel(); 360 } 361 362 getContentPane().removeAll(); 363 364 if (fs != null) { 365 synchronized (fs.getComponentLock()) { 366 synchronized (fs.getButtonsLock()) { 367 setSecondaryTitle(fs.getCaption()); 368 369 fs.attach(m_dffscContainer); 370 m_fsCurrent = fs; 371 372 m_jcmpComponent = fs.getComponent(); 373 374 if (m_jcmpComponent != null) { 375 getContentPane().add(m_jcmpComponent, BorderLayout.CENTER); 376 } 377 378 m_jpButtonBar = new JPanel(false); 379 fs.fillBtnPanel(m_jpButtonBar); 380 381 getContentPane().add(m_jpButtonBar, BorderLayout.SOUTH); 382 383 if (m_fHadFormSheet) { 384 getRootPane().revalidate(); 385 repaint(); 386 } else { 387 m_fHadFormSheet = true; 388 pack(); 389 } 390 } 391 } 392 393 fireFormSheetSet(fs); 394 395 try { 396 if (fs.waitResponse()) { 397 synchronized (getWaiter()) { 398 util.Debug.print("JDisplayFrame.setFormSheet: Preparing to wait for " + fs, -1); 399 while (fs.getDisplay() == m_dffscContainer) { // Corrected 03/08/2001, sz9: was : while (fs.getDisplay() == this) { 400 util.Debug.print("JDisplayFrame.setFormSheet: Starting to wait for " + fs, -1); 401 getWaiter().wait(); 402 util.Debug.print("JDisplayFrame.setFormSheet: Caught notification waiting for " + 403 fs, -1); 404 } 405 } 406 } 407 } 408 catch (InterruptedException ie) { 409 throw ie; 410 } 411 catch (Throwable t) { 412 t.printStackTrace(); 413 } 414 } else { 415 setSecondaryTitle(null); 416 } 417 } 418 419 public void setBounds(Rectangle r) { 420 super.setBounds(r); 421 //necessary to properly update UI 422 if (isVisible()) { 423 setVisible(true); 424 } 425 } 426 427 /** 428 * Return the {@link FormSheet} that is currently attached to the display. 429 */ 430 public FormSheet getFormSheet() { 431 return m_fsCurrent; 432 } 433 434 /** Close the current FormSheet. It is up to the display whether the FormSheet will be cancelled or 435 * just closed normally. 436 * 437 * @override Always 438 */ 439 public void closeFormSheet() { 440 if (m_fsCurrent != null) { 441 closeFormSheet(m_fsCurrent); 442 } 443 } 444 445 /** 446 * Open a fresh {@link JDisplayDialog} and display the FormSheet in it. 447 * 448 * @override Never 449 * 450 * @exception InterruptedException if an interrupt occured while waiting for the 451 * FormSheet to be closed. 452 */ 453 public void popUpFormSheet(FormSheet fs) throws InterruptedException { 454 455 JDisplayDialog jdd = new JDisplayDialog(); 456 457 jdd.setVisible(true); 458 459 try { 460 jdd.setFormSheet(fs); 461 } 462 catch (InterruptedException e) { 463 if (fs.getDisplay() == jdd) { 464 fs.cancel(); 465 } 466 467 throw e; 468 } 469 } 470 471 /** Set and display a MenuSheet. 472 * 473 * <p>If a MenuSheet is already being displayed, <code>setMenuSheet()</code> should remove this 474 * MenuSheet prior to setting the new MenuSheet.</p> 475 * 476 * @override Always 477 * 478 * @param ms the MenuSheet to be displayed. <code>null</code> is a valid value and should result in the 479 * current MenuSheet being closed. 480 */ 481 public void setMenuSheet(MenuSheet ms) { 482 if (m_msCurrent != null) { 483 m_msCurrent.setVisible(false); 484 } 485 486 m_msCurrent = ms; 487 488 if (m_msCurrent != null) { 489 m_msCurrent.setVisible(true); 490 setJMenuBar(ms.getMenuBar()); 491 } else { 492 setJMenuBar(null); 493 } 494 495 /* 496 Corrected 25.01.2001, sz9, was: 497 pack(); 498 */ 499 500 getRootPane().revalidate(); 501 repaint(); 502 } 503 504 /** 505 * Return the {@link MenuSheet} that is currently attached to the display. 506 */ 507 public MenuSheet getMenuSheet() { 508 return m_msCurrent; 509 } 510 511 /** 512 * Return true to indicate this is a useable display. 513 * 514 * @override Never 515 */ 516 public boolean isUseableDisplay() { 517 return true; 518 } 519 520 521 /** 522 * Add a listener to receive notification on the JDisplayFrame's FormSheet. 523 * 524 * @override Never 525 */ 526 public void addFormSheetListener(FormSheetListener fsl) { 527 m_lhListeners.add(FormSheetListener.class, fsl); 528 } 529 530 /** 531 * Remove a listener to receive notification on the JDisplayFrame's FormSheet. 532 * 533 * @override Never 534 */ 535 public void removeFormSheetListener(FormSheetListener fsl) { 536 m_lhListeners.remove(FormSheetListener.class, fsl); 537 } 538 539 /** 540 * Fire an event to all {@link sale.events.FormSheetListener FormSheetListeners} indicating that 541 * a {@link FormSheet} was set on this display. As FormSheet setting is always explicit, no 542 * extra parameter is necessary. 543 * 544 * @override Never 545 * 546 * @param fs the FormSheet that was set 547 */ 548 protected void fireFormSheetSet(FormSheet fs) { 549 FormSheetEvent e = null; 550 Object[] listeners = m_lhListeners.getListenerList(); 551 552 for (int i = listeners.length - 2; i >= 0; i -= 2) { 553 if (listeners[i] == FormSheetListener.class) { 554 if (e == null) { 555 e = new FormSheetEvent(this, fs, true); 556 } 557 ((FormSheetListener)listeners[i + 1]).formSheetSet(e); 558 } 559 } 560 } 561 562 /** 563 * Fire an event to all {@link sale.events.FormSheetListener FormSheetListeners} indicating that 564 * a {@link FormSheet} was removed from this display. 565 * 566 * @override Never 567 * 568 * @param fs the FormSheet that was set 569 * @param fExplicit true, if the FormSheet was closed explicitly, i.e. either by a call to one of 570 * the <code>closeFormSheet</code> methods or by <code>setFormSheet (null)</code>. 571 * 572 * @see #closeFormSheet() 573 * @see #closeFormSheet(FormSheet) 574 * @see #setFormSheet 575 */ 576 protected void fireFormSheetRemoved(FormSheet fs, boolean fExplicit) { 577 FormSheetEvent e = null; 578 579 Object[] listeners = m_lhListeners.getListenerList(); 580 581 for (int i = listeners.length - 2; i >= 0; i -= 2) { 582 if (listeners[i] == FormSheetListener.class) { 583 if (e == null) { 584 e = new FormSheetEvent(this, fs, fExplicit); 585 586 } 587 ((FormSheetListener)listeners[i + 1]).formSheetRemoved(e); 588 } 589 } 590 } 591 592 // FormSheetContainer interface methods 593 594 /** 595 * Closes a FormSheet. 596 * 597 * <p>If a FormSheet is closed, by default, the JDisplayDialog containing it is also closed. You can, 598 * however, alter this behavior by overriding {@link #formSheetClosed}.</p> 599 * 600 * @override Never Instead override {@link #formSheetClosed}. 601 * 602 * @param fs the FormSheet to be closed. 603 */ 604 public void closeFormSheet(FormSheet fs) { 605 boolean fExplicit = true; 606 607 fs.detachDisplay(); 608 609 if (m_fsCurrent == fs) { 610 m_fsCurrent = null; 611 } else { 612 fExplicit = false; 613 } 614 615 formSheetClosed(); 616 util.Debug.print(getClass() + ".closeFormSheet: Preparing to notify waiters for " + fs, -1); 617 synchronized (getWaiter()) { 618 getWaiter().notifyAll(); 619 } 620 util.Debug.print(getClass() + ".closeFormSheet: Notified waiters for " + fs, -1); 621 622 623 fireFormSheetRemoved(fs, fExplicit); 624 } 625 626 /** 627 * Hook method called when the FormSheet was closed. 628 * 629 * @override Sometimes The default implementation calls {@link #exitForm}. 630 */ 631 protected void formSheetClosed() { 632 exitForm(); 633 } 634 635 /** 636 * In addition to disposing of the peer resources, remove the FormSheet and the 637 * MenuSheet. 638 * 639 * @override Never 640 */ 641 public void dispose() { 642 try { 643 setFormSheet(null); 644 } 645 catch (InterruptedException e) {} 646 647 setMenuSheet(null); 648 649 super.dispose(); 650 } 651 652 /** Notification event informing about a change of a FormSheet's caption. 653 * 654 * @override Always 655 * 656 * @param fs the FormSheet whose caption changed. 657 * @param sNewCaption the new caption of the FormSheet. 658 */ 659 public void onFormSheetCaptionChanged(FormSheet fs, String sNewCaption) { 660 setSecondaryTitle(sNewCaption); 661 } 662 663 /** Notification event informing about a change of a FormSheet's component. 664 * 665 * @override Always 666 * 667 * @param fs the FormSheet whose component changed. 668 * @param jcmpNew the new component of the FormSheet. 669 */ 670 public void onFormSheetComponentChanged(FormSheet fs, JComponent jcmpNew) { 671 if (m_fsCurrent == null) { 672 return; // This can happen during deserialization 673 } 674 675 synchronized (fs.getComponentLock()) { 676 getContentPane().remove(m_jcmpComponent); 677 678 m_jcmpComponent = fs.getComponent(); 679 if (m_jcmpComponent != null) { 680 getContentPane().add(m_jcmpComponent, BorderLayout.CENTER); 681 } 682 getRootPane().revalidate(); 683 repaint(); 684 } 685 } 686 687 /** Notification event informing that a button was added to the FormSheet's button bar. 688 * 689 * @override Always 690 * 691 * @param fs the FormSheet whose button bar changed. 692 * @param fb the button that was added to the FormSheet. 693 */ 694 public void onFormSheetButtonAdded(FormSheet fs, FormSheet.FormButton fb) { 695 if (m_fsCurrent == null) { 696 return; // This can happen during deserialization 697 } 698 699 synchronized (fs.getButtonsLock()) { 700 m_jpButtonBar.add(fb.getPeer()); 701 702 /* 703 Corrected 25.01.2001, sz9, was: 704 pack(); 705 */ 706 707 getRootPane().revalidate(); 708 repaint(); 709 710 } 711 } 712 713 /** Notification event informing that a button was removed from the FormSheet's button bar. 714 * 715 * @override Always 716 * 717 * @param fs the FormSheet whose button bar changed. 718 * @param fb the button that was removed from the FormSheet. 719 */ 720 public void onFormSheetButtonRemoved(FormSheet fs, FormSheet.FormButton fb) { 721 if (m_fsCurrent == null) { 722 return; // This can happen during deserialization 723 } 724 725 synchronized (fs.getButtonsLock()) { 726 m_jpButtonBar.remove(fb.getPeer()); 727 728 /* 729 Corrected 25.01.2001, sz9, was: 730 pack(); 731 */ 732 733 getRootPane().revalidate(); 734 repaint(); 735 736 } 737 } 738 739 /** Notification event informing that all buttons were removed from a FormSheet's button bar. 740 * 741 * @override Always 742 * 743 * @param fs the FormSheet whose button bar was cleared. 744 */ 745 public void onFormSheetButtonsCleared(FormSheet fs) { 746 if (m_fsCurrent == null) { 747 return; // This can happen during deserialization 748 } 749 750 synchronized (fs.getButtonsLock()) { 751 m_jpButtonBar.removeAll(); 752 753 /* 754 Corrected 25.01.2001, sz9, was: 755 pack(); 756 */ 757 758 getRootPane().revalidate(); 759 repaint(); 760 761 } 762 } 763 }