Ignore:
Timestamp:
2003-07-15T13:55:22+12:00 (21 years ago)
Author:
jmt12
Message:

Major CDM rewrite so it uses DOM.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gli/src/org/greenstone/gatherer/cdm/FormatManager.java

    r4675 r4932  
    66 * University of Waikato, New Zealand.
    77 *
    8  * <BR><BR>
    9  *
    108 * Author: John Thompson, Greenstone Digital Library, University of Waikato
    119 *
    12  * <BR><BR>
    13  *
    1410 * Copyright (C) 1999 New Zealand Digital Library Project
    15  *
    16  * <BR><BR>
    1711 *
    1812 * This program is free software; you can redistribute it and/or modify
     
    2115 * (at your option) any later version.
    2216 *
    23  * <BR><BR>
    24  *
    2517 * This program is distributed in the hope that it will be useful,
    2618 * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2719 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2820 * GNU General Public License for more details.
    29  *
    30  * <BR><BR>
    3121 *
    3222 * You should have received a copy of the GNU General Public License
     
    3525 *########################################################################
    3626 */
    37 
    38  
    39 
    40 
    41 
    42 
    43 /* GPL_HEADER */
    4427package org.greenstone.gatherer.cdm;
    4528/**************************************************************************************
    46  * Title:        Gatherer
    47  * Description:  The Gatherer: a tool for gathering and enriching a digital collection.
    48  * Company:      The University of Waikato
    49  * Written:        /05/02
    50  * Revised:      04/10/02 - Commented
     29 * Written:     06/05/02
     30 * Revised:     04/10/02 - Commented
     31 *              14/07/03 - DOM support
    5132 **************************************************************************************/
    52 import java.awt.BorderLayout;
    53 import java.awt.CardLayout;
    54 import java.awt.Color;
    55 import java.awt.Dimension;
    56 import java.awt.GridLayout;
    57 import java.awt.event.ActionEvent;
    58 import java.awt.event.ActionListener;
    59 import java.awt.event.KeyAdapter;
    60 import java.awt.event.KeyEvent;
    61 import java.util.ArrayList;
    62 import java.util.Collections;
    63 import java.util.Vector;
    64 import javax.swing.BorderFactory;
    65 import javax.swing.BoxLayout;
    66 import javax.swing.ButtonGroup;
    67 import javax.swing.DefaultComboBoxModel;
    68 import javax.swing.JButton;
    69 import javax.swing.JCheckBox;
    70 import javax.swing.JComboBox;
    71 import javax.swing.JLabel;
    72 import javax.swing.JList;
    73 import javax.swing.JPanel;
    74 import javax.swing.JScrollPane;
    75 import javax.swing.JTabbedPane;
    76 import javax.swing.JTextArea;
    77 import javax.swing.JTextField;
    78 import javax.swing.JToggleButton;
    79 import javax.swing.ListSelectionModel;
    80 import javax.swing.event.ListSelectionEvent;
    81 import javax.swing.event.ListSelectionListener;
     33import java.awt.*;
     34import java.awt.event.*;
     35import java.util.*;
     36import javax.swing.*;
     37import javax.swing.event.*;
    8238import org.greenstone.gatherer.Gatherer;
    8339import org.greenstone.gatherer.cdm.Classifier;
    8440import org.greenstone.gatherer.cdm.ClassifierManager;
     41import org.greenstone.gatherer.cdm.CollectionConfiguration;
    8542import org.greenstone.gatherer.cdm.CollectionDesignManager;
    8643import org.greenstone.gatherer.cdm.CommandTokenizer;
    87 import org.greenstone.gatherer.cdm.DynamicListModel;
     44import org.greenstone.gatherer.cdm.Control;
     45import org.greenstone.gatherer.cdm.DOMProxyListModel;
    8846import org.greenstone.gatherer.cdm.Format;
    8947import org.greenstone.gatherer.msm.ElementWrapper;
    9048import org.greenstone.gatherer.util.Utility;
     49import org.w3c.dom.*;
    9150/** This class maintains a list of format statements, and allows the addition and removal of these statements.
    9251 * @author John Thompson, Greenstone Digital Library, University of Waikato
     
    9453 */
    9554public class FormatManager
    96     extends DynamicListModel {
    97     /** The main manager so we can get to ClassifierManager which is needed to turn position reference such as "CL1" into the appropriate Classifier. */
    98     private CollectionDesignManager manager = null;
     55    extends DOMProxyListModel {
     56
    9957    /** The controls used to edit the format commands. */
    10058    private Control controls = null;
    10159    /** A reference to ourselves so inner classes can get at the model. */
    102     private DynamicListModel model = null;
    103     /** A reference to the Gatherer. */
    104     private Gatherer gatherer = null;
    105     /** 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. */
    106     private Vector unresolved_commands = null;
    107     /** Constructor.
    108      * @param gatherer A reference to the <strong>Gatherer</strong>.
    109      * @param manager A reference to the <strong>CollectionDesignManager</strong> that created this manager.
    110      */
    111     public FormatManager(Gatherer gatherer, CollectionDesignManager manager) {
    112     super();
    113     this.gatherer = gatherer;
    114     this.manager = manager;
     60    private DOMProxyListModel model = null;
     61
     62    /** Constructor. */
     63    public FormatManager() {
     64    super(CollectionDesignManager.collect_config.getDocumentElement(), CollectionConfiguration.FORMAT_ELEMENT, new Format());
    11565    this.model = this;
    116     this.unresolved_commands = new Vector();
     66    Gatherer.println("FormatManager: parsed " + getSize() + " format statements.");
     67    // Establish all of the format objects, so that classifier indexes are initially correct (subsequent refreshes of the model will be sufficient to keep these up to date, as long as we start with a live reference to a classifier.
     68    int size = getSize();
     69    for(int i = 0; i < size; i++) {
     70        getElementAt(i);
     71    }
    11772    }
    11873    /** Method to add a new format to this manager.
     
    12075      */
    12176    public void addFormat(Format format) {
    122     if(formatExists(format) == null) {
    123         addElement(format);
    124         gatherer.c_man.configurationChanged();
    125     }
    126     }
    127     /** 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.
    128       * @param format The <strong>Format</strong> whose uniqueness we want to check.
    129       * @return The <strong>Format</strong> that matches the one given, or <i>null</i> if no such format exists.
    130       */
    131     public Format formatExists(Format format) {
    132     for(int i = 0; i < size(); i++) {
    133         Format current = (Format) get(i);
    134         if(format.getPosition().equals(current.getPosition())) {
    135         return current;
    136         }
    137     }
    138     return null;
    139     }
     77    if(!contains(format)) {
     78        Element element = format.getElement();
     79        // Locate where we should insert this new classifier.
     80        Node target_node = CollectionConfiguration.findInsertionPoint(element);
     81        add(root, format, target_node);
     82        Gatherer.c_man.configurationChanged();
     83    }
     84    }
     85
     86    public void destroy() {
     87    if(controls != null) {
     88        controls.destroy();
     89        controls = null;
     90    }
     91    }
     92
    14093    /** Gets the format indicated by the index.
    141       * @param index The location of the desired format, as an <i>int</i>.
    142       */
     94     * @param index The location of the desired format, as an <i>int</i>.
     95     */
    14396    public Format getFormat(int index) {
    144     return (Format)get(index);
    145     }
     97    Format result = null;
     98    if(0 < index && index < getSize()) {
     99        result = (Format) getElementAt(index);
     100    }
     101    return result;
     102    }
     103   
    146104    /** Method to retrieve this managers controls.
    147       * @return The <strong>Control</strong> for this collection.
    148       */
     105     * @return the Control for this collection.
     106     */
    149107    public Control getControls() {
    150108    if(controls == null) {
    151         controls = new Control();
     109        controls = new FormatControl();
    152110    }
    153111    return controls;
    154112    }
    155     /** Method to invalidate controls when some significant change has occured within the collection. */
    156     public void invalidateControls() {
    157     if(controls != null) {
    158         controls.destroy();
    159     }
    160     controls = null;
    161     }
    162     /** 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.
    163       * @param command The <strong>String</strong> we are trying to parse a command from.
    164       * @param finished A <i>boolean</i> which is <i>true</i> if we are calling this after the the input has been completely parsed (i.e all legal Classifiers are know to exist), or <i>false</i> otherwise.
    165       * @return A <i>boolean</i> which is <i>true</i> if we managed to parse a command, <i>false</i> otherwise.
    166       * @see org.greenstone.gatherer.cdm.Classifier
    167       * @see org.greenstone.gatherer.cdm.CommandTokenizer
    168       * @see org.greenstone.gatherer.cdm.Format
    169       */
    170     public boolean parse(String command, boolean finished) {
    171     String temp = command.toLowerCase();
    172     if(temp.startsWith("format")) {
    173         if(finished) {
    174         CommandTokenizer ct = new CommandTokenizer(command);
    175         ct.nextToken(); // Throw away 'format'
    176         String position = ct.nextToken();
    177         String value = ct.nextToken();
    178         // String speech marks.
    179         if(value.startsWith("\"") && value.endsWith("\"")) {
    180             if(value.equals("\"\"")) {
    181             value = "";
    182             }
    183             else {
    184             value = value.substring(1, value.length() - 1);
    185             }
    186         }
    187         // Ensure we parsed a good command.
    188         if(position != null && value != null) {
    189             // 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).
    190             String feature_name = null;
    191             String part = null;
    192             // If this works, then we're all finished. Yay.
    193             for(int i = 1; i < Format.DEFAULT_PARTS.length; i++) {
    194             if(position.endsWith(Format.DEFAULT_PARTS[i])) {
    195                 part = Format.DEFAULT_PARTS[i];
    196                 feature_name = position.substring(0, position.length() - part.length());
    197             }
    198             }
    199             // Otherwise we can attempt to find the default features, but we have less chance of success.
    200             if(feature_name == null || part == null) {
    201             for(int i = 1; i < Format.DEFAULT_FEATURES.length; i++) {
    202                 if(position.startsWith(Format.DEFAULT_FEATURES[i])) {
    203                 feature_name = Format.DEFAULT_FEATURES[i];
    204                 if(position.length() > feature_name.length()) {
    205                     part = position.substring(feature_name.length());
    206                 }
    207                 else {
    208                     part = "";
    209                 }
    210                 }
    211             }
    212             }
    213             // Otherwise we can assume we are dealing with a classifier and split the position using...
    214             // position            ::= <classifier_position><part>
    215             // classifier_position ::= <alphanum>[0-9]$
    216             // part                ::= ^![0-9]<alpha>
    217             // But I don't like my chances of this working if someone does a scary like CL4Part8B. I just have
    218             // to hope no-one uses numbers, and no-one expects CustomFeatureCustomPart to parse properly.
    219             if(feature_name == null || part == null) {
    220             part = "";
    221             boolean found = false;
    222             int index = position.length() - 1;
    223             while(index >= 0 && !found) {
    224                 if(Character.isDigit(position.charAt(index))) {
    225                 found = true;
    226                 }
    227                 else {
    228                 part = position.charAt(index) + part;
    229                 index--;
    230                 }
    231             }
    232             if(found) {
    233                 feature_name = position.substring(0, index + 1);
    234             }
    235             // We ran out of string. No digits. Arg!
    236             else {
    237                 part = null;
    238             }
    239             }
    240             // And if all else fails, stick it all in feature.
    241             if(feature_name == null || part == null) {
    242             feature_name = position;
    243             part = "";
    244             }
    245             // Now try to retrieve a classifier with the feature name.
    246             Object feature = null;
    247             String feature_name_lc = feature_name.toLowerCase();
    248             if(feature_name_lc.startsWith("cl") && feature_name.length() >= 3) {
    249             String raw_index = feature_name.substring(2); // Lose the 'CL'
    250             int index = -1;
    251             try {
    252                 index = Integer.parseInt(raw_index);
    253             }
    254             catch(NumberFormatException nfe) {
    255                 nfe.printStackTrace();
    256             }
    257             feature = manager.classifiers.getClassifier(index - 1);
    258             }
    259             else {
    260             ///ystem.err.println("name to short for classifier.");
    261             }
    262             if(feature == null) {
    263             feature = feature_name;
    264             }
    265             ///ystem.err.println("Feature name = " + feature_name + "\nPart = " + part);
    266             if(feature instanceof Classifier) {
    267             ///ystem.err.println("Feature is a classifier.");
    268             }
    269             else {
    270             ///ystem.err.println("Feature is a String.");
    271             }
    272             // Now we have a quick look at value. If its true or false we create a FLAG type
    273             if(value.equalsIgnoreCase("true")) {
    274             addFormat(new Format(feature, part, true));
    275             }
    276             else if(value.equalsIgnoreCase("false")) {
    277             addFormat(new Format(feature, part, false));
    278             }
    279             // Otherwise add a plain old value based format
    280             else {
    281             addFormat(new Format(feature, part, value));
    282             }
    283             return true;
    284         }
    285         // Somethings gone terribly, terribly wrong.
    286         return false;
    287         }
    288         else {
    289         // Ensure we have enough tokens for a format command
    290         CommandTokenizer ct = new CommandTokenizer(command);
    291         while(ct.countTokens() < 3) {
    292             command = manager.parseMore(command);
    293             ct = new CommandTokenizer(command);
    294         }
    295         unresolved_commands.add(command);
    296         }
    297         return true;
    298     }
    299     return false;
    300     }
     113
    301114    /** Method to remove a format.
    302       * @param format The <strong>Format</strong> to remove.
    303       */
     115     * @param format The <strong>Format</strong> to remove.
     116     */
    304117    public void removeFormat(Format format) {
    305     removeElement(format);
    306     gatherer.c_man.configurationChanged();
    307     }
    308     /** Method which attempts to reparse obvious format commands which previously referenced unresovable Classifiers.
    309     */
    310     public void reparseUnresolved() {
    311     for(int i = 0; i < unresolved_commands.size(); i++) {
    312         if(!parse((String)unresolved_commands.get(i), true)) {
    313         ///ystem.err.println("*** Error: Command " + unresolved_commands.get(i));
    314         }
    315     }
    316     // Regardless of if they work, clear the commands.
    317     unresolved_commands.clear();
    318     }
    319     /** Method to produce a block of text representing the format commands in this manager, ready to be used in the collection configuration file.
    320     * @return A <strong>String</strong> containing a series of format commands.
    321     */
    322     public String toString() {
    323     StringBuffer text = new StringBuffer("");
    324     for(int i = 0; i < size(); i++) {
    325         Format format = (Format) get(i);
    326         text.append(format.toString());
    327         text.append("\n");
    328     }
    329     text.append("\n");
    330     return text.toString();
    331     }
     118    remove(format);
     119    Gatherer.c_man.configurationChanged();
     120    }
     121
    332122    /** Overloaded to call get with both a key and an empty argument array.
    333       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    334       * @return A <strong>String</strong> 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.
    335       */
     123     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     124     * @return A <strong>String</strong> 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.
     125     */
    336126    private String get(String key) {
    337127    return get(key, null);
    338128    }
     129
    339130    /** 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. <BR>
    340       * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
    341       * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
    342       * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
    343       * @return A <strong>String</strong> 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.
    344       * @see org.greenstone.gatherer.Gatherer
    345       * @see org.greenstone.gatherer.Dictionary
    346       */
     131     * Here the get recieves a second argument which is an array of Strings used to populate argument fields, denoted {<I>n</I>}, within the value String returned. Note that argument numbers greater than or equal to 32 are automatically mapped to the formatting String named Farg<I>n</I>.
     132     * @param key A <strong>String</strong> which is mapped to a initial String within the ResourceBundle.
     133     * @param args A <strong>String[]</strong> used to populate argument fields within the complete String.
     134     * @return A <strong>String</strong> 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.
     135     * @see org.greenstone.gatherer.Gatherer
     136     * @see org.greenstone.gatherer.Dictionary
     137     */
    347138    private String get(String key, String args[]) {
    348139    if(key.indexOf('.') == -1) {
    349140        key = "CDM.FormatManager." + key;
    350141    }
    351     return gatherer.dictionary.get(key, args);
    352     }
    353     private class Control
    354     extends JPanel {
     142    return Gatherer.dictionary.get(key, args);
     143    }
     144
     145    private class FormatControl
     146    extends JPanel
     147    implements Control {
    355148    /** Do we ignore selection changing events (mainly because we're generating them!) */
    356149    private boolean ignore = false;
     
    404197    private Vector part_model = null;
    405198    private Vector special_model = null;
    406     public Control() {
    407         ArrayList feature_model = new ArrayList();
    408                 // Add the set options
    409         for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
    410         feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
    411         }
    412                 // Now the classifiers.
    413         for(int j = 0; j < manager.classifiers.size(); j++) {
    414         feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
    415         }
    416         Collections.sort(feature_model);
     199    public FormatControl() {
     200        ArrayList feature_model = buildFeatureModel();
    417201        part_model = new Vector();
    418202        part_model.add("");//get("Custom"));
     
    430214        special_model.add("[parent(Top):_]");
    431215        special_model.add("[parent(All'_'):_]");
    432         Vector elements = gatherer.c_man.msm.getAssignedElements();
     216        Vector elements = Gatherer.c_man.getCollection().msm.getAssignedElements();
    433217        for(int i = 0; i < elements.size(); i++) {
    434218        special_model.add("[" + ((ElementWrapper)elements.get(i)).toString() + "]");
    435219        }
    436220        Collections.sort(special_model);
    437                 // Create
     221        // Create
    438222        add = new JButton(get("Add"));
    439223        add.setEnabled(false);
     
    443227        control_pane = new JPanel();
    444228        editor = new JTextArea();
    445         editor.setBackground(Color.white);
     229        editor.setBackground(Gatherer.config.getColor("coloring.editable", false));
    446230        editor.setCaretPosition(0);
    447231        editor.setLineWrap(true);
    448         editor.setWrapStyleWord(true);
     232        editor.setWrapStyleWord(false);
    449233        editor_label = new JLabel(get("Editor"));
    450234        editor_label.setHorizontalAlignment(JLabel.CENTER);
     
    496280        value_pane = new JPanel();
    497281        view_pane = new JPanel();
    498                 // Connect
     282        // Connect
    499283        add.addActionListener(new AddListener());
    500284        button_group.add(on);
    501285        button_group.add(off);
    502         editor.addKeyListener(new EditorListener());
     286        editor.getDocument().addDocumentListener(new EditorListener());
    503287        feature.addActionListener(new FeatureListener());
    504288        format_list.addListSelectionListener(new FormatListListener());
     
    596380        ready = true;
    597381    }
     382
    598383    public void destroy() {
    599384    }
     385
    600386    /** Overriden to ensure that the instructions pane is scrolled to the top.
    601             */
    602     public void updateUI() {
     387     */
     388    public void gainFocus() {
     389        // This is only necessary if the components have been realized
    603390        if(ready) {
    604         // Rebuild feature model.
    605         ArrayList feature_model = new ArrayList();
    606         // Add the set options
    607         for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
    608             feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
    609         }
    610         // Now the classifiers.
    611         for(int j = 0; j < manager.classifiers.size(); j++) {
    612             feature_model.add(new Entry(manager.classifiers.getClassifier(j)));
    613         }
     391        model.refresh();
     392        ArrayList feature_model = buildFeatureModel();
     393        // Remember the current selection
     394        Object selected_object = feature.getSelectedItem();
    614395        feature.setModel(new DefaultComboBoxModel(feature_model.toArray()));
     396        // Now resotre the selected object as best as possible
     397        feature.setSelectedItem(selected_object);
    615398        if(instructions != null) {
    616399            instructions.setCaretPosition(0);
    617400        }
    618         }
    619         super.updateUI();
    620     }
    621 
    622 
     401        }   
     402    }
     403
     404    public void loseFocus() {
     405        // Force all of the Formats to update their names with the correct values.
     406        int size = model.getSize();
     407        for(int i = 0; i < size; i++) {
     408        Format format = (Format) model.getElementAt(i);
     409        format.update();
     410        }
     411    }
     412
     413    private ArrayList buildFeatureModel() {
     414        // Rebuild feature model.
     415        ArrayList feature_model = new ArrayList();
     416        // Add the set options
     417        for(int i = 0; i < Format.DEFAULT_FEATURES.length; i++) {
     418        feature_model.add(new Entry(Format.DEFAULT_FEATURES[i]));
     419        }
     420        // Now the classifiers.
     421        for(int j = 0; j < CollectionDesignManager.classifier_manager.getSize(); j++) {
     422        feature_model.add(new Entry(CollectionDesignManager.classifier_manager.getClassifier(j)));
     423        }
     424        Collections.sort(feature_model);
     425        return feature_model;
     426    }
    623427
    624428    /** Formats the formatting string so that it contains safe characters and isn't enclosed in speech marks etc. (Ironic eh?)
    625             * @see java.lang.StringBuffer
    626             */
     429     * @see java.lang.StringBuffer
     430     */
    627431    private String format(String raw) {
    628432        String safe = null;
     
    665469        return raw;
    666470    }
     471
    667472    /** Listens for clicks on the add button, and if the relevant details are provided adds a new format. */
    668473    private class AddListener
    669474        implements ActionListener {
    670475        public void actionPerformed(ActionEvent event) {
    671         ignore = true;
     476        //ignore = true;
    672477        Entry entry = (Entry)feature.getSelectedItem();
    673478        Object f = entry.getFeature();
     
    685490        format_list.setSelectedValue(current_format, true);
    686491        new_entry = false;
    687         ignore = false;
    688         }
    689     }
     492        //ignore = false;
     493        }
     494    }
     495
    690496    private class EditorListener
    691         extends KeyAdapter {
    692         public void keyReleased(KeyEvent event) {
     497        implements DocumentListener {
     498 
     499        public void changedUpdate(DocumentEvent e) {
     500        update();
     501        }
     502         
     503        public void insertUpdate(DocumentEvent e) {
     504        update();
     505        }
     506         
     507        public void removeUpdate(DocumentEvent e) {
     508        update();
     509        }
     510
     511        public void update() {
    693512        String safe = format(editor.getText());
    694513        if(!ignore && current_format != null) {
     
    700519            current_format.setValue("");
    701520            }
    702             gatherer.c_man.configurationChanged();
    703             model.refresh();
     521            Gatherer.c_man.configurationChanged();
     522            model.refresh(current_format);
    704523        }
    705524        Entry entry = (Entry) feature.getSelectedItem();
     
    713532        }
    714533    }
     534
    715535    /** 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. */
    716536    private class Entry
     
    781601        }
    782602    }
     603
    783604    private class FeatureListener
    784605        implements ActionListener {
     
    788609            Entry entry = (Entry) feature.getSelectedItem();
    789610            String name = entry.toString();
    790             int type = Format.getType(name);
    791             switch(type) {
    792             case Format.FLAG:
     611            if(Format.isParamType(name)) {
    793612            // Flags first.
    794613            part.setEnabled(false);
     
    797616            view_type = FLAG;
    798617            add.setEnabled(true); // One of the options must be selected.
    799             break;
    800             default:
     618            }
     619            else {
    801620            part.setEnabled(true);
    802621            part_pane.add(part, BorderLayout.CENTER);
     
    815634        }
    816635    }
     636
    817637    private class FormatListListener
    818638        implements ListSelectionListener {
     
    825645            Entry an_entry = new Entry(current_format.getFeature());
    826646            feature.setSelectedItem(an_entry);
    827             // Try to match the part.
    828             part.setSelectedItem(current_format.getPart());
     647            // If we didn't match anything, add it and select it again
     648            Entry result_entry = (Entry) feature.getSelectedItem();
     649            if(!an_entry.equals(result_entry)) {
     650                feature.insertItemAt(an_entry, feature.getItemCount());
     651                feature.setSelectedItem(an_entry);
     652            }
     653           
     654            if(current_format.canHavePart()) {
     655                part.setEnabled(true);
     656                // Try to match the part.
     657                String part_entry = current_format.getPart();
     658                part.setSelectedItem(part_entry);
     659                // If we didn't match anything, add it and select it again
     660                String selected_part = (String)part.getSelectedItem();
     661                if(!part_entry.equals(selected_part)) {
     662                part.insertItemAt(part_entry, part.getItemCount());
     663                feature.setSelectedItem(part_entry);
     664                }
     665            }
     666            else {
     667                part.setEnabled(false);
     668            }
    829669            // Now use type to determine what controls are visible, and what have initial values.
    830             switch(current_format.getType()) {
    831             case Format.FLAG:
     670            if(current_format.isParamType()) {
    832671                // Flags first.
    833672                part.setEnabled(false);
     
    839678                off.setSelected(!current_format.getState());
    840679                add.setEnabled(false); // Can only update
    841                 break;
    842             default:
     680            }
     681            else {
    843682                part.setEnabled(true);
    844683                part_pane.add(part, BorderLayout.CENTER);
     
    907746            // We have just performed an edit. Immediately update the format and model.
    908747            current_format.setState(on.isSelected());
    909             model.refresh();
     748            model.refresh(current_format);
    910749        }
    911750        }
     
    917756            // We have just performed an edit. Immediately update the format and model.
    918757            current_format.setValue(value.getText());
    919             model.refresh();
     758            model.refresh(current_format);
    920759        }
    921760        }
Note: See TracChangeset for help on using the changeset viewer.