Project

General

Profile

« Previous | Next » 

Revision 2177

Harvest List Editor, a GUI tool for editing Harvest List XML files

View differences:

src/edu/ucsb/nceas/metacat/harvesterClient/HarvestListEditor.java
1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2004 University of New Mexico and the 
4
 *                  Regents of the University of California
5
 *
6
 *   '$Author$'
7
 *     '$Date$'
8
 * '$Revision$'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
 */
24

  
25
package edu.ucsb.nceas.metacat.harvesterClient;
26

  
27
import java.awt.BorderLayout;
28
import java.awt.Dimension;
29
import java.awt.event.ActionEvent;
30
import java.awt.event.ActionListener;
31
import java.io.File;
32
import java.io.FileInputStream;
33
import java.io.FileWriter;
34
import java.io.IOException;
35
import java.io.InputStream;
36
import java.io.InputStreamReader;
37
import java.io.PrintStream;
38
import java.io.PrintWriter;
39
import java.io.Reader;
40
import javax.swing.JButton;
41
import javax.swing.JFileChooser;
42
import javax.swing.JFrame;
43
import javax.swing.JMenu;
44
import javax.swing.JMenuBar;
45
import javax.swing.JMenuItem;
46
import javax.swing.JOptionPane;
47
import javax.swing.JPanel;
48
import javax.swing.JScrollPane;
49
import javax.swing.JTable;
50
import javax.swing.KeyStroke;
51
import javax.swing.ListSelectionModel;
52
import javax.swing.event.ListSelectionEvent;
53
import javax.swing.event.ListSelectionListener;
54
import javax.swing.table.TableColumn;
55
import javax.swing.table.TableModel;
56
import javax.swing.text.Document;
57
import javax.xml.parsers.ParserConfigurationException;
58
import org.xml.sax.Attributes;
59
import org.xml.sax.ContentHandler;
60
import org.xml.sax.ErrorHandler;
61
import org.xml.sax.InputSource;
62
import org.xml.sax.SAXException;
63
import org.xml.sax.SAXParseException;
64
import org.xml.sax.XMLReader;
65
import org.xml.sax.helpers.DefaultHandler;
66
import org.xml.sax.helpers.XMLReaderFactory;
67

  
68
import edu.ucsb.nceas.metacat.harvesterClient.Harvester;
69
import edu.ucsb.nceas.utilities.Options;
70

  
71

  
72
/**
73
 * The Harvest List Editor reads a Harvest List XML file and displays it as a 
74
 * JTable. Allows user to add, modify, or delete <Document> elements in the
75
 * Harvest List, and save changes back to the disk.
76
 * 
77
 */
78
public class HarvestListEditor extends JFrame implements ActionListener {
79

  
80
  // Column names for the JTable  
81
  String[] columnNames = {
82
                          "Scope",
83
                          "Identifier",
84
                          "Revision",
85
                          "Document Type",
86
                          "Document URL"
87
                         };
88

  
89
  String clipboardDocumentType = "";
90
  String clipboardDocumentURL = "";
91
  String clipboardIdentifier = "";
92
  String clipboardRevision = "";
93
  String clipboardScope = "";
94
	JButton copyButton;
95
	JButton cutButton;
96
  String defaultDocumentType;
97
  String defaultDocumentURL;
98
  String defaultHarvestList;
99
  String defaultIdentifier;
100
  String defaultRevision;
101
  String defaultScope;
102
	Document doc;
103
	JScrollPane docPane;
104
  JFileChooser fileChooser = new JFileChooser();
105
  File harvestListFile;
106
  boolean harvestListHasChanged = false;
107
	JMenuBar menuBar;
108
  final int numColumns = 5;
109
  final int numRows = 300;
110
  Options options;
111
  boolean optionsTest = false; // true only for JUnit testing
112
	JButton pasteButton;
113
	JButton pasteDefaultsButton;
114
  Object[][] rowData = new Object[numRows][numColumns];
115
  private String schemaLocation = 
116
    "eml://ecoinformatics.org/harvestList ../../lib/harvester/harvestList.xsd";
117
  int selectedRow = -1;
118
  final JTable table;
119
  TableModel tableModel;
120
  
121
  // Menu items
122
  JMenuItem exitMenuItem = new JMenuItem("Exit");
123
  JMenuItem newMenuItem = new JMenuItem("New");
124
  JMenuItem openMenuItem = new JMenuItem("Open...");
125
  JMenuItem saveMenuItem = new JMenuItem("Save");
126
  JMenuItem saveAsMenuItem = new JMenuItem("Save As...");
127
  
128

  
129
  /**
130
   * The main program. Instantiate the main frame, a HarvestListEditor object.
131
   * 
132
   * @param args
133
   */
134
  public static void main(String[] args) {
135
    HarvestListEditor harvestListEditor = new HarvestListEditor();
136
  }
137

  
138

  
139
  /**
140
   * Constructor for HarvestListEditor class.
141
   */
142
  public HarvestListEditor() {
143
		super("Harvest List Editor");
144

  
145
		JPanel buttonPanel = new JPanel();
146
    String[] fileItems = 
147
                  new String[] {"New", "Open...", "Save", "Save As...", "Exit"};
148
		JMenu fileMenu = new JMenu("File");
149
		char[] fileShortCuts = {'N', 'O', 'S', 'A', 'X'};
150
    TableColumn tableColumn;
151

  
152
    // Load default values from the metacat.properties file
153
    Harvester.loadOptions(optionsTest);
154
    options = Harvester.options;
155
    defaultHarvestList = options.getOption("defaultHarvestList");
156
    defaultDocumentType = options.getOption("defaultDocumentType");
157
    defaultDocumentURL = options.getOption("defaultDocumentURL");
158
    defaultIdentifier = options.getOption("defaultIdentifier");
159
    defaultRevision = options.getOption("defaultRevision");
160
    defaultScope = options.getOption("defaultScope");
161
    System.out.println("defaultHarvestList: " + defaultHarvestList);
162
    System.out.println("defaultDocumentType: " + defaultDocumentType);
163
    System.out.println("defaultDocumentURL: " + defaultDocumentURL);
164
    System.out.println("defaultIdentifier: " + defaultIdentifier);
165
    System.out.println("defaultRevision: " + defaultRevision);
166
    System.out.println("defaultScope: " + defaultScope); 
167

  
168
		setSize(1000, 400);
169
		setDefaultCloseOperation(EXIT_ON_CLOSE);
170
		menuBar = new JMenuBar();
171
    
172
    /*
173
     * Add menu items to the File menu
174
     */
175
		newMenuItem.setAccelerator(KeyStroke.getKeyStroke('N',
176
									                                     java.awt.Event.CTRL_MASK,
177
                                                       false));
178
		newMenuItem.addActionListener(this);
179
		fileMenu.add(newMenuItem);
180

  
181
		openMenuItem.setAccelerator(KeyStroke.getKeyStroke('O',
182
									                                     java.awt.Event.CTRL_MASK,
183
                                                       false));
184
		openMenuItem.addActionListener(this);
185
		fileMenu.add(openMenuItem);
186

  
187
		saveMenuItem.setAccelerator(KeyStroke.getKeyStroke('S',
188
									                                     java.awt.Event.CTRL_MASK,
189
                                                       false));
190
		saveMenuItem.addActionListener(this);
191
    saveMenuItem.setEnabled(false);
192
		fileMenu.add(saveMenuItem);
193

  
194
		saveAsMenuItem.setAccelerator(KeyStroke.getKeyStroke('A',
195
									                                     java.awt.Event.CTRL_MASK,
196
                                                       false));
197
		saveAsMenuItem.addActionListener(this);
198
		fileMenu.add(saveAsMenuItem);
199

  
200
		exitMenuItem.setAccelerator(KeyStroke.getKeyStroke('X',
201
									                                     java.awt.Event.CTRL_MASK,
202
                                                       false));
203
		exitMenuItem.addActionListener(this);
204
		fileMenu.add(exitMenuItem);
205
    
206
		menuBar.add(fileMenu);      // Add the File menu to the menu bar
207
		setJMenuBar(menuBar);       // Set the frame's menu bar to this menu bar
208

  
209
    //table = new JTable(numRows, numColumns);
210
    table = new JTable(rowData, columnNames);
211
    table.setPreferredScrollableViewportSize(new Dimension(900, 300));
212
    tableColumn = table.getColumnModel().getColumn(0);
213
    tableColumn.setPreferredWidth(200);
214
    tableColumn = table.getColumnModel().getColumn(1);
215
    tableColumn.setPreferredWidth(50);
216
    tableColumn = table.getColumnModel().getColumn(2);
217
    tableColumn.setPreferredWidth(50);
218
    tableColumn = table.getColumnModel().getColumn(3);
219
    tableColumn.setPreferredWidth(300);
220
    tableColumn = table.getColumnModel().getColumn(4);
221
    tableColumn.setPreferredWidth(300);
222
    
223
    table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
224
    tableModel = table.getModel();
225

  
226
    //Ask to be notified of selection changes.
227
    ListSelectionModel rowSM = table.getSelectionModel();
228

  
229
    rowSM.addListSelectionListener(new ListSelectionListener() {
230
      public void valueChanged(ListSelectionEvent e) {
231
        ListSelectionModel lsm;
232

  
233
        //Ignore extra messages.
234
        if (e.getValueIsAdjusting()) return;
235

  
236
        lsm = (ListSelectionModel)e.getSource();
237

  
238
        // If now row is selected, disable all buttons.
239
        if (lsm.isSelectionEmpty()) {
240
          selectedRow = -1;
241
          cutButton.setEnabled(false);
242
          copyButton.setEnabled(false);
243
          pasteButton.setEnabled(false);
244
          pasteDefaultsButton.setEnabled(false);
245
        }
246
        // If a row is selected, manage the buttons based on the selected row
247
        // and the current clipboard values.
248
        else {
249
          selectedRow = lsm.getMinSelectionIndex();
250
          manageButtons(selectedRow);
251
        }
252
      }
253
    });
254

  
255
    docPane = new JScrollPane(table);
256
    getContentPane().add(docPane, BorderLayout.CENTER);
257

  
258
		cutButton = new JButton("Cut");
259
		copyButton = new JButton("Copy");
260
		pasteButton = new JButton("Paste");
261
		pasteDefaultsButton = new JButton("Paste Defaults");
262

  
263
    // Action listener for the Copy button.    
264
    copyButton.addActionListener(new ActionListener() {
265
      public void actionPerformed(ActionEvent ae) {				
266
        copyRow(selectedRow);
267
        manageButtons(selectedRow);
268
        harvestListHasChanged = true;
269
			}
270
		}
271
    );
272

  
273
    // Action listener for the Cut button.    
274
    cutButton.addActionListener(new ActionListener() {
275
      public void actionPerformed(ActionEvent ae) {				
276
        cutRow(selectedRow);
277
        manageButtons(selectedRow);
278
        harvestListHasChanged = true;
279
			}
280
		}
281
    );
282

  
283
    // Action listener for the Paste button.    
284
    pasteButton.addActionListener(new ActionListener() {
285
      public void actionPerformed(ActionEvent ae) {
286
        pasteRow(selectedRow);
287
        manageButtons(selectedRow);
288
        harvestListHasChanged = true;
289
			}
290
		}
291
    );
292

  
293
    // Action listener for the Paste Defaults button.    
294
    pasteDefaultsButton.addActionListener(new ActionListener() {
295
      public void actionPerformed(ActionEvent ae) {
296
        pasteDefaultValues(selectedRow);
297
        manageButtons(selectedRow);
298
        harvestListHasChanged = true;
299
			}
300
		}
301
    );
302

  
303
    cutButton.setEnabled(false);
304
    copyButton.setEnabled(false);
305
    pasteButton.setEnabled(false);
306
    pasteDefaultsButton.setEnabled(false);
307
		buttonPanel.add(cutButton);
308
		buttonPanel.add(copyButton);
309
		buttonPanel.add(pasteButton);
310
		buttonPanel.add(pasteDefaultsButton);
311
		buttonPanel.setOpaque(true);
312
		getContentPane().add(buttonPanel, BorderLayout.SOUTH);
313

  
314
    // If the default Harvest List option has a value, and the file exists, 
315
    // loads its contents.
316
    //
317
    if ((defaultHarvestList != null) && (!defaultHarvestList.equals(""))) {
318
      harvestListFile = new File(defaultHarvestList);
319
      if (harvestListFile.exists()) {
320
        try {
321
          loadHarvestList(harvestListFile);
322
          saveMenuItem.setEnabled(true);
323
        }
324
        catch (ParserConfigurationException e) {
325
          System.out.println("Error parsing Harvest List: " + e.getMessage());
326
        }        
327
      }
328
    }
329

  
330
		setVisible(true);
331
  }
332

  
333

  
334
  /**
335
   * Implements action listeners for menu items.
336
   * 
337
   * @param e   An ActionEvent object, determines the menu item that was
338
   *            selected.
339
   */
340
	public void actionPerformed(ActionEvent e) {
341
		if ((e.getActionCommand()).equals("New")) {
342
      fileNew();
343
		}    
344
		else if ((e.getActionCommand()).equals("Open...")) {
345
      fileOpen();
346
    }    
347
    else if ((e.getActionCommand()).equals("Save")) {
348
      fileSave();
349
    }    
350
		else if ((e.getActionCommand()).equals("Save As...")) {
351
      fileSaveAs();
352
    }
353
    else if ((e.getActionCommand()).equals("Exit")) {
354
      fileExit();
355
    }
356
	}
357
  
358

  
359
  /**
360
   * Adds a new row to the table, setting values for each of the five columns
361
   * in the row.
362
   * 
363
   * @param rowIndex              the row index
364
   * @param scope                 the scope string
365
   * @param identifier            the identifier string
366
   * @param revision              the revision string
367
   * @param documentType          the document type
368
   * @param documentURL           the document URL
369
   */
370
  void addRow(int rowIndex, String scope, String identifier, String revision,
371
              String documentType, String documentURL) {
372
    tableModel.setValueAt(scope,        rowIndex, 0);
373
    tableModel.setValueAt(identifier,   rowIndex, 1);
374
    tableModel.setValueAt(revision,     rowIndex, 2);
375
    tableModel.setValueAt(documentType, rowIndex, 3);
376
    tableModel.setValueAt(documentURL,  rowIndex, 4);
377
  }
378

  
379

  
380
  /**
381
   * Composes a single tag line to be written in the Harvest List.
382
   * 
383
   * @param indentLevel    the number of spaces to begin the line with
384
   * @param tag            the tag name
385
   * @param text           the text to insert within the begin and end tags
386
   * @return line          the composed line
387
   */
388
  String composeLine(int indentLevel, String tag, String text) {
389
    String line = "";
390
    
391
    for (int i = 0; i < indentLevel; i++) {
392
      line += " ";
393
    }
394
    
395
    line += "<" + tag + ">";
396
    line += text;
397
    line += "</" + tag + ">";
398
    
399
    return line;
400
  }
401
  
402

  
403
  /**
404
   * Clears all rows in the table, setting all values to null.
405
   */
406
  void clearHarvestList() {
407
    for (int rowIndex = 0; rowIndex < numRows; rowIndex++) {
408
      clearRow(rowIndex);
409
    }
410
  }
411
  
412

  
413
  /**
414
   * Clears a single row in the tables, setting all five fields to null.
415
   * 
416
   * @param rowIndex   the index to the table row to be cleared
417
   */
418
  void clearRow(int rowIndex) {
419
    final String nil = null;
420
    
421
    tableModel.setValueAt(nil, rowIndex, 0);
422
    tableModel.setValueAt(nil, rowIndex, 1);
423
    tableModel.setValueAt(nil, rowIndex, 2);
424
    tableModel.setValueAt(nil, rowIndex, 3);
425
    tableModel.setValueAt(nil, rowIndex, 4);    
426
  }
427
  
428

  
429
  /**
430
   * Copies the values in a given table row to the clipboard.
431
   * 
432
   * @param rowIndex  the index of the table row to be copied
433
   */
434
  void copyRow(int rowIndex) {
435
    clipboardScope = (String) tableModel.getValueAt(rowIndex, 0);
436
    clipboardIdentifier = (String) tableModel.getValueAt(rowIndex, 1);
437
    clipboardRevision = (String) tableModel.getValueAt(rowIndex, 2);
438
    clipboardDocumentType = (String) tableModel.getValueAt(rowIndex, 3);    
439
    clipboardDocumentURL = (String) tableModel.getValueAt(rowIndex, 4);
440
  }
441
  
442

  
443
  /**
444
   * Cuts a row from the table. The row is copied to the clipboard and then
445
   * cleared.
446
   * 
447
   * @param rowIndex  the index of the table row to be copied
448
   */
449
  void cutRow(int rowIndex) {
450
    copyRow(rowIndex);
451
    clearRow(rowIndex);
452
  }
453
  
454

  
455
  /**
456
   * Exit from the Harvest List Editor. Prompt to save changes if appropriate.
457
   */
458
  void fileExit() {
459
    int value;
460

  
461
    if (harvestListHasChanged) {
462
      value = saveChangesDialog();
463
      
464
      if (value == JOptionPane.YES_OPTION) {
465
        try {
466
          // Save the changes then exit
467
          //
468
          fileSave();
469
          System.exit(0);
470
        }
471
        catch (Exception exception) {
472
          exception.printStackTrace();
473
        }
474
      }
475
      else if (value == JOptionPane.NO_OPTION) {
476
        // Exit without saving changes
477
        System.exit(0);
478
      } 
479
    }
480
    else {
481
      System.exit(0);
482
    }
483
  }
484
  
485

  
486
  /**
487
   * Replace the current Harvest List with an empty Harvest List. Prompt to save
488
   * changes if appropriate.
489
   */
490
  void fileNew() {
491
    int value;
492
    
493
    if (harvestListHasChanged) {
494
      value = saveChangesDialog();
495
      
496
      if (value == JOptionPane.YES_OPTION) {
497
        try {
498
          fileSave();
499
        }
500
        catch (Exception exception) {
501
          exception.printStackTrace();
502
        }
503
      }
504
      else if (value == JOptionPane.CANCEL_OPTION) {
505
        return;
506
      }
507
    }
508

  
509
    clearHarvestList();
510
    harvestListFile = null;
511
    saveMenuItem.setEnabled(false);
512
    harvestListHasChanged = false;    
513
  }
514
  
515

  
516
  /**
517
   * Opens a file dialog to load a Harvest List. Prompts to save changes to the
518
   * current Harvest List if appropriate.
519
   */
520
  void fileOpen() {
521
    int value;
522
    
523
    if (harvestListHasChanged) {
524
      value = saveChangesDialog();
525
      
526
      if (value == JOptionPane.YES_OPTION) {
527
        try {
528
          fileSave();
529
        }
530
        catch (Exception exception) {
531
          exception.printStackTrace();
532
        }
533
      }
534
      else if (value == JOptionPane.CANCEL_OPTION) {
535
        return;
536
      }
537
    }
538

  
539
    value = fileChooser.showOpenDialog(HarvestListEditor.this);
540
    
541
    if (value == JFileChooser.APPROVE_OPTION) {
542
      harvestListFile = fileChooser.getSelectedFile();
543
      try {
544
        clearHarvestList();
545
        loadHarvestList(harvestListFile);
546
      }
547
      catch (ParserConfigurationException e) {
548
        System.out.println("Error parsing Harvest List: " + e.getMessage());
549
      }        
550
      harvestListHasChanged = false;
551
      saveMenuItem.setEnabled(true);
552
    }
553
  }
554
  
555

  
556
  /**
557
   * Save the current Harvest List to disk.
558
   */
559
  void fileSave() {
560
    if (harvestListFile != null) {
561
      writeFile(harvestListFile);
562
      harvestListHasChanged = false;
563
    }
564
    else {
565
      System.out.println("No action taken");
566
    }
567
  }
568
  
569

  
570
  /**
571
   * Save the current Harvest List as a potentially different file name.
572
   */
573
  void fileSaveAs() {
574
    int returnVal;
575
    
576
    returnVal = fileChooser.showOpenDialog(HarvestListEditor.this);
577
    
578
    if (returnVal == JFileChooser.APPROVE_OPTION) {
579
      harvestListFile = fileChooser.getSelectedFile();
580
      writeFile(harvestListFile);
581
      saveMenuItem.setEnabled(true);
582
      harvestListHasChanged = false;
583
    }
584
  }
585
  
586

  
587
  /**
588
   * Determines whether the clipboard is currently empty. The clipboard is
589
   * empty if all five of the fields are empty.
590
   * 
591
   * @return      true if the clipboard is empty, else false
592
   */
593
  boolean isEmptyClipboard() {
594
    boolean isEmpty = true;
595
    
596
    isEmpty = isEmpty && (clipboardScope.equals(""));
597
    isEmpty = isEmpty && (clipboardIdentifier.equals(""));
598
    isEmpty = isEmpty && (clipboardRevision.equals(""));
599
    isEmpty = isEmpty && (clipboardDocumentType.equals(""));
600
    isEmpty = isEmpty && (clipboardDocumentURL.equals(""));
601
    
602
    return isEmpty;
603
  }
604
    
605

  
606
  /**
607
   * Determines whether a given row in the table is empty. A row is empty if
608
   * all five of its fields contain either null or "".
609
   * 
610
   * @param rowIndex    the index to the row in the table that is being checked
611
   * @return            true if the row is empty, else false
612
   */
613
  boolean isEmptyRow(int rowIndex) {
614
    boolean isEmpty = true;
615
    String scope = (String) tableModel.getValueAt(rowIndex, 0);
616
    String identifier = (String) tableModel.getValueAt(rowIndex, 1);
617
    String revision = (String) tableModel.getValueAt(rowIndex, 2);
618
    String documentType = (String) tableModel.getValueAt(rowIndex, 3);    
619
    String documentURL = (String) tableModel.getValueAt(rowIndex, 4);
620
    
621
    isEmpty = isEmpty && ((scope == null) || (scope.equals("")));
622
    isEmpty = isEmpty && ((identifier == null) || (identifier.equals("")));
623
    isEmpty = isEmpty && ((revision == null) || (revision.equals("")));
624
    isEmpty = isEmpty && ((documentType == null) || (documentType.equals("")));
625
    isEmpty = isEmpty && ((documentURL == null) || (documentURL.equals("")));
626
    
627
    return isEmpty;
628
  }
629
  
630

  
631
  /**
632
   * Loads the Harvest List from a file. Parses the file using the inner class,
633
   * HarvestListHandler, a SAX parser.
634
   * 
635
   * @param harvestList  the File to be loaded
636
   * @throws ParserConfigurationException
637
   */
638
  void loadHarvestList(File harvestList) throws ParserConfigurationException {
639
    HarvestListHandler harvestListHandler = new HarvestListHandler();
640
    FileInputStream fis;
641
    InputStreamReader inputStreamReader;
642

  
643
    try {
644
      fis = new FileInputStream(harvestList);
645
      inputStreamReader = new InputStreamReader(fis);
646
      System.out.println("Opened file successfully.");
647
      harvestListHandler.runParser(this, inputStreamReader, schemaLocation);
648
      fis.close();
649
    }
650
    catch (SAXException e) {
651
      System.out.println("Error parsing Harvest List: " + e.getMessage());
652
    }
653
    catch (ClassNotFoundException e) {
654
      System.out.println("ClassNotFoundException: " + e.getMessage());
655
    }
656
    catch (IOException ioe) {
657
      System.out.println("Error opening file: " + ioe.getMessage());
658
    }
659
  }
660
  
661

  
662
  /**
663
   * Enables or disables buttons depending on the state of the currently
664
   * selected row and the state of the clipboard.
665
   * 
666
   * @param rowIndex       the index of the currently selected row
667
   */
668
  void manageButtons(int rowIndex) {
669
    
670
    if (isEmptyRow(rowIndex)) {
671
      // Selected row is empty, so disable cut and copy
672
      cutButton.setEnabled(false);
673
      copyButton.setEnabled(false);
674
    }
675
    else {
676
      // Selected row is not empty, so enable cut and copy
677
      cutButton.setEnabled(true);
678
      copyButton.setEnabled(true);
679
    }
680

  
681
    if (isEmptyClipboard()) {
682
      // Clipboard is empty, so disable paste
683
      pasteButton.setEnabled(false);
684
    }
685
    else {
686
      // Clipboard is not empty, so enable paste
687
      pasteButton.setEnabled(true);
688
    }
689

  
690
    // Paste Defaults button is enabled whenever a row is selected    
691
    pasteDefaultsButton.setEnabled(true);
692
  }
693
  
694

  
695
  /**
696
   * Pastes the clipboard values into the specified row.
697
   * 
698
   * @param rowIndex      the index of the row that is being pasted to
699
   */
700
  void pasteRow(int rowIndex) {
701
    tableModel.setValueAt(clipboardScope,        rowIndex, 0);
702
    tableModel.setValueAt(clipboardIdentifier,   rowIndex, 1);
703
    tableModel.setValueAt(clipboardRevision,     rowIndex, 2);
704
    tableModel.setValueAt(clipboardDocumentType, rowIndex, 3);
705
    tableModel.setValueAt(clipboardDocumentURL,  rowIndex, 4);
706
  }
707
  
708

  
709
  /**
710
   * Pastes the default values into the specified row.
711
   * 
712
   * @param rowIndex      the index of the row that is being pasted to
713
   */
714
  void pasteDefaultValues(int rowIndex) {
715
    tableModel.setValueAt(defaultScope,        rowIndex, 0);
716
    tableModel.setValueAt(defaultIdentifier,   rowIndex, 1);
717
    tableModel.setValueAt(defaultRevision,     rowIndex, 2);
718
    tableModel.setValueAt(defaultDocumentType, rowIndex, 3);
719
    tableModel.setValueAt(defaultDocumentURL,  rowIndex, 4);
720
  }
721
  
722

  
723
  /**
724
   * Dialog to determine whether user wants to save changes before proceeding.
725
   * 
726
   * @return   integer value that determines whether the user responded with
727
   *           "Yes", "No", or "Cancel"
728
   */
729
  int saveChangesDialog () {
730
    Object[] options = {"Yes", "No", "Cancel"};
731
    int value;
732
    
733
    value = JOptionPane.showOptionDialog(null,
734
                                         "Save Changes?",
735
                                         "Warning",
736
                                         JOptionPane.DEFAULT_OPTION,
737
                                         JOptionPane.WARNING_MESSAGE,
738
                                         null,
739
                                         options,
740
                                         options[0]); // default option
741
    return value;
742
  }
743
  
744

  
745
  /**
746
   * Writes the contents of the table to file as XML.
747
   * 
748
   * @param harvestList       the File object to write to
749
   */
750
  void writeFile(File harvestList) {
751
    try {
752
      PrintWriter out = new PrintWriter(new FileWriter(harvestList));
753
      out.println("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
754
      out.println("");
755
      out.println(
756
       "<hrv:harvestList xmlns:hrv=\"eml://ecoinformatics.org/harvestList\" >");
757

  
758
      for (int i = 0; i < numRows; i++) {
759
        if (!isEmptyRow(i)) {
760
          writeRow(out, i);
761
        }
762
      }
763

  
764
      out.println("");
765
      out.println("</hrv:harvestList>");
766
      out.close();
767
    }
768
    catch (IOException ioe) {
769
      System.out.println("IOException: " + ioe.getMessage());
770
    }
771
  }
772
  
773

  
774
  /**
775
   * Writes a row of the table to file. A row corresponds to a single
776
   * <Document> element in the Harvest List.
777
   * 
778
   * @param out       the PrintWriter object for the file
779
   * @param rowIndex  the index of the table row that is being written to file
780
   */
781
  void writeRow(PrintWriter out, int rowIndex) {
782
    int indentLevel = 6;
783
    String scope = (String) tableModel.getValueAt(rowIndex, 0);
784
    String identifier = (String) tableModel.getValueAt(rowIndex, 1);
785
    String revision = (String) tableModel.getValueAt(rowIndex, 2);
786
    String documentType = (String) tableModel.getValueAt(rowIndex, 3);    
787
    String documentURL = (String) tableModel.getValueAt(rowIndex, 4);
788

  
789
    out.println("");
790
    out.println("  <document>");
791
    out.println("    <docid>");
792
    out.println(composeLine(indentLevel, "scope", scope));
793
    out.println(composeLine(indentLevel, "identifier", identifier));
794
    out.println(composeLine(indentLevel, "revision", revision));
795
    out.println("    </docid>");
796
    indentLevel = 4;
797
    out.println(composeLine(indentLevel, "documentType", documentType));
798
    out.println(composeLine(indentLevel, "documentURL", documentURL));
799
    out.println("  </document>");
800
  }
801
  
802
  
803
  /**
804
   * This inner class extends DefaultHandler. It parses the Harvest List file,
805
   * writing a new row to the table every time it encounters a </Document>
806
   * end tag.
807
   */
808
  class HarvestListHandler extends DefaultHandler implements ErrorHandler {
809
  
810
    public String scope;
811
    public int identifier;
812
    public String identifierString;
813
    public String documentType;
814
    private HarvestListEditor harvestListEditor;
815
    public int revision;
816
    public String revisionString;
817
    private int rowIndex = 0;
818
    public String documentURL;
819
    private String currentQname;
820
    public final static String DEFAULT_PARSER = 
821
           "org.apache.xerces.parsers.SAXParser";
822
    private boolean schemaValidate = true;
823
	
824

  
825
	  /**
826
     * This method is called for any plain text within an element.
827
     * It parses the value for any of the following elements:
828
     * <scope>, <identifier>, <revision>, <documentType>, <documentURL>
829
     * 
830
     * @param ch          the character array holding the parsed text
831
     * @param start       the start index
832
     * @param length      the text length
833
     * 
834
     */
835
    public void characters (char ch[], int start, int length) {
836
      String s = new String(ch, start, length);
837
 
838
      if (length > 0) {           
839
        if (currentQname.equals("scope")) {
840
          scope += s;
841
        }
842
        else if (currentQname.equals("identifier")) {
843
          identifierString += s;
844
        }
845
        else if (currentQname.equals("revision")) {
846
          revisionString += s;
847
        }
848
        else if (currentQname.equals("documentType")) {
849
          documentType += s;
850
        }
851
        else if (currentQname.equals("documentURL")) {
852
          documentURL += s;
853
        }
854
      }
855
    }
856

  
857

  
858
    /** 
859
     * Handles an end-of-document event.
860
     */
861
    public void endDocument () {
862
      System.out.println("Finished parsing Harvest List");
863
    }
864

  
865

  
866
    /** 
867
     * Handles an end-of-element event. If the end tag is </Document>, then
868
     * creates a new HarvestDocument object and pushes it to the document
869
     * list.
870
     * 
871
     * @param uri
872
     * @param localname
873
     * @param qname
874
     */
875
    public void endElement(String uri, 
876
                           String localname,
877
                           String qname) {
878
      
879
      HarvestDocument harvestDocument;
880
      
881
      if (qname.equals("identifier")) {
882
        identifier = Integer.parseInt(identifierString);
883
      }
884
      else if (qname.equals("revision")) {
885
        revision = Integer.parseInt(revisionString);
886
      }
887
      else if (qname.equals("document")) {
888
        harvestListEditor.addRow(rowIndex, scope, identifierString, 
889
                                revisionString, documentType, documentURL);
890
        rowIndex++;
891
      }
892

  
893
      currentQname = "";
894
    }
895

  
896

  
897
    /**
898
     * Method for handling errors during a parse
899
     *
900
     * @param exception         The parsing error
901
     * @exception SAXException  Description of Exception
902
     */
903
     public void error(SAXParseException e) throws SAXParseException {
904
        System.out.println("SAXParseException: " + e.getMessage());
905
        throw e;
906
    }
907

  
908

  
909
    /**
910
     * Run the validating parser
911
     *
912
     * @param xml             the xml stream to be validated
913
     * @schemaLocation        relative path the to XML Schema file, e.g. "."
914
     * @exception IOException thrown when test files can't be opened
915
     * @exception ClassNotFoundException thrown when SAX Parser class not found
916
     * @exception SAXException
917
     * @exception SAXParserException
918
     */
919
    public void runParser(HarvestListEditor harvestListEditor,
920
                          Reader xml, 
921
                          String schemaLocation)
922
           throws IOException, ClassNotFoundException,
923
                  SAXException, SAXParseException {
924

  
925
      // Get an instance of the parser
926
      XMLReader parser;
927
      
928
      this.harvestListEditor = harvestListEditor;
929
      this.rowIndex = 0;
930

  
931
      parser = XMLReaderFactory.createXMLReader(DEFAULT_PARSER);
932
      // Set Handlers in the parser
933
      parser.setContentHandler((ContentHandler)this);
934
      parser.setErrorHandler((ErrorHandler)this);
935
      parser.setFeature("http://xml.org/sax/features/namespaces", true);
936
      parser.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
937
      parser.setFeature("http://xml.org/sax/features/validation", true);
938
      parser.setProperty(
939
              "http://apache.org/xml/properties/schema/external-schemaLocation", 
940
              schemaLocation);
941

  
942
      if (schemaValidate) {
943
        parser.setFeature("http://apache.org/xml/features/validation/schema", 
944
                          true);
945
      }
946
    
947
      // Parse the document
948
      parser.parse(new InputSource(xml));
949
    }
950

  
951

  
952
    /**
953
     * Handles a start-of-document event.
954
     */
955
    public void startDocument () {
956
      System.out.println("Started parsing Harvest List");
957
    }
958

  
959

  
960
    /** 
961
     * Handles a start-of-element event.
962
     * 
963
     * @param uri
964
     * @param localname
965
     * @param qname
966
     * @param attributes
967
     */
968
    public void startElement(String uri, 
969
                             String localname,
970
                             String qname,
971
                             Attributes attributes) {
972
      
973
      currentQname = qname;
974

  
975
      if (qname.equals("scope")) {
976
        scope = "";
977
      }
978
      else if (qname.equals("identifier")) {
979
        identifierString = "";
980
      }
981
      else if (qname.equals("revision")) {
982
        revisionString = "";
983
      }
984
      else if (qname.equals("documentType")) {
985
        documentType = "";
986
      }
987
      else if (qname.equals("documentURL")) {
988
        documentURL = "";
989
      }
990
    }
991
  }
992
}
0 993

  

Also available in: Unified diff