1
2
3
4
5
6
7
8
9
10
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
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
122 this.viewer = createTreeViewer(parent);
123 setContentProvider(new XMLAccessContentProvider());
124 setLabelProvider(new OutlineItemsLabelProvider(getEditorSite()));
125
126 this.actionContributor = new XMLOutlineActionContributor(this);
127
128
129 this.statusLineManager = new StatusLineUpdateManager(getSite()
130 .getActionBars().getStatusLineManager(),
131 getXMLAccess(), this);
132
133 getViewer().addSelectionChangedListener(this);
134 refreshViewerData(getRoot());
135
136
137 getEditorSite().addSelectionChangedListener(
138 (IDOMSelectionChangedListener) this);
139
140
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
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
192
193
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
226
227
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
244 Object[] expanded = getViewer().getExpandedElements();
245
246 IStructuredSelection oldSelection = (IStructuredSelection) getViewer()
247 .getSelection();
248
249 refreshViewerData(getRoot());
250
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
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
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
284
285
286
287 @Override
288 public void setFocus() {
289 getViewer().getControl().setFocus();
290 }
291
292
293
294
295
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
310
311
312
313 public void addSelectionChangedListener(
314 ISelectionChangedListener listener) {
315 this.selectionListeners.add(listener);
316 }
317
318
319
320
321
322
323 public void addSelectionChangedListener(
324 IDOMSelectionChangedListener listener) {
325 this.domSelectionListeners.add(listener);
326 }
327
328
329
330
331
332
333 public void removeSelectionChangedListener(
334 IDOMSelectionChangedListener listener) {
335 this.domSelectionListeners.remove(listener);
336 }
337
338
339
340
341
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
371 }
372
373 /***
374 * EditorSite's selection change event handling.
375 */
376 public void selectionChanged(DOMSelectionChangedEvent event) {
377
378 if (this.canSelectionChangeListen != 0)
379 return;
380
381
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
449 if (this.canSelectionChangeListen != 0)
450 return;
451
452
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
462 this.domSelection = new DOMIntervalSet(result);
463
464
465
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 }