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