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    }