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.views.navigator;
26  
27  import java.util.*;
28  
29  import org.eclipse.jface.action.*;
30  import org.eclipse.jface.dialogs.MessageDialog;
31  import org.eclipse.jface.viewers.*;
32  import org.eclipse.swt.SWT;
33  import org.eclipse.swt.dnd.*;
34  import org.eclipse.swt.events.*;
35  import org.eclipse.swt.widgets.Composite;
36  import org.eclipse.swt.widgets.Menu;
37  import org.eclipse.ui.*;
38  import org.eclipse.ui.part.IPage;
39  import org.eclipse.ui.part.ViewPart;
40  import org.eclipse.ui.views.properties.*;
41  import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
42  import org.omwg.ontology.Ontology;
43  import org.wsmo.common.Entity;
44  import org.wsmostudio.ui.GUIHelper;
45  import org.wsmostudio.ui.Utils;
46  import org.wsmostudio.ui.WsmoUIPlugin;
47  import org.wsmostudio.ui.dnd.Clipboard;
48  import org.wsmostudio.ui.dnd.WSMOTransfer;
49  import org.wsmostudio.ui.editors.extension.ExtensionManager;
50  import org.wsmostudio.ui.editors.model.ObservableModel;
51  import org.wsmostudio.ui.views.navigator.actions.*;
52  import org.wsmostudio.ui.views.properties.WSMOPropertiesSource;
53  
54  /***
55   * A primary viewer component (<i>WSMO Navigator</i>) of the WSMO Studio. 
56   * It outlines the content of the opened WSMO-API objects in the workbench
57   * in a tree-styled view. It is a part of the WSMO perspective.
58   * From this viewer, different more specialized editors can be opened for
59   * the content of the visualized object. 
60   *
61   * @author not attributable
62   * @version $Revision: 1389 $ $Date: 2007-12-04 17:25:33 +0200 $
63   */
64  
65  public class WSMONavigator extends ViewPart 
66  implements ISelectionProvider, Observer {
67  
68      protected TreeViewer treeViewer;
69      private WSMONavigatorUpdater uiUpdater;
70      private Set<ISelectionChangedListener> selListeners;
71      
72      private WSMOPropertiesSource propsSrc;
73      private ContentExtensionManager extensionManager;
74      private ActionRegistry actionRegistry;
75  
76  
77      public WSMONavigator() {
78          super();
79          uiUpdater = new WSMONavigatorUpdater(this);
80          uiUpdater.registerInOpenedEditors();
81          PlatformUI.getWorkbench()
82              .getActiveWorkbenchWindow()
83                  .getPartService()
84                      .addPartListener(uiUpdater);
85          actionRegistry = new ActionRegistry(this);
86      }
87      
88      public void createPartControl(Composite parent) {
89          treeViewer = new TreeViewer(parent);
90          extensionManager = new ContentExtensionManager();
91          treeViewer.setContentProvider(new NavigatorContentProvider(extensionManager));
92          treeViewer.setLabelProvider(new NavigatorLabelProvider(extensionManager));
93  
94          setWsmoInput(findActiveInput());
95          treeViewer.getTree().addMouseListener(new MouseAdapter() {
96              public void mouseDoubleClick(MouseEvent e) {
97                  processDoubleClick(e);
98              }
99          });
100         createContextMenu();
101         selListeners = new HashSet<ISelectionChangedListener>();
102         getViewSite().setSelectionProvider(this);
103 
104         
105         treeViewer.addSelectionChangedListener(
106                 new ISelectionChangedListener() {
107                     public void selectionChanged(SelectionChangedEvent event) {
108                         propsViewRefresh();
109                     }
110                 });
111         treeViewer.getTree().addKeyListener(new KeyAdapter() {
112             public void keyReleased(KeyEvent e) {
113                 if (e.keyCode == SWT.F5) {
114                     treeViewer.refresh();
115                 }
116             }
117         });
118         initDNDSource();
119         initDNDTarget();
120         
121         new ToolTipProvider(treeViewer.getTree());
122     }
123     
124     private void initDNDSource() {
125 
126         DragSource source = new DragSource(treeViewer.getTree(), DND.DROP_LINK); 
127         Transfer[] types = new Transfer[] {WSMOTransfer.getInstance()}; 
128         source.setTransfer(types); 
129            
130         source.addDragListener(new DragSourceListener() { 
131             public void dragStart(DragSourceEvent event) { 
132                 IStructuredSelection sel = (IStructuredSelection)treeViewer.getSelection();
133                 if (sel == null 
134                         || sel.isEmpty()) {
135                     event.doit = false;
136                 }
137                 List<Entity> selection = new LinkedList<Entity>();
138                 for(Iterator<?> it = sel.iterator(); it.hasNext();) {
139                     Object selObj = it.next();
140                     if (selObj instanceof Entity) {
141                         selection.add((Entity)selObj);
142                     }
143                 }
144                 Clipboard.getInstance().setContent(selection);
145             } 
146             public void dragSetData(DragSourceEvent event) { 
147               if (WSMOTransfer.getInstance().isSupportedType(event.dataType)) { 
148                    event.data = Clipboard.getInstance().getContent(); 
149               } 
150             } 
151             public void dragFinished(DragSourceEvent event) { 
152                 Clipboard.getInstance().clear();
153             }
154          }); 
155         
156     }
157     
158     private void initDNDTarget() {
159         
160         DropTarget target = new DropTarget(this.treeViewer.getTree(), 
161                 DND.DROP_LINK | DND.DROP_DEFAULT | DND.DROP_COPY); 
162           
163         final FileTransfer fileTransfer = FileTransfer.getInstance();
164         final WSMOTransfer wsmoTransfer = WSMOTransfer.getInstance(); 
165         target.setTransfer(new Transfer[] {fileTransfer, wsmoTransfer}); 
166         target.addDropListener(new NavigatorDNDTargetAdapter(this, fileTransfer, wsmoTransfer));
167     }
168     
169     public static void propsViewRefresh() {
170 
171         IWorkbenchPage activePage = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
172         if (activePage == null) {
173             return;
174         }
175         IViewReference[] references = activePage.getViewReferences();
176         for (IViewReference viewRef : references) {
177             if (viewRef.getId().equals("org.eclipse.ui.views.PropertySheet")) {
178                 IViewPart part = viewRef.getView(true);
179                 if (part == null) {
180                     return;
181                 }
182                 
183                 IPage currentPropsPage = ((PropertySheet)part).getCurrentPage();
184                 if (currentPropsPage == null) {
185                 	return;
186                 }
187                 if (currentPropsPage instanceof PropertySheetPage) {
188                 	((PropertySheetPage)currentPropsPage).refresh();
189                 }
190                 else if (currentPropsPage instanceof TabbedPropertySheetPage) {
191                 	((TabbedPropertySheetPage)currentPropsPage).refresh();
192                 }
193                 break;
194             }
195         }
196     }
197     
198     public void notifyActiveFiltersChange() {
199         extensionManager.updateFilters();
200         treeViewer.refresh(true);
201     }
202 
203     void setWsmoInput(IEditorInput newInput) {
204         IEditorInput oldInput = (IEditorInput)treeViewer.getInput();
205         if (oldInput == null) {
206             if (newInput == null) {
207                 return; // no change needed
208             }
209         }
210         else if (false == oldInput.equals(newInput)) {
211             if (oldInput.getAdapter(Observable.class) != null) {
212                 ((Observable)oldInput.getAdapter(Observable.class)).deleteObserver(this);
213                 uiUpdater.saveExpansionInfo(oldInput);
214             }
215         }
216         else {
217             return; // no need to update
218         }
219 
220         treeViewer.setInput(newInput);
221         if (newInput != null 
222                 && newInput.getAdapter(Observable.class) != null) {
223             ((Observable)newInput.getAdapter(Observable.class)).deleteObserver(this);
224             uiUpdater.applyExpansionInfo(newInput);
225         }
226     }
227     
228     public IEditorInput getWsmoInput() {
229         if (this.treeViewer == null) {
230             return null;
231         }
232         return (IEditorInput)this.treeViewer.getInput();
233     }
234     
235     public void update(Observable o, Object target) {
236         if (false == o.equals(getWsmoInput().getAdapter(Observable.class))) {
237             return; // not a relevant notification
238         }
239         treeViewer.refresh(true);
240     }
241 
242     public void setFocus() {
243         treeViewer.getControl().setFocus();
244     }
245 
246     public void processDoubleClick(MouseEvent e) {
247         ISelection selection = treeViewer.getSelection();
248         if (false == selection instanceof IStructuredSelection) {
249             return; 
250         }
251         Object target = ((IStructuredSelection)selection).getFirstElement();
252         if (hasRegisteredEditor(target)) {
253             new EditAction(this).run();
254         }
255         IAction editAction = actionRegistry.getCustomEditAction(target);
256         if(editAction != null) {
257             editAction.run();
258         }
259     }
260     
261     private void createContextMenu() {
262         MenuManager menuMgr = new MenuManager();
263         menuMgr.setRemoveAllWhenShown(true);
264         menuMgr.addMenuListener(new IMenuListener() {
265                 public void menuAboutToShow(IMenuManager mgr) {
266                     fillContextMenu(mgr);
267                 }
268         });
269         
270         // Create menu.
271         Menu contextMenu = menuMgr.createContextMenu(treeViewer.getControl());
272         treeViewer.getControl().setMenu(contextMenu);
273     }
274 
275     private void fillContextMenu(IMenuManager mgr) {
276 
277     	if (false == GUIHelper.containsCursor(treeViewer.getTree())) {
278     		return;
279     	}
280         IStructuredSelection sSel = (IStructuredSelection)treeViewer.getSelection();
281         final Object target = sSel.getFirstElement();
282         if (target == null) {
283             return; // no seleciton
284         }
285         
286         actionRegistry.initAddActions(mgr, target);
287         if (mgr.getItems().length > 0) {
288             mgr.add(new Separator());
289         }
290         addEditMenu(mgr, target);
291         initEditWithMenu(mgr, target);
292         if (mgr.getItems().length > 0) {
293             mgr.add(new Separator());
294         }
295         if (target instanceof Ontology) {
296             OpenTypeAction openTypeAction = new OpenTypeAction("Find Entity ...",
297                                        this.getTree(),
298                                        (Ontology)target);
299             openTypeAction.setUIModel(
300                     (ObservableModel)getWsmoInput().getAdapter(ObservableModel.class));
301             mgr.add(openTypeAction);
302             mgr.add(new Separator());
303         }
304         actionRegistry.initRemoveActions(mgr, target);
305         if (mgr.getItems().length > 0) {
306             mgr.add(new Separator());
307         }
308         if (((ITreeContentProvider)treeViewer.getContentProvider()).hasChildren(target)) {
309             mgr.add(new Action("Expand Subtree") {
310                 public void run() {
311                     treeViewer.expandToLevel(target, TreeViewer.ALL_LEVELS);
312                     treeViewer.getTree().showSelection();
313                 }
314             });
315             mgr.add(new Separator());
316         }
317         actionRegistry.initMiscActions(mgr, target);
318     }
319     
320     private void addEditMenu(IMenuManager mManager, final Object object) {
321         if (hasRegisteredEditor(object)) {
322             EditAction action = new EditAction(this);
323             action.setText("Edit");
324             mManager.add(action);
325         }
326     }
327     
328     private boolean hasRegisteredEditor(Object target) {
329         final ExtensionManager manager = WsmoUIPlugin.getDefault().getExtensionManager();
330         LinkedList<String> allEditors = manager.findEditorsForObject(target);
331         return allEditors != null 
332                 && allEditors.size() > 0;
333     }
334     
335     private void initEditWithMenu(IMenuManager mManager, final Object object) {
336         final ExtensionManager manager = WsmoUIPlugin.getDefault().getExtensionManager();
337         LinkedList<String> allEditors = manager.findEditorsForObject(object);
338         if (allEditors == null 
339                 || allEditors.size() < 2) {
340             return; // no need this menu
341         }
342         mManager.add(new Separator());
343         MenuManager subMenu = new MenuManager("Edit With ...");
344         mManager.add(subMenu);
345         String preferredEditor = manager.findPreferredEditor(object);
346         
347         for (Iterator<String> it = allEditors.iterator(); it.hasNext();) {
348             final String edID = it.next();
349             final String editorDescr = manager.getEditorDescription(edID);
350             Action action = new Action((editorDescr != null) ? editorDescr : edID) {
351                 public void run() {
352                     manager.setPreferredEditor(object, edID);
353                     new EditAction(WSMONavigator.this).run();
354                 }
355             };
356             action.setChecked(edID.equals(preferredEditor));
357             subMenu.add(action);
358         }
359     }
360     
361     public void dispose() {
362         uiUpdater.unregisterFromOpenedEditors();
363         PlatformUI.getWorkbench()
364             .getActiveWorkbenchWindow()
365                 .getPartService()
366                     .removePartListener(uiUpdater);
367         treeViewer = null;
368     }
369 
370     @SuppressWarnings("unchecked")
371     public Object getAdapter(Class adapter) {
372         if (adapter == IPropertySource.class) {
373             if (treeViewer.getTree().getSelectionCount() == 0) {
374                 return null;
375             }
376             Object selection = ((IStructuredSelection)treeViewer.getSelection()).getFirstElement();
377             if (false == selection instanceof Entity) {
378                 return null;
379             }
380             if (propsSrc == null) {
381                 propsSrc =  new WSMOPropertiesSource((Entity)selection);
382             }
383             else {
384                 propsSrc.setData((Entity)selection);
385             }
386             return propsSrc;
387 		}
388         return null;
389      }
390     
391     public boolean ensureEditorForEntityIsClosed(Entity entity) {
392         return ensureEditorForEntityIsClosed(entity, true);
393     }
394     public boolean ensureEditorForEntityIsClosed(Entity entity, boolean showConfirm) {
395 
396         IWorkbenchPage page = PlatformUI.getWorkbench()
397                                   .getActiveWorkbenchWindow()
398                                       .getActivePage();
399         if (page == null) {
400             return true;
401         }
402         Set<IEditorInput> inputs = Utils.findInputsForEntity(entity);
403         
404         if (inputs == null 
405                 || inputs.size() == 0) {
406             return true;
407         }
408         if (showConfirm 
409                 && false == MessageDialog.openConfirm(getSite().getShell(), 
410                               "Editor Closing", 
411                               "The selected entity is currently opened in an editor."
412                               +"\nDo you want to proceed with closing the editor?")) {
413             return false;
414         }
415         for(IEditorInput input : inputs) {
416             IEditorPart editor = page.findEditor(input); 
417             page.closeEditor(editor, false);
418         }
419         return true;
420     }
421     
422     public void fireEntityChanged(Entity entity) {
423         Set<ObservableModel> models = Utils.findModelsForEntity(entity);
424         for(ObservableModel model : models) {
425             model.notifyObservers(entity);
426         }
427     }
428 
429     
430     public void addSelectionChangedListener(ISelectionChangedListener listener) {
431         selListeners.add(listener);
432     }
433     
434     public ISelection getSelection() {
435         return new StructuredSelection(this);
436     }
437     
438     public void removeSelectionChangedListener(ISelectionChangedListener listener) {
439         selListeners.remove(listener);
440     }
441     
442     public void setSelection(ISelection selection) {
443     }
444     
445     private IEditorInput findActiveInput() {
446         IWorkbenchPage page = PlatformUI.getWorkbench()
447                                   .getActiveWorkbenchWindow()
448                                       .getActivePage();
449         if (page == null) {
450             return null; // not initialized yet - no active input
451         }
452         
453         IEditorPart editor = page.getActiveEditor();
454         if (editor != null) {
455             IEditorInput input = editor.getEditorInput();
456             if (input.getAdapter(Entity.class) != null) { // only if adaptable to wsmo
457                 return input;
458             }
459         }
460         return null;
461     }
462 
463     public TreeViewer getTree() {
464         return treeViewer;
465     }
466     
467     public void selectionChanged(SelectionChangedEvent event) {
468     }
469 }
470 
471 /*
472  * $Log$
473  * Revision 1.41  2007/07/25 12:59:29  alex_simov
474  * rfe [1748272]: Multi-line text editor supplied for opening long string values.
475  * Tooltip with dc:description NFP value added to WSMO Navigator as well
476  *
477  * Revision 1.40  2007/07/23 13:56:16  alex_simov
478  * no message
479  *
480  * Revision 1.39  2007/07/19 13:08:31  alex_simov
481  * - rfe [1751326] Navigation through the editor tab
482  * - concepts/attributes which are from a different namespace are prefixed
483  *
484  * Revision 1.38  2007/04/20 14:54:15  alex_simov
485  * Find entity enriched with RegExpr
486  *
487  * Revision 1.37  2007/03/15 15:10:54  alex_simov
488  * RFE [1654102] : Renaming functionality added in WSMO Navigator
489  *
490  * Revision 1.36  2007/02/22 12:44:57  alex_simov
491  * Feature request [1654099]: Drag & Drop in the hierarchy of WSMO Navigator
492  *
493  * Revision 1.35  2007/02/15 17:35:48  alex_simov
494  * no message
495  *
496  * Revision 1.34  2007/02/14 11:31:22  alex_simov
497  * Feature request [1654112]: WSMO Navigator preserves its tree expansion
498  * state when the user switches between editors
499  *
500  * Revision 1.33  2007/02/13 15:53:16  alex_simov
501  * bugfix[1312971]: The WSMO Text editor synchronizes the wsmo object
502  * model automatically with the other editors (if possible) or issues a warning
503  * message otherwise.
504  *
505  * Revision 1.32  2006/12/19 12:34:55  alex_simov
506  * rfe[1618723]: Expand Subtree action added to the WSMO Navigator
507  *
508  * Revision 1.31  2006/08/02 12:30:57  alex_simov
509  * disallow context menu when the mouse pointer is outside the view
510  *
511  * Revision 1.30  2006/07/11 16:14:52  alex_simov
512  * keybindings removed - now defined as global actions for the workbench
513  *
514  * Revision 1.29  2006/06/05 15:59:10  alex_simov
515  * the view is now capable drop target for wsml files
516  *
517  * Revision 1.28  2006/02/20 14:58:30  alex_simov
518  * issue[1428325]: Objects without dedicated editors but having custom
519  * edit actions not opened on mouse double-click in the WSMO Navigator
520  *
521  * Revision 1.27  2006/01/10 13:41:26  alex_simov
522  * bugfix: navigator's restored content allowed invalid input data
523  *
524  * Revision 1.26  2006/01/09 12:51:14  alex_simov
525  * Copyright message in header updated
526  *
527  * Revision 1.25  2006/01/06 14:40:43  alex_simov
528  * method modifier signature changed (propsViewRefresh())
529  *
530  * Revision 1.24  2005/11/18 12:51:18  alex_simov
531  * keyboard shortcuts enabled
532  *
533  * Revision 1.23  2005/11/17 16:08:26  alex_simov
534  * fix
535  *
536  * Revision 1.22  2005/11/15 15:56:05  alex_simov
537  * Drag-and-drop support added from WSMO Navigator to related (ontology) editors
538  *
539  * Revision 1.21  2005/11/10 13:42:44  alex_simov
540  * update
541  *
542  * Revision 1.20  2005/11/09 16:14:34  alex_simov
543  * UIModels notification improved
544  *
545  * Revision 1.19  2005/11/02 14:50:57  alex_simov
546  * moving to MVC architecture cont'd
547  *
548  * Revision 1.18  2005/11/02 08:48:16  alex_simov
549  * org.wsmostudio.ui.navigator_content ext-point enriched with actions for objects
550  *
551  * Revision 1.17  2005/10/14 13:25:18  alex_simov
552  * WSMO Navigator's extension point creation
553  *
554  * Revision 1.16  2005/09/21 15:09:11  alex_simov
555  * minor fixes
556  *
557  * Revision 1.15  2005/09/12 09:27:55  alex_simov
558  * selection actions now update Properties view
559  *
560  * Revision 1.14  2005/09/08 16:46:25  alex_simov
561  * Migrating to Java 1.5
562  *
563  * Revision 1.13  2005/09/02 11:54:10  alex_simov
564  * bugfix: [1280465] ClassCastException
565  *
566  * Revision 1.12  2005/08/05 15:32:29  alex_simov
567  * editors input change notification mechanism added
568  *
569  * Revision 1.11  2005/08/04 15:00:55  alex_simov
570  * editor <-> subeditor dependency links established
571  *
572  * Revision 1.10  2005/08/02 10:33:21  alex_simov
573  * minor code and/or javadoc fixes
574  *
575  * Revision 1.9  2005/07/29 15:08:03  alex_simov
576  * added javadoc: class description, footer
577  *
578  *
579  */