View Javadoc
1   /* 
2    WSMO Studio - a Semantic Web Service Editor
3    Copyright (c) 2004-2006, OntoText Lab. / SIRMA Group
4    
5    This library is free software; you can redistribute it and/or modify it under
6    the terms of the GNU Lesser General Public License as published by the Free
7    Software Foundation; either version 2.1 of the License, or (at your option)
8    any later version.
9    This library is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   details.
13   You should have received a copy of the GNU Lesser General Public License along
14   with this library; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16   */
17  
18  /***
19   * <p>Title: WSMO Studio</p>
20   * <p>Description: Semantic Web Service Editor</p>
21   * <p>Copyright:  Copyright (c) 2004-2006</p>
22   * <p>Company: OntoText Lab. / SIRMA </p>
23   */
24  
25  package org.wsmostudio.ui.editors;
26  
27  import java.util.*;
28  import java.util.List;
29  
30  import org.eclipse.jface.dialogs.*;
31  import org.eclipse.jface.viewers.*;
32  import org.eclipse.jface.window.Window;
33  import org.eclipse.swt.SWT;
34  import org.eclipse.swt.custom.SashForm;
35  import org.eclipse.swt.dnd.*;
36  import org.eclipse.swt.events.*;
37  import org.eclipse.swt.layout.*;
38  import org.eclipse.swt.widgets.*;
39  import org.eclipse.ui.*;
40  import org.omwg.ontology.*;
41  import org.wsmo.common.*;
42  import org.wsmo.common.exception.InvalidModelException;
43  import org.wsmostudio.runtime.*;
44  import org.wsmostudio.ui.*;
45  import org.wsmostudio.ui.dnd.*;
46  import org.wsmostudio.ui.dnd.Clipboard;
47  import org.wsmostudio.ui.editors.common.*;
48  import org.wsmostudio.ui.editors.model.*;
49  import org.wsmostudio.ui.views.navigator.WSMOLabelProvider;
50  
51  /***
52   * An editor component, subclass of WSMOEditor, capable to handle with WSMO-API 
53   * Concept objects.
54   * This editor appears as a part of the WSMO Studio workbench. It is the default
55   * editor implementation for this kind of objects and it can be replaced by 
56   * extending extension points <code>org.wsmostudio.ui.editors</code> and 
57   * <code>org.eclipse.ui.editors</code>.
58   *
59   * @author not attributable
60   * @version $Revision: 1.22 $ $Date: 2006/02/20 12:45:29 $
61   */
62  
63  public class ConceptEditor extends WSMOEditor 
64          implements SelectionListener {
65  
66      private NFPPanel nfpPanel;
67      private InstancesContainerPanel instancesPanel;
68      private ConceptModel model;
69      private Table supTable;
70      
71      private TreeViewer attributesTree;
72      
73      public void createPartControl(Composite parent) {
74          parent.setLayout(new GridLayout(1, false));
75          
76          nfpPanel = new NFPPanel(parent,model);
77          
78          SashForm mainEditor = new SashForm(parent, SWT.VERTICAL );
79          mainEditor.setLayoutData(new GridData(GridData.FILL_BOTH));
80  
81          TabFolder attrTabs = new TabFolder(mainEditor, SWT.NONE);
82          TabItem attrsView = new TabItem(attrTabs, SWT.NONE);
83          
84          attrsView.setText("Attributes");
85          createAttributesView(attrTabs);
86          attrsView.setControl(attributesTree.getTree());
87          initDNDTargetAttrTypes();
88  
89          TabFolder supersTabs = new TabFolder(mainEditor, SWT.NONE);
90          TabItem superConceptsView = new TabItem(supersTabs, SWT.NONE);
91          
92          superConceptsView.setText("Super Concepts");
93          createSuperConceptsView(supersTabs);
94          superConceptsView.setControl(supTable);
95  
96          TabFolder instsTabs = new TabFolder(mainEditor, SWT.NONE);
97          instancesPanel = new InstancesContainerPanel(instsTabs, model);
98          
99          initDNDTargetSuperConcepts();
100     }
101     
102     public void init(IEditorSite site, IEditorInput input) throws PartInitException {
103         super.init(site, input);
104         model = (ConceptModel)input.getAdapter(ConceptModel.class);
105     }
106 
107     public void dispose() {
108         nfpPanel.dispose();
109         model = null;
110         super.dispose();
111     }
112 
113     public void setFocus() {
114         super.setFocus();
115         attributesTree.getTree().setFocus();
116     }
117     
118     protected void updateFromModel() {
119         doUpdateAttributeTree();
120         instancesPanel.update();
121         updateSuperConceptsTable();
122     }
123     
124     @SuppressWarnings("unchecked")
125     private Table createSuperConceptsView(Composite parent) {
126         supTable = new Table(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
127         supTable.setLinesVisible(false);
128         Set<Concept> superConcepts = model.getConcept().listSuperConcepts();
129         for(Concept concept : superConcepts) {
130             Utils.createTableItem(supTable, 
131                                   concept, 
132                                   WsmoImageRegistry.CONCEPT_ICON);
133         }
134         supTable.addMouseListener(new MouseAdapter() {
135             public void mouseUp(MouseEvent e) {
136                 if (e.button != 3) {
137                     return;
138                 }
139                 showContextMenu(supTable, e);
140             }
141             
142         });
143         return supTable;
144     }
145     
146     @SuppressWarnings("unchecked")
147     private void updateSuperConceptsTable() {
148         Set<Concept> superConcepts = new HashSet<Concept>(
149                 model.getConcept().listSuperConcepts());
150         TableItem[] items = supTable.getItems();
151         for(int i = 0; i < items.length; i++) {
152             if (false == superConcepts.contains(items[i].getData())) {
153                 items[i].dispose();
154             }
155             else {
156                 superConcepts.remove(items[i].getData());
157             }
158         }
159         for(Concept concept : superConcepts) {
160             Utils.createTableItem(supTable, 
161                     concept, 
162                     WsmoImageRegistry.CONCEPT_ICON);
163         }
164     }
165 
166     private TreeViewer createAttributesView(Composite parent) {
167         attributesTree = new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
168 
169         attributesTree.setContentProvider(
170                 new AttributeContentProvider(model.getConcept()));
171         attributesTree.setLabelProvider(new WSMOLabelProvider() {
172             public String getText(Object element) {
173                 String strLabel = super.getText(element);
174                 if (element instanceof Attribute) {
175                     StringBuffer sbLabel = new StringBuffer();
176                     Attribute attr = (Attribute)element;
177                     sbLabel.append(strLabel).append(" [");
178                     sbLabel.append(attr.getMinCardinality());
179                     sbLabel.append("..");
180                     if (attr.getMaxCardinality() == Integer.MAX_VALUE) {
181                         sbLabel.append('*');
182                     }
183                     else {
184                         sbLabel.append(attr.getMaxCardinality());
185                     }
186                     sbLabel.append(']');
187                     strLabel = sbLabel.toString();
188                 }
189                 return strLabel;
190             }
191         });
192         attributesTree.setInput(model.getConcept());
193         attributesTree.getTree().addMouseListener(new MouseAdapter() {
194             public void mouseDoubleClick(MouseEvent e) {
195                 TreeItem[] sel = attributesTree.getTree().getSelection();
196                 Object selected = sel[0].getData();
197                 if ((selected instanceof Attribute)
198                         && (sel[0].getBounds().contains(e.x, e.y))) {
199                     doEditAttribute((Attribute)selected);
200                     doUpdateAttributeTree();
201                 }
202             }
203             public void mouseUp(MouseEvent e) {
204                 if (e.button != 3) {
205                     return;
206                 }
207                 showContextMenu(attributesTree.getTree(), e);
208             }
209 
210         });
211         return attributesTree;
212     }
213     
214     private void doEditAttribute(Attribute target)
215     {
216         AttributeModel attrModel = (AttributeModel)Utils.createEditorModel(target, model, "");
217         new AttributeEditor(getSite().getShell(), this, attrModel).open();
218     }
219     
220     public void widgetSelected(SelectionEvent e) {
221         String action = ((MenuItem)e.widget).getText();
222         if (action.equals("Add Super Concept")) {
223             WSMOChooser chooser = WSMOChooser.createConceptChooser(
224                                                            getSite().getShell(), 
225                                                            WSMORuntime.getRuntime());
226             Concept newSuperConcept = (Concept)chooser.open();
227             if (!isValidSuperConcept(model.getConcept(), newSuperConcept)) {
228                 return; // take no action - its already there ...
229             }
230             if (newSuperConcept != null) {
231                 try {
232                     model.addSuperConcept(newSuperConcept);
233                 }
234                 catch(InvalidModelException ime) {
235                     LogManager.logError(ime);
236                 }
237             }
238             return;
239         }
240         if (action.equals("Remove Super Concept")) {
241             TableItem[] sel = supTable.getSelection();
242             if (sel == null || sel.length != 1) {
243                 return;
244             }
245             try {
246                 model.removeSuperConcept((Concept)sel[0].getData());
247             }
248             catch(InvalidModelException ime) {
249                 LogManager.logError(ime);
250             }
251             return;
252         }
253         
254         if (action.equals("Remove Range")) {
255             TreeItem[] sel = attributesTree.getTree().getSelection();
256             TreeItem parentSel = sel[0].getParentItem();
257             Attribute attr = (Attribute)parentSel.getData();
258             Type rangeConcept = (Type)sel[0].getData();
259 
260             try {
261                 attr.removeType(rangeConcept);
262                 model.setChanged();
263             }
264             catch(InvalidModelException ime) {
265                 LogManager.logError(ime);
266             }
267             doUpdateAttributeTree();
268             return;
269         }
270         
271         if (action.equals("Edit Attribute")) {
272             Attribute attr = (Attribute)((IStructuredSelection)attributesTree
273                                                                .getSelection())
274                                                                .getFirstElement();
275             doEditAttribute(attr);
276             doUpdateAttributeTree();
277             return;
278         }
279 
280         if (action.equals("Remove Attribute")) {
281             TreeItem[] sel = attributesTree.getTree().getSelection();
282             try {
283                 model.removeAttribute((Attribute)sel[0].getData());
284                 model.setChanged();
285             }
286             catch(InvalidModelException ime) {
287                 LogManager.logError(ime);
288             }
289             doUpdateAttributeTree();
290             return;
291         }
292 
293         if (action.equals("Add Attribute")) {
294             
295             IdentifierInputDialog iDialog = new IdentifierInputDialog(
296                     getSite().getShell(), 
297                     "New Attribute", 
298                     "Please supply a valid attribute name",
299                     "",
300                     model.getConcept().getOntology(), // the NS container
301                     WSMORuntime.getRuntime().getWsmoFactory(), 
302                     false, // no anonymous allowed
303                     new IInputValidator() {
304                         public String isValid(String newText) {
305                             Set attrs = model.getConcept().listAttributes();
306                             for (Iterator iter = attrs.iterator(); iter.hasNext();) {
307                                 Attribute attr = (Attribute) iter.next();
308                                 if (attr.getIdentifier().toString().endsWith("#"+newText.trim())) {
309                                     return "Attribute name already in use!";
310                                 }
311                             }
312                             return null;
313                         }});
314 
315             
316             if (iDialog.open() != Window.OK) {
317                 return;
318             }
319             IRI attrID = (IRI)iDialog.getIdentifier();
320 
321             try {
322                 Attribute newAttr = model.createAttribute(attrID);
323                 doUpdateAttributeTree();
324                 attributesTree.setSelection(new StructuredSelection(newAttr));
325             }
326             catch(InvalidModelException ime) {
327                 MessageDialog.openError(getSite().getShell(),
328                         "Error Creating Attribute",
329                         ime.getMessage());
330                 LogManager.logError(ime);
331             }
332             return;
333         }
334 
335     }
336 
337     public void widgetDefaultSelected(SelectionEvent e) {
338     }
339 
340     private void showContextMenu(Control parentControl, MouseEvent e) {
341         Menu contextMenu = new Menu(parentControl.getShell(), SWT.POP_UP);
342         fillContextMenuContent(parentControl, contextMenu, e);
343         
344         contextMenu.setLocation(parentControl.toDisplay(e.x, e.y));
345         contextMenu.setVisible(true);
346     }
347     
348     private void fillContextMenuContent(Control parent,
349                                         Menu menu,
350                                         MouseEvent e) {
351         if (parent == supTable) {
352             MenuItem item = new MenuItem(menu, SWT.PUSH);
353             item.setText("Add Super Concept");
354             item.addSelectionListener(this);
355         
356             TableItem[] sel = supTable.getSelection();
357             if (sel != null 
358                     && sel.length > 0 
359                     && sel[0].getBounds(0).contains(e.x, e.y)) {
360                 item = new MenuItem(menu, SWT.PUSH);
361                 item.setText("Remove Super Concept");
362                 item.addSelectionListener(this);
363             }
364             return;
365         }
366         if (parent == attributesTree.getTree()) {
367             TreeItem[] sel = attributesTree.getTree().getSelection();
368             boolean isOnSelection = (sel != null 
369                     && sel.length > 0 
370                     && sel[0].getBounds().contains(e.x, e.y));
371             
372             if (isOnSelection 
373                     && ((IStructuredSelection)attributesTree.getSelection())
374                         .getFirstElement() instanceof Type) {
375                 MenuItem item = new MenuItem(menu, SWT.PUSH);
376                 item.setText("Remove Range");
377                 item.addSelectionListener(this);
378             }
379             else {
380                 MenuItem item = new MenuItem(menu, SWT.PUSH);
381                 item.setText("Add Attribute");
382                 item.addSelectionListener(this);
383         
384                 if (isOnSelection) {
385                     item = new MenuItem(menu, SWT.SEPARATOR);
386                     
387                     item = new MenuItem(menu, SWT.PUSH);
388                     item.setText("Edit Attribute");
389                     item.addSelectionListener(this);
390                     
391                     item = new MenuItem(menu, SWT.SEPARATOR);
392 
393                     item = new MenuItem(menu, SWT.PUSH);
394                     item.setText("Remove Attribute");
395                     item.addSelectionListener(this);
396                 }
397             }
398         }
399     }
400     
401     private boolean isValidSuperConcept(Concept concept, Concept superConcept) {
402         if (concept == superConcept 
403                 || concept.listSuperConcepts().contains(superConcept)) {
404             return false;
405         }
406         // TODO: Mode checks here ....!
407         return true;
408     }
409     
410     protected void doTryToSave() throws Exception {
411         WSMORuntime.getRuntime().doUpdateEntity(model.getConcept().getOntology());
412     }
413     
414     private void doUpdateAttributeTree() {
415         ((AttributeContentProvider)attributesTree.getContentProvider()).prepareToRefresh();
416         attributesTree.refresh(true);
417     }
418     
419     private void initDNDTargetSuperConcepts() {
420         DropTarget target = new DropTarget(supTable, 
421                 DND.DROP_LINK | DND.DROP_DEFAULT); 
422           
423         final WSMOTransfer wsmoTransfer = WSMOTransfer.getInstance(); 
424         target.setTransfer(new Transfer[] {wsmoTransfer}); 
425           
426         target.addDropListener(new DropTargetAdapter() { 
427             public void dragEnter(DropTargetEvent event) { 
428                 if (true == Clipboard.getInstance().ensureContentType(Concept.class)) {
429                     event.detail = DND.DROP_LINK;
430                 }
431                 else {
432                     event.detail = DND.DROP_NONE;
433                 }
434             } 
435             public void dragOver(DropTargetEvent event) { 
436                 event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL; 
437             } 
438             public void drop(DropTargetEvent event) { 
439                 if (wsmoTransfer.isSupportedType(event.currentDataType)) { 
440                     List<Entity> concepts = Clipboard.getInstance().getContent();
441                     for(Entity entity : concepts) {
442                         if (entity instanceof Concept) {
443                             try {
444                                 if (false == model.getConcept().listSuperConcepts().contains(entity)) {
445                                     model.addSuperConcept((Concept)entity);
446                                 }
447                             }
448                             catch(InvalidModelException ime) {
449                                 MessageDialog.openError(getSite().getShell(), 
450                                         "Error", 
451                                         ime.getMessage());
452                                 LogManager.logError(ime);
453                             }
454                         }
455                     }
456                 } 
457             } 
458         }); 
459     }
460     
461     private void initDNDTargetAttrTypes() {
462         DropTarget target = new DropTarget(attributesTree.getTree(), 
463                 DND.DROP_LINK | DND.DROP_DEFAULT); 
464           
465         final WSMOTransfer wsmoTransfer = WSMOTransfer.getInstance(); 
466         target.setTransfer(new Transfer[] {wsmoTransfer}); 
467           
468         target.addDropListener(new DropTargetAdapter() { 
469             public void dragEnter(DropTargetEvent event) { 
470                 event.detail = DND.DROP_NONE;
471             } 
472             public void dragOver(DropTargetEvent event) { 
473                 event.feedback = DND.FEEDBACK_SELECT | DND.FEEDBACK_SCROLL | DND.FEEDBACK_EXPAND; 
474                 if (event.item != null) {
475                     Object selected = event.item.getData();
476                     if (selected instanceof Attribute
477                             && Clipboard.getInstance().ensureContentType(Type.class)) {
478                         event.detail = DND.DROP_LINK;
479                     }
480                     else {
481                         event.detail = DND.DROP_NONE;
482                     }
483                 }
484             } 
485             public void drop(DropTargetEvent event) { 
486                 if (wsmoTransfer.isSupportedType(event.currentDataType)) { 
487                     if (event.item == null) {
488                         return;
489                     }
490                     Object selected = event.item.getData();
491                     if (false == selected instanceof Attribute) {
492                         return;
493                     }
494                     
495                     List<Entity> newTypes = Clipboard.getInstance().getContent();
496                     Set types = ((Attribute)selected).listTypes();
497                     boolean changed = false;
498                     for(Entity entity : newTypes) {
499                         if (entity instanceof Type) {
500                             try {
501                                 if (false == types.contains(entity)) {
502                                     ((Attribute)selected).addType((Type)entity);
503                                     changed = true;
504                                 }
505                             }
506                             catch(InvalidModelException ime) {
507                                 MessageDialog.openError(getSite().getShell(), 
508                                         "Error", 
509                                         ime.getMessage());
510                                 LogManager.logError(ime);
511                             }
512                         }
513                     }
514                     if (changed) {
515                         model.setChanged();
516                     }
517                 } 
518             } 
519         }); 
520     }
521 
522     class AttributeContentProvider implements ITreeContentProvider {
523         
524         private Concept root;
525         private boolean rootIsShown = false;
526         
527         public AttributeContentProvider(Concept owner) {
528             root = owner;
529         }
530         
531         /*
532          * this method is invoked just before the viewer is updated
533          */
534         public void prepareToRefresh() {
535             rootIsShown = false;
536         }
537         
538         public Object[] getChildren(Object parentElement) {
539             if (parentElement instanceof Attribute) {
540                 return ((Attribute)parentElement).listTypes().toArray();
541             }
542             return null;
543         }
544 
545         public Object getParent(Object element) {
546             return null;
547         }
548 
549         public boolean hasChildren(Object element) {
550             if (element == root) {
551                 if (rootIsShown) {
552                     return false; // cut recursion
553                 }
554                 return root.listAttributes().size() > 0;
555             }
556             if (element instanceof Attribute) {
557                 return ((Attribute)element).listTypes().size() > 0;
558             }
559             return false;
560         }
561 
562         public Object[] getElements(Object inputElement) {
563 
564             if (inputElement == root) {
565                 rootIsShown = true;
566                 return root.listAttributes().toArray();
567             }
568             return null;
569         }
570 
571         public void dispose() {
572         }
573 
574         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
575         }
576     }
577 }
578 
579 /*
580  * $Log: ConceptEditor.java,v $
581  * Revision 1.22  2006/02/20 12:45:29  alex_simov
582  * wsmo4j api change: more methods throw InvalidModelExceptions
583  *
584  * Revision 1.21  2006/01/20 16:41:38  alex_simov
585  * IRI creation wrapped in try-catch to produce adequate UI error message
586  *
587  * Revision 1.20  2006/01/09 12:51:13  alex_simov
588  * Copyright message in header updated
589  *
590  * Revision 1.19  2005/11/15 15:54:17  alex_simov
591  * Drag-and-drop support added from WSMO Navigator to related (ontology) editors
592  *
593  * Revision 1.18  2005/11/10 13:46:32  alex_simov
594  * update
595  *
596  * Revision 1.17  2005/11/09 16:17:39  alex_simov
597  * UIModels notification improved
598  *
599  * Revision 1.16  2005/11/02 08:57:02  alex_simov
600  * moving to a better Model-View-Contoller architecture
601  *
602  * Revision 1.15  2005/09/14 14:45:16  alex_simov
603  * fix
604  *
605  * Revision 1.14  2005/09/13 10:00:50  alex_simov
606  * imports customization
607  *
608  * Revision 1.13  2005/09/08 16:46:25  alex_simov
609  * Migrating to Java 1.5
610  *
611  * Revision 1.12  2005/09/02 11:58:41  alex_simov
612  * bugfix: [1280458] WSMO Navigator changes notification improved
613  *
614  * Revision 1.11  2005/08/08 12:19:48  alex_simov
615  * Utils.createTableItem() used where appropriate
616  *
617  * Revision 1.10  2005/08/05 15:32:28  alex_simov
618  * editors input change notification mechanism added
619  *
620  * Revision 1.9  2005/08/02 10:33:20  alex_simov
621  * minor code and/or javadoc fixes
622  *
623  * Revision 1.8  2005/07/29 15:08:02  alex_simov
624  * added javadoc: class description, footer
625  *
626  *
627  */