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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.g2d.diagram.impl;
\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
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
34 * @author Toni Kalajainen
\r
36 public class AbstractDiagram implements IDiagram {
\r
38 ListenerList<CompositionVetoListener> compositionVetoListeners;
\r
39 ListenerList<CompositionListener> compositionListeners;
\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
46 IHintContext hintCtx;
\r
48 public AbstractDiagram(DiagramClass clazz, IHintContext hintCtx)
\r
51 throw new NullPointerException("null clazz");
\r
53 this.hintCtx = hintCtx;
\r
56 public void destroy()
\r
58 List<IElement> ss = getElements();
\r
62 // Fire destroy elements
\r
63 for (IElement e : ss)
\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
71 public void dispose()
\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
79 // Fire deactivate diagram
\r
82 // Dispose all elements to ensure their hints are freed up.
\r
83 for (IElement e : ss) {
\r
84 e.addedToDiagram(null);
\r
92 hintCtx.clearWithoutNotification();
\r
95 public DiagramClass getDiagramClass()
\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
105 public synchronized void removeCompositionListener(CompositionListener listener) {
\r
106 if (compositionListeners == null)
\r
108 compositionListeners.remove(listener);
\r
109 if (compositionListeners.isEmpty())
\r
110 compositionListeners = null;
\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
118 public synchronized void removeCompositionVetoListener(CompositionVetoListener listener) {
\r
119 if (compositionVetoListeners == null)
\r
121 compositionVetoListeners.remove(listener);
\r
122 if (compositionVetoListeners.isEmpty())
\r
123 compositionVetoListeners = null;
\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
131 public synchronized void addElement(IElement e) {
\r
132 assert(clazz!=null);
\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
144 e.addedToDiagram(this);
\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
149 for (ElementListener el : clazz.getItemsByClass(ElementListener.class))
\r
150 el.onElementAdded(this, e);
\r
152 fireElementAdded(e);
\r
155 protected void assertHasElement(IElement e)
\r
157 assert(elements.contains(e));
\r
161 public boolean containsElement(IElement element) {
\r
162 return elements.contains(element);
\r
166 * Remove element from the diagram
\r
167 * @param element element to remove
\r
169 public synchronized void removeElement(IElement e) {
\r
171 // new Exception(e.toString()).printStackTrace();
\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
179 //System.out.println("[" + this + "] removed element " + e + "");
\r
181 boolean removed = elements.remove(e);
\r
186 e.addedToDiagram(null);
\r
188 for (ElementListener el : clazz.getItemsByClass(ElementListener.class))
\r
189 el.onElementRemoved(this, e);
\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
194 fireElementRemoved(e);
\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
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
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
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
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
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
234 public List<IElement> getSnapshot() {
\r
235 List<IElement> snap = snapshot;
\r
238 synchronized (this) {
\r
241 snapshot = snap = Collections.unmodifiableList( new ArrayList<IElement>(list) );
\r
246 protected static void fireDestroyed(IDiagram e)
\r
248 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
\r
249 lc.onDiagramDestroyed(e);
\r
252 protected static void fireDeactivated(IDiagram e)
\r
254 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
\r
255 lc.onDiagramDisposed(e);
\r
258 protected static void fireCreated(IDiagram e)
\r
260 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
\r
261 lc.onDiagramCreated(e);
\r
264 protected static void fireLoaded(IDiagram e)
\r
266 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
\r
267 lc.onDiagramLoaded(e, e.getElements());
\r
270 protected void fireCreated()
\r
275 protected void fireLoaded()
\r
280 protected void fireDestroyed()
\r
282 fireDestroyed(this);
\r
285 protected void fireDeactivated()
\r
287 fireDeactivated(this);
\r
291 public void clearWithoutNotification() {
\r
292 hintCtx.clearWithoutNotification();
\r
296 public <E> E removeHint(Key key) {
\r
297 return hintCtx.removeHint(key);
\r
301 public void setHint(Key key, Object value) {
\r
302 hintCtx.setHint(key, value);
\r
306 public void setHints(Map<Key, Object> hints) {
\r
307 hintCtx.setHints(hints);
\r
311 public void addHintListener(IHintListener listener) {
\r
312 hintCtx.addHintListener(listener);
\r
316 public void addHintListener(IThreadWorkQueue threadAccess,
\r
317 IHintListener listener) {
\r
318 hintCtx.addHintListener(threadAccess, listener);
\r
322 public void addKeyHintListener(Key key, IHintListener listener) {
\r
323 hintCtx.addKeyHintListener(key, listener);
\r
327 public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key,
\r
328 IHintListener listener) {
\r
329 hintCtx.addKeyHintListener(threadAccess, key, listener);
\r
333 public boolean containsHint(Key key) {
\r
334 return hintCtx.containsHint(key);
\r
338 public <E> E getHint(Key key) {
\r
339 return hintCtx.getHint(key);
\r
343 public Map<Key, Object> getHints() {
\r
344 return hintCtx.getHints();
\r
348 public Map<Key, Object> getHintsUnsafe() {
\r
349 return hintCtx.getHintsUnsafe();
\r
353 public <E extends Key> Map<E, Object> getHintsOfClass(Class<E> clazz) {
\r
354 return hintCtx.getHintsOfClass(clazz);
\r
358 public void removeHintListener(IHintListener listener) {
\r
359 hintCtx.removeHintListener(listener);
\r
363 public void removeHintListener(IThreadWorkQueue threadAccess,
\r
364 IHintListener listener) {
\r
365 hintCtx.removeHintListener(threadAccess, listener);
\r
369 public void removeKeyHintListener(Key key, IHintListener listener) {
\r
370 hintCtx.removeKeyHintListener(key, listener);
\r
374 public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key,
\r
375 IHintListener listener) {
\r
376 hintCtx.removeKeyHintListener(threadAccess, key, listener);
\r
380 public boolean bringToTop(IElement e) {
\r
381 assertHasElement(e);
\r
382 if (list.get(list.size()-1)==e) return false;
\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
395 IElement upper = list.get(j);
\r
397 list.set(i, upper);
\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
408 IElement lower = list.get(j);
\r
410 list.set(i, lower);
\r
416 public boolean sendToBottom(IElement e) {
\r
417 assertHasElement(e);
\r
418 if (list.get(0)==e) return false;
\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
437 public List<IElement> getElements() {
\r
438 return unmodifiableList;
\r
442 public void sort(Comparator<IElement> comparator) {
\r
443 Collections.sort(list, comparator);
\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