SerialDatastoreViewer.java
001 /*
002  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
003  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
004  *
005  *  This file is part of GATE (see http://gate.ac.uk/), and is free
006  *  software, licenced under the GNU Library General Public License,
007  *  Version 2, June 1991 (in the distribution as file licence.html,
008  *  and also available at http://gate.ac.uk/gate/licence.html).
009  *
010  *  Valentin Tablan 23/01/2001
011  *
012  *  $Id: SerialDatastoreViewer.java 12006 2009-12-01 17:24:28Z thomas_heitz $
013  *
014  */
015 package gate.gui;
016 
017 import java.awt.Point;
018 import java.awt.event.*;
019 import java.beans.BeanInfo;
020 import java.beans.Introspector;
021 import java.text.NumberFormat;
022 import java.util.*;
023 
024 import javax.swing.*;
025 import javax.swing.tree.*;
026 
027 import gate.*;
028 import gate.creole.*;
029 import gate.creole.metadata.CreoleResource;
030 import gate.creole.metadata.GuiType;
031 import gate.event.DatastoreEvent;
032 import gate.event.DatastoreListener;
033 import gate.persist.PersistenceException;
034 import gate.security.SecurityException;
035 import gate.util.*;
036 
037 @CreoleResource(name = "Serial Datastore Viewer", guiType = GuiType.LARGE,
038     resourceDisplayed = "gate.persist.SerialDataStore", mainViewer = true)
039 public class SerialDatastoreViewer extends JScrollPane implements
040                                                       VisualResource,
041                                                       DatastoreListener {
042 
043   public SerialDatastoreViewer() {
044   }
045 
046   public void cleanup() {
047     datastore.removeDatastoreListener(this);
048     myHandle = null;
049     datastore = null;
050   }
051 
052   /** Accessor for features. */
053   public FeatureMap getFeatures() {
054     return features;
055   }// getFeatures()
056 
057   /** Mutator for features */
058   public void setFeatures(FeatureMap features) {
059     this.features = features;
060   }// setFeatures()
061 
062   // Parameters utility methods
063   /**
064    * Gets the value of a parameter of this resource.
065    
066    @param paramaterName the name of the parameter
067    @return the current value of the parameter
068    */
069   public Object getParameterValue(String paramaterName)
070           throws ResourceInstantiationException {
071     return AbstractResource.getParameterValue(this, paramaterName);
072   }
073 
074   /**
075    * Sets the value for a specified parameter.
076    
077    @param paramaterName the name for the parameteer
078    @param parameterValue the value the parameter will receive
079    */
080   public void setParameterValue(String paramaterName, Object parameterValue)
081           throws ResourceInstantiationException {
082     // get the beaninfo for the resource bean, excluding data about
083     // Object
084     BeanInfo resBeanInf = null;
085     try {
086       resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
087     }
088     catch(Exception e) {
089       throw new ResourceInstantiationException(
090               "Couldn't get bean info for resource "
091                       this.getClass().getName() + Strings.getNl()
092                       "Introspector exception was: " + e);
093     }
094     AbstractResource.setParameterValue(this, resBeanInf, paramaterName,
095             parameterValue);
096   }
097 
098   /**
099    * Sets the values for more parameters in one step.
100    
101    @param parameters a feature map that has paramete names as keys and
102    *          parameter values as values.
103    */
104   public void setParameterValues(FeatureMap parameters)
105           throws ResourceInstantiationException {
106     AbstractResource.setParameterValues(this, parameters);
107   }
108 
109   /** Initialise this resource, and return it. */
110   public Resource init() throws ResourceInstantiationException {
111     return this;
112   }// init()
113 
114   public void clear() {
115   }
116 
117   public void setTarget(Object target) {
118     if(target == null) {
119       datastore = null;
120       return;
121     }
122     if(target instanceof DataStore) {
123       datastore = (DataStore)target;
124       initLocalData();
125       initGuiComponents();
126       initListeners();
127     }
128     else {
129       throw new IllegalArgumentException(
130               "SerialDatastoreViewers can only be used with GATE serial datastores!\n"
131                       + target.getClass().toString()
132                       " is not a GATE serial datastore!");
133     }
134   }
135 
136   public void setHandle(Handle handle) {
137     if(handle instanceof NameBearerHandle) {
138       myHandle = (NameBearerHandle)handle;
139     }
140   }
141 
142   protected void fireProgressChanged(int e) {
143     myHandle.fireProgressChanged(e);
144   }// protected void fireProgressChanged(int e)
145 
146   protected void fireProcessFinished() {
147     myHandle.fireProcessFinished();
148   }// protected void fireProcessFinished()
149 
150   protected void fireStatusChanged(String e) {
151     myHandle.fireStatusChanged(e);
152   }
153 
154   protected void initLocalData() {
155   }
156 
157   protected void initGuiComponents() {
158     treeRoot = new DefaultMutableTreeNode(datastore.getName()true);
159     treeModel = new DefaultTreeModel(treeRoot, true);
160     mainTree = new JTree();
161     mainTree.setModel(treeModel);
162     mainTree.setExpandsSelectedPaths(true);
163     mainTree.expandPath(new TreePath(treeRoot));
164     try {
165       Iterator lrTypesIter = datastore.getLrTypes().iterator();
166       CreoleRegister cReg = Gate.getCreoleRegister();
167       while(lrTypesIter.hasNext()) {
168         String type = (String)lrTypesIter.next();
169         ResourceData rData = (ResourceData)cReg.get(type);
170         DefaultMutableTreeNode node = new DefaultMutableTreeNode(rData
171                 .getName());
172         treeModel.insertNodeInto(node, treeRoot, treeRoot.getChildCount());
173         mainTree.expandPath(new TreePath(new Object[] {treeRoot, node}));
174         Iterator lrIDsIter = datastore.getLrIds(type).iterator();
175         while(lrIDsIter.hasNext()) {
176           String id = (String)lrIDsIter.next();
177           DSEntry entry = new DSEntry(datastore.getLrName(id), id, type);
178           DefaultMutableTreeNode lrNode = new DefaultMutableTreeNode(entry,
179                   false);
180           treeModel.insertNodeInto(lrNode, node, node.getChildCount());
181           node.add(lrNode);
182         }
183       }
184     }
185     catch(PersistenceException pe) {
186       throw new GateRuntimeException(pe.toString());
187     }
188     DefaultTreeSelectionModel selectionModel = new DefaultTreeSelectionModel();
189     selectionModel
190             .setSelectionMode(DefaultTreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
191     mainTree.setSelectionModel(selectionModel);
192     getViewport().setView(mainTree);
193 
194     popup = new JPopupMenu();
195     deleteAction = new DeleteAction();
196     loadAction = new LoadAction();
197     popup.add(deleteAction);
198     popup.add(loadAction);
199   }// protected void initGuiComponents()
200 
201   protected void initListeners() {
202     datastore.addDatastoreListener(this);
203     mainTree.addMouseListener(new MouseAdapter() {
204       public void mouseClicked(MouseEvent e) {
205         if(SwingUtilities.isLeftMouseButton(e&& e.getClickCount() == 2) {
206           // double click -> just load the resource
207           TreePath path = mainTree.getPathForLocation(e.getX(), e.getY());
208           Object value = null;
209           if(path != null)
210             value = ((DefaultMutableTreeNode)path.getLastPathComponent())
211                     .getUserObject();
212           if(value != null && value instanceof DSEntry) {
213             loadAction.ignoreSelection = true;
214             loadAction.setLocation(path);
215             loadAction.actionPerformed(null);
216           }
217         }
218       }// public void mouseClicked(MouseEvent e)
219 
220       @Override
221       public void mousePressed(MouseEvent e) {
222         if(e.isPopupTrigger()) {
223           // where inside the tree?
224           TreePath path = mainTree.getPathForLocation(e.getX(), e.getY());
225           deleteAction.setLocation(path);
226           loadAction.setLocation(path);
227           popup.show(SerialDatastoreViewer.this, e.getX(), e.getY());
228         }
229       }
230 
231       @Override
232       public void mouseReleased(MouseEvent e) {
233         if(e.isPopupTrigger()) {
234           // where inside the tree?
235           TreePath path = mainTree.getPathForLocation(e.getX(), e.getY());
236           deleteAction.setLocation(path);
237           loadAction.setLocation(path);
238           popup.show(SerialDatastoreViewer.this, e.getX(), e.getY());
239         }
240       }
241     });
242   }// protected void initListeners()
243 
244   /**
245    * ACtion to delete all selected resources.
246    */
247   class DeleteAction extends AbstractAction {
248     public DeleteAction() {
249       super("Delete");
250     }
251 
252     public void actionPerformed(ActionEvent e) {
253       // delete all selected resources
254       TreePath[] selectedPaths = mainTree.getSelectionPaths();
255       // if no selection -> delete path under cursor
256       if(selectedPaths == null && location != null) {
257         selectedPaths = new TreePath[] {location};
258         location = null;
259       }
260       if(selectedPaths != null) {
261         for(TreePath aPath : selectedPaths) {
262           Object value = ((DefaultMutableTreeNode)aPath.getLastPathComponent())
263                   .getUserObject();
264           if(value instanceof DSEntry) {
265             DSEntry entry = (DSEntry)value;
266             try {
267               datastore.delete(entry.type, entry.id);
268               // project.frame.resourcesTreeModel.treeChanged();
269             }
270             catch(gate.persist.PersistenceException pe) {
271               JOptionPane.showMessageDialog(SerialDatastoreViewer.this,
272                       "Error!\n" + pe.toString()"GATE",
273                       JOptionPane.ERROR_MESSAGE);
274               pe.printStackTrace(Err.getPrintWriter());
275             }
276             catch(SecurityException se) {
277               JOptionPane.showMessageDialog(SerialDatastoreViewer.this,
278                       "Error!\n" + se.toString()"GATE",
279                       JOptionPane.ERROR_MESSAGE);
280               se.printStackTrace(Err.getPrintWriter());
281             }
282           }
283         }
284       }
285     }
286 
287     /**
288      * The path where the mouse click occurred.
289      */
290     TreePath location;
291 
292     public TreePath getLocation() {
293       return location;
294     }
295 
296     public void setLocation(TreePath location) {
297       this.location = location;
298     }
299   }
300 
301   /**
302    * Action to load all selected resources.
303    */
304   class LoadAction extends AbstractAction {
305     public LoadAction() {
306       super("Load");
307     }
308 
309     public void actionPerformed(ActionEvent e) {
310       Runnable runner = new Runnable(){
311         public void run(){
312           // load all selected resources
313           TreePath[] selectedPaths = mainTree.getSelectionPaths();
314           if(ignoreSelection){
315             ignoreSelection = false;
316            selectedPaths = null;
317           }
318           // if no selection -> load path under cursor
319           if(selectedPaths == null && location != null) {
320             selectedPaths = new TreePath[] {location};
321             location = null;
322           }
323           if(selectedPaths != null) {
324             for(TreePath aPath : selectedPaths) {
325               Object value = ((DefaultMutableTreeNode)aPath.getLastPathComponent())
326                       .getUserObject();
327               if(value instanceof DSEntry) {
328                 DSEntry entry = (DSEntry)value;
329                 try {
330                   MainFrame.lockGUI("Loading " + entry.name);
331                   long start = System.currentTimeMillis();
332                   fireStatusChanged("Loading " + entry.name);
333                   fireProgressChanged(0);
334                   FeatureMap params = Factory.newFeatureMap();
335                   params.put(DataStore.DATASTORE_FEATURE_NAME, datastore);
336                   params.put(DataStore.LR_ID_FEATURE_NAME, entry.id);
337                   FeatureMap features = Factory.newFeatureMap();
338                   Resource res = Factory.createResource(entry.type, params, features,
339                           entry.name);
340                   // project.frame.resourcesTreeModel.treeChanged();
341                   fireProgressChanged(0);
342                   fireProcessFinished();
343                   long end = System.currentTimeMillis();
344                   fireStatusChanged(entry.name
345                           " loaded in "
346                           + NumberFormat.getInstance().format(
347                                   (double)(end - start1000" seconds");
348                 }
349                 catch(ResourceInstantiationException rie) {
350                   MainFrame.unlockGUI();
351                   JOptionPane.showMessageDialog(SerialDatastoreViewer.this,
352                           "Error!\n" + rie.toString()"GATE",
353                           JOptionPane.ERROR_MESSAGE);
354                   rie.printStackTrace(Err.getPrintWriter());
355                   fireProgressChanged(0);
356                   fireProcessFinished();
357                 }
358                 finally {
359                   MainFrame.unlockGUI();
360                 }            
361               }
362             }
363           }  
364         }
365       };
366       Thread thread = new Thread(runner, 
367               SerialDatastoreViewer.this.getClass().getCanonicalName() +  
368               " DS Loader");
369       thread.setPriority(Thread.MIN_PRIORITY);
370       thread.start();
371     }
372 
373     /**
374      * The path where the mouse click occurred.
375      */
376     protected TreePath location;
377     
378     protected boolean ignoreSelection = false;
379 
380     public TreePath getLocation() {
381       return location;
382     }
383 
384     public void setLocation(TreePath location) {
385       this.location = location;
386     }
387   }
388 
389   class DSEntry {
390     DSEntry(String name, String id, String type) {
391       this.name = name;
392       this.type = type;
393       this.id = id;
394     }// DSEntry
395 
396     public String toString() {
397       return name;
398     }
399 
400 
401     String name;
402 
403     String type;
404 
405     String id;
406 
407   }// class DSEntry
408 
409   DefaultMutableTreeNode treeRoot;
410 
411   DefaultTreeModel treeModel;
412 
413   JTree mainTree;
414 
415   DataStore datastore;
416 
417   NameBearerHandle myHandle;
418 
419   /**
420    * Action used to delete selected resources
421    */
422   protected DeleteAction deleteAction;
423 
424   /**
425    * Action object for loading resources.
426    */
427   protected LoadAction loadAction;
428 
429   /**
430    * The popup used for actions.
431    */
432   protected JPopupMenu popup;
433 
434   protected FeatureMap features;
435 
436   private transient Vector progressListeners;
437 
438   private transient Vector statusListeners;
439 
440   public void resourceAdopted(DatastoreEvent e) {
441     // do nothing; SerialDataStore does actually nothing on adopt()
442     // we'll have to listen for RESOURE_WROTE events
443   }
444 
445   public void resourceDeleted(DatastoreEvent e) {
446     String resID = (String)e.getResourceID();
447     DefaultMutableTreeNode node = null;
448     Enumeration nodesEnum = treeRoot.depthFirstEnumeration();
449     boolean found = false;
450     while(nodesEnum.hasMoreElements() && !found) {
451       node = (DefaultMutableTreeNode)nodesEnum.nextElement();
452       Object userObject = node.getUserObject();
453       found = userObject instanceof DSEntry
454               && ((DSEntry)userObject).id.equals(resID);
455     }
456     if(found) {
457       DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent();
458       treeModel.removeNodeFromParent(node);
459       if(parent.getChildCount() == 0treeModel.removeNodeFromParent(parent);
460     }
461   }
462 
463   public void resourceWritten(DatastoreEvent e) {
464     Resource res = e.getResource();
465     String resID = (String)e.getResourceID();
466     String resType = ((ResourceData)Gate.getCreoleRegister().get(
467             res.getClass().getName())).getName();
468     DefaultMutableTreeNode parent = treeRoot;
469     DefaultMutableTreeNode node = null;
470     // first look for the type node
471     Enumeration childrenEnum = parent.children();
472     boolean found = false;
473     while(childrenEnum.hasMoreElements() && !found) {
474       node = (DefaultMutableTreeNode)childrenEnum.nextElement();
475       found = node.getUserObject().equals(resType);
476     }
477     if(!found) {
478       // exhausted the children without finding the node -> new type
479       node = new DefaultMutableTreeNode(resType);
480       treeModel.insertNodeInto(node, parent, parent.getChildCount());
481     }
482     mainTree.expandPath(new TreePath(new Object[] {parent, node}));
483 
484     // now look for the resource node
485     parent = node;
486     childrenEnum = parent.children();
487     found = false;
488     while(childrenEnum.hasMoreElements() && !found) {
489       node = (DefaultMutableTreeNode)childrenEnum.nextElement();
490       found = ((DSEntry)node.getUserObject()).id.equals(resID);
491     }
492     if(!found) {
493       // exhausted the children without finding the node -> new resource
494       try {
495         DSEntry entry = new DSEntry(datastore.getLrName(resID), resID, res
496                 .getClass().getName());
497         node = new DefaultMutableTreeNode(entry, false);
498         treeModel.insertNodeInto(node, parent, parent.getChildCount());
499       }
500       catch(PersistenceException pe) {
501         pe.printStackTrace(Err.getPrintWriter());
502       }
503     }
504   }// public void resourceWritten(DatastoreEvent e)
505 
506 }// public class DSHandle