View Javadoc
1 /* 2 * Copyright (c) 2003 Scott Howlett & Paul Libbrecht. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * 17 * 3. The end-user documentation included with the redistribution, 18 * if any, must include the following acknowledgment: 19 * "This product includes software developed by the Xwing 20 * Project ( http://xwing.sourceforge.net/ )." 21 * Alternately, this acknowledgment may appear in the software itself, 22 * if and wherever such third-party acknowledgments normally appear. 23 * 24 * 4. The name "Xwing" must not be used to endorse or promote products 25 * derived from this software without prior written permission. For 26 * written permission, please contact the project authors via 27 * the Xwing project site, http://xwing.sourceforge.net/ . 28 * 29 * 5. Products derived from this software may not be called "Xwing", 30 * nor may "Xwing" appear in their name, without prior written 31 * permission of the Xwing project. 32 * 33 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 34 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 35 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 36 * DISCLAIMED. IN NO EVENT SHALL THE XWING AUTHORS OR THE PROJECT 37 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 38 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 39 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 40 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 41 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 42 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 43 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44 * SUCH DAMAGE. 45 * 46 * For more information on Xwing, please see 47 * < http://xwing.sourceforge.net/ >. 48 */ 49 50 package net.sourceforge.xwing; 51 52 import java.util.Vector; 53 54 import javax.swing.AbstractListModel; 55 import javax.swing.DefaultListModel; 56 import javax.swing.ListModel; 57 import javax.swing.event.ListDataEvent; 58 import javax.swing.event.ListDataListener; 59 60 /*** 61 * A ListModel that acts as an aggregation of 62 * other ListModel instances. 63 * 64 * Access requests are translated into the corresponding access requests 65 * for the appripriate backingListModel, and change events from a backing 66 * ListModel are similarly translated and propagated to this model's 67 * listeners. 68 * 69 * @author Scott Howlett 70 * @version $Revision: 1.2 $ 71 */ 72 public class AggregatingListModel extends AbstractListModel { 73 74 /*** 75 * The models that form the backing storage for this model. 76 */ 77 private Vector models; 78 79 /*** 80 * A cached count of the total size of all contained models. 81 */ 82 private int totalSize; 83 84 /*** 85 * The listener that is registered with all the backing 86 * models. 87 */ 88 private ListDataListener listener; 89 90 /*** 91 * An internally-created ListModel that allows a client to 92 * add individual members to us. 93 */ 94 private DefaultListModel curTail; 95 96 /*** 97 * Make a new AggregatingListModel. 98 */ 99 public AggregatingListModel() { 100 models = new Vector(); 101 totalSize = 0; 102 listener = new ListDataListener() { 103 104 public void contentsChanged(ListDataEvent e) { 105 totalSize = calcTotalSize(); 106 107 int start = e.getIndex0(); 108 int finish = e.getIndex1(); 109 110 int idx = 0; 111 if (start != -1 || finish != -1) { 112 idx = getStartIndex((ListModel) e.getSource()); 113 } 114 if (start != -1) { 115 start += idx; 116 } 117 if (finish != -1) { 118 finish += idx; 119 } 120 fireContentsChanged(AggregatingListModel.this, start, finish); 121 } 122 123 public void intervalAdded(ListDataEvent e) { 124 totalSize += (e.getIndex1() - e.getIndex0() + 1); 125 int idx = getStartIndex((ListModel) e.getSource()); 126 fireIntervalAdded( 127 AggregatingListModel.this, 128 e.getIndex0() + idx, 129 e.getIndex1() + idx); 130 } 131 132 public void intervalRemoved(ListDataEvent e) { 133 totalSize -= (e.getIndex1() - e.getIndex0() + 1); 134 int idx = getStartIndex((ListModel) e.getSource()); 135 fireIntervalRemoved( 136 AggregatingListModel.this, 137 e.getIndex0() + idx, 138 e.getIndex1() + idx); 139 } 140 141 }; 142 } 143 144 /* (non-javadoc) 145 * @see javax.swing.ListModel#getSize() 146 */ 147 public int getSize() { 148 return totalSize; 149 } 150 151 /* (non-javadoc) 152 * @see javax.swing.ListModel#getElementAt(int) 153 */ 154 public Object getElementAt(int index) { 155 int curVecStart = 0; 156 int curVecEnd = 0; 157 158 for (int i = 0; i < models.size(); ++i) { 159 curVecStart = curVecEnd; 160 ListModel model = (ListModel) models.get(i); 161 curVecEnd += model.getSize(); 162 if (curVecEnd > index) { 163 return model.getElementAt(index - curVecStart); 164 } 165 } 166 return null; 167 } 168 169 /*** 170 * Appends the given ListModel onto the end of our list 171 * of models. If the added ListModel contains any elements, 172 * a ListDataEvent of type <code>INTERVAL_ADDED</code> will 173 * be broadcast to any active listeners. 174 * 175 * @param src the model to add 176 */ 177 public void addListModel(ListModel src) { 178 addListModel(models.size(), src); 179 } 180 181 /*** 182 * Inserts the given ListModel into our list 183 * of models. If the added ListModel contains any elements, 184 * a ListDataEvent of type <code>INTERVAL_ADDED</code> will 185 * be broadcast to any active listeners. 186 * 187 * @param index Where in our list of models to insert the 188 * model. 189 * @param src the model to add 190 */ 191 public void addListModel(int index, ListModel src) { 192 if (index >= models.size()) { 193 curTail = null; 194 } 195 models.add(index, src); 196 src.addListDataListener(listener); 197 198 int srcSize = src.getSize(); 199 totalSize += srcSize; 200 201 if (srcSize > 0) { 202 int start = getStartIndex(src); 203 fireIntervalAdded(this, start, start + srcSize - 1); 204 } 205 } 206 207 /*** 208 * Adds a single element to the end of our list of models. 209 * All elements added via addElement() 210 * are actually added to an internally maintained ListModel. 211 * If multiple elements are added in a series, they will all 212 * be added to the same internal ListModel. But if another 213 * ListModel is added via addListModel(), the next time an 214 * element is added a new ListModel will be created and appended 215 * to our list of models. 216 */ 217 public void addElement(Object element) { 218 if (curTail == null) { 219 DefaultListModel lm = new DefaultListModel(); 220 addListModel(lm); 221 curTail = lm; 222 } 223 curTail.addElement(element); 224 } 225 226 /*** 227 * Remove all our contents. 228 */ 229 public void clear() { 230 int oldSize = totalSize; 231 232 for (int i = 0; i < models.size(); ++i) { 233 ((ListModel) models.get(i)).removeListDataListener(listener); 234 } 235 models.clear(); 236 totalSize = 0; 237 238 if (oldSize > 0) { 239 fireIntervalRemoved(this, 0, oldSize - 1); 240 } 241 } 242 243 /*** 244 * Calculates the virtual start index of the first element 245 * of the given model. 246 */ 247 private int getStartIndex(ListModel model) { 248 int result = 0; 249 for (int i = 0; i < models.size(); ++i) { 250 ListModel m = (ListModel) models.get(i); 251 if (model == m) { 252 break; 253 } 254 result += m.getSize(); 255 } 256 return result; 257 } 258 259 /*** 260 * Calculates the total size of the given model. 261 */ 262 private int calcTotalSize() { 263 int result = 0; 264 for (int i = 0; i < models.size(); ++i) { 265 ListModel m = (ListModel) models.get(i); 266 result += m.getSize(); 267 } 268 return result; 269 } 270 }

This page was automatically generated by Maven