001 /*
002 * Copyright (c) 1995-2010, The University of Sheffield. See the file
003 * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004 *
005 * This file is part of GATE (see http://gate.ac.uk/), and is free
006 * software, licenced under the GNU Library General Public License,
007 * Version 2, June 1991 (in the distribution as file licence.html,
008 * and also available at http://gate.ac.uk/gate/licence.html).
009 *
010 * Valentin Tablan 12/07/2001
011 *
012 * $Id: CorpusEditor.java 12511 2010-04-16 21:41:44Z thomas_heitz $
013 *
014 */
015 package gate.gui;
016
017 import java.awt.BorderLayout;
018 import java.awt.Component;
019 import java.awt.Dimension;
020 import java.awt.datatransfer.Transferable;
021 import java.awt.datatransfer.StringSelection;
022 import java.awt.datatransfer.DataFlavor;
023 import java.awt.datatransfer.UnsupportedFlavorException;
024 import java.awt.event.*;
025 import java.util.*;
026 import java.io.IOException;
027
028 import javax.swing.*;
029 import javax.swing.event.ListSelectionListener;
030 import javax.swing.event.ListSelectionEvent;
031 import javax.swing.table.*;
032
033 import gate.*;
034 import gate.creole.AbstractVisualResource;
035 import gate.event.CorpusEvent;
036 import gate.creole.metadata.CreoleResource;
037 import gate.creole.metadata.GuiType;
038 import gate.event.CorpusListener;
039 import gate.event.CreoleListener;
040 import gate.event.CreoleEvent;
041 import gate.swing.XJTable;
042 import gate.swing.XJPopupMenu;
043 import gate.util.GateException;
044 import gate.util.GateRuntimeException;
045
046 /**
047 * A simple viewer/editor for corpora. It will allow the visualisation of the
048 * list of documents inside a corpus along with their features.
049 * It will also allow addition and removal of documents.
050 */
051 @CreoleResource(name = "Corpus editor", guiType = GuiType.LARGE,
052 resourceDisplayed = "gate.Corpus", mainViewer = true)
053 public class CorpusEditor extends AbstractVisualResource
054 implements CorpusListener {
055
056 public Resource init(){
057 initLocalData();
058 initGuiComponents();
059 initListeners();
060 return this;
061 }
062
063
064 protected void initLocalData(){
065 docTableModel = new DocumentTableModel();
066 try {
067 documentsLoadedCount = Gate.getCreoleRegister()
068 .getAllInstances("gate.Document").size();
069 } catch (GateException exception) {
070 exception.printStackTrace();
071 }
072 }
073
074 protected void initGuiComponents(){
075 setLayout(new BorderLayout());
076 renderer = new DocumentNameRenderer();
077
078 docTable = new XJTable(docTableModel);
079 docTable.setSortable(true);
080 docTable.setSortedColumn(DocumentTableModel.COL_INDEX);
081 docTable.setAutoResizeMode(XJTable.AUTO_RESIZE_LAST_COLUMN);
082 docTable.getColumnModel().getColumn(DocumentTableModel.COL_NAME).
083 setCellRenderer(renderer);
084 docTable.setDragEnabled(true);
085 docTable.setTransferHandler(new TransferHandler() {
086 // drag and drop to move up and down the table rows
087 // import selected documents from the resources tree
088 String source = "";
089 public int getSourceActions(JComponent c) {
090 return MOVE;
091 }
092 protected Transferable createTransferable(JComponent c) {
093 int selectedRows[] = docTable.getSelectedRows();
094 Arrays.sort(selectedRows);
095 return new StringSelection("CorpusEditor"
096 + Arrays.toString(selectedRows));
097 }
098 protected void exportDone(JComponent c, Transferable data, int action) {
099 }
100 public boolean canImport(JComponent c, DataFlavor[] flavors) {
101 for(DataFlavor flavor : flavors) {
102 if(DataFlavor.stringFlavor.equals(flavor)) {
103 return true;
104 }
105 }
106 return false;
107 }
108 public boolean importData(JComponent c, Transferable t) {
109 if (!canImport(c, t.getTransferDataFlavors())) {
110 return false;
111 }
112 try {
113 source = (String)t.getTransferData(DataFlavor.stringFlavor);
114 if (source.startsWith("ResourcesTree")) {
115 int insertion = docTable.getSelectedRow();
116 List<Document> documents = new ArrayList<Document>();
117 source = source.replaceFirst("^ResourcesTree\\[", "");
118 source = source.replaceFirst("\\]$", "");
119 final String documentsNames[] = source.split(", ");
120 List<Resource> loadedDocuments;
121 try {
122 loadedDocuments =
123 Gate.getCreoleRegister().getAllInstances("gate.Document");
124 } catch(GateException e) {
125 e.printStackTrace();
126 return false;
127 }
128 // get the list of documents selected when dragging started
129 for(String documentName : documentsNames) {
130 for (Resource loadedDocument : loadedDocuments) {
131 if (loadedDocument.getName().equals(documentName)
132 && !corpus.contains(loadedDocument)) {
133 documents.add((Document) loadedDocument);
134 }
135 }
136 }
137 // add the documents at the insertion point
138 for (Document document : documents) {
139 if (insertion != -1) {
140 corpus.add(docTable.rowViewToModel(insertion), document);
141 if (insertion == docTable.getRowCount()) { insertion++; }
142 } else {
143 corpus.add(document);
144 }
145 }
146 // select the moved/already existing documents
147 SwingUtilities.invokeLater(new Runnable() {
148 public void run() {
149 docTable.clearSelection();
150 for (String documentName : documentsNames) {
151 for (int row = 0; row < docTable.getRowCount(); row++) {
152 if (docTable.getValueAt(
153 row, docTable.convertColumnIndexToView(1))
154 .equals(documentName)) {
155 docTable.addRowSelectionInterval(row, row);
156 }
157 }
158 }
159 }
160 });
161 changeMessage();
162 return true;
163
164 } else if (source.startsWith("CorpusEditor")) {
165 int insertion = docTable.getSelectedRow();
166 int initialInsertion = insertion;
167 List<Document> documents = new ArrayList<Document>();
168 source = source.replaceFirst("^CorpusEditor\\[", "");
169 source = source.replaceFirst("\\]$", "");
170 String selectedRows[] = source.split(", ");
171 if (Integer.valueOf(selectedRows[0]) < insertion) { insertion++; }
172 // get the list of documents selected when dragging started
173 for(String row : selectedRows) {
174 if (Integer.valueOf(row) == initialInsertion) {
175 // the user dragged the selected rows on themselves, do nothing
176 return false;
177 }
178 documents.add((Document) corpus.get(
179 docTable.rowViewToModel(Integer.valueOf(row))));
180 if (Integer.valueOf(row) < initialInsertion) { insertion--; }
181 }
182 // remove the documents selected when dragging started
183 for(Document document : documents) {
184 corpus.remove(document);
185 }
186 // add the documents at the insertion point
187 for (Document document : documents) {
188 corpus.add(docTable.rowViewToModel(insertion), document);
189 insertion++;
190 }
191 // select the moved documents
192 docTable.addRowSelectionInterval(
193 insertion - selectedRows.length, insertion - 1);
194 return true;
195
196 } else {
197 return false;
198 }
199
200 } catch (UnsupportedFlavorException ufe) {
201 return false;
202 } catch (IOException ioe) {
203 return false;
204 }
205 }
206 });
207
208 JScrollPane scroller = new JScrollPane(docTable);
209 scroller.setHorizontalScrollBarPolicy(
210 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
211 scroller.getViewport().setBackground(docTable.getBackground());
212 add(scroller, BorderLayout.CENTER);
213
214 toolbar = new JToolBar();
215 toolbar.setFloatable(false);
216 toolbar.add(newDocumentAction = new NewDocumentAction());
217 toolbar.add(removeDocumentsAction = new RemoveDocumentsAction());
218 toolbar.addSeparator();
219 toolbar.add(moveUpAction = new MoveUpAction());
220 toolbar.add(moveDownAction = new MoveDownAction());
221 toolbar.addSeparator();
222 toolbar.add(openDocumentsAction = new OpenDocumentsAction());
223
224 removeDocumentsAction.setEnabled(false);
225 moveUpAction.setEnabled(false);
226 moveDownAction.setEnabled(false);
227 openDocumentsAction.setEnabled(false);
228
229 JPanel topPanel = new JPanel(new BorderLayout());
230 topPanel.add(toolbar, BorderLayout.NORTH);
231
232 messageLabel = new JLabel();
233 changeMessage();
234 topPanel.add(messageLabel, BorderLayout.SOUTH);
235
236 add(topPanel, BorderLayout.NORTH);
237 }
238
239 protected void initListeners(){
240
241 // mouse double-click to open the document
242 // context menu to get the actions for the selection
243 docTable.addMouseListener(new MouseAdapter() {
244 public void mouseClicked(MouseEvent e) {
245 processMouseEvent(e);
246 }
247 public void mousePressed(MouseEvent e) {
248 if(e.isPopupTrigger()) { processMouseEvent(e); }
249 }
250 public void mouseReleased(MouseEvent e) {
251 if(e.isPopupTrigger()) { processMouseEvent(e); }
252 }
253 private void processMouseEvent(MouseEvent e) {
254 int row = docTable.rowAtPoint(e.getPoint());
255 if(row == -1) { return; }
256
257 if(e.isPopupTrigger()) {
258 // context menu
259 if(!docTable.isRowSelected(row)) {
260 // if right click outside the selection then reset selection
261 docTable.getSelectionModel().setSelectionInterval(row, row);
262 }
263 JPopupMenu popup = new XJPopupMenu();
264 popup.add(openDocumentsAction);
265 popup.add(removeDocumentsAction);
266 popup.show(docTable, e.getPoint().x, e.getPoint().y);
267
268 } else if(e.getID() == MouseEvent.MOUSE_CLICKED
269 && e.getClickCount() == 2) {
270 // open document on double-click
271 openDocumentsAction.actionPerformed(null);
272 }
273 }
274 });
275
276 // Enter key opens the selected documents
277 docTable.addKeyListener(new KeyAdapter() {
278 public void keyPressed(KeyEvent e) {
279 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
280 openDocumentsAction.actionPerformed(null);
281 }
282 }
283 });
284
285 docTable.getSelectionModel().addListSelectionListener(
286 new ListSelectionListener() {
287 public void valueChanged(ListSelectionEvent e) {
288 // enable/disable buttons according to the selection
289 removeDocumentsAction.setEnabled(docTable.getSelectedRowCount() > 0);
290 openDocumentsAction.setEnabled(docTable.getSelectedRowCount() > 0);
291 moveUpAction.setEnabled(docTable.getSelectedRowCount() > 0
292 && !docTable.isRowSelected(0));
293 moveDownAction.setEnabled(docTable.getSelectedRowCount() > 0
294 && !docTable.isRowSelected(docTable.getRowCount() - 1));
295 }
296 });
297
298 Gate.getCreoleRegister().addCreoleListener(new CreoleListener() {
299 public void resourceLoaded(CreoleEvent e) {
300 if (e.getResource() instanceof Document) {
301 documentsLoadedCount++;
302 changeMessage();
303 }
304 }
305 public void resourceUnloaded(CreoleEvent e) {
306 if (e.getResource() instanceof Document) {
307 documentsLoadedCount--;
308 changeMessage();
309 }
310 }
311 public void datastoreOpened(CreoleEvent e) { /* do nothing */ }
312 public void datastoreCreated(CreoleEvent e) { /* do nothing */ }
313 public void datastoreClosed(CreoleEvent e) { /* do nothing */ }
314 public void resourceRenamed(Resource resource, String oldName,
315 String newName) { /* do nothing */ }
316 });
317 }
318
319 public void cleanup(){
320 super.cleanup();
321 corpus = null;
322 }
323
324 public void setTarget(Object target){
325 if(corpus != null && corpus != target){
326 //we already had a different corpus
327 corpus.removeCorpusListener(this);
328 }
329 if(!(target instanceof Corpus)){
330 throw new IllegalArgumentException(
331 "The GATE corpus editor can only be used with a GATE corpus!\n" +
332 target.getClass().toString() + " is not a GATE corpus!");
333 }
334 this.corpus = (Corpus)target;
335 corpus.addCorpusListener(this);
336 docTableModel.dataChanged();
337 SwingUtilities.invokeLater(new Runnable(){
338 public void run(){
339 docTableModel.fireTableDataChanged();
340 }
341 });
342 }
343
344 public void documentAdded(final CorpusEvent e) {
345 docTableModel.dataChanged();
346 SwingUtilities.invokeLater(new Runnable(){
347 public void run(){
348 changeMessage();
349 docTableModel.fireTableRowsInserted(e.getDocumentIndex(),
350 e.getDocumentIndex());
351 }
352 });
353 }
354
355 public void documentRemoved(final CorpusEvent e) {
356 docTableModel.dataChanged();
357 SwingUtilities.invokeLater(new Runnable(){
358 public void run(){
359 changeMessage();
360 docTableModel.fireTableRowsDeleted(e.getDocumentIndex(),
361 e.getDocumentIndex());
362 }
363 });
364 }
365
366 class DocumentTableModel extends AbstractTableModel{
367 public DocumentTableModel(){
368 documentNames = new ArrayList<String>();
369 }
370
371 /**
372 * Called externally when the underlying corpus has changed.
373 */
374 private void dataChanged(){
375 List<String> newDocs = new ArrayList<String>();
376 if(corpus != null){
377 newDocs.addAll(corpus.getDocumentNames());
378 }
379 List<String> oldDocs = documentNames;
380 documentNames = newDocs;
381 oldDocs.clear();
382 }
383
384 public int getColumnCount() {
385 return COLUMN_COUNT;
386 }
387
388 public int getRowCount() {
389 return documentNames.size();
390 }
391
392 public Object getValueAt(int rowIndex, int columnIndex) {
393 //invalid indexes might appear when update events are slow to act
394 if(rowIndex < 0 || rowIndex >= documentNames.size() ||
395 columnIndex < 0 || columnIndex > COLUMN_COUNT) return null;
396 switch(columnIndex) {
397 case COL_INDEX:
398 return rowIndex;
399 case COL_NAME:
400 return documentNames.get(rowIndex);
401 default:
402 return null;
403 }
404 }
405
406 @Override
407 public Class<?> getColumnClass(int columnIndex) {
408 switch(columnIndex) {
409 case COL_INDEX:
410 return Integer.class;
411 case COL_NAME:
412 return String.class;
413 default:
414 return String.class;
415 }
416 }
417
418 @Override
419 public String getColumnName(int column) {
420 return COLUMN_NAMES[column];
421 }
422
423 @Override
424 public boolean isCellEditable(int rowIndex, int columnIndex) {
425 return false;
426 }
427
428 private List<String> documentNames;
429 private final String[] COLUMN_NAMES = {"Index", "Document name"};
430 private static final int COL_INDEX = 0;
431 private static final int COL_NAME = 1;
432 private static final int COLUMN_COUNT = 2;
433 }
434
435 class DocumentNameRenderer extends DefaultTableCellRenderer implements
436 ListCellRenderer{
437 public DocumentNameRenderer(){
438 super();
439 setIcon(MainFrame.getIcon("document"));
440 }
441
442 public Component getListCellRendererComponent(JList list, Object value,
443 int index, boolean isSelected, boolean cellHasFocus) {
444 // prepare the renderer
445
446 return getTableCellRendererComponent(docTable, value, isSelected,
447 cellHasFocus, index, DocumentTableModel.COL_NAME);
448 }
449
450 @Override
451 public Dimension getMaximumSize() {
452 //we don't mind being extended horizontally
453 Dimension dim = super.getMaximumSize();
454 if(dim != null){
455 dim.width = Integer.MAX_VALUE;
456 setMaximumSize(dim);
457 }
458 return dim;
459 }
460
461 @Override
462 public Dimension getMinimumSize() {
463 //we don't like being squashed!
464 return getPreferredSize();
465 }
466
467
468 }
469
470 class MoveUpAction extends AbstractAction{
471 public MoveUpAction(){
472 super("Move up", MainFrame.getIcon("up"));
473 putValue(SHORT_DESCRIPTION, "Moves selected document(s) up");
474 putValue(MNEMONIC_KEY, KeyEvent.VK_UP);
475 }
476
477 public void actionPerformed(ActionEvent e) {
478 int[] rowsTable = docTable.getSelectedRows();
479 int[] rowsCorpus = new int[rowsTable.length];
480 for(int i = 0; i < rowsTable.length; i++)
481 rowsCorpus[i] = docTable.rowViewToModel(rowsTable[i]);
482 Arrays.sort(rowsCorpus);
483 //starting from the smallest one, move each element up
484 for(int i = 0; i < rowsCorpus.length; i++){
485 if(rowsCorpus[i] > 0){
486 //swap the doc with the one before
487 //serial corpus does not load the document on remove, so we need
488 //to load the document explicitly
489 boolean wasLoaded = corpus.isDocumentLoaded(rowsCorpus[i]);
490 Document doc = (Document)corpus.get(rowsCorpus[i]);
491 corpus.remove(rowsCorpus[i]);
492 rowsCorpus[i] = rowsCorpus[i] - 1;
493 corpus.add(rowsCorpus[i], doc);
494 if(!wasLoaded){
495 corpus.unloadDocument(doc);
496 Factory.deleteResource(doc);
497 }
498 }
499 }
500 //restore selection
501 //the remove / add events will cause the table to be updated
502 //we need to only restore the selection after that happened
503 final int[] selectedRowsCorpus = new int[rowsCorpus.length];
504 System.arraycopy(rowsCorpus, 0, selectedRowsCorpus, 0, rowsCorpus.length);
505 SwingUtilities.invokeLater(new Runnable(){
506 public void run(){
507 docTable.clearSelection();
508 for(int i = 0; i < selectedRowsCorpus.length; i++){
509 int rowTable = docTable.rowModelToView(selectedRowsCorpus[i]);
510 docTable.getSelectionModel().addSelectionInterval(rowTable,
511 rowTable);
512 }
513 }
514 });
515 }
516 }
517
518 class MoveDownAction extends AbstractAction{
519 public MoveDownAction(){
520 super("Move down", MainFrame.getIcon("down"));
521 putValue(SHORT_DESCRIPTION, "Moves selected document(s) down");
522 putValue(MNEMONIC_KEY, KeyEvent.VK_DOWN);
523 }
524
525 public void actionPerformed(ActionEvent e) {
526 int[] rowsTable = docTable.getSelectedRows();
527 int[] rowsCorpus = new int[rowsTable.length];
528 for(int i = 0; i < rowsTable.length; i++)
529 rowsCorpus[i] = docTable.rowViewToModel(rowsTable[i]);
530 Arrays.sort(rowsCorpus);
531 //starting from the largest one, move each element down
532 for(int i = rowsCorpus.length -1; i >=0; i--){
533 if(rowsCorpus[i] < corpus.size() -1){
534 //swap the doc with the one before
535 //serial corpus does not load the document on remove, so we need
536 //to load the document explicitly
537 boolean wasLoaded = corpus.isDocumentLoaded(rowsCorpus[i]);
538 Document doc = (Document)corpus.get(rowsCorpus[i]);
539 corpus.remove(rowsCorpus[i]);
540 rowsCorpus[i]++;
541 corpus.add(rowsCorpus[i], doc);
542 if(!wasLoaded){
543 corpus.unloadDocument(doc);
544 Factory.deleteResource(doc);
545 }
546 }
547 }
548 //restore selection
549 //the remove / add events will cause the table to be updated
550 //we need to only restore the selection after that happened
551 final int[] selectedRowsCorpus = new int[rowsCorpus.length];
552 System.arraycopy(rowsCorpus, 0, selectedRowsCorpus, 0, rowsCorpus.length);
553 SwingUtilities.invokeLater(new Runnable(){
554 public void run(){
555 docTable.clearSelection();
556 for(int i = 0; i < selectedRowsCorpus.length; i++){
557 int rowTable = docTable.rowModelToView(selectedRowsCorpus[i]);
558 docTable.getSelectionModel().addSelectionInterval(rowTable,
559 rowTable);
560 }
561 }
562 });
563 }
564 }
565
566 class NewDocumentAction extends AbstractAction{
567 public NewDocumentAction(){
568 super("Add document", MainFrame.getIcon("add-document"));
569 putValue(SHORT_DESCRIPTION, "Add new document(s) to this corpus");
570 putValue(MNEMONIC_KEY, KeyEvent.VK_ENTER);
571 }
572
573 public void actionPerformed(ActionEvent e){
574 List<Resource> loadedDocuments;
575 try {
576 // get all the documents loaded in the system
577 loadedDocuments = Gate.getCreoleRegister()
578 .getAllInstances("gate.Document");
579 } catch(GateException ge) {
580 //gate.Document is not registered in creole.xml....what is!?
581 throw new GateRuntimeException(
582 "gate.Document is not registered in the creole register!\n" +
583 "Something must be terribly wrong...take a vacation!");
584 }
585 Vector<String> docNames = new Vector<String>();
586 for (Resource loadedDocument : new ArrayList<Resource>(loadedDocuments)) {
587 if (corpus.contains(loadedDocument)) {
588 loadedDocuments.remove(loadedDocument);
589 } else {
590 docNames.add(loadedDocument.getName());
591 }
592 }
593 JList docList = new JList(docNames);
594 docList.getSelectionModel().setSelectionInterval(0, docNames.size()-1);
595 docList.setCellRenderer(renderer);
596 final JOptionPane optionPane = new JOptionPane(new JScrollPane(docList),
597 JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
598 final JDialog dialog = optionPane.createDialog(CorpusEditor.this,
599 "Add document(s) to this corpus");
600 docList.addMouseListener(new MouseAdapter() {
601 public void mouseClicked(MouseEvent e) {
602 if (e.getClickCount() == 2) {
603 optionPane.setValue(JOptionPane.OK_OPTION);
604 dialog.dispose();
605 }
606 }
607 });
608 dialog.setVisible(true);
609 if(optionPane.getValue().equals(JOptionPane.OK_OPTION)){
610 int[] selectedIndices = docList.getSelectedIndices();
611 for (int selectedIndice : selectedIndices) {
612 corpus.add(loadedDocuments.get(selectedIndice));
613 }
614 }
615 changeMessage();
616 }
617 }
618
619 class RemoveDocumentsAction extends AbstractAction{
620 public RemoveDocumentsAction(){
621 super("Remove documents", MainFrame.getIcon("remove-document"));
622 putValue(SHORT_DESCRIPTION,
623 "Removes selected document(s) from this corpus");
624 putValue(MNEMONIC_KEY, KeyEvent.VK_DELETE);
625 }
626
627 public void actionPerformed(ActionEvent e){
628 int[] selectedIndexes = docTable.getSelectedRows();
629 int[] corpusIndexes = new int[selectedIndexes.length];
630 for(int i = 0; i < selectedIndexes.length; i++)
631 corpusIndexes[i] = docTable.rowViewToModel(selectedIndexes[i]);
632 Arrays.sort(corpusIndexes);
633 //remove the document starting with the one with the highest index
634 for(int i = corpusIndexes.length-1; i >= 0; i--){
635 corpus.remove(corpusIndexes[i]);
636 }
637 docTable.clearSelection();
638 changeMessage();
639 }
640 }
641
642 class OpenDocumentsAction extends AbstractAction{
643 public OpenDocumentsAction(){
644 super("Open documents", MainFrame.getIcon("document"));
645 putValue(SHORT_DESCRIPTION,
646 "Opens selected document(s) in a document editor");
647 }
648
649 public void actionPerformed(ActionEvent e){
650 Component root = SwingUtilities.getRoot(CorpusEditor.this);
651 if (!(root instanceof MainFrame)) { return; }
652 final MainFrame mainFrame = (MainFrame) root;
653 final int[] selectedRows = docTable.getSelectedRows();
654 if (selectedRows.length > 10) {
655 Object[] possibleValues =
656 { "Open the "+selectedRows.length+" documents", "Don't open" };
657 int selectedValue =
658 JOptionPane.showOptionDialog(docTable, "Do you want to open "
659 +selectedRows.length+" documents in the central tabbed pane ?",
660 "Warning", JOptionPane.DEFAULT_OPTION,
661 JOptionPane.QUESTION_MESSAGE, null,
662 possibleValues, possibleValues[1]);
663 if (selectedValue == 1
664 || selectedValue == JOptionPane.CLOSED_OPTION) {
665 return;
666 }
667 }
668 for (int row : selectedRows) {
669 // load the document if inside a datastore
670 corpus.get(docTable.rowViewToModel(row));
671 }
672 SwingUtilities.invokeLater(new Runnable() { public void run() {
673 for (int row : selectedRows) {
674 Document doc = (Document) corpus.get(docTable.rowViewToModel(row));
675 // show the document in the central view
676 mainFrame.select(doc);
677 }
678 }});
679 }
680 }
681
682 protected void changeMessage() {
683 SwingUtilities.invokeLater(new Runnable(){ public void run() {
684 if (corpus == null || corpus.size() == 0) {
685 newDocumentAction.setEnabled(true);
686 messageLabel.setText(
687 "<html>To add or remove documents to this corpus:<ul>" +
688 "<li>use the toolbar buttons at the top of this view" +
689 "<li>drag documents from the left resources tree and drop them below" +
690 "<li>right click on the corpus in the resources tree and choose 'Populate'" +
691 "</ul></html>");
692 messageLabel.setVisible(true);
693 } else if (documentsLoadedCount > 0
694 && documentsLoadedCount == corpus.size()) {
695 newDocumentAction.setEnabled(false);
696 messageLabel.setText("All the documents loaded in the " +
697 "system are in this corpus.");
698 messageLabel.setVisible(true);
699 } else if (documentsLoadedCount == 0) {
700 newDocumentAction.setEnabled(false);
701 if (corpus.getDataStore() == null) {
702 messageLabel.setText(
703 "There are no documents loaded in the system. " +
704 "Press F1 for help.");
705 } else {
706 messageLabel.setText("Open a document to load it from the datastore.");
707 }
708 messageLabel.setVisible(true);
709 } else {
710 newDocumentAction.setEnabled(true);
711 messageLabel.setVisible(false);
712 }
713 }});
714 }
715
716 protected XJTable docTable;
717 protected DocumentTableModel docTableModel;
718 protected DocumentNameRenderer renderer;
719 protected JToolBar toolbar;
720 protected Corpus corpus;
721 protected NewDocumentAction newDocumentAction;
722 protected RemoveDocumentsAction removeDocumentsAction;
723 protected MoveUpAction moveUpAction;
724 protected MoveDownAction moveDownAction;
725 protected OpenDocumentsAction openDocumentsAction;
726 protected JLabel messageLabel;
727 protected int documentsLoadedCount;
728 }
|