001    /*
002     * This file is part of muCommander, http://www.mucommander.com
003     * Copyright (C) 2002-2008 Maxence Bernard
004     *
005     * muCommander is free software; you can redistribute it and/or modify
006     * it under the terms of the GNU General Public License as published by
007     * the Free Software Foundation; either version 3 of the License, or
008     * (at your option) any later version.
009     *
010     * muCommander is distributed in the hope that it will be useful,
011     * but WITHOUT ANY WARRANTY; without even the implied warranty of
012     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013     * GNU General Public License for more details.
014     *
015     * You should have received a copy of the GNU General Public License
016     * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017     */
018    
019    package com.mucommander.util;
020    
021    import java.util.Collection;
022    import java.util.Iterator;
023    import java.util.Vector;
024    import java.util.WeakHashMap;
025    
026    /**
027     * AlteredVector is a Vector that is able to notify registered listeners whenever its contents has changed.
028     * <p>
029     * Events are triggered when:
030     * <ul>
031     * <li>one or more elements has been added
032     * <li>one or more elements has been removed
033     * <li>an element has been changed
034     * </ul>
035     * </p>
036     * <p>It is however not aware of modifications that are made to the contained objects themselves.</p>
037     *
038     * @author Maxence Bernard
039     */
040    public class AlteredVector extends Vector {
041    
042        /** Contains all registered listeners, stored as weak references */
043        private WeakHashMap listeners = new WeakHashMap();
044    
045    
046        public AlteredVector() {
047            super();
048        }
049    
050        public AlteredVector(Collection collection) {
051            super(collection);
052        }
053    
054        public AlteredVector(int initialCapacity, int capacityIncrement) {
055            super(initialCapacity, capacityIncrement);
056        }
057    
058        public AlteredVector(int initialCapacity) {
059            super(initialCapacity);
060        }
061    
062    
063        /**
064         * Adds the specified VectorChangeListener to the list of registered listeners.
065         *
066         * <p>Listeners are stored as weak references so {@link #removeVectorChangeListener(VectorChangeListener)}
067         * doesn't need to be called for listeners to be garbage collected when they're not used anymore.</p>
068         *
069         * @param listener the VectorChangeListener to add to the list of registered listeners.
070         * @see            #removeVectorChangeListener(VectorChangeListener)
071         */
072        public void addVectorChangeListener(VectorChangeListener listener) {
073            listeners.put(listener, null);
074        }
075    
076        /**
077         * Removes the specified VectorChangeListener from the list of registered listeners.
078         *
079         * @param listener the VectorChangeListener to remove from the list of registered listeners.
080         * @see            #addVectorChangeListener(VectorChangeListener)
081         */
082        public void removeVectorChangeListener(VectorChangeListener listener) {
083            listeners.remove(listener);
084        }
085    
086    
087        /**
088         * This method is called when one or more elements has been added to this AlteredVector to notify listeners.
089         *
090         * @param startIndex index at which the first element has been added
091         * @param nbAdded number of elements added
092         */
093        private void fireElementsAddedEvent(int startIndex, int nbAdded) {
094            Iterator iterator = listeners.keySet().iterator();
095            while(iterator.hasNext())
096                ((VectorChangeListener)iterator.next()).elementsAdded(startIndex, nbAdded);
097        }
098    
099        /**
100         * This method is called when one or more elements has been removed from this AlteredVector to notify listeners.
101         *
102         * @param startIndex index at which the first element has been removed
103         * @param nbRemoved number of elements removed
104         */
105        private void fireElementsRemovedEvent(int startIndex, int nbRemoved) {
106            Iterator iterator = listeners.keySet().iterator();
107            while(iterator.hasNext())
108                ((VectorChangeListener)iterator.next()).elementsRemoved(startIndex, nbRemoved);
109        }
110    
111        /**
112         * This method is called when an element has been changed in this AlteredVector to notify listeners.
113         *
114         * @param index index of the element that has been changed
115         */
116        private void fireElementChangedEvent(int index) {
117            Iterator iterator = listeners.keySet().iterator();
118            while(iterator.hasNext())
119                ((VectorChangeListener)iterator.next()).elementChanged(index);
120        }
121    
122    
123        ////////////////////////
124        // Overridden methods //
125        ////////////////////////
126    
127        public void setElementAt(Object o, int i) {
128            super.setElementAt(o, i);
129    
130            fireElementChangedEvent(i);
131        }
132    
133        public Object set(int i, Object o) {
134            o = super.set(i, o);
135    
136            fireElementChangedEvent(i);
137    
138            return o;
139        }
140    
141        public void insertElementAt(Object o, int i) {
142            super.insertElementAt(o, i);
143    
144            fireElementsAddedEvent(i, 1);
145        }
146    
147        public void add(int i, Object o) {
148            insertElementAt(o, i);
149    
150            fireElementsAddedEvent(i, 1);
151        }
152    
153        public void addElement(Object o) {
154            super.addElement(o);
155    
156            fireElementsAddedEvent(size()-1, 1);
157        }
158    
159        public boolean add(Object o) {
160            addElement(o);
161    
162            fireElementsAddedEvent(size()-1, 1);
163    
164            return true;
165        }
166    
167        public boolean addAll(Collection collection) {
168            int sizeBefore = size();
169    
170            boolean b = super.addAll(collection);
171    
172            fireElementsAddedEvent(sizeBefore, size()-sizeBefore);
173    
174            return b;
175        }
176    
177        public boolean addAll(int i, Collection collection) {
178            int sizeBefore = size();
179    
180            boolean b = super.addAll(i, collection);
181    
182            fireElementsAddedEvent(i, size()-sizeBefore);
183    
184            return b;
185        }
186    
187        public void removeElementAt(int i) {
188            super.removeElementAt(i);
189    
190            fireElementsRemovedEvent(i, 1);
191        }
192    
193        public Object remove(int i) {
194            Object o = super.remove(i);
195    
196            fireElementsRemovedEvent(i, 1);
197    
198            return o;
199        }
200    
201        public boolean removeElement(Object o) {
202            int index = indexOf(o);
203    
204            if(index==-1)
205                return false;
206    
207            removeElementAt(index);
208    
209            return true;
210        }
211    
212        public boolean remove(Object o) {
213            return removeElement(o);
214        }
215    
216        public void removeAllElements() {
217            int sizeBefore = size();
218    
219            super.removeAllElements();
220    
221            fireElementsRemovedEvent(0, sizeBefore);
222        }
223    
224        public void clear() {
225            removeAllElements();
226        }
227    }