DocumentEditor.java
0001 /*
0002  * Copyright (c) 1995-2012, The University of Sheffield. See the file
0003  * COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
0004  
0005  * This file is part of GATE (see http://gate.ac.uk/), and is free software,
0006  * licenced under the GNU Library General Public License, Version 2, June 1991
0007  * (in the distribution as file licence.html, and also available at
0008  * http://gate.ac.uk/gate/licence.html).
0009  
0010  * Valentin Tablan, 22 March 2004
0011  
0012  * $Id: DocumentEditor.java 19839 2016-12-01 22:59:53Z markagreenwood $
0013  */
0014 package gate.gui.docview;
0015 
0016 import gate.Document;
0017 import gate.Factory;
0018 import gate.Gate;
0019 import gate.GateConstants;
0020 import gate.Resource;
0021 import gate.creole.AbstractVisualResource;
0022 import gate.creole.ResourceData;
0023 import gate.creole.ResourceInstantiationException;
0024 import gate.creole.metadata.CreoleResource;
0025 import gate.creole.metadata.GuiType;
0026 import gate.gui.ActionsPublisher;
0027 import gate.gui.MainFrame;
0028 import gate.gui.annedit.AnnotationData;
0029 import gate.gui.annedit.SearchExpressionsAction;
0030 import gate.swing.JMenuButton;
0031 import gate.util.GateRuntimeException;
0032 import gate.util.OptionsMap;
0033 import gate.util.Strings;
0034 
0035 import java.awt.BorderLayout;
0036 import java.awt.Component;
0037 import java.awt.ComponentOrientation;
0038 import java.awt.Dialog;
0039 import java.awt.Dimension;
0040 import java.awt.Frame;
0041 import java.awt.Insets;
0042 import java.awt.Window;
0043 import java.awt.event.ActionEvent;
0044 import java.awt.event.ActionListener;
0045 import java.awt.event.ComponentAdapter;
0046 import java.awt.event.ComponentEvent;
0047 import java.awt.event.ItemEvent;
0048 import java.awt.event.ItemListener;
0049 import java.awt.event.KeyEvent;
0050 import java.util.ArrayList;
0051 import java.util.Collections;
0052 import java.util.Comparator;
0053 import java.util.Date;
0054 import java.util.Iterator;
0055 import java.util.LinkedHashSet;
0056 import java.util.List;
0057 import java.util.Set;
0058 import java.util.Timer;
0059 import java.util.TimerTask;
0060 import java.util.regex.Matcher;
0061 import java.util.regex.Pattern;
0062 import java.util.regex.PatternSyntaxException;
0063 
0064 import javax.swing.AbstractAction;
0065 import javax.swing.Action;
0066 import javax.swing.Box;
0067 import javax.swing.BoxLayout;
0068 import javax.swing.ButtonGroup;
0069 import javax.swing.JButton;
0070 import javax.swing.JCheckBox;
0071 import javax.swing.JCheckBoxMenuItem;
0072 import javax.swing.JComponent;
0073 import javax.swing.JDialog;
0074 import javax.swing.JLabel;
0075 import javax.swing.JMenuItem;
0076 import javax.swing.JPopupMenu;
0077 import javax.swing.JProgressBar;
0078 import javax.swing.JRadioButtonMenuItem;
0079 import javax.swing.JScrollPane;
0080 import javax.swing.JSplitPane;
0081 import javax.swing.JTextField;
0082 import javax.swing.JToggleButton;
0083 import javax.swing.JToolBar;
0084 import javax.swing.KeyStroke;
0085 import javax.swing.SwingUtilities;
0086 import javax.swing.text.JTextComponent;
0087 
0088 /**
0089  * This is the GATE Document viewer/editor. This class is only the shell of the
0090  * main document VR, which gets populated with views (objects that implement the
0091  {@link DocumentView} interface. Contains a search dialog and an option menu
0092  * button.
0093  */
0094 @SuppressWarnings("serial")
0095 @CreoleResource(name = "Document Editor", guiType = GuiType.LARGE, resourceDisplayed = "gate.Document", mainViewer = true)
0096 public class DocumentEditor extends AbstractVisualResource implements
0097                                                           ActionsPublisher {
0098   /**
0099    * Save the layout of the views and selected annotations.
0100    */
0101   public void saveSettings() {
0102     DocumentEditor de = DocumentEditor.this;
0103     Gate.getUserConfig().put(
0104         DocumentEditor.class.getName() ".centralViewIdx",
0105         Strings.toString(de.centralViewIdx));
0106     Gate.getUserConfig().put(DocumentEditor.class.getName() ".rightViewIdx",
0107         Strings.toString(de.rightViewIdx));
0108     Gate.getUserConfig().put(DocumentEditor.class.getName() ".bottomViewIdx",
0109         Strings.toString(de.bottomViewIdx));
0110     Gate.getUserConfig().put(DocumentEditor.class.getName() ".topViewIdx",
0111         Strings.toString(de.topViewIdx));
0112     LinkedHashSet<String> setTypeSet = new LinkedHashSet<String>();
0113     DocumentView dv = de.getRightView();
0114     if(dv instanceof AnnotationSetsView) {
0115       AnnotationSetsView av = (AnnotationSetsView)dv;
0116       for(AnnotationSetsView.SetHandler sh : av.setHandlers) {
0117         for(AnnotationSetsView.TypeHandler th : sh.typeHandlers) {
0118           if(th.isSelected()) {
0119             setTypeSet.add((sh.set.getName() == null "" : sh.set.getName())
0120                 '.' + th.name);
0121           }
0122         }
0123       }
0124     }
0125     Gate.getUserConfig().put(DocumentEditor.class.getName() ".setTypeSet",
0126         Strings.toString(setTypeSet));
0127     DocumentView bottomView = de.getBottomView();
0128     if(bottomView instanceof AnnotationStackView) {
0129       AnnotationStackView view = (AnnotationStackView)bottomView;
0130       Gate.getUserConfig().put(
0131           DocumentEditor.class.getName() ".stackTypesFeatures",
0132           Strings.toString(view.typesFeatures));
0133       Gate.getUserConfig().put(
0134           DocumentEditor.class.getName() ".stackTargetSetName",
0135           view.targetSetName);
0136     }
0137   }
0138 
0139   /**
0140    * Restore the layout of the views and selected annotations.
0141    */
0142   public void restoreSettings() {
0143     final DocumentEditor de = DocumentEditor.this;
0144     Integer value =
0145         Gate.getUserConfig().getInt(
0146             DocumentEditor.class.getName() ".centralViewIdx");
0147     int centralViewIdx = (value == null: value;
0148     value =
0149         Gate.getUserConfig().getInt(
0150             DocumentEditor.class.getName() ".rightViewIdx");
0151     int rightViewIdx = (value == null? -: value;
0152     value =
0153         Gate.getUserConfig().getInt(
0154             DocumentEditor.class.getName() ".bottomViewIdx");
0155     int bottomViewIdx = (value == null? -: value;
0156     value =
0157         Gate.getUserConfig().getInt(
0158             DocumentEditor.class.getName() ".topViewIdx");
0159     int topViewIdx = (value == null? -: value;
0160     if(de.centralViewIdx != centralViewIdx
0161         && centralViews.size() > centralViewIdx) {
0162       de.setCentralView(centralViewIdx);
0163     }
0164     if(de.rightViewIdx != rightViewIdx && verticalViews.size() > rightViewIdx) {
0165       de.setRightView(rightViewIdx);
0166     }
0167     if(de.bottomViewIdx != bottomViewIdx
0168         && horizontalViews.size() > centralViewIdx) {
0169       de.setBottomView(bottomViewIdx);
0170     }
0171     if(de.topViewIdx != topViewIdx && horizontalViews.size() > centralViewIdx) {
0172       de.setTopView(topViewIdx);
0173     }
0174     DocumentView dv = de.getRightView();
0175     if(dv instanceof AnnotationSetsView) {
0176       Set<String> setTypeSet =
0177           Gate.getUserConfig().getSet(
0178               DocumentEditor.class.getName() ".setTypeSet");
0179       AnnotationSetsView av = (AnnotationSetsView)dv;
0180       for(AnnotationSetsView.SetHandler sh : av.setHandlers) {
0181         for(AnnotationSetsView.TypeHandler th : sh.typeHandlers) {
0182           th.setSelected(false);
0183           for(String setType : setTypeSet) {
0184             String[] values = setType.split("\\.");
0185             if(values.length != 2) {
0186               continue;
0187             }
0188             String setName = values[0].equals(""null : values[0];
0189             String typeName = values[1];
0190             if(av.getSetHandler(setName!= null
0191                 && av.getSetHandler(setName).getTypeHandler(typeName!= null) {
0192               av.setTypeSelected(setName, typeName, true);
0193             }
0194           }
0195         }
0196       }
0197     }
0198     DocumentView bottomView = de.getBottomView();
0199     if(bottomView instanceof AnnotationStackView) {
0200       AnnotationStackView view = (AnnotationStackView)bottomView;
0201       view.typesFeatures =
0202           Gate.getUserConfig().getMap(
0203               DocumentEditor.class.getName() ".stackTypesFeatures");
0204       view.targetSetName =
0205           Gate.getUserConfig().getString(
0206               DocumentEditor.class.getName() ".stackTargetSetName");
0207       view.targetSetLabel.setText("Target set: " + view.targetSetName);
0208     }
0209   }
0210 
0211   /**
0212    * The document view is just an empty shell. This method publishes the actions
0213    * from the contained views.
0214    */
0215   @Override
0216   public List<Action> getActions() {
0217     List<Action> actions = new ArrayList<Action>();
0218     Iterator<DocumentView> viewIter;
0219     if(getCentralViews() != null) {
0220       viewIter = getCentralViews().iterator();
0221       while(viewIter.hasNext()) {
0222         actions.addAll(viewIter.next().getActions());
0223       }
0224     }
0225     if(getHorizontalViews() != null) {
0226       viewIter = getHorizontalViews().iterator();
0227       while(viewIter.hasNext()) {
0228         actions.addAll(viewIter.next().getActions());
0229       }
0230     }
0231     if(getVerticalViews() != null) {
0232       viewIter = getVerticalViews().iterator();
0233       while(viewIter.hasNext()) {
0234         actions.addAll(viewIter.next().getActions());
0235       }
0236     }
0237     return actions;
0238   }
0239 
0240   /*
0241    * (non-Javadoc)
0242    
0243    * @see gate.Resource#init()
0244    */
0245   @Override
0246   public Resource init() throws ResourceInstantiationException {
0247     addComponentListener(new ComponentAdapter() {
0248       @Override
0249       public void componentHidden(ComponentEvent e) {
0250       }
0251 
0252       @Override
0253       public void componentMoved(ComponentEvent e) {
0254       }
0255 
0256       @Override
0257       public void componentResized(ComponentEvent e) {
0258         if(!viewsInitedinitViews();
0259       }
0260 
0261       // lazily build the GUI only when needed
0262       @Override
0263       public void componentShown(ComponentEvent e) {
0264         if(!viewsInitedinitViews();
0265       }
0266     });
0267     return this;
0268   }
0269 
0270   @Override
0271   public void cleanup() {
0272     Iterator<DocumentView> viewsIter;
0273     if(centralViews != null) {
0274       viewsIter = centralViews.iterator();
0275       while(viewsIter.hasNext())
0276         viewsIter.next().cleanup();
0277       centralViews.clear();
0278     }
0279     if(horizontalViews != null) {
0280       viewsIter = horizontalViews.iterator();
0281       while(viewsIter.hasNext())
0282         viewsIter.next().cleanup();
0283       horizontalViews.clear();
0284     }
0285     if(verticalViews != null) {
0286       viewsIter = verticalViews.iterator();
0287       while(viewsIter.hasNext())
0288         viewsIter.next().cleanup();
0289       verticalViews.clear();
0290     }
0291   }
0292 
0293   protected void initViews() {
0294     viewsInited = true;
0295     // start building the UI
0296     setLayout(new BorderLayout());
0297     JProgressBar progressBar = new JProgressBar();
0298     progressBar.setStringPainted(true);
0299     progressBar.setMaximumSize(new Dimension(Integer.MAX_VALUE, progressBar
0300         .getPreferredSize().height));
0301     add(progressBar, BorderLayout.CENTER);
0302     progressBar.setString("Building views");
0303     progressBar.setValue(10);
0304     // create the skeleton UI
0305     topSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, null, null);
0306     topSplit.setResizeWeight(0.3);
0307     topSplit.setContinuousLayout(true);
0308     topSplit.setOneTouchExpandable(true);
0309     bottomSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, topSplit, null);
0310     bottomSplit.setResizeWeight(0.7);
0311     bottomSplit.setContinuousLayout(true);
0312     bottomSplit.setOneTouchExpandable(true);
0313     horizontalSplit =
0314         new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, bottomSplit, null);
0315     horizontalSplit.setResizeWeight(0.7);
0316     horizontalSplit.setContinuousLayout(true);
0317     horizontalSplit.setOneTouchExpandable(true);
0318     // create the bars
0319     topBar = new JToolBar(JToolBar.HORIZONTAL);
0320     topBar.setFloatable(false);
0321     add(topBar, BorderLayout.NORTH);
0322     progressBar.setValue(40);
0323     centralViews = new ArrayList<DocumentView>();
0324     verticalViews = new ArrayList<DocumentView>();
0325     horizontalViews = new ArrayList<DocumentView>();
0326     // parse all Creole resources and look for document views
0327     Set<String> vrSet = Gate.getCreoleRegister().getVrTypes();
0328     List<ResourceData> viewTypes = new ArrayList<ResourceData>();
0329     for(String vr : vrSet) {
0330       ResourceData rData = Gate.getCreoleRegister().get(vr);
0331       try {
0332         if(DocumentView.class.isAssignableFrom(rData.getResourceClass())) {
0333           viewTypes.add(rData);
0334         }
0335       catch(ClassNotFoundException cnfe) {
0336         cnfe.printStackTrace();
0337       }
0338     }
0339     // sort view types by label
0340     Collections.sort(viewTypes, new Comparator<ResourceData>() {
0341       @Override
0342       public int compare(ResourceData rd1, ResourceData rd2) {
0343         return rd1.getName().compareTo(rd2.getName());
0344       }
0345     });
0346     for(ResourceData viewType : viewTypes) {
0347       try {
0348         // create the resource
0349         DocumentView aView =
0350             (DocumentView)Factory.createResource(viewType.getClassName());
0351         aView.setTarget(document);
0352         aView.setOwner(this);
0353         // add the view
0354         addView(aView, viewType.getName());
0355       catch(ResourceInstantiationException rie) {
0356         rie.printStackTrace();
0357       }
0358     }
0359     // select the main central view only
0360     if(centralViews.size() 0setCentralView(0);
0361     // populate the main VIEW
0362     remove(progressBar);
0363     add(horizontalSplit, BorderLayout.CENTER);
0364     searchAction = new SearchAction();
0365     JButton searchButton = new JButton(searchAction);
0366     searchButton.setMargin(new Insets(0000));
0367     topBar.add(Box.createHorizontalStrut(5));
0368     topBar.add(searchButton);
0369     // add a key binding for the search function
0370     getInputMap(WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0371         KeyStroke.getKeyStroke("control F")"Search in text");
0372     getActionMap().put("Search in text", searchAction);
0373     // create menu that contains several options for the document editor
0374     final OptionsMap config = Gate.getUserConfig();
0375     final JPopupMenu optionsMenu = new JPopupMenu("Options menu");
0376     final JMenuItem saveCurrentLayoutMenuItem =
0377         new JMenuItem(new AbstractAction("Save Current Layout") {
0378           @Override
0379           public void actionPerformed(ActionEvent evt) {
0380             saveSettings();
0381           }
0382         });
0383     optionsMenu.add(saveCurrentLayoutMenuItem);
0384     final JCheckBoxMenuItem restoreLayoutAutomaticallyMenuItem =
0385         new JCheckBoxMenuItem("Restore Layout Automatically");
0386     restoreLayoutAutomaticallyMenuItem.setSelected(Gate.getUserConfig()
0387         .getBoolean(
0388             DocumentEditor.class.getName() ".restoreLayoutAutomatically"));
0389     restoreLayoutAutomaticallyMenuItem.addItemListener(new ItemListener() {
0390       @Override
0391       public void itemStateChanged(ItemEvent e) {
0392         // whenever the user checks/unchecks, update the config
0393         config.put(DocumentEditor.class.getName()
0394             ".restoreLayoutAutomatically",
0395             restoreLayoutAutomaticallyMenuItem.isSelected());
0396       }
0397     });
0398     optionsMenu.add(restoreLayoutAutomaticallyMenuItem);
0399     final JCheckBoxMenuItem readOnly = new JCheckBoxMenuItem("Read-only");
0400     readOnly.addItemListener(new ItemListener() {
0401       @Override
0402       public void itemStateChanged(ItemEvent e) {
0403         config.put(GateConstants.DOCEDIT_READ_ONLY, readOnly.isSelected());
0404         setEditable(!readOnly.isSelected());
0405       }
0406     });
0407     readOnly.setSelected(config.getBoolean(GateConstants.DOCEDIT_READ_ONLY));
0408     optionsMenu.addSeparator();
0409     optionsMenu.add(readOnly);
0410     // right to left orientation
0411     final JCheckBoxMenuItem rightToLeftOrientation =
0412         new JCheckBoxMenuItem("Right To Left Orientation");
0413     rightToLeftOrientation.addItemListener(new ItemListener() {
0414       @Override
0415       public void itemStateChanged(ItemEvent e) {
0416         config.put(GateConstants.DOC_RTOL_ORIENTATION,
0417             rightToLeftOrientation.isSelected());
0418         setRightToLeftOrientation(rightToLeftOrientation.isSelected());
0419       }
0420     });
0421     optionsMenu.addSeparator();
0422     optionsMenu.add(rightToLeftOrientation);
0423     ButtonGroup buttonGroup = new ButtonGroup();
0424     final JRadioButtonMenuItem insertAppend =
0425         new JRadioButtonMenuItem("Insert Append");
0426     buttonGroup.add(insertAppend);
0427     insertAppend.setSelected(config
0428         .getBoolean(GateConstants.DOCEDIT_INSERT_APPEND));
0429     insertAppend.addItemListener(new ItemListener() {
0430       @Override
0431       public void itemStateChanged(ItemEvent e) {
0432         config.put(GateConstants.DOCEDIT_INSERT_APPEND,
0433             insertAppend.isSelected());
0434       }
0435     });
0436     optionsMenu.addSeparator();
0437     optionsMenu.add(insertAppend);
0438     final JRadioButtonMenuItem insertPrepend =
0439         new JRadioButtonMenuItem("Insert Prepend");
0440     buttonGroup.add(insertPrepend);
0441     insertPrepend.setSelected(config
0442         .getBoolean(GateConstants.DOCEDIT_INSERT_PREPEND));
0443     insertPrepend.addItemListener(new ItemListener() {
0444       @Override
0445       public void itemStateChanged(ItemEvent e) {
0446         config.put(GateConstants.DOCEDIT_INSERT_PREPEND,
0447             insertPrepend.isSelected());
0448       }
0449     });
0450     optionsMenu.add(insertPrepend);
0451     // if none set then set the default one
0452     if(!(insertAppend.isSelected() || insertPrepend.isSelected())) {
0453       insertAppend.setSelected(true);
0454     }
0455     JMenuButton menuButton = new JMenuButton(optionsMenu);
0456     menuButton.setIcon(MainFrame.getIcon("expanded"));
0457     menuButton.setToolTipText("Options for the document editor");
0458     menuButton.setMargin(new Insets(0001))// icon is not centred
0459     topBar.add(Box.createHorizontalGlue());
0460     topBar.add(menuButton);
0461     // when the editor is shown restore views if layout saving is enable
0462     SwingUtilities.invokeLater(new Runnable() {
0463       @Override
0464       public void run() {
0465         if(Gate.getUserConfig().getBoolean(
0466             DocumentEditor.class.getName() ".restoreLayoutAutomatically")) {
0467           restoreSettings();
0468         }
0469       }
0470     });
0471     validate();
0472   }
0473 
0474   public List<DocumentView> getCentralViews() {
0475     return centralViews == null null : Collections
0476         .unmodifiableList(centralViews);
0477   }
0478 
0479   public List<DocumentView> getHorizontalViews() {
0480     return horizontalViews == null null : Collections
0481         .unmodifiableList(horizontalViews);
0482   }
0483 
0484   public List<DocumentView> getVerticalViews() {
0485     return verticalViews == null null : Collections
0486         .unmodifiableList(verticalViews);
0487   }
0488 
0489   /**
0490    * Registers a new view by adding it to the right list and creating the
0491    * activation button for it.
0492    
0493    @param view
0494    *          view to add to the GUI as a button
0495    @param name
0496    *          name of the view used in the GUI as a button name
0497    */
0498   protected void addView(DocumentView view, String name) {
0499     topBar.add(Box.createHorizontalStrut(5));
0500     final ViewButton viewButton = new ViewButton(view, name);
0501     switch(view.getType()){
0502       case DocumentView.CENTRAL:
0503         centralViews.add(view);
0504         // leftBar.add(new ViewButton(view, name));
0505         topBar.add(viewButton);
0506         break;
0507       case DocumentView.VERTICAL:
0508         verticalViews.add(view);
0509         // rightBar.add(new ViewButton(view, name));
0510         topBar.add(viewButton);
0511         break;
0512       case DocumentView.HORIZONTAL:
0513         horizontalViews.add(view);
0514         topBar.add(viewButton);
0515         // bottomBar.add(new ViewButton(view, name));
0516         break;
0517       default:
0518         throw new GateRuntimeException(getClass().getName()
0519             ": Invalid view type");
0520     }
0521     // binds a F-key to each view toggle button
0522     // avoid the F-Key F1,2,6,8,10 because already used
0523     if((fKeyNumber == 5|| (fKeyNumber == 7|| (fKeyNumber == 9)) {
0524       fKeyNumber++;
0525     }
0526     getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0527         KeyStroke.getKeyStroke("F" (fKeyNumber + 1)),
0528         "Shows view " + fKeyNumber + 1);
0529     getActionMap().put("Shows view " + fKeyNumber + 1new AbstractAction() {
0530       @Override
0531       public void actionPerformed(ActionEvent evt) {
0532         viewButton.doClick();
0533       }
0534     });
0535     // add a tooltip with the key shortcut
0536     if(view instanceof AnnotationSetsView) {
0537       getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0538           KeyStroke.getKeyStroke("shift F" (fKeyNumber + 1)),
0539           "Shows view " + fKeyNumber + 1);
0540       viewButton.setToolTipText("<html>Toggle the view of " + name
0541           "&nbsp;&nbsp;<font color=#667799><small>F" (fKeyNumber + 1)
0542           "&nbsp;&nbsp;</small></font>"
0543           "<br>Set last selected annotations "
0544           "&nbsp;&nbsp;<font color=#667799><small>Shift+F" (fKeyNumber + 1)
0545           "&nbsp;&nbsp;</small></font></html>");
0546     else {
0547       viewButton.setToolTipText("<html>Toggle the view of " + name
0548           "&nbsp;&nbsp;<font color=#667799><small>F" (fKeyNumber + 1)
0549           "&nbsp;&nbsp;</small></font></html>");
0550     }
0551     fKeyNumber++;
0552   }
0553 
0554   /**
0555    * Gets the currently showing top view
0556    
0557    @return {@link DocumentView} object.
0558    */
0559   protected DocumentView getTopView() {
0560     return (topViewIdx == -1null : horizontalViews.get(topViewIdx);
0561   }
0562 
0563   /**
0564    * Shows a new top view based on an index in the {@link #horizontalViews}
0565    * list.
0566    
0567    @param index
0568    *          the index in {@link #horizontalViews} list for the new view to be
0569    *          shown.
0570    */
0571   public void setTopView(int index) {
0572     // deactivate current view
0573     DocumentView oldView = getTopView();
0574     if(oldView != null) {
0575       oldView.setActive(false);
0576     }
0577     topViewIdx = index;
0578     if(topViewIdx == -1)
0579       setTopView(null);
0580     else {
0581       DocumentView newView = horizontalViews.get(topViewIdx);
0582       // hide if shown at the bottom
0583       if(bottomViewIdx == topViewIdx) {
0584         setBottomView(null);
0585         bottomViewIdx = -1;
0586       }
0587       // activate if necessary
0588       if(!newView.isActive()) {
0589         newView.setActive(true);
0590       }
0591       // show the new view
0592       setTopView(newView);
0593     }
0594   }
0595 
0596   /**
0597    * Sets a new UI component in the top location. This method is intended to
0598    * only be called from {@link #setTopView(int)}.
0599    
0600    @param view
0601    *          the new view to be shown.
0602    */
0603   protected void setTopView(DocumentView view) {
0604     topSplit.setTopComponent(view == null null : view.getGUI());
0605     topSplit.resetToPreferredSizes();
0606     updateBar(topBar);
0607     validate();
0608   }
0609 
0610   /**
0611    * Gets the currently showing central view
0612    
0613    @return {@link DocumentView} object.
0614    */
0615   protected DocumentView getCentralView() {
0616     return (centralViewIdx == -1null : centralViews.get(centralViewIdx);
0617   }
0618 
0619   /**
0620    * Shows a new central view based on an index in the {@link #centralViews}
0621    * list.
0622    
0623    @param index
0624    *          the index in {@link #centralViews} list for the new view to be
0625    *          shown.
0626    */
0627   public void setCentralView(int index) {
0628     // deactivate current view
0629     DocumentView oldView = getCentralView();
0630     if(oldView != null) {
0631       oldView.setActive(false);
0632     }
0633     centralViewIdx = index;
0634     if(centralViewIdx == -1)
0635       setCentralView(null);
0636     else {
0637       DocumentView newView = centralViews.get(centralViewIdx);
0638       // activate if necessary
0639       if(!newView.isActive()) {
0640         newView.setActive(true);
0641       }
0642       // show the new view
0643       setCentralView(newView);
0644     }
0645   }
0646 
0647   /**
0648    * Sets a new UI component in the central location. This method is intended to
0649    * only be called from {@link #setCentralView(int)}.
0650    
0651    @param view
0652    *          the new view to be shown.
0653    */
0654   protected void setCentralView(DocumentView view) {
0655     topSplit.setBottomComponent(view == null null : view.getGUI());
0656     topSplit.resetToPreferredSizes();
0657     // updateBar(leftBar);
0658     updateBar(topBar);
0659     validate();
0660   }
0661 
0662   /**
0663    * Gets the currently showing bottom view
0664    
0665    @return {@link DocumentView} object.
0666    */
0667   protected DocumentView getBottomView() {
0668     return (bottomViewIdx == -1null : horizontalViews.get(bottomViewIdx);
0669   }
0670 
0671   /**
0672    * Shows a new bottom view based on an index in the {@link #horizontalViews}
0673    * list.
0674    
0675    @param index
0676    *          the index in {@link #horizontalViews} list for the new view to be
0677    *          shown.
0678    */
0679   public void setBottomView(int index) {
0680     // deactivate current view
0681     DocumentView oldView = getBottomView();
0682     if(oldView != null) {
0683       oldView.setActive(false);
0684     }
0685     bottomViewIdx = index;
0686     if(bottomViewIdx == -1) {
0687       setBottomView(null);
0688     else {
0689       DocumentView newView = horizontalViews.get(bottomViewIdx);
0690       // hide if shown at the top
0691       if(topViewIdx == bottomViewIdx) {
0692         setTopView(null);
0693         topViewIdx = -1;
0694       }
0695       // activate if necessary
0696       if(!newView.isActive()) {
0697         newView.setActive(true);
0698       }
0699       // show the new view
0700       setBottomView(newView);
0701     }
0702   }
0703 
0704   /**
0705    * Sets a new UI component in the top location. This method is intended to
0706    * only be called from {@link #setBottomView(int)}.
0707    
0708    @param view
0709    *          the new view to be shown.
0710    */
0711   protected void setBottomView(DocumentView view) {
0712     bottomSplit.setBottomComponent(view == null null : view.getGUI());
0713     bottomSplit.resetToPreferredSizes();
0714     // updateBar(bottomBar);
0715     updateBar(topBar);
0716     validate();
0717   }
0718 
0719   /**
0720    * Gets the currently showing right view
0721    
0722    @return {@link DocumentView} object.
0723    */
0724   protected DocumentView getRightView() {
0725     return (rightViewIdx == -1null : verticalViews.get(rightViewIdx);
0726   }
0727 
0728   /**
0729    * Shows a new right view based on an index in the {@link #verticalViews}
0730    * list.
0731    
0732    @param index
0733    *          the index in {@link #verticalViews} list for the new view to be
0734    *          shown.
0735    */
0736   public void setRightView(int index) {
0737     // deactivate current view
0738     DocumentView oldView = getRightView();
0739     if(oldView != null) {
0740       oldView.setActive(false);
0741     }
0742     rightViewIdx = index;
0743     if(rightViewIdx == -1)
0744       setRightView(null);
0745     else {
0746       DocumentView newView = verticalViews.get(rightViewIdx);
0747       // activate if necessary
0748       if(!newView.isActive()) {
0749         newView.setActive(true);
0750       }
0751       // show the new view
0752       setRightView(newView);
0753     }
0754   }
0755 
0756   /**
0757    * Sets a new UI component in the right hand side location. This method is
0758    * intended to only be called from {@link #setRightView(int)}.
0759    
0760    @param view
0761    *          the new view to be shown.
0762    */
0763   protected void setRightView(DocumentView view) {
0764     horizontalSplit.setRightComponent(view == null null : view.getGUI());
0765     // updateBar(rightBar);
0766     updateBar(topBar);
0767     validate();
0768   }
0769 
0770   /**
0771    * Change the set of selected annotations. This new value will be sent to all
0772    * active constituent views.
0773    
0774    @param selectedAnnots
0775    *          list of AnnotationData to select
0776    */
0777   public void setSelectedAnnotations(List<AnnotationData> selectedAnnots) {
0778     selectedAnnotations.clear();
0779     selectedAnnotations.addAll(selectedAnnots);
0780     // notify all active views
0781     for(DocumentView aView : centralViews) {
0782       if(aView.isActive()) aView.setSelectedAnnotations(selectedAnnotations);
0783     }
0784     for(DocumentView aView : horizontalViews) {
0785       if(aView.isActive()) aView.setSelectedAnnotations(selectedAnnotations);
0786     }
0787     for(DocumentView aView : verticalViews) {
0788       if(aView.isActive()) aView.setSelectedAnnotations(selectedAnnotations);
0789     }
0790   }
0791 
0792   /**
0793    * Gets the current set of selected annotations.
0794    
0795    @return set of selected annotations
0796    */
0797   public List<AnnotationData> getSelectedAnnotations() {
0798     return selectedAnnotations;
0799   }
0800 
0801   /**
0802    * TODO: to remove? doesn't seems to be used anywhere.
0803    */
0804   protected void updateSplitLocation(JSplitPane split, int foo) {
0805     Component left = split.getLeftComponent();
0806     Component right = split.getRightComponent();
0807     if(left == null) {
0808       split.setDividerLocation(0);
0809       return;
0810     }
0811     if(right == null) {
0812       split.setDividerLocation(1);
0813       return;
0814     }
0815     Dimension leftPS = left.getPreferredSize();
0816     Dimension rightPS = right.getPreferredSize();
0817     double location =
0818         split.getOrientation() == JSplitPane.HORIZONTAL_SPLIT
0819             (double)leftPS.width / (leftPS.width + rightPS.width)
0820             (double)leftPS.height / (leftPS.height + rightPS.height);
0821     split.setDividerLocation(location);
0822   }
0823 
0824   /*
0825    * (non-Javadoc)
0826    
0827    * @see gate.VisualResource#setTarget(java.lang.Object)
0828    */
0829   @Override
0830   public void setTarget(Object target) {
0831     this.document = (Document)target;
0832   }
0833 
0834   /**
0835    * Updates the selected state of the buttons on one of the toolbars.
0836    
0837    @param toolbar
0838    *          toolbar to update
0839    */
0840   protected void updateBar(JToolBar toolbar) {
0841     Component btns[] = toolbar.getComponents();
0842     if(btns != null) {
0843       for(Component btn : btns) {
0844         if(btn instanceof ViewButton) ((ViewButton)btn).updateSelected();
0845       }
0846     }
0847   }
0848 
0849   /**
0850    @return the text component associated with this document editor.
0851    */
0852   protected JTextComponent getTextComponent() {
0853     return (JTextComponent)(((JScrollPane)getCentralView().getGUI())
0854         .getViewport()).getView();
0855   }
0856 
0857   /**
0858    * Set the document as editable or readonly. Documents are editable by
0859    * default.
0860    
0861    @param editable
0862    *          true if editable, false if readonly
0863    */
0864   public void setEditable(boolean editable) {
0865     getTextComponent().setEditable(editable);
0866   }
0867 
0868   /**
0869    * Set the text orientation in the document.
0870    
0871    @param set
0872    *          If true, text is displayed from right to left.
0873    */
0874   public void setRightToLeftOrientation(boolean set) {
0875     // which orientation?
0876     ComponentOrientation orientation =
0877         set
0878             ? ComponentOrientation.RIGHT_TO_LEFT
0879             : ComponentOrientation.LEFT_TO_RIGHT;
0880     // interested only in the text document view
0881     for(DocumentView aView : centralViews) {
0882       if(aView instanceof TextualDocumentView) {
0883         ((TextualDocumentView)aView).changeOrientation(orientation);
0884         break;
0885       }
0886     }
0887     // here interested only in the annotation sets view
0888     for(DocumentView aView : verticalViews) {
0889       if(aView instanceof AnnotationSetsView) {
0890         ((AnnotationSetsView)aView).changeOrientation(orientation);
0891         break;
0892       }
0893     }
0894   }
0895 
0896   /**
0897    * Dialog to search an expression in the document. Select the current match in
0898    * the document. Features: incremental search, case insensitive, whole word,
0899    * highlighted annotations, regular expression.
0900    */
0901   protected class SearchAction extends AbstractAction {
0902     public SearchAction() {
0903       super();
0904       putValue(SHORT_DESCRIPTION, "<html>Search within the document."
0905           "&nbsp;&nbsp;<font color=#667799><small>Ctrl-F"
0906           "&nbsp;&nbsp;</small></font></html>");
0907       putValue(SMALL_ICON, MainFrame.getIcon("search"));
0908     }
0909 
0910     @Override
0911     public void actionPerformed(ActionEvent evt) {
0912       if(searchDialog == null) {
0913         Window parent = SwingUtilities.getWindowAncestor(DocumentEditor.this);
0914         searchDialog =
0915             (parent instanceof Dialog)
0916                 new SearchDialog((Dialog)parent)
0917                 new SearchDialog((Frame)parent);
0918         searchDialog.pack();
0919         searchDialog.setLocationRelativeTo(DocumentEditor.this);
0920         searchDialog.setResizable(true);
0921         MainFrame.getGuiRoots().add(searchDialog);
0922       }
0923       JTextComponent textPane = getTextComponent();
0924       // if the user never gives the focus to the textPane then
0925       // there will never be any selection in it so we force it
0926       textPane.requestFocusInWindow();
0927       // put the selection of the document into the search text field
0928       if(textPane.getSelectedText() != null) {
0929         searchDialog.patternTextField.setText(textPane.getSelectedText());
0930       }
0931       if(searchDialog.isVisible()) {
0932         searchDialog.toFront();
0933       else {
0934         searchDialog.setVisible(true);
0935       }
0936       searchDialog.patternTextField.selectAll();
0937       searchDialog.patternTextField.requestFocusInWindow();
0938     }
0939   }
0940 
0941   protected class SearchDialog extends JDialog {
0942     SearchDialog(Frame owner) {
0943       super(owner, false);
0944       setTitle("Search in \"" + document.getName() "\"");
0945       initLocalData();
0946       initGuiComponents();
0947       initListeners();
0948     }
0949 
0950     SearchDialog(Dialog owner) {
0951       super(owner, false);
0952       setTitle("Search in \"" + document.getName() "\"");
0953       initLocalData();
0954       initGuiComponents();
0955       initListeners();
0956     }
0957 
0958     protected void initLocalData() {
0959       pattern = null;
0960       nextMatchStartsFrom = 0;
0961       findFirstAction = new AbstractAction("Find first") {
0962         {
0963           putValue(SHORT_DESCRIPTION, "Finds first match");
0964           putValue(MNEMONIC_KEY, KeyEvent.VK_F);
0965         }
0966 
0967         @Override
0968         public void actionPerformed(ActionEvent evt) {
0969           String content = document.getContent().toString();
0970           refresh();
0971           if(!isValidRegularExpression()) return;
0972           boolean found = false;
0973           int start = -1;
0974           int end = -1;
0975           nextMatchStartsFrom = 0;
0976           Matcher matcher = pattern.matcher(content);
0977           while(matcher.find(nextMatchStartsFrom&& !found) {
0978             start = matcher.start();
0979             end = matcher.end();
0980             found = false;
0981             if(highlightsChk.isSelected()) {
0982               javax.swing.text.Highlighter.Highlight[] highlights =
0983                   textPane.getHighlighter().getHighlights();
0984               for(javax.swing.text.Highlighter.Highlight h : highlights) {
0985                 if(h.getStartOffset() <= start && h.getEndOffset() >= end) {
0986                   found = true;
0987                   break;
0988                 }
0989               }
0990             else {
0991               found = true;
0992             }
0993             nextMatchStartsFrom = end;
0994           }
0995           if(found) {
0996             setTitle("Found: \""
0997                 + content.substring(Math.max(0, start - 13), start).replaceAll(
0998                     "\\s+"" ")
0999                 "["
1000                 + content.substring(start, end).replaceAll("\\s+"" ")
1001                 "]"
1002                 + content.substring(end, Math.min(content.length(), end + 13))
1003                     .replaceAll("\\s+"" ""\"");
1004             // select the match in the document
1005             textPane.setCaretPosition(start);
1006             textPane.moveCaretPosition(end);
1007           else {
1008             setTitle("Expression not found at all in the document.");
1009             findFirstAction.setEnabled(false);
1010             findNextAction.setEnabled(false);
1011           }
1012           patternTextField.requestFocusInWindow();
1013         }
1014       };
1015       findNextAction = new AbstractAction("Find next") {
1016         {
1017           putValue(SHORT_DESCRIPTION, "Finds next match");
1018           putValue(MNEMONIC_KEY, KeyEvent.VK_N);
1019         }
1020 
1021         @Override
1022         public void actionPerformed(ActionEvent evt) {
1023           String content = document.getContent().toString();
1024           refresh();
1025           if(!isValidRegularExpression()) return;
1026           boolean found = false;
1027           int start = -1;
1028           int end = -1;
1029           if(evt == null) {
1030             // incremental search
1031             nextMatchStartsFrom = textPane.getSelectionStart();
1032           else {
1033             nextMatchStartsFrom = textPane.getCaretPosition();
1034           }
1035           Matcher matcher = pattern.matcher(content);
1036           while(matcher.find(nextMatchStartsFrom&& !found) {
1037             start = matcher.start();
1038             end = matcher.end();
1039             found = false;
1040             if(highlightsChk.isSelected()) {
1041               javax.swing.text.Highlighter.Highlight[] highlights =
1042                   textPane.getHighlighter().getHighlights();
1043               for(javax.swing.text.Highlighter.Highlight h : highlights) {
1044                 if(h.getStartOffset() <= start && h.getEndOffset() >= end) {
1045                   found = true;
1046                   break;
1047                 }
1048               }
1049             else {
1050               found = true;
1051             }
1052             nextMatchStartsFrom = end;
1053           }
1054           if(found) {
1055             setTitle("Found: \""
1056                 + content.substring(Math.max(0, start - 13), start).replaceAll(
1057                     "\\s+"" ")
1058                 "["
1059                 + content.substring(start, end).replaceAll("\\s+"" ")
1060                 "]"
1061                 + content.substring(end, Math.min(content.length(), end + 13))
1062                     .replaceAll("\\s+"" ""\"");
1063             // select the match in the document
1064             textPane.setCaretPosition(start);
1065             textPane.moveCaretPosition(end);
1066           else {
1067             setTitle("Expression not found after the document caret.");
1068             findNextAction.setEnabled(false);
1069           }
1070           patternTextField.requestFocusInWindow();
1071         }
1072       };
1073       cancelAction = new AbstractAction("Cancel") {
1074         {
1075           putValue(SHORT_DESCRIPTION, "Cancel");
1076         }
1077 
1078         @Override
1079         public void actionPerformed(ActionEvent evt) {
1080           searchDialog.setVisible(false);
1081         }
1082       };
1083     }
1084 
1085     protected void initGuiComponents() {
1086       getContentPane().setLayout(
1087           new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
1088       getContentPane().add(Box.createVerticalStrut(5));
1089       Box hBox = Box.createHorizontalBox();
1090       hBox.add(Box.createHorizontalStrut(6));
1091       hBox.add(new JLabel("Find:"));
1092       hBox.add(Box.createHorizontalStrut(6));
1093       hBox.add(patternTextField = new JTextField(20));
1094       hBox.add(Box.createHorizontalStrut(3));
1095       JButton helpRegExpButton = new JButton("?");
1096       helpRegExpButton.setMargin(new Insets(0202));
1097       helpRegExpButton.setToolTipText("GATE search expression builder.");
1098       hBox.add(helpRegExpButton);
1099       hBox.add(Box.createHorizontalGlue());
1100       hBox.add(Box.createHorizontalStrut(6));
1101       hBox.add(Box.createHorizontalGlue());
1102       getContentPane().add(hBox);
1103       getContentPane().add(Box.createVerticalStrut(5));
1104       hBox = Box.createHorizontalBox();
1105       hBox.add(Box.createHorizontalStrut(6));
1106       hBox.add(ignoreCaseChk = new JCheckBox("Ignore case"true));
1107       hBox.add(Box.createHorizontalStrut(6));
1108       hBox.add(wholeWordsChk = new JCheckBox("Whole word"false));
1109       hBox.add(Box.createHorizontalStrut(6));
1110       hBox.add(regularExpressionChk = new JCheckBox("Regular Exp."false));
1111       regularExpressionChk.setToolTipText("Regular expression search.");
1112       hBox.add(Box.createHorizontalStrut(6));
1113       hBox.add(highlightsChk = new JCheckBox("Highlights"false));
1114       highlightsChk
1115           .setToolTipText("Restrict the search on the highlighted annotations.");
1116       hBox.add(Box.createHorizontalStrut(6));
1117       hBox.add(Box.createHorizontalGlue());
1118       getContentPane().add(hBox);
1119       getContentPane().add(Box.createVerticalStrut(5));
1120       hBox = Box.createHorizontalBox();
1121       hBox.add(Box.createHorizontalGlue());
1122       JButton findFirstButton = new JButton(findFirstAction);
1123       hBox.add(findFirstButton);
1124       hBox.add(Box.createHorizontalStrut(6));
1125       hBox.add(new JButton(findNextAction));
1126       hBox.add(Box.createHorizontalStrut(6));
1127       hBox.add(new JButton(cancelAction));
1128       hBox.add(Box.createHorizontalGlue());
1129       getContentPane().add(hBox);
1130       getContentPane().add(Box.createVerticalStrut(5));
1131       getRootPane().setDefaultButton(findFirstButton);
1132       helpRegExpButton.addActionListener(new SearchExpressionsAction(
1133           patternTextField, this, regularExpressionChk));
1134     }
1135 
1136     protected void initListeners() {
1137       addComponentListener(new ComponentAdapter() {
1138         @Override
1139         public void componentShown(ComponentEvent e) {
1140           refresh();
1141         }
1142       });
1143       // incremental search
1144       patternTextField.getDocument().addDocumentListener(
1145           new javax.swing.event.DocumentListener() {
1146             private Timer timer = new Timer("Document Editor search timer",
1147                 true);
1148 
1149             private TimerTask timerTask;
1150 
1151             @Override
1152             public void insertUpdate(javax.swing.event.DocumentEvent e) {
1153               update();
1154             }
1155 
1156             @Override
1157             public void removeUpdate(javax.swing.event.DocumentEvent e) {
1158               update();
1159             }
1160 
1161             @Override
1162             public void changedUpdate(javax.swing.event.DocumentEvent e) {
1163               refresh();
1164             }
1165 
1166             private void update() {
1167               if(timerTask != null) {
1168                 timerTask.cancel();
1169               }
1170               refresh();
1171               Date timeToRun = new Date(System.currentTimeMillis() 250);
1172               timerTask = new TimerTask() {
1173                 @Override
1174                 public void run() {
1175                   findNextAction.actionPerformed(null);
1176                 }
1177               };
1178               // add a delay
1179               timer.schedule(timerTask, timeToRun);
1180             }
1181           });
1182       wholeWordsChk.addActionListener(new ActionListener() {
1183         @Override
1184         public void actionPerformed(ActionEvent e) {
1185           refresh();
1186         }
1187       });
1188       ignoreCaseChk.addActionListener(new ActionListener() {
1189         @Override
1190         public void actionPerformed(ActionEvent e) {
1191           refresh();
1192         }
1193       });
1194       regularExpressionChk.addActionListener(new ActionListener() {
1195         @Override
1196         public void actionPerformed(ActionEvent e) {
1197           refresh();
1198         }
1199       });
1200       highlightsChk.addActionListener(new ActionListener() {
1201         @Override
1202         public void actionPerformed(ActionEvent e) {
1203           refresh();
1204         }
1205       });
1206       ((JComponent)getContentPane()).getInputMap(
1207           JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
1208           KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0)"cancelAction");
1209       ((JComponent)getContentPane()).getActionMap().put("cancelAction",
1210           cancelAction);
1211     }
1212 
1213     /**
1214      * Builds and validates the regular expression before use.
1215      
1216      @return true if the regular expression is valid, false otherwise.
1217      */
1218     protected boolean isValidRegularExpression() {
1219       String patternText = patternTextField.getText();
1220       boolean valid = true;
1221       // update patternRE
1222       try {
1223         String prefixPattern = wholeWordsChk.isSelected() "\\b" "";
1224         prefixPattern += regularExpressionChk.isSelected() "" "\\Q";
1225         String suffixPattern = regularExpressionChk.isSelected() "" "\\E";
1226         suffixPattern += wholeWordsChk.isSelected() "\\b" "";
1227         patternText = prefixPattern + patternText + suffixPattern;
1228         pattern =
1229             ignoreCaseChk.isSelected() ? Pattern.compile(patternText,
1230                 Pattern.CASE_INSENSITIVE: Pattern.compile(patternText);
1231       catch(PatternSyntaxException e) {
1232         setTitle(e.getMessage().replaceFirst("(?s) near index .+$""."));
1233         int index = e.getMessage().indexOf(" near index ");
1234         if(index != -1) {
1235           index += " near index ".length();
1236           patternTextField.setCaretPosition(Integer.valueOf(e.getMessage()
1237               .substring(index, index + 1)));
1238         }
1239         patternTextField.requestFocusInWindow();
1240         valid = false;
1241       }
1242       return valid;
1243     }
1244 
1245     protected void refresh() {
1246       String patternText = patternTextField.getText();
1247       if(patternText != null && patternText.length() 0) {
1248         // update actions state
1249         findFirstAction.setEnabled(true);
1250         findNextAction.setEnabled(true);
1251       else {
1252         findFirstAction.setEnabled(false);
1253         findNextAction.setEnabled(false);
1254       }
1255     }
1256 
1257     JTextComponent textPane = getTextComponent();
1258 
1259     JTextField patternTextField;
1260 
1261     JCheckBox ignoreCaseChk;
1262 
1263     JCheckBox wholeWordsChk;
1264 
1265     JCheckBox regularExpressionChk;
1266 
1267     JCheckBox highlightsChk;
1268 
1269     Pattern pattern;
1270 
1271     int nextMatchStartsFrom;
1272 
1273     Action findFirstAction;
1274 
1275     Action findNextAction;
1276 
1277     Action cancelAction;
1278   // end of class SearchDialog
1279 
1280   protected class ViewButton extends JToggleButton {
1281     public ViewButton(DocumentView aView, String name) {
1282       super();
1283       setSelected(false);
1284       // setBorder(null);
1285       this.view = aView;
1286       setText(name);
1287       // if(aView.getType() == DocumentView.HORIZONTAL){
1288       // setText(name);
1289       // }else if(aView.getType() == DocumentView.CENTRAL){
1290       // setIcon(new VerticalTextIcon(this, name,
1291       // VerticalTextIcon.ROTATE_LEFT));
1292       // }else if(aView.getType() == DocumentView.VERTICAL){
1293       // setIcon(new VerticalTextIcon(this, name,
1294       // VerticalTextIcon.ROTATE_RIGHT));
1295       // }
1296       addActionListener(new ActionListener() {
1297         @Override
1298         public void actionPerformed(ActionEvent evt) {
1299           if(isSelected()) {
1300             // show this new view
1301             switch(view.getType()){
1302               case DocumentView.CENTRAL:
1303                 setCentralView(centralViews.indexOf(view));
1304                 break;
1305               case DocumentView.VERTICAL:
1306                 setRightView(verticalViews.indexOf(view));
1307                 break;
1308               case DocumentView.HORIZONTAL:
1309                 // if(ViewButton.this.getParent() == topBar){
1310                 // setTopView(horizontalViews.indexOf(view));
1311                 // }else{
1312                 setBottomView(horizontalViews.indexOf(view));
1313                 // }
1314                 break;
1315             }
1316             // the view is an annotation sets view
1317             if(view instanceof AnnotationSetsView
1318                 && annotationSetsViewFirstTime) {
1319               annotationSetsViewFirstTime = false;
1320               AnnotationSetsView asv = (AnnotationSetsView)view;
1321               // shift key was pressed
1322               if(evt.getModifiers() == ActionEvent.SHIFT_MASK
1323                   || (evt.getModifiers() == ActionEvent.SHIFT_MASK
1324                       + ActionEvent.MOUSE_EVENT_MASK)) {
1325                 asv.restoreSavedSelectedTypes();
1326               else {
1327                 // expand default set
1328                 asv.getSetHandler(null).setExpanded(true);
1329                 if(document.getAnnotationSetNames() != null) {
1330                   for(Object setName : document.getAnnotationSetNames()) {
1331                     if(!setName.equals("Original markups")) {
1332                       // expand other annotation sets
1333                       asv.getSetHandler((String)setName).setExpanded(true);
1334                     }
1335                   }
1336                 }
1337               }
1338               // remove the tooltip for the shift key
1339               setToolTipText(getToolTipText().replaceFirst("<br>.*</html>$",
1340                   "</html>"));
1341             }
1342           else {
1343             // hide this view
1344             switch(view.getType()){
1345               case DocumentView.CENTRAL:
1346                 setCentralView(-1);
1347                 break;
1348               case DocumentView.VERTICAL:
1349                 setRightView(-1);
1350                 break;
1351               case DocumentView.HORIZONTAL:
1352                 // if(ViewButton.this.getParent() == topBar){
1353                 // setTopView(-1);
1354                 // }else{
1355                 setBottomView(-1);
1356                 // }
1357                 break;
1358             }
1359           }
1360           if(view instanceof TextualDocumentView) {
1361             // enable/disable according to text visibility
1362             searchAction.setEnabled(isSelected());
1363           }
1364         }
1365       });
1366     }
1367 
1368     public void updateSelected() {
1369       switch(view.getType()){
1370         case DocumentView.CENTRAL:
1371           setSelected(getCentralView() == view);
1372           break;
1373         case DocumentView.VERTICAL:
1374           setSelected(getRightView() == view);
1375           break;
1376         case DocumentView.HORIZONTAL:
1377           // if(ViewButton.this.getParent() == topBar){
1378           // setSelected(getTopView() == view);
1379           // }else{
1380           setSelected(getBottomView() == view);
1381           // }
1382           break;
1383       }
1384     }
1385 
1386     DocumentView view;
1387 
1388     boolean annotationSetsViewFirstTime = true;
1389   }
1390 
1391   protected JSplitPane horizontalSplit;
1392 
1393   protected JSplitPane topSplit;
1394 
1395   protected JSplitPane bottomSplit;
1396 
1397   /** The dialog used for text search */
1398   private SearchDialog searchDialog;
1399 
1400   protected Action searchAction;
1401 
1402   /**
1403    * Cached value for the selected annotations.
1404    */
1405   private List<AnnotationData> selectedAnnotations =
1406       new ArrayList<AnnotationData>();
1407 
1408   protected JToolBar topBar;
1409 
1410   // protected JToolBar rightBar;
1411   // protected JToolBar leftBar;
1412   // protected JToolBar bottomBar;
1413   protected Document document;
1414 
1415   /**
1416    * A list of {@link DocumentView} objects of type {@link DocumentView#CENTRAL}
1417    */
1418   protected List<DocumentView> centralViews;
1419 
1420   /**
1421    * A list of {@link DocumentView} objects of type
1422    {@link DocumentView#VERTICAL}
1423    */
1424   protected List<DocumentView> verticalViews;
1425 
1426   /**
1427    * A list of {@link DocumentView} objects of type
1428    {@link DocumentView#HORIZONTAL}
1429    */
1430   protected List<DocumentView> horizontalViews;
1431 
1432   /**
1433    * The index in {@link #centralViews} of the currently active central view.
1434    <code>-1</code> if none is active.
1435    */
1436   protected int centralViewIdx = -1;
1437 
1438   /**
1439    * The index in {@link #verticalViews} of the currently active right view.
1440    <code>-1</code> if none is active.
1441    */
1442   protected int rightViewIdx = -1;
1443 
1444   /**
1445    * The index in {@link #horizontalViews} of the currently active top view.
1446    <code>-1</code> if none is active.
1447    */
1448   protected int topViewIdx = -1;
1449 
1450   /**
1451    * The index in {@link #horizontalViews} of the currently active bottom view.
1452    <code>-1</code> if none is active.
1453    */
1454   protected int bottomViewIdx = -1;
1455 
1456   protected boolean viewsInited = false;
1457 
1458   /**
1459    * Used to know the last F-key used when adding a new view.
1460    */
1461   protected int fKeyNumber = 2;
1462 }