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    }