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

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

2030108: Fixed collectionmeta disappearing.

  • Property svn:keywords set to Author Date Id Revision
File size: 40.8 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.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
424 instructions.setEditable(false);
425 instructions.setLineWrap(true);
426 instructions.setRows(5);
427 instructions.setWrapStyleWord(true);
428 tabbed_pane = new JTabbedPane();
429 JLabel title = new JLabel(get("Title"));
430 title.setHorizontalAlignment(JLabel.CENTER);
431 createSubcollection();
432 createSubindex();
433 // Add listeners
434 // Layout
435 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
436 header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
437 header_pane.setLayout(new BorderLayout());
438 header_pane.add(title, BorderLayout.NORTH);
439 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
440 tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
441 tabbed_pane.addTab(get("Subindex_Controls"), subindex_pane);
442 tabbed_pane.addTab(get("Language_Controls"), manager.languages.getControls());
443 border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
444 border_pane.setLayout(new BorderLayout());
445 border_pane.add(tabbed_pane, BorderLayout.CENTER);
446 setLayout(new BorderLayout());
447 add(header_pane, BorderLayout.NORTH);
448 add(border_pane, BorderLayout.CENTER);
449 }
450 /** Create the subcollection controls.
451 * @see org.greenstone.gatherer.Gatherer
452 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddListener
453 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ListListener
454 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveListener
455 * @see org.greenstone.gatherer.collection.CollectionManager
456 * @see org.greenstone.gatherer.msm.MetadataSetManager
457 */
458 public void createSubcollection() {
459 // Create
460 add = new JButton(get("Add"));
461 add.setMnemonic(KeyEvent.VK_A);
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 Vector source_model = gatherer.c_man.msm.getAssignedElements();
480 source_model.add(0, "Filename");
481 source = new JComboBox(source_model);
482 JLabel source_label = new JLabel(get("Source"));
483 subcollection_list = new JList(model);
484 subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
485 subcollection_pane = new JPanel();
486 ButtonGroup bg = new ButtonGroup();
487 bg.add(include);
488 bg.add(exclude);
489 include.setSelected(true);
490 JPanel subcollection_list_pane = new JPanel();
491 JLabel subcollection_list_label = new JLabel(get("Assigned"));
492
493 // Add listeners
494 add.addActionListener(new AddListener());
495 remove.addActionListener(new RemoveListener());
496 subcollection_list.addListSelectionListener(new ListListener());
497
498 // Layout
499 inclusive_pane.setLayout(new GridLayout());
500 inclusive_pane.add(include);
501 inclusive_pane.add(exclude);
502 button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
503 button_pane_1.setLayout(new GridLayout(5, 2));
504 button_pane_1.add(name_label);
505 button_pane_1.add(name);
506 button_pane_1.add(source_label);
507 button_pane_1.add(source);
508 button_pane_1.add(match_label);
509 button_pane_1.add(match);
510 button_pane_1.add(inclusive_label);
511 button_pane_1.add(inclusive_pane);
512 button_pane_1.add(flags_label);
513 button_pane_1.add(flags);
514 button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
515 button_pane_3.setLayout(new GridLayout(1,2));
516 button_pane_3.add(add);
517 button_pane_3.add(remove);
518 button_pane.setLayout(new BorderLayout());
519 button_pane.add(button_pane_1, BorderLayout.CENTER);
520 button_pane.add(button_pane_3, BorderLayout.SOUTH);
521 subcollection_list_pane.setLayout(new BorderLayout());
522 subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
523 subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
524 subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
525 subcollection_pane.setLayout(new BorderLayout());
526 subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
527 subcollection_pane.add(button_pane, BorderLayout.SOUTH);
528 }
529 /** Create the subindex controls.
530 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddSubIndexListener
531 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ClearDefaultListener
532 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ChangeListener
533 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveSubIndexListener
534 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.SetDefaultListener
535 * @see org.greenstone.gatherer.util.ExclusiveListListener
536 */
537 public void createSubindex() {
538 // Creation
539 JPanel subindex_name_panel = new JPanel();
540 JLabel subindex_name_label = new JLabel(get("Name"));
541 subindex_name = new JTextField();
542
543 add_index = new JButton(get("Add_Subindex"));
544 add_index.setMnemonic(KeyEvent.VK_A);
545 add_index.setEnabled(false);
546 JPanel button_pane_2 = new JPanel();
547 clear_default = new JButton(get("Clear_Default_Subindex"));
548 clear_default.setMnemonic(KeyEvent.VK_C);
549 if(default_index == null) {
550 clear_default.setEnabled(false);
551 }
552 JLabel default_label = new JLabel(get("Default_Subindex"));
553 JPanel default_pane = new JPanel();
554 if(default_index == null) {
555 default_value = new JTextField();
556 }
557 else {
558 default_value = new JTextField(default_index.getSubIndex().toString());
559 }
560 JPanel subindex_inner_pane_1 = new JPanel();
561 JPanel subindex_inner_pane_2 = new JPanel();
562 remove_index = new JButton(get("Remove_Subindex"));
563 remove_index.setMnemonic(KeyEvent.VK_R);
564 set_default = new JButton(get("Set_Default_Subindex"));
565 set_default.setMnemonic(KeyEvent.VK_S);
566 JLabel subcollection_label = new JLabel(get("Subcollection"));
567 subcollection_list_2 = new JList(model);
568 JPanel list_2_pane = new JPanel();
569 subindex_pane = new JPanel();
570 JLabel subindexes_label = new JLabel(get("Subindexes"));
571 subindexes_list = new JList(subindexes);
572 subindexes_list.setCellRenderer(new SubIndexListCellRenderer());
573 subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
574 JPanel subindexes_pane = new JPanel();
575
576 // Add listeners
577 ChangeListener cl = new ChangeListener();
578 ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
579 ell.add(subcollection_list_2);
580 ell.add(subindexes_list);
581 add_index.addActionListener(new AddSubIndexListener());
582 clear_default.addActionListener(new ClearDefaultListener());
583 exclude.addActionListener(cl);
584 include.addActionListener(cl);
585 remove_index.addActionListener(new RemoveSubIndexListener());
586 set_default.addActionListener(new SetDefaultListener());
587 source.addActionListener(cl);
588 flags.addKeyListener(cl);
589 match.addKeyListener(cl);
590 name.addKeyListener(cl);
591
592 subindex_name.getDocument().addDocumentListener(new SubIndexNameDocumentListener());
593 subcollection_list_2.addListSelectionListener(new SubcollectionListSelectionListener());
594
595 // Layout
596 subindex_name_panel.setLayout(new BorderLayout());
597 subindex_name_panel.add(subindex_name_label, BorderLayout.WEST);
598 subindex_name_panel.add(subindex_name, BorderLayout.CENTER);
599
600 list_2_pane.setLayout(new BorderLayout());
601 list_2_pane.add(subcollection_label, BorderLayout.NORTH);
602 list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
603
604 subindexes_pane.setLayout(new BorderLayout());
605 subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
606 subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
607
608 subindex_inner_pane_2.setLayout(new GridLayout(1,2,0,5));
609 subindex_inner_pane_2.add(list_2_pane);
610 subindex_inner_pane_2.add(subindexes_pane);
611
612 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
613 default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
614 default_pane.setLayout(new BorderLayout());
615 default_pane.add(default_label, BorderLayout.WEST);
616 default_pane.add(default_value, BorderLayout.CENTER);
617
618 subindex_inner_pane_1.setLayout(new BorderLayout());
619 subindex_inner_pane_1.add(subindex_name_panel, BorderLayout.NORTH);
620 subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
621 subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
622
623 button_pane_2.setLayout(new GridLayout(2,2));
624 button_pane_2.add(add_index);
625 button_pane_2.add(remove_index);
626 button_pane_2.add(clear_default);
627 button_pane_2.add(set_default);
628
629 subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
630 subindex_pane.setLayout(new BorderLayout());
631 subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
632 subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
633 }
634
635 private class SubIndexListCellRenderer
636 extends DefaultListCellRenderer {
637
638 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
639 StringBuffer text = new StringBuffer(value.toString());
640 // Retrieve the indexes name if any.
641 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(value, manager.languages.getDefaultLanguage(), true);
642 if(metadata != null) {
643 text.append(" \"");
644 text.append(metadata.getValue());
645 text.append("\"");
646 }
647 return super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
648 }
649
650 }
651
652 private class SubcollectionListSelectionListener
653 implements ListSelectionListener {
654
655 public void valueChanged(ListSelectionEvent event) {
656 if(!event.getValueIsAdjusting()) {
657 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
658 }
659 }
660 }
661
662 private class SubIndexNameDocumentListener
663 implements DocumentListener {
664 /** Gives notification that an attribute or set of attributes changed. */
665 public void changedUpdate(DocumentEvent e) {
666 update();
667 }
668 /** Gives notification that there was an insert into the document. */
669 public void insertUpdate(DocumentEvent e) {
670 update();
671 }
672 /** Gives notification that a portion of the document has been removed. */
673 public void removeUpdate(DocumentEvent e) {
674 update();
675 }
676 /** 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. */
677 private void update() {
678 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
679 }
680 }
681
682 /** Method to unregister any listeners to avoid memory leaks.
683 */
684 public void destroy() {
685 }
686 /** 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.
687 * @return A <i>boolean</i> which is always <i>false</i>.
688 * @see org.greenstone.gatherer.msm.ElementWrapper
689 */
690 public boolean hasFocus() {
691 // If we have a current metadata open, and something has changed then save the change.
692 if(changed && current != null) {
693 String n = name.getText();
694 String s = null;
695 Object o = source.getSelectedItem();
696 if(o instanceof ElementWrapper) {
697 ElementWrapper e = (ElementWrapper)o;
698 s = e.toString();
699 }
700 String e = match.getText();
701 String f = flags.getText();
702 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
703 current.update(n, s, e, include.isSelected(), f);
704 int index = model.indexOf(current);
705 changed();
706 subindexes.changed();
707 if(default_index != null) {
708 default_value.setText(default_index.getSubIndex().toString());
709 }
710 }
711 changed = false;
712 }
713 return false;
714 }
715 /** Overriden to ensure the instructions are scrolled to top.
716 */
717 public void updateUI() {
718 if(instructions != null) {
719 instructions.setCaretPosition(0);
720 }
721 super.updateUI();
722 }
723 /** 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. */
724 private class AddListener
725 implements ActionListener {
726 /** 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.
727 * @param event An <strong>ActionEvent</strong> containing information about the event.
728 * @see org.greenstone.gatherer.cdm.Subcollection
729 * @see org.greenstone.gatherer.msm.ElementWrapper
730 */
731 public void actionPerformed(ActionEvent event) {
732 String n = name.getText();
733 String s = null;
734 Object o = source.getSelectedItem();
735 if(o instanceof ElementWrapper) {
736 ElementWrapper e = (ElementWrapper)o;
737 s = e.toString();
738 }
739 String e = match.getText();
740 String f = flags.getText();
741 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
742 Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
743 addSubcollection(sub);
744 }
745 changed = false;
746 }
747 }
748 /** 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. */
749 private class AddSubIndexListener
750 implements 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 check if they have a series of subcollections selected, and if so build an new subindex based apon them.
752 * @param event An <strong>ActionEvent</strong> containing information about the event.
753 * @see org.greenstone.gatherer.cdm.SubIndex
754 */
755 public void actionPerformed(ActionEvent event) {
756 if(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0) {
757 Vector selected = new Vector();
758 Object raw[] = subcollection_list_2.getSelectedValues();
759 for(int i = 0; i < raw.length; i++) {
760 selected.add(raw[i]);
761 }
762 SubIndex subindex = new SubIndex(selected);
763 addSubIndex(subindex);
764 // Add the subindexes name.
765 CollectionMeta metadata = new CollectionMeta(manager, subindex, manager.languages.getDefaultLanguage(), subindex_name.getText());
766 manager.collectionmetadatum.addMetadata(metadata);
767 }
768 }
769 }
770 /** 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. */
771 public class ChangeListener
772 extends KeyAdapter
773 implements ActionListener {
774 /** 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.
775 * @param event An <strong>ActionEvent</strong> containing information about the event.
776 */
777 public void actionPerformed(ActionEvent event) {
778 changed = true;
779 validate();
780 }
781 /** Any inheritor of KeyAdapter can override this method so we can be informed when an key has been type in one of our target controls. In this case we want to record that somethings changed, then validate the controls.
782 * @param event An <strong>KeyEvent</strong> containing information about the event.
783 */
784 public void keyPressed(KeyEvent event) {
785 changed = true;
786 validate();
787 }
788 /** Method to validate the current editor values, and enable or disable controls based on said values. */
789 private void validate() {
790 if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
791 add.setEnabled(true);
792 }
793 else {
794 add.setEnabled(false);
795 }
796 }
797 }
798 /** 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>. */
799 private class ClearDefaultListener
800 implements ActionListener {
801 /** 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.
802 * @param event An <strong>ActionEvent</strong> containing information about the event.
803 */
804 public void actionPerformed(ActionEvent event) {
805 setDefaultSubIndex(null);
806 clear_default.setEnabled(false);
807 default_value.setText("");
808 }
809 }
810 /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
811 private class ListListener
812 implements ListSelectionListener {
813 /** 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.
814 * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
815 * @see org.greenstone.gatherer.cdm.Subcollection
816 * @see org.greenstone.gatherer.msm.ElementWrapper
817 */
818 public void valueChanged(ListSelectionEvent event) {
819 // If we have a previous collection and the users changed something, but not added, then update subcollection.
820 if(changed && current != null) {
821 String n = name.getText();
822 String s = null;
823 Object o = source.getSelectedItem();
824 if(o instanceof ElementWrapper) {
825 ElementWrapper e = (ElementWrapper)o;
826 s = e.toString();
827 }
828 String e = match.getText();
829 String f = flags.getText();
830 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
831 current.update(n, s, e, include.isSelected(), f);
832 int index = model.indexOf(current);
833 changed();
834 subindexes.changed();
835 if(default_index != null) {
836 default_value.setText(default_index.getSubIndex().toString());
837 }
838 }
839 }
840 // Now load the new entry.
841 if(!subcollection_list.isSelectionEmpty()) {
842 current = (Subcollection) subcollection_list.getSelectedValue();
843 flags.setText(current.getFlags());
844 include.setSelected(current.getInclude());
845 exclude.setSelected(!current.getInclude());
846 match.setText(current.getExpression());
847 name.setText(current.getName());
848 String s = current.getSource();
849 int pos = 0;
850 Object value = source.getItemAt(pos);
851 while(value != null) {
852 if(value instanceof ElementWrapper) {
853 ElementWrapper e = (ElementWrapper) value;
854 if(e.toString().equals(s)) {
855 source.setSelectedIndex(pos);
856 value = null;
857 }
858 else {
859 pos++;
860 value = source.getItemAt(pos);
861 }
862 }
863 else if(value.toString().equals(s)) {
864 source.setSelectedIndex(pos);
865 value = null;
866 }
867 else {
868 pos++;
869 value = source.getItemAt(pos);
870 }
871 }
872 // Can't add one thats already there.
873 add.setEnabled(false);
874 // You can remove it though...
875 remove.setEnabled(true);
876 }
877 else {
878 flags.setText("");
879 include.setSelected(true);
880 match.setText("");
881 name.setText("");
882 source.setSelectedIndex(0);
883 remove.setEnabled(false);
884 }
885 // Have to do this after so we don't get called when nothings actually changed.
886 changed = false;
887 }
888 }
889 /** 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. */
890 private class RemoveListener
891 implements ActionListener {
892 /** 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.
893 * @param event An <strong>ActionEvent</strong> containing information about the event.
894 * @see org.greenstone.gatherer.cdm.Subcollection
895 */
896 public void actionPerformed(ActionEvent event) {
897 if(!subcollection_list.isSelectionEmpty()) {
898 Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
899 removeSubIndexes(sub_col);
900 removeSubcollection(sub_col);
901 }
902 }
903 }
904 /** 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. */
905 private class RemoveSubIndexListener
906 implements ActionListener {
907 /** 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.
908 * @param event An <strong>ActionEvent</strong> containing information about the event.
909 * @see org.greenstone.gatherer.cdm.SubIndex
910 */
911 public void actionPerformed(ActionEvent event) {
912 if(!subindexes_list.isSelectionEmpty()) {
913 removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
914 }
915 }
916 }
917 /** 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. */
918 private class SetDefaultListener
919 implements ActionListener {
920 /** 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.
921 * @param event An <strong>ActionEvent</strong> containing information about the event.
922 * @see org.greenstone.gatherer.cdm.DefaultSubIndex
923 * @see org.greenstone.gatherer.cdm.SubIndex
924 */
925 public void actionPerformed(ActionEvent event) {
926 if(!subindexes_list.isSelectionEmpty()) {
927 setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
928 clear_default.setEnabled(true);
929 default_value.setText(default_index.getSubIndex().toString());
930 }
931 }
932 }
933 }
934}
935
936
937
938
939
940
941
942
943
Note: See TracBrowser for help on using the repository browser.