001 package users.swing;
002
003 import javax.swing.*;
004
005 import java.util.*;
006
007 import users.*;
008 import users.events.*;
009
010 import util.*;
011
012 /**
013 * A ListModel modelling the set or a subset of users managed by a UserManager.
014 *
015 * @see UserManager
016 * @see User
017 *
018 * @author Steffen Zschaler
019 * @version 2.0 05/05/1999
020 * @since v2.0
021 */
022 public class UserListModel extends AbstractListModel implements UserDataListener, HelpableListener {
023
024 /**
025 * ID for serialization.
026 */
027 private static final long serialVersionUID = -4843733101582107151L;
028
029 /**
030 * A local copy of the list of users to provide easy and consistent access via an
031 * index.
032 *
033 * This model is kept up to date by registering as a listener with the UserManager.
034 *
035 * @serial
036 */
037 protected List<User> m_lUsers;
038
039 /**
040 * A Comparator that orders the users. By default, users are ordered by their name.
041 *
042 * @serial
043 */
044 protected Comparator<User> m_cmpComparator = new SerializableComparator<User>() {
045 private static final long serialVersionUID = -750125937466643557L;
046 public int compare(User u1, User u2) {
047 return u1.getName().compareTo(u2.getName());
048 }
049 };
050
051 /**
052 * A filter that defines the subset of users that are displayed. If <code>null</code> no
053 * filtering will occur.
054 *
055 * @serial
056 */
057 protected UserFilter m_ufFilter;
058
059 /**
060 * The UserManager that is being modelled.
061 *
062 * @serial
063 */
064 protected UserManager m_um;
065
066 /**
067 * Create a new UserListModel modelling the global UserManager. All Users will be displayed and they will be
068 * sorted by their names.
069 */
070 public UserListModel() {
071 this(UserManager.getGlobalUM());
072 }
073
074 /**
075 * Create a new UserListModel modelling the global UserManager.
076 *
077 * @param uf a filter that defines the set of users to be displayed. If <code>null</code>, no filtering will
078 * occur.
079 * @param cmp a Comparator that defines the order of the users to be displayed. The objects to be compared
080 * by this comparator will be Users. If <code>null</code>, users will be ordered by their names.
081 */
082 public UserListModel(UserFilter uf, Comparator<User> cmp) {
083 this(UserManager.getGlobalUM(), uf, cmp);
084 }
085
086 /**
087 * Create a new UserListModel modelling a given UserManager. All Users will be displayed and they will be
088 * sorted by their names.
089 *
090 * @param um the UserManager to be modelled.
091 */
092 public UserListModel(UserManager um) {
093 this(um, null, null);
094 }
095
096 /**
097 * Create a new UserListModel modelling a given UserManager.
098 *
099 * @param um the UserManager to be modelled.
100 * @param uf a filter that defines the set of users to be displayed. If <code>null</code>, no filtering will
101 * occur.
102 * @param cmp a Comparator that defines the order of the users to be displayed. The objects to be compared
103 * by this comparator will be Users. If <code>null</code>, users will be ordered by their names.
104 */
105 public UserListModel(UserManager um, UserFilter uf, Comparator<User> cmp) {
106 super();
107
108 // replace listener list for special support
109 listenerList = new ListenerHelper(this);
110
111 m_um = um;
112 m_ufFilter = uf;
113
114 if (cmp != null) {
115 m_cmpComparator = cmp;
116 }
117
118 updateModel();
119 }
120
121 // List Model methods
122
123 /**
124 * Return the number of users in the model.
125 *
126 * @return the number of users in the model.
127 *
128 * @override Never
129 */
130 public int getSize() {
131 // make sure internal model is up to date.
132 ((ListenerHelper)listenerList).needModelUpdate();
133
134 return m_lUsers.size();
135 }
136
137 /**
138 * Get a user by index.
139 *
140 * @param nIndex the index of the user to be returned.
141 *
142 * @return the user associated with the given index.
143 *
144 * @override Never
145 */
146 public Object getElementAt(int nIndex) {
147 // make sure internal model is up to date.
148 ((ListenerHelper)listenerList).needModelUpdate();
149
150 return m_lUsers.get(nIndex);
151 }
152
153 // UserDataListener methods
154
155 /**
156 * Respond to the <code>userAdded</code> event by updating the internal model
157 * and forwarding a translated version of the event to anyone who listens to us.
158 *
159 * @param e the event object describing the event.
160 *
161 * @override Sometimes
162 */
163 public void userAdded(UserDataEvent e) {
164 updateModel();
165
166 int nPos = m_lUsers.indexOf(e.getUser());
167
168 if (nPos > -1) {
169 fireIntervalAdded(this, nPos, nPos);
170 }
171 }
172
173 /**
174 * Respond to the <code>userDeleted</code> event by updating the internal model
175 * and forwarding a translated version of the event to anyone who listens to us.
176 *
177 * @param e the event object describing the event.
178 *
179 * @override Sometimes
180 */
181 public void userDeleted(UserDataEvent e) {
182 int nPos = m_lUsers.indexOf(e.getUser());
183
184 updateModel();
185
186 if (nPos > -1) {
187 fireIntervalRemoved(this, nPos, nPos);
188 }
189 }
190
191 // HelpableListener methods
192 /**
193 * Update the internal model.
194 *
195 * @override Sometimes
196 */
197 public synchronized void updateModel() {
198 List<User> lUsers = new LinkedList<User>(m_um.getUsers());
199
200 if (m_ufFilter != null) {
201 for (Iterator<User> i = lUsers.iterator(); i.hasNext(); ) {
202 if (!m_ufFilter.match(i.next())) {
203 i.remove();
204 }
205 }
206 }
207
208 Collections.sort(lUsers, m_cmpComparator);
209
210 m_lUsers = lUsers;
211 }
212
213 /**
214 * Subscribe to the UserManager to be informed of any changes in its set of users.
215 *
216 * @override Never
217 */
218 public void subscribe() {
219 m_um.addUserDataListener(this);
220 }
221
222 /**
223 * Unsubscribe from the UserManager as there is no need to listen to it anymore, as
224 * we are not listened to anymore. From now on we are working in "poll-mode" until
225 * any listener indicates an interest in us again.
226 *
227 * @override Never
228 */
229 public void unsubscribe() {
230 m_um.removeUserDataListener(this);
231 }
232 }