001/* A top-level dialog window for displaying the state of an instance.
002
003 Copyright (c) 2006-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 */
027package ptolemy.actor.gui;
028
029import java.awt.Color;
030import java.awt.Component;
031import java.awt.Dimension;
032import java.awt.Frame;
033import java.awt.event.KeyAdapter;
034import java.awt.event.KeyEvent;
035import java.net.URL;
036import java.util.ArrayList;
037import java.util.Arrays;
038import java.util.List;
039
040import javax.swing.JLabel;
041import javax.swing.JPanel;
042import javax.swing.JTable;
043import javax.swing.table.AbstractTableModel;
044import javax.swing.table.TableCellRenderer;
045import javax.swing.table.TableColumn;
046
047import ptolemy.kernel.Entity;
048import ptolemy.kernel.util.ChangeListener;
049import ptolemy.kernel.util.ChangeRequest;
050import ptolemy.kernel.util.NamedObj;
051import ptolemy.kernel.util.Settable;
052
053///////////////////////////////////////////////////////////////////
054//// OpenInstanceDialog
055
056/**
057 This class is a non-modal dialog that displays the current state of
058 parameters of an instance.
059
060 @author Edward A. Lee
061 @version $Id$
062 @since Ptolemy II 5.2
063 @Pt.ProposedRating Yellow (eal)
064 @Pt.AcceptedRating Red (eal)
065 */
066@SuppressWarnings("serial")
067public class OpenInstanceDialog extends PtolemyDialog
068        implements ChangeListener {
069
070    /** Construct a dialog that presents the parameters as a table. Each row of the
071     *  table corresponds to one parameter. The table shows the expression and its
072     *  current evaluated value.
073     *  @param tableau The DialogTableau.
074     *  @param owner The object that, per the user, appears to be generating the
075     *   dialog.
076     *  @param target The object whose ports are being configured.
077     *  @param configuration The configuration to use to open the help screen
078     *   (or null if help is not supported).
079     */
080    public OpenInstanceDialog(DialogTableau tableau, Frame owner, Entity target,
081            Configuration configuration) {
082        super("Instance: " + target.getFullName(), tableau, owner, target,
083                configuration);
084
085        // Listen for changes that may need to be reflected in the table.
086        // FIXME: Should we just selectively listen to each parameter?
087        getTarget().addChangeListener(this);
088
089        _parameterTable = new JTable();
090
091        // Initialize which columns will be visible for this target.
092        _initColumnNames();
093
094        // Create the TableModel and set certain cell editors and renderers
095        _setupTableModel();
096
097        // The height of the window depends on the number of columns.
098        // FIXME: How to know the height of each row? 16 is a guess.
099        int height = _parameterTableModel.getRowCount() * 16;
100        if (height < 64) {
101            height = 64;
102        } else if (height > 256) {
103            height = 256;
104        }
105        _parameterTable
106                .setPreferredScrollableViewportSize(new Dimension(600, height));
107
108        // Initialize the displayed column widths.
109        _initColumnSizes();
110
111        // Make the contents of the table scrollable
112        setScrollableContents(_parameterTable);
113
114        _parameterTable.addKeyListener(new KeyAdapter() {
115            @Override
116            public void keyReleased(KeyEvent event) {
117                int code = event.getKeyCode();
118                if (code == KeyEvent.VK_ENTER || code == KeyEvent.VK_ESCAPE) {
119                    _cancel();
120                }
121            }
122        });
123
124        pack();
125        setVisible(true);
126    }
127
128    ///////////////////////////////////////////////////////////////////
129    ////                         public methods                    ////
130
131    /** Update the table.
132     *  This is called when a change has been successfully executed.
133     *  @param change The change that has been executed.
134     */
135    @Override
136    public void changeExecuted(ChangeRequest change) {
137        // The ports of the _target may have changed.
138        _setupTableModel();
139
140        // Given a new renderer, need to do this as well.
141        _initColumnSizes();
142    }
143
144    /** Do nothing.
145     *  This is called when a change has resulted in an exception.
146     *  @param change The change that was attempted.
147     *  @param exception The exception that resulted.
148     */
149    @Override
150    public void changeFailed(ChangeRequest change, Exception exception) {
151    }
152
153    ///////////////////////////////////////////////////////////////////
154    ////                         protected methods                 ////
155
156    /** Do nothing. This dialog doesn't need additional buttons.
157     */
158    @Override
159    protected void _createExtendedButtons(JPanel _buttons) {
160    }
161
162    /** Return a URL that points to the help page, which for this
163     *  dialog is the expressions documentation.
164     *  @return A URL that points to the help page
165     */
166    @Override
167    protected URL _getHelpURL() {
168        URL doc = getClass().getClassLoader()
169                .getResource("doc/openInstanceHelp.htm");
170        return doc;
171    }
172
173    ///////////////////////////////////////////////////////////////////
174    ////                         private methods                   ////
175
176    /** Initialize which columns will be visible for this target.
177     */
178    private void _initColumnNames() {
179        String[] temp = { ColumnNames.COL_NAME, ColumnNames.COL_EXPRESSION,
180                ColumnNames.COL_VALUE };
181        // Store the column names as an ArrayList.
182        List columnList = Arrays.asList(temp);
183        _columnNames = new ArrayList(columnList);
184    }
185
186    /** Initialize the displayed column widths.
187     */
188    private void _initColumnSizes() {
189        TableColumn column = null;
190        column = _parameterTable.getColumnModel().getColumn(0);
191        column.setPreferredWidth(150);
192        // column.setMaxWidth(300);
193        column = _parameterTable.getColumnModel().getColumn(1);
194        column.setPreferredWidth(300);
195        column = _parameterTable.getColumnModel().getColumn(2);
196        column.setPreferredWidth(300);
197    }
198
199    /** Creates and sets the TableModel. Also arranges for some columns
200     *  to have their particular renderers and/or editors. This method
201     *  will be invoked when the dialog is created, and every time a
202     *  change request from above causes the table to change.
203     */
204    private void _setupTableModel() {
205        _parameterTableModel = new ParametersTableModel(getTarget());
206        _parameterTable.setModel(_parameterTableModel);
207        _parameterTable.setDefaultRenderer(String.class,
208                new StringCellRenderer());
209    }
210
211    ///////////////////////////////////////////////////////////////////
212    ////                         private variables                 ////
213
214    /** List of names of columns that will be used for this target. */
215    private ArrayList _columnNames;
216
217    /** The background color for expert parameters. */
218    private static Color _EXPERT_COLOR = new Color(1.0f, 0.9f, 0.9f);
219
220    /** The background color for invisible parameters. */
221    private static Color _INVISIBLE_COLOR = new Color(0.9f, 0.9f, 0.9f);
222
223    /** The target parameter list. */
224    private List _parameters;
225
226    /** Table of parameters. */
227    JTable _parameterTable;
228
229    /** The table model. */
230    ParametersTableModel _parameterTableModel = null;
231
232    /** Strings that are available for the column names. */
233    private static class ColumnNames {
234        public final static String COL_NAME = "Name";
235
236        public final static String COL_EXPRESSION = "Expression";
237
238        public final static String COL_VALUE = "Value";
239    }
240
241    ///////////////////////////////////////////////////////////////////
242    ////                         inner classes                     ////
243
244    /** The table model.
245     */
246    private class ParametersTableModel extends AbstractTableModel {
247
248        /** Create a table model for the specified target.
249         *  @param target The target.
250         */
251        public ParametersTableModel(NamedObj target) {
252            _parameters = target.attributeList(Settable.class);
253        }
254
255        /** Return the number of columns.
256         *  @see javax.swing.table.TableModel#getColumnCount()
257         */
258        @Override
259        public int getColumnCount() {
260            return _columnNames.size();
261        }
262
263        /** Return the number of rows.
264         *  @see javax.swing.table.TableModel#getRowCount()
265         */
266        @Override
267        public int getRowCount() {
268            return _parameters.size();
269        }
270
271        /** Return the column header name.
272         *  @see javax.swing.table.TableModel#getColumnName(int)
273         */
274        @Override
275        public String getColumnName(int col) {
276            return (String) _columnNames.get(col);
277        }
278
279        /** Return the value at a particular row and column.
280         *  @param row The row number.
281         *  @param col The column number.
282         *  @see javax.swing.table.TableModel#getValueAt(int, int)
283         */
284        @Override
285        public Object getValueAt(int row, int col) {
286            Settable parameter = (Settable) _parameters.get(row);
287            if (ColumnNames.COL_NAME.equals(getColumnName(col))) {
288                return parameter.getDisplayName();
289            } else if (ColumnNames.COL_EXPRESSION.equals(getColumnName(col))) {
290                return parameter.getExpression();
291            } else {
292                return parameter.getValueAsString();
293            }
294        }
295
296        /** Set the value at a particular row and column, which does nothing
297         *  because this table is not editable.
298         *  @param value The new value.
299         *  @param row The row number.
300         *  @param col The column number.
301         *  @see javax.swing.table.TableModel#setValueAt(Object, int, int)
302         */
303        @Override
304        public void setValueAt(Object value, int row, int col) {
305        }
306
307        /** Get the Java Class associated with a column param column.
308         *  @param col The column number.
309         *  @return String.class.
310         *  @see javax.swing.table.TableModel#getColumnClass(int)
311         */
312        @Override
313        public Class getColumnClass(int col) {
314            return String.class;
315        }
316
317        /** Return false. This table is not editable.
318         *  @param row The row number.
319         *  @param col The column number.
320         *  @return False.
321         *  @see javax.swing.table.TableModel#isCellEditable(int, int)
322         */
323        @Override
324        public boolean isCellEditable(int row, int col) {
325            return false;
326        }
327    }
328
329    /** Default renderer for table cells.
330     */
331    private class StringCellRenderer extends JLabel
332            implements TableCellRenderer {
333        public StringCellRenderer() {
334            super();
335        }
336
337        @Override
338        public Component getTableCellRendererComponent(JTable table,
339                Object value, boolean isSelected, boolean hasFocus, int row,
340                int col) {
341            setOpaque(true);
342            setText((String) value);
343            // The color depends on the properties of the parameter.
344            Settable parameter = (Settable) _parameters.get(row);
345            if (parameter.getVisibility() == Settable.EXPERT) {
346                setBackground(_EXPERT_COLOR);
347            } else if (parameter.getVisibility() == Settable.NONE) {
348                setBackground(_INVISIBLE_COLOR);
349            } else {
350                setBackground(Color.WHITE);
351            }
352            return this;
353        }
354    }
355}