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