1   /*
2    *  Copyright (c) 1998-2005, The University of Sheffield.
3    *
4    *  This file is part of GATE (see http://gate.ac.uk/), and is free
5    *  software, licenced under the GNU Library General Public License,
6    *  Version 2, June 1991 (in the distribution as file licence.html,
7    *  and also available at http://gate.ac.uk/gate/licence.html).
8    *
9    *  Valentin Tablan 23/01/2001
10   *
11   *  $Id: SerialDatastoreViewer.java,v 1.21 2005/01/11 13:51:34 ian Exp $
12   *
13   */
14  package gate.gui;
15  
16  import java.awt.event.*;
17  import java.beans.BeanInfo;
18  import java.beans.Introspector;
19  import java.text.NumberFormat;
20  import java.util.*;
21  
22  import javax.swing.*;
23  import javax.swing.tree.*;
24  
25  import gate.*;
26  import gate.creole.*;
27  import gate.event.DatastoreEvent;
28  import gate.event.DatastoreListener;
29  import gate.persist.PersistenceException;
30  import gate.security.SecurityException;
31  import gate.util.*;
32  
33  public class SerialDatastoreViewer extends JScrollPane
34                                     implements VisualResource,
35                                                DatastoreListener {
36  
37    public SerialDatastoreViewer() {
38    }
39  
40  
41    public void cleanup(){
42      myHandle = null;
43      datastore = null;
44    }
45  
46    /** Accessor for features. */
47    public FeatureMap getFeatures(){
48      return features;
49    }//getFeatures()
50  
51    /** Mutator for features*/
52    public void setFeatures(FeatureMap features){
53      this.features = features;
54    }// setFeatures()
55  
56    //Parameters utility methods
57    /**
58     * Gets the value of a parameter of this resource.
59     * @param paramaterName the name of the parameter
60     * @return the current value of the parameter
61     */
62    public Object getParameterValue(String paramaterName)
63                  throws ResourceInstantiationException{
64      return AbstractResource.getParameterValue(this, paramaterName);
65    }
66  
67    /**
68     * Sets the value for a specified parameter.
69     *
70     * @param paramaterName the name for the parameteer
71     * @param parameterValue the value the parameter will receive
72     */
73    public void setParameterValue(String paramaterName, Object parameterValue)
74                throws ResourceInstantiationException{
75      // get the beaninfo for the resource bean, excluding data about Object
76      BeanInfo resBeanInf = null;
77      try {
78        resBeanInf = Introspector.getBeanInfo(this.getClass(), Object.class);
79      } catch(Exception e) {
80        throw new ResourceInstantiationException(
81          "Couldn't get bean info for resource " + this.getClass().getName()
82          + Strings.getNl() + "Introspector exception was: " + e
83        );
84      }
85      AbstractResource.setParameterValue(this, resBeanInf, paramaterName, parameterValue);
86    }
87  
88    /**
89     * Sets the values for more parameters in one step.
90     *
91     * @param parameters a feature map that has paramete names as keys and
92     * parameter values as values.
93     */
94    public void setParameterValues(FeatureMap parameters)
95                throws ResourceInstantiationException{
96      AbstractResource.setParameterValues(this, parameters);
97    }
98  
99    /** Initialise this resource, and return it. */
100   public Resource init() throws ResourceInstantiationException {
101     return this;
102   }//init()
103 
104   public void clear(){
105   }
106 
107   public void setTarget(Object target){
108     if(target == null){
109       datastore = null;
110       return;
111     }
112     if(target instanceof DataStore){
113       datastore = (DataStore)target;
114       initLocalData();
115       initGuiComponents();
116       initListeners();
117     }else{
118       throw new IllegalArgumentException(
119         "SerialDatastoreViewers can only be used with GATE serial datastores!\n" +
120         target.getClass().toString() + " is not a GATE serial datastore!");
121     }
122   }
123 
124 
125   public void setHandle(Handle handle){
126     if(handle instanceof NameBearerHandle){
127       myHandle = (NameBearerHandle)handle;
128     }
129   }
130 
131   protected void fireProgressChanged(int e) {
132     myHandle.fireProgressChanged(e);
133   }//protected void fireProgressChanged(int e)
134 
135   protected void fireProcessFinished() {
136     myHandle.fireProcessFinished();
137   }//protected void fireProcessFinished()
138 
139   protected void fireStatusChanged(String e) {
140     myHandle.fireStatusChanged(e);
141   }
142 
143   protected void initLocalData(){
144   }
145 
146   protected void initGuiComponents(){
147     treeRoot = new DefaultMutableTreeNode(
148                  datastore.getName(), true);
149     treeModel = new DefaultTreeModel(treeRoot, true);
150     mainTree = new JTree();
151     mainTree.setModel(treeModel);
152     mainTree.setExpandsSelectedPaths(true);
153     mainTree.expandPath(new TreePath(treeRoot));
154     try {
155       Iterator lrTypesIter = datastore.getLrTypes().iterator();
156       CreoleRegister cReg = Gate.getCreoleRegister();
157       while(lrTypesIter.hasNext()){
158         String type = (String)lrTypesIter.next();
159         ResourceData rData = (ResourceData)cReg.get(type);
160         DefaultMutableTreeNode node = new DefaultMutableTreeNode(
161                                                               rData.getName());
162         treeModel.insertNodeInto(node, treeRoot, treeRoot.getChildCount());
163         mainTree.expandPath(new TreePath(new Object[]{treeRoot, node}));
164         Iterator lrIDsIter = datastore.getLrIds(type).iterator();
165         while(lrIDsIter.hasNext()){
166           String id = (String)lrIDsIter.next();
167           DSEntry entry = new DSEntry(datastore.getLrName(id), id, type);
168           DefaultMutableTreeNode lrNode =
169             new DefaultMutableTreeNode(entry, false);
170           treeModel.insertNodeInto(lrNode, node, node.getChildCount());
171           node.add(lrNode);
172         }
173       }
174     } catch(PersistenceException pe) {
175       throw new GateRuntimeException(pe.toString());
176     }
177     DefaultTreeSelectionModel selectionModel = new DefaultTreeSelectionModel();
178     selectionModel.setSelectionMode(
179         DefaultTreeSelectionModel.SINGLE_TREE_SELECTION);
180     mainTree.setSelectionModel(selectionModel);
181     getViewport().setView(mainTree);
182   }//protected void initGuiComponents()
183 
184   protected void initListeners(){
185     datastore.addDatastoreListener(this);
186     mainTree.addMouseListener(new MouseAdapter() {
187       public void mouseClicked(MouseEvent e) {
188         //where inside the tree?
189         TreePath path = mainTree.getPathForLocation(e.getX(), e.getY());
190         Object value = null;
191         if(path != null) value = ((DefaultMutableTreeNode)
192                                   path.getLastPathComponent()).getUserObject();
193 
194         if(SwingUtilities.isRightMouseButton(e)){
195           //right click
196           if(value != null && value instanceof DSEntry){
197             JPopupMenu popup = ((DSEntry)value).getPopup();
198             popup.show(SerialDatastoreViewer.this, e.getX(), e.getY());
199           }
200         }else if(SwingUtilities.isLeftMouseButton(e) &&
201                  e.getClickCount() == 2){
202           //double click -> just load the resource
203           if(value != null && value instanceof DSEntry){
204             new LoadAction((DSEntry)value).actionPerformed(null);
205           }
206         }
207       }//public void mouseClicked(MouseEvent e)
208     });
209   }//protected void initListeners()
210 
211 
212   class LoadAction extends AbstractAction {
213     LoadAction(DSEntry entry){
214       super("Load");
215       this.entry = entry;
216     }
217 
218     public void actionPerformed(ActionEvent e){
219       Runnable runnable = new Runnable(){
220         public void run(){
221           try{
222             MainFrame.lockGUI("Loading " + entry.name);
223             long start = System.currentTimeMillis();
224             fireStatusChanged("Loading " + entry.name);
225             fireProgressChanged(0);
226             FeatureMap params = Factory.newFeatureMap();
227             params.put(DataStore.DATASTORE_FEATURE_NAME, datastore);
228             params.put(DataStore.LR_ID_FEATURE_NAME, entry.id);
229             FeatureMap features = Factory.newFeatureMap();
230             Resource res = Factory.createResource(entry.type, params, features,
231                                                    entry.name);
232             //project.frame.resourcesTreeModel.treeChanged();
233             fireProgressChanged(0);
234             fireProcessFinished();
235             long end = System.currentTimeMillis();
236             fireStatusChanged(entry.name + " loaded in " +
237                               NumberFormat.getInstance().format(
238                               (double)(end - start) / 1000) + " seconds");
239           } catch(ResourceInstantiationException rie){
240             MainFrame.unlockGUI();
241             JOptionPane.showMessageDialog(SerialDatastoreViewer.this,
242                                           "Error!\n" + rie.toString(),
243                                           "GATE", JOptionPane.ERROR_MESSAGE);
244             rie.printStackTrace(Err.getPrintWriter());
245             fireProgressChanged(0);
246             fireProcessFinished();
247           }finally{
248             MainFrame.unlockGUI();
249           }
250         }
251       };//runnable
252       Thread thread = new Thread(Thread.currentThread().getThreadGroup(),
253                                  runnable,
254                                  "Loader from DS");
255       thread.setPriority(Thread.MIN_PRIORITY);
256       thread.start();
257     }// public void actionPerformed(ActionEvent e)
258     DSEntry entry;
259   }//class LoadAction extends AbstractAction
260 
261   class DeleteAction extends AbstractAction {
262     DeleteAction(DSEntry entry){
263       super("Delete");
264       this.entry = entry;
265     }
266 
267     public void actionPerformed(ActionEvent e){
268       try{
269         datastore.delete(entry.type, entry.id);
270         //project.frame.resourcesTreeModel.treeChanged();
271       }catch(gate.persist.PersistenceException pe){
272         JOptionPane.showMessageDialog(SerialDatastoreViewer.this,
273                                       "Error!\n" + pe.toString(),
274                                       "GATE", JOptionPane.ERROR_MESSAGE);
275         pe.printStackTrace(Err.getPrintWriter());
276       } catch(SecurityException se){
277         JOptionPane.showMessageDialog(SerialDatastoreViewer.this,
278                                       "Error!\n" + se.toString(),
279                                       "GATE", JOptionPane.ERROR_MESSAGE);
280         se.printStackTrace(Err.getPrintWriter());
281       }
282     }// public void actionPerformed(ActionEvent e)
283     DSEntry entry;
284   }// class DeleteAction
285 
286 
287   class DSEntry {
288     DSEntry(String name, String id, String type){
289       this.name = name;
290       this.type = type;
291       this.id = id;
292       popup = new JPopupMenu();
293       popup.add(new LoadAction(this));
294       popup.add(new DeleteAction(this));
295     }// DSEntry
296 
297     public String toString(){
298       return name;
299     }
300 
301     public JPopupMenu getPopup(){
302       return popup;
303     }
304 
305     String name;
306     String type;
307     String id;
308     JPopupMenu popup;
309   }// class DSEntry
310 
311   DefaultMutableTreeNode treeRoot;
312   DefaultTreeModel treeModel;
313   JTree mainTree;
314   DataStore datastore;
315   NameBearerHandle myHandle;
316   protected FeatureMap features;
317 
318   private transient Vector progressListeners;
319   private transient Vector statusListeners;
320   public void resourceAdopted(DatastoreEvent e) {
321     //do nothing; SerialDataStore does actually nothing on adopt()
322     //we'll have to listen for RESOURE_WROTE events
323   }
324 
325   public void resourceDeleted(DatastoreEvent e) {
326     String resID = (String) e.getResourceID();
327     DefaultMutableTreeNode node = null;
328     Enumeration nodesEnum = treeRoot.depthFirstEnumeration();
329     boolean found = false;
330     while(nodesEnum.hasMoreElements() && !found){
331       node = (DefaultMutableTreeNode)nodesEnum.nextElement();
332       Object userObject = node.getUserObject();
333       found = userObject instanceof DSEntry &&
334               ((DSEntry)userObject).id.equals(resID);
335     }
336     if(found){
337       DefaultMutableTreeNode parent = (DefaultMutableTreeNode)node.getParent();
338       treeModel.removeNodeFromParent(node);
339       if(parent.getChildCount() == 0) treeModel.removeNodeFromParent(parent);
340     }
341   }
342 
343   public void resourceWritten(DatastoreEvent e) {
344     Resource res = e.getResource();
345     String resID = (String) e.getResourceID();
346     String resType = ((ResourceData)Gate.getCreoleRegister().
347                       get(res.getClass().getName())).getName();
348     DefaultMutableTreeNode parent = treeRoot;
349     DefaultMutableTreeNode node = null;
350     //first look for the type node
351     Enumeration childrenEnum = parent.children();
352     boolean found = false;
353     while(childrenEnum.hasMoreElements() && !found){
354       node = (DefaultMutableTreeNode)childrenEnum.nextElement();
355       found = node.getUserObject().equals(resType);
356     }
357     if(!found){
358       //exhausted the children without finding the node -> new type
359       node = new DefaultMutableTreeNode(resType);
360       treeModel.insertNodeInto(node, parent, parent.getChildCount());
361     }
362     mainTree.expandPath(new TreePath(new Object[]{parent, node}));
363 
364     //now look for the resource node
365     parent = node;
366     childrenEnum = parent.children();
367     found = false;
368     while(childrenEnum.hasMoreElements() && !found){
369       node = (DefaultMutableTreeNode)childrenEnum.nextElement();
370       found = ((DSEntry)node.getUserObject()).id.equals(resID);
371     }
372     if(!found){
373       //exhausted the children without finding the node -> new resource
374       try{
375         DSEntry entry = new DSEntry(datastore.getLrName(resID), resID,
376                                     res.getClass().getName());
377         node = new DefaultMutableTreeNode(entry, false);
378         treeModel.insertNodeInto(node, parent, parent.getChildCount());
379       }catch(PersistenceException pe){
380         pe.printStackTrace(Err.getPrintWriter());
381       }
382     }
383   }//public void resourceWritten(DatastoreEvent e)
384 
385 }//public class DSHandle