1
2
3
4
5
6
7
8
9
10
11
12 package sk.uniba.euromath.editor.xmlEditor;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.HashMap;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
22 import javax.xml.transform.Source;
23
24 import org.eclipse.draw2d.ColorConstants;
25 import org.eclipse.draw2d.geometry.Rectangle;
26 import org.eclipse.gef.EditDomain;
27 import org.eclipse.gef.EditPart;
28 import org.eclipse.gef.GraphicalViewer;
29 import org.eclipse.gef.KeyHandler;
30 import org.eclipse.gef.RootEditPart;
31 import org.eclipse.gef.commands.CommandStack;
32 import org.eclipse.gef.editparts.ScalableRootEditPart;
33 import org.eclipse.gef.ui.parts.GraphicalViewerKeyHandler;
34 import org.eclipse.swt.events.FocusEvent;
35 import org.eclipse.swt.events.FocusListener;
36 import org.eclipse.swt.widgets.Composite;
37 import org.eclipse.ui.IEditorSite;
38
39 import sk.baka.ikslibs.interval.DOMIntervalSet;
40 import sk.baka.ikslibs.modify.IChangeCollector;
41 import sk.uniba.euromath.document.XMLAccess;
42 import sk.uniba.euromath.editor.EditorException;
43 import sk.uniba.euromath.editor.EditorSite;
44 import sk.uniba.euromath.editor.IEditor;
45 import sk.uniba.euromath.editor.IFocusListener;
46 import sk.uniba.euromath.editor.IRenderer;
47 import sk.uniba.euromath.editor.actions.IActionContributor;
48 import sk.uniba.euromath.editor.figures.IEMFigure;
49 import sk.uniba.euromath.editor.selections.DOMSelectionChangedEvent;
50 import sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener;
51 import sk.uniba.euromath.editor.selections.IDOMSelectionProvider;
52 import sk.uniba.euromath.editor.xmlEditor.actions.XMLActionContributor;
53 import sk.uniba.euromath.editor.xmlEditor.tools.XMLStructureTool;
54 import sk.uniba.euromath.editor.xmlEditor.viewers.XMLGraphicalViewerImpl;
55 import sk.uniba.euromath.editor.xmlEditor.viewers.XMLScrollingGraphicalViewer;
56
57 /***
58 * Common IEditor for any namespaces and any renderer. Used by default, if no
59 * editor is registered for namespace. Is implemented using GEF, providing
60 * structure(of whole nodes) selections, context menu, editing capabilities.
61 * Uses only one type EditPart - XMLEditPart. EditDomain provides one tool -
62 * XMLStructureTool. GraphicalViewer is XMLScrollingGraphicalViewer if this is
63 * root editor in IEditor "hierarchy" otherwise XMLGraphicalViewerImpl. Uses
64 * XMLActionContributor to create context menu and to contribute to global bars
65 * and context menu.
66 *
67 *
68 * @author Tomáš Studva 31.7.2005 Martin Kollar
69 */
70
71 public class XMLEditor implements IEditor, IDOMSelectionProvider, FocusListener {
72
73 /***
74 * Action contributor makes almost all action related contribution to
75 * bars.
76 */
77 private IActionContributor actionContributor;
78
79 /***
80 * Factory for creating editparts. Special XMLEditPartFactory is used.
81 */
82 private XMLEditPartFactory editPartFactory;
83
84 /***
85 * Graphical viewer instance. One from default implementation of GEF is
86 * used.
87 */
88 private GraphicalViewer graphicalViewer;
89
90 /***
91 * Edit domain. Default implementation is used.
92 */
93 private EditDomain editDomain;
94
95 /***
96 * XMLAccess instance.
97 */
98 private XMLAccess xmlAccess;
99
100 /***
101 * Renderer associated/collaborating with this XMLEditor.
102 */
103 private IRenderer renderer;
104
105 /***
106 * Key handler //TODO GUI pouvazovat kedy ouzivat keyhandler a naco, je
107 * to v popise classy KeyHandler (samozrejme je to na nas)
108 */
109 private KeyHandler keyHandler;
110
111 /***
112 * EditorSite instance.
113 */
114 private EditorSite editorSite;
115
116 /***
117 * List of listeners listening to XMLEditor's selection events.
118 */
119 private final ArrayList<IDOMSelectionChangedListener> selectionListeners;
120
121 /***
122 * Guards selection listening. Prevents event-listen loops. Can listen
123 * only when equals zero.
124 */
125 private int canSelectionChangeListen = 0;
126
127 /***
128 * Composite from init, which host this editor.
129 */
130 private Composite composite;
131
132 /***
133 * List of listeners listening to XMLEditor's focus events.
134 */
135 private final List<IFocusListener> focusListeners;
136
137 /***
138 * Constructor.
139 */
140 public XMLEditor() {
141 this.selectionListeners = new ArrayList<IDOMSelectionChangedListener>();
142 this.focusListeners = new ArrayList<IFocusListener>();
143 setEditDomain(createEditDomain());
144 }
145
146 /***
147 * Getter.
148 *
149 * @return EditorSite instance
150 */
151 public EditorSite getEditorSite() {
152 return this.editorSite;
153 }
154
155 /***
156 * @return <code>true</code> if this is a rootEditor
157 */
158 public boolean isRootEditor() {
159 return getEditorSite().isRootEditor(this);
160 }
161
162 /***
163 * Configures viewer for work. After this configuration viewer is
164 * prepared to display contents.
165 *
166 * @param source
167 */
168 protected void configureGraphicalViewer() {
169 setEditPartFactory(createEditPartFactory());
170 GraphicalViewer viewer = getGraphicalViewer();
171 viewer.getControl()
172 .setBackground(ColorConstants.listBackground);
173 viewer.setEditDomain(getEditDomain());
174 viewer.setEditPartFactory(getEditPartFactory());
175 viewer.setRootEditPart(createRootEditPart());
176 }
177
178 /***
179 * Creates XMLEditPartFactory.
180 *
181 * @return created XMLEditPartFactory
182 */
183 protected XMLEditPartFactory createEditPartFactory() {
184 return new XMLEditPartFactory();
185 }
186
187 /***
188 * Creates and inits KeyHandler which handles key events, when no tool
189 * is active.
190 */
191 protected void createAndInitKeyHandler() {
192 setKeyHandler(new GraphicalViewerKeyHandler(
193 getGraphicalViewer()));
194
195
196
197 }
198
199 /***
200 * Hooks the GraphicalViewer to the rest of the EditorSite.
201 */
202 protected void hookGraphicalViewer() {
203
204
205
206
207 getSelectionListeners()
208 .add(
209 (IDOMSelectionChangedListener) getGraphicalViewer());
210 ((IDOMSelectionProvider) getGraphicalViewer())
211 .addSelectionChangedListener(this);
212 }
213
214 /***
215 * Returns graphical viewer hooked on this Editor's composite.
216 *
217 * @return graphical viewer.
218 */
219 protected GraphicalViewer getGraphicalViewer() {
220 return this.graphicalViewer;
221 }
222
223 /***
224 * Setter for GraphicalViewer.
225 *
226 * @param viewer
227 */
228 protected void setGraphicalViewer(GraphicalViewer viewer) {
229 getEditDomain().addViewer(viewer);
230 this.graphicalViewer = viewer;
231 }
232
233 /***
234 * Creates GraphicalViewer on parent Composite for transformed doc
235 * source.
236 *
237 * @param parent
238 * @param source
239 */
240 public void createGraphicalViewer(Composite parent) {
241 GraphicalViewer viewer;
242 if (isRootEditor()) {
243 viewer = new XMLScrollingGraphicalViewer(this);
244 } else {
245 viewer = new XMLGraphicalViewerImpl(this);
246 }
247
248 viewer.createControl(parent);
249 setGraphicalViewer(viewer);
250 configureGraphicalViewer();
251 hookGraphicalViewer();
252 }
253
254 /***
255 * Getter for key handler.
256 *
257 * @return KeyHandler
258 */
259 private KeyHandler getKeyHandler() {
260 return this.keyHandler;
261 }
262
263 /***
264 * Set the contents of the GraphicalViewer, when is ready.
265 *
266 * @param rootFigure
267 * root of tree of figures, to edit/display.
268 */
269 protected void initializeGraphicalViewer(IEMFigure rootFigure) {
270 getGraphicalViewer().setContents(createTopEditPart(rootFigure));
271
272 createAndInitKeyHandler();
273 if (getKeyHandler() != null) {
274 getGraphicalViewer().setKeyHandler(getKeyHandler());
275 }
276 }
277
278 /***
279 * Creates top most editpart which is editor dependend - manipulates
280 * with model, is used as editpart for editor dependent view - root
281 * figure.
282 *
283 * @param rootFigure
284 * root of figure tree to edit/display
285 * @return created top editpart
286 */
287 protected EditPart createTopEditPart(IEMFigure rootFigure) {
288 return getEditPartFactory().createEditPart(null, rootFigure);
289 }
290
291
292
293
294
295
296
297
298
299 public void init(Source transformedDoc, IRenderer renderer,
300 Composite parent, XMLAccess xmlAccess,
301 EditorSite editorSite) throws EditorException {
302 this.composite = parent;
303 this.xmlAccess = xmlAccess;
304 this.renderer = renderer;
305 this.editorSite = editorSite;
306
307 createGraphicalViewer(parent);
308 setActionContributor(createActionContributor());
309 initializeGraphicalViewer(renderer.getRootFigure());
310 performPaintUpdate();
311 }
312
313
314
315
316
317
318
319 public void reinit(Source transformedDoc, IChangeCollector changes) {
320
321 getVisualInfo().clear();
322 initializeGraphicalViewer(getRenderer().getRootFigure());
323 performPaintUpdate();
324 }
325
326 /***
327 * Returns IdVisualInfo object. Holds which ids have been visualized and
328 * by which XMLEditPart
329 *
330 * @return IdVisualInfo
331 */
332 public IdVisualInfo getVisualInfo() {
333 return (getEditPartFactory()).getVisualInfo();
334 }
335
336 /***
337 * Creates action contributor.
338 *
339 * @return created IActionContributor
340 */
341 protected IActionContributor createActionContributor() {
342 return new XMLActionContributor(getEditorSite(),
343 getGraphicalViewer());
344 }
345
346 /***
347 * Getter.
348 *
349 * @return XMLAccess
350 */
351 public XMLAccess getXMLAccess() {
352 return this.xmlAccess;
353 }
354
355 /***
356 * Returns EditorSite's PartSite.
357 *
358 * @return IEditorSite of EditoSite.
359 */
360 protected IEditorSite getIEditorSite() {
361 return getEditorSite().getEditorSite();
362 }
363
364 /***
365 * Returns renderer associated with this IEditor.
366 */
367 public IRenderer getRenderer() {
368 return this.renderer;
369 }
370
371 /***
372 * Returns Composite where children IEditors will be created.
373 */
374 public Composite getClientComposite() {
375 return (Composite) getGraphicalViewer().getControl();
376 }
377
378 /***
379 * Returns composite, which host this IEditor.
380 */
381 public Composite getHostingComposite() {
382 return this.composite;
383 }
384
385 /***
386 * Sets this Editor active.
387 */
388 public void setFocus() {
389 getGraphicalViewer().getControl().setFocus();
390 }
391
392
393
394
395
396
397 public void performPaintUpdate() {
398 getGraphicalViewer().flush();
399 }
400
401 /***
402 * Returns the command stack.
403 *
404 * @return the command stack
405 */
406 protected CommandStack getCommandStack() {
407 return getEditDomain().getCommandStack();
408 }
409
410 /***
411 * Returns EditDomain.
412 *
413 * @return editomain
414 */
415 protected EditDomain getEditDomain() {
416 return this.editDomain;
417 }
418
419 /***
420 * Setter.
421 *
422 * @param editDomain
423 * to set.
424 */
425 private void setEditDomain(EditDomain editDomain) {
426 this.editDomain = editDomain;
427 }
428
429 /***
430 * Creates and configures EditDomain. Sets DefaultTool a ActiveTool
431 *
432 * @return new EditDomain
433 */
434 protected EditDomain createEditDomain() {
435 EditDomain e = new XMLEditDomain(this);
436 e.setDefaultTool(new XMLStructureTool());
437 e.setActiveTool(e.getDefaultTool());
438 return e;
439 }
440
441 /***
442 * Creates root editpart
443 *
444 * @return created root editpart
445 */
446 protected RootEditPart createRootEditPart() {
447 return new ScalableRootEditPart();
448 }
449
450 /***
451 * Getter
452 *
453 * @return used EditPartFactory
454 */
455 public XMLEditPartFactory getEditPartFactory() {
456 return this.editPartFactory;
457 }
458
459 /***
460 * Setter.
461 *
462 * @param editPartFactory
463 * to set
464 */
465 public void setEditPartFactory(XMLEditPartFactory editPartFactory) {
466 this.editPartFactory = editPartFactory;
467 }
468
469 public void dispose() {
470 ((XMLActionContributor)getActionContributor()).dispose();
471 getEditDomain().setActiveTool(null);
472 getSelectionListeners().clear();
473 getFocusListeners().clear();
474 }
475
476 /***
477 * @return Selection in that is stored, what is selected in whole
478 * document
479 */
480 public DOMIntervalSet getDOMSelection() {
481 if (getEditorSite() == null) {
482 throw new IllegalStateException(
483 "Editor have to be initialized at first");
484 }
485 return getEditorSite().getDOMSelection();
486
487 }
488
489 /***
490 * @param listener
491 * IDOMSelectionChangedListener to be add to listeners
492 */
493 public void addSelectionChangedListener(
494 IDOMSelectionChangedListener listener) {
495 if (!(getSelectionListeners().contains(listener))) {
496 getSelectionListeners().add(listener);
497 }
498 }
499
500 /***
501 * @param listener
502 * IDOMSelectionChangedListener to be removed from
503 * listeners
504 */
505 public void removeSelectionChangedListener(
506 IDOMSelectionChangedListener listener) {
507 getSelectionListeners().remove(listener);
508 }
509
510 /***
511 * Stops listening to selection change events.
512 */
513 protected void stopSelectionListening() {
514 this.canSelectionChangeListen++;
515 }
516
517 /***
518 * Starts listening to selection change events.
519 */
520 protected void startSelectionListening() {
521 if (this.canSelectionChangeListen == 0)
522 throw new IllegalArgumentException();
523 this.canSelectionChangeListen--;
524 }
525
526 /***
527 * Fires selection change event.
528 *
529 * @param selection
530 * DOMIntervalSet instance which will be fired
531 */
532 protected void fireSelectionChangeEvent(DOMIntervalSet selection) {
533
534 stopSelectionListening();
535 DOMSelectionChangedEvent event = new DOMSelectionChangedEvent(
536 this, selection);
537
538 for (IDOMSelectionChangedListener listener : getSelectionListeners()) {
539 listener.selectionChanged(event);
540 }
541 startSelectionListening();
542 }
543
544 /***
545 * Routs information about this new IXMLSelection to SelectionListeners
546 *
547 * @param selection
548 * IXMLSelection to set
549 */
550 public void setSelection(DOMIntervalSet selection) {
551 fireSelectionChangeEvent(selection);
552 }
553
554 /***
555 * If event is IXMLSelection than this selection is routed to
556 * SelectionListeners in other way do nothing
557 *
558 * @param event
559 */
560 public void selectionChanged(DOMSelectionChangedEvent event) {
561
562 if (this.canSelectionChangeListen != 0)
563 return;
564 setSelection(event.getDOMSelection());
565 }
566
567 /***
568 * @return Returns the selectionListeners.
569 */
570 public ArrayList<IDOMSelectionChangedListener> getSelectionListeners() {
571 return this.selectionListeners;
572 }
573
574 /***
575 * Returns xml action contributor, can be called only after init.
576 *
577 * @return action contributor to bars and menus
578 */
579 public IActionContributor getActionContributor() {
580 if (this.actionContributor == null) {
581 throw new IllegalStateException();
582 }
583 return this.actionContributor;
584 }
585
586 /***
587 * @param actionContributor
588 * The ActionContributor to set.
589 */
590 public void setActionContributor(IActionContributor actionContributor) {
591 this.actionContributor = actionContributor;
592 }
593
594 public void addFocusListener(IFocusListener listener) {
595 if (!(getFocusListeners().contains(listener))) {
596 getFocusListeners().add(listener);
597 }
598 }
599
600 public void removeFocusListener(IFocusListener listener) {
601 getFocusListeners().remove(listener);
602 }
603
604 public void focusGained(FocusEvent e) {
605 for (IFocusListener listener : getFocusListeners()) {
606 listener.focusGained(this);
607 }
608 }
609
610 public void focusLost(FocusEvent e) {
611 for (IFocusListener listener : getFocusListeners()) {
612 listener.focusGained(this);
613 }
614 }
615
616 /***
617 * @return Returns the focusListeners.
618 */
619 public List<IFocusListener> getFocusListeners() {
620 return this.focusListeners;
621 }
622
623
624
625
626
627
628 public Set<String> getVisualizedIds() {
629 return getVisualInfo().getIds();
630 }
631
632 /***
633 * @param keyHandler
634 * The keyHandler to set.
635 */
636 protected void setKeyHandler(KeyHandler keyHandler) {
637 this.keyHandler = keyHandler;
638 }
639
640 public void sortIds(List<String> ids) {
641 Map<Rectangle, String> map = new HashMap<Rectangle, String>();
642 List<Rectangle> visuals = new ArrayList<Rectangle>();
643
644
645
646 for (String id : ids) {
647 if (getVisualInfo().getVisualParts(id).isEmpty()) {
648 continue;
649 }
650 Rectangle rect = new Rectangle(getVisualInfo()
651 .getVisualParts(id).get(0).getFigure()
652 .getBounds());
653 for (IXMLEditPart editPart : getVisualInfo()
654 .getVisualParts(id)) {
655 rect = rect.getUnion(editPart.getFigure()
656 .getBounds());
657 }
658 visuals.add(rect);
659 map.put(rect, id);
660 }
661
662 Collections.sort(visuals, new Comparator<Rectangle>() {
663
664 /***
665 * Compared are firstly Y-centers of rectangle with gap
666 * of 10% of height of smaller rectangle. If one has
667 * Y-center + 10% of height of smaller rectangle lesser
668 * than Y-center of second, is smaller. If not than
669 * their Y-positions are nearly same. So more are
670 * compared by X position. If stil not smaller was
671 * determined, compared are once more by Y-center but
672 * without gap. This results in one smaller or they are
673 * equals.
674 */
675 public int compare(Rectangle o1, Rectangle o2) {
676 if ((o1.x < 0) || (o1.y < 0) || (o1.width < 0)
677 || (o1.height < 0)
678 || (o2.x < 0) || (o2.y < 0)
679 || (o2.width < 0)
680 || (o2.height < 0)) {
681 throw new IllegalArgumentException();
682 }
683
684 int yGap = (int) (0.1 * Math.min(o1.height,
685 o2.height));
686
687
688 if (o1.y + o1.height * 0.5 + yGap < o2.y
689 + o2.height * 0.5) {
690 return -1;
691 }
692 if (o2.y + o2.height * 0.5 + yGap < o1.y
693 + o1.height * 0.5) {
694 return 1;
695 }
696
697
698 if (o1.x < o2.x) {
699 return -1;
700 }
701 if (o2.x < o1.x) {
702 return 1;
703 }
704
705
706 if (o1.y + o1.height * 0.5 < o2.y + o2.height
707 * 0.5) {
708 return -1;
709 }
710 if (o2.y + o2.height * 0.5 < o1.y + o1.height
711 * 0.5) {
712 return 1;
713 }
714
715
716
717 return 0;
718 }
719 });
720 ids.clear();
721 for (Rectangle rect : visuals) {
722 ids.add(map.get(rect));
723 }
724 }
725
726 }