/* * JFLAP - Formal Languages and Automata Package * * * Susan H. Rodger * Computer Science Department * Duke University * August 27, 2009 * Copyright (c) 2002-2009 * All rights reserved. * JFLAP is open source software. Please see the LICENSE for terms. * */ package gui.lsystem; import grammar.Production; import grammar.UnboundGrammar; import grammar.lsystem.*; import gui.HighlightTable; import gui.TableTextSizeSlider; import gui.grammar.GrammarInputPane; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; /** * The LSystemInputPane is a pane used to input and display the * textual representation of an L-system. * * @author Thomas Finley */ public class LSystemInputPane extends JPanel { /** * Instantiates an empty LSystemInputPane. */ public LSystemInputPane() { this(SYSTEM); } /** * Instantiates an LSystemInputPane for a given LSystem. * * @param lsystem * the lsystem to display */ public LSystemInputPane(LSystem lsystem) { super(new BorderLayout()); initializeStructures(lsystem); initializeListener(); initializeView(); } /** * Initializes the data structures and the subviews. * * @param lsystem * the L-system to initialize the views on */ private void initializeStructures(LSystem lsystem) { // Create the axiom text field. axiomField = new JTextField(listAsString(lsystem.getAxiom())); // Create the grammar view that holds replacement productions. Set replacements = lsystem.getSymbolsWithReplacements(); Iterator it = replacements.iterator(); UnboundGrammar g = new UnboundGrammar(); while (it.hasNext()) { String symbol = (String) it.next(); java.util.List[] r = lsystem.getReplacements(symbol); for (int i = 0; i < r.length; i++) { Production p = new Production(symbol, listAsString(r[i])); g.addProduction(p); } } productionInputPane = new GrammarInputPane(g); // Create the parameter table model. parameterModel = new ParameterTableModel(lsystem.getValues()); // We may as well use this as our cached system. cachedSystem = lsystem; } /** * Lays out the subviews in this view. */ private void initializeView() { // Create the view for the axiom text field. JPanel axiomView = new JPanel(new BorderLayout()); axiomView.add(new JLabel("Axiom: "), BorderLayout.WEST); axiomView.add(axiomField, BorderLayout.CENTER); add(axiomView, BorderLayout.NORTH); // Create the view for the grammar pane and the rest. parameterTable = new HighlightTable(parameterModel); parameterTable.add(new TableTextSizeSlider(parameterTable), BorderLayout.SOUTH); JScrollPane scroller = new JScrollPane(parameterTable); Dimension bestSize = new Dimension(400, 200); /* * parameterTable.setPreferredSize(bestSize); * productionInputPane.getTable().setPreferredSize(bestSize); */ productionInputPane.setPreferredSize(bestSize); scroller.setPreferredSize(bestSize); JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, productionInputPane, scroller); add(split, BorderLayout.CENTER); // Finally, show the grid. parameterTable.setShowGrid(true); parameterTable.setGridColor(Color.lightGray); scroller .setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); /* * final JComboBox box = new JComboBox ((String[]) * Renderer.ASSIGN_WORDS.toArray(new String[0])); * box.setLightWeightPopupEnabled(false); * scroller.setCorner(JScrollPane.UPPER_RIGHT_CORNER, box); * box.addItemListener(new ItemListener() { public void * itemStateChanged(ItemEvent e) { if (e.getStateChange() != e.SELECTED) * return; String s = (String) e.getItem(); box.setSelectedIndex(-1); // * No selection! setEditing(s); } }); */ final JPopupMenu menu = new JPopupMenu(); ActionListener listener = new ActionListener() { public void actionPerformed(ActionEvent e) { setEditing(e.getActionCommand()); } }; String[] words = (String[]) Renderer.ASSIGN_WORDS .toArray(new String[0]); for (int i = 0; i < words.length; i++) { menu.add(words[i]).addActionListener(listener); } JPanel c = new JPanel(); c.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent e) { menu.show((Component) e.getSource(), e.getPoint().x, e .getPoint().y); } }); scroller.setCorner(JScrollPane.UPPER_RIGHT_CORNER, c); } /** * Creates the listener to update the edited-ness. */ public void initializeListener() { axiomField.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { fireLSystemInputEvent(); } public void removeUpdate(DocumentEvent e) { fireLSystemInputEvent(); } public void insertUpdate(DocumentEvent e) { fireLSystemInputEvent(); } }); TableModelListener tml = new TableModelListener() { public void tableChanged(TableModelEvent e) { fireLSystemInputEvent(); } }; parameterModel.addTableModelListener(tml); productionInputPane.getTable().getModel().addTableModelListener(tml); } /** * Given a list of objects, this converts it to a space delimited string. * * @param list * the list to convert to a string * @return a string containing the elements of the list */ public static String listAsString(java.util.List list) { Iterator it = list.iterator(); if (!it.hasNext()) return ""; StringBuffer sb = new StringBuffer(); sb.append(it.next()); while (it.hasNext()) { sb.append(' '); sb.append(it.next()); } return sb.toString(); } /** * Returns the L-system this pane displays. * * @return the L-system this pane displays */ public LSystem getLSystem() { // Make sure we're not editing anything. if (productionInputPane.getTable().getCellEditor() != null) productionInputPane.getTable().getCellEditor().stopCellEditing(); if (parameterTable.getCellEditor() != null) parameterTable.getCellEditor().stopCellEditing(); // Do we already have a cached copy? try { if (cachedSystem == null) cachedSystem = new LSystem(axiomField.getText(), productionInputPane.getGrammar(UnboundGrammar.class), parameterModel.getParameters()); } catch (IllegalArgumentException e) { JOptionPane.showMessageDialog(this, e.getMessage(), "L-System Error", JOptionPane.ERROR_MESSAGE); } return cachedSystem; } /** * Adds an L-system input listener. * * @param listener * the listener to start sending change events to */ public void addLSystemInputListener(LSystemInputListener listener) { lSystemInputListeners.add(listener); } /** * Removes an L-system input listener. * * @param listener * the listener to stop sending change events to */ public void removeLSystemInputListener(LSystemInputListener listener) { lSystemInputListeners.remove(listener); } /** * Fires a notification to listeners that the L-system was changed. */ protected void fireLSystemInputEvent() { cachedSystem = null; Iterator it = lSystemInputListeners.iterator(); while (it.hasNext()) ((LSystemInputListener) (it.next())).lSystemChanged(reusedEvent); } /** * This will edit the value for a particular parameter in the parameter * table. If no such value exists yet it shall be created. The value field * in the table shall be edited. * * @param item * the key of the value we want to edit */ private void setEditing(String item) { int i; for (i = 0; i < parameterModel.getRowCount(); i++) if (parameterModel.getValueAt(i, 0).equals(item)) break; if (i == parameterModel.getRowCount()) // We need to create it. parameterModel.setValueAt(item, --i, 0); int column = parameterTable.convertColumnIndexToView(1); parameterTable.editCellAt(i, column); parameterTable.requestFocus(); } /** An empty L-system. */ private static final LSystem SYSTEM = new LSystem(); /** The axiom text field. */ private JTextField axiomField; /** The production view. */ private GrammarInputPane productionInputPane; /** The parameter table model. */ private ParameterTableModel parameterModel; /** The parameter table view. */ private HighlightTable parameterTable; /** The set of input listeners. */ private Set lSystemInputListeners = new HashSet(); /** The event reused in firing off the notifications. */ private LSystemInputEvent reusedEvent = new LSystemInputEvent(this); /** The cached L-system. Firing an L-S input event invalidates this. */ private LSystem cachedSystem = null; }