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

Last change on this file since 9645 was 9562, checked in by kjdon, 19 years ago

made the move up and down buttons disabled to start with - cos nothing is initially selected in the list

  • Property svn:keywords set to Author Date Id Revision
File size: 22.5 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.Utility;
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("", Utility.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("", Utility.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 move_down_button.addActionListener(new MoveListener(false));
317 move_up_button.addActionListener(new MoveListener(true));
318 remove_button.addActionListener(new RemoveListener());
319 replace_button.addActionListener(new ReplaceListener());
320 set_default_button.addActionListener(new SetDefaultListener());
321 subcollection_index_name_textfield.getDocument().addDocumentListener(new NameListener());
322 subcollection_index_list.addListSelectionListener(new SubcollectionIndexListListener());
323 source_list.addListSelectionListener(new SourceListListener());
324
325 // Layout
326 movement_pane.setBorder(BorderFactory.createEmptyBorder(0,2,0,0));
327 movement_pane.setLayout(new GridLayout(3,1));
328 movement_pane.add(move_up_button);
329 movement_pane.add(move_down_button);
330 movement_pane.add(set_default_button);
331
332 assigned_indexes_pane.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
333 assigned_indexes_pane.setLayout(new BorderLayout());
334 assigned_indexes_pane.add(index_label, BorderLayout.NORTH);
335 assigned_indexes_pane.add(new JScrollPane(subcollection_index_list), BorderLayout.CENTER);
336 assigned_indexes_pane.add(movement_pane, BorderLayout.EAST);
337
338 labels_pane.setLayout(new BorderLayout());
339 labels_pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 10, 5));
340 labels_pane.add(name_label, BorderLayout.NORTH);
341 labels_pane.add(source_label, BorderLayout.CENTER);
342
343 boxes_pane.setLayout(new BorderLayout());
344 boxes_pane.add(subcollection_index_name_textfield, BorderLayout.NORTH);
345 boxes_pane.add(new JScrollPane(source_list), BorderLayout.CENTER);
346
347 details_pane.setLayout(new BorderLayout());
348 details_pane.add(labels_pane, BorderLayout.WEST);
349 details_pane.add(boxes_pane, BorderLayout.CENTER);
350
351 button_pane.setLayout(new GridLayout(1,3));
352 button_pane.add(add_button);
353 button_pane.add(replace_button);
354 button_pane.add(remove_button);
355
356 index_pane.setLayout(new BorderLayout());
357 index_pane.add(details_pane, BorderLayout.CENTER);
358 index_pane.add(button_pane, BorderLayout.SOUTH);
359
360 content_pane.setLayout(new BorderLayout());
361 content_pane.add(assigned_indexes_pane, BorderLayout.NORTH);
362 content_pane.add(index_pane, BorderLayout.CENTER);
363
364 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
365 setLayout(new BorderLayout());
366 add(content_pane, BorderLayout.CENTER);
367 }
368
369
370 public void destroy()
371 {
372 }
373
374
375 public void gainFocus()
376 {
377 // Reload the source list
378 ArrayList sources = new ArrayList();
379 ListModel source_model = CollectionDesignManager.subcollection_manager;
380 for (int i = 0; i < source_model.getSize(); i++) {
381 sources.add(source_model.getElementAt(i));
382 }
383 source_list.setListData(sources);
384
385 // Refresh the subcollection index list
386 subcollection_index_list.updateUI();
387
388 // If there is one selected, fill in the controls
389 updateControlsWithSelectedIndex();
390 }
391
392
393 public void loseFocus()
394 {
395 }
396
397
398 private void updateControlsWithSelectedIndex()
399 {
400 SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
401 if (selected_index == null) {
402 return;
403 }
404
405 // Display the selected subcollection index's name
406 String id = selected_index.getID();
407 String name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + id).getValue(true);
408 subcollection_index_name_textfield.setText(name);
409
410 // Display the selected subcollection index's sources
411 source_list.clearTicked();
412 source_list.setTickedObjects(selected_index.getSources().toArray());
413 }
414
415
416 private void validateControls()
417 {
418 boolean add_enabled = false;
419 boolean replace_enabled = false;
420
421 // Indexes must have a name
422 if (subcollection_index_name_textfield.getText().length() == 0) {
423 add_enabled = false;
424 }
425 // Can't add a new index if no sources are selected
426 else if (source_list.isNothingTicked()) {
427 add_enabled = false;
428 }
429 // If we get this far, create a dummy index and see if it's already assigned in the collection
430 else {
431 ArrayList sources = source_list.getTicked();
432 SubcollectionIndex subcollection_index = new SubcollectionIndex(sources.toArray());
433
434 // Subcollection index already exists: can't add, but can replace if the name has changed
435 if (model.contains(subcollection_index)) {
436 add_enabled = false;
437
438 // Here we need to check if we have changed the name - if so, we can enable the replace button
439 if (subcollection_index_list.getSelectedIndex() != -1) {
440 String name = subcollection_index_name_textfield.getText();
441 SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
442 String selected_name = CollectionDesignManager.collectionmeta_manager.getMetadatum("." + selected_index.getID()).getValue(true);
443 if (!name.equals(selected_name)) {
444 replace_enabled = true;
445 }
446 }
447 }
448
449 // Subcollection index doesn't already exist: can add, or replace if there is something selected
450 else {
451 add_enabled = true;
452 if (subcollection_index_list.getSelectedIndex() != -1) {
453 replace_enabled = true;
454 }
455 }
456 }
457
458 // We should now know the add_button state
459 add_button.setEnabled(add_enabled);
460 replace_button.setEnabled(replace_enabled);
461 }
462
463
464 private class AddListener
465 implements ActionListener
466 {
467 public void actionPerformed(ActionEvent event)
468 {
469 String name = subcollection_index_name_textfield.getText();
470 if (!source_list.isNothingTicked() && name.length() != 0) {
471 ArrayList sources = source_list.getTicked();
472 SubcollectionIndex subcollection_index = new SubcollectionIndex(sources.toArray());
473
474 // Before we add the index to the model, we have to add the collection metadata for this
475 CollectionMeta metadatum = new CollectionMeta("." + subcollection_index.getID());
476 metadatum.setValue(name);
477 CollectionDesignManager.collectionmeta_manager.addMetadatum(metadatum);
478
479 // Finally, add the subcollection index
480 addSubcollectionIndex(subcollection_index);
481 subcollection_index_list.setSelectedIndex(model.getSize() - 1);
482 }
483 }
484 }
485
486
487 private class MoveListener
488 implements ActionListener
489 {
490 private boolean move_up;
491
492 public MoveListener(boolean move_up)
493 {
494 this.move_up = move_up;
495 }
496
497 public void actionPerformed(ActionEvent event)
498 {
499 // Retrieve the selected subcollection index
500 SubcollectionIndex subcollection_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
501 if (subcollection_index != null) {
502 int new_position = moveSubcollectionIndex(subcollection_index, move_up);
503 // Ensure the subcollection index that moved is still selected
504 subcollection_index_list.setSelectedIndex(new_position);
505 }
506 }
507 }
508
509
510 /** Listens for key presses within the name field, and enabled or disables controls as appropriate. */
511 private class NameListener
512 implements DocumentListener
513 {
514 public void changedUpdate(DocumentEvent e)
515 {
516 validateControls();
517 }
518
519 public void insertUpdate(DocumentEvent e)
520 {
521 validateControls();
522 }
523
524 public void removeUpdate(DocumentEvent e)
525 {
526 validateControls();
527 }
528 }
529
530
531 private class RemoveListener
532 implements ActionListener
533 {
534 public void actionPerformed(ActionEvent event)
535 {
536 int i = subcollection_index_list.getSelectedIndex();
537 if (i != -1) {
538 removeSubcollectionIndex((SubcollectionIndex) subcollection_index_list.getSelectedValue());
539 }
540
541 int size = subcollection_index_list.getModel().getSize();
542 if (i == size) {
543 i--;
544 }
545 subcollection_index_list.setSelectedIndex(i);
546 validateControls();
547 }
548 }
549
550
551 private class ReplaceListener
552 implements ActionListener
553 {
554 public void actionPerformed(ActionEvent event)
555 {
556 if (subcollection_index_list.isSelectionEmpty()) {
557 // This should never happen, but just in case...
558 replace_button.setEnabled(false);
559 return;
560 }
561
562 // We'll just remove the old one and add the new one
563 removeSubcollectionIndex((SubcollectionIndex) subcollection_index_list.getSelectedValue());
564 replace_button.setEnabled(false);
565 add_button.setEnabled(true);
566 add_button.doClick();
567 add_button.setEnabled(false);
568 }
569 }
570
571
572 private class SetDefaultListener
573 implements ActionListener
574 {
575 public void actionPerformed(ActionEvent event)
576 {
577 SubcollectionIndex subcollection_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
578 if (subcollection_index != null) {
579 setDefaultSubcollectionIndex(subcollection_index);
580 // This should cause a repaint of just the desired row
581 subcollection_index_list.setSelectedValue(subcollection_index, true);
582 }
583 set_default_button.setEnabled(false);
584 }
585 }
586
587
588 private class SourceListListener
589 implements ListSelectionListener
590 {
591 public void valueChanged(ListSelectionEvent event)
592 {
593 validateControls();
594 }
595 }
596
597
598 /** Listens for selections within the list on the SubcollectionIndexManager controls, and if a change is detected enables, or disables, controls appropriately. */
599 private class SubcollectionIndexListListener
600 implements ListSelectionListener
601 {
602 /** 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
603 * @param event A <strong>ListSelectionEvent</strong> containing further information about the list selection.
604 */
605 public void valueChanged(ListSelectionEvent event)
606 {
607 if (event.getValueIsAdjusting()) {
608 return;
609 }
610
611 int i = subcollection_index_list.getSelectedIndex();
612 int size = subcollection_index_list.getModel().getSize();
613 if (i < 0 || i >= size) {
614 move_down_button.setEnabled(false);
615 move_up_button.setEnabled(false);
616 remove_button.setEnabled(false);
617 replace_button.setEnabled(false);
618 set_default_button.setEnabled(false);
619 return;
620 }
621
622 // Enable the buttons appropriately
623 remove_button.setEnabled(true);
624 SubcollectionIndex selected_index = (SubcollectionIndex) subcollection_index_list.getSelectedValue();
625 set_default_button.setEnabled(default_index == null || !default_index.equals(selected_index));
626 if (i > 0) {
627 move_up_button.setEnabled(true);
628 }
629 else {
630 move_up_button.setEnabled(false);
631 }
632 if (i < size-1){
633 move_down_button.setEnabled(true);
634 }
635 else {
636 move_down_button.setEnabled(false);
637 }
638
639 // Need to fill in the rest of the bits
640 updateControlsWithSelectedIndex();
641 }
642 }
643
644
645 private class SubcollectionIndexListCellRenderer
646 extends DefaultListCellRenderer
647 {
648 /** Return a component that has been configured to display the specified value. */
649 public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
650 JLabel component = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
651 if (default_index != null && default_index.equals(value)) {
652 component.setText(component.getText() + " " + Dictionary.get("CDM.SubcollectionIndexManager.Default_Partition_Indicator"));
653 }
654 return component;
655 }
656 }
657 }
658}
Note: See TracBrowser for help on using the repository browser.