View Javadoc

1   /*
2    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius
3    * University, Bratislava. This file is protected by the Mozilla Public License
4    * version 1.1 (the License); you may not use this file except in compliance
5    * with the License. You may obtain a copy of the License at
6    * http://euromath2.sourceforge.net/license.html Unless required by applicable
7    * law or agreed to in writing, software distributed under the License is
8    * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
9    * KIND, either express or implied. See the License for the specific language
10   * governing permissions and limitations under the License.
11   */
12  package sk.uniba.euromath.plugin.views.outline;
13  
14  import java.util.ArrayList;
15  import java.util.HashSet;
16  import java.util.List;
17  import java.util.Set;
18  
19  import org.eclipse.core.runtime.IAdaptable;
20  import org.eclipse.jface.action.IMenuManager;
21  import org.eclipse.jface.action.IStatusLineManager;
22  import org.eclipse.jface.action.IToolBarManager;
23  import org.eclipse.jface.viewers.ISelection;
24  import org.eclipse.jface.viewers.ISelectionChangedListener;
25  import org.eclipse.jface.viewers.IStructuredSelection;
26  import org.eclipse.jface.viewers.ITreeSelection;
27  import org.eclipse.jface.viewers.SelectionChangedEvent;
28  import org.eclipse.jface.viewers.StructuredSelection;
29  import org.eclipse.jface.viewers.TreePath;
30  import org.eclipse.jface.viewers.TreeViewer;
31  import org.eclipse.swt.SWT;
32  import org.eclipse.swt.widgets.Composite;
33  import org.eclipse.swt.widgets.Control;
34  import org.eclipse.ui.part.Page;
35  import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
36  import org.eclipse.ui.views.properties.IPropertySource;
37  import org.w3c.dom.Node;
38  
39  import sk.baka.ikslibs.interval.DOMInterval;
40  import sk.baka.ikslibs.interval.DOMIntervalSet;
41  import sk.baka.ikslibs.levelmapper.NodeListID;
42  import sk.uniba.euromath.document.IGeneralListener;
43  import sk.uniba.euromath.document.XMLAccess;
44  import sk.uniba.euromath.editor.EditorSite;
45  import sk.uniba.euromath.editor.selections.DOMSelectionChangedEvent;
46  import sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener;
47  import sk.uniba.euromath.editor.selections.IDOMSelectionProvider;
48  import sk.uniba.euromath.plugin.views.outline.actions.XMLOutlineActionContributor;
49  import sk.uniba.euromath.plugin.views.outline.items.OutlineItem;
50  
51  public class XMLOutlinePage extends Page implements IContentOutlinePage,
52                  IDOMSelectionChangedListener, ISelectionChangedListener,
53                  IAdaptable, IDOMSelectionProvider {
54          /***
55           * Jface tree viewer to display xml document in DOM tree style.
56           */
57          private TreeViewer viewer;
58  
59          private XMLAccessContentProvider contentProvider;
60  
61          /***
62           * Label provider for outline items.
63           */
64          private OutlineItemsLabelProvider labelProvider;
65  
66          private Set<ISelectionChangedListener> selectionListeners = new HashSet<ISelectionChangedListener>();
67  
68          private Set<IDOMSelectionChangedListener> domSelectionListeners = new HashSet<IDOMSelectionChangedListener>();
69  
70          /***
71           * Guards selection listening (of any type). Prevents event-listen
72           * loops. Can listen only when equals zero.
73           */
74          private int canSelectionChangeListen = 0;
75  
76          /***
77           * Holds selection displayed by this outline;
78           */
79          private DOMIntervalSet domSelection = new DOMIntervalSet();
80  
81          private XMLAccess xmlAccess;
82  
83          private final EditorSite editorSite;
84  
85          private final IGeneralListener xmlAccessChangeHandler = new IGeneralListener() {
86                  public void documentWasTransformed(XMLAccess xmlAccess) {
87                          handleDocumentTransformation(xmlAccess);
88                  }
89          };;
90  
91          private StatusLineUpdateManager statusLineManager;
92  
93          private boolean showingTransformed;
94  
95          /***
96           * Outline action contributor.
97           */
98          protected XMLOutlineActionContributor actionContributor;
99  
100         /***
101          * Contructor.
102          * 
103          * @param editorSite
104          *                associated editor site
105          */
106         public XMLOutlinePage(EditorSite editorSite) {
107                 super();
108                 this.editorSite = editorSite;
109                 setXmlAccess(editorSite.getXMLAccess());
110                 // add document transformation notification handler
111                 getXMLAccess().getListeners().addGeneralListener(
112                                 this.xmlAccessChangeHandler);
113                 this.showingTransformed = false;
114         }
115 
116         /***
117          * Set ups outline view.
118          */
119         @Override
120         public void createControl(Composite parent) {
121                 // create and set up viewer
122                 this.viewer = createTreeViewer(parent);
123                 setContentProvider(new XMLAccessContentProvider());
124                 setLabelProvider(new OutlineItemsLabelProvider(getEditorSite()));
125 
126                 this.actionContributor = new XMLOutlineActionContributor(this);
127 
128                 // status line
129                 this.statusLineManager = new StatusLineUpdateManager(getSite()
130                                 .getActionBars().getStatusLineManager(),
131                                 getXMLAccess(), this);
132 
133                 getViewer().addSelectionChangedListener(this);
134                 refreshViewerData(getRoot());
135 
136                 // regiter as selection change listener to EditorSite
137                 getEditorSite().addSelectionChangedListener(
138                                 (IDOMSelectionChangedListener) this);
139 
140                 // TODO Studva remove or leave it
141                 selectionChanged(new DOMSelectionChangedEvent(getEditorSite(),
142                                 getEditorSite().getDOMSelection()));
143         }
144 
145         @Override
146         public void makeContributions(IMenuManager menuManager,
147                         IToolBarManager toolBarManager,
148                         IStatusLineManager statusLineManager) {
149                 super.makeContributions(menuManager, toolBarManager,
150                                 statusLineManager);
151         }
152 
153         @Override
154         public void dispose() {
155                 this.actionContributor.dispose();
156                 super.dispose();
157         }
158 
159         /***
160          * Returns XML node which will be the root of the outline tree.
161          */
162         protected Node getRoot() {
163                 Node result = null;
164                 if (this.xmlAccess != null) {
165                         if (this.showingTransformed) {
166                                 getLabelProvider().setWithInvertedImages(false);
167                                 // TODO studva transformed doc retreival
168                                 result = getXMLAccess().getDocument()
169                                                 .getDocumentElement();
170                         } else {
171                                 getLabelProvider().setWithInvertedImages(true);
172                                 result = getXMLAccess().getDocument()
173                                                 .getDocumentElement();
174                         }
175                 }
176                 return result;
177         }
178 
179         /***
180          * Creates and set ups reeViewer on composite.
181          * 
182          * @param parent
183          * @return
184          */
185         protected TreeViewer createTreeViewer(Composite parent) {
186                 return new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
187                                 | SWT.V_SCROLL);
188         }
189 
190         /*
191          * (non-Javadoc)
192          * 
193          * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
194          */
195         public Object getAdapter(Class adapter) {
196                 if (adapter == IPropertySource.class) {
197                         if (getViewer().getSelection() != null) {
198                                 IStructuredSelection sSel = (IStructuredSelection) getViewer()
199                                                 .getSelection();
200                                 if (!sSel.isEmpty() && (sSel.size() == 1)) {
201                                         Object e0 = sSel.getFirstElement();
202                                         if (e0 instanceof IPropertySource) {
203                                                 return e0;
204                                         } else if (e0 instanceof OutlineItem) {
205                                                 return ((OutlineItem) e0)
206                                                                 .getPropertySource();
207                                         }
208                                 }
209                         }
210                         return null;
211                 }
212 
213                 if (adapter.equals(IDOMSelectionProvider.class)) {
214                         return this;
215                 }
216 
217                 if (adapter.equals(XMLAccess.class)) {
218                         return getXMLAccess();
219                 }
220 
221                 return getEditorSite().getAdapter(adapter);
222         }
223 
224         /*
225          * (non-Javadoc)
226          * 
227          * @see org.eclipse.ui.part.IPage#getControl()
228          */
229         @Override
230         public Control getControl() {
231                 return getViewer().getControl();
232         }
233 
234         /***
235          * Handles when document has been transformed. Updates viewer to display
236          * data from document.
237          * 
238          * @param newData
239          *                new document access
240          */
241         public void handleDocumentTransformation(XMLAccess newData) {
242                 setXmlAccess(newData);
243                 // store current expansion:
244                 Object[] expanded = getViewer().getExpandedElements();
245                 // store selection
246                 IStructuredSelection oldSelection = (IStructuredSelection) getViewer()
247                                 .getSelection();
248                 // refresh data
249                 refreshViewerData(getRoot());
250                 // expand
251                 List<OutlineItem> newItems = new ArrayList<OutlineItem>();
252                 for (int i = 0; i < expanded.length; i++) {
253                         newItems
254                                         .add(getContentProvider()
255                                                         .getItem(
256                                                                         ((OutlineItem) expanded[i])
257                                                                                         .getModel()));
258                 }
259                 getViewer().setExpandedElements(newItems.toArray());
260                 // select
261                 List selItems = oldSelection.toList();
262                 newItems = new ArrayList<OutlineItem>();
263                 for (int i = 0; i < selItems.size(); i++) {
264                         newItems.add(getContentProvider().getItem(
265                                         ((OutlineItem) selItems.get(i))
266                                                         .getModel()));
267                 }
268                 StructuredSelection viewerSel = new StructuredSelection(
269                                 newItems);
270                 getViewer().setSelection(viewerSel);
271                 // scroll
272                 if (!viewerSel.isEmpty()) {
273                         getViewer().reveal(viewerSel.getFirstElement());
274                 }
275         }
276 
277         public void refreshViewerData(Node topNode) {
278                 getViewer().setInput(topNode);
279                 getViewer().refresh(true);
280         }
281 
282         /*
283          * (non-Javadoc)
284          * 
285          * @see org.eclipse.ui.part.IPage#setFocus()
286          */
287         @Override
288         public void setFocus() {
289                 getViewer().getControl().setFocus();
290         }
291 
292         /*
293          * (non-Javadoc)
294          * 
295          * @see sk.uniba.euromath.editor.selections.IDOMSelectionProvider#getDOMSelection()
296          */
297         public DOMIntervalSet getDOMSelection() {
298                 return this.domSelection;
299         }
300 
301         /***
302          * This method is only here because of contract - is realy not needed.
303          */
304         public ISelection getSelection() {
305                 return getViewer().getSelection();
306         }
307 
308         /*
309          * (non-Javadoc)
310          * 
311          * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
312          */
313         public void addSelectionChangedListener(
314                         ISelectionChangedListener listener) {
315                 this.selectionListeners.add(listener);
316         }
317 
318         /*
319          * (non-Javadoc)
320          * 
321          * @see sk.uniba.euromath.editor.selections.IDOMSelectionProvider#addSelectionChangedListener(sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener)
322          */
323         public void addSelectionChangedListener(
324                         IDOMSelectionChangedListener listener) {
325                 this.domSelectionListeners.add(listener);
326         }
327 
328         /*
329          * (non-Javadoc)
330          * 
331          * @see sk.uniba.euromath.editor.selections.IDOMSelectionProvider#removeSelectionChangedListener(sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener)
332          */
333         public void removeSelectionChangedListener(
334                         IDOMSelectionChangedListener listener) {
335                 this.domSelectionListeners.remove(listener);
336         }
337 
338         /*
339          * (non-Javadoc)
340          * 
341          * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener)
342          */
343         public void removeSelectionChangedListener(
344                         ISelectionChangedListener listener) {
345                 this.selectionListeners.remove(listener);
346         }
347 
348         /***
349          * Routs information about this new IXMLSelection to SelectionListeners
350          * and to TreeViewer
351          * 
352          * @param selection
353          *                IXMLSelection to set
354          */
355         public void setSelection(DOMIntervalSet domSelection) {
356                 IStructuredSelection selection = convertDOMSelectionToStructuredSelection(domSelection);
357                 getViewer().setSelection(selection);
358                 if (!selection.isEmpty()) {
359                         getViewer().reveal(selection.getFirstElement());
360                 }
361 
362                 fireSelectionChangeEvent(domSelection);
363         }
364 
365         /***
366          * This method is only here because of contract - is realy not needed.
367          */
368         public void setSelection(ISelection selection) {
369                 getViewer().setSelection(selection);
370                 // by listening to viewver selection changes everything goes ok
371         }
372 
373         /***
374          * EditorSite's selection change event handling.
375          */
376         public void selectionChanged(DOMSelectionChangedEvent event) {
377                 // guards listening
378                 if (this.canSelectionChangeListen != 0)
379                         return;
380 
381                 // to synchronize selection with editor site
382                 setSelection(event.getDOMSelection());
383         }
384 
385         protected IStructuredSelection convertDOMSelectionToStructuredSelection(
386                         DOMIntervalSet domSelection) {
387                 List<OutlineItem> items = new ArrayList<OutlineItem>();
388 
389                 Set<String> ids = domSelection.getContentIds(getXMLAccess()
390                                 .getIDManager());
391                 for (String id : ids) {
392                         NodeListID nlID = this.xmlAccess.getIDManager()
393                                         .getNodeNull(id);
394                         if (nlID != null) {
395                                 for (int j = 0; j < nlID.getLength(); j++) {
396                                         OutlineItem p = this.contentProvider
397                                                         .getItem(nlID.item(j));
398                                         if (p != null) {
399                                                 items.add(p);
400                                         }
401                                 }
402                         }
403                 }
404                 return new StructuredSelection(items);
405         }
406 
407         /***
408          * Stops listening to selection change events.
409          */
410         protected void stopSelectionListening() {
411                 this.canSelectionChangeListen++;
412         }
413 
414         /***
415          * Starts listening to selection change events.
416          */
417         protected void startSelectionListening() {
418                 if (this.canSelectionChangeListen == 0)
419                         throw new IllegalArgumentException();
420                 this.canSelectionChangeListen--;
421         }
422 
423         /***
424          * Fires event when selection in page changed.
425          * 
426          * @param xmlSelection
427          *                new selection to fire in event
428          */
429         protected void fireSelectionChangeEvent(DOMIntervalSet xmlSelection) {
430                 if (this.domSelectionListeners.isEmpty())
431                         return;
432                 stopSelectionListening();
433 
434                 DOMSelectionChangedEvent event = new DOMSelectionChangedEvent(
435                                 this, xmlSelection);
436                 for (IDOMSelectionChangedListener listener : this.domSelectionListeners) {
437                         listener.selectionChanged(event);
438                 }
439 
440                 startSelectionListening();
441         }
442 
443         /***
444          * Handles selection changes in viewer. Selection change in viewer is
445          * selection change in outline, so selection change event is fired.
446          */
447         public void selectionChanged(SelectionChangedEvent event) {
448                 // guards listening
449                 if (this.canSelectionChangeListen != 0)
450                         return;
451                 // transform structured selection of viewer to DOMIntervalSet
452                 // and fire selection change event
453                 DOMIntervalSet result = new DOMIntervalSet();
454                 TreePath[] selectionPaths = ((ITreeSelection) getViewer()
455                                 .getSelection()).getPaths();
456                 for (TreePath path : selectionPaths) {
457                         Node node = ((OutlineItem) path.getLastSegment())
458                                         .getModel();
459                         result.union(DOMInterval.create(node), null);
460                 }
461                 // update local dom selection
462                 this.domSelection = new DOMIntervalSet(result);
463 
464                 // fireSelectionChangeEvent with DOM selection to
465                 // selectionListeners
466                 fireSelectionChangeEvent(result);
467         }
468 
469         public void setShowTransformed(boolean showTrn) {
470                 if (showTrn != this.showingTransformed) {
471                         this.showingTransformed = showTrn;
472                         refreshViewerData(getRoot());
473                 }
474         }
475 
476         /***
477          * @return Returns the viewer.
478          */
479         public TreeViewer getViewer() {
480                 return this.viewer;
481         }
482 
483         /***
484          * @return Returns the contentProvider.
485          */
486         public XMLAccessContentProvider getContentProvider() {
487                 return this.contentProvider;
488         }
489 
490         /***
491          * Associates with Outline content provider.
492          * 
493          * @param contentProvider
494          *                The contentProvider to set.
495          */
496         public void setContentProvider(XMLAccessContentProvider contentProvider) {
497                 this.contentProvider = contentProvider;
498                 getViewer().setContentProvider(getContentProvider());
499         }
500 
501         /***
502          * @return Returns the xmlAccess.
503          */
504         public XMLAccess getXMLAccess() {
505                 return this.xmlAccess;
506         }
507 
508         /***
509          * @param xmlAccess
510          *                The xmlAccess to set.
511          */
512         private void setXmlAccess(XMLAccess xmlAccess) {
513                 this.xmlAccess = xmlAccess;
514         }
515 
516         /***
517          * @return Returns the editorSite.
518          */
519         private EditorSite getEditorSite() {
520                 return this.editorSite;
521         }
522 
523         /***
524          * @return Returns the labelProvider.
525          */
526         protected OutlineItemsLabelProvider getLabelProvider() {
527                 return this.labelProvider;
528         }
529 
530         /***
531          * Associates with Outline label provider.
532          * 
533          * @param labelProvider
534          *                The labelProvider to set.
535          */
536         protected void setLabelProvider(OutlineItemsLabelProvider labelProvider) {
537                 this.labelProvider = labelProvider;
538                 getViewer().setLabelProvider(getLabelProvider());
539         }
540 }