1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.g2d.diagram.impl;
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.HashSet;
18 import java.util.List;
22 import org.simantics.g2d.diagram.DiagramClass;
23 import org.simantics.g2d.diagram.IDiagram;
24 import org.simantics.g2d.diagram.handler.DiagramAdapter;
25 import org.simantics.g2d.diagram.handler.ElementListener;
26 import org.simantics.g2d.diagram.handler.LifeCycle;
27 import org.simantics.g2d.element.IElement;
28 import org.simantics.utils.datastructures.ListenerList;
29 import org.simantics.utils.datastructures.hints.IHintContext;
30 import org.simantics.utils.datastructures.hints.IHintListener;
31 import org.simantics.utils.threads.IThreadWorkQueue;
34 * @author Toni Kalajainen
36 public class AbstractDiagram implements IDiagram {
38 ListenerList<CompositionVetoListener> compositionVetoListeners;
39 ListenerList<CompositionListener> compositionListeners;
41 Set<IElement> elements = new HashSet<IElement>();
42 ArrayList<IElement> list = new ArrayList<IElement>();
43 List<IElement> unmodifiableList = Collections.unmodifiableList(list);
44 volatile List<IElement> snapshot = null;
48 public AbstractDiagram(DiagramClass clazz, IHintContext hintCtx)
51 throw new NullPointerException("null clazz");
53 this.hintCtx = hintCtx;
58 List<IElement> ss = getElements();
62 // Fire destroy elements
66 // Fire destroy diagram
67 for (org.simantics.g2d.diagram.handler.LifeCycle lc : clazz.getItemsByClass(org.simantics.g2d.diagram.handler.LifeCycle.class))
68 lc.onDiagramDestroyed(this);
73 List<IElement> ss = getElements();
74 // Fire deactiavate elements
76 for (org.simantics.g2d.element.handler.LifeCycle lc : e.getElementClass().getItemsByClass(org.simantics.g2d.element.handler.LifeCycle.class))
77 lc.onElementDeactivated(this, e);
79 // Fire deactivate diagram
82 // Dispose all elements to ensure their hints are freed up.
83 for (IElement e : ss) {
84 e.addedToDiagram(null);
92 hintCtx.clearWithoutNotification();
95 public DiagramClass getDiagramClass()
100 public synchronized void addCompositionListener(CompositionListener listener) {
101 if (compositionListeners ==null)
102 compositionListeners = new ListenerList<CompositionListener>(CompositionListener.class);
103 compositionListeners.add(listener);
105 public synchronized void removeCompositionListener(CompositionListener listener) {
106 if (compositionListeners == null)
108 compositionListeners.remove(listener);
109 if (compositionListeners.isEmpty())
110 compositionListeners = null;
113 public synchronized void addCompositionVetoListener(CompositionVetoListener listener) {
114 if (compositionVetoListeners ==null)
115 compositionVetoListeners = new ListenerList<CompositionVetoListener>(CompositionVetoListener.class);
116 compositionVetoListeners.add(listener);
118 public synchronized void removeCompositionVetoListener(CompositionVetoListener listener) {
119 if (compositionVetoListeners == null)
121 compositionVetoListeners.remove(listener);
122 if (compositionVetoListeners.isEmpty())
123 compositionVetoListeners = null;
127 * Adds a new element. The element will not be initialized
128 * @param clazz element class
129 * @return element of class
131 public synchronized void addElement(IElement e) {
134 // Give the possibility for listeners to veto an element addition
135 if (!fireBeforeElementAdded(e)) {
136 System.out.println("Element addition VETOED for " + e);
144 e.addedToDiagram(this);
146 for (org.simantics.g2d.element.handler.LifeCycle lc : e.getElementClass().getItemsByClass(org.simantics.g2d.element.handler.LifeCycle.class))
147 lc.onElementActivated(this, e);
149 for (ElementListener el : clazz.getItemsByClass(ElementListener.class))
150 el.onElementAdded(this, e);
155 protected void assertHasElement(IElement e)
157 assert(elements.contains(e));
161 public boolean containsElement(IElement element) {
162 return elements.contains(element);
166 * Remove element from the diagram
167 * @param element element to remove
169 public synchronized void removeElement(IElement e) {
171 // new Exception(e.toString()).printStackTrace();
173 // Give the possibility for listeners to veto an element removal.
174 if (!fireBeforeElementRemoved(e)) {
175 System.out.println("Element removal VETOED for " + e);
179 //System.out.println("[" + this + "] removed element " + e + "");
181 boolean removed = elements.remove(e);
186 e.addedToDiagram(null);
188 for (ElementListener el : clazz.getItemsByClass(ElementListener.class))
189 el.onElementRemoved(this, e);
191 for (org.simantics.g2d.element.handler.LifeCycle lc : e.getElementClass().getItemsByClass(org.simantics.g2d.element.handler.LifeCycle.class))
192 lc.onElementDeactivated(this, e);
194 fireElementRemoved(e);
198 * @param e the element to be added
199 * @return <code>true</code> if the addition was allowed by all listeners or
200 * <code>false</code> if the addition was vetoed
202 protected boolean fireBeforeElementAdded(IElement e) {
203 if (compositionVetoListeners==null) return true;
204 for (CompositionVetoListener l : compositionVetoListeners.getListeners())
205 if (!l.beforeElementAdded(this, e))
211 * @param e the element to be removed
212 * @return <code>true</code> if the removal was allowed by all listeners or
213 * <code>false</code> if the removal was vetoed
215 protected boolean fireBeforeElementRemoved(IElement e) {
216 if (compositionVetoListeners==null) return true;
217 for (CompositionVetoListener l : compositionVetoListeners.getListeners())
218 if (!l.beforeElementRemoved(this, e))
222 protected void fireElementAdded(IElement e) {
223 if (compositionListeners==null) return;
224 for (CompositionListener l : compositionListeners.getListeners())
225 l.onElementAdded(this, e);
227 protected void fireElementRemoved(IElement e) {
228 if (compositionListeners==null) return;
229 for (CompositionListener l : compositionListeners.getListeners())
230 l.onElementRemoved(this, e);
234 public List<IElement> getSnapshot() {
235 List<IElement> snap = snapshot;
238 synchronized (this) {
241 snapshot = snap = Collections.unmodifiableList( new ArrayList<IElement>(list) );
246 protected static void fireDestroyed(IDiagram e)
248 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
249 lc.onDiagramDestroyed(e);
252 protected static void fireDeactivated(IDiagram e)
254 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
255 lc.onDiagramDisposed(e);
258 protected static void fireCreated(IDiagram e)
260 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
261 lc.onDiagramCreated(e);
264 protected static void fireLoaded(IDiagram e)
266 for (LifeCycle lc : e.getDiagramClass().getItemsByClass(LifeCycle.class))
267 lc.onDiagramLoaded(e, e.getElements());
270 protected void fireCreated()
275 protected void fireLoaded()
280 protected void fireDestroyed()
285 protected void fireDeactivated()
287 fireDeactivated(this);
291 public void clearWithoutNotification() {
292 hintCtx.clearWithoutNotification();
296 public <E> E removeHint(Key key) {
297 return hintCtx.removeHint(key);
301 public void setHint(Key key, Object value) {
302 hintCtx.setHint(key, value);
306 public void setHints(Map<Key, Object> hints) {
307 hintCtx.setHints(hints);
311 public void addHintListener(IHintListener listener) {
312 hintCtx.addHintListener(listener);
316 public void addHintListener(IThreadWorkQueue threadAccess,
317 IHintListener listener) {
318 hintCtx.addHintListener(threadAccess, listener);
322 public void addKeyHintListener(Key key, IHintListener listener) {
323 hintCtx.addKeyHintListener(key, listener);
327 public void addKeyHintListener(IThreadWorkQueue threadAccess, Key key,
328 IHintListener listener) {
329 hintCtx.addKeyHintListener(threadAccess, key, listener);
333 public boolean containsHint(Key key) {
334 return hintCtx.containsHint(key);
338 public <E> E getHint(Key key) {
339 return hintCtx.getHint(key);
343 public Map<Key, Object> getHints() {
344 return hintCtx.getHints();
348 public Map<Key, Object> getHintsUnsafe() {
349 return hintCtx.getHintsUnsafe();
353 public <E extends Key> Map<E, Object> getHintsOfClass(Class<E> clazz) {
354 return hintCtx.getHintsOfClass(clazz);
358 public void removeHintListener(IHintListener listener) {
359 hintCtx.removeHintListener(listener);
363 public void removeHintListener(IThreadWorkQueue threadAccess,
364 IHintListener listener) {
365 hintCtx.removeHintListener(threadAccess, listener);
369 public void removeKeyHintListener(Key key, IHintListener listener) {
370 hintCtx.removeKeyHintListener(key, listener);
374 public void removeKeyHintListener(IThreadWorkQueue threadAccess, Key key,
375 IHintListener listener) {
376 hintCtx.removeKeyHintListener(threadAccess, key, listener);
380 public boolean bringToTop(IElement e) {
382 if (list.get(list.size()-1)==e) return false;
390 public boolean bringUp(IElement e) {
392 int i = list.indexOf(e);
393 if (i==list.size()-1) return false;
395 IElement upper = list.get(j);
403 public boolean sendDown(IElement e) {
405 int i = list.indexOf(e);
406 if (i==0) return false;
408 IElement lower = list.get(j);
416 public boolean sendToBottom(IElement e) {
418 if (list.get(0)==e) return false;
426 public boolean moveTo(IElement e, int position) {
428 int indexOf = list.indexOf(e);
429 if (indexOf==position) return false;
430 list.remove(indexOf);
431 list.add(position, e);
437 public List<IElement> getElements() {
438 return unmodifiableList;
442 public void sort(Comparator<IElement> comparator) {
443 Collections.sort(list, comparator);
446 @SuppressWarnings("rawtypes")
447 public Object getAdapter(Class adapter) {
448 for (DiagramAdapter ea : clazz.getItemsByClass(DiagramAdapter.class)) {
449 Object result = ea.getAdapter(this, adapter);