Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 1995-2012, The University of Sheffield. See the file
* COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
*
* This file is part of GATE (see http://gate.ac.uk/), and is free
* software, licenced under the GNU Library General Public License,
* Version 2, June 1991 (in the distribution as file licence.html,
* and also available at http://gate.ac.uk/gate/licence.html).
*
* Valentin Tablan 12/07/2001
*
* $Id: CorpusEditor.java 19641 2016-10-06 07:24:25Z markagreenwood $
*
*/
package gate.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.*;
import java.util.*;
import java.io.IOException;
import javax.swing.*;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.table.*;
import gate.*;
import gate.creole.AbstractVisualResource;
import gate.event.CorpusEvent;
import gate.creole.metadata.CreoleResource;
import gate.creole.metadata.GuiType;
import gate.event.CorpusListener;
import gate.event.CreoleListener;
import gate.event.CreoleEvent;
import gate.swing.XJTable;
import gate.swing.XJPopupMenu;
import gate.util.GateException;
import gate.util.GateRuntimeException;
/**
* A simple viewer/editor for corpora. It will allow the visualisation of the
* list of documents inside a corpus along with their features.
* It will also allow addition and removal of documents.
*/
@SuppressWarnings("serial")
@CreoleResource(name = "Corpus editor", guiType = GuiType.LARGE,
resourceDisplayed = "gate.Corpus", mainViewer = true)
public class CorpusEditor extends AbstractVisualResource
implements CorpusListener {
@Override
public Resource init(){
initLocalData();
initGuiComponents();
initListeners();
return this;
}
protected void initLocalData(){
docTableModel = new DocumentTableModel();
try {
documentsLoadedCount = Gate.getCreoleRegister()
.getAllInstances("gate.Document").size();
} catch (GateException exception) {
exception.printStackTrace();
}
}
protected void initGuiComponents(){
setLayout(new BorderLayout());
renderer = new DocumentNameRenderer();
docTable = new XJTable(docTableModel);
docTable.setSortable(true);
docTable.setSortedColumn(DocumentTableModel.COL_INDEX);
docTable.setAutoResizeMode(XJTable.AUTO_RESIZE_LAST_COLUMN);
docTable.getColumnModel().getColumn(DocumentTableModel.COL_NAME).
setCellRenderer(renderer);
docTable.setDragEnabled(true);
docTable.setTransferHandler(new TransferHandler() {
// drag and drop to move up and down the table rows
// import selected documents from the resources tree
String source = "";
@Override
public int getSourceActions(JComponent c) {
return MOVE;
}
@Override
protected Transferable createTransferable(JComponent c) {
int selectedRows[] = docTable.getSelectedRows();
Arrays.sort(selectedRows);
return new StringSelection("CorpusEditor"
+ Arrays.toString(selectedRows));
}
@Override
protected void exportDone(JComponent c, Transferable data, int action) {
}
@Override
public boolean canImport(JComponent c, DataFlavor[] flavors) {
for(DataFlavor flavor : flavors) {
if(DataFlavor.stringFlavor.equals(flavor)) {
return true;
}
}
return false;
}
@Override
public boolean importData(JComponent c, Transferable t) {
if (!canImport(c, t.getTransferDataFlavors())) {
return false;
}
try {
source = (String)t.getTransferData(DataFlavor.stringFlavor);
if (source.startsWith("ResourcesTree")) {
int insertion = docTable.getSelectedRow();
List documents = new ArrayList();
source = source.replaceFirst("^ResourcesTree\\[", "");
source = source.replaceFirst("\\]$", "");
final String documentsNames[] = source.split(", ");
List loadedDocuments;
try {
loadedDocuments =
Gate.getCreoleRegister().getAllInstances("gate.Document");
} catch(GateException e) {
e.printStackTrace();
return false;
}
// get the list of documents selected when dragging started
for(String documentName : documentsNames) {
for (Resource loadedDocument : loadedDocuments) {
if (loadedDocument.getName().equals(documentName)
&& !corpus.contains(loadedDocument)) {
documents.add((Document) loadedDocument);
}
}
}
// add the documents at the insertion point
for (Document document : documents) {
if (insertion != -1) {
corpus.add(docTable.rowViewToModel(insertion), document);
if (insertion == docTable.getRowCount()) { insertion++; }
} else {
corpus.add(document);
}
}
// select the moved/already existing documents
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
docTable.clearSelection();
for (String documentName : documentsNames) {
for (int row = 0; row < docTable.getRowCount(); row++) {
if (docTable.getValueAt(
row, docTable.convertColumnIndexToView(1))
.equals(documentName)) {
docTable.addRowSelectionInterval(row, row);
}
}
}
}
});
changeMessage();
return true;
} else if (source.startsWith("CorpusEditor")) {
int insertion = docTable.getSelectedRow();
int initialInsertion = insertion;
List documents = new ArrayList();
source = source.replaceFirst("^CorpusEditor\\[", "");
source = source.replaceFirst("\\]$", "");
String selectedRows[] = source.split(", ");
if (Integer.parseInt(selectedRows[0]) < insertion) { insertion++; }
// get the list of documents selected when dragging started
for(String row : selectedRows) {
if (Integer.parseInt(row) == initialInsertion) {
// the user dragged the selected rows on themselves, do nothing
return false;
}
documents.add(corpus.get(
docTable.rowViewToModel(Integer.parseInt(row))));
if (Integer.parseInt(row) < initialInsertion) { insertion--; }
}
// remove the documents selected when dragging started
for(Document document : documents) {
corpus.remove(document);
}
// add the documents at the insertion point
for (Document document : documents) {
corpus.add(docTable.rowViewToModel(insertion), document);
insertion++;
}
// select the moved documents
docTable.addRowSelectionInterval(
insertion - selectedRows.length, insertion - 1);
return true;
} else {
return false;
}
} catch (UnsupportedFlavorException ufe) {
return false;
} catch (IOException ioe) {
return false;
}
}
});
JScrollPane scroller = new JScrollPane(docTable);
scroller.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
scroller.getViewport().setBackground(docTable.getBackground());
add(scroller, BorderLayout.CENTER);
toolbar = new JToolBar();
toolbar.setFloatable(false);
toolbar.add(newDocumentAction = new NewDocumentAction());
toolbar.add(removeDocumentsAction = new RemoveDocumentsAction());
toolbar.addSeparator();
toolbar.add(moveUpAction = new MoveUpAction());
toolbar.add(moveDownAction = new MoveDownAction());
toolbar.addSeparator();
toolbar.add(openDocumentsAction = new OpenDocumentsAction());
removeDocumentsAction.setEnabled(false);
moveUpAction.setEnabled(false);
moveDownAction.setEnabled(false);
openDocumentsAction.setEnabled(false);
JPanel topPanel = new JPanel(new BorderLayout());
topPanel.add(toolbar, BorderLayout.NORTH);
messageLabel = new JLabel();
changeMessage();
topPanel.add(messageLabel, BorderLayout.SOUTH);
add(topPanel, BorderLayout.NORTH);
}
protected void initListeners(){
// mouse double-click to open the document
// context menu to get the actions for the selection
docTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
processMouseEvent(e);
}
@Override
public void mousePressed(MouseEvent e) {
if(e.isPopupTrigger()) { processMouseEvent(e); }
}
@Override
public void mouseReleased(MouseEvent e) {
if(e.isPopupTrigger()) { processMouseEvent(e); }
}
private void processMouseEvent(MouseEvent e) {
int row = docTable.rowAtPoint(e.getPoint());
if(row == -1) { return; }
if(e.isPopupTrigger()) {
// context menu
if(!docTable.isRowSelected(row)) {
// if right click outside the selection then reset selection
docTable.getSelectionModel().setSelectionInterval(row, row);
}
JPopupMenu popup = new XJPopupMenu();
popup.add(openDocumentsAction);
popup.add(removeDocumentsAction);
popup.show(docTable, e.getPoint().x, e.getPoint().y);
} else if(e.getID() == MouseEvent.MOUSE_CLICKED
&& e.getClickCount() == 2) {
// open document on double-click
openDocumentsAction.actionPerformed(null);
}
}
});
// Enter key opens the selected documents
docTable.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
openDocumentsAction.actionPerformed(null);
}
}
});
docTable.getSelectionModel().addListSelectionListener(
new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
// enable/disable buttons according to the selection
removeDocumentsAction.setEnabled(docTable.getSelectedRowCount() > 0);
openDocumentsAction.setEnabled(docTable.getSelectedRowCount() > 0);
moveUpAction.setEnabled(docTable.getSelectedRowCount() > 0
&& !docTable.isRowSelected(0));
moveDownAction.setEnabled(docTable.getSelectedRowCount() > 0
&& !docTable.isRowSelected(docTable.getRowCount() - 1));
}
});
Gate.getCreoleRegister().addCreoleListener(new CreoleListener() {
@Override
public void resourceLoaded(CreoleEvent e) {
if (e.getResource() instanceof Document) {
documentsLoadedCount++;
changeMessage();
}
}
@Override
public void resourceUnloaded(CreoleEvent e) {
if (e.getResource() instanceof Document) {
documentsLoadedCount--;
changeMessage();
}
}
@Override
public void datastoreOpened(CreoleEvent e) { /* do nothing */ }
@Override
public void datastoreCreated(CreoleEvent e) { /* do nothing */ }
@Override
public void datastoreClosed(CreoleEvent e) { /* do nothing */ }
@Override
public void resourceRenamed(Resource resource, String oldName,
String newName) { /* do nothing */ }
});
}
@Override
public void cleanup(){
super.cleanup();
corpus = null;
}
@Override
public void setTarget(Object target){
if(corpus != null && corpus != target){
//we already had a different corpus
corpus.removeCorpusListener(this);
}
if(!(target instanceof Corpus)){
throw new IllegalArgumentException(
"The GATE corpus editor can only be used with a GATE corpus!\n" +
target.getClass().toString() + " is not a GATE corpus!");
}
this.corpus = (Corpus)target;
corpus.addCorpusListener(this);
docTableModel.dataChanged();
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
docTableModel.fireTableDataChanged();
}
});
}
@Override
public void documentAdded(final CorpusEvent e) {
docTableModel.dataChanged();
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
changeMessage();
docTableModel.fireTableRowsInserted(e.getDocumentIndex(),
e.getDocumentIndex());
}
});
}
@Override
public void documentRemoved(final CorpusEvent e) {
docTableModel.dataChanged();
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
changeMessage();
docTableModel.fireTableRowsDeleted(e.getDocumentIndex(),
e.getDocumentIndex());
}
});
}
class DocumentTableModel extends AbstractTableModel{
public DocumentTableModel(){
documentNames = new ArrayList();
}
/**
* Called externally when the underlying corpus has changed.
*/
private void dataChanged(){
List newDocs = new ArrayList();
if(corpus != null){
newDocs.addAll(corpus.getDocumentNames());
}
List oldDocs = documentNames;
documentNames = newDocs;
oldDocs.clear();
}
@Override
public int getColumnCount() {
return COLUMN_COUNT;
}
@Override
public int getRowCount() {
return documentNames.size();
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
//invalid indexes might appear when update events are slow to act
if(rowIndex < 0 || rowIndex >= documentNames.size() ||
columnIndex < 0 || columnIndex > COLUMN_COUNT) return null;
switch(columnIndex) {
case COL_INDEX:
return rowIndex;
case COL_NAME:
return documentNames.get(rowIndex);
default:
return null;
}
}
@Override
public Class getColumnClass(int columnIndex) {
switch(columnIndex) {
case COL_INDEX:
return Integer.class;
case COL_NAME:
return String.class;
default:
return String.class;
}
}
@Override
public String getColumnName(int column) {
return COLUMN_NAMES[column];
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
private List documentNames;
private final String[] COLUMN_NAMES = {"Index", "Document name"};
private static final int COL_INDEX = 0;
private static final int COL_NAME = 1;
private static final int COLUMN_COUNT = 2;
}
class DocumentNameRenderer extends DefaultTableCellRenderer implements
ListCellRenderer{
public DocumentNameRenderer(){
super();
setIcon(MainFrame.getIcon("document"));
}
@Override
public Component getListCellRendererComponent(JList list, String value,
int index, boolean isSelected, boolean cellHasFocus) {
// prepare the renderer
return getTableCellRendererComponent(docTable, value, isSelected,
cellHasFocus, index, DocumentTableModel.COL_NAME);
}
@Override
public Dimension getMaximumSize() {
//we don't mind being extended horizontally
Dimension dim = super.getMaximumSize();
if(dim != null){
dim.width = Integer.MAX_VALUE;
setMaximumSize(dim);
}
return dim;
}
@Override
public Dimension getMinimumSize() {
//we don't like being squashed!
return getPreferredSize();
}
}
class MoveUpAction extends AbstractAction{
public MoveUpAction(){
super("Move up", MainFrame.getIcon("up"));
putValue(SHORT_DESCRIPTION, "Moves selected document(s) up");
putValue(MNEMONIC_KEY, KeyEvent.VK_UP);
}
@Override
public void actionPerformed(ActionEvent e) {
int[] rowsTable = docTable.getSelectedRows();
int[] rowsCorpus = new int[rowsTable.length];
for(int i = 0; i < rowsTable.length; i++)
rowsCorpus[i] = docTable.rowViewToModel(rowsTable[i]);
Arrays.sort(rowsCorpus);
//starting from the smallest one, move each element up
for(int i = 0; i < rowsCorpus.length; i++){
if(rowsCorpus[i] > 0){
//swap the doc with the one before
//serial corpus does not load the document on remove, so we need
//to load the document explicitly
boolean wasLoaded = corpus.isDocumentLoaded(rowsCorpus[i]);
Document doc = corpus.get(rowsCorpus[i]);
corpus.remove(rowsCorpus[i]);
rowsCorpus[i] = rowsCorpus[i] - 1;
corpus.add(rowsCorpus[i], doc);
if(!wasLoaded){
corpus.unloadDocument(doc);
Factory.deleteResource(doc);
}
}
}
//restore selection
//the remove / add events will cause the table to be updated
//we need to only restore the selection after that happened
final int[] selectedRowsCorpus = new int[rowsCorpus.length];
System.arraycopy(rowsCorpus, 0, selectedRowsCorpus, 0, rowsCorpus.length);
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
docTable.clearSelection();
for(int i = 0; i < selectedRowsCorpus.length; i++){
int rowTable = docTable.rowModelToView(selectedRowsCorpus[i]);
docTable.getSelectionModel().addSelectionInterval(rowTable,
rowTable);
}
}
});
}
}
class MoveDownAction extends AbstractAction{
public MoveDownAction(){
super("Move down", MainFrame.getIcon("down"));
putValue(SHORT_DESCRIPTION, "Moves selected document(s) down");
putValue(MNEMONIC_KEY, KeyEvent.VK_DOWN);
}
@Override
public void actionPerformed(ActionEvent e) {
int[] rowsTable = docTable.getSelectedRows();
int[] rowsCorpus = new int[rowsTable.length];
for(int i = 0; i < rowsTable.length; i++)
rowsCorpus[i] = docTable.rowViewToModel(rowsTable[i]);
Arrays.sort(rowsCorpus);
//starting from the largest one, move each element down
for(int i = rowsCorpus.length -1; i >=0; i--){
if(rowsCorpus[i] < corpus.size() -1){
//swap the doc with the one before
//serial corpus does not load the document on remove, so we need
//to load the document explicitly
boolean wasLoaded = corpus.isDocumentLoaded(rowsCorpus[i]);
Document doc = corpus.get(rowsCorpus[i]);
corpus.remove(rowsCorpus[i]);
rowsCorpus[i]++;
corpus.add(rowsCorpus[i], doc);
if(!wasLoaded){
corpus.unloadDocument(doc);
Factory.deleteResource(doc);
}
}
}
//restore selection
//the remove / add events will cause the table to be updated
//we need to only restore the selection after that happened
final int[] selectedRowsCorpus = new int[rowsCorpus.length];
System.arraycopy(rowsCorpus, 0, selectedRowsCorpus, 0, rowsCorpus.length);
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
docTable.clearSelection();
for(int i = 0; i < selectedRowsCorpus.length; i++){
int rowTable = docTable.rowModelToView(selectedRowsCorpus[i]);
docTable.getSelectionModel().addSelectionInterval(rowTable,
rowTable);
}
}
});
}
}
class NewDocumentAction extends AbstractAction{
public NewDocumentAction(){
super("Add document", MainFrame.getIcon("add-document"));
putValue(SHORT_DESCRIPTION, "Add new document(s) to this corpus");
putValue(MNEMONIC_KEY, KeyEvent.VK_ENTER);
}
@Override
public void actionPerformed(ActionEvent e){
List loadedDocuments;
try {
// get all the documents loaded in the system
loadedDocuments = Gate.getCreoleRegister()
.getAllInstances("gate.Document");
} catch(GateException ge) {
//gate.Document is not registered in creole.xml....what is!?
throw new GateRuntimeException(
"gate.Document is not registered in the creole register!\n" +
"Something must be terribly wrong...take a vacation!");
}
Vector docNames = new Vector();
for (Resource loadedDocument : new ArrayList(loadedDocuments)) {
if (corpus.contains(loadedDocument)) {
loadedDocuments.remove(loadedDocument);
} else {
docNames.add(loadedDocument.getName());
}
}
JList docList = new JList(docNames);
docList.getSelectionModel().setSelectionInterval(0, docNames.size()-1);
docList.setCellRenderer(renderer);
final JOptionPane optionPane = new JOptionPane(new JScrollPane(docList),
JOptionPane.QUESTION_MESSAGE, JOptionPane.OK_CANCEL_OPTION);
final JDialog dialog = optionPane.createDialog(CorpusEditor.this,
"Add document(s) to this corpus");
docList.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
optionPane.setValue(JOptionPane.OK_OPTION);
dialog.dispose();
}
}
});
dialog.setVisible(true);
if(optionPane.getValue().equals(JOptionPane.OK_OPTION)){
int[] selectedIndices = docList.getSelectedIndices();
for (int selectedIndice : selectedIndices) {
corpus.add((Document)loadedDocuments.get(selectedIndice));
}
}
changeMessage();
}
}
class RemoveDocumentsAction extends AbstractAction{
public RemoveDocumentsAction(){
super("Remove documents", MainFrame.getIcon("remove-document"));
putValue(SHORT_DESCRIPTION,
"Removes selected document(s) from this corpus");
putValue(MNEMONIC_KEY, KeyEvent.VK_DELETE);
}
@Override
public void actionPerformed(ActionEvent e){
int[] selectedIndexes = docTable.getSelectedRows();
int[] corpusIndexes = new int[selectedIndexes.length];
for(int i = 0; i < selectedIndexes.length; i++)
corpusIndexes[i] = docTable.rowViewToModel(selectedIndexes[i]);
Arrays.sort(corpusIndexes);
//remove the document starting with the one with the highest index
for(int i = corpusIndexes.length-1; i >= 0; i--){
corpus.remove(corpusIndexes[i]);
}
docTable.clearSelection();
changeMessage();
}
}
class OpenDocumentsAction extends AbstractAction{
public OpenDocumentsAction(){
super("Open documents", MainFrame.getIcon("document"));
putValue(SHORT_DESCRIPTION,
"Opens selected document(s) in a document editor");
}
@Override
public void actionPerformed(ActionEvent e){
Component root = SwingUtilities.getRoot(CorpusEditor.this);
if (!(root instanceof MainFrame)) { return; }
final MainFrame mainFrame = (MainFrame) root;
final int[] selectedRows = docTable.getSelectedRows();
if (selectedRows.length > 10) {
Object[] possibleValues =
{ "Open the "+selectedRows.length+" documents", "Don't open" };
int selectedValue =
JOptionPane.showOptionDialog(docTable, "Do you want to open "
+selectedRows.length+" documents in the central tabbed pane ?",
"Warning", JOptionPane.DEFAULT_OPTION,
JOptionPane.QUESTION_MESSAGE, null,
possibleValues, possibleValues[1]);
if (selectedValue == 1
|| selectedValue == JOptionPane.CLOSED_OPTION) {
return;
}
}
for (int row : selectedRows) {
// load the document if inside a datastore
corpus.get(docTable.rowViewToModel(row));
}
SwingUtilities.invokeLater(new Runnable() { @Override
public void run() {
for (int row : selectedRows) {
Document doc = corpus.get(docTable.rowViewToModel(row));
// show the document in the central view
mainFrame.select(doc);
}
}});
}
}
protected void changeMessage() {
SwingUtilities.invokeLater(new Runnable(){ @Override
public void run() {
if (corpus == null || corpus.size() == 0) {
newDocumentAction.setEnabled(true);
messageLabel.setText(
"To add or remove documents to this corpus:
" +
"
use the toolbar buttons at the top of this view" +
"
drag documents from the left resources tree and drop them below" +
"
right click on the corpus in the resources tree and choose 'Populate'" +
"
");
messageLabel.setVisible(true);
}
// This is a really stupid way of checking if all the open documents are in the
//corpus and it seems to be causing more problems than it might possibly be trying
//to solve
/*else if (documentsLoadedCount > 0
&& documentsLoadedCount == corpus.size()) {
newDocumentAction.setEnabled(false);
messageLabel.setText("All the documents loaded in the " +
"system are in this corpus.");
messageLabel.setVisible(true);
} */
else if (documentsLoadedCount == 0) {
newDocumentAction.setEnabled(false);
if (corpus.getDataStore() == null) {
messageLabel.setText(
"There are no documents loaded in the system. " +
"Press F1 for help.");
} else {
messageLabel.setText("Open a document to load it from the datastore.");
}
messageLabel.setVisible(true);
} else {
newDocumentAction.setEnabled(true);
messageLabel.setVisible(false);
}
}});
}
protected XJTable docTable;
protected DocumentTableModel docTableModel;
protected DocumentNameRenderer renderer;
protected JToolBar toolbar;
protected Corpus corpus;
protected NewDocumentAction newDocumentAction;
protected RemoveDocumentsAction removeDocumentsAction;
protected MoveUpAction moveUpAction;
protected MoveDownAction moveDownAction;
protected OpenDocumentsAction openDocumentsAction;
protected JLabel messageLabel;
protected int documentsLoadedCount;
}