001    /*
002     * The contents of this file are subject to the Mozilla Public License
003     * Version 1.1 (the "License");  you may not use this file except in 
004     * compliance with the License.  You may obtain a copy of the License at
005     * http://www.mozilla.org/MPL/
006     *
007     * Software distributed under the License is distributed on an "AS IS" basis,
008     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
009     * the specific language governing rights and limitations under the License.
010     *
011     * The Original Code is Protege-2000.
012     *
013     * The Initial Developer of the Original Code is Stanford University. Portions
014     * created by Stanford University are Copyright (C) 2006.  All Rights Reserved.
015     *
016     * Protege was developed by Stanford Medical Informatics
017     * (http://www.smi.stanford.edu) at the Stanford University School of Medicine
018     * with support from the National Library of Medicine, the National Science
019     * Foundation, and the Defense Advanced Research Projects Agency.  Current
020     * information about Protege can be obtained at http://protege.stanford.edu.
021     *
022     */
023    
024    package edu.uchsc.ccp.knowtator.ui;
025    
026    import java.awt.BorderLayout;
027    import java.awt.Component;
028    import java.awt.Container;
029    import java.awt.Dialog;
030    import java.awt.FlowLayout;
031    import java.awt.Frame;
032    import java.awt.GridLayout;
033    import java.awt.Point;
034    import java.awt.Window;
035    import java.awt.event.ActionEvent;
036    import java.awt.event.KeyAdapter;
037    import java.awt.event.KeyEvent;
038    import java.awt.event.WindowAdapter;
039    import java.awt.event.WindowEvent;
040    
041    import javax.swing.AbstractAction;
042    import javax.swing.Action;
043    import javax.swing.BorderFactory;
044    import javax.swing.JButton;
045    import javax.swing.JDialog;
046    import javax.swing.JPanel;
047    import javax.swing.SwingUtilities;
048    
049    import edu.stanford.smi.protege.resource.LocalizedText;
050    import edu.stanford.smi.protege.resource.ResourceKey;
051    import edu.stanford.smi.protege.util.ComponentFactory;
052    import edu.stanford.smi.protege.util.ComponentUtilities;
053    import edu.stanford.smi.protege.util.Disposable;
054    import edu.stanford.smi.protege.util.MessagePanel;
055    import edu.stanford.smi.protege.util.StandardAction;
056    import edu.stanford.smi.protege.util.Validatable;
057    
058    /**
059     * This code was copied directly from the Protege source code from
060     * edu.stanford.smi.protege.util.ModalDialog I copied the code so that I could
061     * modify it so that I could move the location of the where the dialog appears.
062     * 
063     * A class to handle all modal dialog processing. This class just wraps the
064     * JDialog modal dialog implementation but adds some additional features such as
065     * a call back mechanism to stop an "OK". This class was originally written to
066     * work around the JDK 1.0 modal dialogs that didn't work at all. It also
067     * predates the JOptionPane stuff that is similar.
068     * 
069     * @author Ray Fergerson <fergerson@smi.stanford.edu>
070     */
071    public class ModalDialog extends JDialog implements Disposable {
072    
073            static final long serialVersionUID = 0;
074    
075            public static final int OPTION_OK = 1;
076    
077            public static final int OPTION_YES = 2;
078    
079            public static final int OPTION_NO = 3;
080    
081            public static final int OPTION_CANCEL = 4;
082    
083            public static final int OPTION_CLOSE = 5;
084    
085            public static final int RESULT_ERROR = 6;
086    
087            public static final int MODE_OK_CANCEL = 11;
088    
089            public static final int MODE_YES_NO_CANCEL = 12;
090    
091            public static final int MODE_YES_NO = 13;
092    
093            public static final int MODE_CLOSE = 14;
094    
095            private int _result;
096    
097            private Component _panel;
098    
099            private JPanel _buttonsPanel;
100    
101            private CloseCallback _closeCallback;
102    
103            private boolean _enableCloseButton;
104    
105            private static ModalDialog _currentDialog; // used for testing
106    
107            private static Point _location;
108    
109            public static interface CloseCallback {
110                    boolean canClose(int result);
111            }
112    
113            private class WindowCloseListener extends WindowAdapter {
114                    public void windowClosing(WindowEvent event) {
115                            int option = OPTION_CANCEL;
116                            if (!_enableCloseButton) {
117                                    int result = ModalDialog.showMessageDialog(ModalDialog.this, LocalizedText
118                                                    .getText(ResourceKey.DIALOG_SAVE_CHANGES_TEXT), ModalDialog.MODE_YES_NO, null);
119                                    if (result == OPTION_YES) {
120                                            option = OPTION_OK;
121                                    }
122                            }
123                            attemptClose(option);
124                    }
125            }
126    
127            private ModalDialog(Dialog parent, Component panel, String title, int mode, CloseCallback callback,
128                            boolean enableClose, Point location) {
129                    super(parent, title, true);
130                    init(panel, mode, callback, enableClose, location);
131            }
132    
133            private ModalDialog(Frame parentFrame, Component panel, String title, int mode, CloseCallback callback,
134                            boolean enableCloseButton, Point location) {
135                    super(parentFrame, title, true);
136                    init(panel, mode, callback, enableCloseButton, location);
137            }
138    
139            public static void attemptDialogClose(int result) {
140                    ModalDialog dialog = getCurrentDialog();
141                    if (dialog != null) {
142                            dialog.attemptClose(result);
143                    }
144            }
145    
146            public void attemptClose(int result) {
147                    _location = getLocation();
148                    boolean canClose;
149                    if (_closeCallback == null) {
150                            canClose = true;
151                    } else {
152                            canClose = _closeCallback.canClose(result);
153                    }
154                    if (canClose && result == OPTION_OK && _panel instanceof Validatable) {
155                            Validatable validatable = (Validatable) _panel;
156                            canClose = validatable.validateContents();
157                            if (canClose) {
158                                    validatable.saveContents();
159                            }
160                    }
161                    if (canClose) {
162                            _result = result;
163                            close();
164                    }
165            }
166    
167            private void close() {
168                    ComponentUtilities.dispose(this);
169                    _currentDialog = null;
170            }
171    
172            private JButton createButton(final int result, ResourceKey key) {
173                    Action action = new StandardAction(key) {
174                            public void actionPerformed(ActionEvent event) {
175                                    attemptClose(result);
176                            }
177                    };
178                    JButton button = ComponentFactory.createButton(action);
179                    button.addKeyListener(new KeyAdapter() {
180                            public void keyPressed(KeyEvent event) {
181                                    switch (event.getKeyCode()) {
182                                    case KeyEvent.VK_ENTER:
183                                            attemptClose(result);
184                                            break;
185                                    case KeyEvent.VK_ESCAPE:
186                                            attemptClose(OPTION_CANCEL);
187                                            break;
188                                    default:
189                                            // do nothing
190                                            break;
191                                    }
192                            }
193                    });
194                    return button;
195            }
196    
197            private JPanel createButtonsPanel(int mode) {
198                    JPanel buttonsGrid = ComponentFactory.createPanel();
199                    buttonsGrid.setLayout(new GridLayout(1, 3, 10, 10));
200                    switch (mode) {
201                    case MODE_OK_CANCEL:
202                            buttonsGrid.add(createButton(OPTION_OK, ResourceKey.OK_BUTTON_LABEL));
203                            buttonsGrid.add(createButton(OPTION_CANCEL, ResourceKey.CANCEL_BUTTON_LABEL));
204                            break;
205                    case MODE_YES_NO:
206                            buttonsGrid.add(createButton(OPTION_YES, ResourceKey.YES_BUTTON_LABEL));
207                            buttonsGrid.add(createButton(OPTION_NO, ResourceKey.NO_BUTTON_LABEL));
208                            break;
209                    case MODE_YES_NO_CANCEL:
210                            buttonsGrid.add(createButton(OPTION_YES, ResourceKey.YES_BUTTON_LABEL));
211                            buttonsGrid.add(createButton(OPTION_NO, ResourceKey.NO_BUTTON_LABEL));
212                            buttonsGrid.add(createButton(OPTION_CANCEL, ResourceKey.CANCEL_BUTTON_LABEL));
213                            break;
214                    case MODE_CLOSE:
215                            buttonsGrid.add(createButton(OPTION_CLOSE, ResourceKey.CLOSE_BUTTON_LABEL));
216                            break;
217                    default:
218                            // do nothing
219                            break;
220                    }
221    
222                    JPanel panel = ComponentFactory.createPanel();
223                    panel.setLayout(new FlowLayout());
224                    panel.add(buttonsGrid);
225    
226                    return panel;
227            }
228    
229            public static ModalDialog getCurrentDialog() {
230                    return _currentDialog;
231            }
232    
233            // Doesn't work!
234            private void getFocus() {
235                    SwingUtilities.invokeLater(new Runnable() {
236                            public void run() {
237                                    JButton button = (JButton) ((Container) _buttonsPanel.getComponent(0)).getComponent(0);
238                                    button.requestFocus();
239                            }
240                    });
241            }
242    
243            private void init(Component panel, int mode, CloseCallback callback, boolean enableCloseButton, Point location) {
244                    _currentDialog = this;
245                    _closeCallback = callback;
246                    _enableCloseButton = enableCloseButton;
247                    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
248                    addWindowListener(new WindowCloseListener());
249    
250                    switch (mode) {
251                    case MODE_OK_CANCEL:
252                            _result = OPTION_CANCEL;
253                            break;
254                    case MODE_YES_NO_CANCEL:
255                            _result = OPTION_CANCEL;
256                            break;
257                    case MODE_CLOSE:
258                            _result = OPTION_CLOSE;
259                            break;
260                    default:
261                            // do nothing
262                            break;
263                    }
264    
265                    _panel = panel;
266                    _buttonsPanel = createButtonsPanel(mode);
267    
268                    layoutWidgets();
269    
270                    pack();
271                    ComponentUtilities.center(this);
272                    getFocus();
273                    if (location != null) {
274                            _location = location;
275                            setLocation(location);
276                    } else if (_location != null) {
277                            setLocation(_location);
278                    } else {
279                            _location = getLocation();
280                    }
281                    setVisible(true);
282            }
283    
284            private void layoutWidgets() {
285                    JPanel borderedPanel = ComponentFactory.createPanel();
286                    borderedPanel.setLayout(new BorderLayout());
287                    borderedPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
288                    borderedPanel.add(_panel);
289    
290                    getContentPane().setLayout(new BorderLayout());
291                    getContentPane().add(borderedPanel, BorderLayout.CENTER);
292                    getContentPane().add(_buttonsPanel, BorderLayout.SOUTH);
293            }
294    
295            public static int showDialog(Component parent, Component panel, String title, int mode, Point location) {
296                    return showDialog(parent, panel, title, mode, null, location);
297            }
298    
299            public static int showDialog(Component parent, Component panel, String title, int mode, CloseCallback callback,
300                            Point location) {
301                    return showDialog(parent, panel, title, mode, callback, true, location);
302            }
303    
304            public static int showDialog(Component parent, Component panel, String title, int mode, CloseCallback callback,
305                            boolean enableCloseButton, Point location) {
306                    ModalDialog dialog;
307                    Window window;
308                    if (parent == null || parent instanceof Window) {
309                            window = (Window) parent;
310                    } else {
311                            window = SwingUtilities.windowForComponent(parent);
312                    }
313                    if (window instanceof Frame || window == null) {
314                            dialog = new ModalDialog((Frame) window, panel, title, mode, callback, enableCloseButton, location);
315                    } else {
316                            dialog = new ModalDialog((Dialog) window, panel, title, mode, callback, enableCloseButton, location);
317                    }
318                    int result;
319                    if (dialog == null) {
320                            result = RESULT_ERROR;
321                    } else {
322                            result = dialog._result;
323                    }
324                    return result;
325            }
326    
327            public static void showMessageDialog(Component parent, String message, Point location) {
328                    showMessageDialog(parent, message, ModalDialog.MODE_CLOSE, location);
329            }
330    
331            public static void showMessageDialog(Component parent, String message, String title, Point location) {
332                    showMessageDialog(parent, message, title, ModalDialog.MODE_CLOSE, location);
333            }
334    
335            public static int showMessageDialog(Component parent, String message, int mode, Point location) {
336                    return showDialog(parent, new MessagePanel(message), "", mode, location);
337            }
338    
339            public static int showMessageDialog(Component parent, String message, String title, int mode, Point location) {
340                    return showDialog(parent, new MessagePanel(message), title, mode, location);
341            }
342    
343            public static Action getCloseAction(final Component c) {
344                    return new AbstractAction() {
345                            public void actionPerformed(ActionEvent event) {
346                                    Component root = SwingUtilities.getRoot(c);
347                                    if (root instanceof ModalDialog) {
348                                            ModalDialog dialog = (ModalDialog) root;
349                                            dialog.attemptClose(ModalDialog.OPTION_OK);
350                                    }
351                            }
352                    };
353            }
354    
355    }
356