Changeset 4424


Ignore:
Timestamp:
2003-05-30T13:49:03+12:00 (21 years ago)
Author:
mdewsnip
Message:

Cleaned a lot of dead code out of here, moved some code into MetaEditPane, and tidied up all the listeners and the interaction between table, text field and value tree. Now totally bug free. Yip, not one. No bugs. None. Nada. Zip. And hey wow, a flying pig!

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/gli/src/org/greenstone/gatherer/valuetree/GValueTree.java

    r4408 r4424  
    4444import javax.swing.tree.*;
    4545import org.greenstone.gatherer.Gatherer;
    46 import org.greenstone.gatherer.gui.EditorDialog;
    4746import org.greenstone.gatherer.gui.MetaEditPane;
    4847import org.greenstone.gatherer.gui.SmarterTextArea;
    49 import org.greenstone.gatherer.gui.combobox.GComboBox;
    50 import org.greenstone.gatherer.gui.combobox.GComboBoxModel;
    5148import org.greenstone.gatherer.msm.ElementWrapper;
    5249import org.greenstone.gatherer.msm.Metadata;
    53 import org.greenstone.gatherer.msm.MetadataComboBoxModel;
    54 import org.greenstone.gatherer.msm.MSMAction;
    55 import org.greenstone.gatherer.msm.MSMEvent;
    56 import org.greenstone.gatherer.msm.MSMListener;
    5750import org.greenstone.gatherer.util.Utility;
    5851/**
     
    6255public class GValueTree
    6356    extends JPanel
    64     implements ActionListener, FocusListener, MSMListener, TreeSelectionListener {
    65     /** Is the metadata currently shown in the edit controls common to all records selected. */
    66     private boolean common = false;
    67     /** Certain actions are disabled if the metadata selected isn't at file level. */
    68     private boolean file_level = false;
    69     private boolean ignore = false;
    70     private boolean ignore_item_change = false;
     57    implements TreeSelectionListener {
     58    private boolean ignore_tree_selection_event = false;
     59    private boolean manual_text_edit_event;
     60    private JPanel center_pane;
    7161    private CardLayout card_layout;
    72     private DefaultListModel list_model;
    7362    /** The metadata element that is currently selected. */
    7463    private ElementWrapper selected_metadata_element = null;
    75     //private GComboBox elements;
    76     private MetadataComboBoxModel em;
    7764    private GValueModel vm;
    78     private Hashtable previous_values = new Hashtable();
    79     private JButton add;
    80     /** This button creates an editor dialog to allow for an expanded area to type in text. */
    81     private JButton expand = null;
    82     private JButton remove;
    83     private JButton restore;
    84     private JButton search;
    85     private JButton update;
    86     //private JLabel element_label;
    87     private JLabel value_label;
    88     private JList list;
    89     private JPanel auto_pane;
    90     private JPanel button_pane;
    91     private JPanel center_pane;
    92     //private JPanel list_pane;
    93     private JPanel north_pane;
    94     //private JPanel south_pane;
    95     private JPanel tree_pane;
    96     private JPanel value_pane;
    9765    private JTextArea auto_message;
    9866    private JTextField value;
     
    10068    private MetaEditPane metaedit;
    10169    private String args[] = new String[1];
    102     private TreePath previous;
    103     private ValueListener value_listener;
    10470    /** Stock standard size for labels. */
    10571    static final private Dimension LABEL_SIZE = new Dimension(132, 26);
    10672
    107     //static final private String LIST = "List";
    10873    static final private String NONE = "None";
    10974    static final private String TREE = "Tree";
    11075
    11176
    112     public GValueTree(MetaEditPane metaedit, int width, int height, JButton add, JButton update, JButton remove) {
    113     this(metaedit, new Dimension(width, height), add, update, remove);
    114     }
    115 
    116     public GValueTree(MetaEditPane metaedit, Dimension size, JButton add, JButton update, JButton remove) {
     77    public GValueTree(MetaEditPane metaedit, int width, int height, JButton add, JButton update, JButton remove, JButton expand) {
    11778    super();
    11879
    119     this.add = add;
    12080    this.metaedit = metaedit;
    121     this.remove = remove;
    122     this.update = update;
    123 
    124     ///ystem.err.println("Created new ValueListener!");
    125     value_listener = new ValueListener();
    126 
    127     int height = size.height;
    128     int width = size.width;
    12981
    13082    setFont(Gatherer.config.getFont("general.font", false));
    131     //setSize(size);
     83
     84    Dimension size = new Dimension(width, height);
    13285    setPreferredSize(size);
    13386
    134     //north_pane = new JPanel();
    135 
    136     //element_label = new JLabel(get("Element"));
    137     //element_label.setPreferredSize(LABEL_SIZE);
    138 
    139     //elements = new GComboBox();
    140     //elements.addItemListener(this);
    141     //elements.setEditable(false);
    142     //elements.setMaximumRowCount(5);
    143     //elements.setPreferredSize(new Dimension(413, 24));
    144 
    14587    center_pane = new JPanel();
    14688
    14789    card_layout = new CardLayout();
    14890
    149     auto_pane = new JPanel();
     91    JPanel auto_pane = new JPanel();
    15092    args[0] = "Title";
    15193    auto_message = new SmarterTextArea(get("AutoMessage", args), false);
     
    15496    auto_message.setWrapStyleWord(true);
    15597
    156     tree_pane = new JPanel();
     98    JPanel tree_pane = new JPanel();
    15799
    158100    JLabel tree_label = new JLabel(get("Tree"));
     
    163105    tree.setRootVisible(true);
    164106    tree.putClientProperty("JTree.lineStyle", "Angled");
    165     //setTreeEnabled(false);
    166 
    167     //list_pane = new JPanel();
    168     //JLabel list_label = new JLabel(get("List"));
    169     //list_model = new DefaultListModel();
    170     //list = new JList(list_model);
    171     //list.addListSelectionListener(new ListSelectionListenerImpl());
    172107
    173108    JPanel controls_pane = new JPanel();
    174109
    175     value_pane = new JPanel();
    176     value_label = new JLabel(get("Value"));
     110    JPanel value_pane = new JPanel();
     111    JLabel value_label = new JLabel(get("Value"));
    177112    value_label.setPreferredSize(LABEL_SIZE);
    178113    JPanel edit_pane = new JPanel();
    179     expand = new JButton(get("General.Expand"));
    180     expand.setMnemonic(KeyEvent.VK_E);
    181     expand.setPreferredSize(MetaEditPane.BUTTON_SIZE);
    182114
    183115    value = new JTextField();
    184     value.addActionListener(this);
    185116    value.setBackground(Gatherer.config.getColor("coloring.editable", false));
    186     value.addFocusListener(this);
    187     //value.addKeyListener(this);
    188117    value.setPreferredSize(new Dimension(413, 24));
    189 
    190     button_pane = new JPanel();
     118    value.getDocument().addDocumentListener(new DocumentListenerImpl());
     119
     120    JPanel button_pane = new JPanel();
    191121
    192122    JPanel inner_button_pane = new JPanel();
    193123
    194     //restore = new JButton(get("Restore"));
    195     //restore.setEnabled(false);
    196     //restore.setMnemonic(KeyEvent.VK_T);
    197 
    198     //search = new JButton(get("Search"));
    199     //search.setMnemonic(KeyEvent.VK_S);
    200 
    201     // Connection
    202     expand.addActionListener(this);
    203     //restore.addActionListener(this);
    204     //search.addActionListener(this);
    205     value.getDocument().addDocumentListener(new DocumentListenerImpl());
    206 
    207124    // Layout
    208     //element_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
    209     //north_pane.setLayout(new BorderLayout());
    210     //north_pane.add(element_label, BorderLayout.CENTER);
    211     //north_pane.add(elements, BorderLayout.EAST);
    212 
    213125    tree_pane.setLayout(new BorderLayout());
    214126    tree_pane.add(tree_label, BorderLayout.NORTH);
    215127    tree_pane.add(new JScrollPane(tree), BorderLayout.CENTER);
    216128
    217     //list_pane.setLayout(new BorderLayout());
    218     //list_pane.add(list_label, BorderLayout.NORTH);
    219     //list_pane.add(new JScrollPane(list), BorderLayout.CENTER);
    220 
    221129    auto_pane.setBorder(BorderFactory.createEmptyBorder(25,10,25,10));
    222130    auto_pane.setLayout(new BorderLayout());
     
    226134    center_pane.setLayout(card_layout);
    227135    center_pane.add(tree_pane, TREE);
    228     //center_pane.add(list_pane, LIST);
    229136    center_pane.add(auto_pane, NONE);
    230137
     
    251158    controls_pane.setLayout(new BorderLayout());
    252159    controls_pane.add(value_pane, BorderLayout.CENTER);
    253     //controls_pane.add(button_pane, BorderLayout.SOUTH);
    254160
    255161    this.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
     
    257163    this.add(controls_pane, BorderLayout.NORTH);
    258164    this.add(center_pane, BorderLayout.CENTER);
    259     //this.add(south_pane, BorderLayout.SOUTH);
    260     }
    261 
    262     public void actionPerformed(ActionEvent event) {
    263     ignore = true;
    264     if(event.getSource() == value) {
    265         StringTokenizer tokenizer = new StringTokenizer(value.getText(), "\\");
    266         TreePath closest = getClosestPath(tokenizer);
    267         if(closest != null) {
    268         TreePath path = tree.getSelectionPath();
    269         GValueNode node = (GValueNode)path.getLastPathComponent();
    270         ///ystem.err.println("1. Set value: " + node.toString());
    271         value.setText(Utility.stripNL(node.toString()));//formatPath(path, false)));
    272         value.setCaretPosition(0);
    273         // Now systematically add to selected record.
    274         add.doClick();
    275         }
    276         else {
    277         int response = JOptionPane.showConfirmDialog(this, "Do you wish to create a new entry?", "Warning", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
    278         if(response == JOptionPane.YES_OPTION) {
    279             TreePath new_path = addNode(value.getText());
    280             tree.setSelectionPath(new_path);
    281             // tree.scrollPathToVisible(new_path);
    282             scrollTreePathToVisible(new_path);
    283             GValueNode node = (GValueNode)new_path.getLastPathComponent();
    284             ///ystem.err.println("2. Set value: " + node.toString());
    285             value.setText(Utility.stripNL(node.toString()));   
    286             value.setCaretPosition(0);
    287             // Now systematically add to selected record.
    288             add.doClick();
    289         }
    290         }
    291     }
    292     //else if(event.getSource() == search) {
    293     //    searchValues();
    294     //    restore.setEnabled(true);
    295     //    card_layout.show(center_pane, LIST);
    296     //}
    297     //else if(event.getSource() == restore) {
    298     //    restore.setEnabled(false);
    299     //    card_layout.show(center_pane, TREE);
    300     //}
    301     else if(event.getSource() == expand) {
    302         EditorDialog ed = new EditorDialog();
    303         String temp = ed.display(value.getText());
    304         if(temp != null) {
    305         ///ystem.err.println("3. Set value: " + temp);
    306         value.setText(temp);
    307         value.setCaretPosition(0);
    308         }
    309         //validateControls();
    310     }
    311     ignore = false;
    312     }
    313     /** Called whenever an element within the metadata set module changes in some way.
    314       * @param event A <strong>MSMEvent</strong> which contains information about the change.
    315       */
    316     public void elementChanged(MSMEvent event) {
    317     /* @TODO - Not sure. Figure out. */
    318     }
    319     public void focusGained(FocusEvent event) {
    320 
    321     }
    322 
    323     public void focusLost(FocusEvent event) {
    324 
    325     }
    326 
    327     public boolean getCommon() {
    328     return common;
    329     }
     165    }
     166
     167
     168    public GValueModel getModel() {
     169    return (GValueModel) tree.getModel();
     170    }
     171
    330172
    331173    public ElementWrapper getSelectedMetadataElement() {
     
    333175    }
    334176
     177
    335178    public String getSelectedValue() {
    336     String value_text = value.getText();
    337     previous_values.put(selected_metadata_element, value_text);
    338     return value_text;
    339     }
    340 
    341     public GValueModel getValueModel() {
    342     return (GValueModel) tree.getModel();
    343     }
    344 
    345     /** This method is required for any ItemListener so that it can be informed when the state of an item set changes (such as when a new selection is made in a combobox). Note that this update is subtly different from the validateControls() method as it also gathers new models for each combobox as required. The reason this isn't done as part of validateControls() is that this would continously reset whatever the user is attempting to type (ie value would be found to be enabled and a new model would be loaded erasing whatever the user just typed in value to fire the validateControls() in the first place!)
    346       * @param event An ItemEvent encapsulating all the information about this event.
    347       */
    348      /*
    349     public void itemStateChanged(ItemEvent event) {
    350           ///ystem.err.println("Item State Changed");
    351           if(!ignore_item_change) {
    352                 ignore_item_change = true;
    353                 selected_metadata_element = (ElementWrapper)em.getSelectedItem();
    354                 if(selected_metadata_element != null) {
    355                      //elements.setToolTipText(selected_metadata_element.getToolTip());
    356                      vm = null;
    357                      vm = Gatherer.c_man.getCollection().msm.getValueTree(selected_metadata_element);
    358                      if(vm != null) {
    359                           ///ystem.err.println("Assigning value model.");
    360                           vm.addTreeModelListener(value_listener);
    361                           tree.addTreeSelectionListener(this);
    362                           setTreeEnabled(true);
    363                      }
    364                      else {
    365                           ///ystem.err.println("Creating new model.");
    366                           vm = new GValueModel(get("Not_Applicable"));
    367                           setTreeEnabled(false);
    368                      }
    369                      tree.setModel(vm);
    370                 }
    371                 else {
    372                      setTreeEnabled(false);
    373                 }
    374                 value.setText("");
    375                 metaedit.validateControls(false);
    376           }
    377           previous = null;
    378           ignore_item_change = false;
    379           validateControls();
    380     }
    381      */
    382 
    383      /** Called whenever a metadata value is changed.
    384       * @param event A <strong>MSMEvent</strong> which encapsulates relevant data about the change.
    385       */
    386     public void metadataChanged(MSMEvent event) {
    387     // Don't care.
    388     }
    389      
    390     public void newMetadataSetManager() {
    391     if(Gatherer.c_man != null && Gatherer.c_man.getCollection() != null && Gatherer.c_man.getCollection().msm != null) {
    392         Gatherer.c_man.getCollection().msm.addMSMListener(this);
    393     }
    394     setChanged(null);
    395     }
    396 
    397     public void refreshValueTree() {
    398     if(em != null && em.getSize() > 0) {
    399         setSelectedMetadataElement((ElementWrapper)em.getSelectedItem());
    400     }
    401     }
    402    
    403     public void registerModel(GValueModel model) {
    404     vm = model;
    405     vm.addTreeModelListener(value_listener);
    406     tree.setModel(model);
    407     tree.addTreeSelectionListener(this);
    408     }
    409     /** Called whenever a set within the metadata set module changes in some way.
    410       * @param event A <strong>MSMEvent</strong> which contains information about the change.
    411       */
    412     public void setChanged(MSMEvent event) {
    413     // Update the element model.
    414     MetadataComboBoxModel model = Gatherer.c_man.getCollection().msm.getElementModel();
    415     if(model.getSize() > 0) {
    416         setElementModel(model);
    417         model.setSelectedItem(model.getElementAt(0));
    418         vm = Gatherer.c_man.getCollection().msm.getValueTree((ElementWrapper)model.getSelectedItem());
    419         setTreeEnabled(true);
    420         if(vm == null) {
    421         vm = new GValueModel(get("Not_Applicable"));
    422         setTreeEnabled(false);
    423         }
    424     }
    425     else {
    426         vm = new GValueModel();
    427         setTreeEnabled(true);
    428     }
    429     vm.addTreeModelListener(value_listener);
    430     tree.setModel(vm);
    431     tree.addTreeSelectionListener(this);
    432     }
    433 
    434     public void setCommon(boolean common) {
    435     this.common = common;
    436     }
    437 
    438     public void setElementModel(MetadataComboBoxModel model) {
    439     ///ystem.err.println("Reset ElementModel.");
    440     setTreeEnabled(true);
    441     Gatherer.c_man.getCollection().msm.addMSMListener(this);
    442     if(model == null) {
    443         Gatherer.println("model = null");
    444         System.exit(0);
    445     }
    446     ignore_item_change = true;
    447     em = model;
    448     //elements.setModel(em);
    449     if(em.getSize() > 0) {
    450                 ///ystem.err.println("em.size() > 0");
    451                 //elements.setEnabled(true);
    452                 //elements.setSelectedIndex(0);
    453         selected_metadata_element = (ElementWrapper)em.getSelectedItem();
    454                 //elements.setToolTipText(selected_metadata_element.getToolTip());
    455                 // First we create and install a blank model, or else no updates ever work.
    456         vm = new GValueModel(get("Not_Applicable"));
    457         tree.setModel(vm);
    458                 // Now we create a new model if applicable, disabling otherwise.
    459         if(selected_metadata_element.getNamespace().length() > 0) {
    460         vm = Gatherer.c_man.getCollection().msm.getValueTree(selected_metadata_element);
    461         vm.addTreeModelListener(value_listener);
    462         ///ystem.err.println("Found existing model containing " + vm.size() + " entries");
    463         setTreeEnabled(true);
    464         tree.setModel(vm); // This doesn't seem to work
    465         }
    466         else {
    467         ///ystem.err.println("Creating new model.");
    468         setTreeEnabled(false);
    469         }
    470                 ///ystem.err.println("The value tree should have been updated by now.");
    471                 ///ystem.err.println("6. Set value: " + getLastValue());
    472         value.setText(Utility.stripNL(getLastValue()));
    473         value.setCaretPosition(0);
    474     }
    475     else {
    476                 ///ystem.err.println("No elements loaded.");
    477                 //elements.setEnabled(false);
    478                 //elements.setToolTipText(get("No_Description"));
    479                 //setTreeEnabled(false);
    480         value.setText("");
    481     }
    482     previous = null;
    483     ignore_item_change = false;
    484     validateControls();
    485     }
    486 
    487     public void setFileLevel(boolean file_level) {
    488     this.file_level = file_level;
    489     }
     179    return value.getText();
     180    }
     181
    490182
    491183    public void setRootVisible(boolean val) {
     
    493185    }
    494186
    495     public void setSelectedMetadataElement(ElementWrapper element) {
    496     if(!ignore_item_change) {
    497         ignore_item_change = true;
    498         if(element != null) {
    499         selected_metadata_element = element;
    500         //elements.setSelectedItem(element);
    501         //elements.setToolTipText(element.getToolTip());
    502         vm = Gatherer.c_man.getCollection().msm.getValueTree(element);
    503         if(vm != null) {
    504             vm.addTreeModelListener(value_listener);
    505             setTreeEnabled(true);
     187
     188    public void setSelectedMetadataElement(ElementWrapper element)
     189    {
     190    // System.err.println("Setting selected metadata element to: " + element);
     191    if (element == null) {
     192        selected_metadata_element = null;
     193        setTreeEnabled(false);
     194        return;
     195    }
     196
     197    // Don't bother if the element selected is the same as the current one
     198    if (selected_metadata_element != null && element.equals(selected_metadata_element)) {
     199        return;
     200    }
     201
     202    if (vm != null) {
     203        // Close any expanded paths in the tree
     204        GValueNode root_node = (GValueNode) vm.getRoot();
     205        for (int i = 0; i < root_node.getChildCount(); i++) {
     206        GValueNode child_node = (GValueNode) root_node.getChildAt(i);
     207        TreePath child_path = new TreePath(child_node.getPath());
     208        if (tree.isExpanded(child_path)) {
     209            tree.collapsePath(child_path);
    506210        }
    507         else {
    508             vm = new GValueModel(get("Not_Applicable"));
    509             setTreeEnabled(false);
    510         }
    511         tree.setModel(vm);
    512         ///ystem.err.println("7. Set value: " + getLastValue());
    513         //value.setText(Utility.stripNL(getLastValue()));
    514         //value.setCaretPosition(0);
    515         }
    516         else {
    517         //elements.setToolTipText(get("No_Description"));
    518         setTreeEnabled(false);
    519         //value.setText("");
    520         }
    521         metaedit.validateControls(false);
    522     }
    523     previous = null;
    524     ignore_item_change = false;
    525     //validateControls();
    526     }
    527 
    528     public void setSelectedValue(String val) {
    529     ignore = true;
     211        }
     212    }
     213
     214    // Load the model for the newly selected metadata element
     215    selected_metadata_element = element;
     216    vm = Gatherer.c_man.getCollection().msm.getValueTree(element);
     217    setTreeEnabled(true);
     218    tree.setModel(vm);
     219    }
     220
     221
     222    /** Handles TreeSelectionEvents. */
     223    public void valueChanged(TreeSelectionEvent event)
     224    {
     225    if(tree.getSelectionCount() != 0 && !ignore_tree_selection_event) {
     226        TreePath path = tree.getSelectionPath();
     227        GValueNode node = (GValueNode) path.getLastPathComponent();
     228        setSelectedValue(node.getFullPath());
     229    }
     230    }
     231
     232
     233    /** Sets the value in the text field. */
     234    public void setSelectedValue(String val)
     235    {
     236    // Setting the text of the field causes the DocumentListener to be notified, and
     237    //   updating the tree is handled there (DocumentListenerImpl::validate())
     238    // System.err.println("Setting selected value to: " + val);
     239    manual_text_edit_event = val.equals("");  // Set to false unless val == ""
    530240    value.setText(Utility.stripNL(val));
    531241    value.setCaretPosition(0);
    532     StringTokenizer tokenizer = new StringTokenizer(val, "\\");
    533     TreePath closest = getClosestPath(tokenizer);
    534     if(previous != null) {
    535         tree.collapsePath(getParent(previous));
    536         previous = null;
    537     }
    538     if(closest != null) {
    539         tree.setSelectionPath(closest);
    540                 // tree.scrollPathToVisible(closest);
    541         scrollTreePathToVisible(closest);
    542     }
    543     ignore = false;
    544     //validateControls();
    545     }
    546 
    547     /** This method enables or diables the various controls based upon the
    548       * state of the system. This method should be called after every change
    549       * which could affect the GUI. <br>
    550       * Hack #1: For some reason this gets called 14 times for one selection. One day I'll figure out why, but for now I'll just ignore all but every fourteenth call.
    551       */
    552     public void validateControls() {
    553     Metadata selected_metadata = metaedit.getSelectedMetadata();
    554     if(metaedit.getSelectedNode() != null && selected_metadata != null) {
    555         ElementWrapper element = selected_metadata.getElement();
    556         if(element.getNamespace() != "") {
    557         GValueNode value_node = selected_metadata.getValueNode();
    558         ///ystem.err.println("Value node = " + value_node);
    559         // We may be dealing with an element that has no current value
    560         if(value_node == null) {
    561             String new_value = value.getText();
    562             if(new_value.length() > 0) {
    563             add.setEnabled(true);
    564             }
    565             else {
    566             add.setEnabled(false);
    567             }
    568             // Nothing to update
    569             update.setEnabled(false);
    570             // Nothing to remove
    571             remove.setEnabled(false);
    572         }
    573         // Or else we have some current value that may or may not match the one in our value field.
    574         else {
    575             String current_value = selected_metadata.getValueNode().getFullPath();
    576             String new_value = value.getText();
    577             ///ystem.err.println("Current value: '" + current_value + "'");
    578             ///ystem.err.println("New value:     '" + new_value + "'");
    579             if(new_value.length() > 0 && !current_value.equals(new_value)) {
    580             add.setEnabled(true);
    581             if(common) {
    582                 update.setEnabled(true);
    583             }
    584             else {
    585                 update.setEnabled(false);
    586             }
    587             }
    588             else {
    589             add.setEnabled(false);
    590             update.setEnabled(false);
    591             }
    592             // If you have something selected, and we're at the file level, you can remove it.
    593             if(file_level) {
    594             remove.setEnabled(true);
    595             }
    596             else {
    597             remove.setEnabled(false);
    598             }
    599         }
    600         }
    601         else {
    602         add.setEnabled(false);
    603         update.setEnabled(false);
    604         remove.setEnabled(false);
    605         }           
    606     }
    607     else {
    608         add.setEnabled(false);
    609         update.setEnabled(false);
    610         remove.setEnabled(false);
    611     }
    612     }
    613 
    614     /** Called when the value tree of a certain element has changed significantly. If we are displaying the tree for the element noted in the event, then reload the value model.
    615       * @param event A <strong>MSMEvent</strong> containing information about the event.
    616       */
    617     public void valueChanged(MSMEvent event) {
    618     ElementWrapper element = event.getElement();
    619     if(selected_metadata_element.equals(element)) {
    620         GValueModel temp = Gatherer.c_man.getCollection().msm.getValueTree(element);
    621         if(temp != null) {
    622         vm = temp;
    623         tree.setModel(vm);
    624         vm.removeTreeModelListener(value_listener);
    625         vm.addTreeModelListener(value_listener);
    626         setTreeEnabled(true);
    627         setSelectedValue(value.getText());
    628         }
    629         else {
    630         vm = new GValueModel(get("Not_Applicable"));
    631         tree.setModel(vm);
    632         setTreeEnabled(false);
    633         }
    634     }
    635     }
    636 
    637     public void valueChanged(TreeSelectionEvent event) {
    638     if(tree.getSelectionCount() != 0 && !ignore) {
    639         TreePath path = tree.getSelectionPath();
    640         GValueNode node = (GValueNode) path.getLastPathComponent();
    641         value.setText(node.getFullPath());//formatPath(tree.getSelectionPath(), false)));
    642         value.setCaretPosition(0);
    643         validateControls();
    644     }
    645     }
    646    
    647     private TreePath addNode(String reference) {
    648     StringTokenizer tokenizer = new StringTokenizer(reference, "\\");
    649     GValueModel model = (GValueModel)tree.getModel();
    650     GValueNode current = (GValueNode)model.getRoot();
    651     while(tokenizer.hasMoreElements()) {
    652         String token = tokenizer.nextToken();
    653         GValueNode node = (GValueNode)getClosestNode(token, current);
    654         if(node == null) {
    655         Gatherer.println("Before: '" + current.toString() + "'");
    656         for(int i = 0; i < current.getChildCount(); i++) {
    657             Gatherer.println(current.getChildAt(i).toString());
    658         }
    659         node = model.addValue(token, current, null);
    660         Gatherer.println("After: '" + current.toString() + "'");
    661         for(int i = 0; i < current.getChildCount(); i++) {
    662             Gatherer.println(current.getChildAt(i).toString());
    663         }
    664         }
    665         current = node;
    666     }
    667     tree.updateUI();
    668     if(current != null) {
    669         return new TreePath(current.getPath());
    670     }
    671     else {
    672         return new TreePath(((GValueNode)model.getRoot()).getPath());
    673     }
    674     }
    675     /** Returns the given tree path as path formatted string (ie subject\subject\subject).
    676       * @param tree The <strong>JTree</strong> the TreePath came from. Used to determine if the root node should be encoded as well.
    677       * @param path A <strong>TreePath</strong> that you wish to encode to String.
    678       * @param full <i>true</i> if this is the full path (ie a leaf node), <i>false</i> otherwise.
    679       * @return A <strong>String</strong> encoding the information from the TreePath.
    680       * @see javax.swing.JTree
    681       * @see javax.swing.tree.TreePath
    682       */
    683     static public String formatPath(JTree tree, TreePath path, boolean full) {
    684     String text = "";
    685     int i = 0;
    686     if(tree == null || (!tree.isRootVisible() && !full)) {
    687         i = 1;
    688     }
    689     for( ; i < path.getPathCount(); i++) {
    690         GValueNode node = (GValueNode)path.getPathComponent(i);
    691         text = text + node.toString();
    692         if(node.getChildCount() > 0) {
    693         text = text + "\\";
    694         }
    695     }
    696     if(full && text.endsWith("\\")) {
    697         return text.substring(0, text.length() - 1);
    698     }
    699     return text;
    700     }
     242    manual_text_edit_event = true;
     243    }
     244
    701245
    702246    private String get(String key) {
     
    711255    }
    712256
    713     private GValueNode getClosestNode(String target, GValueNode current) {
    714     // We have struck it lucky.
    715     if(startsWith(current.toString(), target)) {
    716         return current;
    717     }
    718     GValueNode closest = null;
    719     for(int i = 0; i < current.getChildCount() && closest == null; i++) {
    720         closest = getClosestNode(target, (GValueNode)current.getChildAt(i));
    721     }
    722     return closest;
    723     }
    724 
    725     private TreePath getClosestPath(StringTokenizer tokenizer) {
    726     if(tokenizer.countTokens() > 0) {
    727         TreeNode tree_node = (TreeNode)tree.getModel().getRoot();
    728         if(tree_node instanceof GValueNode) {
    729         GValueNode current = (GValueNode)tree_node;
    730         TreePath closest = null;
    731         while(tokenizer.hasMoreElements() && current != null) {
    732             current = getClosestNode(tokenizer.nextToken(), current);
    733         }
    734         if(current != null) {
    735             return new TreePath(current.getPath());
    736         }
    737         return null;
    738         }
    739     }
    740     return null;
    741     }
    742 
    743     private String getLastValue() {
    744     if(previous_values.containsKey(selected_metadata_element)) {
    745         return (String)previous_values.get(selected_metadata_element);
    746     }
    747     return "";
    748     }
    749 
    750     private TreePath getParent(TreePath path) {
    751     if(path.getPathCount() > 1) {
    752         TreeNode nodes[] = new TreeNode[path.getPathCount() - 1];
    753         for(int i = 0; i < path.getPathCount() - 1; i++) {
    754         nodes[i] = (TreeNode)path.getPathComponent(i);
    755         }
    756         return new TreePath(nodes);
    757     }
    758     return null;
    759     }
    760 
    761     private void searchValues() {
    762     // Clear any old search results.
    763     list_model.clear();
    764     String target = value.getText();
    765     GValueNode current = (GValueNode)tree.getModel().getRoot();
    766     Vector search_space = new Vector();
    767     search_space.add(current);
    768     for(int i = 0; i < search_space.size(); i++) {
    769         GValueNode node = (GValueNode)search_space.get(i);
    770         // Add this nodes children.
    771         for(int j = 0; j < node.getChildCount(); j++) {
    772         search_space.add(node.getChildAt(j));
    773         }
    774         // And if this node matches add it to list, except for the very
    775         // first node as that is AssignedValues the root node!
    776         if(node.toString().indexOf(target) != -1 &&
    777            node != current) {
    778         list_model.add(list_model.size(), node);
    779         }
    780     }
    781     }
    782257
    783258    private void setTreeEnabled(boolean value) {
     
    800275    }
    801276
    802     private boolean startsWith(String longer, String shorter) {
    803     if(longer.length() > shorter.length()) {
    804         longer = longer.substring(0, shorter.length());
    805     }
    806     return longer.equalsIgnoreCase(shorter);
    807     }
    808 
    809     private void printTreePaths() {
    810     ///ystem.out.println("Tree Paths according to getPath() method.");
    811     Vector nodes = new Vector();
    812     nodes.add(tree.getModel().getRoot());
    813     while(nodes.size() > 0) {
    814         GValueNode node = (GValueNode)nodes.get(0);
    815         nodes.remove(node);
    816         for(int i = 0; i < node.getChildCount(); i++) {
    817         nodes.add(node.getChildAt(i));
    818         }
    819                 ///ystem.out.println("TreePath = " + node.getPath());
    820     }
    821     }
     277
     278    /** Returns a TreePath for the node most closely matching the metadata value. */
     279    private TreePath getClosestPath(String val)
     280    {
     281    // Start at the root of the tree
     282    GValueNode tree_node = (GValueNode) tree.getModel().getRoot();
     283
     284    // Hierarchical values are separated using '\'
     285    StringTokenizer tokenizer = new StringTokenizer(val, "\\");
     286    while (tokenizer.hasMoreTokens()) {
     287        String token = tokenizer.nextToken();
     288
     289        // All components except the last must match exactly
     290        if (tokenizer.hasMoreTokens()) {
     291        for (int i = 0; i < tree_node.getChildCount(); i++) {
     292            GValueNode child_node = (GValueNode) tree_node.getChildAt(i);
     293            if (child_node.toString().equals(token)) {
     294            // The matching node has been found, so move onto the next token
     295            tree_node = child_node;
     296            break;
     297            }
     298        }
     299        }
     300
     301        // The last component may match partially
     302        else {
     303        for (int i = 0; i < tree_node.getChildCount(); i++) {
     304            GValueNode child_node = (GValueNode) tree_node.getChildAt(i);
     305            if (child_node.toString().startsWith(token)) {
     306            // The closest node has been found, so return its path
     307            return new TreePath(child_node.getPath());
     308            }
     309        }
     310
     311        // Not even a partial match
     312        return null;
     313        }
     314    }
     315
     316    // If nothing else, return the path of the root node
     317    return new TreePath(tree_node.getPath());
     318    }
     319
    822320
    823321    /** This function is copied from JTree::setPathToVisible(), and modified so tree rows
    824     are always shown flushed left. */
    825     public void scrollTreePathToVisible(TreePath path) {
     322    are always shown flushed left. Note: doesn't do accessibleContext stuff. */
     323    private void scrollTreePathToVisible(TreePath path)
     324    {
    826325    if (path != null) {
    827326        tree.makeVisible(path);
    828327
    829328        Rectangle bounds = tree.getPathBounds(path);
    830 
    831329        if (bounds != null) {
    832330        bounds.width += bounds.x;
    833331        bounds.x = 0;
    834332        tree.scrollRectToVisible(bounds);
    835         // if (tree.getAccessibleContext() != null) {
    836         //     ((AccessibleJTree) tree.getAccessibleContext()).fireVisibleDataPropertyChange();
    837         // }
    838         }
    839     }
    840     }
     333        }
     334    }
     335    }
     336
    841337
    842338    private class DocumentListenerImpl
     
    846342        validate();
    847343    }
    848          
     344
    849345    /** Gives notification that there was an insert into the document. */
    850346    public void insertUpdate(DocumentEvent e) {
    851347        validate();
    852348    }
    853          
     349
    854350    /** Gives notification that a portion of the document has been removed. */
    855351    public void removeUpdate(DocumentEvent e) {
     
    857353    }
    858354
    859     public void validate() {
    860         ignore = true;
    861                 ///ystem.err.println("Key released.");
    862         StringTokenizer tokenizer = new StringTokenizer(value.getText(), "\\");
    863         TreePath closest = getClosestPath(tokenizer);
    864         if(closest == previous) {
    865         validateControls();
    866         ignore = false;
    867         return;
    868         }
    869         else {
    870         // Clear previous
    871         if(previous != null) {
    872             // We have a brand new match close up the old one.
    873             if(closest != null) {
    874             if(getParent(previous) != null &&
    875                !getParent(previous).toString().equals("[AssignedValues]")) {
    876                 tree.collapsePath(getParent(previous));
    877             }
    878             previous = null;
    879             }
    880             // We haven't got a match, but we did have a matching path to
    881             // this point. Move the selection to previous paths parent.
    882             else {
    883             tree.setSelectionPath(getParent(previous));
    884             }
     355
     356    /** Ensures that the value text field and value tree are synchronized. */
     357    private void validate()
     358    {
     359        String value_text = value.getText();
     360        // System.err.println("\n(Validate) Value text: " + value_text);
     361
     362        // Ignore the validate() with empty text that occurs when value.setText() is used
     363        if (!value_text.equals("") || manual_text_edit_event == true) {
     364        TreePath closest_path = getClosestPath(value_text);
     365
     366        // Select the new path in the tree
     367        // The tree selection event this causes must be ignored, since it alters value
     368        ignore_tree_selection_event = true;
     369        tree.setSelectionPath(closest_path);
     370        ignore_tree_selection_event = false;
     371
     372        // If a folder has been specified, make sure it is expanded
     373        if (value_text.endsWith("\\") && !tree.isExpanded(closest_path)) {
     374            tree.expandPath(closest_path);
    885375        }
    886                      
    887         if(closest != null) {
    888             tree.setSelectionPath(closest);
    889             // tree.scrollPathToVisible(closest);
    890             scrollTreePathToVisible(closest);
    891             previous = closest;
    892         }
    893         }
    894         ignore = false;
    895         validateControls();
    896     }
    897     }
    898 
    899     private class ListSelectionListenerImpl
    900     implements ListSelectionListener {
    901     public void valueChanged(ListSelectionEvent event) {
    902         GValueNode node = (GValueNode)list.getSelectedValue();
    903         value.setText(Utility.stripNL(node.toString()));//formatPath(node.getPath(), false)));
    904         value.setCaretPosition(0);
    905     }
    906     }
    907 
    908     private class ValueListener
    909     implements TreeModelListener {
    910     /* Called when nodes have been modified, but the model hasn't changed.
    911      * @param event Everything you ever wanted to know about model changes
    912      * in one tidy TreeModelEvent package.
    913             */
    914     public void treeNodesChanged(TreeModelEvent event) {
    915         update();
    916     }
    917          
    918     /* Called when nodes have been added to the model.
    919             * @param event Everything you ever wanted to know about model changes
    920             * in one tidy TreeModelEvent package.
    921             */
    922     public void treeNodesInserted(TreeModelEvent event) {
    923         update();
    924     }
    925          
    926     /* Called when nodes have been removed from the model.
    927             * @param event Everything you ever wanted to know about model changes
    928             * in one tidy TreeModelEvent package.
    929             */
    930     public void treeNodesRemoved(TreeModelEvent event) {
    931         update();
    932     }
    933          
    934     /** Called when nodes have been rearranged within the model.
    935             * @param event Everything you ever wanted to know about model changes
    936             * in one tidy TreeModelEvent package.
    937             */
    938     public void treeStructureChanged(TreeModelEvent event) {
    939         update();
    940     }
    941          
    942     private void update() {
    943                 // Don't bother updating if the metaedit tab isn't selected.
    944         if(Gatherer.g_man.getSelectedView() == Gatherer.g_man.metaedit_pane) {
    945         vm = null;
    946         vm = Gatherer.c_man.getCollection().msm.getValueTree((ElementWrapper)em.getSelectedItem());
    947         if(vm != null) {
    948             vm.addTreeModelListener(value_listener);
    949         }
    950         else {
    951             vm = new GValueModel(get("Not_Applicable"));
    952         }
    953         tree.setModel(vm);
    954         tree.repaint();
     376
     377        // Make sure the path is visible on the screen
     378        scrollTreePathToVisible(closest_path);
     379        // One call should be enough, but it isn't in some cases (for some reason)
     380        scrollTreePathToVisible(closest_path);
     381
     382        // Update the status of the buttons
     383        metaedit.validateControls();
    955384        }
    956385    }
Note: See TracChangeset for help on using the changeset viewer.