]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/events/ListenerList.java
Fixed multiple issues causing dangling references to discarded queries
[simantics/platform.git] / bundles / org.simantics.scenegraph / src / org / simantics / scenegraph / g2d / events / ListenerList.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *******************************************************************************/
12 /*
13  * 12.6.2007
14  */
15 package org.simantics.scenegraph.g2d.events;
16
17 import java.lang.reflect.Array;
18
19 import org.simantics.utils.threads.SyncListenerList;
20
21 /**
22  * ListenerList is an efficient and synchronized list of listeners.
23  * The class is optimized for quick getListeners and slow add/remove.
24  * 
25  * @see SyncListenerList for thread context switching listener list impl
26  * 
27  * @author Toni Kalajainen
28  * @param <T> 
29  */
30 public class ListenerList<T> {
31
32     /**
33      * Array of listeners
34      */
35     private volatile T [] array;
36
37     /** 
38      * The class of T
39      */
40     private final Class<T> componentType;
41
42     /**
43      * Construct new Listener List
44      * @param componentType the class of the listener type
45      */
46     public ListenerList(Class<T> componentType)
47     {
48         this.componentType = componentType;
49         array = createArray(0);
50     }
51
52     public T[] getListeners()
53     {
54         return array;
55     }
56
57     public synchronized void add(T listener)
58     {
59         int oldLength = array.length;
60         int newLength = oldLength + 1;
61         T newArray[] = createArray(newLength);
62         System.arraycopy(array, 0, newArray, 0, oldLength);
63         newArray[oldLength] = listener;
64         array = newArray;
65     }
66
67     /**
68      * Removes the first occurance of listener.
69      * If the listener is added multiple times, then it must be removed
70      * as many times.
71      * 
72      * @param listener a listener
73      * @return the listener that was removed from the list
74      */
75     public synchronized boolean remove(T listener)
76     {
77         int pos = getPos(listener);
78         if (pos<0) return false;
79
80         int oldLength = array.length;
81         int newLength = oldLength -1;
82         T newArray[] = createArray(newLength);
83
84         // Copy beginning
85         if (pos>0)
86             System.arraycopy(array, 0, newArray, 0, pos);
87
88         // Copy ending
89         if (pos<newLength)
90             System.arraycopy(array, pos+1, newArray, pos, newLength-pos);
91
92         array = newArray;
93         return true;
94     }
95
96     private synchronized int getPos(T listener)
97     {
98         for (int i=0; i<array.length; i++)
99             if (array[i] == listener)
100                 return i;
101         return -1;
102     }
103
104     public int size()
105     {
106         return array.length;
107     }
108
109     public boolean isEmpty()
110     {
111         return array.length == 0;
112     }
113
114     public void clear()
115     {
116         array = createArray(0);
117     }
118
119     @SuppressWarnings("unchecked")
120     private T[] createArray(int size)
121     {
122         return (T[]) Array.newInstance(componentType, size);
123     }
124
125 }