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

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

2030098: Fixed translation manager and separated the Languages from the possible text fragment Translations.

  • Property svn:keywords set to Author Date Id Revision
File size: 40.4 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 /** Method to get all of the subindexes set.
172 * @return A <strong>SubIndexes</strong> object containing all the defined indexes.
173 */
174 public SubIndexes getSubIndexes() {
175 return subindexes;
176 }
177 /** Method to get all of the subcollections defined.
178 * @return A <strong>Vector</strong> of subcollections.
179 */
180 public Vector getSubcollections() {
181 Vector subcollections = new Vector();
182 for(int i = 0; i < size(); i++) {
183 subcollections.add(get(i));
184 }
185 return subcollections;
186 }
187 /** Mark the current controls, if any, as invalid and deallocate them. Any further use of the controls will requires them being rebuilt.
188 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control
189 */
190 public void invalidateControls() {
191 if(controls != null) {
192 controls.destroy();
193 controls = null;
194 }
195 }
196 /** 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.
197 * @param command The <strong>String</strong> to be parsed.
198 * @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>.
199 * @return A <i>boolean</i> which is <i>true</i> if a command was parsed, <i>false</i> otherwise.
200 * @see org.greenstone.gatherer.cdm.CommandTokenizer
201 * @see org.greenstone.gatherer.cdm.DefaultSubIndex
202 * @see org.greenstone.gatherer.cdm.Subcollection
203 * @see org.greenstone.gatherer.cdm.SubIndex
204 */
205 public boolean parse(String command, boolean finished) {
206 String temp = command.toLowerCase();
207 CommandTokenizer tokenizer = new CommandTokenizer(command);
208 tokenizer.nextToken(); // Throw away head.
209 if(temp.startsWith("subcollection")) {
210 if(tokenizer.countTokens() >= 2) {
211 String name = tokenizer.nextToken();
212 String pattern = tokenizer.nextToken();
213 addSubcollection(new Subcollection(name, pattern));
214 return true;
215 }
216 }
217 else if(temp.startsWith("indexsubcollections")) {
218 // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
219 if(!finished) {
220 unresolved.add(command);
221 }
222 else {
223 while(tokenizer.hasMoreTokens()) {
224 addSubIndex(new SubIndex(tokenizer.nextToken(), this));
225 }
226 }
227 return true;
228 }
229 else if(temp.startsWith("defaultsubcollection")) {
230 // These entries depend on what subcollections have previously been set, so we cannot safely parse them until after the file is complete.
231 if(!finished) {
232 unresolved.add(command);
233 }
234 else {
235 if(tokenizer.hasMoreTokens()) {
236 setDefaultSubIndex(new DefaultSubIndex(tokenizer.nextToken(), this));
237 }
238 }
239 return true;
240 }
241 return false;
242 }
243 /** Method to remove a certain subindex.
244 * @param subindex The <strong>SubIndex</strong> you wish to remove.
245 * @see org.greenstone.gatherer.Gatherer
246 * @see org.greenstone.gatherer.collection.CollectionManager
247 */
248 public void removeSubIndex(SubIndex subindex) {
249 subindexes.removeElement(subindex);
250 gatherer.c_man.configurationChanged();
251 }
252 /** Method to remove all of the subindexes that contain a certain subcollection.
253 * @param sub The <strong>Subcollection</strong> that you wish to remove.
254 * @see org.greenstone.gatherer.Gatherer
255 * @see org.greenstone.gatherer.cdm.SubIndex
256 * @see org.greenstone.gatherer.collection.CollectionManager
257 */
258 public void removeSubIndexes(Subcollection sub) {
259 for(int i = subindexes.size() - 1; i >= 0; i--) {
260 SubIndex subindex = (SubIndex)subindexes.get(i);
261 if(subindex.containsSubcollection(sub.getName())) {
262 subindexes.removeElement(subindex);
263 }
264 }
265 gatherer.c_man.configurationChanged();
266 }
267 /** Method to remove the given subcollection.
268 * @param sub The <strong>Subcollection</strong> you want to remove.
269 * @see org.greenstone.gatherer.Gatherer
270 * @see org.greenstone.gatherer.collection.CollectionManager
271 */
272 public void removeSubcollection(Subcollection sub) {
273 removeElement(sub);
274 subcollections.remove(sub);
275 gatherer.c_man.configurationChanged();
276 }
277 /** Method to retry the parsing of commands that were previously unable to be parsed as they referenced subcollections that may not have been instantiated.
278 */
279 public void reparseUnresolved() {
280 for(int i = 0; i < unresolved.size(); i++) {
281 parse((String)unresolved.get(i), true);
282 }
283 unresolved.clear();
284 }
285 /** Method to set the default subcollection index.
286 * @param subcollection The <strong>Subcollection</strong> to use as the default index.
287 * @see org.greenstone.gatherer.Gatherer
288 * @see org.greenstone.gatherer.collection.CollectionManager
289 */
290 public void setDefaultSubIndex(DefaultSubIndex subindex) {
291 this.default_index = subindex;
292 if(subindex != null) {
293 addSubIndex(subindex.getSubIndex());
294 }
295 gatherer.c_man.configurationChanged();
296 }
297 /** 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.
298 * @return A <strong>String</strong> containing a block of configuration commands.
299 * @see org.greenstone.gatherer.cdm.SubIndex
300 * @see org.greenstone.gatherer.cdm.Subcollection
301 */
302 public String toString() {
303 String text = "";
304 // Retrieve the subcollection names and sort them.
305 if(subcollections.size() > 0) {
306 Vector names = new Vector(subcollections.keySet());
307 Collections.sort(names);
308 for(int i = 0; i < names.size(); i++) {
309 Subcollection sub =
310 (Subcollection) subcollections.get(names.get(i));
311 text = text + sub.toString();
312 }
313 // Now add a entry, separated by spaces for each subcollection
314 // index.
315 if(subindexes.size() > 0) {
316 text = text + subindexes.toString();
317 }
318 // Finally add the default subcollection index if necessary.
319 if(default_index != null) {
320 text = text + default_index.toString();
321 }
322 text = text + "\n";
323 }
324 // Otherwise if there were no subcollections, there aren't going to be
325 // subcollection indexes, nor a default subcollection index are there.
326 return text;
327 }
328 /** Method to retrieve a phrase from the dictionary based on a key.
329 * @param key A <strong>String</strong> used to find the correct phrase.
330 * @param args A <strong>String[]</strong> of arguments used in formatting and filling out the phrase.
331 * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
332 */
333 private String get(String key) {
334 return get(key, null);
335 }
336 /** Method to retrieve a phrase from the dictionary based on a key.
337 * @param key A <strong>String</strong> used to find the correct phrase.
338 * @return A <strong>String</strong> containing the correct phrase with the correct formatting.
339 * @see org.greenstone.gatherer.Dictionary
340 * @see org.greenstone.gatherer.Gatherer
341 */
342 private String get(String key, String args[]) {
343 if(key.indexOf(".") == -1) {
344 key = "CDM.SubcollectionManager." + key;
345 }
346 return gatherer.dictionary.get(key, args);
347 }
348 /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
349 private class Control
350 extends JPanel {
351 /** <i>true</i> if the current selection has changed. */
352 private boolean changed = false;
353 /** Button to add a subcollection. */
354 private JButton add = null;
355 /** Button to add a subindex. */
356 private JButton add_index = null;
357 /** Button to clear the default subindex. */
358 private JButton clear_default = null;
359 /** Button to remove a subcollection. */
360 private JButton remove = null;
361 /** Button to remove a subindex. */
362 private JButton remove_index = null;
363 /** Button to set the default subindex. */
364 private JButton set_default = null;
365 /** Button to cause an update of the subcollections. */
366 private JButton update = null;
367 /** 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. */
368 private JComboBox source = null;
369 /** The list of assigned subcollections. */
370 private JList subcollection_list = null;
371 /** The list of subcollections available for the creation of subindexes. */
372 private JList subcollection_list_2 = null;
373 /** The list of assigned subindexes. */
374 private JList subindexes_list = null;
375 /** The label denoting the list of subindexes. */
376 private JLabel subindexes_label = null;
377 /** The panel containing the subcollection controls. */
378 private JPanel subcollection_pane = null;
379 /** The panel containing the subindex controls. */
380 private JPanel subindex_pane = null;
381 /** The tabbed pane used to store the subcollection and subindex controls. */
382 private JTabbedPane tabbed_pane = null;
383 /** The area used to display inline instructions. */
384 private JTextArea instructions = null;
385 /** The field displaying the name of the default subindex. */
386 private JTextField default_value = null;
387 /** A field used for specifying flags for the PERL expression matching, such as 'i' for case insensitive. */
388 private JTextField flags = null;
389 /** The pattern the source text must match. */
390 private JTextField match = null;
391 /** The name of this subcollection. */
392 private JTextField name = null;
393 /** The name of this subindex. */
394 private JTextField subindex_name;
395 /** When this button is selected the filter matching files are excluded. */
396 private JToggleButton exclude = null;
397 /** When this button is selected the filter matching files are included. */
398 private JToggleButton include = null;
399 /** The existing subcollection whose details you are reviewing, if any. */
400 private Subcollection current = null;
401 /** Constructor, creates the outer parts of the view, then calls two methods in turn to create the subcollection controls and subindex controls.
402 */
403 public Control() {
404 // Create
405 JPanel border_pane = new JPanel();
406 JPanel header_pane = new JPanel();
407 instructions = new JTextArea(get("Instructions"));
408 instructions.setBackground(Gatherer.config.getColor("coloring.collection_tree_background", false));
409 instructions.setEditable(false);
410 instructions.setLineWrap(true);
411 instructions.setRows(5);
412 instructions.setWrapStyleWord(true);
413 tabbed_pane = new JTabbedPane();
414 JLabel title = new JLabel(get("Title"));
415 title.setHorizontalAlignment(JLabel.CENTER);
416 createSubcollection();
417 createSubindex();
418 // Add listeners
419 // Layout
420 instructions.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
421 header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
422 header_pane.setLayout(new BorderLayout());
423 header_pane.add(title, BorderLayout.NORTH);
424 header_pane.add(new JScrollPane(instructions), BorderLayout.CENTER);
425 tabbed_pane.addTab(get("Subcollection_Controls"), subcollection_pane);
426 tabbed_pane.addTab(get("Subindex_Controls"), subindex_pane);
427 tabbed_pane.addTab(get("Language_Controls"), manager.languages.getControls());
428 border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
429 border_pane.setLayout(new BorderLayout());
430 border_pane.add(tabbed_pane, BorderLayout.CENTER);
431 setLayout(new BorderLayout());
432 add(header_pane, BorderLayout.NORTH);
433 add(border_pane, BorderLayout.CENTER);
434 }
435 /** Create the subcollection controls.
436 * @see org.greenstone.gatherer.Gatherer
437 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddListener
438 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ListListener
439 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveListener
440 * @see org.greenstone.gatherer.collection.CollectionManager
441 * @see org.greenstone.gatherer.msm.MetadataSetManager
442 */
443 public void createSubcollection() {
444 // Create
445 add = new JButton(get("Add"));
446 add.setMnemonic(KeyEvent.VK_A);
447 JPanel button_pane = new JPanel();
448 JPanel button_pane_1 = new JPanel();
449 JPanel button_pane_3 = new JPanel();
450 exclude = new JToggleButton(get("Exclude"));
451 exclude.setMnemonic(KeyEvent.VK_X);
452 flags = new JTextField();
453 JLabel flags_label = new JLabel(get("Flags"));
454 include = new JToggleButton(get("Include"));
455 include.setMnemonic(KeyEvent.VK_I);
456 JLabel inclusive_label = new JLabel(get("Inclusive"));
457 JPanel inclusive_pane = new JPanel();
458 match = new JTextField();
459 JLabel match_label = new JLabel(get("Match"));
460 name = new JTextField();
461 JLabel name_label = new JLabel(get("Name"));
462 remove = new JButton(get("Remove"));
463 remove.setMnemonic(KeyEvent.VK_R);
464 Vector source_model = gatherer.c_man.msm.getAssignedElements();
465 source_model.add(0, "Filename");
466 source = new JComboBox(source_model);
467 JLabel source_label = new JLabel(get("Source"));
468 subcollection_list = new JList(model);
469 subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
470 subcollection_pane = new JPanel();
471 ButtonGroup bg = new ButtonGroup();
472 bg.add(include);
473 bg.add(exclude);
474 include.setSelected(true);
475 JPanel subcollection_list_pane = new JPanel();
476 JLabel subcollection_list_label = new JLabel(get("Assigned"));
477
478 // Add listeners
479 add.addActionListener(new AddListener());
480 remove.addActionListener(new RemoveListener());
481 subcollection_list.addListSelectionListener(new ListListener());
482
483 // Layout
484 inclusive_pane.setLayout(new GridLayout());
485 inclusive_pane.add(include);
486 inclusive_pane.add(exclude);
487 button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
488 button_pane_1.setLayout(new GridLayout(5, 2));
489 button_pane_1.add(name_label);
490 button_pane_1.add(name);
491 button_pane_1.add(source_label);
492 button_pane_1.add(source);
493 button_pane_1.add(match_label);
494 button_pane_1.add(match);
495 button_pane_1.add(inclusive_label);
496 button_pane_1.add(inclusive_pane);
497 button_pane_1.add(flags_label);
498 button_pane_1.add(flags);
499 button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
500 button_pane_3.setLayout(new GridLayout(1,2));
501 button_pane_3.add(add);
502 button_pane_3.add(remove);
503 button_pane.setLayout(new BorderLayout());
504 button_pane.add(button_pane_1, BorderLayout.CENTER);
505 button_pane.add(button_pane_3, BorderLayout.SOUTH);
506 subcollection_list_pane.setLayout(new BorderLayout());
507 subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
508 subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
509 subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
510 subcollection_pane.setLayout(new BorderLayout());
511 subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
512 subcollection_pane.add(button_pane, BorderLayout.SOUTH);
513 }
514 /** Create the subindex controls.
515 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.AddSubIndexListener
516 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ClearDefaultListener
517 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.ChangeListener
518 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.RemoveSubIndexListener
519 * @see org.greenstone.gatherer.cdm.SubcollectionManager.Control.SetDefaultListener
520 * @see org.greenstone.gatherer.util.ExclusiveListListener
521 */
522 public void createSubindex() {
523 // Creation
524 JPanel subindex_name_panel = new JPanel();
525 JLabel subindex_name_label = new JLabel(get("Name"));
526 subindex_name = new JTextField();
527
528 add_index = new JButton(get("Add_Subindex"));
529 add_index.setMnemonic(KeyEvent.VK_A);
530 add_index.setEnabled(false);
531 JPanel button_pane_2 = new JPanel();
532 clear_default = new JButton(get("Clear_Default_Subindex"));
533 clear_default.setMnemonic(KeyEvent.VK_C);
534 if(default_index == null) {
535 clear_default.setEnabled(false);
536 }
537 JLabel default_label = new JLabel(get("Default_Subindex"));
538 JPanel default_pane = new JPanel();
539 if(default_index == null) {
540 default_value = new JTextField();
541 }
542 else {
543 default_value = new JTextField(default_index.getSubIndex().toString());
544 }
545 JPanel subindex_inner_pane_1 = new JPanel();
546 JPanel subindex_inner_pane_2 = new JPanel();
547 remove_index = new JButton(get("Remove_Subindex"));
548 remove_index.setMnemonic(KeyEvent.VK_R);
549 set_default = new JButton(get("Set_Default_Subindex"));
550 set_default.setMnemonic(KeyEvent.VK_S);
551 JLabel subcollection_label = new JLabel(get("Subcollection"));
552 subcollection_list_2 = new JList(model);
553 JPanel list_2_pane = new JPanel();
554 subindex_pane = new JPanel();
555 JLabel subindexes_label = new JLabel(get("Subindexes"));
556 subindexes_list = new JList(subindexes);
557 subindexes_list.setCellRenderer(new SubIndexListCellRenderer());
558 subindexes_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
559 JPanel subindexes_pane = new JPanel();
560
561 // Add listeners
562 ChangeListener cl = new ChangeListener();
563 ExclusiveListSelectionListener ell = new ExclusiveListSelectionListener();
564 ell.add(subcollection_list_2);
565 ell.add(subindexes_list);
566 add_index.addActionListener(new AddSubIndexListener());
567 clear_default.addActionListener(new ClearDefaultListener());
568 exclude.addActionListener(cl);
569 include.addActionListener(cl);
570 remove_index.addActionListener(new RemoveSubIndexListener());
571 set_default.addActionListener(new SetDefaultListener());
572 source.addActionListener(cl);
573 flags.addKeyListener(cl);
574 match.addKeyListener(cl);
575 name.addKeyListener(cl);
576
577 subindex_name.getDocument().addDocumentListener(new SubIndexNameDocumentListener());
578 subcollection_list_2.addListSelectionListener(new SubcollectionListSelectionListener());
579
580 // Layout
581 subindex_name_panel.setLayout(new BorderLayout());
582 subindex_name_panel.add(subindex_name_label, BorderLayout.WEST);
583 subindex_name_panel.add(subindex_name, BorderLayout.CENTER);
584
585 list_2_pane.setLayout(new BorderLayout());
586 list_2_pane.add(subcollection_label, BorderLayout.NORTH);
587 list_2_pane.add(new JScrollPane(subcollection_list_2), BorderLayout.CENTER);
588
589 subindexes_pane.setLayout(new BorderLayout());
590 subindexes_pane.add(subindexes_label, BorderLayout.NORTH);
591 subindexes_pane.add(new JScrollPane(subindexes_list), BorderLayout.CENTER);
592
593 subindex_inner_pane_2.setLayout(new GridLayout(1,2,0,5));
594 subindex_inner_pane_2.add(list_2_pane);
595 subindex_inner_pane_2.add(subindexes_pane);
596
597 default_label.setBorder(BorderFactory.createEmptyBorder(0,0,0,5));
598 default_pane.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createCompoundBorder(BorderFactory.createEmptyBorder(5,5,5,5), BorderFactory.createRaisedBevelBorder()), BorderFactory.createEmptyBorder(2,2,2,2)));
599 default_pane.setLayout(new BorderLayout());
600 default_pane.add(default_label, BorderLayout.WEST);
601 default_pane.add(default_value, BorderLayout.CENTER);
602
603 subindex_inner_pane_1.setLayout(new BorderLayout());
604 subindex_inner_pane_1.add(subindex_name_panel, BorderLayout.NORTH);
605 subindex_inner_pane_1.add(subindex_inner_pane_2, BorderLayout.CENTER);
606 subindex_inner_pane_1.add(default_pane, BorderLayout.SOUTH);
607
608 button_pane_2.setLayout(new GridLayout(2,2));
609 button_pane_2.add(add_index);
610 button_pane_2.add(remove_index);
611 button_pane_2.add(clear_default);
612 button_pane_2.add(set_default);
613
614 subindex_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
615 subindex_pane.setLayout(new BorderLayout());
616 subindex_pane.add(subindex_inner_pane_1, BorderLayout.CENTER);
617 subindex_pane.add(button_pane_2, BorderLayout.SOUTH);
618 }
619
620 private class SubIndexListCellRenderer
621 extends DefaultListCellRenderer {
622
623 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
624 StringBuffer text = new StringBuffer(value.toString());
625 // Retrieve the indexes name if any.
626 CollectionMeta metadata = manager.collectionmetadatum.getMetadata(value, manager.languages.getDefaultLanguage(), true);
627 if(metadata != null) {
628 text.append(" \"");
629 text.append(metadata.getValue());
630 text.append("\"");
631 }
632 return super.getListCellRendererComponent(list, text.toString(), index, isSelected, cellHasFocus);
633 }
634
635 }
636
637 private class SubcollectionListSelectionListener
638 implements ListSelectionListener {
639
640 public void valueChanged(ListSelectionEvent event) {
641 if(!event.getValueIsAdjusting()) {
642 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
643 }
644 }
645 }
646
647 private class SubIndexNameDocumentListener
648 implements DocumentListener {
649 /** Gives notification that an attribute or set of attributes changed. */
650 public void changedUpdate(DocumentEvent e) {
651 update();
652 }
653 /** Gives notification that there was an insert into the document. */
654 public void insertUpdate(DocumentEvent e) {
655 update();
656 }
657 /** Gives notification that a portion of the document has been removed. */
658 public void removeUpdate(DocumentEvent e) {
659 update();
660 }
661 /** 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. */
662 private void update() {
663 add_index.setEnabled(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0);
664 }
665 }
666
667 /** Method to unregister any listeners to avoid memory leaks.
668 */
669 public void destroy() {
670 }
671 /** 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.
672 * @return A <i>boolean</i> which is always <i>false</i>.
673 * @see org.greenstone.gatherer.msm.ElementWrapper
674 */
675 public boolean hasFocus() {
676 // If we have a current metadata open, and something has changed then save the change.
677 if(changed && current != null) {
678 String n = name.getText();
679 String s = null;
680 Object o = source.getSelectedItem();
681 if(o instanceof ElementWrapper) {
682 ElementWrapper e = (ElementWrapper)o;
683 s = e.toString();
684 }
685 String e = match.getText();
686 String f = flags.getText();
687 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
688 current.update(n, s, e, include.isSelected(), f);
689 int index = model.indexOf(current);
690 changed();
691 subindexes.changed();
692 if(default_index != null) {
693 default_value.setText(default_index.getSubIndex().toString());
694 }
695 }
696 changed = false;
697 }
698 return false;
699 }
700 /** Overriden to ensure the instructions are scrolled to top.
701 */
702 public void updateUI() {
703 if(instructions != null) {
704 instructions.setCaretPosition(0);
705 }
706 super.updateUI();
707 }
708 /** 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. */
709 private class AddListener
710 implements ActionListener {
711 /** 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.
712 * @param event An <strong>ActionEvent</strong> containing information about the event.
713 * @see org.greenstone.gatherer.cdm.Subcollection
714 * @see org.greenstone.gatherer.msm.ElementWrapper
715 */
716 public void actionPerformed(ActionEvent event) {
717 String n = name.getText();
718 String s = null;
719 Object o = source.getSelectedItem();
720 if(o instanceof ElementWrapper) {
721 ElementWrapper e = (ElementWrapper)o;
722 s = e.toString();
723 }
724 String e = match.getText();
725 String f = flags.getText();
726 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
727 Subcollection sub = new Subcollection(n, include.isSelected(), s, e, f);
728 addSubcollection(sub);
729 }
730 changed = false;
731 }
732 }
733 /** 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. */
734 private class AddSubIndexListener
735 implements ActionListener {
736 /** 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.
737 * @param event An <strong>ActionEvent</strong> containing information about the event.
738 * @see org.greenstone.gatherer.cdm.SubIndex
739 */
740 public void actionPerformed(ActionEvent event) {
741 if(!subcollection_list_2.isSelectionEmpty() && subindex_name.getText().length() > 0) {
742 Vector selected = new Vector();
743 Object raw[] = subcollection_list_2.getSelectedValues();
744 for(int i = 0; i < raw.length; i++) {
745 selected.add(raw[i]);
746 }
747 SubIndex subindex = new SubIndex(selected);
748 addSubIndex(subindex);
749 // Add the subindexes name.
750 CollectionMeta metadata = new CollectionMeta(manager, subindex, manager.languages.getDefaultLanguage(), subindex_name.getText());
751 manager.collectionmetadatum.addMetadata(metadata);
752 }
753 }
754 }
755 /** 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. */
756 public class ChangeListener
757 extends KeyAdapter
758 implements ActionListener {
759 /** 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.
760 * @param event An <strong>ActionEvent</strong> containing information about the event.
761 */
762 public void actionPerformed(ActionEvent event) {
763 changed = true;
764 validate();
765 }
766 /** 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.
767 * @param event An <strong>KeyEvent</strong> containing information about the event.
768 */
769 public void keyPressed(KeyEvent event) {
770 changed = true;
771 validate();
772 }
773 /** Method to validate the current editor values, and enable or disable controls based on said values. */
774 private void validate() {
775 if(changed && name.getText().length() > 0 && match.getText().length() > 0) {
776 add.setEnabled(true);
777 }
778 else {
779 add.setEnabled(false);
780 }
781 }
782 }
783 /** 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>. */
784 private class ClearDefaultListener
785 implements ActionListener {
786 /** 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.
787 * @param event An <strong>ActionEvent</strong> containing information about the event.
788 */
789 public void actionPerformed(ActionEvent event) {
790 setDefaultSubIndex(null);
791 clear_default.setEnabled(false);
792 default_value.setText("");
793 }
794 }
795 /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
796 private class ListListener
797 implements ListSelectionListener {
798 /** 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.
799 * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
800 * @see org.greenstone.gatherer.cdm.Subcollection
801 * @see org.greenstone.gatherer.msm.ElementWrapper
802 */
803 public void valueChanged(ListSelectionEvent event) {
804 // If we have a previous collection and the users changed something, but not added, then update subcollection.
805 if(changed && current != null) {
806 String n = name.getText();
807 String s = null;
808 Object o = source.getSelectedItem();
809 if(o instanceof ElementWrapper) {
810 ElementWrapper e = (ElementWrapper)o;
811 s = e.toString();
812 }
813 String e = match.getText();
814 String f = flags.getText();
815 if(n != null && n.length() > 0 && (s == null || s.length() > 0) && e != null && e.length() > 0) {
816 current.update(n, s, e, include.isSelected(), f);
817 int index = model.indexOf(current);
818 changed();
819 subindexes.changed();
820 if(default_index != null) {
821 default_value.setText(default_index.getSubIndex().toString());
822 }
823 }
824 }
825 // Now load the new entry.
826 if(!subcollection_list.isSelectionEmpty()) {
827 current = (Subcollection) subcollection_list.getSelectedValue();
828 flags.setText(current.getFlags());
829 include.setSelected(current.getInclude());
830 exclude.setSelected(!current.getInclude());
831 match.setText(current.getExpression());
832 name.setText(current.getName());
833 String s = current.getSource();
834 int pos = 0;
835 Object value = source.getItemAt(pos);
836 while(value != null) {
837 if(value instanceof ElementWrapper) {
838 ElementWrapper e = (ElementWrapper) value;
839 if(e.toString().equals(s)) {
840 source.setSelectedIndex(pos);
841 value = null;
842 }
843 else {
844 pos++;
845 value = source.getItemAt(pos);
846 }
847 }
848 else if(value.toString().equals(s)) {
849 source.setSelectedIndex(pos);
850 value = null;
851 }
852 else {
853 pos++;
854 value = source.getItemAt(pos);
855 }
856 }
857 // Can't add one thats already there.
858 add.setEnabled(false);
859 // You can remove it though...
860 remove.setEnabled(true);
861 }
862 else {
863 flags.setText("");
864 include.setSelected(true);
865 match.setText("");
866 name.setText("");
867 source.setSelectedIndex(0);
868 remove.setEnabled(false);
869 }
870 // Have to do this after so we don't get called when nothings actually changed.
871 changed = false;
872 }
873 }
874 /** 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. */
875 private class RemoveListener
876 implements ActionListener {
877 /** 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.
878 * @param event An <strong>ActionEvent</strong> containing information about the event.
879 * @see org.greenstone.gatherer.cdm.Subcollection
880 */
881 public void actionPerformed(ActionEvent event) {
882 if(!subcollection_list.isSelectionEmpty()) {
883 Subcollection sub_col = (Subcollection)subcollection_list.getSelectedValue();
884 removeSubIndexes(sub_col);
885 removeSubcollection(sub_col);
886 }
887 }
888 }
889 /** 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. */
890 private class RemoveSubIndexListener
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 subindex selected, and if so remove it.
893 * @param event An <strong>ActionEvent</strong> containing information about the event.
894 * @see org.greenstone.gatherer.cdm.SubIndex
895 */
896 public void actionPerformed(ActionEvent event) {
897 if(!subindexes_list.isSelectionEmpty()) {
898 removeSubIndex((SubIndex)subindexes_list.getSelectedValue());
899 }
900 }
901 }
902 /** 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. */
903 private class SetDefaultListener
904 implements ActionListener {
905 /** 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.
906 * @param event An <strong>ActionEvent</strong> containing information about the event.
907 * @see org.greenstone.gatherer.cdm.DefaultSubIndex
908 * @see org.greenstone.gatherer.cdm.SubIndex
909 */
910 public void actionPerformed(ActionEvent event) {
911 if(!subindexes_list.isSelectionEmpty()) {
912 setDefaultSubIndex(new DefaultSubIndex((SubIndex)subindexes_list.getSelectedValue()));
913 clear_default.setEnabled(true);
914 default_value.setText(default_index.getSubIndex().toString());
915 }
916 }
917 }
918 }
919}
920
921
922
923
924
925
926
927
928
Note: See TracBrowser for help on using the repository browser.