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