001 package sale;
002
003 import javax.swing.*;
004 import javax.swing.event.*;
005
006 import java.awt.event.*;
007 import java.awt.BorderLayout;
008 import java.io.*;
009
010 import sale.stdforms.*;
011 import sale.events.*;
012
013 /**
014 * A JDialog that can display Form- and MenuSheets.
015 *
016 * <p>You can use this frame to pop up messages and dialogs in extra windows, while
017 * maintaining consistency with the rest of the GUI by using the familiar FormSheet
018 * look'n'feel.</p>
019 *
020 * <p>The frame will display one {@link FormSheet}, and, by default, will close when the FormSheet
021 * is closed. Closing the frame using the systems menu or any other OS dependent gesture
022 * will result in a call to {@link FormSheet#cancel()} on the FormSheet.</p>
023 *
024 * <p>Also, the frame may display a {@link MenuSheet}. It can therefore be used wherever a Display
025 * can be used.</p>
026 *
027 * <p><strong>Attention:</strong> This class is not meant to be serialized.</p>
028 *
029 * @author Steffen Zschaler
030 * @version 2.0 25/05/1999
031 * @since v2.0
032 */
033 public class JDisplayDialog extends JDialog implements Display, FormSheetContainer {
034
035 /**
036 * ID for serialization.
037 */
038 private static final long serialVersionUID = -326751707151867738L;
039
040 /**
041 * Object used to block {@link #setFormSheet} when the FormSheet demands it.
042 */
043 private transient Object m_oWaiter;
044 /**
045 * Return the object used to block {@link #setFormSheet} when the FormSheet demands it.
046 */
047 private Object getWaiter() {
048 if (m_oWaiter == null) {
049 m_oWaiter = new Object();
050 }
051
052 return m_oWaiter;
053 }
054
055 /**
056 * The currently displaying component.
057 */
058 private transient JComponent m_jcmpComponent;
059
060 /**
061 * The currently displaying button bar panel.
062 */
063 private transient JPanel m_jpButtonBar;
064
065 /**
066 * The current FormSheet.
067 */
068 private transient FormSheet m_fsCurrent;
069
070 /**
071 * The current MenuSheet.
072 */
073 private transient MenuSheet m_msCurrent;
074
075 /**
076 * The list of listeners.
077 */
078 protected transient EventListenerList m_ellListeners = new EventListenerList();
079
080 /**
081 * JDisplayDialogs are not meant to be serialized!
082 */
083 private void writeObject(ObjectOutputStream oos) throws IOException {
084 throw new NotSerializableException("JDisplayDialog");
085 }
086
087 /**
088 * Create a new JDisplayDialog.
089 */
090 public JDisplayDialog() {
091 super();
092
093 getContentPane().setLayout(new java.awt.BorderLayout());
094
095 addWindowListener(new WindowAdapter() {
096 public void windowClosing(WindowEvent e) {
097 if (m_fsCurrent != null) {
098 m_fsCurrent.cancel();
099 }
100 }
101 });
102 }
103
104 /**
105 * Create a new JDisplayDialog with the given owner.
106 *
107 * @param jfOwner the JFrame owning the display dialog.
108 */
109 public JDisplayDialog(JFrame jfOwner) {
110 super(jfOwner);
111
112 getContentPane().setLayout(new java.awt.BorderLayout());
113
114 addWindowListener(new WindowAdapter() {
115 public void windowClosing(WindowEvent e) {
116 if (m_fsCurrent != null) {
117 m_fsCurrent.cancel();
118 }
119 }
120 });
121 }
122
123 // FormSheetContainer interface methods.
124
125 /**
126 * Close a FormSheet.
127 *
128 * <p>If a FormSheet is closed, by default, the JDisplayDialog containing it is also closed. You can,
129 * however, alter this behavior by overriding {@link #formSheetClosed}.</p>
130 *
131 * @override Never Instead override {@link #formSheetClosed}.
132 *
133 * @param fs the FormSheet to be closed.
134 */
135 public void closeFormSheet(FormSheet fs) {
136 boolean fExplicit = true;
137
138 fs.detachDisplay();
139
140 if (m_fsCurrent == fs) {
141 m_fsCurrent = null;
142 } else {
143 fExplicit = false;
144 }
145
146 formSheetClosed();
147
148 synchronized (getWaiter()) {
149 getWaiter().notifyAll();
150 }
151
152 fireFormSheetRemoved(fs, fExplicit);
153 }
154
155 /**
156 * Hook method called when the FormSheet was closed.
157 *
158 * @override Sometimes The default implementation closes the JDisplayDialog.
159 */
160 protected void formSheetClosed() {
161 setVisible(false);
162 dispose();
163 }
164
165 /**
166 * In addition to disposing of the peer resources, remove the FormSheet and the
167 * MenuSheet.
168 *
169 * @override Never
170 */
171 public void dispose() {
172 try {
173 setFormSheet(null);
174 }
175 catch (InterruptedException e) {}
176
177 setMenuSheet(null);
178
179 super.dispose();
180 }
181
182 /**
183 * Notification event informing about a change of a FormSheet's caption.
184 *
185 * @override Never
186 *
187 * @param fs the FormSheet whose caption changed.
188 * @param sNewCaption the new caption of the FormSheet.
189 */
190 public void onFormSheetCaptionChanged(FormSheet fs, String sNewCaption) {
191 setTitle(sNewCaption);
192 }
193
194 /**
195 * Notification event informing about a change of a FormSheet's component.
196 *
197 * @override Never
198 *
199 * @param fs the FormSheet whose component changed.
200 * @param jcmpNew the new component of the FormSheet.
201 */
202 public void onFormSheetComponentChanged(FormSheet fs, JComponent jcmpNew) {
203 synchronized (fs.getComponentLock()) {
204 getContentPane().remove(m_jcmpComponent);
205
206 m_jcmpComponent = fs.getComponent();
207 if (m_jcmpComponent != null) {
208 getContentPane().add(m_jcmpComponent, BorderLayout.CENTER);
209 }
210
211 pack();
212 }
213 }
214
215 /**
216 * Notification event informing that a button was added to the FormSheet's button bar.
217 *
218 * @override Never
219 *
220 * @param fs the FormSheet whose button bar changed.
221 * @param fb the button that was added to the FormSheet.
222 */
223 public void onFormSheetButtonAdded(FormSheet fs, FormSheet.FormButton fb) {
224 synchronized (fs.getButtonsLock()) {
225 m_jpButtonBar.add(fb.getPeer());
226
227 pack();
228 }
229 }
230
231 /**
232 * Notification event informing that a button was removed from the FormSheet's button bar.
233 *
234 * @override Never
235 *
236 * @param fs the FormSheet whose button bar changed.
237 * @param fb the button that was removed from the FormSheet.
238 */
239 public void onFormSheetButtonRemoved(FormSheet fs, FormSheet.FormButton fb) {
240 synchronized (fs.getButtonsLock()) {
241 m_jpButtonBar.remove(fb.getPeer());
242
243 pack();
244 }
245 }
246
247 /**
248 * Notification event informing that all buttons were removed from a FormSheet's button bar.
249 *
250 * @override Never
251 *
252 * @param fs the FormSheet whose button bar was cleared.
253 */
254 public void onFormSheetButtonsCleared(FormSheet fs) {
255 synchronized (fs.getButtonsLock()) {
256 m_jpButtonBar.removeAll();
257
258 pack();
259 }
260 }
261
262 // Display interface methods
263
264 /**
265 * Set and display a FormSheet.
266 *
267 * <p>If {@link FormSheet#waitResponse fs.waitResponse()} returns true,
268 * <code>setFormSheet()</code> blocks, until the FormSheet is closed by a matching
269 * call to {@link #closeFormSheet}.</p>
270 *
271 * @override Never
272 *
273 * @param fs the FormSheet to be displayed.
274 *
275 * @exception InterruptedException if an interrupt occurs while waiting for the
276 * FormSheet to be closed.
277 */
278 public void setFormSheet(FormSheet fs) throws InterruptedException {
279
280 if (m_fsCurrent != null) {
281 FormSheet fsTemp = m_fsCurrent;
282
283 if (fs != null) { // setFormSheet (null) will be interpreted as an explicit close, too.
284 m_fsCurrent = null;
285 }
286
287 fsTemp.cancel();
288 }
289 getContentPane().removeAll();
290
291 if (fs != null) {
292 synchronized (fs.getComponentLock()) {
293 synchronized (fs.getButtonsLock()) {
294 setTitle(fs.getCaption());
295
296 fs.attach(this);
297 m_fsCurrent = fs;
298
299 m_jcmpComponent = fs.getComponent();
300
301 if (m_jcmpComponent != null) {
302 getContentPane().add(m_jcmpComponent, BorderLayout.CENTER);
303 }
304
305 m_jpButtonBar = new JPanel(false);
306 fs.fillBtnPanel(m_jpButtonBar);
307
308 getContentPane().add(m_jpButtonBar, BorderLayout.SOUTH);
309
310 pack();
311 }
312 }
313
314 fireFormSheetSet(fs);
315
316 if (fs.waitResponse()) {
317 synchronized (getWaiter()) {
318 while (fs.getDisplay() == this) {
319 getWaiter().wait();
320 }
321 }
322 }
323 }
324 }
325
326 /**
327 * Return the {@link FormSheet} that is currently attached to the display.
328 */
329 public FormSheet getFormSheet() {
330 return m_fsCurrent;
331 }
332
333 /**
334 * Close the current FormSheet.
335 *
336 * @override Never
337 */
338 public void closeFormSheet() {
339 if (m_fsCurrent != null) {
340 closeFormSheet(m_fsCurrent);
341 }
342 }
343
344 /**
345 * Open a fresh {@link JDisplayDialog} and display the FormSheet in it.
346 *
347 * @override Never
348 *
349 * @exception InterruptedException if an interrupt occured while waiting for the
350 * FormSheet to be closed.
351 */
352 public void popUpFormSheet(FormSheet fs) throws InterruptedException {
353 setVisible(true);
354
355 try {
356 setFormSheet(fs);
357 }
358 catch (InterruptedException e) {
359 if (fs.getDisplay() == this) {
360 fs.cancel();
361 }
362
363 throw e;
364 }
365 }
366
367 /**
368 * Opens a fresh {@link JDisplayDialog} which is assigned to a FormSheet and displays
369 * another FormSheet in it.
370 *
371 * @override Never
372 * @param fsParent the FormSheet to which the JDisplayDialog is assigned.
373 * @param fsToSet the FormSheet which is displayed by the JDisplayDialog.
374 *
375 * @exception InterruptedException if an interrupt occured while waiting for the
376 * FormSheet to be closed.
377 */
378 public void popUpFormSheet(FormSheet fsParent, FormSheet fsToSet) throws InterruptedException {
379 try {
380 setFormSheet(fsToSet);
381 setLocationRelativeTo(fsParent.getComponent());
382 setVisible(true);
383 }
384 catch (InterruptedException e) {
385 if (fsToSet.getDisplay() == this) {
386 fsToSet.cancel();
387 }
388 throw e;
389 }
390 }
391
392 /**
393 * Remove any old MenuSheet and display the new one.
394 *
395 * @override Never
396 *
397 * @param ms the MenuSheet to be displayed.
398 */
399 public void setMenuSheet(MenuSheet ms) {
400 if (m_msCurrent != null) {
401 m_msCurrent.setVisible(false);
402 }
403
404 m_msCurrent = ms;
405
406 if (m_msCurrent != null) {
407 m_msCurrent.setVisible(true);
408 setJMenuBar(ms.getMenuBar());
409 } else {
410 setJMenuBar(null);
411 }
412
413 pack();
414 }
415
416 /**
417 * Return the {@link MenuSheet} that is currently attached to the display.
418 */
419 public MenuSheet getMenuSheet() {
420 return m_msCurrent;
421 }
422
423 /**
424 * Return true to indicate this is a useable display.
425 *
426 * @override Never
427 */
428 public boolean isUseableDisplay() {
429 return true;
430 }
431
432 /**
433 * Add a listener to receive notification on the JDisplayDialog's FormSheet.
434 *
435 * @override Never
436 */
437 public void addFormSheetListener(FormSheetListener fsl) {
438 m_ellListeners.add(FormSheetListener.class, fsl);
439 }
440
441 /**
442 * Remove a listener to receive notification on the JDisplayDialog's FormSheet.
443 *
444 * @override Never
445 */
446 public void removeFormSheetListener(FormSheetListener fsl) {
447 m_ellListeners.remove(FormSheetListener.class, fsl);
448 }
449
450 /**
451 * Fire an event to all {@link sale.events.FormSheetListener FormSheetListeners} indicating that
452 * a {@link FormSheet} was set on this display. As FormSheet setting is always explicit, no
453 * extra parameter is necessary.
454 *
455 * @override Never
456 *
457 * @param fs the FormSheet that was set
458 */
459 protected void fireFormSheetSet(FormSheet fs) {
460 FormSheetEvent e = null;
461
462 Object[] listeners = m_ellListeners.getListenerList();
463
464 for (int i = listeners.length - 2; i >= 0; i -= 2) {
465 if (listeners[i] == FormSheetListener.class) {
466 if (e == null) {
467 e = new FormSheetEvent(this, fs, true);
468
469 }
470 ((FormSheetListener)listeners[i + 1]).formSheetSet(e);
471 }
472 }
473 }
474
475 /**
476 * Fire an event to all {@link sale.events.FormSheetListener FormSheetListeners} indicating that
477 * a {@link FormSheet} was removed from this display.
478 *
479 * @override Never
480 *
481 * @param fs the FormSheet that was set
482 * @param fExplicit true, if the FormSheet was closed explicitly, i.e. either by a call to one of
483 * the <code>closeFormSheet</code> methods or by <code>setFormSheet (null)</code>.
484 *
485 * @see #closeFormSheet()
486 * @see #closeFormSheet(FormSheet)
487 * @see #setFormSheet
488 */
489 protected void fireFormSheetRemoved(FormSheet fs, boolean fExplicit) {
490 FormSheetEvent e = null;
491
492 Object[] listeners = m_ellListeners.getListenerList();
493
494 for (int i = listeners.length - 2; i >= 0; i -= 2) {
495 if (listeners[i] == FormSheetListener.class) {
496 if (e == null) {
497 e = new FormSheetEvent(this, fs, fExplicit);
498
499 }
500 ((FormSheetListener)listeners[i + 1]).formSheetRemoved(e);
501 }
502 }
503 }
504
505 /**
506 * JDisplayDialog test suite.
507 */
508 public static void main(java.lang.String[] args) {
509 final JDisplayDialog jdd = new JDisplayDialog();
510 jdd.setVisible(true);
511
512 MenuSheet ms = new MenuSheet("Main");
513 ms.add(new MenuSheetItem("Quit", new Action() {
514 private static final long serialVersionUID = 2734448317849130419L;
515 public void doAction(SaleProcess p, SalesPoint sp) {
516 jdd.dispose();
517 }
518 }));
519
520 jdd.setMenuSheet(ms);
521
522 final MsgForm mfTest = new sale.stdforms.MsgForm("Testmessage",
523 "Dies ist ein Test des JFormSheetFrames.\n\n" +
524 "Wir verwenden dazu ein veraendertes MsgForm.");
525
526 mfTest.addButton("Toggle Caption", 1, new Action() {
527 private static final long serialVersionUID = 3661359200322902803L;
528 public void doAction(SaleProcess p, SalesPoint sp) {
529 if (mfTest.getCaption().equals("Testmessage")) {
530 mfTest.setCaption("Geaendert !");
531 } else {
532 mfTest.setCaption("Testmessage");
533 }
534 }
535 });
536
537 mfTest.addButton("Add button", 2, new Action() {
538 private static final long serialVersionUID = -6514280491544062500L;
539 public void doAction(SaleProcess p, SalesPoint sp) {
540 mfTest.addButton("Tester", 700, null);
541 mfTest.getButton(2).setEnabled(false);
542 mfTest.getButton(3).setEnabled(true);
543 }
544 });
545
546 mfTest.addButton("Remove button", 3, new Action() {
547 private static final long serialVersionUID = -4483019927000420030L;
548 public void doAction(SaleProcess p, SalesPoint sp) {
549 mfTest.removeButton(700);
550 mfTest.getButton(2).setEnabled(true);
551 mfTest.getButton(3).setEnabled(false);
552 }
553 });
554 mfTest.getButton(3).setEnabled(false);
555
556 final JComponent[] ajcmp = new JComponent[1];
557 ajcmp[0] = new JLabel("Tester");
558
559 mfTest.addButton("Toggle Component", 4, new Action() {
560 private static final long serialVersionUID = -7835577623326127041L;
561 public void doAction(SaleProcess p, SalesPoint sp) {
562 ajcmp[0] = mfTest.setComponent(ajcmp[0]);
563 }
564 });
565
566 try {
567 jdd.setFormSheet(mfTest);
568 }
569 catch (InterruptedException e) {}
570
571 System.err.println("FormSheet was " + ((mfTest.isCancelled()) ? ("cancelled.") : ("closed normally.")));
572
573 System.exit(0);
574 }
575
576 public void load(ObjectInputStream ois) throws IOException, ClassNotFoundException {}
577
578 public void save(ObjectOutputStream oos) throws IOException {}
579
580 }