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

Last change on this file since 8231 was 8231, checked in by mdewsnip, 20 years ago

Replaced all "Gatherer.config" with "Configuration".

  • Property svn:keywords set to Author Date Id Revision
File size: 23.7 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
29/**************************************************************************************
30 * Written: ??/??/02
31 * Revised: 04/07/03 - DOM support
32 **************************************************************************************/
33import java.awt.*;
34import java.awt.event.*;
35import java.util.*;
36import javax.swing.*;
37import javax.swing.event.*;
38import org.greenstone.gatherer.Configuration;
39import org.greenstone.gatherer.Dictionary;
40import org.greenstone.gatherer.Gatherer;
41import org.greenstone.gatherer.cdm.CollectionConfiguration;
42import org.greenstone.gatherer.cdm.CollectionDesignManager;
43import org.greenstone.gatherer.cdm.Control;
44import org.greenstone.gatherer.cdm.DOMProxyListModel;
45import org.greenstone.gatherer.cdm.Subcollection;
46import org.greenstone.gatherer.gui.GLIButton;
47import org.greenstone.gatherer.gui.NonWhitespaceField;
48import org.greenstone.gatherer.msm.ElementWrapper;
49import org.greenstone.gatherer.util.ExclusiveListSelectionListener;
50import org.greenstone.gatherer.util.StaticStrings;
51import org.greenstone.gatherer.util.Utility;
52import org.w3c.dom.*;
53
54/** This class maintains a list of subcollections within our collection.
55 * @author John Thompson, Greenstone Digital Library, University of Waikato
56 * @version 2.4
57 */
58public class SubcollectionManager
59 extends DOMProxyListModel {
60
61 static final private String DISABLED_CONTROLS = "Disabled";
62 static final private String ENABLED_CONTROLS = "Normal";
63 static final private String CLASS_DICTIONARY_NAME = "CDM.SubcollectionManager.";
64
65 /** The controls used to edit the settings of this manager. */
66 private Control controls = null;
67
68 private DOMProxyListModel model;
69
70 /** Constructor.
71 * @see org.greenstone.gatherer.Gatherer
72 * @see org.greenstone.gatherer.cdm.CollectionConfiguration
73 * @see org.greenstone.gatherer.cdm.CollectionDesignManager
74 * @see org.greenstone.gatherer.cdm.DOMProxyListModel
75 * @see org.greenstone.gatherer.cdm.Subcollection
76 */
77 public SubcollectionManager() {
78 super(CollectionDesignManager.collect_config.getDocumentElement(), StaticStrings.SUBCOLLECTION_ELEMENT, new Subcollection());
79 Gatherer.println("SubcollectionManager: " + getSize() + " subcollections parsed.");
80 this.model = this;
81 }
82
83 /** Method to add a new subcollection.
84 * @param subcollection the Subcollection to add
85 * @see org.greenstone.gatherer.Gatherer
86 * @see org.greenstone.gatherer.cdm.CollectionConfiguration
87 * @see org.greenstone.gatherer.cdm.DOMProxyListModel
88 * @see org.greenstone.gatherer.collection.CollectionManager
89 */
90 private void addSubcollection(Subcollection subcollection) {
91 if(!contains(subcollection)) {
92 Element element = subcollection.getElement();
93 // Locate where we should insert this new subcollection.
94 Node target_node = CollectionConfiguration.findInsertionPoint(element);
95 // Failing that we insert immediately after a language string
96 add(root, subcollection, target_node);
97 Gatherer.c_man.configurationChanged();
98 }
99 }
100
101 public void destroy() {
102 if(controls != null) {
103 controls.destroy();
104 controls = null;
105 }
106 }
107
108 /** Method to retrieve the controls for this manager.
109 * @return the Control used to edit the subcollection data
110 */
111 public Control getControls() {
112 if(controls == null) {
113 controls = new SubcollectionControl();
114 }
115 return controls;
116 }
117
118 /** Method to retrieve a certain subcollection by its name.
119 * @param name a String which is used as the key for finding the matching subcollection
120 * @return the requested Subcollection or null if no such subcollection exists.
121 */
122 private Subcollection getSubcollection(String name) {
123 Subcollection result = null;
124 int size = getSize();
125 for(int i = 0; i < size; i++) {
126 Subcollection subcollection = (Subcollection) getElementAt(i);
127 if(subcollection.getName().equals(name)) {
128 result = subcollection;
129 }
130 }
131 return result;
132 }
133
134
135 /** Called when the detail mode has changed which in turn may cause several design elements to be available/hidden
136 * @param mode the new mode as an int
137 */
138 public void modeChanged(int mode) {
139 if(controls != null) {
140 ((SubcollectionControl)controls).modeChanged(mode);
141 }
142 }
143
144 /** Method to remove the given subcollection.
145 * @param subcollection the Subcollection you want to remove
146 * @see org.greenstone.gatherer.Gatherer
147 * @see org.greenstone.gatherer.collection.CollectionManager
148 */
149 private void removeSubcollection(Subcollection subcollection) {
150 remove(subcollection);
151 Gatherer.c_man.configurationChanged();
152 }
153
154 private void updateSubcollection(Subcollection subcollection, String name, boolean include, String source, String pattern, String flags) {
155 subcollection.setFlags(flags);
156 subcollection.setInclusive(include);
157 subcollection.setName(name);
158 subcollection.setPattern(pattern);
159 subcollection.setSource(source);
160 refresh(subcollection);
161 Gatherer.c_man.configurationChanged();
162 }
163
164 /** This class creates a JPanel containing serveral more controls used for editing subcollection information. */
165 private class SubcollectionControl
166 extends JPanel
167 implements Control {
168
169 private CardLayout card_layout;
170 private JButton add_button;
171 private JButton remove_button;
172 private JButton update_button;
173 private JComboBox source_combobox;
174 private JList subcollection_list;
175 private JPanel border_pane;
176 private JTabbedPane tabbed_pane;
177 private JTextArea instructions_area;
178 private JTextField flags_field;
179 private JTextField match_field;
180 private JTextField name_field;
181 private JRadioButton exclude_button;
182 private JRadioButton include_button;
183
184 /** Constructor */
185 public SubcollectionControl() {
186 // Create
187 JPanel header_pane = new JPanel();
188 instructions_area = new JTextArea();
189 instructions_area.setEditable(false);
190 instructions_area.setLineWrap(true);
191 instructions_area.setRows(6);
192 instructions_area.setWrapStyleWord(true);
193 Dictionary.registerText(instructions_area, "CDM.SubcollectionManager.Instructions");
194
195 border_pane = new JPanel();
196 card_layout = new CardLayout();
197
198 tabbed_pane = new JTabbedPane();
199 JLabel title = new JLabel();
200 title.setHorizontalAlignment(JLabel.CENTER);
201 Dictionary.registerText(title, "CDM.SubcollectionManager.Title");
202
203 JPanel button_pane_3 = new JPanel();
204 add_button = new GLIButton();
205 add_button.setMnemonic(KeyEvent.VK_A);
206 add_button.setEnabled(false);
207 Dictionary.registerBoth(add_button, "CDM.SubcollectionManager.Add", "CDM.SubcollectionManager.Add_Tooltip");
208 remove_button = new GLIButton();
209 remove_button.setMnemonic(KeyEvent.VK_R);
210 remove_button.setEnabled(false);
211 Dictionary.registerBoth(remove_button, "CDM.SubcollectionManager.Remove", "CDM.SubcollectionManager.Remove_Tooltip");
212 update_button = new GLIButton();
213 update_button.setMnemonic(KeyEvent.VK_C);
214 update_button.setEnabled(false);
215 Dictionary.registerBoth(update_button, "CDM.SubcollectionManager.Replace", "CDM.SubcollectionManager.Replace_Tooltip");
216
217 JPanel button_pane = new JPanel();
218 JPanel button_pane_1 = new JPanel();
219 include_button = new JRadioButton();
220 include_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
221 include_button.setMnemonic(KeyEvent.VK_I);
222 include_button.setOpaque(false);
223 Dictionary.registerText(include_button, "CDM.SubcollectionManager.Include");
224 exclude_button = new JRadioButton();
225 exclude_button.setBackground(Configuration.getColor("coloring.collection_tree_background", false));
226 exclude_button.setMnemonic(KeyEvent.VK_X);
227 exclude_button.setOpaque(false);
228 Dictionary.registerText(exclude_button, "CDM.SubcollectionManager.Exclude");
229
230 JLabel flags_label = new JLabel();
231 Dictionary.registerText(flags_label, "CDM.SubcollectionManager.Flags");
232 flags_field = new NonWhitespaceField();
233 Dictionary.registerTooltip(flags_field, "CDM.SubcollectionManager.Flags_Tooltip");
234
235 JPanel inclusive_pane = new JPanel();
236 JLabel inclusive_label = new JLabel();
237 Dictionary.registerText(inclusive_label, "CDM.SubcollectionManager.Inclusive");
238
239 JLabel match_label = new JLabel();
240 Dictionary.registerText(match_label, "CDM.SubcollectionManager.Match");
241 match_field = new JTextField();
242 Dictionary.registerTooltip(match_field, "CDM.SubcollectionManager.Match_Tooltip");
243
244 JLabel name_label = new JLabel();
245 Dictionary.registerText(name_label, "CDM.SubcollectionManager.Name");
246 name_field = new NonWhitespaceField();
247 Dictionary.registerTooltip(name_field, "CDM.SubcollectionManager.Name_Tooltip");
248
249 JLabel source_label = new JLabel();
250 Dictionary.registerText(source_label, "CDM.SubcollectionManager.Source");
251 Vector source_model = Gatherer.c_man.getCollection().msm.getAssignedElements();
252 source_model.add(0, StaticStrings.FILENAME_STR);
253 source_combobox = new JComboBox(source_model);
254 Dictionary.registerTooltip(source_combobox, "CDM.SubcollectionManager.Source_Tooltip");
255
256 subcollection_list = new JList(model);
257 subcollection_list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
258 JPanel subcollection_pane = new JPanel();
259 ButtonGroup bg = new ButtonGroup();
260 bg.add(include_button);
261 bg.add(exclude_button);
262 include_button.setSelected(true);
263 JPanel subcollection_list_pane = new JPanel();
264 JLabel subcollection_list_label = new JLabel();
265 Dictionary.registerText(subcollection_list_label, "CDM.SubcollectionManager.Assigned");
266
267 // Create a message pane which explains why these controls are not currently active
268 JPanel message_pane = new JPanel();
269 String args[] = new String[3];
270 args[0] = Configuration.getModeAsString();
271 args[1] = Dictionary.get("Preferences.Mode.Systems");
272 args[2] = Dictionary.get("Preferences.Mode.Expert");
273 JTextArea message_textarea = new JTextArea();
274 Dictionary.registerText(message_textarea, "CDM.SubcollectionManager.Partitions_Disabled", args);
275 message_textarea.setEditable(false);
276 message_textarea.setHighlighter(null); // Prevent highlighting
277 message_textarea.setLineWrap(true);
278 message_textarea.setOpaque(false); // Make it transparent
279 message_textarea.setWrapStyleWord(true);
280
281 // Add listeners
282 SubCollectionChangeListener cl = new SubCollectionChangeListener();
283 add_button.addActionListener(new AddSubCollectionListener());
284 remove_button.addActionListener(new RemoveSubCollectionListener());
285 update_button.addActionListener(new UpdateSubCollectionListener());
286 exclude_button.addActionListener(cl);
287 include_button.addActionListener(cl);
288 source_combobox.addActionListener(cl);
289 flags_field.getDocument().addDocumentListener(cl);
290 match_field.getDocument().addDocumentListener(cl);
291 name_field.getDocument().addDocumentListener(cl);
292 subcollection_list.addListSelectionListener(new SubCollectionListListener());
293
294 // Layout
295 instructions_area.setBorder(BorderFactory.createEmptyBorder(2,5,2,5));
296
297 header_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
298 header_pane.setLayout(new BorderLayout());
299 header_pane.add(title, BorderLayout.NORTH);
300 header_pane.add(new JScrollPane(instructions_area), BorderLayout.CENTER);
301
302 inclusive_pane.setLayout(new GridLayout());
303 inclusive_pane.add(include_button);
304 inclusive_pane.add(exclude_button);
305
306 button_pane_1.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
307 button_pane_1.setLayout(new GridLayout(5, 2));
308 button_pane_1.add(name_label);
309 button_pane_1.add(name_field);
310 button_pane_1.add(source_label);
311 button_pane_1.add(source_combobox);
312 button_pane_1.add(match_label);
313 button_pane_1.add(match_field);
314 button_pane_1.add(inclusive_label);
315 button_pane_1.add(inclusive_pane);
316 button_pane_1.add(flags_label);
317 button_pane_1.add(flags_field);
318
319 button_pane_3.setBorder(BorderFactory.createEmptyBorder(5,0,0,0));
320 button_pane_3.setLayout(new GridLayout(1,3));
321 button_pane_3.add(add_button);
322 button_pane_3.add(update_button);
323 button_pane_3.add(remove_button);
324
325 button_pane.setLayout(new BorderLayout());
326 button_pane.add(button_pane_1, BorderLayout.CENTER);
327 button_pane.add(button_pane_3, BorderLayout.SOUTH);
328
329 subcollection_list_pane.setLayout(new BorderLayout());
330 subcollection_list_pane.add(subcollection_list_label, BorderLayout.NORTH);
331 subcollection_list_pane.add(new JScrollPane(subcollection_list), BorderLayout.CENTER);
332 subcollection_pane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
333 subcollection_pane.setLayout(new BorderLayout());
334 subcollection_pane.add(subcollection_list_pane, BorderLayout.CENTER);
335 subcollection_pane.add(button_pane, BorderLayout.SOUTH);
336
337 tabbed_pane.addTab(Dictionary.get("CDM.SubcollectionManager.Subcollection_Controls"), subcollection_pane);
338 tabbed_pane.addTab(Dictionary.get("CDM.SubcollectionManager.Subindex_Controls"), (JPanel) CollectionDesignManager.subcollectionindex_manager.getControls());
339 tabbed_pane.addTab(Dictionary.get("CDM.SubcollectionManager.Language_Controls"), (JPanel) CollectionDesignManager.language_manager.getControls());
340
341 message_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
342 message_pane.setLayout(new GridLayout(3,1,0,0));
343 message_pane.add(new JPanel());
344 message_pane.add(message_textarea);
345 message_pane.add(new JPanel());
346
347 border_pane.setBorder(BorderFactory.createEmptyBorder(0,5,5,5));
348 border_pane.setLayout(card_layout);
349 if(Configuration.getMode() > Configuration.LIBRARIAN_MODE) {
350 border_pane.add(tabbed_pane, ENABLED_CONTROLS);
351 border_pane.add(message_pane, DISABLED_CONTROLS);
352 }
353 else {
354 border_pane.add(message_pane, DISABLED_CONTROLS);
355 border_pane.add(tabbed_pane, ENABLED_CONTROLS);
356 }
357
358 setLayout(new BorderLayout());
359 add(header_pane, BorderLayout.NORTH);
360 add(border_pane, BorderLayout.CENTER);
361 }
362
363 /** Method to unregister any listeners to avoid memory leaks.
364 */
365 public void destroy() {
366 }
367
368 public void gainFocus() {
369 // Rebuild the sources combobox
370 Vector source_model = Gatherer.c_man.getCollection().msm.getAssignedElements();
371 source_model.add(0, "Filename"); // Add filename as a possible source.
372 source_combobox.setModel(new DefaultComboBoxModel(source_model));
373 }
374
375 public void loseFocus() {
376 }
377
378 /** Called when the detail mode has changed which in turn controls if any of the partition controls are visible, or if they are instead replaced with a message explaining why they are not.
379 * @param mode the new mode as an int
380 */
381 public void modeChanged(int mode) {
382 if(mode > Configuration.LIBRARIAN_MODE) {
383 card_layout.show(border_pane, ENABLED_CONTROLS);
384 }
385 else {
386 card_layout.show(border_pane, DISABLED_CONTROLS);
387 }
388 }
389
390 /** 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. */
391 private class AddSubCollectionListener
392 implements ActionListener {
393 /** 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.
394 * @param event An <strong>ActionEvent</strong> containing information about the event.
395 * @see org.greenstone.gatherer.cdm.Subcollection
396 */
397 public void actionPerformed(ActionEvent event) {
398 String name = name_field.getText();
399 String source = null;
400 Object object = source_combobox.getSelectedItem();
401 if(object instanceof ElementWrapper) {
402 ElementWrapper element_wrapper = (ElementWrapper)object;
403 source = element_wrapper.getName();
404 if(source.indexOf(StaticStrings.NS_SEP) == -1) {
405 source = StaticStrings.EXTRACTED_NAMESPACE + source;
406 }
407 }
408 else {
409 source = object.toString();
410 }
411 String pattern = match_field.getText();
412 String flags = flags_field.getText();
413 if(name.length() > 0 && (source == null || source.length() > 0) && pattern.length() > 0) {
414 Subcollection subcollection = new Subcollection(name, include_button.isSelected(), source, pattern, flags);
415 addSubcollection(subcollection);
416 // Change the selection to the new subcollection
417 subcollection_list.setSelectedValue(subcollection, true);
418 }
419 add_button.setEnabled(false);
420 }
421 }
422
423 /** This class listens for any key entry in a text field, selection change in a combobox or button click, and updates a subcollection as appropriate. Its also convenient to use this class to test if the add button should be active yet. */
424 private class SubCollectionChangeListener
425 implements DocumentListener, ActionListener {
426 /** 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.
427 * @param event An <strong>ActionEvent</strong> containing information about the event.
428 */
429 public void actionPerformed(ActionEvent event) {
430 validateAdd();
431 }
432
433 public void changedUpdate(DocumentEvent event) {
434 validateAdd();
435 }
436
437 public void insertUpdate(DocumentEvent event) {
438 validateAdd();
439
440 }
441
442 public void removeUpdate(DocumentEvent event) {
443 validateAdd();
444 }
445
446 /** Method to validate the current subcollection editor values, and enable or disable controls (add button) based on said values. */
447 private void validateAdd() {
448 if(name_field.getText().length() > 0 && match_field.getText().length() > 0) {
449 if (getSubcollection(name_field.getText()) == null) {
450 add_button.setEnabled(true);
451 } else {
452 add_button.setEnabled(false);
453 }
454 }
455 else {
456 add_button.setEnabled(false);
457 }
458 }
459 }
460
461 /** 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. */
462 private class RemoveSubCollectionListener
463 implements ActionListener {
464 /** 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.
465 * @param event An <strong>ActionEvent</strong> containing information about the event.
466 * @see org.greenstone.gatherer.cdm.Subcollection
467 */
468 public void actionPerformed(ActionEvent event) {
469 if(!subcollection_list.isSelectionEmpty()) {
470 Subcollection subcollection = (Subcollection)subcollection_list.getSelectedValue();
471 removeSubcollection(subcollection);
472 // And remove subcollection indexes dependant on this subcollection
473 CollectionDesignManager.subcollectionindex_manager.removeSubcollectionIndexes(subcollection);
474 }
475 remove_button.setEnabled(false);
476 }
477 }
478
479 private class UpdateSubCollectionListener
480 implements ActionListener {
481 public void actionPerformed(ActionEvent event) {
482 if(!subcollection_list.isSelectionEmpty()) {
483 Subcollection subcollection = (Subcollection)subcollection_list.getSelectedValue();
484 String name = name_field.getText();
485 String source = null;
486 Object object = source_combobox.getSelectedItem();
487 if(object instanceof ElementWrapper) {
488 ElementWrapper element_wrapper = (ElementWrapper)object;
489 source = element_wrapper.getName();
490 if(source.indexOf(StaticStrings.NS_SEP) == -1) {
491 source = StaticStrings.EXTRACTED_NAMESPACE + source;
492 }
493 }
494 else {
495 source = object.toString();
496 }
497 String pattern = match_field.getText();
498 String flags = flags_field.getText();
499 if(name.length() > 0 && (source == null || source.length() > 0) && pattern.length() > 0) {
500 updateSubcollection(subcollection, name, include_button.isSelected(), source, pattern, flags);
501 }
502 }
503 }
504 }
505
506 /** This class listens for selections in the list on the subcollections pane of the SubcollectionManager, and updates the controls as necessary to reflect selection. */
507 private class SubCollectionListListener
508 implements ListSelectionListener {
509 /** 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.
510 * @param event A <strong>ListSelectionEvent</strong> containing information related to this event.
511 * @see org.greenstone.gatherer.cdm.Subcollection
512 */
513 public void valueChanged(ListSelectionEvent event) {
514 // Now the entry
515 if(!subcollection_list.isSelectionEmpty()) {
516 Subcollection subcollection = (Subcollection) subcollection_list.getSelectedValue();
517 flags_field.setText(subcollection.getFlags());
518 include_button.setSelected(subcollection.isInclusive());
519 exclude_button.setSelected(!subcollection.isInclusive());
520 match_field.setText(subcollection.getPattern());
521 name_field.setText(subcollection.getName());
522 String s = subcollection.getSource();
523 int pos = 0;
524 Object value = source_combobox.getItemAt(pos);
525 //ystem.err.println("Search for: " + s);
526 while(value != null) {
527 if(value instanceof ElementWrapper) {
528 ElementWrapper e = (ElementWrapper) value;
529 String e_name = e.getName();
530 if(e_name.indexOf(StaticStrings.NS_SEP) == -1) {
531 e_name = StaticStrings.EXTRACTED_NAMESPACE + e_name;
532 }
533 //ystem.err.print("Compare to: " + e_name);
534 if(e_name.equals(s)) {
535 source_combobox.setSelectedIndex(pos);
536 value = null;
537 //ystem.err.println(" - Match");
538 }
539 else {
540 pos++;
541 value = source_combobox.getItemAt(pos);
542 //ystem.err.println(" - Fail");
543 }
544 }
545 else if(value.toString().equals(s)) {
546 source_combobox.setSelectedIndex(pos);
547 value = null;
548 }
549 else {
550 pos++;
551 value = source_combobox.getItemAt(pos);
552 }
553 }
554 // Can't add one thats already there.
555 add_button.setEnabled(false);
556 // You can update or remove it though...
557 remove_button.setEnabled(true);
558 update_button.setEnabled(true);
559 }
560 else {
561 flags_field.setText("");
562 include_button.setSelected(true);
563 match_field.setText("");
564 name_field.setText("");
565 source_combobox.setSelectedIndex(0);
566 remove_button.setEnabled(false);
567 update_button.setEnabled(false);
568 }
569 }
570 }
571 }
572}
Note: See TracBrowser for help on using the repository browser.