
gate.gui.docview.AnnotationListView 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) 2009-2010, Ontotext AD.
* 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).
*
* AnnotatioListView.java
*
* Valentin Tablan, May 25, 2004
*
* $Id: AnnotationListView.java 17606 2014-03-09 12:12:49Z markagreenwood $
*/
package gate.gui.docview;
import gate.*;
import gate.creole.*;
import gate.event.AnnotationEvent;
import gate.event.AnnotationListener;
import gate.gui.MainFrame;
import gate.gui.annedit.*;
import gate.swing.XJTable;
import gate.util.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.util.List;
import java.util.Timer;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.text.JTextComponent;
/**
* A tabular view for a list of annotations.
* Used as part of the document viewer to display all the annotation currently
* highlighted.
*/
@SuppressWarnings("serial")
public class AnnotationListView extends AbstractDocumentView
implements AnnotationListener, AnnotationList, AnnotationEditorOwner{
public AnnotationListView(){
annDataList = new ArrayList();
editorsCache = new HashMap();
}
/**
* (non-Javadoc)
* @see gate.gui.docview.AnnotationList#getAnnotationAtRow(int)
*/
@Override
public AnnotationData getAnnotationAtRow(int row) {
return annDataList == null ? null : annDataList.get(
table.rowViewToModel(row));
}
/* (non-Javadoc)
* @see gate.gui.docview.AnnotationList#getSelectionModel()
*/
@Override
public ListSelectionModel getSelectionModel() {
return table == null ? null : table.getSelectionModel();
}
@Override
public void cleanup() {
super.cleanup();
for(AnnotationData aData : annDataList){
aData.getAnnotation().removeAnnotationListener(this);
}
annDataList.clear();
textView = null;
}
/* (non-Javadoc)
* @see gate.gui.docview.AbstractDocumentView#initGUI()
*/
@Override
protected void initGUI() {
tableModel = new AnnotationTableModel();
table = new XJTable(tableModel);
table.setAutoResizeMode(XJTable.AUTO_RESIZE_LAST_COLUMN);
table.setSortable(true);
table.setSortedColumn(START_COL);
table.setIntercellSpacing(new Dimension(2, 0));
table.setEnableHidingColumns(true);
scroller = new JScrollPane(table);
mainPanel = new JPanel();
mainPanel.setLayout(new GridBagLayout());
GridBagConstraints constraints = new GridBagConstraints();
constraints.gridx = 0;
constraints.gridwidth = 4;
constraints.gridy = 0;
constraints.weightx = 1;
constraints.weighty = 1;
constraints.fill= GridBagConstraints.BOTH;
mainPanel.add(scroller, constraints);
constraints.gridx = GridBagConstraints.RELATIVE;
constraints.gridwidth = 1;
constraints.gridy = 1;
constraints.weightx = 0;
constraints.weighty = 0;
constraints.fill= GridBagConstraints.NONE;
constraints.anchor = GridBagConstraints.WEST;
statusLabel = new JLabel();
mainPanel.add(statusLabel, constraints);
constraints.fill= GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.EAST;
mainPanel.add(Box.createHorizontalStrut(10), constraints);
mainPanel.add(new JLabel("Select: "), constraints);
filterTextField = new JTextField(20);
filterTextField.setToolTipText("Select the rows containing this text.");
mainPanel.add(filterTextField, constraints);
//get a pointer to the text view used to display
//the selected annotations
Iterator centralViewsIter = owner.getCentralViews().iterator();
while(textView == null && centralViewsIter.hasNext()){
DocumentView aView = centralViewsIter.next();
if(aView instanceof TextualDocumentView)
textView = (TextualDocumentView)aView;
}
initListeners();
}
@Override
public Component getGUI(){
return mainPanel;
}
protected void initListeners(){
tableModel.addTableModelListener(new TableModelListener(){
@Override
public void tableChanged(TableModelEvent e){
statusLabel.setText(
Integer.toString(tableModel.getRowCount()) +
" Annotations (" +
Integer.toString(table.getSelectedRowCount()) +
" selected)");
}
});
table.getSelectionModel().
addListSelectionListener(new ListSelectionListener(){
@Override
public void valueChanged(ListSelectionEvent e){
if(!isActive())return;
if(e.getValueIsAdjusting()) return;
statusLabel.setText(
Integer.toString(tableModel.getRowCount()) +
" Annotations (" +
Integer.toString(table.getSelectedRowCount()) +
" selected)");
//if the new selection is already known about, no more work to do
if(localSelectionUpdating) return;
//update the list of selected annotations globally
int[] viewRows = table.getSelectedRows();
List selAnns = new ArrayList();
for(int i = 0; i < viewRows.length; i++){
int modelRow = table.rowViewToModel(viewRows[i]);
if(modelRow >= 0){
selAnns.add(annDataList.get(modelRow));
}
}
owner.setSelectedAnnotations(selAnns);
if(table.getSelectedRowCount() >= 1){
int viewRow = table.getSelectionModel().getLeadSelectionIndex();
if(table.getSelectionModel().isSelectedIndex(viewRow)){
int modelRow = table.rowViewToModel(viewRow);
AnnotationData aHandler = annDataList.get(modelRow);
//scroll to show the last highlight
if(aHandler != null && aHandler.getAnnotation() != null)
textView.scrollAnnotationToVisible(aHandler.getAnnotation());
}else{
//last operation was a remove selection
//do nothing
}
}
}
});
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent me) {
processMouseEvent(me);
}
@Override
public void mouseReleased(MouseEvent me) {
processMouseEvent(me);
}
@Override
public void mousePressed(MouseEvent me) {
int row = table.rowAtPoint(me.getPoint());
if(me.isPopupTrigger()
&& !table.isRowSelected(row)) {
// if right click outside the selection then reset selection
table.getSelectionModel().setSelectionInterval(row, row);
}
processMouseEvent(me);
}
protected void processMouseEvent(MouseEvent me){
int viewRow = table.rowAtPoint(me.getPoint());
final int modelRow = viewRow == -1 ?
viewRow :
table.rowViewToModel(viewRow);
// popup menu
if(me.isPopupTrigger()) {
JPopupMenu popup = new JPopupMenu();
popup.add(new DeleteAction());
//add the custom edit actions
if(modelRow != -1){
AnnotationData aHandler = annDataList.get(modelRow);
popup.addSeparator();
List specificEditorActions = getSpecificEditorActions(
aHandler.getAnnotationSet(), aHandler.getAnnotation());
for (Action action : specificEditorActions) {
popup.add(action);
}
if (!(popup.getComponent(popup.getComponentCount()-1)
instanceof JSeparator)) {
popup.addSeparator();
}
for (Action action : getGenericEditorActions(
aHandler.getAnnotationSet(), aHandler.getAnnotation())) {
if (specificEditorActions.contains(action)) { continue; }
popup.add(action);
}
if ((popup.getComponent(popup.getComponentCount()-1)
instanceof JSeparator)) {
popup.remove(popup.getComponentCount()-1);
}
}
popup.show(table, me.getX(), me.getY());
}
}
});
table.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(AncestorEvent event) {
// force the table to be sorted when the view is shown
tableModel.fireTableDataChanged();
}
@Override
public void ancestorMoved(AncestorEvent event) {
}
@Override
public void ancestorRemoved(AncestorEvent event) {
}
});
// select all the rows containing the text from filterTextField
filterTextField.getDocument().addDocumentListener( new DocumentListener() {
private Timer timer = new Timer("Annotation list selection timer", true);
private TimerTask timerTask;
@Override
public void changedUpdate(DocumentEvent e) { /* do nothing */ }
@Override
public void insertUpdate(DocumentEvent e) { update(); }
@Override
public void removeUpdate(DocumentEvent e) { update(); }
private void update() {
if (timerTask != null) { timerTask.cancel(); }
Date timeToRun = new Date(System.currentTimeMillis() + 300);
timerTask = new TimerTask() { @Override
public void run() {
selectRows();
}};
// add a delay
timer.schedule(timerTask, timeToRun);
}
private void selectRows() {
table.clearSelection();
if (filterTextField.getText().trim().length() < 2
|| table.getRowCount() == 0) {
return;
}
// block upward events
localSelectionUpdating = true;
for (int row = 0; row < table.getRowCount(); row++) {
for (int col = 0; col < table.getColumnCount(); col++) {
if (table.getValueAt(row, col) != null
&& table.getValueAt(row, col).toString()
.contains(filterTextField.getText().trim())) {
table.addRowSelectionInterval(row, row);
break;
}
}
}
localSelectionUpdating = false;
// update the highlights in the document
if (table.isCellSelected(0,0)) {
table.addRowSelectionInterval(0, 0);
} else {
table.removeRowSelectionInterval(0, 0);
}
}
});
// Delete key for deleting selected annotations
table.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_DELETE) {
new DeleteAction().actionPerformed(new ActionEvent(e.getSource(),
e.getID(), "", e.getWhen(), e.getModifiers()));
}
}
});
}
public List getSpecificEditorActions(AnnotationSet set,
Annotation annotation) {
List actions = new ArrayList();
//add the specific editors
List specificEditorClasses =
Gate.getCreoleRegister().getAnnotationVRs(annotation.getType());
if (specificEditorClasses != null &&
specificEditorClasses.size() > 0) {
for (String editorClass : specificEditorClasses) {
AnnotationVisualResource editor =
editorsCache.get(editorClass);
if (editor == null) {
//create the new type of editor
try {
editor = (AnnotationVisualResource)
Factory.createResource(editorClass);
editorsCache.put(editorClass, editor);
} catch (ResourceInstantiationException rie) {
rie.printStackTrace(Err.getPrintWriter());
}
}
actions.add(new EditAnnotationAction(set, annotation, editor));
}
}
return actions;
}
public List getGenericEditorActions(AnnotationSet set,
Annotation annotation) {
List actions = new ArrayList();
//add generic editors
List genericEditorClasses = Gate.getCreoleRegister().
getAnnotationVRs();
if (genericEditorClasses != null &&
genericEditorClasses.size() > 0) {
for (String editorClass : genericEditorClasses) {
AnnotationVisualResource editor = editorsCache.get(editorClass);
if (editor == null) {
//create the new type of editor
try {
ResourceData resData = Gate.getCreoleRegister().get(editorClass);
Class> resClass = resData.getResourceClass();
if (OwnedAnnotationEditor.class.isAssignableFrom(resClass)) {
OwnedAnnotationEditor newEditor =
(OwnedAnnotationEditor) resClass.newInstance();
newEditor.setOwner(AnnotationListView.this);
newEditor.init();
editor = newEditor;
} else {
editor = (AnnotationVisualResource)
Factory.createResource(editorClass);
}
editorsCache.put(editorClass, editor);
} catch (Exception rie) {
rie.printStackTrace(Err.getPrintWriter());
}
}
actions.add(new EditAnnotationAction(set, annotation, editor));
}
}
return actions;
}
protected class DeleteAction extends AbstractAction {
public DeleteAction() {
super("Delete Annotations");
putValue(SHORT_DESCRIPTION, "Delete selected annotations");
putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke("DELETE"));
}
@Override
public void actionPerformed(ActionEvent event){
if ((event.getModifiers() & ActionEvent.SHIFT_MASK)
!= ActionEvent.SHIFT_MASK
&& (event.getModifiers() & InputEvent.BUTTON1_MASK)
!= InputEvent.BUTTON1_MASK) {
// shows a confirm dialog before to delete annotations
int choice = JOptionPane.showOptionDialog(MainFrame.getInstance(), new
Object[]{"Are you sure you want to delete the "
+ table.getSelectedRowCount() + " selected annotations?",
"You can use Shift+Delete to bypass this dialog.\n\n"},
"Delete annotations",
JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null,
new String[]{"Delete annotations", "Cancel"}, "Cancel");
if (choice == JOptionPane.CLOSED_OPTION || choice == 1) { return; }
}
List annotationsData = new ArrayList();
for (int selectedRow : table.getSelectedRows()) {
annotationsData.add(annDataList.get(table.rowViewToModel(selectedRow)));
}
for (AnnotationData annotationData : annotationsData) {
annotationData.getAnnotationSet().remove(annotationData.getAnnotation());
}
}
}
/* (non-Javadoc)
* @see gate.gui.docview.AbstractDocumentView#registerHooks()
*/
@Override
protected void registerHooks() {
//this is called on activation
// showHighlights();
}
/* (non-Javadoc)
* @see gate.gui.docview.AbstractDocumentView#unregisterHooks()
*/
@Override
protected void unregisterHooks() {
//this is called on de-activation
//remove highlights
// textView.removeAllBlinkingHighlights();
}
/* (non-Javadoc)
* @see gate.gui.docview.DocumentView#getType()
*/
@Override
public int getType() {
return HORIZONTAL;
}
// protected void showHighlights(){
// int[] viewRows = table.getSelectedRows();
// AnnotationData aHandler = null;
// for(int i = 0; i < viewRows.length; i++){
// int modelRow = table.rowViewToModel(viewRows[i]);
// if(modelRow >= 0){
// aHandler = annDataList.get(modelRow);
// textView.addBlinkingHighlight(aHandler.getAnnotation());
// }
// }
// }
/**
* Adds an annotation to be displayed in the list.
* @param ann the annotation
* @param set the set containing the annotation
* @return a tag that can be used to refer to this annotation for future
* operations, e.g. when removing the annotation from display.
*/
public AnnotationDataImpl addAnnotation(Annotation ann, AnnotationSet set){
AnnotationDataImpl aData = new AnnotationDataImpl(set, ann);
annDataList.add(aData);
int row = annDataList.size() -1;
try{
localSelectionUpdating = true;
if(tableModel != null) tableModel.fireTableRowsInserted(row, row);
}finally{
localSelectionUpdating = false;
}
//listen for the new annotation's events
aData.getAnnotation().addAnnotationListener(AnnotationListView.this);
return aData;
}
public void removeAnnotation(AnnotationData tag){
int row = annDataList.indexOf(tag);
if(row >= 0){
AnnotationData aHandler = annDataList.get(row);
//remove from selection, if the table is built
List selAnns = owner.getSelectedAnnotations();
if(selAnns.remove(tag)){
owner.setSelectedAnnotations(selAnns);
}
aHandler.getAnnotation().removeAnnotationListener(
AnnotationListView.this);
annDataList.remove(row);
//owner was already notified
try{
localSelectionUpdating = true;
if(tableModel != null) tableModel.fireTableRowsDeleted(row, row);
}finally{
localSelectionUpdating = false;
}
}
}
public void removeAnnotations(Collection tags){
//to speed-up things, first remove all blinking highlights
if(table != null){
table.getSelectionModel().clearSelection();
}
//cache the selected annotations
final List selAnns = owner.getSelectedAnnotations();
boolean selectionChanged = false;
//now do the actual removal, in batch mode
for(AnnotationData aData : tags){
annDataList.remove(aData);
if(selAnns.remove(aData)){
selectionChanged = true;
}
aData.getAnnotation().removeAnnotationListener(AnnotationListView.this);
}
//update the table display
if(tableModel != null) tableModel.fireTableDataChanged();
//restore selection
if(selectionChanged){
//this needs to happen after the table has caught up with all the changes
//hence we need to queue it to the GUI thread
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
owner.setSelectedAnnotations(selAnns);
}});
}
}
/**
* Adds a batch of annotations in one go.
* For each annotation, a tag object will be created. The return value is
* list that returns the tags in the same order as the collection used
* for the input annotations.
* This method does not assume it was called from the UI Thread.
* @return a collection of tags corresponding to the annotations.
* @param annotations a collection of annotations
* @param set the annotation set to which all the annotations belong.
*/
public List addAnnotations(List annotations,
AnnotationSet set){
List tags = new ArrayList();
for(Annotation ann : annotations){
AnnotationData aTag = new AnnotationDataImpl(set, ann);
tags.add(aTag);
annDataList.add(aTag);
ann.addAnnotationListener(AnnotationListView.this);
}
try{
//this will cause the selection to change (the actual selection contents
//stay the same, but the row numbers may change)
//we want to avoid circular notifications.
localSelectionUpdating = true;
if(tableModel != null) tableModel.fireTableDataChanged();
}finally{
localSelectionUpdating = false;
}
return tags;
}
/**
* Returns the tags for all the annotations currently displayed
* @return a list of {@link AnnotationDataImpl}.
*/
public List getAllAnnotations(){
return annDataList;
}
@Override
public void annotationUpdated(AnnotationEvent e){
//update all occurrences of this annotation
// if annotations tab has not been set to visible state
// table will be null.
if(table == null) return;
//save selection
int[] selection = table.getSelectedRows();
if(selection != null){
localSelectionUpdating = true;
}
Annotation ann = (Annotation)e.getSource();
if(tableModel != null){
for(int i = 0; i < annDataList.size(); i++){
AnnotationData aHandler = annDataList.get(i);
if(aHandler.getAnnotation() == ann)tableModel.fireTableRowsUpdated(i, i);
}
}
//restore selection
table.clearSelection();
if(selection != null){
localSelectionUpdating = true;
for(int i = 0; i < selection.length; i++){
table.addRowSelectionInterval(selection[i], selection[i]);
}
localSelectionUpdating = false;
}
}
/* (non-Javadoc)
* @see gate.gui.docview.AbstractDocumentView#setSelectedAnnotations(java.util.List)
*/
@Override
public void setSelectedAnnotations(final List selectedAnnots) {
//if the list of selected annotations differs from the current selection,
//update the selection.
//otherwise do nothing (to break infinite looping)
//first get the local list of selected annotations
int[] viewRows = table.getSelectedRows();
List localSelAnns = new ArrayList();
for (int viewRow : viewRows) {
int modelRow = table.rowViewToModel(viewRow);
if (modelRow >= 0) {
localSelAnns.add(annDataList.get(modelRow));
}
}
//now compare with the new value
if(localSelAnns.size() == selectedAnnots.size()){
//same size, we need to actually compare contents
localSelAnns.removeAll(selectedAnnots);
if(localSelAnns.isEmpty()){
//lists are the same -> exit!
return;
}
}
//if we got this far, the selection lists were different
//we need to change the selection from the UI thread.
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
try{
//block upward events
localSelectionUpdating = true;
//update the local selection
table.getSelectionModel().clearSelection();
int rowToScrollTo = -1;
for(AnnotationData aData : selectedAnnots){
int modelRow = annDataList.indexOf(aData);
if(modelRow != -1){
int viewRow = table.rowModelToView(modelRow);
table.getSelectionModel().addSelectionInterval(viewRow, viewRow);
rowToScrollTo = viewRow;
}
}
if(rowToScrollTo >= 0){
table.scrollRectToVisible(table.getCellRect(rowToScrollTo, 0, true));
}
}finally{
//re-enable upward events
localSelectionUpdating = false;
}
}
});
}
/**
* Selects the annotation for the given tag.
* @param tag the tag of the annotation to be selected.
*/
public void selectAnnotationForTag(Object tag){
int modelPosition = annDataList.indexOf(tag);
table.getSelectionModel().clearSelection();
if(modelPosition != -1){
int tablePosition = table.rowModelToView(modelPosition);
table.getSelectionModel().setSelectionInterval(tablePosition,
tablePosition);
table.scrollRectToVisible(table.getCellRect(tablePosition, 0, false));
}
}
/* (non-Javadoc)
* @see gate.gui.annedit.AnnotationEditorOwner#annotationChanged(gate.Annotation, gate.AnnotationSet, java.lang.String)
*/
@Override
public void annotationChanged(Annotation ann, AnnotationSet set,
String oldType) {
//do nothing
}
/* (non-Javadoc)
* @see gate.gui.annedit.AnnotationEditorOwner#getNextAnnotation()
*/
@Override
public Annotation getNextAnnotation() {
return null;
}
/* (non-Javadoc)
* @see gate.gui.annedit.AnnotationEditorOwner#getPreviousAnnotation()
*/
@Override
public Annotation getPreviousAnnotation() {
return null;
}
/* (non-Javadoc)
* @see gate.gui.annedit.AnnotationEditorOwner#getTextComponent()
*/
@Override
public JTextComponent getTextComponent() {
//get a pointer to the text view used to display
//the selected annotations
Iterator centralViewsIter = owner.getCentralViews().iterator();
while(textView == null && centralViewsIter.hasNext()){
DocumentView aView = centralViewsIter.next();
if(aView instanceof TextualDocumentView)
textView = (TextualDocumentView)aView;
}
return (JTextArea)((JScrollPane)textView.getGUI()).getViewport().getView();
}
/* (non-Javadoc)
* @see gate.gui.annedit.AnnotationEditorOwner#selectAnnotation(gate.gui.annedit.AnnotationData)
*/
@Override
public void selectAnnotation(AnnotationData data) {
}
/* (non-Javadoc)
* @see gate.gui.docview.AnnotationList#getRowForAnnotation(gate.gui.annedit.AnnotationData)
*/
@Override
public int getRowForAnnotation(AnnotationData data) {
return annDataList.indexOf(data);
}
class AnnotationTableModel extends AbstractTableModel{
@Override
public int getRowCount(){
return annDataList.size();
}
@Override
public int getColumnCount(){
return 6;
}
@Override
public String getColumnName(int column){
switch(column){
case TYPE_COL: return "Type";
case SET_COL: return "Set";
case START_COL: return "Start";
case END_COL: return "End";
case ID_COL: return "Id";
case FEATURES_COL: return "Features";
default: return "?";
}
}
@Override
public Class> getColumnClass(int column){
switch(column){
case TYPE_COL: return String.class;
case SET_COL: return String.class;
case START_COL: return Long.class;
case END_COL: return Long.class;
case ID_COL: return Integer.class;
case FEATURES_COL: return String.class;
default: return String.class;
}
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex){
return false;
}
@SuppressWarnings("unchecked")
@Override
public Object getValueAt(int row, int column){
if(row >= annDataList.size()) return null;
AnnotationData aData = annDataList.get(row);
switch(column){
case TYPE_COL: return aData.getAnnotation().getType();
case SET_COL: return aData.getAnnotationSet().getName();
case START_COL: return aData.getAnnotation().getStartNode().getOffset();
case END_COL: return aData.getAnnotation().getEndNode().getOffset();
case ID_COL: return aData.getAnnotation().getId();
case FEATURES_COL:
//sort the features by name
FeatureMap features = aData.getAnnotation().getFeatures();
@SuppressWarnings("rawtypes")
List keyList = new ArrayList(features.keySet());
Collections.sort(keyList);
StringBuffer strBuf = new StringBuffer("{");
Iterator
© 2015 - 2025 Weber Informatics LLC | Privacy Policy