1   /*
2    *  OntoLexEditorVR.java
3    *
4    *  Copyright (c) 1998-2001, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  Kalina Bontcheva, 20/02/2003
12   *
13   *  $Id: OntoLexEditorVR.java,v 1.2 2003/03/13 19:42:44 kalina Exp $
14   */
15  
16  package gate.gui.lexicon;
17  
18  import gate.creole.AbstractVisualResource;
19  import com.ontotext.gate.vr.*;
20  import gate.lexicon.*;
21  import gate.util.*;
22  import javax.swing.*;
23  import gate.creole.ontology.*;
24  import java.util.*;
25  import gate.*;
26  import javax.swing.event.ListSelectionEvent;
27  import javax.swing.event.ListSelectionListener;
28  import javax.swing.event.TreeSelectionEvent;
29  import javax.swing.event.TreeSelectionListener;
30  import javax.swing.tree.*;
31  import gate.util.GateRuntimeException;
32  import java.net.URL;
33  import java.awt.GridLayout;
34  import java.awt.Component;
35  import java.awt.Dimension;
36  import gate.gui.MainFrame;
37  
38  public class OntoLexEditorVR extends AbstractVisualResource
39      implements ListSelectionListener, TreeSelectionListener {
40  
41    public OntoLexEditorVR() {
42      initLocalData();
43      initGuiComponents();
44      initListeners();
45    }
46  
47    public void valueChanged(ListSelectionEvent e) {
48      Object source = ((JList) e.getSource()).getSelectedValue();
49      if (source == null || ! (source instanceof LexKBSynset)) {
50        ontoEditor.setSelectionRow(0);
51        selectedSynset = null;
52        return;
53      }
54      LexKBSynset theSynset = (LexKBSynset) source;
55      this.selectedSynset = theSynset;
56      updateOntologySelection();
57    }
58  
59    public void valueChanged(TreeSelectionEvent e) {
60      TreePath[] paths = e.getPaths();
61  
62    }
63  
64    protected void updateOntologySelection() {
65      if (selectedSynset == null) {
66        ontoEditor.setSelectionRow(0);
67        return;
68      }
69  
70      List conceptIDs = ontoLex.getConceptIds(selectedSynset.getId());
71      if (conceptIDs == null || conceptIDs.isEmpty()) {
72        //select the top of the ontology, since there is no corresponding concept
73        ontoEditor.setSelectionRow(0);
74        return;
75      }
76  
77      if (theOntology == null)
78        return;
79  
80      //select the given conceptIDs in the ontology editor
81      for (int i=0; i < conceptIDs.size(); i++) {
82        Object conceptID = conceptIDs.get(i);
83        OClass theClass = theOntology.getClassByName((String) conceptID);
84        TreePath thePath = treePath4Class(theClass);
85        if (thePath == null)
86          ontoEditor.setSelectionRow(0);
87        else if (i==0)
88          ontoEditor.getSelectionModel().setSelectionPath(thePath);
89        else
90          ontoEditor.getSelectionModel().addSelectionPath(thePath);
91      }//for
92  
93    }
94  
95    protected TreePath treePath4Class(OClass theClass) {
96      List thePathList = new ArrayList();
97      thePathList.add(ontoModel.getRoot());
98      TreePath thePath = null;
99      Iterator theTopsIter = ((ClassNode)ontoModel.getRoot()).getChildren();
100     boolean found = false;
101     while( !found && theTopsIter.hasNext()) {
102       ClassNode theTopNode = (ClassNode) theTopsIter.next();
103       OClass theTop = (OClass) theTopNode.getSource();
104       try {
105         //check if our class is a subtype of this top
106         if (theTop.getSubClasses(OClass.TRANSITIVE_CLOSURE).contains(theClass)) {
107           //if yes, let's find the full path
108           thePathList.add(theTopNode);
109           getRemainingPath(theTopNode, theClass, thePathList);
110           found = true;
111         }
112       } catch (NoSuchClosureTypeException ex) {
113         throw new GateRuntimeException(ex.getMessage());
114       }
115     }//while loop through the top concepts
116 
117     thePath = new TreePath(thePathList.toArray());
118     return thePath;
119   }
120 
121   protected void getRemainingPath(
122       ClassNode theParent, OClass theTarget, List thePath)
123       throws NoSuchClosureTypeException
124   {
125     Iterator theChildrenIter = theParent.getChildren();
126     while (theChildrenIter.hasNext()) {
127       ClassNode childNode = (ClassNode) theChildrenIter.next();
128       OClass theChild = (OClass) childNode.getSource();
129       if (theChild.equals(theTarget)) {
130         thePath.add(childNode);
131         break;
132       }
133       if (!theChild.getSubClasses(OClass.TRANSITIVE_CLOSURE).contains(theTarget))
134         continue;
135       thePath.add(childNode);
136       getRemainingPath(childNode, theTarget, thePath);
137     }
138   }
139 
140   protected void initLocalData(){
141   }
142 
143   protected void initGuiComponents(){
144     mainBox = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
145     leftBox = Box.createVerticalBox();
146     rightBox = Box.createVerticalBox();
147 
148     this.setLayout(gridLayout1);
149 
150     this.add(mainBox, null);
151     mainBox.add(leftBox);
152     mainBox.add(rightBox);
153 
154     JScrollPane ontoScroller = new JScrollPane(ontoEditor);
155 //    ontoScroller.setMinimumSize(new Dimension(300, 400));
156     rightBox.add(ontoScroller, null);
157     ontoEditor.setVisible(false);
158     ontoEditor.addTreeSelectionListener(this);
159     ontoEditor.getSelectionModel().setSelectionMode(
160         javax.swing.tree.TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
161 
162     KnowledgeBaseTreeCellRenderer kbTreeCellRenderer =
163                               new KnowledgeBaseTreeCellRenderer();
164     ontoEditor.setCellRenderer(kbTreeCellRenderer);
165 
166 
167     synsetScroller = new JScrollPane();
168     leftBox.add(synsetScroller, null);
169     synsetScroller.setVisible(false);
170 
171     addMappingButton = new JButton(new AddMappingAction());
172     addMappingButton.setText("Add Mapping");
173 
174     removeMappingButton = new JButton(new RemoveMappingAction());
175     removeMappingButton.setText("Remove Mapping");
176 
177     Box buttonBox = Box.createHorizontalBox();
178     buttonBox.add(addMappingButton);
179     buttonBox.add(Box.createHorizontalStrut(20));
180     buttonBox.add(removeMappingButton);
181     this.add(buttonBox);
182 
183   }
184 
185   protected void initListeners(){
186   }
187 
188  /**
189  * Called by the GUI when this viewer/editor has to initialise itself for a
190  * specific object.
191  * @param target the object (be it a {@link gate.Resource},
192  * {@link gate.DataStore} or whatever) this viewer has to display
193  */
194   public void setTarget(Object target) {
195     if(target == null) return;
196     if(!(target instanceof gate.lexicon.OntoLexLR)){
197       throw new GateRuntimeException(this.getClass().getName() +
198                                      " can only be used to display " +
199                                      gate.lexicon.OntoLexLR.class.getName() +
200                                      "\n" + target.getClass().getName() +
201                                      " is not a " +
202                                      gate.lexicon.OntoLexLR.class.getName() + "!");
203     }
204     this.ontoLex = (gate.lexicon.OntoLexLR) target;
205 
206     updateGUI();
207   }
208 
209   protected void updateGUI(){
210     Ontology ontology = loadOntology(ontoLex.getOntologyIdentifier());
211     ClassNode root = ClassNode.createRootNode(ontology, true);
212     this.ontoModel = new OntoTreeModel(root);
213     this.ontoEditor.setModel(ontoModel);
214     ontoEditor.setVisible(true);
215 
216     //remove myself from the listeners first, so there are no memory leaks
217     if (chooseSynsetPanel != null)
218       chooseSynsetPanel.removeSynsetSelectionListener(this);
219 
220     LexicalKnowledgeBase lexKB = loadLexicon(ontoLex.getLexKBIdentifier());
221     if (lexKB == null)
222       return;
223     chooseSynsetPanel = new ChooseSynsetPanel(lexKB, false);
224     chooseSynsetPanel.addSynsetSelectionListener(this);
225     selectedSynset = chooseSynsetPanel.getSelectedSynset();
226     synsetScroller.getViewport().add(chooseSynsetPanel);
227     synsetScroller.setVisible(true);
228   }
229 
230   private Ontology loadOntology(Object ontoId) {
231 
232     //first if the ontoId is a URL with a gate:// location, this needs to be
233     //converted to an absolute URL, coz otherwise this ontology's URL will
234     //not be found among the already loaded ones, because they are converted
235     if ((ontoId instanceof URL) &&
236         (((URL)ontoId).getProtocol().indexOf("gate")>=0) )
237       ontoId = gate.util.protocols.gate.Handler.class.getResource(
238                     Files.getResourcePath() + ((URL)ontoId).getPath());
239 
240     List lrs = Gate.getCreoleRegister().getPublicLrInstances();
241     Iterator iter1 = lrs.iterator();
242     while (iter1.hasNext()) {
243       gate.LanguageResource lr = (LanguageResource) iter1.next();
244       if (! (lr instanceof Ontology))
245         continue;
246       Ontology currentOntology = (Ontology) lr;
247       if (currentOntology.getURL().equals(ontoId)) {
248         theOntology = currentOntology;
249         break;
250       }
251     }//while
252 
253     //the ontology is not loaded, we must do that
254     if (theOntology == null) {
255       try {
256         FeatureMap fm = Factory.newFeatureMap();
257         fm.put("URL", ontoId);
258 
259         theOntology = (Ontology)Factory.createResource(
260             "com.ontotext.gate.ontology.DAMLKnowledgeBaseImpl",
261             fm
262           );
263       } catch (gate.creole.ResourceInstantiationException ex) {
264         throw new GateRuntimeException(
265             "Cannot load the ontology used in this OntoLex mapping!");
266       }
267     }//if
268 
269     return theOntology;
270   }
271 
272   private LexicalKnowledgeBase loadLexicon(Object lexId) {
273     LexicalKnowledgeBase theLexicon = null;
274 
275     List lrs = Gate.getCreoleRegister().getPublicLrInstances();
276     Iterator iter1 = lrs.iterator();
277     while (iter1.hasNext()) {
278       gate.LanguageResource lr = (LanguageResource) iter1.next();
279       if (! (lr instanceof LexicalKnowledgeBase))
280         continue;
281       LexicalKnowledgeBase currentLexicon = (LexicalKnowledgeBase) lr;
282       if (currentLexicon.getLexiconId().equals(lexId)) {
283         theLexicon = currentLexicon;
284         break;
285       }
286     }//while
287 
288     //the ontology is not loaded, we must do that
289     if (theLexicon == null) {
290       throw new GateRuntimeException(
291         "Please load the lexicon first before trying to use/define a mapping for it!");
292     }//if
293 
294     return theLexicon;
295   }
296 
297   protected JTree ontoEditor = new JTree();
298   protected OntoTreeModel ontoModel;
299   protected ChooseSynsetPanel synsetEditor;
300   protected OntoLexLR ontoLex;
301   protected Ontology theOntology;
302   protected GridLayout gridLayout1 = new GridLayout(2,1);
303   protected JSplitPane mainBox;
304   protected Box leftBox;
305   protected Box rightBox;
306   protected ChooseSynsetPanel chooseSynsetPanel;
307   protected JScrollPane synsetScroller;
308   protected LexKBSynset selectedSynset = null;
309   protected JButton addMappingButton;
310   protected JButton removeMappingButton;
311 
312   /**
313    */
314   protected class AddMappingAction extends AbstractAction{
315     AddMappingAction(){
316       super("AddMapping");
317       putValue(SHORT_DESCRIPTION, "Add a new mapping");
318     }
319     public void actionPerformed(java.awt.event.ActionEvent e){
320       if (selectedSynset == null) {
321         JOptionPane.showMessageDialog(
322         OntoLexEditorVR.this,
323         "Please choose a synset and a corresponding concept first");
324         return;
325       }
326       TreePath[] selectedPaths = ontoEditor.getSelectionPaths();
327       if (selectedPaths == null || selectedPaths.length == 0) {
328         JOptionPane.showMessageDialog(
329         OntoLexEditorVR.this,
330         "Please choose a synset and a corresponding concept first");
331         return;
332       }
333 
334       for (int i=0; i< selectedPaths.length; i++) {
335         ClassNode selectedNode = (ClassNode) selectedPaths[i].getLastPathComponent();
336         if (! (selectedNode.getSource() instanceof OClass))
337           continue;
338         ontoLex.add(((OClass)selectedNode.getSource()).getName(),
339                     selectedSynset.getId());
340       }//for loop
341       updateOntologySelection();
342 
343     }//actionPerformed
344   }
345 
346   /**
347    */
348   protected class RemoveMappingAction extends AbstractAction{
349     RemoveMappingAction(){
350       super("RemoveMapping");
351       putValue(SHORT_DESCRIPTION, "Remove the selected mapping");
352     }
353     public void actionPerformed(java.awt.event.ActionEvent e){
354       if (selectedSynset == null) {
355         Out.prln("Select a synset first");
356         return;
357       }
358       TreePath[] selectedPaths = ontoEditor.getSelectionPaths();
359       if (selectedPaths == null || selectedPaths.length == 0) {
360         Out.prln("Select an ontology concept first");
361         return;
362       }
363 
364       for (int i=0; i< selectedPaths.length; i++) {
365         ClassNode selectedNode = (ClassNode) selectedPaths[i].getLastPathComponent();
366         if (! (selectedNode.getSource() instanceof OClass))
367           continue;
368         ontoLex.remove(((OClass)selectedNode.getSource()).getName(),
369                        selectedSynset.getId());
370         ontoEditor.getSelectionModel().removeSelectionPath(selectedPaths[i]);
371       }//for loop
372 
373       updateOntologySelection();
374     }//actionPerformed
375   }
376 
377   protected class KnowledgeBaseTreeCellRenderer extends DefaultTreeCellRenderer {
378     public KnowledgeBaseTreeCellRenderer() {
379     }
380     public Component getTreeCellRendererComponent(JTree tree,
381                                               Object value,
382                                               boolean sel,
383                                               boolean expanded,
384                                               boolean leaf,
385                                               int row,
386                                               boolean hasFocus){
387       super.getTreeCellRendererComponent(tree, value, sel, expanded,
388                                          leaf, row, hasFocus);
389       if (! (value instanceof ClassNode))
390         return this;
391       ClassNode theNode = (ClassNode) value;
392       if(theNode.getSource() instanceof OClass) {
393         setIcon(MainFrame.getIcon("Class.gif"));
394       } else if(theNode.getSource() instanceof OInstance) {
395         setIcon(MainFrame.getIcon("Instance.gif"));
396       }
397       return this;
398     }
399   }
400 
401 
402 }