/** *######################################################################### * * A component of the Gatherer application, part of the Greenstone digital * library suite from the New Zealand Digital Library Project at the * University of Waikato, New Zealand. * *

* * Author: John Thompson, Greenstone Digital Library, University of Waikato * *

* * Copyright (C) 1999 New Zealand Digital Library Project * *

* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * *

* * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * *

* * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *######################################################################## */ /* GPL_HEADER */ package org.greenstone.gatherer.cdm; /************************************************************************************** * Title: Gatherer * Description: The Gatherer: a tool for gathering and enriching a digital collection. * Company: The University of Waikato * Written: /05/02 * Revised: 04/10/02 - Commented **************************************************************************************/ import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.DefaultComboBoxModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JToggleButton; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.greenstone.gatherer.Gatherer; import org.greenstone.gatherer.cdm.Classifier; import org.greenstone.gatherer.cdm.ClassifierManager; import org.greenstone.gatherer.cdm.CollectionDesignManager; import org.greenstone.gatherer.cdm.CommandTokenizer; import org.greenstone.gatherer.cdm.DynamicListModel; import org.greenstone.gatherer.cdm.Format; import org.greenstone.gatherer.msm.ElementWrapper; import org.greenstone.gatherer.util.Utility; /** This class maintains a list of format statements, and allows the addition and removal of these statements. * @author John Thompson, Greenstone Digital Library, University of Waikato * @version 2.3 */ public class FormatManager extends DynamicListModel { /** The main manager so we can get to ClassifierManager which is needed to turn position reference such as "CL1" into the appropriate Classifier. */ private CollectionDesignManager manager = null; /** The controls used to edit the format commands. */ private Control controls = null; /** A reference to ourselves so inner classes can get at the model. */ private DynamicListModel model = null; /** A reference to the Gatherer. */ private Gatherer gatherer = null; /** We may have somehow recieved a format command which references a classifier that hasn't been parsed yet, so this variable holds a list of failed commands which are retried after the loading is complete. */ private Vector unresolved_commands = null; /** Constructor. * @param gatherer A reference to the Gatherer. * @param manager A reference to the CollectionDesignManager that created this manager. */ public FormatManager(Gatherer gatherer, CollectionDesignManager manager) { super(); this.gatherer = gatherer; this.manager = manager; this.model = this; this.unresolved_commands = new Vector(); } /** Method to add a new format to this manager. * @param format The Format to add. */ public void addFormat(Format format) { if(formatExists(format) == null) { addElement(format); gatherer.c_man.configurationChanged(); } } /** Method which determines if a certain format exists, in which case it must be removed before a new format of the same component is added. For general formatting statements this compares types, for 'custom' ones it compares list and part. * @param format The Format whose uniqueness we want to check. * @return The Format that matches the one given, or null if no such format exists. */ public Format formatExists(Format format) { for(int i = 0; i < size(); i++) { Format current = (Format) get(i); if(format.getPosition().equals(current.getPosition())) { return current; } } return null; } /** Gets the format indicated by the index. * @param index The location of the desired format, as an int. */ public Format getFormat(int index) { return (Format)get(index); } /** Method to retrieve this managers controls. * @return The Control for this collection. */ public Control getControls() { if(controls == null) { controls = new Control(); } return controls; } /** Method to invalidate controls when some significant change has occured within the collection. */ public void invalidateControls() { if(controls != null) { controls.destroy(); } controls = null; } /** This method attempts to parse a format command from the given string. If a format is parsed, it is immediately added to this managers list of format commands. * @param command The String we are trying to parse a command from. * @param finished A boolean which is true if we are calling this after the the input has been completely parsed (i.e all legal Classifiers are know to exist), or false otherwise. * @return A boolean which is true if we managed to parse a command, false otherwise. * @see org.greenstone.gatherer.cdm.Classifier * @see org.greenstone.gatherer.cdm.CommandTokenizer * @see org.greenstone.gatherer.cdm.Format */ public boolean parse(String command, boolean finished) { String temp = command.toLowerCase(); if(temp.startsWith("format")) { if(finished) { CommandTokenizer ct = new CommandTokenizer(command); ct.nextToken(); // Throw away 'format' String position = ct.nextToken(); String value = ct.nextToken(); // String speech marks. if(value.startsWith("\"") && value.endsWith("\"")) { if(value.equals("\"\"")) { value = ""; } else { value = value.substring(1, value.length() - 1); } } // Ensure we parsed a good command. if(position != null && value != null) { // The trickiest bit of parsing format commands is figuring out how much of the position is feature, and how much part. Since the parts are far less likely to change or be customized in any way, we'll try to match them first (except "" of course). String feature_name = null; String part = null; // If this works, then we're all finished. Yay. for(int i = 1; i < Format.DEFAULT_PARTS.length; i++) { if(position.endsWith(Format.DEFAULT_PARTS[i])) { part = Format.DEFAULT_PARTS[i]; feature_name = position.substring(0, position.length() - part.length()); } } // Otherwise we can attempt to find the default features, but we have less chance of success. if(feature_name == null || part == null) { for(int i = 1; i < Format.DEFAULT_FEATURES.length; i++) { if(position.startsWith(Format.DEFAULT_FEATURES[i])) { feature_name = Format.DEFAULT_FEATURES[i]; if(position.length() > feature_name.length()) { part = position.substring(feature_name.length()); } else { part = ""; } } } } // Otherwise we can assume we are dealing with a classifier and split the position using... // position ::= // classifier_position ::= [0-9]$ // part ::= ^![0-9] // But I don't like my chances of this working if someone does a scary like CL4Part8B. I just have // to hope no-one uses numbers, and no-one expects CustomFeatureCustomPart to parse properly. if(feature_name == null || part == null) { part = ""; boolean found = false; int index = position.length() - 1; while(index >= 0 && !found) { if(Character.isDigit(position.charAt(index))) { found = true; } else { part = position.charAt(index) + part; index--; } } if(found) { feature_name = position.substring(0, index + 1); } // We ran out of string. No digits. Arg! else { part = null; } } // And if all else fails, stick it all in feature. if(feature_name == null || part == null) { feature_name = position; part = ""; } // Now try to retrieve a classifier with the feature name. Object feature = null; String feature_name_lc = feature_name.toLowerCase(); if(feature_name_lc.startsWith("cl") && feature_name.length() >= 3) { String raw_index = feature_name.substring(2); // Lose the 'CL' int index = -1; try { index = Integer.parseInt(raw_index); } catch(NumberFormatException nfe) { nfe.printStackTrace(); } feature = manager.classifiers.getClassifier(index - 1); } else { ///ystem.err.println("name to short for classifier."); } if(feature == null) { feature = feature_name; } ///ystem.err.println("Feature name = " + feature_name + "\nPart = " + part); if(feature instanceof Classifier) { ///ystem.err.println("Feature is a classifier."); } else { ///ystem.err.println("Feature is a String."); } // Now we have a quick look at value. If its true or false we create a FLAG type if(value.equalsIgnoreCase("true")) { addFormat(new Format(feature, part, true)); } else if(value.equalsIgnoreCase("false")) { addFormat(new Format(feature, part, false)); } // Otherwise add a plain old value based format else { addFormat(new Format(feature, part, value)); } return true; } // Somethings gone terribly, terribly wrong. return false; } else { unresolved_commands.add(command); } return true; } return false; } /** Method to remove a format. * @param format The Format to remove. */ public void removeFormat(Format format) { removeElement(format); gatherer.c_man.configurationChanged(); } /** Method which attempts to reparse obvious format commands which previously referenced unresovable Classifiers. */ public void reparseUnresolved() { for(int i = 0; i < unresolved_commands.size(); i++) { if(!parse((String)unresolved_commands.get(i), true)) { ///ystem.err.println("*** Error: Command " + unresolved_commands.get(i)); } } // Regardless of if they work, clear the commands. unresolved_commands.clear(); } /** Method to produce a block of text representing the format commands in this manager, ready to be used in the collection configuration file. * @return A String containing a series of format commands. */ public String toString() { StringBuffer text = new StringBuffer(""); for(int i = 0; i < size(); i++) { Format format = (Format) get(i); text.append(format.toString()); text.append("\n"); } text.append("\n"); return text.toString(); } /** Overloaded to call get with both a key and an empty argument array. * @param key A String which is mapped to a initial String within the ResourceBundle. * @return A String which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call. */ private String get(String key) { return get(key, null); } /** Used to retrieve a property value from the Locale specific ResourceBundle, based upon the key and arguments supplied. If the key cannot be found or if some other part of the call fails a default (English) error message is returned.
* Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {n}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Fargn. * @param key A String which is mapped to a initial String within the ResourceBundle. * @param args A String[] used to populate argument fields within the complete String. * @return A String which has been referenced by the key String and that either contains no argument fields, or has had the argument fields automatiically populated with formatting Strings of with argument String provided in the get call. * @see org.greenstone.gatherer.Gatherer * @see org.greenstone.gatherer.Dictionary */ private String get(String key, String args[]) { if(key.indexOf('.') == -1) { key = "CDM.FormatManager." + key; } return gatherer.dictionary.get(key, args); } private class Control extends JPanel { /** Do we ignore selection changing events (mainly because we're generating them!) */ private boolean ignore = false; private boolean new_entry = true; private boolean ready = false; private ButtonGroup button_group = null; private CardLayout card_layout = null; private Dimension LABEL_SIZE = new Dimension(175,25); private Format current_format = null; private String view_type = "custom"; private JButton add = null; private JButton insert = null; private JButton preview = null; private JButton remove = null; private JComboBox feature = null; private JComboBox part = null; private JComboBox special = null; private JLabel editor_label = null; private JLabel feature_label = null; private JLabel format_list_label = null; private JLabel part_label = null; private JLabel special_label = null; private JLabel title = null; private JLabel value_label = null; private JList format_list = null; private JPanel blank_pane = null; private JPanel control_pane = null; private JPanel editor_pane = null; private JPanel feature_pane = null; private JPanel format_list_pane = null; private JPanel header_pane = null; private JPanel inner_button_pane = null; private JPanel inner_state_pane = null; private JPanel inner_value_pane = null; private JPanel options_pane = null; private JPanel outer_button_pane = null; private JPanel part_pane = null; private JPanel special_pane = null; private JPanel state_pane = null; private JPanel value_pane = null; private JPanel view_pane = null; private JTextArea editor = null; private JTextArea instructions = null; private JTextField value = null; private JToggleButton off = null; private JToggleButton on = null; private String BLANK = "blank"; private String CUSTOM = "custom"; private String FLAG = "flag"; private String PARAM = "param"; private Vector part_model = null; private Vector special_model = null; public Control() { ArrayList feature_model = new ArrayList(); // Add the set options for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) { feature_model.add(new Entry(Format.DEFAULT_FEATURES[i])); } // Now the classifiers. for(int j = 0; j < manager.classifiers.size(); j++) { feature_model.add(new Entry(manager.classifiers.getClassifier(j))); } Collections.sort(feature_model); part_model = new Vector(); part_model.add("");//get("Custom")); part_model.add("DateList"); part_model.add("HList"); part_model.add("Invisible"); part_model.add("VList"); special_model = new Vector(); special_model.add("[Text]"); special_model.add("[link]"); special_model.add("[/link]"); special_model.add("[icon]"); special_model.add("[num]"); special_model.add("[parent():_]"); special_model.add("[parent(Top):_]"); special_model.add("[parent(All'_'):_]"); Vector elements = gatherer.c_man.msm.getAssignedElements(); for(int i = 0; i < elements.size(); i++) { special_model.add("[" + ((ElementWrapper)elements.get(i)).toString() + "]"); } Collections.sort(special_model); // Create add = new JButton(get("Add")); add.setEnabled(false); blank_pane = new JPanel(); button_group = new ButtonGroup(); card_layout = new CardLayout(); control_pane = new JPanel(); editor = new JTextArea(); editor.setCaretPosition(0); editor.setLineWrap(true); editor.setWrapStyleWord(true); editor_label = new JLabel(get("Editor")); editor_label.setHorizontalAlignment(JLabel.CENTER); editor_pane = new JPanel(); feature = new JComboBox(feature_model.toArray()); feature.setEditable(true); feature_label = new JLabel(get("Feature")); feature_label.setPreferredSize(LABEL_SIZE); format_list = new JList(model); format_list_label = new JLabel(get("Assigned_Formats")); format_list_pane = new JPanel(); feature_pane = new JPanel(); header_pane = new JPanel(); inner_button_pane = new JPanel(); inner_state_pane = new JPanel(); inner_value_pane = new JPanel(); insert = new JButton(get("Insert")); instructions = new JTextArea(get("Instructions")); instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false)); instructions.setEditable(false); instructions.setLineWrap(true); instructions.setRows(4); instructions.setWrapStyleWord(true); off = new JToggleButton(get("Off")); off.setSelected(false); on = new JToggleButton(get("On")); on.setSelected(true); options_pane = new JPanel(); outer_button_pane = new JPanel(); part = new JComboBox(part_model); part.setEditable(true); part_label = new JLabel(get("Part")); part_label.setPreferredSize(LABEL_SIZE); part_pane = new JPanel(); preview = new JButton(get("Preview")); preview.setEnabled(false); remove = new JButton(get("Remove")); remove.setEnabled(false); special = new JComboBox(special_model); special_label = new JLabel(get("Special")); special_label.setHorizontalAlignment(JLabel.CENTER); special_pane = new JPanel(); state_pane = new JPanel(); title = new JLabel(get("Title")); title.setHorizontalAlignment(JLabel.CENTER); title.setOpaque(true); value = new JTextField(); value_label = new JLabel(get("Value")); value_pane = new JPanel(); view_pane = new JPanel(); // Connect add.addActionListener(new AddListener()); button_group.add(on); button_group.add(off); editor.addKeyListener(new EditorListener()); feature.addActionListener(new FeatureListener()); format_list.addListSelectionListener(new FormatListListener()); insert.addActionListener(new InsertListener()); off.addActionListener(new StateListener()); on.addActionListener(new StateListener()); part.addActionListener(new PartListener()); preview.addActionListener(new PreviewListener()); remove.addActionListener(new RemoveListener()); value.addKeyListener(new ValueListener()); // Layout instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5)); header_pane.setLayout(new BorderLayout()); header_pane.add(title, BorderLayout.NORTH); header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER); format_list_label.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); format_list_pane.setLayout(new BorderLayout()); format_list_pane.add(format_list_label, BorderLayout.NORTH); format_list_pane.add(new JScrollPane(format_list), BorderLayout.CENTER); feature_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5)); feature_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); feature_pane.setLayout(new BorderLayout()); feature_pane.add(feature_label, BorderLayout.WEST); feature_pane.add(feature, BorderLayout.CENTER); part_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5)); part_pane.setBorder(BorderFactory.createEmptyBorder(5,0,5,0)); part_pane.setLayout(new BorderLayout()); part_pane.add(part_label, BorderLayout.WEST); part_pane.add(part, BorderLayout.CENTER); options_pane.setLayout(new GridLayout(2,1)); options_pane.add(feature_pane); options_pane.add(part_pane); inner_state_pane = new JPanel(new GridLayout(1,2)); inner_state_pane.add(on); inner_state_pane.add(off); state_pane.setLayout(new BorderLayout()); state_pane.add(inner_state_pane, BorderLayout.NORTH); state_pane.add(new JPanel(), BorderLayout.CENTER); value_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5)); inner_value_pane.setLayout(new BorderLayout()); inner_value_pane.add(value_label, BorderLayout.WEST); inner_value_pane.add(value, BorderLayout.CENTER); value_pane.setLayout(new BorderLayout()); value_pane.add(inner_value_pane, BorderLayout.NORTH); value_pane.add(new JPanel(), BorderLayout.CENTER); special_pane.setLayout(new GridLayout(3,1)); special_pane.add(special_label); special_pane.add(special); special_pane.add(insert); editor_pane.setLayout(new BorderLayout()); editor_pane.add(editor_label, BorderLayout.NORTH); editor_pane.add(new JScrollPane(editor), BorderLayout.CENTER); editor_pane.add(special_pane, BorderLayout.EAST); // Magic for view_pane card layout. view_pane.setLayout(card_layout); view_pane.add(editor_pane, CUSTOM); view_pane.add(state_pane, FLAG); //view_pane.add(value_pane, PARAM); inner_button_pane.setLayout(new GridLayout(1,2)); inner_button_pane.add(add); inner_button_pane.add(remove); outer_button_pane.setBorder(BorderFactory.createEmptyBorder(5,0,0,0)); outer_button_pane.setLayout(new GridLayout(1,1)); outer_button_pane.add(inner_button_pane); //outer_button_pane.add(preview); control_pane.setLayout(new BorderLayout()); control_pane.add(options_pane, BorderLayout.NORTH); control_pane.add(view_pane, BorderLayout.CENTER); control_pane.add(outer_button_pane, BorderLayout.SOUTH); setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); setLayout(new BorderLayout()); add(header_pane, BorderLayout.NORTH); add(format_list_pane, BorderLayout.CENTER); add(control_pane, BorderLayout.SOUTH); ready = true; } public void destroy() { } /** Overriden to ensure that the instructions pane is scrolled to the top. */ public void updateUI() { if(ready) { // Rebuild feature model. ArrayList feature_model = new ArrayList(); // Add the set options for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) { feature_model.add(new Entry(Format.DEFAULT_FEATURES[i])); } // Now the classifiers. for(int j = 0; j < manager.classifiers.size(); j++) { feature_model.add(new Entry(manager.classifiers.getClassifier(j))); } feature.setModel(new DefaultComboBoxModel(feature_model.toArray())); if(instructions != null) { instructions.setCaretPosition(0); } } super.updateUI(); } /** Formats the formatting string so that it contains safe characters and isn't enclosed in speech marks etc. (Ironic eh?) * @see java.lang.StringBuffer */ private String format(String raw) { String safe = null; if(raw != null && raw.length() > 0) { StringBuffer temp = new StringBuffer(raw); // Remove quotes at start and end. Look at my wiggly save three lines of code skills. char start = ' '; while(temp.length() > 0 && (start = temp.charAt(0)) == '\"' || start == '\'') { temp.delete(0, 1); } int length = 0; char end = ' '; while((length = temp.length()) > 0 && (end = temp.charAt(length - 1)) == '\"' || end == '\'') { temp.delete(length - 1, length); } // Now escape quotes within the format string int quote_index = -1; while((quote_index = temp.indexOf("\"", quote_index + 1)) != -1) { temp.replace(quote_index, quote_index + 1, "\\\""); quote_index = quote_index + 1; } // Done. safe = temp.toString(); } return safe; } /** Remove safe characters from string replacing them with unsafe ones. * @see java.lang.StringBuffer */ private String unformat(String safe) { String raw = null; if(safe != null && safe.length() > 0) { StringBuffer temp = new StringBuffer(safe); int quote_index = -1; while((quote_index = temp.indexOf("\\\"")) != -1) { temp.replace(quote_index, quote_index + 2, "\""); } raw = temp.toString(); } return raw; } /** Listens for clicks on the add button, and if the relevant details are provided adds a new format. */ private class AddListener implements ActionListener { public void actionPerformed(ActionEvent event) { ignore = true; Entry entry = (Entry)feature.getSelectedItem(); Object f = entry.getFeature(); String p = (String)part.getSelectedItem(); if(view_type.equals(FLAG)) { current_format = new Format(f, p, on.isSelected()); } else { current_format = new Format(f, p, format(Utility.stripNL(editor.getText()))); } addFormat(current_format); add.setEnabled(false); remove.setEnabled(true); // Update list selection format_list.setSelectedValue(current_format, true); new_entry = false; ignore = false; } } private class EditorListener extends KeyAdapter { public void keyReleased(KeyEvent event) { String safe = format(editor.getText()); if(!ignore && current_format != null) { // We have just performed an edit. Immediately update the format and model. if(safe != null) { current_format.setValue(safe); } else { current_format.setValue(""); } gatherer.c_man.configurationChanged(); model.refresh(); } Entry entry = (Entry) feature.getSelectedItem(); String name = entry.toString(); if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && safe != null && safe.length() != 0 && new_entry) { add.setEnabled(true); } else { add.setEnabled(false); } } } /** This object provides a wrapping around an entry in the format target control, which is tranparent as to whether it is backed by a String or a Classifier. */ private class Entry implements Comparable { private Classifier classifier = null; private CustomClassifier custom_classifier = null; private String text = null; public Entry(Object object) { if(object instanceof Classifier) { classifier = (Classifier)object; } if(object instanceof CustomClassifier) { custom_classifier = (CustomClassifier)object; } else if(object instanceof String) { text = (String)object; } else { text = ""; } } public Entry(String text) { this.text = text; } public int compareTo(Object object) { if(object == null) { return 1; } if(toString() == null) { return -1; } else { String object_str = object.toString(); if(object_str == null) { return 1; } return toString().compareTo(object_str); } } public boolean equals(Object object) { if(compareTo(object) == 0) { return true; } return false; } public Classifier getClassifier() { return classifier; } public CustomClassifier getCustomClassifier() { return custom_classifier; } public Object getFeature() { if(classifier != null) { return classifier; } return text; } public String toString() { if(classifier != null) { String name = classifier.toString(); return name.substring(9); } if(custom_classifier != null) { String name = custom_classifier.toString(); return name;//.substring(17); } return text; } } private class FeatureListener implements ActionListener { public void actionPerformed(ActionEvent event) { if(!ignore) { current_format = null; Entry entry = (Entry) feature.getSelectedItem(); String name = entry.toString(); int type = Format.getType(name); switch(type) { case Format.FLAG: // Flags first. part.setEnabled(false); part_pane.remove(part); card_layout.show(view_pane, FLAG); view_type = FLAG; add.setEnabled(true); // One of the options must be selected. break; default: part.setEnabled(true); part_pane.add(part, BorderLayout.CENTER); card_layout.show(view_pane, CUSTOM); view_type = CUSTOM; if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && editor.getText().length() != 0) { add.setEnabled(true); } else { add.setEnabled(false); } } control_pane.updateUI(); new_entry = true; } } } private class FormatListListener implements ListSelectionListener { public void valueChanged(ListSelectionEvent event) { if(!ignore) { if(!format_list.isSelectionEmpty()) { ignore = true; current_format = (Format)format_list.getSelectedValue(); // Try to match the target, remembering the entries within are Entry's Entry an_entry = new Entry(current_format.getFeature()); feature.setSelectedItem(an_entry); // Try to match the part. part.setSelectedItem(current_format.getPart()); // Now use type to determine what controls are visible, and what have initial values. switch(current_format.getType()) { case Format.FLAG: // Flags first. part.setEnabled(false); part_pane.remove(part); card_layout.show(view_pane, FLAG); view_type = FLAG; // Initial value on.setSelected(current_format.getState()); off.setSelected(!current_format.getState()); add.setEnabled(false); // Can only update break; default: part.setEnabled(true); part_pane.add(part, BorderLayout.CENTER); card_layout.show(view_pane, CUSTOM); view_type = CUSTOM; // Initial value editor.setText(unformat(current_format.getValue())); add.setEnabled(false); } control_pane.updateUI(); ignore = false; preview.setEnabled(true); remove.setEnabled(true); new_entry = false; } else { preview.setEnabled(false); remove.setEnabled(false); } } } } private class InsertListener implements ActionListener { public void actionPerformed(ActionEvent event) { editor.insert((String)special.getSelectedItem(), editor.getCaretPosition()); } } private class PartListener implements ActionListener { public void actionPerformed(ActionEvent event) { if(!ignore) { current_format = null; Entry entry = (Entry) feature.getSelectedItem(); String name = entry.toString(); if(!(name.length() == 0 && ((String)part.getSelectedItem()).length() == 0) && editor.getText().length() != 0) { add.setEnabled(true); } else { add.setEnabled(false); } new_entry = true; } } } private class PreviewListener implements ActionListener { public void actionPerformed(ActionEvent event) { } } private class RemoveListener implements ActionListener { public void actionPerformed(ActionEvent event) { if(!format_list.isSelectionEmpty()) { removeFormat((Format)format_list.getSelectedValue()); // Change buttons add.setEnabled(true); remove.setEnabled(false); } } } private class StateListener implements ActionListener { public void actionPerformed(ActionEvent event) { if(!ignore && current_format != null) { // We have just performed an edit. Immediately update the format and model. current_format.setState(on.isSelected()); model.refresh(); } } } private class ValueListener extends KeyAdapter { public void keyReleased(KeyEvent event) { if(!ignore && current_format != null) { // We have just performed an edit. Immediately update the format and model. current_format.setValue(value.getText()); model.refresh(); } } } } }