source: trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionManager.java@ 4675

Last change on this file since 4675 was 4675, checked in by jmt12, 21 years ago

Sunday's work

  • Property svn:keywords set to Author Date Id Revision
File size: 42.3 KB
Line 
1/**
2 *#########################################################################
3 *
4 * A component of the Gatherer application, part of the Greenstone digital
5 * library suite from the New Zealand Digital Library Project at the
6 * University of Waikato, New Zealand.
7 *
8 * <BR><BR>
9 *
10 * Author: John Thompson, Greenstone Digital Library, University of Waikato
11 *
12 * <BR><BR>
13 *
14 * Copyright (C) 1999 New Zealand Digital Library Project
15 *
16 * <BR><BR>
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * <BR><BR>
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * <BR><BR>
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *########################################################################
36 */
37
38
39
40
41
42
43package org.greenstone.gatherer.cdm;
44/**************************************************************************************
45 * Title: Gatherer
46 * Description: The Gatherer: a tool for gathering and enriching a digital collection.
47 * Copyright: Copyright (c) 2001
48 * Company: The University of Waikato
49 * Written: 02/05/02
50 * Revised: 17/11/02 - Commented
51 **************************************************************************************/
52import java.awt.*;
53import java.awt.event.*;
54import java.util.*;
55import javax.swing.*;
56import javax.swing.event.*;
57import org.greenstone.gatherer.Gatherer;
58import org.greenstone.gatherer.cdm.Subcollection;
59import org.greenstone.gatherer.cdm.SubIndex;
60import org.greenstone.gatherer.cdm.SubIndexes;
61import org.greenstone.gatherer.msm.ElementWrapper;
62import org.greenstone.gatherer.util.ExclusiveListSelectionListener;
63import org.w3c.dom.Element;
64/** This class maintains a list of subcollections within our collection, and also records which of these subcollections we are building indexes for.
65 * @author John Thompson, Greenstone Digital Library, University of Waikato
66 * @version 2.1
67 */
68public class SubcollectionManager
69 extends DefaultListModel {
70 /** A reference to the manager so we can get access to languages. */
71 private CollectionDesignManager manager;
72 /** The controls used to edit the settings of this manager. */
73 private Control controls = null;
74 /** A reference to this class so we can use it as a model in our inner classes. */
75 private DefaultListModel model = null;
76 /** The default index for the subcollections. */
77 private DefaultSubIndex default_index = null;
78 /** A reference to the Gatherer. */
79 private Gatherer gatherer = null;
80 /** A hashtable of subcollections, with mappings from name to subcollection. */
81 private Hashtable subcollections = null;
82 /** A vector-type structure of subcollection indexes. */
83 private SubIndexes subindexes = null;
84 /** A vector containing all of the subcollection commands that are unresolved, or in other words require that all 'subcollection <name> "<exp>"' to have been previously parsed before we can be certain their references will make sense. */
85 private ArrayList unresolved = null;
86 /** Constructor.
87 * @param gatherer A reference to the <Strong>Gatherer</strong>.
88 * @see org.greenstone.gatherer.cdm.SubIndexes
89 */
90 public SubcollectionManager(Gatherer gatherer, CollectionDesignManager manager) {
91 super();
92 this.gatherer = gatherer;
93 this.manager = manager;
94 this.model = this;
95 this.subcollections = new Hashtable();
96 this.subindexes = new SubIndexes();
97 this.unresolved = new ArrayList();
98 }
99 /** Method to add a subindex.
100 * @param subindex A <strong>SubIndex</strong>.
101 * @see org.greenstone.gatherer.Gatherer
102 * @see org.greenstone.gatherer.collection.CollectionManager
103 */
104 public void addSubIndex(SubIndex subindex) {
105 if(!subindexes.contains(subindex)) {
106 subindexes.addElement(subindex);
107 gatherer.c_man.configurationChanged();
108 }
109 }
110 /** Method to add a new subcollection. Adds it to both the underlying list model and the hashtable mapping names to subcollections.
111 * @param sub The <strong>Subcollection</strong> to add.
112 * @return A <i>boolean</i> indicating if the addition was successful (<i>true</i>) or not (<i>false</i>).
113 * @see org.greenstone.gatherer.Gatherer
114 * @see org.greenstone.gatherer.collection.CollectionManager
115 */
116 public boolean addSubcollection(Subcollection sub) {
117 if(!contains(sub)) {
118 addElement(sub);
119 subcollections.put(sub.getName(), sub);
120 gatherer.c_man.configurationChanged();
121 return true;
122 }
123 return false;
124 }
125 /** A method to add a new subcollection, by specifying its name, metadata element if applicable and Perl expression to filter pages into or out of this collection.
126 * @param name A <>>String</>> which is a unique identifier of a subcollection.
127 * @param include A <i>boolean</i> indicating whether this is an inclusion filter (<i>true</i>) or an exclusion one (<i>false</i>).
128 * @param element An <>>Element</>> which is either the metadata whose value should be matched against the given expression, or <i>null</i> if you wish to match against the file name.
129 * @param exp A <>>String</>> containing a Perl expression which is used as the filter for this subcollection.
130 * @param flags A <strong>String<strong> listing any special flags to be applied when matching the expression.
131 * @return A <i>boolean</i> with a value of <i>true</i> if the addition was successful.
132 * @see org.greenstone.gatherer.cdm.Subcollection
133 */
134 public boolean addSubcollection(String name, boolean include, String element, String exp, String flags) {
135 Subcollection sub = null;
136 if(element != null) {
137 sub = new Subcollection(name, include, element, exp, flags);
138 }
139 else {
140 sub = new Subcollection(name, include, exp, flags);
141 }
142 return addSubcollection(sub);
143 }
144 /** Refresh all derived components using this manager as a model.
145 */
146 public void changed() {
147 fireContentsChanged(this, 0, getSize() - 1);
148 }
149 /** Method to retrieve the controls for this manager.
150 * @return A <Strong>Control</strong> object which contains the controls used to edit the subcollection data.
151 */
152 public Control getControls() {
153 if(controls == null) {
154 controls = new Control();
155 }
156 return controls;
157 }
158 /** Method to retrieve the default index.
159 * @return A <strong>DefaultSubIndex</strong> object.
160 */
161 public DefaultSubIndex getDefaultSubIndex() {
162 return default_index;
163 }
164 /** Method to retrieve a certain subcollection by its name.
165 * @param name A <strong>String</strong> which is used as the key for finding the matching subcollection.
166 * @return The requested <strong>Subcollection</strong> or <i>null</i> if no such subcollection exists.
167 */
168 public Subcollection getSubcollection(String name) {
169 return (Subcollection) subcollections.get(name);
170 }
171
172 /** Retrieve a certain subindex given its name.
173 * @param name the String representation of a subindex.
174 * @return the SubIndex requested or null if no such subindex.
175 */
176 public SubIndex getSubIndex(String name) {
177 for(int i = 0; i < subindexes.size(); i++) {
178 SubIndex subindex = (SubIndex) subindexes.get(i);
179 if(subindex.toString().equals(name)) {
180 return subindex;
181 }
182 }
183 return null;
184 }
185
186 /** Method to get all of the subindexes set.
187 * @return A <strong>SubIndexes</strong> object containing all the defined indexes.
188 */
189 public SubIndexes getSubIndexes() {
190 return subindexes;
191 }
192 /** Method to get all of the subcollections defined.
193 * @return A <strong>Vector</strong> of subcollections.
194 */
195 public Vector getSubcollections() {
196 Vector subcollections = new Vector();
197 for(int i = 0; i < size(); i++) {
198 subcollections.add(get(i));
199 }
200 return subcollections;
201 }
202 /** Mark the current controls, if any, as invalid and deallocate them. Any further use of the controls will requires them being rebuilt.
203 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control
204 */
205 public void invalidateControls() {
206 if(controls != null) {
207 controls.destroy();
208 controls = null;
209 }
210 }
211 /** This method attempts to parse a subcollection related command from the given command string. If such a string is successfully parsed, it is immediately added to the data within this collection.
212 * @param command The <strong>String</strong> to be parsed.
213 * @param finished This <i>boolean</i> is usually <i>false</i> when called, unless this parse call is being made -after- the entire collection configuration file has been read in in which case it is <i>true</i>.
214 * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
215 * @see org.greenstone.gatherer.cdm.CommandTokenizer
216 * @see org.greenstone.gatherer.cdm.DefaultSubIndex
217 * @see org.greenstone.gatherer.cdm.Subcollection
218 * @see org.greenstone.gatherer.cdm.SubIndex
219 */
220 public boolean parse(String command, boolean finished) {
221 String temp = command.toLowerCase();
222 CommandTokenizer tokenizer = new CommandTokenizer(command);
223 tokenizer.nextToken(); // Throw away head.
224 if(temp.startsWith("subcollection")) {
225 if(tokenizer.countTokens() >= 2) {
226 String name = tokenizer.nextToken();
227 String pattern = tokenizer.nextToken();
228 addSubcollection(new Subcollection(name, pattern));
229 return true;
230 }
231 }
232 else if(temp.startsWith("indexsubcollections")) {
233 // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
234 if(!finished) {
235 unresolved.add(command);
236 }
237 else {
238 while(tokenizer.hasMoreTokens()) {
239 addSubIndex(new SubIndex(tokenizer.nextToken(), this));
240 }
241 }
242 return true;
243 }
244 else if(temp.startsWith("defaultsubcollection")) {
245 // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
246 if(!finished) {
247 unresolved.add(command);
248 }
249 else {
250 if(tokenizer.hasMoreTokens()) {
251 setDefaultSubIndex(new DefaultSubIndex(tokenizer.nextToken(), this));
252 }
253 }
254 return true;
255 }
256 return false;
257 }
258 /** Method to remove a certain subindex.
259 * @param subindex The <strong>SubIndex</strong> you wish to remove.
260 * @see org.greenstone.gatherer.Gatherer
261 * @see org.greenstone.gatherer.collection.CollectionManager
262 */
263 public void removeSubIndex(SubIndex subindex) {
264 subindexes.removeElement(subindex);
265 gatherer.c_man.configurationChanged();
266 }
267 /** Method to remove all of the subindexes that contain a certain subcollection.
268 * @param sub The <strong>Subcollection</strong> that you wish to remove.
269 * @see org.greenstone.gatherer.Gatherer
270 * @see org.greenstone.gatherer.cdm.SubIndex
271 * @see org.greenstone.gatherer.collection.CollectionManager
272 */
273 public void removeSubIndexes(Subcollection sub) {
274 for(int i = subindexes.size() - 1; i >= 0; i--) {
275 SubIndex subindex = (SubIndex)subindexes.get(i);
276 if(subindex.containsSubcollection(sub.getName())) {
277 subindexes.removeElement(subindex);
278 }
279 }
280 gatherer.c_man.configurationChanged();
281 }
282 /** Method to remove the given subcollection.
283 * @param sub The <strong>Subcollection</strong> you want to remove.
284 * @see org.greenstone.gatherer.Gatherer
285 * @see org.greenstone.gatherer.collection.CollectionManager
286 */
287 public void removeSubcollection(Subcollection sub) {
288 removeElement(sub);
289 subcollections.remove(sub);
290 gatherer.c_man.configurationChanged();
291 }
292 /** Method to retry the parsing of commands that were previously unable to be parsed as they referenced subcollections that may not have been instantiated.
293 */
294 public void reparseUnresolved() {
295 for(int i = 0; i < unresolved.size(); i++) {
296 parse((String)unresolved.get(i), true);
297 }
298 unresolved.clear();
299 }
300 /** Method to set the default subcollection index.
301 * @param subcollection The <strong>Subcollection</strong> to use as the default index.
302 * @see org.greenstone.gatherer.Gatherer
303 * @see org.greenstone.gatherer.collection.CollectionManager
304 */
305 public void setDefaultSubIndex(DefaultSubIndex subindex) {
306 this.default_index = subindex;
307 if(subindex != null) {
308 addSubIndex(subindex.getSubIndex());
309 }
310 gatherer.c_man.configurationChanged();
311 }
312 /** This method causes the contents of this manager to be converted to a string, which is accomplished by calling <i>toString()</i> on each subcollection, then printing out the contents of the index vector.
313 * @return A <strong>String</strong> containing a block of configuration commands.
314 * @see org.greenstone.gatherer.cdm.SubIndex
315 * @see org.greenstone.gatherer.cdm.Subcollection
316 */
317 public String toString() {
318 String text = "";
319 // Retrieve the subcollection names and sort them.
320 if(subcollections.size() > 0) {
321 Vector names = new Vector(subcollections.keySet());
322 Collections.sort(names);
323 for(int i = 0; i < names.size(); i++) {
324 Subcollection sub =
325 (Subcollection) subcollections.get(names.get(i));
326 text = text + sub.toString();
327 }
328 // Now add a entry, separated by spaces for each subcollection
329 // index.
330 if(subindexes.size() > 0) {
331 text = text + subindexes.toString();
332 }
333 // Finally add the default subcollection index if necessary.
334 if(default_index != null) {
335 text = text + default_index.toString();
336 }
337 text = text + "\n";
338 }
339 // Otherwise if there were no subcollections, there aren't going to be
340 // subcollection indexes, nor a default subcollection index are there.
341 return text;
342 }
343 /** Method to retrieve a phrase from the dictionary based on a key.
344 * @param key A <strong>String</strong> used to find the correct phrase.
345 * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
346 * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
347 */
348 private String get(String key) {
349 return get(key, null);
350 }
351 /** Method to retrieve a phrase from the dictionary based on a key.
352 * @param key A <strong>String</strong> used to find the correct phrase.
353 * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
354 * @see org.greenstone.gatherer.Dictionary
355 * @see org.greenstone.gatherer.Gatherer
356 */
357 private String get(String key, String args[]) {
358 if(key.indexOf(".") == -1) {
359 key = "CDM.SubcollectionManager." + key;
360 }
361 return gatherer.dictionary.get(key, args);
362 }
363 /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
364 private class Control
365 extends JPanel {
366 /** <i>true</i> if the current selection has changed. */
367 private boolean changed = false;
368 /** Button to add a subcollection. */
369 private JButton add = null;
370 /** Button to add a subindex. */
371 private JButton add_index = null;
372 /** Button to clear the default subindex. */
373 private JButton clear_default = null;
374 /** Button to remove a subcollection. */
375 private JButton remove = null;
376 /** Button to remove a subindex. */
377 private JButton remove_index = null;
378 /** Button to set the default subindex. */
379 private JButton set_default = null;
380 /** Button to cause an update of the subcollections. */
381 private JButton update = null;
382 /** A combobox allowing you to choose which field the data for matching should be taken from. Includes text body and filename, as well as all assigned metadata elements. */
383 private JComboBox source = null;
384 /** The list of assigned subcollections. */
385 private JList subcollection_list = null;
386 /** The list of subcollections available for the creation of subindexes. */
387 private JList subcollection_list_2 = null;
388 /** The list of assigned subindexes. */
389 private JList subindexes_list = null;
390 /** The label denoting the list of subindexes. */
391 private JLabel subindexes_label = null;
392 /** The panel containing the subcollection controls. */
393 private JPanel subcollection_pane = null;
394 /** The panel containing the subindex controls. */
395 private JPanel subindex_pane = null;
396 /** The tabbed pane used to store the subcollection and subindex controls. */
397 private JTabbedPane tabbed_pane = null;
398 /** The area used to display inline instructions. */
399 private JTextArea instructions = null;
400 /** The field displaying the name of the default subindex. */
401 private JTextField default_value = null;
402 /** A field used for specifying flags for the PERL expression matching, such as 'i' for case insensitive. */
403 private JTextField flags = null;
404 /** The pattern the source text must match. */
405 private JTextField match = null;
406 /** The name of this subcollection. */
407 private JTextField name = null;
408 /** The name of this subindex. */
409 private JTextField subindex_name;
410 /** When this button is selected the filter matching files are excluded. */
411 private JToggleButton exclude = null;
412 /** When this button is selected the filter matching files are included. */
413 private JToggleButton include = null;
414 /** The existing subcollection whose details you are reviewing, if any. */
415 private Subcollection current = null;
416 /** Constructor, creates the outer parts of the view, then calls two methods in turn to create the subcollection controls and subindex controls.
417 */
418 public Control() {
419 // Create
420 JPanel border_pane = new JPanel();
421 JPanel header_pane = new JPanel();
422 instructions = new JTextArea(get("Instructions"));
423 instructions.setEditable(false);
424 instructions.setLineWrap(true);
425 instructions.setRows(5);
426 instructions.setWrapStyleWord(true);
427 tabbed_pane = new JTabbedPane();
428 JLabel title = new JLabel(get("Title"));
429 title.setHorizontalAlignment(JLabel.CENTER);
430 createSubCollection();
431 createSubIndex();
432 // Add listeners
433 // Layout
434 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
435 header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
436 header_pane.setLayout(new BorderLayout());
437 header_pane.add(title, BorderLayout.NORTH);
438 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
439 tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
440 tabbed_pane.addTab(get("Subindex_Controls"), subindex_pane);
441 tabbed_pane.addTab(get("Language_Controls"), manager.languages.getControls());
442 border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
443 border_pane.setLayout(new BorderLayout());
444 border_pane.add(tabbed_pane, BorderLayout.CENTER);
445 setLayout(new BorderLayout());
446 add(header_pane, BorderLayout.NORTH);
447 add(border_pane, BorderLayout.CENTER);
448 }
449 /** Create the subcollection controls.
450 * @see org.greenstone.gatherer.Gatherer
451 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddListener
452 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ListListener
453 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveListener
454 * @see org.greenstone.gatherer.collection.CollectionManager
455 * @see org.greenstone.gatherer.msm.MetadataSetManager
456 */
457 public void createSubCollection() {
458 // Create
459 add = new JButton(get("Add"));
460 add.setMnemonic(KeyEvent.VK_A);
461 add.setEnabled(false);
462 JPanel button_pane = new JPanel();
463 JPanel button_pane_1 = new JPanel();
464 JPanel button_pane_3 = new JPanel();
465 exclude = new JToggleButton(get("Exclude"));
466 exclude.setMnemonic(KeyEvent.VK_X);
467 flags = new JTextField();
468 JLabel flags_label = new JLabel(get("Flags"));
469 include = new JToggleButton(get("Include"));
470 include.setMnemonic(KeyEvent.VK_I);
471 JLabel inclusive_label = new JLabel(get("Inclusive"));
472 JPanel inclusive_pane = new JPanel();
473 match = new JTextField();
474 JLabel match_label = new JLabel(get("Match"));
475 name = new JTextField();
476 JLabel name_label = new JLabel(get("Name"));
477 remove = new JButton(get("Remove"));
478 remove.setMnemonic(KeyEvent.VK_R);
479 remove.setEnabled(false);
480 Vector source_model = gatherer.c_man.msm.getAssignedElements();
481 source_model.add(0, "Filename");
482 source = new JComboBox(source_model);
483 JLabel source_label = new JLabel(get("Source"));
484 subcollection_list = new JList(model);
485 subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
486 subcollection_pane = new JPanel();
487 ButtonGroup bg = new ButtonGroup();
488 bg.add(include);
489 bg.add(exclude);
490 include.setSelected(true);
491 JPanel subcollection_list_pane = new JPanel();
492 JLabel subcollection_list_label = new JLabel(get("Assigned"));
493
494 // Add listeners
495 SubCollectionChangeListener cl = new SubCollectionChangeListener();
496 add.addActionListener(new AddSubCollectionListener());
497 remove.addActionListener(new RemoveSubCollectionListener());
498 subcollection_list.addListSelectionListener(new SubCollectionListListener());
499 //exclude.addActionListener(cl);
500 //include.addActionListener(cl);
501 //source.addActionListener(cl);
502 //flags.addDocumentListener(cl);
503 match.getDocument().addDocumentListener(cl);
504 name.getDocument().addDocumentListener(cl);
505
506 // Layout
507 inclusive_pane.setLayout(new GridLayout());
508 inclusive_pane.add(include);
509 inclusive_pane.add(exclude);
510 button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
511 button_pane_1.setLayout(new GridLayout(5, 2));
512 button_pane_1.add(name_label);
513 button_pane_1.add(name);
514 button_pane_1.add(source_label);
515 button_pane_1.add(source);
516 button_pane_1.add(match_label);
517 button_pane_1.add(match);
518 button_pane_1.add(inclusive_label);
519 button_pane_1.add(inclusive_pane);
520 button_pane_1.add(flags_label);
521 button_pane_1.add(flags);
522 button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
523 button_pane_3.setLayout(new GridLayout(1,2));
524 button_pane_3.add(add);
525 button_pane_3.add(remove);
526 button_pane.setLayout(new BorderLayout());
527 button_pane.add(button_pane_1, BorderLayout.CENTER);
528 button_pane.add(button_pane_3, BorderLayout.SOUTH);
529 subcollection_list_pane.setLayout(new BorderLayout());
530 subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
531 subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
532 subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
533 subcollection_pane.setLayout(new BorderLayout());
534 subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
535 subcollection_pane.add(button_pane, BorderLayout.SOUTH);
536 }
537 /** Create the subindex controls.
538 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddSubIndexListener
539 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ClearDefaultListener
540 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ChangeListener
541 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveSubIndexListener
542 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.SetDefaultListener
543 * @see org.greenstone.gatherer.util.ExclusiveListListener
544 */
545 public void createSubIndex() {
546 // Creation
547 JPanel subindex_name_panel = new JPanel();
548 JLabel subindex_name_label = new JLabel(get("PartitionName"));
549 subindex_name = new JTextField();
550
551 add_index = new JButton(get("Add_Subindex"));
552 add_index.setMnemonic(KeyEvent.VK_A);
553 add_index.setEnabled(false);
554 JPanel button_pane_2 = new JPanel();
555 clear_default = new JButton(get("Clear_Default_Subindex"));
556 clear_default.setMnemonic(KeyEvent.VK_C);
557 if(default_index == null) {
558 clear_default.setEnabled(false);
559 }
560 JLabel default_label = new JLabel(get("Default_Subindex"));
561 JPanel default_pane = new JPanel();
562 if(default_index == null) {
563 default_value = new JTextField();
564 }
565 else {
566 default_value = new JTextField(default_index.getSubIndex().toString());
567 }
568 default_value.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
569 default_value.setEditable(false);
570 JPanel subindex_inner_pane_1 = new JPanel();
571 JPanel subindex_inner_pane_2 = new JPanel();
572 remove_index = new JButton(get("Remove_Subindex"));
573 remove_index.setMnemonic(KeyEvent.VK_R);
574 set_default = new JButton(get("Set_Default_Subindex"));
575 set_default.setMnemonic(KeyEvent.VK_S);
576 JLabel subcollection_label = new JLabel(get("Subcollection"));
577 subcollection_list_2 = new JList(model);
578 JPanel list_2_pane = new JPanel();
579 subindex_pane = new JPanel();
580 JLabel subindexes_label = new JLabel(get("Subindexes"));
581 subindexes_list = new JList(subindexes);
582 subindexes_list.setCellRenderer(new SubIndexListCellRenderer());
583 subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
584 JPanel subindexes_pane = new JPanel();
585
586 // Add listeners
587 ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
588 ell.add(subcollection_list_2);
589 ell.add(subindexes_list);
590 add_index.addActionListener(new AddSubIndexListener());
591 clear_default.addActionListener(new ClearDefaultSubIndexListener());
592 remove_index.addActionListener(new RemoveSubIndexListener());
593 set_default.addActionListener(new SetDefaultSubIndexListener());
594
595 subindex_name.getDocument().addDocumentListener(new SubIndexNameDocumentListener());
596 subcollection_list_2.addListSelectionListener(new SubCollectionList2Listener());
597
598 // Layout
599 subindex_name_panel.setLayout(new BorderLayout());
600 subindex_name_panel.add(subindex_name_label, BorderLayout.WEST);
601 subindex_name_panel.add(subindex_name, BorderLayout.CENTER);
602
603 list_2_pane.setLayout(new BorderLayout());
604 list_2_pane.add(subcollection_label, BorderLayout.NORTH);
605 list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
606
607 subindexes_pane.setLayout(new BorderLayout());
608 subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
609 subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
610
611 subindex_inner_pane_2.setLayout(new GridLayout(1,2,0,5));
612 subindex_inner_pane_2.add(list_2_pane);
613 subindex_inner_pane_2.add(subindexes_pane);
614
615 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
616 default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
617 default_pane.setLayout(new BorderLayout());
618 default_pane.add(default_label, BorderLayout.WEST);
619 default_pane.add(default_value, BorderLayout.CENTER);
620
621 subindex_inner_pane_1.setLayout(new BorderLayout());
622 subindex_inner_pane_1.add(subindex_name_panel, BorderLayout.NORTH);
623 subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
624 subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
625
626 button_pane_2.setLayout(new GridLayout(2,2));
627 button_pane_2.add(add_index);
628 button_pane_2.add(remove_index);
629 button_pane_2.add(clear_default);
630 button_pane_2.add(set_default);
631
632 subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
633 subindex_pane.setLayout(new BorderLayout());
634 subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
635 subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
636 }
637
638
639 /** Method to unregister any listeners to avoid memory leaks.
640 */
641 public void destroy() {
642 }
643 /** We have overriden this method to provide completely different functionality, given that our JPanel will never actually have focus. We call this method in GUI on the view we are about to replace, and this method checks if a change has occured and if so updates the current object.
644 * @return A <i>boolean</i> which is always <i>false</i>.
645 * @see org.greenstone.gatherer.msm.ElementWrapper
646 */
647 public boolean hasFocus() {
648 // If we have a current metadata open, and something has changed then save the change.
649 if(changed && current != null) {
650 String n = name.getText();
651 String s = null;
652 Object o = source.getSelectedItem();
653 if(o instanceof ElementWrapper) {
654 ElementWrapper e = (ElementWrapper)o;
655 s = e.toString();
656 }
657 String e = match.getText();
658 String f = flags.getText();
659 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
660 current.update(n, s, e, include.isSelected(), f);
661 int index = model.indexOf(current);
662 changed();
663 subindexes.changed();
664 if(default_index != null) {
665 default_value.setText(default_index.getSubIndex().toString());
666 }
667 }
668 changed = false;
669 }
670 return false;
671 }
672 /** Overriden to ensure the instructions are scrolled to top.
673 */
674 public void updateUI() {
675 if(instructions != null) {
676 instructions.setCaretPosition(0);
677 }
678 super.updateUI();
679 }
680
681 /** Method to validate the current subcollection editor values, and enable or disable controls (add button) based on said values.
682 * we want to disable add until a new name is present
683 */
684 protected void validateAdd() {
685 if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
686 if (subcollections.containsKey(name.getText())) {
687 add.setEnabled(false);
688 } else {
689 add.setEnabled(true);
690 }
691 }
692 else {
693 add.setEnabled(false);
694 }
695 }
696 /** Listens for actions apon the 'add' button in the SubcollectionManager controls, and if detected calls the addSubcollection method of the manager with a newly created subcollection. */
697 private class AddSubCollectionListener
698 implements ActionListener {
699 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we wish to retrieve information from the various edit controls, and if we have sufficient data to build a new subcollection do so.
700 * @param event An <strong>ActionEvent</strong> containing information about the event.
701 * @see org.greenstone.gatherer.cdm.Subcollection
702 * @see org.greenstone.gatherer.msm.ElementWrapper
703 */
704 public void actionPerformed(ActionEvent event) {
705 String n = name.getText(); // not allowed spaces!
706 if (n.indexOf(' ')!=-1) {
707 n = n.substring(0, n.indexOf(' '));
708 name.setText(n);
709 }
710 String s = null;
711 Object o = source.getSelectedItem();
712 if(o instanceof ElementWrapper) {
713 ElementWrapper e = (ElementWrapper)o;
714 s = e.toString();
715 }
716 String e = match.getText();
717 String f = flags.getText();
718 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
719 Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
720 addSubcollection(sub);
721 }
722 changed = false;
723 validateAdd();
724 }
725 }
726 /** Listens for actions apon the 'add subindex' button in the SubcollectionManager controls, and if detected calls the addSubindex method of the manager with a newly created subindex. */
727 private class AddSubIndexListener
728 implements ActionListener {
729 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a series of subcollections selected, and if so build an new subindex based apon them.
730 * @param event An <strong>ActionEvent</strong> containing information about the event.
731 * @see org.greenstone.gatherer.cdm.SubIndex
732 */
733 public void actionPerformed(ActionEvent event) {
734 if(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0) {
735 Vector selected = new Vector();
736 Object raw[] = subcollection_list_2.getSelectedValues();
737 for(int i = 0; i < raw.length; i++) {
738 selected.add(raw[i]);
739 }
740 SubIndex subindex = new SubIndex(selected);
741 addSubIndex(subindex);
742 // Add the subindexes name.
743 CollectionMeta metadata = new CollectionMeta(manager, subindex, manager.languages.getDefaultLanguage(), subindex_name.getText());
744 manager.collectionmetadatum.addMetadata(metadata);
745 }
746 }
747 }
748 /** This class listens for any key entry in a text field, selection change in a combobox or button click, and when detected sets the changed flag to true. Its also convenient to use this class to test if the add button should be active yet. */
749 private class SubCollectionChangeListener
750 implements DocumentListener, ActionListener {
751 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to record that somethings changed, then validate the controls.
752 * @param event An <strong>ActionEvent</strong> containing information about the event.
753 */
754 public void actionPerformed(ActionEvent event) {
755 changed = true;
756 validateAdd();
757 }
758
759 public void changedUpdate(DocumentEvent event) {
760 changed = true;
761 validateAdd();
762 }
763 public void insertUpdate(DocumentEvent event) {
764 changed = true;
765 validateAdd();
766
767 }
768
769 public void removeUpdate(DocumentEvent event) {
770 changed = true;
771 validateAdd();
772 }
773 }
774 /** Listens for actions apon the 'clear default subindex' button in the SubcollectionManager controls, and if detected calls the setDefaultSubIndex() method of the manager with <i>null</i>. */
775 private class ClearDefaultSubIndexListener
776 implements ActionListener {
777 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to clear the default subindex.
778 * @param event An <strong>ActionEvent</strong> containing information about the event.
779 */
780 public void actionPerformed(ActionEvent event) {
781 setDefaultSubIndex(null);
782 clear_default.setEnabled(false);
783 default_value.setText("");
784 }
785 }
786 /** Listens for actions apon the 'remove' button in the SubcollectionManager controls, and if detected calls the remove method of the manager with the SubIndex selected for removal. */
787 private class RemoveSubCollectionListener
788 implements ActionListener {
789 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subcolleciton selected, and if so remove both it and any subindexes based on it.
790 * @param event An <strong>ActionEvent</strong> containing information about the event.
791 * @see org.greenstone.gatherer.cdm.Subcollection
792 */
793 public void actionPerformed(ActionEvent event) {
794 if(!subcollection_list.isSelectionEmpty()) {
795 Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
796 removeSubIndexes(sub_col);
797 removeSubcollection(sub_col);
798 }
799 }
800 }
801 /** Listens for actions apon the 'remove subindex' button in the SubcollectionManager controls, and if detected calls the removeSubIndex method of the manager with the SubIndex selected for removal. */
802 private class RemoveSubIndexListener
803 implements ActionListener {
804 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subindex selected, and if so remove it.
805 * @param event An <strong>ActionEvent</strong> containing information about the event.
806 * @see org.greenstone.gatherer.cdm.SubIndex
807 */
808 public void actionPerformed(ActionEvent event) {
809 if(!subindexes_list.isSelectionEmpty()) {
810 removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
811 }
812 }
813 }
814 /** Listens for actions apon the 'set default subindex' button in the SubcollectionManager controls, and if detected calls the setDefaultSubIndex method of the manager with the SubIndex selected for default. */
815 private class SetDefaultSubIndexListener
816 implements ActionListener {
817 /** Any implementation of ActionListener must include this method so we can be informed when an action has been performed on one of our target controls. In this case we want to check if they have a subindex selected, and if so set it as default.
818 * @param event An <strong>ActionEvent</strong> containing information about the event.
819 * @see org.greenstone.gatherer.cdm.DefaultSubIndex
820 * @see org.greenstone.gatherer.cdm.SubIndex
821 */
822 public void actionPerformed(ActionEvent event) {
823 if(!subindexes_list.isSelectionEmpty()) {
824 setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
825 clear_default.setEnabled(true);
826 default_value.setText(default_index.getSubIndex().toString());
827 }
828 }
829 }
830
831
832 /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
833 private class SubCollectionListListener
834 implements ListSelectionListener {
835 /** Any implementation of ListSelectionListener must include this method so we can be informed when the selection changes. In this case we want to execute any changes the users made to the entry, then update the controls with details of the new selection.
836 * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
837 * @see org.greenstone.gatherer.cdm.Subcollection
838 * @see org.greenstone.gatherer.msm.ElementWrapper
839 */
840 public void valueChanged(ListSelectionEvent event) {
841 // If we have a previous collection and the users changed something, but not added, then update subcollection.
842 if(changed && current != null) {
843 String n = name.getText();
844 String s = null;
845 Object o = source.getSelectedItem();
846 if(o instanceof ElementWrapper) {
847 ElementWrapper e = (ElementWrapper)o;
848 s = e.toString();
849 }
850 String e = match.getText();
851 String f = flags.getText();
852 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
853 current.update(n, s, e, include.isSelected(), f);
854 int index = model.indexOf(current);
855 changed();
856 subindexes.changed();
857 if(default_index != null) {
858 default_value.setText(default_index.getSubIndex().toString());
859 }
860 }
861 }
862 // Now load the new entry.
863 if(!subcollection_list.isSelectionEmpty()) {
864 current = (Subcollection) subcollection_list.getSelectedValue();
865 flags.setText(current.getFlags());
866 include.setSelected(current.getInclude());
867 exclude.setSelected(!current.getInclude());
868 match.setText(current.getExpression());
869 name.setText(current.getName());
870 String s = current.getSource();
871 int pos = 0;
872 Object value = source.getItemAt(pos);
873 while(value != null) {
874 if(value instanceof ElementWrapper) {
875 ElementWrapper e = (ElementWrapper) value;
876 if(e.toString().equals(s)) {
877 source.setSelectedIndex(pos);
878 value = null;
879 }
880 else {
881 pos++;
882 value = source.getItemAt(pos);
883 }
884 }
885 else if(value.toString().equals(s)) {
886 source.setSelectedIndex(pos);
887 value = null;
888 }
889 else {
890 pos++;
891 value = source.getItemAt(pos);
892 }
893 }
894 // Can't add one thats already there.
895 add.setEnabled(false);
896 // You can remove it though...
897 remove.setEnabled(true);
898 }
899 else {
900 flags.setText("");
901 include.setSelected(true);
902 match.setText("");
903 name.setText("");
904 source.setSelectedIndex(0);
905 remove.setEnabled(false);
906 }
907 // Have to do this after so we don't get called when nothings actually changed.
908 changed = false;
909
910 }
911 }
912
913 private class SubCollectionList2Listener
914 implements ListSelectionListener {
915
916 public void valueChanged(ListSelectionEvent event) {
917 if(!event.getValueIsAdjusting()) {
918 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
919 }
920 }
921 }
922
923 private class SubIndexListCellRenderer
924 extends DefaultListCellRenderer {
925
926 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
927 StringBuffer text = new StringBuffer(value.toString());
928 // Retrieve the indexes name if any.
929 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(value, manager.languages.getDefaultLanguage(), true);
930 if(metadata != null) {
931 text.append(" \"");
932 text.append(metadata.getValue());
933 text.append("\"");
934 }
935 return super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
936 }
937
938 }
939
940 private class SubIndexNameDocumentListener
941 implements DocumentListener {
942 /** Gives notification that an attribute or set of attributes changed. */
943 public void changedUpdate(DocumentEvent e) {
944 update();
945 }
946 /** Gives notification that there was an insert into the document. */
947 public void insertUpdate(DocumentEvent e) {
948 update();
949 }
950 /** Gives notification that a portion of the document has been removed. */
951 public void removeUpdate(DocumentEvent e) {
952 update();
953 }
954 /** The text area has changed in some way. Given that this can only happed when we are editing or adding a text fragment we better respond appropriately. */
955 private void update() {
956 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
957 }
958 }
959
960 }
961}
962
963
964
965
966
967
968
969
970
Note: See TracBrowser for help on using the repository browser.