source: trunk/gli/src/org/greenstone/gatherer/cdm/SubcollectionIndexManager.java@ 10250

Last change on this file since 10250 was 10237, checked in by mdewsnip, 19 years ago

New code for "incremental" building, by Matthew Whyte.

I've only had time to look at this briefly; I've fixed a few obvious problems but I imagine this will be pretty flaky for a while.

  • Property svn:keywords set to Author Date Id Revision
File size: 23.0 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 * Author: John Thompson, Greenstone Digital Library, University of Waikato
9 *
10 * Copyright (C) 1999 New Zealand Digital Library Project
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 *########################################################################
26 */
27package org.greenstone.gatherer.cdm;
28
29import java.awt.*;
30import java.awt.event.*;
31import java.util.*;
32import javax.swing.*;
33import javax.swing.event.*;
34import org.greenstone.gatherer.DebugStream;
35import org.greenstone.gatherer.Dictionary;
36import org.greenstone.gatherer.Gatherer;
37import org.greenstone.gatherer.gui.GLIButton;
38import org.greenstone.gatherer.util.CheckList;
39import org.greenstone.gatherer.util.JarTools;
40import org.w3c.dom.*;
41
42
43/** This class maintains a list of indexes partitions for the purpose of defining subcollections.
44 * @author John Thompson, Greenstone Digital Library, University of Waikato
45 * @version 2.4
46 */
47public class SubcollectionIndexManager
48 extends DOMProxyListModel
49{
50 static final private Dimension FIELD_SIZE = new Dimension(200, 30);
51
52 private Control controls;
53 private DOMProxyListModel model;
54 private SubcollectionIndex default_index;
55
56
57 /** Constructor. */
58 public SubcollectionIndexManager(Element subindexes)
59 {
60 super(subindexes, CollectionConfiguration.INDEX_ELEMENT, new SubcollectionIndex());
61 DebugStream.println("SubcollectionIndexManager: " + getSize() + " subcollection indexes parsed.");
62 model = this;
63
64 // Parse and retrieve the default index
65 NodeList default_index_elements = CollectionDesignManager.collect_config.getDocumentElement().getElementsByTagName(CollectionConfiguration.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
66 if (default_index_elements.getLength() > 0) {
67 default_index = new SubcollectionIndex((Element) default_index_elements.item(0));
68 }
69 }
70
71
72 /** Method to add a subindex.
73 * @param subindex a SubcollectionIndex
74 * @see org.greenstone.gatherer.Gatherer
75 * @see org.greenstone.gatherer.collection.CollectionManager
76 */
77 private void addSubcollectionIndex(SubcollectionIndex subcollection_index)
78 {
79 if (!contains(subcollection_index)) {
80 add(getSize(), subcollection_index);
81 Gatherer.c_man.configurationChanged();
82 }
83 }
84
85
86 public void destroy()
87 {
88 if (controls != null) {
89 controls.destroy();
90 controls = null;
91 }
92 default_index = null;
93 model = null;
94 }
95
96
97 public Control getControls()
98 {
99 if (controls == null) {
100 controls = new SubcollectionIndexControls();
101 }
102 return controls;
103 }
104
105
106 /** Method to get all of the subindexes set.
107 * @return an ArrayList containing all the defined indexes
108 */
109 public ArrayList getSubcollectionIndexes()
110 {
111 return children();
112 }
113
114
115 private int moveSubcollectionIndex(SubcollectionIndex subcollection_index, boolean move_up)
116 {
117 // Determine the current position of the subcollection index
118 int position = indexOf(subcollection_index);
119 int new_position;
120
121 // Attempt to move the subcollection index up
122 if (move_up) {
123 // Check it's not already at the top
124 if (position == 0) {
125 return position;
126 }
127
128 // This automatically removes the index first, as an Element can only exist once in a particular document
129 new_position = position - 1;
130 addBefore(subcollection_index, (SubcollectionIndex) getElementAt(new_position));
131 }
132
133 // Attempt to move the subcollection index down
134 else {
135 // Check it's not already at the bottom
136 if (position == (getSize()) - 1) {
137 return position;
138 }
139
140 // This automatically removes the index first, as an Element can only exist once in a particular document
141 new_position = position + 1;
142 addAfter(subcollection_index, (SubcollectionIndex) getElementAt(new_position));
143 }
144
145 // Schedule the collection for saving
146 Gatherer.c_man.configurationChanged();
147 return new_position;
148 }
149
150
151 /** Method to remove a certain subcollection index. */
152 private void removeSubcollectionIndex(SubcollectionIndex subcollection_index)
153 {
154 if (subcollection_index != null) {
155 // Remove any current metadata from this index
156 CollectionDesignManager.collectionmeta_manager.removeMetadata("." + subcollection_index.getID());
157
158 // Check if the index removed happens to be the default index
159 if (default_index != null && default_index.equals(subcollection_index)) {
160 // If so our first solution is to set the first subcollection index to be the default
161 if (getSize() > 0) {
162 setDefaultSubcollectionIndex((SubcollectionIndex) getElementAt(0));
163 }
164 else {
165 default_index.setAssigned(false);
166 }
167 }
168
169 // Remove the index
170 remove(subcollection_index);
171 Gatherer.c_man.configurationChanged();
172 }
173 }
174
175
176 /** Method to remove all of the subindexes that contain a certain subcollection.
177 * @param subcollection the Subcollection that has been removed
178 * @see org.greenstone.gatherer.cdm.Subcollection
179 * @see org.greenstone.gatherer.cdm.SubcollectionIndex
180 */
181 public void removeSubcollectionIndexes(Subcollection subcollection)
182 {
183 String subcollection_name = subcollection.getName();
184 int size = getSize();
185 for(int i = size - 1; i >= 0; i--) {
186 SubcollectionIndex subcollection_index = (SubcollectionIndex) getElementAt(i);
187 if (subcollection_index.getSources().contains(subcollection_name)) {
188 removeSubcollectionIndex(subcollection_index);
189 }
190 }
191 }
192
193
194 /** Method to set the default subcollection index.
195 * @param index The <strong>SubcollectionIndex</strong> to use as the default index.
196 * @see org.greenstone.gatherer.Gatherer
197 * @see org.greenstone.gatherer.collection.CollectionManager
198 * @see org.greenstone.gatherer.cdm.SubcollectionIndex
199 */
200 private void setDefaultSubcollectionIndex(SubcollectionIndex subcollection_index)
201 {
202 if (subcollection_index != null) {
203 if (default_index == null) {
204 // Create the default index element, and place immediately after indexes element.
205 Element default_index_element = root.getOwnerDocument().createElement(CollectionConfiguration.SUBCOLLECTION_DEFAULT_INDEX_ELEMENT);
206 default_index = new SubcollectionIndex(default_index_element);
207 Node target_node = CollectionConfiguration.findInsertionPoint(default_index_element);
208 if (target_node != null) {
209 root.getOwnerDocument().getDocumentElement().insertBefore(default_index_element, target_node);
210 }
211 else {
212 root.getOwnerDocument().getDocumentElement().appendChild(default_index_element);
213 }
214 }
215 default_index.setAssigned(true);
216 default_index.setSources(subcollection_index.getSources());
217 }
218 else {
219 if (default_index != null) {
220 default_index.setAssigned(false);
221 }
222 }
223 Gatherer.c_man.configurationChanged();
224 }
225
226
227 /** This class creates a set of controls for editing the indexes. */
228 private class SubcollectionIndexControls
229 extends JPanel
230 implements Control
231 {
232 private CheckList source_list;
233 private JButton add_button;
234 private JButton move_down_button;
235 private JButton move_up_button;
236 private JButton remove_button;
237 private JButton replace_button;
238 private JButton set_default_button;
239 private JList subcollection_index_list;
240 private JTextField subcollection_index_name_textfield;
241
242
243 /** Constructor.
244 */
245 public SubcollectionIndexControls()
246 {
247 super();
248
249 ArrayList sources = new ArrayList();
250 ListModel source_model = CollectionDesignManager.subcollection_manager;
251 for (int i = 0; i < source_model.getSize(); i++) {
252 sources.add(source_model.getElementAt(i));
253 }
254
255 // Creation
256 JPanel assigned_indexes_pane = new JPanel();
257 JLabel index_label = new JLabel();
258 Dictionary.registerText(index_label, "CDM.SubcollectionIndexManager.Subindexes");
259 subcollection_index_list = new JList(model);
260 subcollection_index_list.setCellRenderer(new SubcollectionIndexListCellRenderer());
261 subcollection_index_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
262 subcollection_index_list.setVisibleRowCount(2);
263
264 JPanel movement_pane = new JPanel();
265 move_up_button = new JButton("", JarTools.getImage("arrow-up.gif"));
266 move_up_button.setEnabled(false);
267 move_up_button.setMnemonic(KeyEvent.VK_U);
268 Dictionary.registerBoth(move_up_button, "CDM.Move.Move_Up", "CDM.Move.Move_Up_Tooltip");
269
270 move_down_button = new JButton("", JarTools.getImage("arrow-down.gif"));
271 move_down_button.setEnabled(false);
272 move_down_button.setMnemonic(KeyEvent.VK_D);
273 Dictionary.registerBoth(move_down_button, "CDM.Move.Move_Down", "CDM.Move.Move_Down_Tooltip");
274
275 set_default_button = new GLIButton();
276 set_default_button.setEnabled(false);
277 set_default_button.setMnemonic(KeyEvent.VK_S);
278 Dictionary.registerBoth(set_default_button, "CDM.SubcollectionIndexManager.Set_Default_Subindex", "CDM.SubcollectionIndexManager.Set_Default_Subindex_Tooltip");
279
280 JPanel index_pane = new JPanel();
281 JPanel details_pane = new JPanel();
282 JPanel labels_pane = new JPanel();
283 JPanel boxes_pane = new JPanel();
284 JPanel content_pane = new JPanel();
285
286 JLabel name_label = new JLabel();
287 Dictionary.registerText(name_label, "CDM.SubcollectionIndexManager.PartitionName");
288 subcollection_index_name_textfield = new JTextField();
289 subcollection_index_name_textfield.setPreferredSize(FIELD_SIZE);
290 Dictionary.registerTooltip(subcollection_index_name_textfield, "CDM.SubcollectionIndexManager.PartitionName_Tooltip");
291
292 JLabel source_label = new JLabel();
293 Dictionary.registerText(source_label, "CDM.SubcollectionIndexManager.Source");
294 source_list = new CheckList(false);
295 source_list.setListData(sources);
296 Dictionary.registerTooltip(source_list, "CDM.SubcollectionIndexManager.Source_Tooltip");
297
298 JPanel button_pane = new JPanel();
299 add_button = new GLIButton();
300 add_button.setEnabled(false);
301 add_button.setMnemonic(KeyEvent.VK_A);
302 Dictionary.registerBoth(add_button, "CDM.SubcollectionIndexManager.Add_Subindex", "CDM.SubcollectionIndexManager.Add_Subindex_Tooltip");
303
304 remove_button = new GLIButton();
305 remove_button.setEnabled(false);
306 remove_button.setMnemonic(KeyEvent.VK_R);
307 Dictionary.registerBoth(remove_button, "CDM.SubcollectionIndexManager.Remove_Subindex", "CDM.SubcollectionIndexManager.Remove_Subindex_Tooltip");
308
309 replace_button = new GLIButton();
310 replace_button.setEnabled(false);
311 replace_button.setMnemonic(KeyEvent.VK_P);
312 Dictionary.registerBoth(replace_button, "CDM.SubcollectionIndexManager.Replace_Subindex", "CDM.SubcollectionIndexManager.Replace_Subindex_Tooltip");
313
314 // Listeners
315 add_button.addActionListener(new AddListener());
316 add_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
317 move_down_button.addActionListener(new MoveListener(false));
318 move_down_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
319 move_up_button.addActionListener(new MoveListener(true));
320 move_up_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
321 remove_button.addActionListener(new RemoveListener());
322 remove_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
323 replace_button.addActionListener(new ReplaceListener());
324 replace_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
325 set_default_button.addActionListener(new SetDefaultListener());
326 set_default_button.addActionListener(CollectionDesignManager.buildcol_change_listener);
327 subcollection_index_name_textfield.getDocument().addDocumentListener(new NameListener());
328 subcollection_index_list.addListSelectionListener(new SubcollectionIndexListListener());
329 source_list.addListSelectionListener(new SourceListListener());
330
331 // Layout
332 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
333 movement_pane.setLayout(new GridLayout(3,1));
334 movement_pane.add(move_up_button);
335 movement_pane.add(move_down_button);
336 movement_pane.add(set_default_button);
337
338 assigned_indexes_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
339 assigned_indexes_pane.setLayout(new BorderLayout());
340 assigned_indexes_pane.add(index_label, BorderLayout.NORTH);
341 assigned_indexes_pane.add(new JScrollPane(subcollection_index_list), BorderLayout.CENTER);
342 assigned_indexes_pane.add(movement_pane, BorderLayout.EAST);
343
344 labels_pane.setLayout(new BorderLayout());
345 labels_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
346 labels_pane.add(name_label, BorderLayout.NORTH);
347 labels_pane.add(source_label, BorderLayout.CENTER);
348
349 boxes_pane.setLayout(new BorderLayout());
350 boxes_pane.add(subcollection_index_name_textfield, BorderLayout.NORTH);
351 boxes_pane.add(new JScrollPane(source_list), BorderLayout.CENTER);
352
353 details_pane.setLayout(new BorderLayout());
354 details_pane.add(labels_pane, BorderLayout.WEST);
355 details_pane.add(boxes_pane, BorderLayout.CENTER);
356
357 button_pane.setLayout(new GridLayout(1,3));
358 button_pane.add(add_button);
359 button_pane.add(replace_button);
360 button_pane.add(remove_button);
361
362 index_pane.setLayout(new BorderLayout());
363 index_pane.add(details_pane, BorderLayout.CENTER);
364 index_pane.add(button_pane, BorderLayout.SOUTH);
365
366 content_pane.setLayout(new BorderLayout());
367 content_pane.add(assigned_indexes_pane, BorderLayout.NORTH);
368 content_pane.add(index_pane, BorderLayout.CENTER);
369
370 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
371 setLayout(new BorderLayout());
372 add(content_pane, BorderLayout.CENTER);
373 }
374
375
376 public void destroy()
377 {
378 }
379
380
381 public void gainFocus()
382 {
383 // Reload the source list
384 ArrayList sources = new ArrayList();
385 ListModel source_model = CollectionDesignManager.subcollection_manager;
386 for (int i = 0; i < source_model.getSize(); i++) {
387 sources.add(source_model.getElementAt(i));
388 }
389 source_list.setListData(sources);
390
391 // Refresh the subcollection index list
392 subcollection_index_list.updateUI();
393
394 // If there is one selected, fill in the controls
395 updateControlsWithSelectedIndex();
396 }
397
398
399 public void loseFocus()
400 {
401 }
402
403
404 private void updateControlsWithSelectedIndex()
405 {
406 SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
407 if (selected_index == null) {
408 return;
409 }
410
411 // Display the selected subcollection index's name
412 String id = selected_index.getID();
413 String name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + id).getValue(true);
414 subcollection_index_name_textfield.setText(name);
415
416 // Display the selected subcollection index's sources
417 source_list.clearTicked();
418 source_list.setTickedObjects(selected_index.getSources().toArray());
419 }
420
421
422 private void validateControls()
423 {
424 boolean add_enabled = false;
425 boolean replace_enabled = false;
426
427 // Indexes must have a name
428 if (subcollection_index_name_textfield.getText().length() == 0) {
429 add_enabled = false;
430 }
431 // Can't add a new index if no sources are selected
432 else if (source_list.isNothingTicked()) {
433 add_enabled = false;
434 }
435 // If we get this far, create a dummy index and see if it's already assigned in the collection
436 else {
437 ArrayList sources = source_list.getTicked();
438 SubcollectionIndex subcollection_index = new SubcollectionIndex(sources.toArray());
439
440 // Subcollection index already exists: can't add, but can replace if the name has changed
441 if (model.contains(subcollection_index)) {
442 add_enabled = false;
443
444 // Here we need to check if we have changed the name - if so, we can enable the replace button
445 if (subcollection_index_list.getSelectedIndex() != -1) {
446 String name = subcollection_index_name_textfield.getText();
447 SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
448 String selected_name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + selected_index.getID()).getValue(true);
449 if (!name.equals(selected_name)) {
450 replace_enabled = true;
451 }
452 }
453 }
454
455 // Subcollection index doesn't already exist: can add, or replace if there is something selected
456 else {
457 add_enabled = true;
458 if (subcollection_index_list.getSelectedIndex() != -1) {
459 replace_enabled = true;
460 }
461 }
462 }
463
464 // We should now know the add_button state
465 add_button.setEnabled(add_enabled);
466 replace_button.setEnabled(replace_enabled);
467 }
468
469
470 private class AddListener
471 implements ActionListener
472 {
473 public void actionPerformed(ActionEvent event)
474 {
475 String name = subcollection_index_name_textfield.getText();
476 if (!source_list.isNothingTicked() && name.length() != 0) {
477 ArrayList sources = source_list.getTicked();
478 SubcollectionIndex subcollection_index = new SubcollectionIndex(sources.toArray());
479
480 // Before we add the index to the model, we have to add the collection metadata for this
481 CollectionMeta metadatum = new CollectionMeta("." + subcollection_index.getID());
482 metadatum.setValue(name);
483 CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
484
485 // Finally, add the subcollection index
486 addSubcollectionIndex(subcollection_index);
487 subcollection_index_list.setSelectedIndex(model.getSize() - 1);
488 }
489 }
490 }
491
492
493 private class MoveListener
494 implements ActionListener
495 {
496 private boolean move_up;
497
498 public MoveListener(boolean move_up)
499 {
500 this.move_up = move_up;
501 }
502
503 public void actionPerformed(ActionEvent event)
504 {
505 // Retrieve the selected subcollection index
506 SubcollectionIndex subcollection_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
507 if (subcollection_index != null) {
508 int new_position = moveSubcollectionIndex(subcollection_index, move_up);
509 // Ensure the subcollection index that moved is still selected
510 subcollection_index_list.setSelectedIndex(new_position);
511 }
512 }
513 }
514
515
516 /** Listens for key presses within the name field, and enabled or disables controls as appropriate. */
517 private class NameListener
518 implements DocumentListener
519 {
520 public void changedUpdate(DocumentEvent e)
521 {
522 validateControls();
523 }
524
525 public void insertUpdate(DocumentEvent e)
526 {
527 validateControls();
528 }
529
530 public void removeUpdate(DocumentEvent e)
531 {
532 validateControls();
533 }
534 }
535
536
537 private class RemoveListener
538 implements ActionListener
539 {
540 public void actionPerformed(ActionEvent event)
541 {
542 int i = subcollection_index_list.getSelectedIndex();
543 if (i != -1) {
544 removeSubcollectionIndex((SubcollectionIndex) subcollection_index_list.getSelectedValue());
545 }
546
547 int size = subcollection_index_list.getModel().getSize();
548 if (i == size) {
549 i--;
550 }
551 subcollection_index_list.setSelectedIndex(i);
552 validateControls();
553 }
554 }
555
556
557 private class ReplaceListener
558 implements ActionListener
559 {
560 public void actionPerformed(ActionEvent event)
561 {
562 if (subcollection_index_list.isSelectionEmpty()) {
563 // This should never happen, but just in case...
564 replace_button.setEnabled(false);
565 return;
566 }
567
568 // We'll just remove the old one and add the new one
569 removeSubcollectionIndex((SubcollectionIndex) subcollection_index_list.getSelectedValue());
570 replace_button.setEnabled(false);
571 add_button.setEnabled(true);
572 add_button.doClick();
573 add_button.setEnabled(false);
574 }
575 }
576
577
578 private class SetDefaultListener
579 implements ActionListener
580 {
581 public void actionPerformed(ActionEvent event)
582 {
583 SubcollectionIndex subcollection_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
584 if (subcollection_index != null) {
585 setDefaultSubcollectionIndex(subcollection_index);
586 // This should cause a repaint of just the desired row
587 subcollection_index_list.setSelectedValue(subcollection_index, true);
588 }
589 set_default_button.setEnabled(false);
590 }
591 }
592
593
594 private class SourceListListener
595 implements ListSelectionListener
596 {
597 public void valueChanged(ListSelectionEvent event)
598 {
599 validateControls();
600 }
601 }
602
603
604 /** Listens for selections within the list on the SubcollectionIndexManager controls, and if a change is detected enables, or disables, controls appropriately. */
605 private class SubcollectionIndexListListener
606 implements ListSelectionListener
607 {
608 /** This method is called whenever the source list selection changes. When it does we need to fill in the various parts of the list description panel
609 * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
610 */
611 public void valueChanged(ListSelectionEvent event)
612 {
613 if (event.getValueIsAdjusting()) {
614 return;
615 }
616
617 int i = subcollection_index_list.getSelectedIndex();
618 int size = subcollection_index_list.getModel().getSize();
619 if (i < 0 || i >= size) {
620 move_down_button.setEnabled(false);
621 move_up_button.setEnabled(false);
622 remove_button.setEnabled(false);
623 replace_button.setEnabled(false);
624 set_default_button.setEnabled(false);
625 return;
626 }
627
628 // Enable the buttons appropriately
629 remove_button.setEnabled(true);
630 SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
631 set_default_button.setEnabled(default_index == null || !default_index.equals(selected_index));
632 if (i > 0) {
633 move_up_button.setEnabled(true);
634 }
635 else {
636 move_up_button.setEnabled(false);
637 }
638 if (i < size-1){
639 move_down_button.setEnabled(true);
640 }
641 else {
642 move_down_button.setEnabled(false);
643 }
644
645 // Need to fill in the rest of the bits
646 updateControlsWithSelectedIndex();
647 }
648 }
649
650
651 private class SubcollectionIndexListCellRenderer
652 extends DefaultListCellRenderer
653 {
654 /** Return a component that has been configured to display the specified value. */
655 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
656 JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
657 if (default_index != null && default_index.equals(value)) {
658 component.setText(component.getText() + " " + Dictionary.get("CDM.SubcollectionIndexManager.Default_Partition_Indicator"));
659 }
660 return component;
661 }
662 }
663 }
664}
Note: See TracBrowser for help on using the repository browser.