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.IStatusLineManager;
21  import org.eclipse.jface.viewers.ISelection;
22  import org.eclipse.jface.viewers.ISelectionChangedListener;
23  import org.eclipse.jface.viewers.ISelectionProvider;
24  import org.eclipse.jface.viewers.IStructuredSelection;
25  import org.eclipse.jface.viewers.SelectionChangedEvent;
26  import org.eclipse.jface.viewers.StructuredSelection;
27  import org.eclipse.jface.viewers.TreeViewer;
28  import org.eclipse.swt.SWT;
29  import org.eclipse.swt.widgets.Composite;
30  import org.eclipse.swt.widgets.Control;
31  import org.eclipse.ui.part.Page;
32  import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
33  import org.eclipse.ui.views.properties.IPropertySource;
34  import org.w3c.dom.Node;
35  
36  import sk.baka.ikslibs.interval.DOMIntervalSet;
37  import sk.baka.ikslibs.levelmapper.NodeListID;
38  import sk.uniba.euromath.document.IGeneralListener;
39  import sk.uniba.euromath.document.XMLAccess;
40  import sk.uniba.euromath.editor.EditorSite;
41  import sk.uniba.euromath.editor.selections.DOMSelectionChangedEvent;
42  import sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener;
43  import sk.uniba.euromath.editor.selections.IDOMSelectionProvider;
44  import sk.uniba.euromath.plugin.views.outline.actions.XMLOutlineActionContributor;
45  import sk.uniba.euromath.plugin.views.outline.items.OutlineItem;
46  
47  // FIXME Studva root is after open document selected, shit event from tree
48  // widget
49  
50  public class XMLOutlinePage extends Page implements IContentOutlinePage,
51          IDOMSelectionChangedListener, ISelectionChangedListener, IAdaptable,
52          IDOMSelectionProvider {
53      /***
54       * Jface tree viewer to display xml document in DOM tree style.
55       */
56      private TreeViewer viewer;
57  
58      private XMLAccessContentProvider contentProvider;
59  
60      /***
61       * Label provider for outline items.
62       */
63      private OutlineItemsLabelProvider labelProvider;
64  
65      private Set<ISelectionChangedListener> selectionListeners = new HashSet<ISelectionChangedListener>();
66  
67      private Set<IDOMSelectionChangedListener> domSelectionListeners = new HashSet<IDOMSelectionChangedListener>();
68  
69      private XMLAccess xmlAccess = null;
70  
71      private final EditorSite editorSite;
72  
73      private final IGeneralListener xmlAccessChangeHandler;
74  
75      private StatusLineUpdateManager statusLineManager;
76  
77      private boolean showingTransformed;
78  
79      /***
80       * Outline action contributor.
81       */
82      protected XMLOutlineActionContributor actionContributor;
83  
84      public XMLOutlinePage(EditorSite site) {
85          super();
86          this.editorSite = site;
87          this.xmlAccessChangeHandler = new IGeneralListener() {
88              public void documentWasTransformed(XMLAccess xmlAccess) {
89                  handleDocumentTransformation(xmlAccess);
90              }
91          };
92          setXmlAccess(site.getXMLAccess());
93          getXMLAccess().getListeners().addGeneralListener(
94                  getXmlAccessChangeHandler());
95          setShowingTransformed(false);
96      }
97  
98      @Override
99      public void createControl(Composite parent) {
100         setViewer(createTreeViewer(parent));
101         setActionContributor(new XMLOutlineActionContributor(getSite()
102                 .getWorkbenchWindow().getActivePage().getActivePart(), this));
103         prepareStatusLineManager(getSite().getActionBars()
104                 .getStatusLineManager());
105         refreshViewerData(getRoot());
106         getViewer().addSelectionChangedListener(this);
107         // regiter as selection change listener to EditorSite
108         getEditorSite().addSelectionChangedListener(
109                 (IDOMSelectionChangedListener) this);
110         selectionChanged(new DOMSelectionChangedEvent(getEditorSite(),
111                 getEditorSite().getDOMSelection()));
112     }
113 
114     /***
115      * Returns a XML node which will be the root of the outline tree.
116      */
117     protected Node getRoot() {
118         Node result = null;
119         if (this.xmlAccess != null) {
120             if (isShowingTransformed()) {
121                 getLabelProvider().setWithInvertedImages(false);
122                 // TODO studva transformed doc
123                 result = getXMLAccess().getDocument().getDocumentElement();
124             } else {
125                 getLabelProvider().setWithInvertedImages(true);
126                 result = this.xmlAccess.getDocument().getDocumentElement();
127             }
128         }
129         return result;
130     }
131 
132     protected void prepareStatusLineManager(IStatusLineManager manager) {
133         setStatusLineManager(new StatusLineUpdateManager(manager,
134                 getXMLAccess()));
135         this.statusLineManager.setImageRegistry(getLabelProvider()
136                 .getImageRegistry());
137         this.statusLineManager.connect(this);
138     }
139 
140     protected TreeViewer createTreeViewer(Composite parent) {
141         TreeViewer result = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
142                 | SWT.V_SCROLL);
143         setContentProvider(new XMLAccessContentProvider());
144         result.setContentProvider(getContentProvider());
145         setLabelProvider(new OutlineItemsLabelProvider(getEditorSite()));
146         result.setLabelProvider(getLabelProvider());
147         return result;
148     }
149 
150     /*
151      * (non-Javadoc)
152      * 
153      * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
154      */
155     public Object getAdapter(Class adapter) {
156         if (adapter == IPropertySource.class) {
157             if (getViewer().getSelection() != null) {
158                 if (getViewer().getSelection() instanceof IStructuredSelection) {
159                     IStructuredSelection sSel = (IStructuredSelection) getViewer()
160                             .getSelection();
161                     if (!sSel.isEmpty() && (sSel.size() == 1)) {
162                         Object e0 = sSel.getFirstElement();
163                         if (e0 instanceof IPropertySource) {
164                             return e0;
165                         } else if (e0 instanceof OutlineItem) {
166                             return ((OutlineItem) e0).getPropertySource();
167                         }
168                     }
169                 }
170             }
171             return null;
172         }
173 
174         if (adapter.equals(IDOMSelectionProvider.class)) {
175             return this;
176         }
177 
178         if (adapter.equals(IDOMSelectionProvider.class)) {
179             return this;
180         }
181 
182         if (adapter.equals(XMLAccess.class)) {
183             return getXMLAccess();
184         }
185 
186         return null;
187     }
188 
189     /*
190      * (non-Javadoc)
191      * 
192      * @see org.eclipse.ui.part.IPage#getControl()
193      */
194     @Override
195     public Control getControl() {
196         return getViewer().getControl();
197     }
198 
199     public void handleDocumentTransformation(XMLAccess newData) {
200         setXmlAccess(newData);
201         // store current expansion:
202         Object[] expanded = getViewer().getExpandedElements();
203         // store selection
204         IStructuredSelection oldSelection = (IStructuredSelection) getViewer()
205                 .getSelection();
206         // refresh data
207         refreshViewerData(getRoot());
208         // expand
209         List<OutlineItem> newItems = new ArrayList<OutlineItem>();
210         for (int i = 0; i < expanded.length; i++) {
211             newItems.add(getContentProvider().getItem(
212                     ((OutlineItem) expanded[i]).getModel()));
213         }
214         getViewer().setExpandedElements(newItems.toArray());
215         // select
216         List selItems = oldSelection.toList();
217         newItems = new ArrayList<OutlineItem>();
218         for (int i = 0; i < selItems.size(); i++) {
219             newItems.add(getContentProvider().getItem(
220                     ((OutlineItem) selItems.get(i)).getModel()));
221         }
222         StructuredSelection viewerSel = new StructuredSelection(newItems);
223         getViewer().setSelection(viewerSel);
224         // scroll
225         if (!viewerSel.isEmpty()) {
226             getViewer().reveal(viewerSel.getFirstElement());
227         }
228     }
229 
230     public void refreshViewerData(Node topNode) {
231         getViewer().setInput(topNode);
232         getViewer().refresh(true);
233     }
234 
235     public void refresh() {
236         handleDocumentTransformation(getXMLAccess());
237     }
238 
239     /*
240      * (non-Javadoc)
241      * 
242      * @see org.eclipse.ui.part.IPage#setFocus()
243      */
244     @Override
245     public void setFocus() {
246         getViewer().getControl().setFocus();
247     }
248 
249     /***
250      * @return Selection in that is stored, what is selected in whole document
251      */
252     public DOMIntervalSet getDOMSelection() {
253         return getEditorSite().getDOMSelection();
254     }
255 
256     /***
257      * 
258      */
259     public void addSelectionChangedListener(
260             IDOMSelectionChangedListener listener) {
261         this.domSelectionListeners.add(listener);
262     }
263 
264     /***
265      * 
266      */
267     public void removeSelectionChangedListener(
268             ISelectionChangedListener listener) {
269         this.domSelectionListeners.remove(listener);
270     }
271 
272     /***
273      * Routs information about this new IXMLSelection to SelectionListeners and
274      * to TreeViewer
275      * 
276      * @param selection
277      *            IXMLSelection to set
278      */
279     public void setSelection(DOMIntervalSet selection) {
280         fireSelectionChangeEvent(selection);
281     }
282 
283     /***
284      * This should be called from TreeViewer or from EditorSite Selection in the
285      * Event can be IStructureSelection or IXMLSelection depending on even
286      * source.
287      * 
288      * @param event
289      *            Event that contains Selection
290      */
291     public void selectionChanged(DOMSelectionChangedEvent event) {
292 
293         if (event.getSource() == getViewer()) {
294             // TODO :GUI
295             // synchronize this IStructureSelection with curent IXMLSelection
296             // fireSelectionChangeEvent with this updated IXMLSelection to
297             // selectionListeners
298         } else {
299             // make new IStructureSelection from IXMLSelection and set it to the
300             // TreeViewer
301             IStructuredSelection sSel = convertIXMLSelectionToIStructureSelection(event
302                     .getDOMSelection());
303             getViewer().setSelection(sSel);
304             if (!sSel.isEmpty()) {
305                 getViewer().reveal(sSel.getFirstElement());
306             }
307             // fireSelectionChangeEvent with IXMLSelection to selectionListeners
308             fireSelectionChangeEvent(event.getDOMSelection());
309         }
310 
311         // IMPLEMENT: single normalized status bar text for selections from
312         // different
313         // sources (outline, editor). At this point, status bar text is shown,
314         // only if
315         // outline is the active part.
316         this.statusLineManager.show(getDOMSelection());
317     }
318 
319     /***
320      * XMLOutlinePage starts selection listening. It adds itself to
321      * XMLOutlinePage's listeners listeners. And add itself to TreeViewer's
322      * selectionListeners It is a "two way listening" Call in pair with
323      * stopSelectionListening().
324      */
325     private void startSelectionListening() {
326         for (ISelectionChangedListener listener : this.selectionListeners)
327             if (listener instanceof ISelectionProvider)
328                 ((ISelectionProvider) listener)
329                         .removeSelectionChangedListener(this);
330         for (IDOMSelectionChangedListener listener : this.domSelectionListeners)
331             if (listener instanceof IDOMSelectionProvider)
332                 ((IDOMSelectionProvider) listener)
333                         .removeSelectionChangedListener(this);
334         getViewer().addSelectionChangedListener(this);
335     }
336 
337     /***
338      * XMLOutlinePage does not realy stops selection listening because
339      * setSelection and selectionChange are public methods, but it removes
340      * itself from XMLOutlinePage's listeners listeners. And removes itself from
341      * TreeViewer's selectionListeners This prevents from loops.
342      */
343     private void stopSelectionListening() {
344         for (ISelectionChangedListener listener : this.selectionListeners)
345             if (listener instanceof ISelectionProvider)
346                 ((ISelectionProvider) listener)
347                         .removeSelectionChangedListener(this);
348         for (IDOMSelectionChangedListener listener : this.domSelectionListeners)
349             if (listener instanceof IDOMSelectionProvider)
350                 ((IDOMSelectionProvider) listener)
351                         .removeSelectionChangedListener(this);
352 
353         getViewer().removeSelectionChangedListener(this);
354     }
355 
356     /***
357      * @param xmlSelection
358      *            IXMLSelection to be routed to selectionListeners
359      */
360     protected void fireSelectionChangeEvent(DOMIntervalSet xmlSelection) {
361         if (this.domSelectionListeners.isEmpty())
362             return;
363         stopSelectionListening();
364 
365         DOMSelectionChangedEvent event = new DOMSelectionChangedEvent(this,
366                 xmlSelection);
367         for (IDOMSelectionChangedListener listener : this.domSelectionListeners) {
368             listener.selectionChanged(event);
369         }
370 
371         startSelectionListening();
372     }
373 
374     /***
375      * Makes IDs from IStructureSelection and IDs from IXMLSelection. Then the
376      * are 3 cases
377      * <ul>
378      * <li> id from IStructureSelection is in IDs from IXMLSelection - no
379      * change, so do nothing</li>
380      * <li> id from IStructureSelection is NOT in IDs from IXMLSelection - new
381      * Node was selected in Outline, so add to IXMLSelection whole DOMInterval
382      * of this Node</li>
383      * <li> id from IXMLSelection is NOT in IDs from IStructureSelection - Node
384      * was deselected, so remove DOMInterval of this NOde </li>
385      * </ul>
386      * 
387      * @param sSel
388      *            IStructureSelection from TreeViewer
389      * @param xmlSelection
390      *            curent IXMLSelection, that will be updated
391      * 
392      * @return
393      */
394     protected DOMIntervalSet synchronizeViewerSelection(
395             IStructuredSelection sSel, DOMIntervalSet xmlSelection) {
396         // TODO : GUI - implement
397         return null;
398     }
399 
400     protected IStructuredSelection convertIXMLSelectionToIStructureSelection(
401             DOMIntervalSet xmlSelection) {
402         List<OutlineItem> n = new ArrayList<OutlineItem>();
403 
404         Set<String> ids = xmlSelection.getContentIds(getXMLAccess().getIdManager());
405         for (String id : ids) {
406             NodeListID nlID = this.xmlAccess.getIdManager().getNodeNull(id);
407             if (nlID != null) {
408                 for (int j = 0; j < nlID.getLength(); j++) {
409                     OutlineItem p = this.contentProvider.getItem(nlID.item(j));
410                     if (p != null) {
411                         n.add(p);
412                     }
413                 }
414             }
415         }
416 
417         return new StructuredSelection(n);
418     }
419 
420     public void setShowTransformed(boolean showTrn) {
421         if (showTrn != this.showingTransformed) {
422             this.showingTransformed = showTrn;
423             refreshViewerData(getRoot());
424         }
425     }
426 
427     /***
428      * @return Returns the viewer.
429      */
430     public TreeViewer getViewer() {
431         return this.viewer;
432     }
433 
434     /***
435      * @param viewer
436      *            The viewer to set.
437      */
438     public void setViewer(TreeViewer viewer) {
439         this.viewer = viewer;
440     }
441 
442     /***
443      * @return Returns the actionContributor.
444      */
445     public XMLOutlineActionContributor getActionContributor() {
446         return this.actionContributor;
447     }
448 
449     /***
450      * @param actionContributor
451      *            The actionContributor to set.
452      */
453     public void setActionContributor(
454             XMLOutlineActionContributor actionContributor) {
455         this.actionContributor = actionContributor;
456     }
457 
458     /***
459      * @return Returns the contentProvider.
460      */
461     public XMLAccessContentProvider getContentProvider() {
462         return this.contentProvider;
463     }
464 
465     /***
466      * @param contentProvider
467      *            The contentProvider to set.
468      */
469     public void setContentProvider(XMLAccessContentProvider contentProvider) {
470         this.contentProvider = contentProvider;
471     }
472 
473     /***
474      * @return Returns the xmlAccess.
475      */
476     public XMLAccess getXMLAccess() {
477         return this.xmlAccess;
478     }
479 
480     /***
481      * @param xmlAccess
482      *            The xmlAccess to set.
483      */
484     private void setXmlAccess(XMLAccess xmlAccess) {
485         this.xmlAccess = xmlAccess;
486     }
487 
488     /***
489      * @return Returns the editorSite.
490      */
491     private EditorSite getEditorSite() {
492         return this.editorSite;
493     }
494 
495     /***
496      * @return Returns the labelProvider.
497      */
498     protected OutlineItemsLabelProvider getLabelProvider() {
499         return this.labelProvider;
500     }
501 
502     /***
503      * @param labelProvider
504      *            The labelProvider to set.
505      */
506     protected void setLabelProvider(OutlineItemsLabelProvider labelProvider) {
507         this.labelProvider = labelProvider;
508     }
509 
510     /***
511      * @return Returns the showingTransformed.
512      */
513     protected boolean isShowingTransformed() {
514         return this.showingTransformed;
515     }
516 
517     /***
518      * @param showingTransformed
519      *            The showingTransformed to set.
520      */
521     protected void setShowingTransformed(boolean showingTransformed) {
522         this.showingTransformed = showingTransformed;
523     }
524 
525     /***
526      * @return Returns the xmlAccessChangeHandler.
527      */
528     protected IGeneralListener getXmlAccessChangeHandler() {
529         return this.xmlAccessChangeHandler;
530     }
531 
532     /***
533      * @param statusLineManager
534      *            The statusLineManager to set.
535      */
536     protected void setStatusLineManager(
537             StatusLineUpdateManager statusLineManager) {
538         this.statusLineManager = statusLineManager;
539     }
540 
541     public void addSelectionChangedListener(ISelectionChangedListener listener) {
542         // TODO Auto-generated method stub
543         
544     }
545 
546     public ISelection getSelection() {
547         // TODO Auto-generated method stub
548         return null;
549     }
550 
551     public void setSelection(ISelection selection) {
552         // TODO Auto-generated method stub
553         
554     }
555 
556     public void selectionChanged(SelectionChangedEvent event) {
557         // TODO Auto-generated method stub
558         
559     }
560 
561     public void removeSelectionChangedListener(IDOMSelectionChangedListener listener) {
562         // TODO Auto-generated method stub
563         
564     }
565 
566 
567 }