001/* A frame for presenting a dialog
002
003 Copyright (c) 2003-2014 The Regents of the University of California.
004 All rights reserved.
005 Permission is hereby granted, without written agreement and without
006 license or royalty fees, to use, copy, modify, and distribute this
007 software and its documentation for any purpose, provided that the above
008 copyright notice and the following two paragraphs appear in all copies
009 of this software.
010
011 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
012 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
013 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
014 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
015 SUCH DAMAGE.
016
017 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
018 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
019 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
020 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
021 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
022 ENHANCEMENTS, OR MODIFICATIONS.
023
024 PT_COPYRIGHT_VERSION_2
025 COPYRIGHTENDKEY
026
027 */
028package ptolemy.actor.gui;
029
030import java.awt.BorderLayout;
031import java.awt.Dimension;
032import java.awt.Frame;
033import java.awt.GraphicsConfiguration;
034import java.awt.GraphicsDevice;
035import java.awt.GraphicsEnvironment;
036import java.awt.Point;
037import java.awt.Rectangle;
038import java.awt.event.ActionEvent;
039import java.awt.event.ActionListener;
040import java.awt.event.WindowAdapter;
041import java.awt.event.WindowEvent;
042import java.net.URL;
043
044import javax.swing.JButton;
045import javax.swing.JComponent;
046import javax.swing.JFrame;
047import javax.swing.JPanel;
048import javax.swing.JScrollPane;
049
050import ptolemy.kernel.Entity;
051import ptolemy.util.MessageHandler;
052
053///////////////////////////////////////////////////////////////////
054//// PtolemyDialog
055
056/**
057 Ptolemy specific dialog.
058
059 @author Rowland R Johnson
060 @version $Id$
061 @since Ptolemy II 4.0
062 @Pt.ProposedRating Red (rowland)
063 @Pt.AcceptedRating Red (rowland)
064 */
065@SuppressWarnings("serial")
066public abstract class PtolemyDialog extends JFrame implements ActionListener {
067    /**
068     * Construct a PtolemyDialog.
069     *
070     * @param title The title of the PtolemyDialog.
071     * @param dialogTableau  The dialogTableau, used to set the title.
072     * @param owner  The frame.
073     * @param target The model
074     * @param configuration  a Configuration object
075     */
076    public PtolemyDialog(String title, DialogTableau dialogTableau, Frame owner,
077            Entity target, Configuration configuration) {
078        super(title);
079        _owner = owner;
080        _dialogTableau = dialogTableau;
081        _target = target;
082        _configuration = configuration;
083        _dialogTableau.setTitle(title);
084
085        // This JDialog consists of two components. On top is a JComponent
086        // inside of a JScrolPane that displays the ports and their attributes.
087        // On bottom is a JPanel that contains buttons that cause various
088        // actions.
089        JPanel _buttons = _createButtonsPanel();
090        getContentPane().add(_buttons, BorderLayout.SOUTH);
091        addWindowListener(new WindowAdapter() {
092            @Override
093            public void windowClosing(WindowEvent e) {
094                _cancel();
095            }
096        });
097
098        _owner.addWindowListener(new WindowAdapter() {
099            @Override
100            public void windowIconified(WindowEvent e) {
101                _iconify();
102            }
103
104            @Override
105            public void windowDeiconified(WindowEvent e) {
106                _deiconify();
107            }
108        });
109
110        GraphicsEnvironment ge = GraphicsEnvironment
111                .getLocalGraphicsEnvironment();
112        GraphicsDevice[] SCREENS = ge.getScreenDevices();
113        Point ownerLoc = owner.getLocation();
114        Rectangle screenBounds = null;
115
116        for (GraphicsDevice element : SCREENS) {
117            GraphicsConfiguration gc = element.getDefaultConfiguration();
118            Rectangle bounds = gc.getBounds();
119
120            if (bounds.contains(ownerLoc)) {
121                screenBounds = bounds;
122                break;
123            }
124        }
125
126        if (screenBounds != null) {
127            Dimension size = getPreferredSize();
128            int x = screenBounds.x + screenBounds.width / 2 - size.width / 2;
129            int y = screenBounds.y + screenBounds.height / 2 - size.height / 2;
130            setLocation(x, y);
131        } else {
132            setLocationRelativeTo(_owner);
133        }
134    }
135
136    ///////////////////////////////////////////////////////////////////
137    ////                         public methods                    ////
138
139    /** If the action event is a JButton, process the button press.
140     *  @param aEvent The event.
141     */
142    @Override
143    public void actionPerformed(ActionEvent aEvent) {
144        String command = aEvent.getActionCommand();
145
146        if (aEvent.getSource() instanceof JButton) {
147            _processButtonPress(command);
148        }
149    }
150
151    /** Return the target.
152     *  @return The target.
153     *  @see #setTarget(Entity)
154     */
155    public Entity getTarget() {
156        return _target;
157    }
158
159    /** If necessary save any state.
160     *  In this base class, do nothing.  Derived classes should extend
161     *  this method so that the {@link #_cancel()} method save state
162     *  if necessary.
163     */
164    public void saveIfRequired() {
165    }
166
167    /** Set the contents of this dialog.
168     *  @param contents The contents.
169     */
170    public void setContents(JComponent contents) {
171        _contents = contents;
172        getContentPane().add(_contents, BorderLayout.CENTER);
173    }
174
175    /** Set the contents of this dialog.
176     *  @param contents The contents.
177     */
178    public void setScrollableContents(JComponent contents) {
179        _contents = contents;
180
181        JScrollPane scrollPane = new JScrollPane(_contents);
182        getContentPane().add(scrollPane, BorderLayout.CENTER);
183    }
184
185    /** Set the target of this dialog.
186     * @param entity Target of this dialog.
187     *  @see #getTarget()
188     */
189    public void setTarget(Entity entity) {
190        _target = entity;
191    }
192
193    ///////////////////////////////////////////////////////////////////
194    ////                         protected methods                 ////
195
196    /** Cancel this dialog, saving if necessary.
197     */
198    protected void _cancel() {
199        saveIfRequired();
200        dispose();
201    }
202
203    /** Created extended buttons.
204     *  @param _buttons The buttons to be created.
205     */
206    protected abstract void _createExtendedButtons(JPanel _buttons);
207
208    /** Get the URL that is the help for this dialog.
209     * @return URL that is the help for this dialog.
210     */
211    protected abstract URL _getHelpURL();
212
213    /** Return true if any of the values have been changed, but the state
214     *  has not yet been saved.
215     *  @return True if values have been changed but not saved.
216     */
217    protected boolean _isDirty() {
218        return _dirty;
219    }
220
221    /** Process button presses.
222     *  The button semantics are
223     *  <br>Commit - Apply and then cancel the dialog.
224     *  <br>Apply  - make the changes that have been expressed thus far.
225     *  <br>Help   - Show the associated help.
226     *  <br>Cancel - Remove the dialog without making any pending changes.
227     * @param button The name of the button to process.
228     */
229    protected void _processButtonPress(String button) {
230        if (button.equals("Cancel")) {
231            _cancel();
232        } else if (button.equals("Help")) {
233            _showHelp();
234        } else {
235            //TODO throw an exception here
236        }
237    }
238
239    /** Set the boolean that determines if the GUI has a change that has not
240     *  applied to the system.
241     * @param dirty True if the GUI has a change that has not been applied.
242     */
243    protected void _setDirty(boolean dirty) {
244        _dirty = dirty;
245    }
246
247    /** Display the help URL.
248     *  @see #_getHelpURL()
249     */
250    protected void _showHelp() {
251        URL toRead = _getHelpURL();
252
253        if (toRead != null && _configuration != null) {
254            try {
255                _configuration.openModel(null, toRead, toRead.toExternalForm());
256            } catch (Exception ex) {
257                MessageHandler.error("Help screen failure", ex);
258            }
259        } else {
260            MessageHandler.error("No help available.");
261        }
262    }
263
264    ///////////////////////////////////////////////////////////////////
265    ////                         protected members                   ////
266
267    /** The configuration that corresponds with this dialog.
268     *  The configuration is used to properly display the help text.
269     */
270    protected Configuration _configuration;
271
272    /** The help button. */
273    protected JButton _helpButton;
274
275    /** The cancel button. */
276    protected JButton _cancelButton;
277
278    ///////////////////////////////////////////////////////////////////
279    ////                         private methods                   ////
280
281    /** Create the buttons panel. */
282    private JPanel _createButtonsPanel() {
283        JPanel _buttons = new JPanel();
284
285        _createExtendedButtons(_buttons);
286        _helpButton = new JButton("Help");
287        _buttons.add(_helpButton);
288        _cancelButton = new JButton("Cancel");
289        _buttons.add(_cancelButton);
290
291        for (int i = 0; i < _buttons.getComponentCount(); i++) {
292            ((JButton) _buttons.getComponent(i)).addActionListener(this);
293        }
294
295        return _buttons;
296    }
297
298    private void _deiconify() {
299        setExtendedState(Frame.NORMAL);
300    }
301
302    private void _iconify() {
303        setExtendedState(Frame.ICONIFIED);
304    }
305
306    ///////////////////////////////////////////////////////////////////
307    ////                         private members                   ////
308    private JComponent _contents;
309
310    /** The following is true if any of the values have been changed but not
311     * applied.
312     */
313    private boolean _dirty = false;
314
315    private DialogTableau _dialogTableau;
316
317    private Frame _owner;
318
319    private Entity _target;
320}