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

Last change on this file since 4579 was 4579, checked in by kjdon, 21 years ago

fixed a stupid bug (that I did)

  • Property svn:keywords set to Author Date Id Revision
File size: 41.1 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("PartitionName"));
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 default_value.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
561 default_value.setEditable(false);
562 JPanel subindex_inner_pane_1 = new JPanel();
563 JPanel subindex_inner_pane_2 = new JPanel();
564 remove_index = new JButton(get("Remove_Subindex"));
565 remove_index.setMnemonic(KeyEvent.VK_R);
566 set_default = new JButton(get("Set_Default_Subindex"));
567 set_default.setMnemonic(KeyEvent.VK_S);
568 JLabel subcollection_label = new JLabel(get("Subcollection"));
569 subcollection_list_2 = new JList(model);
570 JPanel list_2_pane = new JPanel();
571 subindex_pane = new JPanel();
572 JLabel subindexes_label = new JLabel(get("Subindexes"));
573 subindexes_list = new JList(subindexes);
574 subindexes_list.setCellRenderer(new SubIndexListCellRenderer());
575 subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
576 JPanel subindexes_pane = new JPanel();
577
578 // Add listeners
579 ChangeListener cl = new ChangeListener();
580 ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
581 ell.add(subcollection_list_2);
582 ell.add(subindexes_list);
583 add_index.addActionListener(new AddSubIndexListener());
584 clear_default.addActionListener(new ClearDefaultListener());
585 exclude.addActionListener(cl);
586 include.addActionListener(cl);
587 remove_index.addActionListener(new RemoveSubIndexListener());
588 set_default.addActionListener(new SetDefaultListener());
589 source.addActionListener(cl);
590 flags.addKeyListener(cl);
591 match.addKeyListener(cl);
592 name.addKeyListener(cl);
593
594 subindex_name.getDocument().addDocumentListener(new SubIndexNameDocumentListener());
595 subcollection_list_2.addListSelectionListener(new SubcollectionListSelectionListener());
596
597 // Layout
598 subindex_name_panel.setLayout(new BorderLayout());
599 subindex_name_panel.add(subindex_name_label, BorderLayout.WEST);
600 subindex_name_panel.add(subindex_name, BorderLayout.CENTER);
601
602 list_2_pane.setLayout(new BorderLayout());
603 list_2_pane.add(subcollection_label, BorderLayout.NORTH);
604 list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
605
606 subindexes_pane.setLayout(new BorderLayout());
607 subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
608 subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
609
610 subindex_inner_pane_2.setLayout(new GridLayout(1,2,0,5));
611 subindex_inner_pane_2.add(list_2_pane);
612 subindex_inner_pane_2.add(subindexes_pane);
613
614 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
615 default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
616 default_pane.setLayout(new BorderLayout());
617 default_pane.add(default_label, BorderLayout.WEST);
618 default_pane.add(default_value, BorderLayout.CENTER);
619
620 subindex_inner_pane_1.setLayout(new BorderLayout());
621 subindex_inner_pane_1.add(subindex_name_panel, BorderLayout.NORTH);
622 subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
623 subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
624
625 button_pane_2.setLayout(new GridLayout(2,2));
626 button_pane_2.add(add_index);
627 button_pane_2.add(remove_index);
628 button_pane_2.add(clear_default);
629 button_pane_2.add(set_default);
630
631 subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
632 subindex_pane.setLayout(new BorderLayout());
633 subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
634 subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
635 }
636
637 private class SubIndexListCellRenderer
638 extends DefaultListCellRenderer {
639
640 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
641 StringBuffer text = new StringBuffer(value.toString());
642 // Retrieve the indexes name if any.
643 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(value, manager.languages.getDefaultLanguage(), true);
644 if(metadata != null) {
645 text.append(" \"");
646 text.append(metadata.getValue());
647 text.append("\"");
648 }
649 return super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
650 }
651
652 }
653
654 private class SubcollectionListSelectionListener
655 implements ListSelectionListener {
656
657 public void valueChanged(ListSelectionEvent event) {
658 if(!event.getValueIsAdjusting()) {
659 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
660 }
661 }
662 }
663
664 private class SubIndexNameDocumentListener
665 implements DocumentListener {
666 /** Gives notification that an attribute or set of attributes changed. */
667 public void changedUpdate(DocumentEvent e) {
668 update();
669 }
670 /** Gives notification that there was an insert into the document. */
671 public void insertUpdate(DocumentEvent e) {
672 update();
673 }
674 /** Gives notification that a portion of the document has been removed. */
675 public void removeUpdate(DocumentEvent e) {
676 update();
677 }
678 /** 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. */
679 private void update() {
680 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
681 }
682 }
683
684 /** Method to unregister any listeners to avoid memory leaks.
685 */
686 public void destroy() {
687 }
688 /** 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.
689 * @return A <i>boolean</i> which is always <i>false</i>.
690 * @see org.greenstone.gatherer.msm.ElementWrapper
691 */
692 public boolean hasFocus() {
693 // If we have a current metadata open, and something has changed then save the change.
694 if(changed && current != null) {
695 String n = name.getText();
696 String s = null;
697 Object o = source.getSelectedItem();
698 if(o instanceof ElementWrapper) {
699 ElementWrapper e = (ElementWrapper)o;
700 s = e.toString();
701 }
702 String e = match.getText();
703 String f = flags.getText();
704 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
705 current.update(n, s, e, include.isSelected(), f);
706 int index = model.indexOf(current);
707 changed();
708 subindexes.changed();
709 if(default_index != null) {
710 default_value.setText(default_index.getSubIndex().toString());
711 }
712 }
713 changed = false;
714 }
715 return false;
716 }
717 /** Overriden to ensure the instructions are scrolled to top.
718 */
719 public void updateUI() {
720 if(instructions != null) {
721 instructions.setCaretPosition(0);
722 }
723 super.updateUI();
724 }
725 /** 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. */
726 private class AddListener
727 implements ActionListener {
728 /** 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.
729 * @param event An <strong>ActionEvent</strong> containing information about the event.
730 * @see org.greenstone.gatherer.cdm.Subcollection
731 * @see org.greenstone.gatherer.msm.ElementWrapper
732 */
733 public void actionPerformed(ActionEvent event) {
734 String n = name.getText(); // not allowed spaces!
735 if (n.indexOf(' ')!=-1) {
736 n = n.substring(0, n.indexOf(' '));
737 name.setText(n);
738 }
739 String s = null;
740 Object o = source.getSelectedItem();
741 if(o instanceof ElementWrapper) {
742 ElementWrapper e = (ElementWrapper)o;
743 s = e.toString();
744 }
745 String e = match.getText();
746 String f = flags.getText();
747 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
748 Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
749 addSubcollection(sub);
750 }
751 changed = false;
752 }
753 }
754 /** 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. */
755 private class AddSubIndexListener
756 implements ActionListener {
757 /** 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.
758 * @param event An <strong>ActionEvent</strong> containing information about the event.
759 * @see org.greenstone.gatherer.cdm.SubIndex
760 */
761 public void actionPerformed(ActionEvent event) {
762 if(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0) {
763 Vector selected = new Vector();
764 Object raw[] = subcollection_list_2.getSelectedValues();
765 for(int i = 0; i < raw.length; i++) {
766 selected.add(raw[i]);
767 }
768 SubIndex subindex = new SubIndex(selected);
769 addSubIndex(subindex);
770 // Add the subindexes name.
771 CollectionMeta metadata = new CollectionMeta(manager, subindex, manager.languages.getDefaultLanguage(), subindex_name.getText());
772 manager.collectionmetadatum.addMetadata(metadata);
773 }
774 }
775 }
776 /** 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. */
777 public class ChangeListener
778 extends KeyAdapter
779 implements ActionListener {
780 /** 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.
781 * @param event An <strong>ActionEvent</strong> containing information about the event.
782 */
783 public void actionPerformed(ActionEvent event) {
784 changed = true;
785 validate();
786 }
787 /** 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.
788 * @param event An <strong>KeyEvent</strong> containing information about the event.
789 */
790 public void keyPressed(KeyEvent event) {
791 changed = true;
792 validate();
793 }
794 /** Method to validate the current editor values, and enable or disable controls based on said values. */
795 private void validate() {
796 if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
797 add.setEnabled(true);
798 }
799 else {
800 add.setEnabled(false);
801 }
802 }
803 }
804 /** 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>. */
805 private class ClearDefaultListener
806 implements ActionListener {
807 /** 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.
808 * @param event An <strong>ActionEvent</strong> containing information about the event.
809 */
810 public void actionPerformed(ActionEvent event) {
811 setDefaultSubIndex(null);
812 clear_default.setEnabled(false);
813 default_value.setText("");
814 }
815 }
816 /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
817 private class ListListener
818 implements ListSelectionListener {
819 /** 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.
820 * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
821 * @see org.greenstone.gatherer.cdm.Subcollection
822 * @see org.greenstone.gatherer.msm.ElementWrapper
823 */
824 public void valueChanged(ListSelectionEvent event) {
825 // If we have a previous collection and the users changed something, but not added, then update subcollection.
826 if(changed && current != null) {
827 String n = name.getText();
828 String s = null;
829 Object o = source.getSelectedItem();
830 if(o instanceof ElementWrapper) {
831 ElementWrapper e = (ElementWrapper)o;
832 s = e.toString();
833 }
834 String e = match.getText();
835 String f = flags.getText();
836 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
837 current.update(n, s, e, include.isSelected(), f);
838 int index = model.indexOf(current);
839 changed();
840 subindexes.changed();
841 if(default_index != null) {
842 default_value.setText(default_index.getSubIndex().toString());
843 }
844 }
845 }
846 // Now load the new entry.
847 if(!subcollection_list.isSelectionEmpty()) {
848 current = (Subcollection) subcollection_list.getSelectedValue();
849 flags.setText(current.getFlags());
850 include.setSelected(current.getInclude());
851 exclude.setSelected(!current.getInclude());
852 match.setText(current.getExpression());
853 name.setText(current.getName());
854 String s = current.getSource();
855 int pos = 0;
856 Object value = source.getItemAt(pos);
857 while(value != null) {
858 if(value instanceof ElementWrapper) {
859 ElementWrapper e = (ElementWrapper) value;
860 if(e.toString().equals(s)) {
861 source.setSelectedIndex(pos);
862 value = null;
863 }
864 else {
865 pos++;
866 value = source.getItemAt(pos);
867 }
868 }
869 else if(value.toString().equals(s)) {
870 source.setSelectedIndex(pos);
871 value = null;
872 }
873 else {
874 pos++;
875 value = source.getItemAt(pos);
876 }
877 }
878 // Can't add one thats already there.
879 add.setEnabled(false);
880 // You can remove it though...
881 remove.setEnabled(true);
882 }
883 else {
884 flags.setText("");
885 include.setSelected(true);
886 match.setText("");
887 name.setText("");
888 source.setSelectedIndex(0);
889 remove.setEnabled(false);
890 }
891 // Have to do this after so we don't get called when nothings actually changed.
892 changed = false;
893 }
894 }
895 /** 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. */
896 private class RemoveListener
897 implements ActionListener {
898 /** 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.
899 * @param event An <strong>ActionEvent</strong> containing information about the event.
900 * @see org.greenstone.gatherer.cdm.Subcollection
901 */
902 public void actionPerformed(ActionEvent event) {
903 if(!subcollection_list.isSelectionEmpty()) {
904 Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
905 removeSubIndexes(sub_col);
906 removeSubcollection(sub_col);
907 }
908 }
909 }
910 /** 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. */
911 private class RemoveSubIndexListener
912 implements ActionListener {
913 /** 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.
914 * @param event An <strong>ActionEvent</strong> containing information about the event.
915 * @see org.greenstone.gatherer.cdm.SubIndex
916 */
917 public void actionPerformed(ActionEvent event) {
918 if(!subindexes_list.isSelectionEmpty()) {
919 removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
920 }
921 }
922 }
923 /** 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. */
924 private class SetDefaultListener
925 implements ActionListener {
926 /** 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.
927 * @param event An <strong>ActionEvent</strong> containing information about the event.
928 * @see org.greenstone.gatherer.cdm.DefaultSubIndex
929 * @see org.greenstone.gatherer.cdm.SubIndex
930 */
931 public void actionPerformed(ActionEvent event) {
932 if(!subindexes_list.isSelectionEmpty()) {
933 setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
934 clear_default.setEnabled(true);
935 default_value.setText(default_index.getSubIndex().toString());
936 }
937 }
938 }
939 }
940}
941
942
943
944
945
946
947
948
949
Note: See TracBrowser for help on using the repository browser.