001/* A top-level dialog window for editing Unit constraints.
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 */
027package ptolemy.vergil.unit;
028
029import java.awt.Dimension;
030import java.awt.Frame;
031import java.net.URL;
032import java.util.Vector;
033
034import javax.swing.DefaultCellEditor;
035import javax.swing.JButton;
036import javax.swing.JPanel;
037import javax.swing.JTable;
038import javax.swing.JTextField;
039import javax.swing.ListSelectionModel;
040import javax.swing.event.ListSelectionEvent;
041import javax.swing.event.ListSelectionListener;
042import javax.swing.table.AbstractTableModel;
043import javax.swing.table.TableColumn;
044
045import ptolemy.actor.gui.Configuration;
046import ptolemy.actor.gui.DialogTableau;
047import ptolemy.actor.gui.PtolemyDialog;
048import ptolemy.kernel.Entity;
049import ptolemy.kernel.util.ChangeListener;
050import ptolemy.kernel.util.ChangeRequest;
051import ptolemy.moml.MoMLChangeRequest;
052import ptolemy.moml.unit.UnitAttribute;
053import ptolemy.moml.unit.UnitEquation;
054
055///////////////////////////////////////////////////////////////////
056//// UnitConstraintsDialog
057
058/**
059 Unit Constraints Dialog.
060
061 @author Rowland R Johnson
062 @version $Id$
063 @since Ptolemy II 8.0
064 @Pt.ProposedRating Yellow (rowland)
065 @Pt.AcceptedRating Red (rowland)
066 */
067@SuppressWarnings("serial")
068public class UnitConstraintsDialog extends PtolemyDialog
069        implements ChangeListener {
070    /**
071     * Construct a dialog that presents Unit constraints as a table. Each row
072     * of the table corresponds to one constraint. The user modifies the table
073     * to specify changes in the equations.
074     * <p>
075     * This dialog is is not modal. In particular, changes can be undone by
076     * clicking Edit-&gt;Undo, and the help screen can be manipulated while this
077     * dialog exists. The dialog is placed relative to the owner.
078     *
079     * @param tableau The object that, per the user, appears to be
080     * generating the dialog.
081     * @param owner The frame.
082     * @param target The object whose ports are being configured.
083     * @param configuration The configuration to use to open the help
084     * screen (or null if help is not supported).
085     */
086    public UnitConstraintsDialog(DialogTableau tableau, Frame owner,
087            Entity target, Configuration configuration) {
088        super("Configure units for " + target.getName(), tableau, owner, target,
089                configuration);
090
091        Vector _constraintExpression = new Vector();
092        UnitAttribute _unitConstraints = (UnitAttribute) target
093                .getAttribute("_unitConstraints");
094
095        if (_unitConstraints != null) {
096            Vector _constraintExpressions = _unitConstraints
097                    .getUnitConstraints().getConstraints();
098
099            for (int i = 0; i < _constraintExpressions.size(); i++) {
100                UnitEquation uEq = (UnitEquation) _constraintExpressions.get(i);
101                String commonDesc = uEq.descriptiveForm();
102                System.out.println("_constraint " + commonDesc);
103                _constraintExpression.add(commonDesc);
104            }
105        }
106
107        _unitsTable = new JTable();
108        _unitsTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
109        setScrollableContents(_unitsTable);
110
111        ListSelectionModel rowSM = _unitsTable.getSelectionModel();
112        rowSM.addListSelectionListener(_rowSelectionListener);
113
114        // Create the TableModel and set certain cell editors and renderers
115        _setupTableModel(_constraintExpression);
116        _unitsTable.setTableHeader(null);
117        pack();
118        setVisible(true);
119    }
120
121    // The table model for the table.
122    class UnitsTableModel extends AbstractTableModel {
123        Vector _unitsDataTable;
124
125        public UnitsTableModel(Vector unitsExpression) {
126            _unitsDataTable = new Vector(unitsExpression);
127        }
128
129        @Override
130        public int getRowCount() {
131            return _unitsDataTable.size();
132        }
133
134        @Override
135        public int getColumnCount() {
136            return 1;
137        }
138
139        @Override
140        public String getColumnName(int i) {
141            return "Constraint";
142        }
143
144        @Override
145        public Object getValueAt(int row, int col) {
146            return _unitsDataTable.elementAt(row);
147        }
148
149        public void addNewConstraint() {
150            _unitsDataTable.add("");
151
152            // Now tell the GUI so that it can update itself.
153            fireTableRowsInserted(getRowCount(), getRowCount());
154        }
155
156        @Override
157        public boolean isCellEditable(int arg0, int arg1) {
158            return true;
159        }
160
161        @Override
162        public void setValueAt(Object value, int row, int col) {
163            _unitsDataTable.set(row, value);
164            _enableApplyButton(true);
165            _setDirty(true);
166        }
167
168        @Override
169        public String toString() {
170            StringBuffer retv = new StringBuffer("");
171
172            if (_unitsDataTable.size() > 0) {
173                retv.append((String) _unitsDataTable.elementAt(0));
174
175                for (int i = 1; i < _unitsDataTable.size(); i++) {
176                    retv.append(";" + (String) _unitsDataTable.elementAt(i));
177                }
178            }
179
180            return retv.toString();
181        }
182    }
183
184    /*
185     * (non-Javadoc)
186     *
187     * @see ptolemy.kernel.util.ChangeListener#changeExecuted(ChangeRequest)
188     */
189    @Override
190    public void changeExecuted(ChangeRequest change) {
191        // TODO Auto-generated method stub
192    }
193
194    /*
195     * (non-Javadoc)
196     *
197     * @see ptolemy.kernel.util.ChangeListener#changeFailed(ChangeRequest,
198     *      Exception)
199     */
200    @Override
201    public void changeFailed(ChangeRequest change, Exception exception) {
202        // TODO Auto-generated method stub
203    }
204
205    /** Apply the unit constraints to the model.
206     */
207    protected void _apply() {
208        String expr = _unitsTableModel.toString();
209        String moml = "<property name=\"_unitConstraints\" "
210                + "class = \"ptolemy.data.unit.UnitAttribute\" " + "value = \""
211                + expr + "\"/>";
212
213        MoMLChangeRequest request = new MoMLChangeRequest(this, getTarget(),
214                moml, null);
215        request.setUndoable(true);
216
217        // NOTE: There is no need to listen for completion
218        // or errors in this change request, since, in theory,
219        // it will just work. Will someone report the error
220        // if one occurs? I hope so...
221        getTarget().requestChange(request);
222    }
223
224    /*
225     * (non-Javadoc)
226     *
227     * @see ptolemy.actor.gui.PtolemyDialog#_createExtendedButtons()
228     */
229    @Override
230    protected void _createExtendedButtons(JPanel _buttons) {
231        _commitButton = new JButton("Commit");
232        _buttons.add(_commitButton);
233        _applyButton = new JButton("Apply");
234        _buttons.add(_applyButton);
235        _addButton = new JButton("Add");
236        _buttons.add(_addButton);
237        _removeButton = new JButton("Remove           ");
238        _removeButton.setEnabled(false);
239        _buttons.add(_removeButton);
240    }
241
242    /** Enable or disable the apply button.
243     *  @param enabled True if the apply button should be enabled.
244     */
245    protected void _enableApplyButton(boolean enabled) {
246        _applyButton.setEnabled(enabled);
247    }
248
249    /** Return the help URL.
250     *  @return The help URL
251     */
252    @Override
253    protected URL _getHelpURL() {
254        URL helpURL = getClass().getClassLoader()
255                .getResource("ptolemy/actor/gui/doc/unitConstraintsDialog.htm");
256        return helpURL;
257    }
258
259    /** Process a button press.  Add and Apply buttons are handled
260     *  here.  Other button presses are handled by the superclass.
261     *  @param button The button to process.
262     */
263    @Override
264    protected void _processButtonPress(String button) {
265        if (button.equals("Add")) {
266            _unitsTableModel.addNewConstraint();
267        } else if (button.equals("Apply")) {
268            _apply();
269        } else {
270            super._processButtonPress(button);
271        }
272    }
273
274    private void _setupTableModel(Vector constraintExpressions) {
275        _unitsTableModel = new UnitsTableModel(constraintExpressions);
276        _unitsTable.setModel(_unitsTableModel);
277
278        TableColumn _constraintColumn = _unitsTable.getColumnModel()
279                .getColumn(0);
280        JTextField textField = new JTextField();
281        final DefaultCellEditor constraintEditor = new DefaultCellEditor(
282                textField);
283        constraintEditor.setClickCountToStart(1);
284        _constraintColumn.setCellEditor(constraintEditor);
285
286        //        textField.addFocusListener(new FocusAdapter() {
287        //            public void focusLost(FocusEvent fe) {
288        //                constraintEditor.stopCellEditing();
289        //            }
290        //        });
291        _enableApplyButton(false);
292    }
293
294    ///////////////////////////////////////////////////////////////////
295    ////                         private variables                 ////
296    private JButton _addButton;
297
298    private JButton _applyButton;
299
300    private JButton _commitButton;
301
302    private JButton _removeButton;
303
304    private ListSelectionListener _rowSelectionListener = new ListSelectionListener() {
305        ///////////////////////////////////////////////////////////////////
306        //// inner class ////
307        @Override
308        public void valueChanged(ListSelectionEvent e) {
309            if (e.getValueIsAdjusting()) {
310                return;
311            }
312
313            //Ignore extra messages.
314            ListSelectionModel lsm = (ListSelectionModel) e.getSource();
315
316            if (lsm.isSelectionEmpty()) {
317                _removeButton.setText("Remove");
318                _removeButton.setEnabled(false);
319                // _selectedRow = -1;
320            } else {
321                // _selectedRow = lsm.getMinSelectionIndex();
322                _removeButton.setEnabled(true);
323            }
324        }
325    };
326
327    // private int _selectedRow = -1;
328
329    private JTable _unitsTable;
330
331    private UnitsTableModel _unitsTableModel;
332}