
gate.gui.CorpusEditor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gate-core Show documentation
Show all versions of gate-core Show documentation
GATE - general achitecture for text engineering - is
open source software capable of solving almost any text processing problem.
This artifact enables you to embed the core GATE Embedded with its essential dependencies.
You will able to use the GATE Embedded API and load and store GATE XML documents. This
artifact is the perfect dependency for CREOLE plugins or for applications that need to customize
the GATE dependencies due to confict with their own dependencies or for lower footprint.
The newest version!
/*
* 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 extends String> 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;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy