/* @Copyright (c) 2007-2014 The Regents of the University of California. All rights reserved. Permission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. PT_COPYRIGHT_VERSION_2 COPYRIGHTENDKEY */ package ptolemy.vergil.gt; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.net.URLDecoder; import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.Vector; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.ComboBoxEditor; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import ptolemy.actor.gt.GTEntity; import ptolemy.actor.gt.GTIngredient; import ptolemy.actor.gt.GTIngredientElement; import ptolemy.actor.gt.GTIngredientList; import ptolemy.actor.gt.GTIngredientsAttribute; import ptolemy.actor.gt.GTTools; import ptolemy.actor.gt.MalformedStringException; import ptolemy.actor.gt.ValidationException; import ptolemy.actor.gt.ingredients.criteria.BooleanCriterionElement; import ptolemy.actor.gt.ingredients.criteria.ChoiceCriterionElement; import ptolemy.actor.gt.ingredients.criteria.Criterion; import ptolemy.actor.gt.ingredients.criteria.StringCriterionElement; import ptolemy.actor.gt.ingredients.operations.BooleanOperationElement; import ptolemy.actor.gt.ingredients.operations.Operation; import ptolemy.actor.gt.ingredients.operations.StringOperationElement; import ptolemy.actor.gui.Configuration; import ptolemy.actor.gui.DialogTableau; import ptolemy.actor.gui.EditorFactory; import ptolemy.actor.gui.Effigy; import ptolemy.actor.gui.HTMLViewer; import ptolemy.actor.gui.PtolemyDialog; import ptolemy.actor.gui.TableauFrame; import ptolemy.kernel.util.Attribute; import ptolemy.kernel.util.IllegalActionException; import ptolemy.kernel.util.InternalErrorException; import ptolemy.kernel.util.KernelRuntimeException; import ptolemy.kernel.util.NameDuplicationException; import ptolemy.kernel.util.NamedObj; import ptolemy.kernel.util.StringAttribute; import ptolemy.moml.MoMLChangeRequest; import ptolemy.util.StringUtilities; import ptolemy.vergil.toolbox.VisibleParameterEditorFactory; ////////////////////////////////////////////////////////////////////////// //// GTIngredientsEditor /** @author Thomas Huining Feng @version $Id: GTIngredientsEditor.java 70402 2014-10-23 00:52:20Z cxh $ @since Ptolemy II 6.1 @Pt.ProposedRating Red (tfeng) @Pt.AcceptedRating Red (tfeng) */ @SuppressWarnings("serial") public class GTIngredientsEditor extends PtolemyDialog { public GTIngredientsEditor(DialogTableau tableau, Frame owner, NamedObj target, Configuration configuration) { super("", tableau, owner, null, configuration); _owner = owner; _target = target; Attribute attribute = null; if (GTTools.isInPattern(target)) { if (target instanceof GTEntity) { attribute = target.getAttribute("criteria"); } else { try { target.workspace().getReadAccess(); attribute = target.attributeList( GTIngredientsAttribute.class).get(0); } finally { target.workspace().doneReading(); } } _ingredientClasses = _criterionClasses; tableau.setTitle("Criteria editor for " + target.getName()); } else if (GTTools.isInReplacement(target)) { if (target instanceof GTEntity) { attribute = target.getAttribute("operations"); } else { try { target.workspace().getReadAccess(); attribute = target.attributeList( GTIngredientsAttribute.class).get(0); } finally { target.workspace().doneReading(); } } _ingredientClasses = _operationClasses; tableau.setTitle("Operations editor for " + target.getName()); } _attribute = (GTIngredientsAttribute) attribute; _temporaryIngredientList = new GTIngredientList(_attribute); _createComponents(); } @Override public void actionPerformed(ActionEvent e) { String command = e.getActionCommand(); if ("add".equals(command)) { addNewRow(); } else if ("remove".equals(command)) { removeSelectedRows(); } else if ("commit".equals(command)) { commit(); } else if ("apply".equals(command)) { apply(); } else if ("cancel".equals(command)) { cancel(); } } public void addNewRow() { try { GTIngredient ingredient = null; for (Class theClass : _ingredientClasses) { ingredient = _createTemporaryIngredient(theClass); if (ingredient.isApplicable(_target)) { break; } } if (ingredient == null) { return; } Row row = new Row(ingredient); int rowCount = _tableModel.getRowCount(); _tableModel.addRow(new Object[] { rowCount + 1, row, row }); if (rowCount == 0) { _table.getSelectionModel().addSelectionInterval(0, 0); } } catch (Exception e) { throw new KernelRuntimeException(e, "Unable to create a new " + "criterion or operation instance."); } } public boolean apply() { GTIngredientList ingredientList = new GTIngredientList(_attribute); Vector dataVector = _tableModel.getDataVector(); for (Object rowData : dataVector) { Vector rowVector = (Vector) rowData; Row row = (Row) rowVector.get(1); GTIngredient incredient = _createIngredientFromRow(row); ingredientList.add(incredient); } try { ingredientList.validate(); } catch (ValidationException e) { String message = e.getMessage() + "\nPress Edit to return to modify the criterion or " + "operation, or press Revert to revert to its previous " + "value."; String[] options = new String[] { "Edit", "Revert" }; int selected = JOptionPane.showOptionDialog(null, message, "Validation Error", JOptionPane.OK_CANCEL_OPTION, JOptionPane.ERROR_MESSAGE, null, options, options[1]); if (selected == 1) { resetTable(_initialIngredientList); } return false; } String moml = ""; MoMLChangeRequest request = new MoMLChangeRequest(this, _target, moml, null); request.setUndoable(true); _attribute.requestChange(request); return true; } public void cancel() { setVisible(false); } public void centerOnScreen() { Toolkit tk = Toolkit.getDefaultToolkit(); setLocation((tk.getScreenSize().width - getSize().width) / 2, (tk.getScreenSize().height - getSize().height) / 2); } public void commit() { if (apply()) { setVisible(false); } } @Override public Dimension getPreferredSize() { if (isPreferredSizeSet()) { return super.getPreferredSize(); } else { return _PREFERRED_SIZE; } } public void removeSelectedRows() { _editor.stopCellEditing(); int[] rows = _table.getSelectedRows(); int size = _tableModel.getRowCount(); for (int i = 0, deleted = 0; i < size; i++) { if (deleted < rows.length && i == rows[deleted]) { _tableModel.removeRow(i - deleted); deleted++; } else { _tableModel.setValueAt(i - deleted + 1, i - deleted, 0); } } } public void resetTable(GTIngredientList ingredientList) { int[] selectedRows = _table.getSelectedRows(); _editor.stopCellEditing(); while (_tableModel.getRowCount() > 0) { _tableModel.removeRow(0); } int i = 0; for (GTIngredient ingredient : ingredientList) { Row row = new Row(ingredient); _tableModel.addRow(new Object[] { i++ + 1, row, row }); } if (selectedRows.length == 0) { if (i > 0) { _table.getSelectionModel().addSelectionInterval(0, 0); } } else { for (i = 0; i < selectedRows.length; i++) { _table.getSelectionModel().addSelectionInterval( selectedRows[i], selectedRows[i]); } } } @SuppressWarnings("unchecked") public static List> searchIngredientClasses( String[] packages, ClassLoader loader) { List> ingredientClasses = new LinkedList>(); for (String pkg : packages) { try { Enumeration urls = loader.getResources(pkg.replace('.', '/')); while (urls.hasMoreElements()) { URL url = urls.nextElement(); File directory = new File(URLDecoder.decode(url.getPath(), "UTF-8")); File[] files = directory.listFiles(); for (File file : files) { if (!file.exists() || !file.isFile()) { continue; } String filePath = file.getName(); if (!filePath.endsWith(".class")) { continue; } String className = filePath.substring(0, filePath.length() - 6); className = className.replace('$', '.'); String fullClassName = pkg + "." + className; try { Class cls = loader.loadClass(fullClassName); if (!Modifier.isAbstract(cls.getModifiers()) && GTIngredient.class.isAssignableFrom(cls)) { ingredientClasses .add((Class) cls); } } catch (ClassNotFoundException e) { } catch (NoClassDefFoundError e) { } } } } catch (IOException e) { } } return ingredientClasses; } @Override public void setVisible(boolean visible) { if (visible && _attribute != null) { try { _initialIngredientList = _attribute.getIngredientList(); resetTable(_initialIngredientList); } catch (MalformedStringException e) { throw new KernelRuntimeException(e, "Attribute \"" + _attribute.getName() + "\" of " + "entity " + _target.getName() + " is malformed."); } } super.setVisible(visible); } public static final String REGULAR_EXPRESSION_HELP_FILE = "ptolemy/configs/doc/basicHelp.htm"; /** * @author tfeng * * @see VisibleParameterEditorFactory */ public static class Factory extends EditorFactory { public Factory(NamedObj container, String name) throws IllegalActionException, NameDuplicationException { super(container, name); attributeName = new StringAttribute(this, "attributeName"); } @Override public void createEditor(NamedObj object, Frame parent) { Configuration configuration = ((TableauFrame) parent) .getConfiguration(); Effigy effigy = ((TableauFrame) parent).getEffigy(); // The dialog now only works with TransitionMatcher, which is not an // Entity. /*DialogTableau dialogTableau = DialogTableau.createDialog(parent, configuration, effigy, GTIngredientsEditor.class, (Entity) object); if (dialogTableau != null) { dialogTableau.show(); }*/ DialogTableau tableau; try { tableau = new DialogTableau(effigy, effigy.uniqueName("dialog")); tableau.setFrame(new GTIngredientsEditor(tableau, parent, object, configuration)); tableau.show(); } catch (Throwable throwable) { throw new InternalErrorException(null, throwable, "Unable to create " + "ingredient editor for " + object.getName()); } } public StringAttribute attributeName; } protected void _createComponents() { // Clear all the buttons and panels created by superclasses. getContentPane().removeAll(); _tableModel = new DefaultTableModel(new Object[] { "", "Class", "Elements" }, 0) { @Override public boolean isCellEditable(int row, int column) { if (column == 0) { return false; } else { return super.isCellEditable(row, column); } } }; _table = new JTable(_tableModel); _table.setRowHeight(_ROW_HEIGHT); _table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); _table.setSelectionBackground(_SELECTED_COLOR); _table.setSelectionForeground(Color.BLACK); _table.addKeyListener(new KeyListener() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { commit(); } else if (e.getKeyCode() == KeyEvent.VK_ESCAPE) { cancel(); } } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { } }); _table.setEnabled(_attribute != null); JTableHeader header = _table.getTableHeader(); header.setFont(new Font("Dialog", Font.BOLD, 11)); header.setForeground(Color.BLUE); header.setReorderingAllowed(false); DefaultTableCellRenderer renderer = (DefaultTableCellRenderer) header .getDefaultRenderer(); renderer.setHorizontalAlignment(SwingConstants.CENTER); renderer.setPreferredSize(new Dimension(0, 22)); _editor = new IngredientContentEditor(); TableColumnModel model = _table.getColumnModel(); model.getColumn(1).setCellEditor(_editor); model.getColumn(1).setCellRenderer(_editor); model.getColumn(2).setCellEditor(_editor); model.getColumn(2).setCellRenderer(_editor); JScrollPane scrollPane = new JScrollPane(_table); getContentPane().add(scrollPane, BorderLayout.CENTER); JPanel bottomPanel = new JPanel(new BorderLayout()); GridLayout gridLayout = new GridLayout(); gridLayout.setHgap(5); JPanel helpPanel = new JPanel(gridLayout); helpPanel.setBorder(BorderFactory.createEmptyBorder(3, 5, 0, 5)); helpPanel.setPreferredSize(new Dimension(0, 25)); TableauFrame owner = _owner instanceof TableauFrame ? (TableauFrame) _owner : null; helpPanel.add(new HelpLabel("Normal text only", _NON_REGULAR_EXPRESSION_BACKGROUND)); try { helpPanel.add(new HelpLabel("Regular expression", _REGULAR_EXPRESSION_BACKGROUND, new URL( _REGULAR_EXPRESSION_HELP_FILE), owner)); } catch (MalformedURLException e1) { helpPanel.add(new HelpLabel("Regular expression", _REGULAR_EXPRESSION_BACKGROUND)); } helpPanel.add(new HelpLabel("Evaluated expression", _PTOLEMY_EXPRESSION_BACKGROUND, _PTOLEMY_EXPRESSION_HELP_FILE, owner)); helpPanel.add(new HelpLabel("Do not match", _DISABLED_BACKGROUND)); bottomPanel.add(helpPanel, BorderLayout.NORTH); JPanel buttonsPanel = new JPanel(); JButton addButton = new JButton("Add"); addButton.setActionCommand("add"); addButton.addActionListener(this); addButton.setEnabled(_attribute != null); buttonsPanel.add(addButton); JButton removeButton = new JButton("Remove"); removeButton.setActionCommand("remove"); removeButton.addActionListener(this); removeButton.setEnabled(_attribute != null); buttonsPanel.add(removeButton); JButton commitButton = new JButton("Commit"); commitButton.setActionCommand("commit"); commitButton.addActionListener(this); commitButton.setEnabled(_attribute != null); buttonsPanel.add(commitButton); getRootPane().setDefaultButton(commitButton); JButton applyButton = new JButton("Apply"); applyButton.setActionCommand("apply"); applyButton.addActionListener(this); applyButton.setEnabled(_attribute != null); buttonsPanel.add(applyButton); JButton cancelButton = new JButton("Cancel"); cancelButton.setActionCommand("cancel"); cancelButton.addActionListener(this); buttonsPanel.add(cancelButton); bottomPanel.add(buttonsPanel, BorderLayout.SOUTH); getContentPane().add(bottomPanel, BorderLayout.SOUTH); TableColumn column0 = model.getColumn(0); column0.setMinWidth(10); column0.setPreferredWidth(15); column0.setMaxWidth(30); DefaultTableCellRenderer indexRenderer = new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { return super.getTableCellRendererComponent(table, value, isSelected, false, row, column); } }; indexRenderer.setHorizontalAlignment(SwingConstants.CENTER); column0.setCellRenderer(indexRenderer); model.getColumn(1).setPreferredWidth(150); model.getColumn(2).setPreferredWidth(650); setDefaultCloseOperation(DISPOSE_ON_CLOSE); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { cancel(); } }); setPreferredSize(_PREFERRED_SIZE); } @Override protected void _createExtendedButtons(JPanel _buttons) { } @SuppressWarnings("unchecked") protected GTIngredient _createIngredientFromRow(Row row) { JComboBox classSelector = row.getClassSelector(); ComboElement element = (ComboElement) classSelector.getSelectedItem(); Class ingredientClass = (Class) element .getIngredientClass(); GTIngredient ingredient; try { ingredient = _createTemporaryIngredient(ingredientClass); } catch (Exception e) { throw new KernelRuntimeException(e, "Unable to create criterion or " + "operation from class \"" + ingredientClass.getName() + "\"."); } JCheckBox[] checkBoxes = row.getCheckBoxs(); JComponent[] components = row.getEditingComponents(); for (int i = 0; i < checkBoxes.length; i++) { if (checkBoxes[i] != null) { ingredient.setEnabled(i, Boolean.valueOf(checkBoxes[i].isSelected())); } JComponent editor = components[i]; if (editor instanceof JTextField) { ingredient.setValue(i, ((JTextField) editor).getText()); } else if (editor instanceof JComboBox) { ingredient.setValue(i, ((JComboBox) editor).getSelectedItem() .toString()); } else if (editor instanceof JCheckBox) { ingredient.setValue(i, Boolean.valueOf(((JCheckBox) editor).isSelected())); } } return ingredient; } @Override protected URL _getHelpURL() { URL helpURL = getClass().getClassLoader().getResource( REGULAR_EXPRESSION_HELP_FILE); return helpURL; } private GTIngredient _createTemporaryIngredient( Class ingredientClass) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { Constructor constructor = ingredientClass .getConstructor(GTIngredientList.class); return constructor .newInstance(new Object[] { _temporaryIngredientList }); } private static final Color _DISABLED_BACKGROUND = new Color(220, 220, 220); private static final Border _EMPTY_BORDER = BorderFactory .createEmptyBorder(); private static final Color _NON_REGULAR_EXPRESSION_BACKGROUND = new Color( 230, 230, 255); private static final Dimension _PREFERRED_SIZE = new Dimension(800, 500); private static final Color _PTOLEMY_EXPRESSION_BACKGROUND = new Color(255, 200, 200); private static final String _PTOLEMY_EXPRESSION_HELP_FILE = "doc/expressions.htm"; private static final Color _REGULAR_EXPRESSION_BACKGROUND = new Color(200, 255, 255); private static final String _REGULAR_EXPRESSION_HELP_FILE = "http://download.oracle.com/javase/tutorial/essential/regex/"; private static final int _ROW_HEIGHT = 45; private static final Color _SELECTED_COLOR = new Color(230, 230, 255); private static final Border _TEXT_FIELD_BORDER = new JTextField() .getBorder(); private static final Color _UNSELECTED_COLOR = Color.WHITE; private GTIngredientsAttribute _attribute; private static List> _criterionClasses; private IngredientContentEditor _editor; private List> _ingredientClasses; private GTIngredientList _initialIngredientList; private static List> _operationClasses; private Frame _owner; private JTable _table; private DefaultTableModel _tableModel; private NamedObj _target; private GTIngredientList _temporaryIngredientList; private static class ColorizedComboBox extends JComboBox { public Color getCustomBackground() { return _background; } @Override public void setBackground(Color color) { super.setBackground(color); ComboBoxEditor editor = getEditor(); if (editor != null) { editor.getEditorComponent().setBackground(color); } } @Override public void setEditable(boolean editable) { ((JTextField) _editor.getEditorComponent()).setEditable(editable); } ColorizedComboBox(Color background) { super.setEditable(true); _background = background; setBorder(_EMPTY_BORDER); setEditor(_editor); } private Color _background; private Editor _editor = new Editor(); private class Editor extends MouseAdapter implements ActionListener, ComboBoxEditor, FocusListener { @Override public void actionPerformed(ActionEvent e) { if (_textField.isEditable()) { setSelectedItem(_textField.getText()); } setPopupVisible(!isPopupVisible()); } @Override public void addActionListener(ActionListener l) { } @Override public void focusGained(FocusEvent e) { if (_textField.isEditable()) { _textField.getCaret().setVisible(true); if (_textField.isEnabled()) { setPopupVisible(true); } } } @Override public void focusLost(FocusEvent e) { hidePopup(); if (_textField.isEditable()) { setSelectedItem(_textField.getText()); _textField.getCaret().setVisible(false); } } @Override public Component getEditorComponent() { return _textField; } @Override public Object getItem() { return _textField.isEditable() ? _textField.getText() : _value; } @Override public void mousePressed(MouseEvent e) { if (_textField.hasFocus() && _textField.isEnabled()) { setPopupVisible(!isPopupVisible()); } } @Override public void removeActionListener(ActionListener l) { } @Override public void selectAll() { _textField.selectAll(); } @Override public void setItem(Object value) { _value = value; if (value == null) { _textField.setText(""); } else { _textField.setText(value.toString()); } } Editor() { _textField.setEditable(false); _textField.setOpaque(true); _textField.addMouseListener(this); _textField.addFocusListener(this); _textField.addActionListener(this); } private JTextField _textField = new JTextField(); private Object _value; } } private static class ColorizedTextField extends JTextField { public Color getCustomBackground() { return _background; } ColorizedTextField(Color background) { _background = background; } private Color _background; } private static class ComboElement { public ComboElement(GTIngredient ingredient) { _ingredientClass = ingredient.getClass(); _ingredient = ingredient; } public GTIngredient getIngredient() { return _ingredient; } public Class getIngredientClass() { return _ingredientClass; } @Override public String toString() { return _ingredientClass.getSimpleName(); } private GTIngredient _ingredient; private Class _ingredientClass; } private static class HelpLabel extends JLabel implements MouseListener { @Override public void mouseClicked(MouseEvent event) { if (_help != null) { String host = _help.getHost(); if (host.length() > 0) { // The help file is located on another server. String message = "The help file is located on server " + host + ". Do you want to open it? (A network " + "connection is required.)"; int selected = JOptionPane.showConfirmDialog(null, message, "Validation Error", JOptionPane.YES_NO_OPTION, JOptionPane.ERROR_MESSAGE, null); if (selected == 1) { return; } } try { Configuration configuration = _owner.getConfiguration(); configuration .openModel(null, _help, _help.toExternalForm()); } catch (Exception e1) { HTMLViewer viewer = new HTMLViewer(); try { viewer.setPage(_help); viewer.pack(); viewer.show(); } catch (IOException e2) { throw new KernelRuntimeException("Cannot open help " + "file."); } } } } @Override public void mouseEntered(MouseEvent e) { Color color = new Color(Math.min( (int) (_background.getRed() * 1.1), 255), Math.min( (int) (_background.getGreen() * 1.1), 255), Math.min( (int) (_background.getBlue() * 1.1), 255)); setBackground(color); } @Override public void mouseExited(MouseEvent e) { setBackground(_background); } @Override public void mousePressed(MouseEvent e) { } @Override public void mouseReleased(MouseEvent e) { } HelpLabel(String label, Color background) { this(label, background, (URL) null, null); } HelpLabel(String label, Color background, String helpFile, TableauFrame owner) { this(label, background, HelpLabel.class.getClassLoader() .getResource(helpFile), owner); } HelpLabel(String label, Color background, URL help, TableauFrame owner) { super(label, SwingConstants.CENTER); setBackground(background); setBorder(_TEXT_FIELD_BORDER); setOpaque(true); _background = background; _help = help; if (_help != null) { setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); addMouseListener(this); } _owner = owner; } private Color _background; private URL _help; private TableauFrame _owner; } private static class IngredientContentEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer { @Override public Object getCellEditorValue() { return _currentRow; } @Override public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { _currentRow = (Row) value; _currentRow.setSelected(isSelected, false); return column == 1 ? _currentRow.getLeftPanel() : _currentRow .getRightPanel(); } @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Row currentRow = (Row) value; currentRow.setSelected(isSelected, true); return column == 1 ? currentRow.getLeftPanel() : currentRow .getRightPanel(); } private Row _currentRow; } private class Row implements ItemListener { public Row(GTIngredient ingredient) { _rightPanel.setBorder(_EMPTY_BORDER); Class ingredientClass = ingredient.getClass(); _classSelector.addItemListener(this); _classSelector.setEditable(false); for (Class listedIngerdient : _ingredientClasses) { if (listedIngerdient == null && ingredientClass == null || listedIngerdient != null && listedIngerdient.equals(ingredientClass)) { ComboElement element = new ComboElement(ingredient); _classSelector.addItem(element); _classSelector.setSelectedItem(element); } else { try { GTIngredient newIngredient = _createTemporaryIngredient(listedIngerdient); if (newIngredient.isApplicable(_target)) { ComboElement element = new ComboElement( newIngredient); _classSelector.addItem(element); } } catch (Exception e) { throw new KernelRuntimeException(e, "Unable to create criterion or operation from " + "class \"" + listedIngerdient.getName() + "\"."); } } } JLabel classLabel; if (ingredient instanceof Criterion) { classLabel = new JLabel("Criterion Class"); } else if (ingredient instanceof Operation) { classLabel = new JLabel("Operation Class"); } else { classLabel = new JLabel(); } classLabel.setHorizontalAlignment(SwingConstants.CENTER); classLabel.setPreferredSize(new Dimension(0, 18)); classLabel.setVerticalAlignment(SwingConstants.TOP); _leftPanel.add(classLabel, BorderLayout.NORTH); _leftPanel.add(_classSelector, BorderLayout.CENTER); _leftPanel.setBorder(new EmptyBorder(2, 5, 4, 5)); } public JCheckBox[] getCheckBoxs() { return _checkBoxes; } public JComboBox getClassSelector() { return _classSelector; } public JComponent[] getEditingComponents() { return _components; } public JPanel getLeftPanel() { return _leftPanel; } public JPanel getRightPanel() { return _rightPanel; } @Override public void itemStateChanged(ItemEvent e) { _initRightPanel(); if (e.getStateChange() == ItemEvent.SELECTED) { DefaultTableModel tableModel = (DefaultTableModel) _table .getModel(); for (int i = 0; i < tableModel.getRowCount(); i++) { if (tableModel.getValueAt(i, 1) == this) { tableModel.fireTableRowsUpdated(i, i); break; } } } } public void setSelected(boolean selected, boolean renderOnly) { Color color = selected ? _SELECTED_COLOR : _UNSELECTED_COLOR; _leftPanel.setBackground(color); _rightPanel.setBackground(color); _classSelector.setBackground(color); if (renderOnly) { for (Component component : _components) { if (component instanceof JComboBox) { component = ((JComboBox) component).getEditor() .getEditorComponent(); } if (component instanceof JTextField) { ((JTextField) component).getCaret().setVisible(false); } } } for (int i = 0; i < _checkBoxes.length; i++) { JComponent component = _components[i]; if (_checkBoxes[i] == null || _checkBoxes[i].isSelected()) { if (selected) { if (component instanceof ColorizedTextField) { ColorizedTextField textField = (ColorizedTextField) component; textField.setBackground(textField .getCustomBackground()); } else if (component instanceof ColorizedComboBox) { ColorizedComboBox comboBox = (ColorizedComboBox) component; comboBox.setBackground(comboBox .getCustomBackground()); } else { component.setBackground(_SELECTED_COLOR); } } else { component.setBackground(_UNSELECTED_COLOR); } } else { component.setBackground(_DISABLED_BACKGROUND); } } } protected int _getColumnWidth(JComponent component) { if (component instanceof JTextField || component instanceof JComboBox) { return 80; } else if (component instanceof JCheckBox) { return 40; } else { return 80; } } protected JComponent _getComponent(GTIngredientElement element) { JComponent component = null; if (element instanceof BooleanCriterionElement || element instanceof BooleanOperationElement) { JCheckBox checkBox = new JCheckBox(); checkBox.setHorizontalAlignment(SwingConstants.CENTER); component = checkBox; } else if (element instanceof StringCriterionElement) { StringCriterionElement stringElement = (StringCriterionElement) element; boolean acceptRE = stringElement.acceptRegularExpression(); boolean acceptExp = stringElement.acceptPtolemyExpression(); Color background; if (acceptRE) { background = _REGULAR_EXPRESSION_BACKGROUND; } else if (acceptExp) { background = _PTOLEMY_EXPRESSION_BACKGROUND; } else { background = _NON_REGULAR_EXPRESSION_BACKGROUND; } if (element instanceof ChoiceCriterionElement) { ChoiceCriterionElement choiceElement = (ChoiceCriterionElement) element; ColorizedComboBox comboBox = new ColorizedComboBox( background); comboBox.setEditable(choiceElement.isEditable()); for (Object choice : choiceElement.getChoices()) { comboBox.addItem(choice); } component = comboBox; } else { component = new ColorizedTextField(background); } } else if (element instanceof StringOperationElement) { StringOperationElement stringElement = (StringOperationElement) element; boolean acceptExp = stringElement.acceptPtolemyExpression(); Color background; if (acceptExp) { background = _PTOLEMY_EXPRESSION_BACKGROUND; } else { background = _NON_REGULAR_EXPRESSION_BACKGROUND; } component = new ColorizedTextField(background); } return component; } protected void _initRightPanel() { _rightPanel.removeAll(); ComboElement selectedElement = (ComboElement) _classSelector .getSelectedItem(); GTIngredient ingredient = selectedElement.getIngredient(); GTIngredientElement[] elements = ingredient.getElements(); _components = new JComponent[elements.length]; _checkBoxes = new JCheckBox[elements.length]; GridBagConstraints c = new GridBagConstraints(); for (int i = 0; i < elements.length; i++) { GTIngredientElement element = elements[i]; JPanel panel = new JPanel(new BorderLayout()); panel.setBorder(new EmptyBorder(0, 3, 2, 3)); panel.setOpaque(false); String columnName = element.getName(); JPanel captionPanel = new JPanel(new FlowLayout( FlowLayout.CENTER, 0, 0)); captionPanel.setOpaque(false); captionPanel.setPreferredSize(new Dimension(0, 18)); JCheckBox checkBox = null; boolean enabled; if (element.canDisable()) { checkBox = new JCheckBox(columnName); checkBox.setOpaque(false); checkBox.setBorder(_EMPTY_BORDER); checkBox.setHorizontalAlignment(SwingConstants.CENTER); checkBox.setVerticalAlignment(SwingConstants.TOP); checkBox.addActionListener(new CheckBoxActionListener(i)); captionPanel.add(checkBox); enabled = ingredient.isEnabled(i); checkBox.setSelected(enabled); } else { JLabel label = new JLabel(columnName); captionPanel.add(label); enabled = true; } panel.add(captionPanel, BorderLayout.NORTH); JComponent component = _getComponent(element); component.setPreferredSize(new Dimension(0, 20)); _setComponentValue(element, component, ingredient.getValue(i)); panel.add(component, BorderLayout.CENTER); c.fill = GridBagConstraints.HORIZONTAL; c.weightx = _getColumnWidth(component); c.gridx = i + 1; c.gridy = 0; _rightPanel.add(panel, c); _checkBoxes[i] = checkBox; _components[i] = component; _setEnablement(component, enabled); } } protected void _setComponentValue(GTIngredientElement element, JComponent component, Object value) { if (element instanceof BooleanCriterionElement || element instanceof BooleanOperationElement) { ((JCheckBox) component).setSelected(((Boolean) value) .booleanValue()); } else if (element instanceof StringCriterionElement) { if (element instanceof ChoiceCriterionElement) { ((JComboBox) component).setSelectedItem(value.toString()); } else { ((JTextField) component).setText(value.toString()); } } else if (element instanceof StringOperationElement) { ((JTextField) component).setText(value.toString()); } } private void _setEnablement(JComponent component, boolean enabled) { component.setEnabled(enabled); if (enabled) { if (component instanceof ColorizedTextField) { ColorizedTextField textField = (ColorizedTextField) component; textField.setBackground(textField.getCustomBackground()); } else if (component instanceof ColorizedComboBox) { ColorizedComboBox comboBox = (ColorizedComboBox) component; comboBox.setBackground(comboBox.getCustomBackground()); } else { component.setBackground(_SELECTED_COLOR); } } else { component.setBackground(_DISABLED_BACKGROUND); } } private JCheckBox[] _checkBoxes; private JComboBox _classSelector = new ColorizedComboBox( _NON_REGULAR_EXPRESSION_BACKGROUND); private JComponent[] _components; private JPanel _leftPanel = new JPanel(new BorderLayout()); private JPanel _rightPanel = new JPanel(new GridBagLayout()); private class CheckBoxActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { boolean selected = ((JCheckBox) e.getSource()).isSelected(); _setEnablement(_components[_index], selected); } CheckBoxActionListener(int index) { _index = index; } private int _index; } } static { _criterionClasses = searchIngredientClasses( new String[] { "ptolemy.actor.gt.ingredients.criteria" }, ClassLoader.getSystemClassLoader()); _operationClasses = searchIngredientClasses( new String[] { "ptolemy.actor.gt.ingredients.operations" }, ClassLoader.getSystemClassLoader()); } }