]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.g2d/src/org/simantics/g2d/diagram/impl/AbstractDiagram.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.g2d / src / org / simantics / g2d / diagram / impl / AbstractDiagram.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.g2d.diagram.impl;\r
13 \r
14 import java.util.ArrayList;\r
15 import java.util.Collections;\r
16 import java.util.Comparator;\r
17 import java.util.HashSet;\r
18 import java.util.List;\r
19 import java.util.Map;\r
20 import java.util.Set;\r
21 \r
22 import org.simantics.g2d.diagram.DiagramClass;\r
23 import org.simantics.g2d.diagram.IDiagram;\r
24 import org.simantics.g2d.diagram.handler.DiagramAdapter;\r
25 import org.simantics.g2d.diagram.handler.ElementListener;\r
26 import org.simantics.g2d.diagram.handler.LifeCycle;\r
27 import org.simantics.g2d.element.IElement;\r
28 import org.simantics.utils.datastructures.ListenerList;\r
29 import org.simantics.utils.datastructures.hints.IHintContext;\r
30 import org.simantics.utils.datastructures.hints.IHintListener;\r
31 import org.simantics.utils.threads.IThreadWorkQueue;\r
32 \r
33 /**\r
34  * @author Toni Kalajainen\r
35  */\r
36 public class AbstractDiagram implements IDiagram {\r
37 \r
38     ListenerList<CompositionVetoListener> compositionVetoListeners;\r
39     ListenerList<CompositionListener>     compositionListeners;\r
40 \r
41     Set<IElement>                         elements         = new HashSet<IElement>();\r
42     ArrayList<IElement>                   list             = new ArrayList<IElement>();\r
43     List<IElement>                        unmodifiableList = Collections.unmodifiableList(list);\r
44     volatile List<IElement>               snapshot         = null;\r
45     DiagramClass                          clazz;\r
46     IHintContext                          hintCtx;\r
47 \r
48     public AbstractDiagram(DiagramClass clazz, IHintContext hintCtx)\r
49     {\r
50         if (clazz == null)\r
51             throw new NullPointerException("null clazz");\r
52         this.clazz = clazz;\r
53         this.hintCtx = hintCtx;\r
54     }\r
55 \r
56     public void destroy()\r
57     {\r
58         List<IElement> ss = getElements();\r
59 \r
60         dispose();\r
61 \r
62         // Fire destroy elements\r
63         for (IElement e : ss)\r
64             e.destroy();\r
65 \r
66         // Fire destroy diagram\r
67         for (org.simantics.g2d.diagram.handler.LifeCycle lc : clazz.getItemsByClass(org.simantics.g2d.diagram.handler.LifeCycle.class))\r
68             lc.onDiagramDestroyed(this);\r
69     }\r
70 \r
71     public void dispose()\r
72     {\r
73         List<IElement> ss = getElements();\r
74         // Fire deactiavate elements\r
75         for (IElement e : ss)\r
76             for (org.simantics.g2d.element.handler.LifeCycle lc : e.getElementClass().getItemsByClass(org.simantics.g2d.element.handler.LifeCycle.class))\r
77                 lc.onElementDeactivated(this, e);\r
78 \r
79         // Fire deactivate diagram\r
80         fireDeactivated();\r
81 \r
82         // Dispose all elements to ensure their hints are freed up.\r
83         for (IElement e : ss) {\r
84             e.addedToDiagram(null);\r
85             e.dispose();\r
86         }\r
87 \r
88         elements.clear();\r
89         list.clear();\r
90         snapshot = null;\r
91 \r
92         hintCtx.clearWithoutNotification();\r
93     }\r
94 \r
95     public DiagramClass getDiagramClass()\r
96     {\r
97         return clazz;\r
98     }\r
99 \r
100     public synchronized void addCompositionListener(CompositionListener listener) {\r
101         if (compositionListeners ==null)\r
102             compositionListeners = new ListenerList<CompositionListener>(CompositionListener.class);\r
103         compositionListeners.add(listener);\r
104     }\r
105     public synchronized void removeCompositionListener(CompositionListener listener) {\r
106         if (compositionListeners == null)\r
107             return;\r
108         compositionListeners.remove(listener);\r
109         if (compositionListeners.isEmpty())\r
110             compositionListeners = null;\r
111     }\r
112 \r
113     public synchronized void addCompositionVetoListener(CompositionVetoListener listener) {\r
114         if (compositionVetoListeners ==null)\r
115             compositionVetoListeners = new ListenerList<CompositionVetoListener>(CompositionVetoListener.class);\r
116         compositionVetoListeners.add(listener);\r
117     }\r
118     public synchronized void removeCompositionVetoListener(CompositionVetoListener listener) {\r
119         if (compositionVetoListeners == null)\r
120             return;\r
121         compositionVetoListeners.remove(listener);\r
122         if (compositionVetoListeners.isEmpty())\r
123             compositionVetoListeners = null;\r
124     }\r
125 \r
126     /**\r
127      * Adds a new element. The element will not be initialized\r
128      * @param clazz element class\r
129      * @return element of class\r
130      */\r
131     public synchronized void addElement(IElement e) {\r
132         assert(clazz!=null);\r
133 \r
134         // Give the possibility for listeners to veto an element addition\r
135         if (!fireBeforeElementAdded(e)) {\r
136             System.out.println("Element addition VETOED for " + e);\r
137             return;\r
138         }\r
139 \r
140         snapshot = null;\r
141         elements.add(e);\r
142         list.add(e);\r
143 \r
144         e.addedToDiagram(this);\r
145 \r
146         for (org.simantics.g2d.element.handler.LifeCycle lc : e.getElementClass().getItemsByClass(org.simantics.g2d.element.handler.LifeCycle.class))\r
147             lc.onElementActivated(this, e);\r
148 \r
149         for (ElementListener el : clazz.getItemsByClass(ElementListener.class))\r
150             el.onElementAdded(this, e);\r
151 \r
152         fireElementAdded(e);\r
153     }\r
154 \r
155     protected void assertHasElement(IElement e)\r
156     {\r
157         assert(elements.contains(e));\r
158     }\r
159 \r
160     @Override\r
161     public boolean containsElement(IElement element) {\r
162         return elements.contains(element);\r
163     }\r
164 \r
165     /**\r
166      * Remove element from the diagram\r
167      * @param element element to remove\r
168      */\r
169     public synchronized void removeElement(IElement e) {\r
170 \r
171 //        new Exception(e.toString()).printStackTrace();\r
172 \r
173         // Give the possibility for listeners to veto an element removal.\r
174         if (!fireBeforeElementRemoved(e)) {\r
175             System.out.println("Element removal VETOED for " + e);\r
176             return;\r
177         }\r
178 \r
179         //System.out.println("[" + this + "] removed element " + e + "");\r
180 \r
181         boolean removed = elements.remove(e);\r
182         assert(removed);\r
183         list.remove(e);\r
184         snapshot = null;\r
185 \r
186         e.addedToDiagram(null);\r
187 \r
188         for (ElementListener el : clazz.getItemsByClass(ElementListener.class))\r
189             el.onElementRemoved(this, e);\r
190 \r
191         for (org.simantics.g2d.element.handler.LifeCycle lc : e.getElementClass().getItemsByClass(org.simantics.g2d.element.handler.LifeCycle.class))\r
192             lc.onElementDeactivated(this, e);\r
193 \r
194         fireElementRemoved(e);\r
195     }\r
196 \r
197     /**\r
198      * @param e the element to be added\r
199      * @return <code>true</code> if the addition was allowed by all listeners or\r
200      *         <code>false</code> if the addition was vetoed\r
201      */\r
202     protected boolean fireBeforeElementAdded(IElement e) {\r
203         if (compositionVetoListeners==null) return true;\r
204         for (CompositionVetoListener l : compositionVetoListeners.getListeners())\r
205             if (!l.beforeElementAdded(this, e))\r
206                 return false;\r
207         return true;\r
208     }\r
209 \r
210     /**\r
211      * @param e the element to be removed\r
212      * @return <code>true</code> if the removal was allowed by all listeners or\r
213      *         <code>false</code> if the removal was vetoed\r
214      */\r
215     protected boolean fireBeforeElementRemoved(IElement e) {\r
216         if (compositionVetoListeners==null) return true;\r
217         for (CompositionVetoListener l : compositionVetoListeners.getListeners())\r
218             if (!l.beforeElementRemoved(this, e))\r
219                 return false;\r
220         return true;\r
221     }\r
222     protected void fireElementAdded(IElement e) {\r
223         if (compositionListeners==null) return;\r
224         for (CompositionListener l : compositionListeners.getListeners())\r
225             l.onElementAdded(this, e);\r
226     }\r
227     protected void fireElementRemoved(IElement e) {\r
228         if (compositionListeners==null) return;\r
229         for (CompositionListener l : compositionListeners.getListeners())\r
230             l.onElementRemoved(this, e);\r
231     }\r
232 \r
233     @Override\r
234     public List<IElement> getSnapshot() {\r
235         List<IElement> snap = snapshot;\r
236         if (snap != null)\r
237             return snap;\r
238         synchronized (this) {\r
239             snap = snapshot;\r
240             if (snap == null)\r
241                 snapshot = snap = Collections.unmodifiableList( new ArrayList<IElement>(list) );\r
242         }\r
243         return snap;\r
244     }\r
245 \r
246     protected static void fireDestroyed(IDiagram e)\r
247     {\r
248         for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))\r
249             lc.onDiagramDestroyed(e);\r
250     }\r
251 \r
252     protected static void fireDeactivated(IDiagram e)\r
253     {\r
254         for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))\r
255             lc.onDiagramDisposed(e);\r
256     }\r
257 \r
258     protected static void fireCreated(IDiagram e)\r
259     {\r
260         for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))\r
261             lc.onDiagramCreated(e);\r
262     }\r
263 \r
264     protected static void fireLoaded(IDiagram e)\r
265     {\r
266         for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))\r
267             lc.onDiagramLoaded(e, e.getElements());\r
268     }\r
269 \r
270     protected void fireCreated()\r
271     {\r
272         fireCreated(this);\r
273     }\r
274 \r
275     protected void fireLoaded()\r
276     {\r
277         fireLoaded(this);\r
278     }\r
279 \r
280     protected void fireDestroyed()\r
281     {\r
282         fireDestroyed(this);\r
283     }\r
284 \r
285     protected void fireDeactivated()\r
286     {\r
287         fireDeactivated(this);\r
288     }\r
289 \r
290     @Override\r
291     public void clearWithoutNotification() {\r
292         hintCtx.clearWithoutNotification();\r
293     }\r
294 \r
295     @Override\r
296     public <E> E removeHint(Key key) {\r
297         return hintCtx.removeHint(key);\r
298     }\r
299 \r
300     @Override\r
301     public void setHint(Key key, Object value) {\r
302         hintCtx.setHint(key, value);\r
303     }\r
304 \r
305     @Override\r
306     public void setHints(Map<Key, Object> hints) {\r
307         hintCtx.setHints(hints);\r
308     }\r
309 \r
310     @Override\r
311     public void addHintListener(IHintListener listener) {\r
312         hintCtx.addHintListener(listener);\r
313     }\r
314 \r
315     @Override\r
316     public void addHintListener(IThreadWorkQueue threadAccess,\r
317             IHintListener listener) {\r
318         hintCtx.addHintListener(threadAccess, listener);\r
319     }\r
320 \r
321     @Override\r
322     public void addKeyHintListener(Key key, IHintListener listener) {\r
323         hintCtx.addKeyHintListener(key, listener);\r
324     }\r
325 \r
326     @Override\r
327     public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key,\r
328             IHintListener listener) {\r
329         hintCtx.addKeyHintListener(threadAccess, key, listener);\r
330     }\r
331 \r
332     @Override\r
333     public boolean containsHint(Key key) {\r
334         return hintCtx.containsHint(key);\r
335     }\r
336 \r
337     @Override\r
338     public <E> E getHint(Key key) {\r
339         return hintCtx.getHint(key);\r
340     }\r
341 \r
342     @Override\r
343     public Map<Key, Object> getHints() {\r
344         return hintCtx.getHints();\r
345     }\r
346 \r
347     @Override\r
348     public Map<Key, Object> getHintsUnsafe() {\r
349         return hintCtx.getHintsUnsafe();\r
350     }\r
351 \r
352     @Override\r
353     public <E extends Key> Map<E, Object> getHintsOfClass(Class<E> clazz) {\r
354         return hintCtx.getHintsOfClass(clazz);\r
355     }\r
356 \r
357     @Override\r
358     public void removeHintListener(IHintListener listener) {\r
359         hintCtx.removeHintListener(listener);\r
360     }\r
361 \r
362     @Override\r
363     public void removeHintListener(IThreadWorkQueue threadAccess,\r
364             IHintListener listener) {\r
365         hintCtx.removeHintListener(threadAccess, listener);\r
366     }\r
367 \r
368     @Override\r
369     public void removeKeyHintListener(Key key, IHintListener listener) {\r
370         hintCtx.removeKeyHintListener(key, listener);\r
371     }\r
372 \r
373     @Override\r
374     public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key,\r
375             IHintListener listener) {\r
376         hintCtx.removeKeyHintListener(threadAccess, key, listener);\r
377     }\r
378 \r
379     @Override\r
380     public boolean bringToTop(IElement e) {\r
381         assertHasElement(e);\r
382         if (list.get(list.size()-1)==e) return false;\r
383         list.add( e );\r
384         list.remove( e );\r
385         snapshot = null;\r
386         return true;\r
387     }\r
388 \r
389     @Override\r
390     public boolean bringUp(IElement e) {\r
391         assertHasElement(e);\r
392         int i = list.indexOf(e);\r
393         if (i==list.size()-1) return false;\r
394         int j = i+1;\r
395         IElement upper = list.get(j);\r
396         list.set(j, e);\r
397         list.set(i, upper);\r
398         snapshot = null;\r
399         return true;\r
400     }\r
401 \r
402     @Override\r
403     public boolean sendDown(IElement e) {\r
404         assertHasElement(e);\r
405         int i = list.indexOf(e);\r
406         if (i==0) return false;\r
407         int j = i-1;\r
408         IElement lower = list.get(j);\r
409         list.set(j, e);\r
410         list.set(i, lower);\r
411         snapshot = null;\r
412         return true;\r
413     }\r
414 \r
415     @Override\r
416     public boolean sendToBottom(IElement e) {\r
417         assertHasElement(e);\r
418         if (list.get(0)==e) return false;\r
419         list.remove(e);\r
420         list.add(0, e);\r
421         snapshot = null;\r
422         return true;\r
423     }\r
424 \r
425     @Override\r
426     public boolean moveTo(IElement e, int position) {\r
427         assertHasElement(e);\r
428         int indexOf = list.indexOf(e);\r
429         if (indexOf==position) return false;\r
430         list.remove(indexOf);\r
431         list.add(position, e);\r
432         snapshot = null;\r
433         return true;\r
434     }\r
435 \r
436     @Override\r
437     public List<IElement> getElements() {\r
438         return unmodifiableList;\r
439     }\r
440 \r
441     @Override\r
442     public void sort(Comparator<IElement> comparator) {\r
443         Collections.sort(list, comparator);\r
444     }\r
445 \r
446     @SuppressWarnings("rawtypes")\r
447     public Object getAdapter(Class adapter) {\r
448         for (DiagramAdapter ea : clazz.getItemsByClass(DiagramAdapter.class)) {\r
449             Object result = ea.getAdapter(this, adapter);\r
450             if (result != null)\r
451                 return result;\r
452         }\r
453         return null;\r
454     }\r
455 \r
456 }\r