View Javadoc

1   /*
2    * Created on Jul 24, 2005.
3    * Copyright 1999-2006 Faculty of Mathematics, Physics and Informatics, Comenius University, Bratislava.
4    * This file is protected by the Mozilla Public License
5    * version 1.1 (the "License"); you may not use this file except in compliance with the License. 
6    * You may obtain a copy of the License at 
7    * 
8    *      http://euromath2.sourceforge.net/license.html
9    * 
10   * Unless required by applicable law or agreed to in writing, software 
11   * distributed under the License is distributed on an "AS IS" BASIS, 
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
13   * See the License for the specific language governing permissions and 
14   * limitations under the License. 
15   */
16  package sk.uniba.euromath.editor;
17  
18  import java.util.ArrayList;
19  import java.util.Collection;
20  import java.util.EnumMap;
21  import java.util.EnumSet;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.LinkedList;
25  import java.util.List;
26  import java.util.Map;
27  import java.util.Queue;
28  import java.util.Set;
29  
30  import org.apache.commons.io.FilenameUtils;
31  import org.eclipse.core.runtime.IAdaptable;
32  import org.eclipse.core.runtime.IProgressMonitor;
33  import org.eclipse.core.runtime.IStatus;
34  import org.eclipse.draw2d.ColorConstants;
35  import org.eclipse.draw2d.geometry.Dimension;
36  import org.eclipse.draw2d.geometry.Point;
37  import org.eclipse.jface.dialogs.MessageDialog;
38  import org.eclipse.jface.viewers.ISelection;
39  import org.eclipse.jface.viewers.ISelectionChangedListener;
40  import org.eclipse.jface.viewers.ISelectionProvider;
41  import org.eclipse.jface.window.Window;
42  import org.eclipse.swt.SWT;
43  import org.eclipse.swt.graphics.Rectangle;
44  import org.eclipse.swt.layout.FillLayout;
45  import org.eclipse.swt.widgets.Composite;
46  import org.eclipse.ui.IEditorInput;
47  import org.eclipse.ui.IEditorSite;
48  import org.eclipse.ui.PartInitException;
49  import org.eclipse.ui.part.EditorPart;
50  import org.eclipse.ui.views.contentoutline.IContentOutlinePage;
51  
52  import sk.baka.ikslibs.ResultEnum;
53  import sk.baka.ikslibs.interval.DOMIntervalSet;
54  import sk.baka.xml.gene.CoordinatorInputKey;
55  import sk.baka.xml.gene.ExportException;
56  import sk.baka.xml.gene.exportgraph.TransformGraph;
57  import sk.uniba.euromath.EuroMath;
58  import sk.uniba.euromath.document.DocumentView;
59  import sk.uniba.euromath.document.XMLAccess;
60  import sk.uniba.euromath.editor.actions.MultiViewActionContributor;
61  import sk.uniba.euromath.editor.dialogs.Dialogs;
62  import sk.uniba.euromath.editor.dialogs.IWidgetFactory;
63  import sk.uniba.euromath.editor.dialogs.WidgetWrapperDialog;
64  import sk.uniba.euromath.editor.lang.Messages;
65  import sk.uniba.euromath.editor.selections.DOMSelectionChangedEvent;
66  import sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener;
67  import sk.uniba.euromath.editor.selections.IDOMSelectionProvider;
68  import sk.uniba.euromath.editor.widgets.FileBrowserEnum;
69  import sk.uniba.euromath.editor.widgets.FileRequirementsEnum;
70  import sk.uniba.euromath.editor.widgets.FileSelector;
71  import sk.uniba.euromath.editor.widgets.GraphSelectorWidget;
72  import sk.uniba.euromath.editor.widgets.IUserInputWidget;
73  import sk.uniba.euromath.editor.widgets.MessageLevelEnum;
74  import sk.uniba.euromath.editor.widgets.MultiWidget;
75  import sk.uniba.euromath.editor.xmlEditor.XMLEditor;
76  import sk.uniba.euromath.editor.xmlEditor.policies.FigureSelectionPolicy;
77  import sk.uniba.euromath.gene.IEditorDataReceiver;
78  import sk.uniba.euromath.gene.GeneDataProvider.RendererSite;
79  import sk.uniba.euromath.gene.gui.widgets.EncodingWidget;
80  import sk.uniba.euromath.gene.gui.widgets.XMLSerializerPropertiesWidget;
81  import sk.uniba.euromath.plugin.views.outline.XMLOutlinePage;
82  
83  /***
84   * TODO STUDVA recoment
85   * <h6>Is a View, is a true compound editor, composites of IEditors.</h6>
86   * <p>
87   * This class houses instances of IEditors: chooses from available, creates
88   * and/or destroys instances of IEditors when required and creates and positions
89   * Composites for them.
90   * </p>
91   * <p>
92   * Is is also ISelectionProvider and owns XMLSelection. Other
93   * IXMLSelectionProviders refernces this XMLSelection, modifies it and send
94   * changes back to EditorSite through methods setSelection(...) or
95   * selectionChanged(...)<br>
96   * </p>
97   * <p>
98   * Is also responsible for loading, transforming, saving. Main functionality is
99   * driven by GENE.
100  * </p>
101  * <p>
102  * Acts as view in MultiViewXMLEditor.
103  * </p>
104  * 
105  * @author Tomáš Studva, Martin Vysny, Martin Kollar
106  * @see sk.uniba.euromath.editor.IEditor
107  */
108 public final class EditorSite extends EditorPart implements
109                 IDOMSelectionProvider, IDOMSelectionChangedListener,
110                 ISelectionProvider, IEditorDataReceiver, IFocusListener {
111 
112         /***
113          * Auxiliary class for structure purpose only. Ties together IEditor
114          * info and stores IEditor hierarchy.
115          * 
116          * @author Tomáš Studva 23.1.2006
117          */
118         private class EditorContext {
119                 /***
120                  * Editor.
121                  */
122                 public IEditor editor;
123 
124                 /***
125                  * Used renderer site by editor.
126                  */
127                 public RendererSite rendererSite;
128 
129                 /***
130                  * Associated input.
131                  */
132                 public CoordinatorInputKey key;
133 
134                 /***
135                  * GENE id - renderer id.
136                  */
137                 public String id;
138 
139                 /***
140                  * Parent editor context reference.
141                  */
142                 public EditorContext parentEditorContext;
143 
144                 /***
145                  * Contructor.
146                  * 
147                  * @param editor -
148                  *                IEditor
149                  * @param rendererSite -
150                  *                used renderer site by editor
151                  * @param key
152                  *                Associated input
153                  * @param id -
154                  *                GENE id - renderer id
155                  * @param parentEditorContext -
156                  *                parent editor context reference
157                  */
158                 public EditorContext(IEditor editor, RendererSite rendererSite,
159                                 CoordinatorInputKey key, String id,
160                                 EditorContext parentEditorContext) {
161                         super();
162                         this.editor = editor;
163                         this.rendererSite = rendererSite;
164                         this.key = key;
165                         this.parentEditorContext = parentEditorContext;
166                         this.id = id;
167                 }
168         }
169 
170         /***
171          * Contributor instance.
172          */
173         private MultiViewActionContributor actionContributor;
174 
175         /***
176          * Topmost composite.
177          */
178         private Composite rootComposite;
179 
180         /***
181          * Active editor.
182          */
183         private IEditor activeEditor;
184 
185         /***
186          * Root editor, works with rootComposite.
187          */
188         private IEditor rootEditor;
189 
190         /***
191          * Editor containing this as view.
192          */
193         private final MultiViewXMLEditor parentMultiEditor;
194 
195         private DOMIntervalSet xmlSelection;
196 
197         /***
198          * Selection listeners of this editor site. Editor site selectionis
199          * synchronized with selection provider from this list.
200          */
201         private final List<IDOMSelectionChangedListener> selectionListeners = new ArrayList<IDOMSelectionChangedListener>();
202 
203         /***
204          * Guards selection listening. Prevents event-listen loops. Can listen
205          * only when equals zero.
206          */
207         private int canSelectionChangeListen = 0;
208 
209         /***
210          * IFocusListeners listening to focus changes between IEditors.
211          */
212         private final List<IFocusListener> focusListeners = new ArrayList<IFocusListener>();
213 
214         /***
215          * Outline page for this EditorSite - view.
216          */
217         private XMLOutlinePage outlinePage;
218 
219         /***
220          * Holds only those ids of nodes from xml data document, that are
221          * visualized(displayed) by at least one IEditor.
222          */
223         private final Set<String> visualizedIds;
224 
225         /***
226          * Holds source of last selectionChangeEvent.
227          */
228         // private Object selectionChangeEventSource;
229         /***
230          * For every key map holds associated(created, used) IEditor.
231          */
232         private final Map<CoordinatorInputKey, IEditor> keyEditorMap = new HashMap<CoordinatorInputKey, IEditor>();
233 
234         /***
235          * For every key map holds renderer related context(site).
236          */
237         private Map<CoordinatorInputKey, RendererSite> keyRendererSiteMap;
238 
239         /***
240          * For every key map holds editor related context. Context also contains
241          * key, so whole tree hierarchy is navigable.
242          */
243         private Map<CoordinatorInputKey, EditorContext> editorContexts = new HashMap<CoordinatorInputKey, EditorContext>();
244 
245         /***
246          * Constructor.
247          * 
248          * @param parentMultiEditor
249          *                host for this EditorSite.
250          */
251         public EditorSite(MultiViewXMLEditor parentMultiEditor) {
252                 this.parentMultiEditor = parentMultiEditor;
253                 // this.selectionProviders = new
254                 // ArrayList<IXMLSelectionProvider>();
255                 // this.globalSelection = new HashMap<IEditor, IXMLSelection>();
256                 this.xmlSelection = new DOMIntervalSet();
257                 this.visualizedIds = new HashSet<String>();
258         }
259 
260         /***
261          * @see org.eclipse.ui.ISaveablePart#doSave(org.eclipse.core.runtime.IProgressMonitor)
262          */
263         @Override
264         public void doSave(IProgressMonitor monitor) {
265                 try {
266                         getParentMultiEditor().getResourceManipulator().save(
267                                         null);
268                 } catch (Exception ex) {
269                         EuroMath.log(IStatus.ERROR, 0,
270                                         "Error storing document", ex); //$NON-NLS-1$
271                         MessageDialog
272                                         .openError(
273                                                         getEditorSite()
274                                                                         .getShell(),
275                                                         Messages
276                                                                         .getString("ERROR"), //$NON-NLS-1$
277                                                         Messages
278                                                                         .getString("ERROR_STORING_DOCUMENT") + ex.getLocalizedMessage()); //$NON-NLS-1$
279                 }
280         }
281 
282         /***
283          * @see org.eclipse.ui.ISaveablePart#doSaveAs()
284          */
285         @Override
286         public void doSaveAs() {
287                 final IWidgetFactory<MultiWidget> wfactory = new IWidgetFactory<MultiWidget>() {
288                         /*
289                          * (non-Javadoc)
290                          * 
291                          * @see sk.uniba.euromath.editor.dialogs.IWidgetFactory#create(org.eclipse.swt.widgets.Composite)
292                          */
293                         public MultiWidget create(Composite parent) {
294                                 final List<IUserInputWidget> widgets = new ArrayList<IUserInputWidget>(
295                                                 3);
296                                 // create the file selector.
297                                 final String docName = parentMultiEditor
298                                                 .getXMLAccess().getFileName();
299                                 int extSeparator = docName.lastIndexOf('.');
300                                 if (extSeparator < 0)
301                                         extSeparator = docName.length();
302                                 final String documentExtension = FilenameUtils
303                                                 .getExtension(docName);
304                                 final Map<FileRequirementsEnum, MessageLevelEnum> flags = new EnumMap<FileRequirementsEnum, MessageLevelEnum>(
305                                                 FileRequirementsEnum.class);
306                                 flags
307                                                 .put(
308                                                                 FileRequirementsEnum.MUST_BE_CREATABLE_FILE,
309                                                                 MessageLevelEnum.ERROR);
310                                 flags.put(FileRequirementsEnum.MUST_BE_FILE,
311                                                 MessageLevelEnum.ERROR);
312                                 flags
313                                                 .put(
314                                                                 FileRequirementsEnum.OBJECT_MUST_NOT_EXIST,
315                                                                 MessageLevelEnum.WARNING);
316                                 flags.put(FileRequirementsEnum.PATH_MUST_EXIST,
317                                                 MessageLevelEnum.ERROR);
318                                 final FileSelector fs = new FileSelector(
319                                                 parent, documentExtension,
320                                                 MessageLevelEnum.WARNING,
321                                                 flags,
322                                                 FileBrowserEnum.SAVE_FILE);
323                                 fs.setFileName(getXMLAccess().getDocumentURL()
324                                                 .toString());
325                                 widgets.add(fs);
326                                 // create the encoding selector
327                                 final EncodingWidget eq = new EncodingWidget(
328                                                 parent);
329                                 if (getXMLAccess().getEncoding() != null)
330                                         eq.select(getXMLAccess().getEncoding());
331                                 widgets.add(eq);
332                                 // create the output formatting query
333                                 final XMLSerializerPropertiesWidget deq = new XMLSerializerPropertiesWidget(
334                                                 parent);
335                                 widgets.add(deq);
336                                 return new MultiWidget(parent, widgets);
337                         }
338                 };
339                 final WidgetWrapperDialog<MultiWidget> dlg = new WidgetWrapperDialog<MultiWidget>(
340                                 getEditorSite().getShell(),
341                                 Messages.getString("SAVE_AS"), //$NON-NLS-1$
342                                 Messages.getString("SAVE_FILE_AS", //$NON-NLS-1$
343                                                 getXMLAccess().getFileName()),
344                                 wfactory);
345                 if (dlg.open() != Window.OK)
346                         return;
347                 // retrieve data from the dialog.
348                 final String fname = ((FileSelector) dlg.getWidget()
349                                 .getWidgets().get(0)).getFileName();
350                 final String encoding = ((EncodingWidget) dlg.getWidget()
351                                 .getWidgets().get(1)).getSelected();
352                 final XMLSerializerPropertiesWidget deq = (XMLSerializerPropertiesWidget) dlg
353                                 .getWidget().getWidgets().get(2);
354                 // save the file
355                 try {
356                         getParentMultiEditor().getResourceManipulator().save(
357                                         fname, encoding, deq);
358                 } catch (Exception ex) {
359                         EuroMath.log(IStatus.ERROR, 0,
360                                         "Error storing document", ex); //$NON-NLS-1$
361                         MessageDialog
362                                         .openError(
363                                                         getEditorSite()
364                                                                         .getShell(),
365                                                         Messages
366                                                                         .getString("ERROR"), //$NON-NLS-1$
367                                                         Messages
368                                                                         .getString("ERROR_STORING_DOCUMENT") + ex.getLocalizedMessage()); //$NON-NLS-1$
369                 }
370         }
371 
372         /***
373          * 
374          * @see org.eclipse.ui.IEditorPart#init(org.eclipse.ui.IEditorSite,
375          *      org.eclipse.ui.IEditorInput)
376          */
377         @Override
378         public void init(IEditorSite site, IEditorInput input)
379                         throws PartInitException {
380                 setSite(site);
381                 setInput(input);
382         }
383 
384         /***
385          * 
386          * @see org.eclipse.ui.ISaveablePart#isDirty()
387          */
388         @Override
389         public boolean isDirty() {
390                 return !getXMLAccess().getUndoManager().isSavePoint();
391         }
392 
393         /***
394          * 
395          * @see org.eclipse.ui.ISaveablePart#isSaveAsAllowed()
396          */
397         @Override
398         public boolean isSaveAsAllowed() {
399                 return true;
400         }
401 
402         /***
403          * Creates and initalizes IEditor for coordinator with "parent
404          * parentEditor". Actually IEditors don't have parents. Also creates
405          * Composite.
406          * 
407          * @param coordinator
408          *                CoordinatorInputKey for which to create editor
409          * @param id
410          *                of root node for newly created editr, it is also same
411          *                id as have associated renderer
412          * @param parentEditor
413          *                editor with Composite which host Composite for this
414          *                new editor
415          * @return new IEditor instance
416          * 
417          * @throws EditorException
418          *                 is thrown in all bad cases: no suitable editor found,
419          *                 editor creation failure, editor init failure
420          */
421         private IEditor buildEditor(CoordinatorInputKey coordinator, String id,
422                         IEditor parentEditor) throws EditorException {
423 
424                 String nameSpace = coordinator.targetNamespace;
425                 EnumSet<ResultEnum> resultTypes = EnumSet
426                                 .of(coordinator.info.resultType);
427 
428                 // get suitable editors
429                 List<EditorInfo> editorInfo = EditInstanceProvider
430                                 .getInstance().getEditorsForNamespace(
431                                                 nameSpace, resultTypes);
432                 try {
433                         IRenderer parentRenderer = parentEditor.getRenderer();
434                         RendererSite rendererSite = this.keyRendererSiteMap
435                                         .get(coordinator);
436                         // create composite on parents composite
437                         parentEditor.getClientComposite().setLayout(
438                                         new PreferredByControlLayout());
439                         Composite c = new Composite(parentEditor
440                                         .getClientComposite(),
441                                         SWT.NO_RADIO_GROUP);
442                         c.setBackground(ColorConstants.green);
443                         c.setLayout(new FillLayout());
444                         Point p = parentRenderer.getPlacement(id);
445                         Dimension dim = rendererSite.renderer.getCanvasSize();
446                         c
447                                         .setLayoutData(new Rectangle(
448                                                         p.x,
449                                                         p.y,
450                                                         dim.width
451                                                                         + 2
452                                                                         * FigureSelectionPolicy.SELECION_BORDER_WIDTH,
453                                                         dim.height
454                                                                         + 2
455                                                                         * FigureSelectionPolicy.SELECION_BORDER_WIDTH));
456                         // create IEditor
457                         IEditor editor = createBestEditor(editorInfo);
458                         // init IEditor
459                         editor.init(rendererSite.getSource().getSource(),
460                                         rendererSite.renderer, c,
461                                         getXMLAccess(), this);
462                         return editor;
463                 } catch (ExportException e) {
464                         throw new EditorException(
465                                         "Some IEditor fails to create.", e); //$NON-NLS-1$
466                 } catch (EditorException e) {
467                         throw new EditorException(
468                                         "Some IEditor fails to initialize.", e); //$NON-NLS-1$
469                 }
470         }
471 
472         /***
473          * Creates and initalizes root IEditor. Also creates Composite.
474          * 
475          * @param coordinator
476          *                Coordinator for this root editor
477          * @return root Editor
478          * 
479          * @throws EditorException
480          *                 is thrown in all bad cases: no suitable editor found,
481          *                 editor creation failure, editor init failure
482          */
483         private IEditor buildRootEditor(CoordinatorInputKey coordinator)
484                         throws EditorException {
485                 String nameSpace = coordinator.targetNamespace;
486                 EnumSet<ResultEnum> resultTypes = EnumSet.of(coordinator
487                                 .getResultType());
488                 // get suitable editors
489                 List<EditorInfo> editorInfo = EditInstanceProvider
490                                 .getInstance().getEditorsForNamespace(
491                                                 nameSpace, resultTypes);
492 
493                 try {
494                         getRootComposite().setLayout(new FillLayout());
495                         // create rootEditor
496                         IEditor result = createBestEditor(editorInfo);
497                         RendererSite rootRendererSite = this.keyRendererSiteMap
498                                         .get(coordinator);
499                         // init rootEditor
500                         // rootComposite.setLayout(null);
501                         result.init(rootRendererSite.getSource().getSource(),
502                                         rootRendererSite.renderer,
503                                         getRootComposite(), getXMLAccess(),
504                                         this);
505                         return result;
506                 } catch (ExportException e) {
507                         throw new EditorException(
508                                         "Root IEditor fails to create.", e); //$NON-NLS-1$
509                 }
510 
511         }
512 
513         /***
514          * Creates best editor. Created is IEditor implementing most of
515          * interfaces providing editing capability, such as
516          * {@link IXMLSelectionProvider}, providing Selections.
517          * 
518          * @param editorInfo
519          * @return new instance
520          * @throws EditorException
521          * @throws ExportException
522          */
523         private IEditor createBestEditor(List<EditorInfo> editorInfo)
524                         throws ExportException {
525                 // TODO Studva make it work as in coment or better
526                 if ((editorInfo == null) || editorInfo.isEmpty()) {
527                         return new XMLEditor();
528                 }
529                 return editorInfo.get(0).newEditor();
530         }
531 
532         /*
533          * (non-Javadoc)
534          * 
535          * @see sk.uniba.euromath.gene.IEditorDataReceiver#initReceiver()
536          */
537         public void initReceiver() {
538                 // nothing needs to be initialized.
539         }
540 
541         /***
542          * @see IEditorDataReceiver#dataChanged(java.util.Map,
543          *      CoordinatorInputKey, java.util.Map, java.util.Map,
544          *      java.util.Set, java.util.Set)
545          */
546         public void dataChanged(
547                         Map<CoordinatorInputKey, RendererSite> rendererKeys,
548                         CoordinatorInputKey rootKey,
549                         Map<CoordinatorInputKey, Set<CoordinatorInputKey>> nametreeHierarchy,
550                         Map<String, CoordinatorInputKey> geneIdMapping,
551                         Set<CoordinatorInputKey> newKeys,
552                         Set<CoordinatorInputKey> deletedKeys)
553                         throws EditorException {
554 
555                 this.editorContexts.clear();
556 
557                 // compute inverse map of geneIdMapping map.
558                 final HashMap<CoordinatorInputKey, String> keyIdMapping = new HashMap<CoordinatorInputKey, String>(
559                                 geneIdMapping.size());
560                 for (final String id : geneIdMapping.keySet()) {
561                         keyIdMapping.put(geneIdMapping.get(id), id);
562                 }
563 
564                 this.keyRendererSiteMap = rendererKeys;
565                 // delete old bad editors, for which now doesn't exists Key
566                 for (CoordinatorInputKey deletedKey : deletedKeys) {
567                         if (this.keyEditorMap.containsKey(deletedKey)) {
568                                 // destroy editor - remove from map, dispose,
569                                 // remove form
570                                 // selectionProviders
571                                 IEditor editor = this.keyEditorMap
572                                                 .get(deletedKey);
573                                 // getSelectionProviders().remove(editor);
574                                 if (editor instanceof IDOMSelectionProvider)
575                                         removeSelectionChangedListener(editor);
576                                 // getGlobalSelection().remove(editor);
577 
578                                 // remove this as focus listener
579                                 editor.addFocusListener(this);
580                                 // remove this as selection listener, if root
581                                 // editor provide
582                                 // selections
583                                 if (editor instanceof IDOMSelectionProvider) {
584                                         ((IDOMSelectionProvider) editor)
585                                                         .removeSelectionChangedListener(this);
586                                 }
587                                 editor.dispose();
588                                 this.keyEditorMap.remove(deletedKey);
589                         }
590                 }
591 
592                 // if needed build root editor
593                 if (newKeys.contains(rootKey)) {
594                         setRootEditor(buildRootEditor(rootKey));
595                         this.keyEditorMap.put(rootKey, getRootEditor());
596                         // fill context
597                         this.editorContexts.put(rootKey, new EditorContext(
598                                         getRootEditor(),
599                                         this.keyRendererSiteMap.get(rootKey),
600                                         rootKey, keyIdMapping.get(rootKey),
601                                         null));
602                         // add this as focus listener to handle focus events
603                         getRootEditor().addFocusListener(this);
604                         // add this as selection listener, if root editor
605                         // provide
606                         // selections
607                         if (getRootEditor() instanceof IDOMSelectionProvider) {
608                                 ((IDOMSelectionProvider) getRootEditor())
609                                                 .addSelectionChangedListener(this);
610                                 addSelectionChangedListener(getRootEditor());
611 
612                                 // getSelectionProviders().add(
613                                 // (IXMLSelectionProvider) getRootEditor());
614 
615                                 // getGlobalSelection().put(
616                                 // getRootEditor(),
617                                 // ((IXMLSelectionProvider) getRootEditor())
618                                 // .getSelection());
619                         }
620                 } else {
621                         // reinit of root editor
622                         getRootEditor().reinit(
623                                         rendererKeys.get(rootKey).getSource()
624                                                         .getSource(),
625                                         rendererKeys.get(rootKey).getSource());
626                         // update context
627                         this.editorContexts.put(rootKey, new EditorContext(
628                                         getRootEditor(),
629                                         this.keyRendererSiteMap.get(rootKey),
630                                         rootKey, keyIdMapping.get(rootKey),
631                                         null));
632 
633                 }
634 
635                 // build editors from root to lists
636                 IEditor parentEditor;
637                 IEditor newEditor;
638                 CoordinatorInputKey parentKey;
639 
640                 // contains keys for build editors, which don't have build
641                 // children
642                 Queue<CoordinatorInputKey> parentKeys = new LinkedList<CoordinatorInputKey>();
643                 parentKeys.add(rootKey);
644 
645                 while (!parentKeys.isEmpty()) {
646                         // choose one from list
647                         parentKey = parentKeys.poll();
648                         parentEditor = this.keyEditorMap.get(parentKey);
649                         // build its children
650                         for (CoordinatorInputKey sonKey : nametreeHierarchy
651                                         .get(parentKey)) {
652                                 if (newKeys.contains(sonKey)) {
653                                         final String sonKeyId = keyIdMapping
654                                                         .get(sonKey);
655                                         assert sonKeyId != null;
656                                         newEditor = buildEditor(sonKey,
657                                                         sonKeyId, parentEditor);
658                                         this.keyEditorMap
659                                                         .put(sonKey, newEditor);
660                                         // fill context
661                                         this.editorContexts
662                                                         .put(
663                                                                         sonKey,
664                                                                         new EditorContext(
665                                                                                         newEditor,
666                                                                                         this.keyRendererSiteMap
667                                                                                                         .get(sonKey),
668                                                                                         sonKey,
669                                                                                         keyIdMapping
670                                                                                                         .get(sonKey),
671                                                                                         this.editorContexts
672                                                                                                         .get(parentKey)));
673                                         // add freshly build editor to parent
674                                         // keys
675                                         parentKeys.add(sonKey);
676                                         // add this as focus listener to handle
677                                         // focus events
678                                         newEditor.addFocusListener(this);
679                                         // add this as selection listener, if
680                                         // new editor provide
681                                         // selections
682                                         if (newEditor instanceof IDOMSelectionProvider) {
683                                                 ((IDOMSelectionProvider) newEditor)
684                                                                 .addSelectionChangedListener(this);
685                                                 addSelectionChangedListener(newEditor);
686 
687                                                 // getSelectionProviders().add(
688                                                 // (IXMLSelectionProvider)
689                                                 // newEditor);
690 
691                                                 // getGlobalSelection().put(
692                                                 // newEditor,
693                                                 // ((IXMLSelectionProvider)
694                                                 // newEditor)
695                                                 // .getSelection());
696                                         }
697                                 } else {
698                                         // reinit
699                                         this.keyEditorMap
700                                                         .get(sonKey)
701                                                         .reinit(
702                                                                         rendererKeys
703                                                                                         .get(
704                                                                                                         sonKey)
705                                                                                         .getSource()
706                                                                                         .getSource(),
707                                                                         rendererKeys
708                                                                                         .get(
709                                                                                                         sonKey)
710                                                                                         .getSource());
711                                         // fill context
712                                         this.editorContexts
713                                                         .put(
714                                                                         sonKey,
715                                                                         new EditorContext(
716                                                                                         this.keyEditorMap
717                                                                                                         .get(sonKey),
718                                                                                         this.keyRendererSiteMap
719                                                                                                         .get(sonKey),
720                                                                                         sonKey,
721                                                                                         keyIdMapping
722                                                                                                         .get(sonKey),
723                                                                                         this.editorContexts
724                                                                                                         .get(parentKey)));
725                                 }
726                         }
727 
728                 }
729                 layout();
730                 computeVisualizedIds();
731                 fireSelectionChangeEvent();
732         }
733 
734         @Override
735         public void createPartControl(Composite parent) {
736                 this.rootComposite = parent;
737 
738                 // init the document presentation
739                 try {
740                         final DocumentView view = new DocumentView(
741                                         getParentMultiEditor().getXMLAccess(),
742                                         null, this);
743                         final WidgetWrapperDialog<GraphSelectorWidget> dlg = Dialogs
744                                         .createGraphSelector(
745                                                         this
746                                                                         .getEditorSite()
747                                                                         .getShell(),
748                                                         GraphSelectorWidget
749                                                                         .getEditableChoices(view
750                                                                                         .getEditGraph()),
751                                                         view.getEditGraph());
752                         if (dlg.open() != Window.OK) {
753                                 // user pressed cancel, abort the document
754                                 // opening process.
755                                 return;
756                         }
757                         final TransformGraph graph = dlg
758                                         .getWidget()
759                                         .getTransformationInfo(
760                                                         view
761                                                                         .getCoordinatorInfo());
762                         view.initialize(graph);
763                         // tu uz by mal tvoj EditorSite automaticky dostavat
764                         // tucne data
765                         // od GENE, instancovat editory atd atd.
766 
767                         getParentMultiEditor().getXMLAccess().openView(view);
768                 } catch (Exception ex) {
769                         EuroMath.log(IStatus.ERROR, 0,
770                                         "Error opening document view", ex); //$NON-NLS-1$
771                         MessageDialog
772                                         .openError(
773                                                         getEditorSite()
774                                                                         .getShell(),
775                                                         Messages
776                                                                         .getString("ERROR"), //$NON-NLS-1$
777                                                         Messages
778                                                                         .getString("ERROR_INITIALIZING_EDITOR") //$NON-NLS-1$
779                                                                         + ex
780                                                                                         .getLocalizedMessage());
781                         return;
782                 }
783                 // only when all was successful, create outline page
784                 createOutlinePage();
785         }
786 
787         /***
788          * Creates outline page.
789          */
790         private void createOutlinePage() {
791                 this.outlinePage = new XMLOutlinePage(this);
792                 // listen to its selection changes - synchronize selection
793                 this.outlinePage.addSelectionChangedListener(this);
794         }
795 
796         /***
797          * Returns outline page instance.
798          * 
799          * @return outline page instance
800          */
801         public XMLOutlinePage getOutlinePage() {
802                 return this.outlinePage;
803         }
804 
805         /***
806          * Sets focus to activete this EditorSite. As active editor is choosed
807          * last active or root editor.
808          */
809         @Override
810         public void setFocus() {
811                 if (getActiveEditor() != null)
812                         getActiveEditor().setFocus();
813                 if (getRootEditor() != null)
814                         setActiveEditor(getRootEditor());
815         }
816 
817         /***
818          * Sets editor as IEditor with focus.
819          * 
820          * @param editor
821          *                to set as active = with focus
822          */
823         private void setActiveEditor(IEditor editor) {
824                 this.activeEditor = editor;
825                 editor.setFocus();
826         }
827 
828         /***
829          * Returns active editor.
830          * 
831          * @return IEditor with focus
832          */
833         public IEditor getActiveEditor() {
834                 return this.activeEditor;
835         }
836 
837         /***
838          * Returns root editor.
839          * 
840          * @return root IEditor
841          */
842         public IEditor getRootEditor() {
843                 return this.rootEditor;
844         }
845 
846         /***
847          * Returns multi editor containing this EditorSite instance as child
848          * view.
849          * 
850          * @return parent multi editor
851          */
852         public MultiViewXMLEditor getParentMultiEditor() {
853                 return this.parentMultiEditor;
854         }
855 
856         /***
857          * Returns document instance.
858          * 
859          * @return xmlaccess instance
860          */
861         public XMLAccess getXMLAccess() {
862                 return getParentMultiEditor().getXMLAccess();
863         }
864 
865         /*
866          * (non-Javadoc)
867          * 
868          * @see sk.uniba.euromath.editor.selections.IDOMSelectionProvider#addSelectionChangedListener(sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener)
869          */
870         public void addSelectionChangedListener(
871                         IDOMSelectionChangedListener listener) {
872                 if (!this.selectionListeners.contains(listener)) {
873                         this.selectionListeners.add(listener);
874                 }
875         }
876 
877         /*
878          * (non-Javadoc)
879          * 
880          * @see sk.uniba.euromath.editor.selections.IDOMSelectionProvider#removeSelectionChangedListener(sk.uniba.euromath.editor.selections.IDOMSelectionChangedListener)
881          */
882         public void removeSelectionChangedListener(
883                         IDOMSelectionChangedListener listener) {
884                 this.selectionListeners.remove(listener);
885 
886         }
887 
888         /*
889          * (non-Javadoc)
890          * 
891          * @see sk.uniba.euromath.editor.selections.IDOMSelectionProvider#getDOMSelection()
892          */
893         public DOMIntervalSet getDOMSelection() {
894                 return new DOMIntervalSet(xmlSelection);
895         }
896 
897         /***
898          * Routes this new IXMLSelection to all listeners
899          * 
900          * @param selection
901          *                DOM selection to set
902          */
903         public void setSelection(DOMIntervalSet selection) {
904                 setSelection(selection, true);
905         }
906 
907         /***
908          * Fires SelectionEvent to all listeners, if toAll is <code>true</code>.
909          * Otherwise fires SelectionEvent only to active editor, if it provides
910          * selections (is IXMLSelectionProvider)
911          * 
912          * @param selection
913          *                IXMLSelection
914          * @param toAll
915          *                <code>true</code> means route in all IEditors, that
916          *                provides selections <code>false</code> route only in
917          *                active editor, if it provides selections
918          */
919         public void setSelection(DOMIntervalSet selection, Boolean toAll) {
920                 this.xmlSelection = selection;
921 
922                 if (toAll)
923                         fireSelectionChangeEvent();
924                 else {
925                         if ((getActiveEditor() != null)
926                                         && (getActiveEditor() instanceof IDOMSelectionProvider)) {
927 
928                                 // stop listening to ActiveEditor
929                                 ((IDOMSelectionProvider) getActiveEditor())
930                                                 .removeSelectionChangedListener(this);
931 
932                                 getActiveEditor()
933                                                 .selectionChanged(
934                                                                 new DOMSelectionChangedEvent(
935                                                                                 this,
936                                                                                 getDOMSelection()));
937 
938                                 // start listening to ActiveEditor
939                                 ((IDOMSelectionProvider) getActiveEditor())
940                                                 .addSelectionChangedListener(this);
941                         }
942                 }
943 
944         }
945 
946         /***
947          * FireSelectionChangeEvent containing current selection to listeners
948          */
949         private void fireSelectionChangeEvent() {
950                 // stop listening to avoid to receive by loop own event
951                 stopSelectionListening();
952 
953                 DOMSelectionChangedEvent event = new DOMSelectionChangedEvent(
954                                 this, getDOMSelection());
955 
956                 for (IDOMSelectionChangedListener listener : this.selectionListeners)
957                         listener.selectionChanged(event);
958 
959                 startSelectionListening();
960         }
961 
962         /***
963          * Stops listening to selection change events.
964          */
965         protected void stopSelectionListening() {
966                 this.canSelectionChangeListen++;
967         }
968 
969         /***
970          * Starts listening to selection change events.
971          */
972         protected void startSelectionListening() {
973                 if (this.canSelectionChangeListen == 0)
974                         throw new IllegalArgumentException();
975                 this.canSelectionChangeListen--;
976         }
977 
978         /***
979          * Source of event can be
980          * <ul>
981          * <li>IEditor</li>
982          * <li>ContentOutline</li>
983          * <li>something else for future </li>
984          * </ul>
985          * All this sources should be IXMLSelectionProviders, but more
986          * imporatant is that their IXMLSelection have to be "synchronized" with
987          * other IXMLSelectionProviders
988          * 
989          * @param event
990          *                SelectionChangedEvent <b>If event.getSelection() is
991          *                not instance of XMLSelection, does nothing.<b>
992          */
993         public void selectionChanged(DOMSelectionChangedEvent event) {
994                 if (this.xmlSelection.equals(event.getDOMSelection()))
995                         return;
996                 // guards listening
997                 if (this.canSelectionChangeListen != 0)
998                         return;
999                 this.xmlSelection = new DOMIntervalSet(event.getDOMSelection());
1000                 fireSelectionChangeEvent();
1001         }
1002 
1003         /***
1004          * @return selection providers IEditors or XMLOutline
1005          */
1006         /*
1007          * public List<IXMLSelectionProvider> getSelectionProviders() { return
1008          * this.selectionProviders; }
1009          * 
1010          * 
1011          * public HashMap<IEditor, IXMLSelection> getGlobalSelection() { return
1012          * this.globalSelection; }
1013          * 
1014          * public Object getSelectionChangeEventSource() { return
1015          * this.selectionChangeEventSource; }
1016          * 
1017          * public void setSelectionChangeEventSource(Object
1018          * selectionChangeEventSource) { this.selectionChangeEventSource =
1019          * selectionChangeEventSource; }
1020          */
1021 
1022         /***
1023          * Initializes every IEditor with shared action registry.
1024          * 
1025          * @param actionContributor
1026          */
1027         public void setActionContributor(
1028                         MultiViewActionContributor actionContributor) {
1029                 if (getActionContributor() == null) {
1030                         this.actionContributor = actionContributor;
1031                         for (IEditor editor : getAllIEditors()) {
1032                                 editor
1033                                                 .getActionContributor()
1034                                                 .init(
1035                                                                 this.actionContributor
1036                                                                                 .getActionRegistry());
1037                         }
1038                 }
1039         }
1040 
1041         /***
1042          * Returns the adapter for the specified class.
1043          */
1044         @Override
1045         public Object getAdapter(Class adapter) {
1046                 if (adapter.equals(IContentOutlinePage.class))
1047                         return getOutlinePage();
1048 
1049                 if (adapter.equals(IDOMSelectionProvider.class))
1050                         return this;
1051 
1052                 if (adapter.equals(XMLAccess.class))
1053                         return getXMLAccess();
1054 
1055                 if (adapter.equals(IEditor.class))
1056                         return getActiveEditor();
1057 
1058                 if (getActiveEditor() instanceof IAdaptable)
1059                         return ((IAdaptable) getActiveEditor())
1060                                         .getAdapter(adapter);
1061 
1062                 return null;
1063         }
1064 
1065         /***
1066          * Test if IEditor is root editor. If root editor doesn't exists, every
1067          * time returns true.
1068          * 
1069          * @param editor
1070          *                to test
1071          * @return <code>true</code> if editor is a rootEditor
1072          */
1073         public boolean isRootEditor(IEditor editor) {
1074                 return (getRootEditor() == editor) || (getRootEditor() == null);
1075         }
1076 
1077         /***
1078          * Lays out editors composites.
1079          */
1080         private void layout() {
1081                 // paints all editors and updates positions of editors
1082                 // composites
1083                 for (EditorContext editorContext : this.editorContexts.values()) {
1084                         // paint editor
1085                         // get renderer, parent renderer and id
1086                         if (editorContext.editor != getRootEditor()) {
1087                                 IRenderer parentRenderer = editorContext.parentEditorContext.rendererSite.renderer;
1088                                 Point location = parentRenderer
1089                                                 .getPlacement(editorContext.id);
1090                                 try {
1091                                         Dimension dim = editorContext.rendererSite.renderer
1092                                                         .getCanvasSize();
1093 
1094                                         editorContext.editor
1095                                                         .getHostingComposite()
1096                                                         .setLayoutData(
1097                                                                         new Rectangle(
1098                                                                                         location.x,
1099                                                                                         location.y,
1100                                                                                         dim.width,
1101                                                                                         dim.height));
1102                                 } catch (EditorException e) {
1103                                         EuroMath
1104                                                         .log(
1105                                                                         IStatus.ERROR,
1106                                                                         0,
1107                                                                         "Renderer dimension retreiving error.", e); //$NON-NLS-1$
1108                                 }
1109                         }
1110                 }
1111                 getRootComposite().layout(true, true);
1112         }
1113 
1114         /***
1115          * @return Returns the actionContributor.
1116          */
1117         public MultiViewActionContributor getActionContributor() {
1118                 return this.actionContributor;
1119         }
1120 
1121         /***
1122          * Adds listener as focus listener. Listener is added if is not yet
1123          * listening.
1124          * 
1125          * @param listener
1126          *                to add
1127          */
1128         public void addFocusListener(IFocusListener listener) {
1129                 if (!getFocusListeners().contains(listener))
1130                         getFocusListeners().add(listener);
1131         }
1132 
1133         /***
1134          * Removes listener. If not listener is not listening, nothing is done.
1135          * 
1136          * @param listener
1137          *                to remove
1138          */
1139         public void removeFocusListener(IFocusListener listener) {
1140                 getFocusListeners().remove(listener);
1141         }
1142 
1143         /***
1144          * @return Returns the focusListeners.
1145          */
1146         private List<IFocusListener> getFocusListeners() {
1147                 return this.focusListeners;
1148         }
1149 
1150         /***
1151          * @param rootEditor
1152          *                The rootEditor to set.
1153          */
1154         private void setRootEditor(IEditor rootEditor) {
1155                 this.rootEditor = rootEditor;
1156         }
1157 
1158         /***
1159          * IEditor has gained focus. Send message to focus listeners.
1160          */
1161         public void focusGained(IEditor editor) {
1162                 for (IFocusListener listener : getFocusListeners()) {
1163                         listener.focusGained(editor);
1164                 }
1165         }
1166 
1167         /***
1168          * IEditor has lost focus. Send message to focus listeners.
1169          */
1170         public void focusLost(IEditor editor) {
1171                 for (IFocusListener listener : getFocusListeners()) {
1172                         listener.focusLost(editor);
1173                 }
1174         }
1175 
1176         /***
1177          * Returns all IEditors in this site.
1178          * 
1179          * @return collection of all IEditors in this site
1180          */
1181         public Collection<IEditor> getAllIEditors() {
1182                 return this.keyEditorMap.values();
1183         }
1184 
1185         /***
1186          * Computes or recomputes visualized ids.
1187          * 
1188          * @see #getVisualizedIds()
1189          */
1190         private void computeVisualizedIds() {
1191                 this.visualizedIds.clear();
1192                 for (IEditor editor : getAllIEditors())
1193                         this.visualizedIds.addAll(editor.getVisualizedIds());
1194         }
1195 
1196         /***
1197          * Returns ids of nodes which are graphically rendered(represented) by
1198          * at least one IEditor. Id's are without :N.
1199          * 
1200          * @return list of ids which are visualized by at least one IEditor
1201          */
1202         public Set<String> getVisualizedIds() {
1203                 return this.visualizedIds;
1204         }
1205 
1206         /***
1207          * @return Returns the rootComposite.
1208          */
1209         public Composite getRootComposite() {
1210                 return this.rootComposite;
1211         }
1212 
1213         public void addSelectionChangedListener(
1214                         ISelectionChangedListener listener) {
1215                 // this is here because of context menu
1216         }
1217 
1218         public ISelection getSelection() {
1219                 return null;
1220         }
1221 
1222         public void removeSelectionChangedListener(
1223                         ISelectionChangedListener listener) {
1224         }
1225 
1226         public void setSelection(ISelection selection) {
1227         }
1228 
1229         @Override
1230         public void dispose() {
1231                 if (this.outlinePage != null)
1232                         this.outlinePage.removeSelectionChangedListener(this);
1233                 super.dispose();
1234         }
1235 }