author | never |
Mon, 12 Jul 2010 22:27:18 -0700 | |
changeset 5926 | a36f90d986b6 |
parent 5506 | 202f599c92aa |
child 11268 | f0e59c4852de |
permissions | -rw-r--r-- |
2 | 1 |
/* |
5506 | 2 |
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. |
2 | 3 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 |
* |
|
5 |
* This code is free software; you can redistribute it and/or modify it |
|
6 |
* under the terms of the GNU General Public License version 2 only, as |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 10 |
* |
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
5506 | 21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
2 | 24 |
*/ |
25 |
||
26 |
package javax.swing.tree; |
|
27 |
||
28 |
import java.beans.PropertyChangeListener; |
|
29 |
import java.io.*; |
|
30 |
import java.util.ArrayList; |
|
31 |
import java.util.BitSet; |
|
32 |
import java.util.Enumeration; |
|
33 |
import java.util.EventListener; |
|
34 |
import java.util.Hashtable; |
|
35 |
import java.util.List; |
|
36 |
import java.util.Vector; |
|
37 |
import javax.swing.event.*; |
|
38 |
import javax.swing.DefaultListSelectionModel; |
|
39 |
||
40 |
/** |
|
41 |
* Default implementation of TreeSelectionModel. Listeners are notified |
|
42 |
* whenever |
|
43 |
* the paths in the selection change, not the rows. In order |
|
44 |
* to be able to track row changes you may wish to become a listener |
|
45 |
* for expansion events on the tree and test for changes from there. |
|
46 |
* <p>resetRowSelection is called from any of the methods that update |
|
47 |
* the selected paths. If you subclass any of these methods to |
|
48 |
* filter what is allowed to be selected, be sure and message |
|
49 |
* <code>resetRowSelection</code> if you do not message super. |
|
50 |
* |
|
51 |
* <strong>Warning:</strong> |
|
52 |
* Serialized objects of this class will not be compatible with |
|
53 |
* future Swing releases. The current serialization support is |
|
54 |
* appropriate for short term storage or RMI between applications running |
|
55 |
* the same version of Swing. As of 1.4, support for long term storage |
|
56 |
* of all JavaBeans<sup><font size="-2">TM</font></sup> |
|
57 |
* has been added to the <code>java.beans</code> package. |
|
58 |
* Please see {@link java.beans.XMLEncoder}. |
|
59 |
* |
|
60 |
* @see javax.swing.JTree |
|
61 |
* |
|
62 |
* @author Scott Violet |
|
63 |
*/ |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
64 |
public class DefaultTreeSelectionModel implements Cloneable, Serializable, TreeSelectionModel |
2 | 65 |
{ |
66 |
/** Property name for selectionMode. */ |
|
67 |
public static final String SELECTION_MODE_PROPERTY = "selectionMode"; |
|
68 |
||
69 |
/** Used to messaged registered listeners. */ |
|
70 |
protected SwingPropertyChangeSupport changeSupport; |
|
71 |
||
72 |
/** Paths that are currently selected. Will be null if nothing is |
|
73 |
* currently selected. */ |
|
74 |
protected TreePath[] selection; |
|
75 |
||
76 |
/** Event listener list. */ |
|
77 |
protected EventListenerList listenerList = new EventListenerList(); |
|
78 |
||
79 |
/** Provides a row for a given path. */ |
|
80 |
transient protected RowMapper rowMapper; |
|
81 |
||
82 |
/** Handles maintaining the list selection model. The RowMapper is used |
|
83 |
* to map from a TreePath to a row, and the value is then placed here. */ |
|
84 |
protected DefaultListSelectionModel listSelectionModel; |
|
85 |
||
86 |
/** Mode for the selection, will be either SINGLE_TREE_SELECTION, |
|
87 |
* CONTIGUOUS_TREE_SELECTION or DISCONTIGUOUS_TREE_SELECTION. |
|
88 |
*/ |
|
89 |
protected int selectionMode; |
|
90 |
||
91 |
/** Last path that was added. */ |
|
92 |
protected TreePath leadPath; |
|
93 |
/** Index of the lead path in selection. */ |
|
94 |
protected int leadIndex; |
|
95 |
/** Lead row. */ |
|
96 |
protected int leadRow; |
|
97 |
||
98 |
/** Used to make sure the paths are unique, will contain all the paths |
|
99 |
* in <code>selection</code>. |
|
100 |
*/ |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
101 |
private Hashtable<TreePath, Boolean> uniquePaths; |
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
102 |
private Hashtable<TreePath, Boolean> lastPaths; |
2 | 103 |
private TreePath[] tempPaths; |
104 |
||
105 |
||
106 |
/** |
|
107 |
* Creates a new instance of DefaultTreeSelectionModel that is |
|
108 |
* empty, with a selection mode of DISCONTIGUOUS_TREE_SELECTION. |
|
109 |
*/ |
|
110 |
public DefaultTreeSelectionModel() { |
|
111 |
listSelectionModel = new DefaultListSelectionModel(); |
|
112 |
selectionMode = DISCONTIGUOUS_TREE_SELECTION; |
|
113 |
leadIndex = leadRow = -1; |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
114 |
uniquePaths = new Hashtable<TreePath, Boolean>(); |
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
115 |
lastPaths = new Hashtable<TreePath, Boolean>(); |
2 | 116 |
tempPaths = new TreePath[1]; |
117 |
} |
|
118 |
||
119 |
/** |
|
120 |
* Sets the RowMapper instance. This instance is used to determine |
|
121 |
* the row for a particular TreePath. |
|
122 |
*/ |
|
123 |
public void setRowMapper(RowMapper newMapper) { |
|
124 |
rowMapper = newMapper; |
|
125 |
resetRowSelection(); |
|
126 |
} |
|
127 |
||
128 |
/** |
|
129 |
* Returns the RowMapper instance that is able to map a TreePath to a |
|
130 |
* row. |
|
131 |
*/ |
|
132 |
public RowMapper getRowMapper() { |
|
133 |
return rowMapper; |
|
134 |
} |
|
135 |
||
136 |
/** |
|
137 |
* Sets the selection model, which must be one of SINGLE_TREE_SELECTION, |
|
138 |
* CONTIGUOUS_TREE_SELECTION or DISCONTIGUOUS_TREE_SELECTION. If mode |
|
139 |
* is not one of the defined value, |
|
140 |
* <code>DISCONTIGUOUS_TREE_SELECTION</code> is assumed. |
|
141 |
* <p>This may change the selection if the current selection is not valid |
|
142 |
* for the new mode. For example, if three TreePaths are |
|
143 |
* selected when the mode is changed to <code>SINGLE_TREE_SELECTION</code>, |
|
144 |
* only one TreePath will remain selected. It is up to the particular |
|
145 |
* implementation to decide what TreePath remains selected. |
|
146 |
* <p> |
|
147 |
* Setting the mode to something other than the defined types will |
|
148 |
* result in the mode becoming <code>DISCONTIGUOUS_TREE_SELECTION</code>. |
|
149 |
*/ |
|
150 |
public void setSelectionMode(int mode) { |
|
151 |
int oldMode = selectionMode; |
|
152 |
||
153 |
selectionMode = mode; |
|
154 |
if(selectionMode != TreeSelectionModel.SINGLE_TREE_SELECTION && |
|
155 |
selectionMode != TreeSelectionModel.CONTIGUOUS_TREE_SELECTION && |
|
156 |
selectionMode != TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) |
|
157 |
selectionMode = TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION; |
|
158 |
if(oldMode != selectionMode && changeSupport != null) |
|
159 |
changeSupport.firePropertyChange(SELECTION_MODE_PROPERTY, |
|
438
2ae294e4518c
6613529: Avoid duplicate object creation within JDK packages
dav
parents:
2
diff
changeset
|
160 |
Integer.valueOf(oldMode), |
2ae294e4518c
6613529: Avoid duplicate object creation within JDK packages
dav
parents:
2
diff
changeset
|
161 |
Integer.valueOf(selectionMode)); |
2 | 162 |
} |
163 |
||
164 |
/** |
|
165 |
* Returns the selection mode, one of <code>SINGLE_TREE_SELECTION</code>, |
|
166 |
* <code>DISCONTIGUOUS_TREE_SELECTION</code> or |
|
167 |
* <code>CONTIGUOUS_TREE_SELECTION</code>. |
|
168 |
*/ |
|
169 |
public int getSelectionMode() { |
|
170 |
return selectionMode; |
|
171 |
} |
|
172 |
||
173 |
/** |
|
174 |
* Sets the selection to path. If this represents a change, then |
|
175 |
* the TreeSelectionListeners are notified. If <code>path</code> is |
|
176 |
* null, this has the same effect as invoking <code>clearSelection</code>. |
|
177 |
* |
|
178 |
* @param path new path to select |
|
179 |
*/ |
|
180 |
public void setSelectionPath(TreePath path) { |
|
181 |
if(path == null) |
|
182 |
setSelectionPaths(null); |
|
183 |
else { |
|
184 |
TreePath[] newPaths = new TreePath[1]; |
|
185 |
||
186 |
newPaths[0] = path; |
|
187 |
setSelectionPaths(newPaths); |
|
188 |
} |
|
189 |
} |
|
190 |
||
191 |
/** |
|
192 |
* Sets the selection. Whether the supplied paths are taken as the |
|
193 |
* new selection depends upon the selection mode. If the supplied |
|
194 |
* array is {@code null}, or empty, the selection is cleared. If |
|
195 |
* the selection mode is {@code SINGLE_TREE_SELECTION}, only the |
|
196 |
* first path in {@code pPaths} is used. If the selection |
|
197 |
* mode is {@code CONTIGUOUS_TREE_SELECTION} and the supplied paths |
|
198 |
* are not contiguous, then only the first path in {@code pPaths} is |
|
199 |
* used. If the selection mode is |
|
200 |
* {@code DISCONTIGUOUS_TREE_SELECTION}, then all paths are used. |
|
201 |
* <p> |
|
202 |
* All {@code null} paths in {@code pPaths} are ignored. |
|
203 |
* <p> |
|
204 |
* If this represents a change, all registered {@code |
|
205 |
* TreeSelectionListener}s are notified. |
|
206 |
* <p> |
|
207 |
* The lead path is set to the last unique path. |
|
208 |
* <p> |
|
209 |
* The paths returned from {@code getSelectionPaths} are in the same |
|
210 |
* order as those supplied to this method. |
|
211 |
* |
|
212 |
* @param pPaths the new selection |
|
213 |
*/ |
|
214 |
public void setSelectionPaths(TreePath[] pPaths) { |
|
215 |
int newCount, newCounter, oldCount, oldCounter; |
|
216 |
TreePath[] paths = pPaths; |
|
217 |
||
218 |
if(paths == null) |
|
219 |
newCount = 0; |
|
220 |
else |
|
221 |
newCount = paths.length; |
|
222 |
if(selection == null) |
|
223 |
oldCount = 0; |
|
224 |
else |
|
225 |
oldCount = selection.length; |
|
226 |
if((newCount + oldCount) != 0) { |
|
227 |
if(selectionMode == TreeSelectionModel.SINGLE_TREE_SELECTION) { |
|
228 |
/* If single selection and more than one path, only allow |
|
229 |
first. */ |
|
230 |
if(newCount > 1) { |
|
231 |
paths = new TreePath[1]; |
|
232 |
paths[0] = pPaths[0]; |
|
233 |
newCount = 1; |
|
234 |
} |
|
235 |
} |
|
236 |
else if(selectionMode == |
|
237 |
TreeSelectionModel.CONTIGUOUS_TREE_SELECTION) { |
|
238 |
/* If contiguous selection and paths aren't contiguous, |
|
239 |
only select the first path item. */ |
|
240 |
if(newCount > 0 && !arePathsContiguous(paths)) { |
|
241 |
paths = new TreePath[1]; |
|
242 |
paths[0] = pPaths[0]; |
|
243 |
newCount = 1; |
|
244 |
} |
|
245 |
} |
|
246 |
||
247 |
TreePath beginLeadPath = leadPath; |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
248 |
Vector<PathPlaceHolder> cPaths = new Vector<PathPlaceHolder>(newCount + oldCount); |
2 | 249 |
List<TreePath> newSelectionAsList = |
250 |
new ArrayList<TreePath>(newCount); |
|
251 |
||
252 |
lastPaths.clear(); |
|
253 |
leadPath = null; |
|
254 |
/* Find the paths that are new. */ |
|
255 |
for(newCounter = 0; newCounter < newCount; newCounter++) { |
|
256 |
TreePath path = paths[newCounter]; |
|
257 |
if (path != null && lastPaths.get(path) == null) { |
|
258 |
lastPaths.put(path, Boolean.TRUE); |
|
259 |
if (uniquePaths.get(path) == null) { |
|
260 |
cPaths.addElement(new PathPlaceHolder(path, true)); |
|
261 |
} |
|
262 |
leadPath = path; |
|
263 |
newSelectionAsList.add(path); |
|
264 |
} |
|
265 |
} |
|
266 |
||
267 |
TreePath[] newSelection = newSelectionAsList.toArray( |
|
268 |
new TreePath[newSelectionAsList.size()]); |
|
269 |
||
270 |
/* Get the paths that were selected but no longer selected. */ |
|
271 |
for(oldCounter = 0; oldCounter < oldCount; oldCounter++) |
|
272 |
if(selection[oldCounter] != null && |
|
273 |
lastPaths.get(selection[oldCounter]) == null) |
|
274 |
cPaths.addElement(new PathPlaceHolder |
|
275 |
(selection[oldCounter], false)); |
|
276 |
||
277 |
selection = newSelection; |
|
278 |
||
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
279 |
Hashtable<TreePath, Boolean> tempHT = uniquePaths; |
2 | 280 |
|
281 |
uniquePaths = lastPaths; |
|
282 |
lastPaths = tempHT; |
|
283 |
lastPaths.clear(); |
|
284 |
||
285 |
// No reason to do this now, but will still call it. |
|
286 |
insureUniqueness(); |
|
287 |
||
288 |
updateLeadIndex(); |
|
289 |
||
290 |
resetRowSelection(); |
|
291 |
/* Notify of the change. */ |
|
292 |
if(cPaths.size() > 0) |
|
293 |
notifyPathChange(cPaths, beginLeadPath); |
|
294 |
} |
|
295 |
} |
|
296 |
||
297 |
/** |
|
298 |
* Adds path to the current selection. If path is not currently |
|
299 |
* in the selection the TreeSelectionListeners are notified. This has |
|
300 |
* no effect if <code>path</code> is null. |
|
301 |
* |
|
302 |
* @param path the new path to add to the current selection |
|
303 |
*/ |
|
304 |
public void addSelectionPath(TreePath path) { |
|
305 |
if(path != null) { |
|
306 |
TreePath[] toAdd = new TreePath[1]; |
|
307 |
||
308 |
toAdd[0] = path; |
|
309 |
addSelectionPaths(toAdd); |
|
310 |
} |
|
311 |
} |
|
312 |
||
313 |
/** |
|
314 |
* Adds paths to the current selection. If any of the paths in |
|
315 |
* paths are not currently in the selection the TreeSelectionListeners |
|
316 |
* are notified. This has |
|
317 |
* no effect if <code>paths</code> is null. |
|
318 |
* <p>The lead path is set to the last element in <code>paths</code>. |
|
319 |
* <p>If the selection mode is <code>CONTIGUOUS_TREE_SELECTION</code>, |
|
320 |
* and adding the new paths would make the selection discontiguous. |
|
321 |
* Then two things can result: if the TreePaths in <code>paths</code> |
|
322 |
* are contiguous, then the selection becomes these TreePaths, |
|
323 |
* otherwise the TreePaths aren't contiguous and the selection becomes |
|
324 |
* the first TreePath in <code>paths</code>. |
|
325 |
* |
|
326 |
* @param paths the new path to add to the current selection |
|
327 |
*/ |
|
328 |
public void addSelectionPaths(TreePath[] paths) { |
|
329 |
int newPathLength = ((paths == null) ? 0 : paths.length); |
|
330 |
||
331 |
if(newPathLength > 0) { |
|
332 |
if(selectionMode == TreeSelectionModel.SINGLE_TREE_SELECTION) { |
|
333 |
setSelectionPaths(paths); |
|
334 |
} |
|
335 |
else if(selectionMode == TreeSelectionModel. |
|
336 |
CONTIGUOUS_TREE_SELECTION && !canPathsBeAdded(paths)) { |
|
337 |
if(arePathsContiguous(paths)) { |
|
338 |
setSelectionPaths(paths); |
|
339 |
} |
|
340 |
else { |
|
341 |
TreePath[] newPaths = new TreePath[1]; |
|
342 |
||
343 |
newPaths[0] = paths[0]; |
|
344 |
setSelectionPaths(newPaths); |
|
345 |
} |
|
346 |
} |
|
347 |
else { |
|
348 |
int counter, validCount; |
|
349 |
int oldCount; |
|
350 |
TreePath beginLeadPath = leadPath; |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
351 |
Vector<PathPlaceHolder> cPaths = null; |
2 | 352 |
|
353 |
if(selection == null) |
|
354 |
oldCount = 0; |
|
355 |
else |
|
356 |
oldCount = selection.length; |
|
357 |
/* Determine the paths that aren't currently in the |
|
358 |
selection. */ |
|
359 |
lastPaths.clear(); |
|
360 |
for(counter = 0, validCount = 0; counter < newPathLength; |
|
361 |
counter++) { |
|
362 |
if(paths[counter] != null) { |
|
363 |
if (uniquePaths.get(paths[counter]) == null) { |
|
364 |
validCount++; |
|
365 |
if(cPaths == null) |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
366 |
cPaths = new Vector<PathPlaceHolder>(); |
2 | 367 |
cPaths.addElement(new PathPlaceHolder |
368 |
(paths[counter], true)); |
|
369 |
uniquePaths.put(paths[counter], Boolean.TRUE); |
|
370 |
lastPaths.put(paths[counter], Boolean.TRUE); |
|
371 |
} |
|
372 |
leadPath = paths[counter]; |
|
373 |
} |
|
374 |
} |
|
375 |
||
376 |
if(leadPath == null) { |
|
377 |
leadPath = beginLeadPath; |
|
378 |
} |
|
379 |
||
380 |
if(validCount > 0) { |
|
381 |
TreePath newSelection[] = new TreePath[oldCount + |
|
382 |
validCount]; |
|
383 |
||
384 |
/* And build the new selection. */ |
|
385 |
if(oldCount > 0) |
|
386 |
System.arraycopy(selection, 0, newSelection, 0, |
|
387 |
oldCount); |
|
388 |
if(validCount != paths.length) { |
|
389 |
/* Some of the paths in paths are already in |
|
390 |
the selection. */ |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
391 |
Enumeration<TreePath> newPaths = lastPaths.keys(); |
2 | 392 |
|
393 |
counter = oldCount; |
|
394 |
while (newPaths.hasMoreElements()) { |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
395 |
newSelection[counter++] = newPaths.nextElement(); |
2 | 396 |
} |
397 |
} |
|
398 |
else { |
|
399 |
System.arraycopy(paths, 0, newSelection, oldCount, |
|
400 |
validCount); |
|
401 |
} |
|
402 |
||
403 |
selection = newSelection; |
|
404 |
||
405 |
insureUniqueness(); |
|
406 |
||
407 |
updateLeadIndex(); |
|
408 |
||
409 |
resetRowSelection(); |
|
410 |
||
411 |
notifyPathChange(cPaths, beginLeadPath); |
|
412 |
} |
|
413 |
else |
|
414 |
leadPath = beginLeadPath; |
|
415 |
lastPaths.clear(); |
|
416 |
} |
|
417 |
} |
|
418 |
} |
|
419 |
||
420 |
/** |
|
421 |
* Removes path from the selection. If path is in the selection |
|
422 |
* The TreeSelectionListeners are notified. This has no effect if |
|
423 |
* <code>path</code> is null. |
|
424 |
* |
|
425 |
* @param path the path to remove from the selection |
|
426 |
*/ |
|
427 |
public void removeSelectionPath(TreePath path) { |
|
428 |
if(path != null) { |
|
429 |
TreePath[] rPath = new TreePath[1]; |
|
430 |
||
431 |
rPath[0] = path; |
|
432 |
removeSelectionPaths(rPath); |
|
433 |
} |
|
434 |
} |
|
435 |
||
436 |
/** |
|
437 |
* Removes paths from the selection. If any of the paths in paths |
|
438 |
* are in the selection the TreeSelectionListeners are notified. |
|
439 |
* This has no effect if <code>paths</code> is null. |
|
440 |
* |
|
441 |
* @param paths the paths to remove from the selection |
|
442 |
*/ |
|
443 |
public void removeSelectionPaths(TreePath[] paths) { |
|
444 |
if (paths != null && selection != null && paths.length > 0) { |
|
445 |
if(!canPathsBeRemoved(paths)) { |
|
446 |
/* Could probably do something more interesting here! */ |
|
447 |
clearSelection(); |
|
448 |
} |
|
449 |
else { |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
450 |
Vector<PathPlaceHolder> pathsToRemove = null; |
2 | 451 |
|
452 |
/* Find the paths that can be removed. */ |
|
453 |
for (int removeCounter = paths.length - 1; removeCounter >= 0; |
|
454 |
removeCounter--) { |
|
455 |
if(paths[removeCounter] != null) { |
|
456 |
if (uniquePaths.get(paths[removeCounter]) != null) { |
|
457 |
if(pathsToRemove == null) |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
458 |
pathsToRemove = new Vector<PathPlaceHolder>(paths.length); |
2 | 459 |
uniquePaths.remove(paths[removeCounter]); |
460 |
pathsToRemove.addElement(new PathPlaceHolder |
|
461 |
(paths[removeCounter], false)); |
|
462 |
} |
|
463 |
} |
|
464 |
} |
|
465 |
if(pathsToRemove != null) { |
|
466 |
int removeCount = pathsToRemove.size(); |
|
467 |
TreePath beginLeadPath = leadPath; |
|
468 |
||
469 |
if(removeCount == selection.length) { |
|
470 |
selection = null; |
|
471 |
} |
|
472 |
else { |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
473 |
Enumeration<TreePath> pEnum = uniquePaths.keys(); |
2 | 474 |
int validCount = 0; |
475 |
||
476 |
selection = new TreePath[selection.length - |
|
477 |
removeCount]; |
|
478 |
while (pEnum.hasMoreElements()) { |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
479 |
selection[validCount++] = pEnum.nextElement(); |
2 | 480 |
} |
481 |
} |
|
482 |
if (leadPath != null && |
|
483 |
uniquePaths.get(leadPath) == null) { |
|
484 |
if (selection != null) { |
|
485 |
leadPath = selection[selection.length - 1]; |
|
486 |
} |
|
487 |
else { |
|
488 |
leadPath = null; |
|
489 |
} |
|
490 |
} |
|
491 |
else if (selection != null) { |
|
492 |
leadPath = selection[selection.length - 1]; |
|
493 |
} |
|
494 |
else { |
|
495 |
leadPath = null; |
|
496 |
} |
|
497 |
updateLeadIndex(); |
|
498 |
||
499 |
resetRowSelection(); |
|
500 |
||
501 |
notifyPathChange(pathsToRemove, beginLeadPath); |
|
502 |
} |
|
503 |
} |
|
504 |
} |
|
505 |
} |
|
506 |
||
507 |
/** |
|
508 |
* Returns the first path in the selection. This is useful if there |
|
509 |
* if only one item currently selected. |
|
510 |
*/ |
|
511 |
public TreePath getSelectionPath() { |
|
512 |
if (selection != null && selection.length > 0) { |
|
513 |
return selection[0]; |
|
514 |
} |
|
515 |
return null; |
|
516 |
} |
|
517 |
||
518 |
/** |
|
519 |
* Returns the selection. |
|
520 |
* |
|
521 |
* @return the selection |
|
522 |
*/ |
|
523 |
public TreePath[] getSelectionPaths() { |
|
524 |
if(selection != null) { |
|
525 |
int pathSize = selection.length; |
|
526 |
TreePath[] result = new TreePath[pathSize]; |
|
527 |
||
528 |
System.arraycopy(selection, 0, result, 0, pathSize); |
|
529 |
return result; |
|
530 |
} |
|
531 |
return new TreePath[0]; |
|
532 |
} |
|
533 |
||
534 |
/** |
|
535 |
* Returns the number of paths that are selected. |
|
536 |
*/ |
|
537 |
public int getSelectionCount() { |
|
538 |
return (selection == null) ? 0 : selection.length; |
|
539 |
} |
|
540 |
||
541 |
/** |
|
542 |
* Returns true if the path, <code>path</code>, |
|
543 |
* is in the current selection. |
|
544 |
*/ |
|
545 |
public boolean isPathSelected(TreePath path) { |
|
546 |
return (path != null) ? (uniquePaths.get(path) != null) : false; |
|
547 |
} |
|
548 |
||
549 |
/** |
|
550 |
* Returns true if the selection is currently empty. |
|
551 |
*/ |
|
552 |
public boolean isSelectionEmpty() { |
|
553 |
return (selection == null || selection.length == 0); |
|
554 |
} |
|
555 |
||
556 |
/** |
|
557 |
* Empties the current selection. If this represents a change in the |
|
558 |
* current selection, the selection listeners are notified. |
|
559 |
*/ |
|
560 |
public void clearSelection() { |
|
561 |
if (selection != null && selection.length > 0) { |
|
562 |
int selSize = selection.length; |
|
563 |
boolean[] newness = new boolean[selSize]; |
|
564 |
||
565 |
for(int counter = 0; counter < selSize; counter++) |
|
566 |
newness[counter] = false; |
|
567 |
||
568 |
TreeSelectionEvent event = new TreeSelectionEvent |
|
569 |
(this, selection, newness, leadPath, null); |
|
570 |
||
571 |
leadPath = null; |
|
572 |
leadIndex = leadRow = -1; |
|
573 |
uniquePaths.clear(); |
|
574 |
selection = null; |
|
575 |
resetRowSelection(); |
|
576 |
fireValueChanged(event); |
|
577 |
} |
|
578 |
} |
|
579 |
||
580 |
/** |
|
581 |
* Adds x to the list of listeners that are notified each time the |
|
582 |
* set of selected TreePaths changes. |
|
583 |
* |
|
584 |
* @param x the new listener to be added |
|
585 |
*/ |
|
586 |
public void addTreeSelectionListener(TreeSelectionListener x) { |
|
587 |
listenerList.add(TreeSelectionListener.class, x); |
|
588 |
} |
|
589 |
||
590 |
/** |
|
591 |
* Removes x from the list of listeners that are notified each time |
|
592 |
* the set of selected TreePaths changes. |
|
593 |
* |
|
594 |
* @param x the listener to remove |
|
595 |
*/ |
|
596 |
public void removeTreeSelectionListener(TreeSelectionListener x) { |
|
597 |
listenerList.remove(TreeSelectionListener.class, x); |
|
598 |
} |
|
599 |
||
600 |
/** |
|
601 |
* Returns an array of all the tree selection listeners |
|
602 |
* registered on this model. |
|
603 |
* |
|
604 |
* @return all of this model's <code>TreeSelectionListener</code>s |
|
605 |
* or an empty |
|
606 |
* array if no tree selection listeners are currently registered |
|
607 |
* |
|
608 |
* @see #addTreeSelectionListener |
|
609 |
* @see #removeTreeSelectionListener |
|
610 |
* |
|
611 |
* @since 1.4 |
|
612 |
*/ |
|
613 |
public TreeSelectionListener[] getTreeSelectionListeners() { |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
614 |
return listenerList.getListeners(TreeSelectionListener.class); |
2 | 615 |
} |
616 |
||
617 |
/** |
|
618 |
* Notifies all listeners that are registered for |
|
619 |
* tree selection events on this object. |
|
620 |
* @see #addTreeSelectionListener |
|
621 |
* @see EventListenerList |
|
622 |
*/ |
|
623 |
protected void fireValueChanged(TreeSelectionEvent e) { |
|
624 |
// Guaranteed to return a non-null array |
|
625 |
Object[] listeners = listenerList.getListenerList(); |
|
626 |
// TreeSelectionEvent e = null; |
|
627 |
// Process the listeners last to first, notifying |
|
628 |
// those that are interested in this event |
|
629 |
for (int i = listeners.length-2; i>=0; i-=2) { |
|
630 |
if (listeners[i]==TreeSelectionListener.class) { |
|
631 |
// Lazily create the event: |
|
632 |
// if (e == null) |
|
633 |
// e = new ListSelectionEvent(this, firstIndex, lastIndex); |
|
634 |
((TreeSelectionListener)listeners[i+1]).valueChanged(e); |
|
635 |
} |
|
636 |
} |
|
637 |
} |
|
638 |
||
639 |
/** |
|
640 |
* Returns an array of all the objects currently registered |
|
641 |
* as <code><em>Foo</em>Listener</code>s |
|
642 |
* upon this model. |
|
643 |
* <code><em>Foo</em>Listener</code>s are registered using the |
|
644 |
* <code>add<em>Foo</em>Listener</code> method. |
|
645 |
* |
|
646 |
* <p> |
|
647 |
* |
|
648 |
* You can specify the <code>listenerType</code> argument |
|
649 |
* with a class literal, |
|
650 |
* such as |
|
651 |
* <code><em>Foo</em>Listener.class</code>. |
|
652 |
* For example, you can query a |
|
653 |
* <code>DefaultTreeSelectionModel</code> <code>m</code> |
|
654 |
* for its tree selection listeners with the following code: |
|
655 |
* |
|
656 |
* <pre>TreeSelectionListener[] tsls = (TreeSelectionListener[])(m.getListeners(TreeSelectionListener.class));</pre> |
|
657 |
* |
|
658 |
* If no such listeners exist, this method returns an empty array. |
|
659 |
* |
|
660 |
* @param listenerType the type of listeners requested; this parameter |
|
661 |
* should specify an interface that descends from |
|
662 |
* <code>java.util.EventListener</code> |
|
663 |
* @return an array of all objects registered as |
|
664 |
* <code><em>Foo</em>Listener</code>s on this component, |
|
665 |
* or an empty array if no such |
|
666 |
* listeners have been added |
|
667 |
* @exception ClassCastException if <code>listenerType</code> |
|
668 |
* doesn't specify a class or interface that implements |
|
669 |
* <code>java.util.EventListener</code> |
|
670 |
* |
|
671 |
* @see #getTreeSelectionListeners |
|
672 |
* @see #getPropertyChangeListeners |
|
673 |
* |
|
674 |
* @since 1.3 |
|
675 |
*/ |
|
676 |
public <T extends EventListener> T[] getListeners(Class<T> listenerType) { |
|
677 |
return listenerList.getListeners(listenerType); |
|
678 |
} |
|
679 |
||
680 |
/** |
|
681 |
* Returns the selection in terms of rows. There is not |
|
682 |
* necessarily a one-to-one mapping between the {@code TreePath}s |
|
683 |
* returned from {@code getSelectionPaths} and this method. In |
|
684 |
* particular, if a {@code TreePath} is not viewable (the {@code |
|
685 |
* RowMapper} returns {@code -1} for the row corresponding to the |
|
686 |
* {@code TreePath}), then the corresponding row is not included |
|
687 |
* in the returned array. For example, if the selection consists |
|
688 |
* of two paths, {@code A} and {@code B}, with {@code A} at row |
|
689 |
* {@code 10}, and {@code B} not currently viewable, then this method |
|
690 |
* returns an array with the single entry {@code 10}. |
|
691 |
* |
|
692 |
* @return the selection in terms of rows |
|
693 |
*/ |
|
694 |
public int[] getSelectionRows() { |
|
695 |
// This is currently rather expensive. Needs |
|
696 |
// to be better support from ListSelectionModel to speed this up. |
|
697 |
if (rowMapper != null && selection != null && selection.length > 0) { |
|
698 |
int[] rows = rowMapper.getRowsForPaths(selection); |
|
699 |
||
700 |
if (rows != null) { |
|
701 |
int invisCount = 0; |
|
702 |
||
703 |
for (int counter = rows.length - 1; counter >= 0; counter--) { |
|
704 |
if (rows[counter] == -1) { |
|
705 |
invisCount++; |
|
706 |
} |
|
707 |
} |
|
708 |
if (invisCount > 0) { |
|
709 |
if (invisCount == rows.length) { |
|
710 |
rows = null; |
|
711 |
} |
|
712 |
else { |
|
713 |
int[] tempRows = new int[rows.length - invisCount]; |
|
714 |
||
715 |
for (int counter = rows.length - 1, visCounter = 0; |
|
716 |
counter >= 0; counter--) { |
|
717 |
if (rows[counter] != -1) { |
|
718 |
tempRows[visCounter++] = rows[counter]; |
|
719 |
} |
|
720 |
} |
|
721 |
rows = tempRows; |
|
722 |
} |
|
723 |
} |
|
724 |
} |
|
725 |
return rows; |
|
726 |
} |
|
727 |
return new int[0]; |
|
728 |
} |
|
729 |
||
730 |
/** |
|
731 |
* Returns the smallest value obtained from the RowMapper for the |
|
732 |
* current set of selected TreePaths. If nothing is selected, |
|
733 |
* or there is no RowMapper, this will return -1. |
|
734 |
*/ |
|
735 |
public int getMinSelectionRow() { |
|
736 |
return listSelectionModel.getMinSelectionIndex(); |
|
737 |
} |
|
738 |
||
739 |
/** |
|
740 |
* Returns the largest value obtained from the RowMapper for the |
|
741 |
* current set of selected TreePaths. If nothing is selected, |
|
742 |
* or there is no RowMapper, this will return -1. |
|
743 |
*/ |
|
744 |
public int getMaxSelectionRow() { |
|
745 |
return listSelectionModel.getMaxSelectionIndex(); |
|
746 |
} |
|
747 |
||
748 |
/** |
|
749 |
* Returns true if the row identified by <code>row</code> is selected. |
|
750 |
*/ |
|
751 |
public boolean isRowSelected(int row) { |
|
752 |
return listSelectionModel.isSelectedIndex(row); |
|
753 |
} |
|
754 |
||
755 |
/** |
|
756 |
* Updates this object's mapping from TreePath to rows. This should |
|
757 |
* be invoked when the mapping from TreePaths to integers has changed |
|
758 |
* (for example, a node has been expanded). |
|
759 |
* <p>You do not normally have to call this, JTree and its associated |
|
760 |
* Listeners will invoke this for you. If you are implementing your own |
|
761 |
* View class, then you will have to invoke this. |
|
762 |
* <p>This will invoke <code>insureRowContinuity</code> to make sure |
|
763 |
* the currently selected TreePaths are still valid based on the |
|
764 |
* selection mode. |
|
765 |
*/ |
|
766 |
public void resetRowSelection() { |
|
767 |
listSelectionModel.clearSelection(); |
|
768 |
if(selection != null && rowMapper != null) { |
|
769 |
int aRow; |
|
770 |
int validCount = 0; |
|
771 |
int[] rows = rowMapper.getRowsForPaths(selection); |
|
772 |
||
773 |
for(int counter = 0, maxCounter = selection.length; |
|
774 |
counter < maxCounter; counter++) { |
|
775 |
aRow = rows[counter]; |
|
776 |
if(aRow != -1) { |
|
777 |
listSelectionModel.addSelectionInterval(aRow, aRow); |
|
778 |
} |
|
779 |
} |
|
780 |
if(leadIndex != -1 && rows != null) { |
|
781 |
leadRow = rows[leadIndex]; |
|
782 |
} |
|
783 |
else if (leadPath != null) { |
|
784 |
// Lead selection path doesn't have to be in the selection. |
|
785 |
tempPaths[0] = leadPath; |
|
786 |
rows = rowMapper.getRowsForPaths(tempPaths); |
|
787 |
leadRow = (rows != null) ? rows[0] : -1; |
|
788 |
} |
|
789 |
else { |
|
790 |
leadRow = -1; |
|
791 |
} |
|
792 |
insureRowContinuity(); |
|
793 |
||
794 |
} |
|
795 |
else |
|
796 |
leadRow = -1; |
|
797 |
} |
|
798 |
||
799 |
/** |
|
800 |
* Returns the lead selection index. That is the last index that was |
|
801 |
* added. |
|
802 |
*/ |
|
803 |
public int getLeadSelectionRow() { |
|
804 |
return leadRow; |
|
805 |
} |
|
806 |
||
807 |
/** |
|
808 |
* Returns the last path that was added. This may differ from the |
|
809 |
* leadSelectionPath property maintained by the JTree. |
|
810 |
*/ |
|
811 |
public TreePath getLeadSelectionPath() { |
|
812 |
return leadPath; |
|
813 |
} |
|
814 |
||
815 |
/** |
|
816 |
* Adds a PropertyChangeListener to the listener list. |
|
817 |
* The listener is registered for all properties. |
|
818 |
* <p> |
|
819 |
* A PropertyChangeEvent will get fired when the selection mode |
|
820 |
* changes. |
|
821 |
* |
|
822 |
* @param listener the PropertyChangeListener to be added |
|
823 |
*/ |
|
824 |
public synchronized void addPropertyChangeListener( |
|
825 |
PropertyChangeListener listener) { |
|
826 |
if (changeSupport == null) { |
|
827 |
changeSupport = new SwingPropertyChangeSupport(this); |
|
828 |
} |
|
829 |
changeSupport.addPropertyChangeListener(listener); |
|
830 |
} |
|
831 |
||
832 |
/** |
|
833 |
* Removes a PropertyChangeListener from the listener list. |
|
834 |
* This removes a PropertyChangeListener that was registered |
|
835 |
* for all properties. |
|
836 |
* |
|
837 |
* @param listener the PropertyChangeListener to be removed |
|
838 |
*/ |
|
839 |
||
840 |
public synchronized void removePropertyChangeListener( |
|
841 |
PropertyChangeListener listener) { |
|
842 |
if (changeSupport == null) { |
|
843 |
return; |
|
844 |
} |
|
845 |
changeSupport.removePropertyChangeListener(listener); |
|
846 |
} |
|
847 |
||
848 |
/** |
|
849 |
* Returns an array of all the property change listeners |
|
850 |
* registered on this <code>DefaultTreeSelectionModel</code>. |
|
851 |
* |
|
852 |
* @return all of this model's <code>PropertyChangeListener</code>s |
|
853 |
* or an empty |
|
854 |
* array if no property change listeners are currently registered |
|
855 |
* |
|
856 |
* @see #addPropertyChangeListener |
|
857 |
* @see #removePropertyChangeListener |
|
858 |
* |
|
859 |
* @since 1.4 |
|
860 |
*/ |
|
861 |
public PropertyChangeListener[] getPropertyChangeListeners() { |
|
862 |
if (changeSupport == null) { |
|
863 |
return new PropertyChangeListener[0]; |
|
864 |
} |
|
865 |
return changeSupport.getPropertyChangeListeners(); |
|
866 |
} |
|
867 |
||
868 |
/** |
|
869 |
* Makes sure the currently selected <code>TreePath</code>s are valid |
|
870 |
* for the current selection mode. |
|
871 |
* If the selection mode is <code>CONTIGUOUS_TREE_SELECTION</code> |
|
872 |
* and a <code>RowMapper</code> exists, this will make sure all |
|
873 |
* the rows are contiguous, that is, when sorted all the rows are |
|
874 |
* in order with no gaps. |
|
875 |
* If the selection isn't contiguous, the selection is |
|
876 |
* reset to contain the first set, when sorted, of contiguous rows. |
|
877 |
* <p> |
|
878 |
* If the selection mode is <code>SINGLE_TREE_SELECTION</code> and |
|
879 |
* more than one TreePath is selected, the selection is reset to |
|
880 |
* contain the first path currently selected. |
|
881 |
*/ |
|
882 |
protected void insureRowContinuity() { |
|
883 |
if(selectionMode == TreeSelectionModel.CONTIGUOUS_TREE_SELECTION && |
|
884 |
selection != null && rowMapper != null) { |
|
885 |
DefaultListSelectionModel lModel = listSelectionModel; |
|
886 |
int min = lModel.getMinSelectionIndex(); |
|
887 |
||
888 |
if(min != -1) { |
|
889 |
for(int counter = min, |
|
890 |
maxCounter = lModel.getMaxSelectionIndex(); |
|
891 |
counter <= maxCounter; counter++) { |
|
892 |
if(!lModel.isSelectedIndex(counter)) { |
|
893 |
if(counter == min) { |
|
894 |
clearSelection(); |
|
895 |
} |
|
896 |
else { |
|
897 |
TreePath[] newSel = new TreePath[counter - min]; |
|
898 |
int selectionIndex[] = rowMapper.getRowsForPaths(selection); |
|
899 |
// find the actual selection pathes corresponded to the |
|
900 |
// rows of the new selection |
|
901 |
for (int i = 0; i < selectionIndex.length; i++) { |
|
902 |
if (selectionIndex[i]<counter) { |
|
903 |
newSel[selectionIndex[i]-min] = selection[i]; |
|
904 |
} |
|
905 |
} |
|
906 |
setSelectionPaths(newSel); |
|
907 |
break; |
|
908 |
} |
|
909 |
} |
|
910 |
} |
|
911 |
} |
|
912 |
} |
|
913 |
else if(selectionMode == TreeSelectionModel.SINGLE_TREE_SELECTION && |
|
914 |
selection != null && selection.length > 1) { |
|
915 |
setSelectionPath(selection[0]); |
|
916 |
} |
|
917 |
} |
|
918 |
||
919 |
/** |
|
920 |
* Returns true if the paths are contiguous, |
|
921 |
* or this object has no RowMapper. |
|
922 |
*/ |
|
923 |
protected boolean arePathsContiguous(TreePath[] paths) { |
|
924 |
if(rowMapper == null || paths.length < 2) |
|
925 |
return true; |
|
926 |
else { |
|
927 |
BitSet bitSet = new BitSet(32); |
|
928 |
int anIndex, counter, min; |
|
929 |
int pathCount = paths.length; |
|
930 |
int validCount = 0; |
|
931 |
TreePath[] tempPath = new TreePath[1]; |
|
932 |
||
933 |
tempPath[0] = paths[0]; |
|
934 |
min = rowMapper.getRowsForPaths(tempPath)[0]; |
|
935 |
for(counter = 0; counter < pathCount; counter++) { |
|
936 |
if(paths[counter] != null) { |
|
937 |
tempPath[0] = paths[counter]; |
|
938 |
int[] rows = rowMapper.getRowsForPaths(tempPath); |
|
939 |
if (rows == null) { |
|
940 |
return false; |
|
941 |
} |
|
942 |
anIndex = rows[0]; |
|
943 |
if(anIndex == -1 || anIndex < (min - pathCount) || |
|
944 |
anIndex > (min + pathCount)) |
|
945 |
return false; |
|
946 |
if(anIndex < min) |
|
947 |
min = anIndex; |
|
948 |
if(!bitSet.get(anIndex)) { |
|
949 |
bitSet.set(anIndex); |
|
950 |
validCount++; |
|
951 |
} |
|
952 |
} |
|
953 |
} |
|
954 |
int maxCounter = validCount + min; |
|
955 |
||
956 |
for(counter = min; counter < maxCounter; counter++) |
|
957 |
if(!bitSet.get(counter)) |
|
958 |
return false; |
|
959 |
} |
|
960 |
return true; |
|
961 |
} |
|
962 |
||
963 |
/** |
|
964 |
* Used to test if a particular set of <code>TreePath</code>s can |
|
965 |
* be added. This will return true if <code>paths</code> is null (or |
|
966 |
* empty), or this object has no RowMapper, or nothing is currently selected, |
|
967 |
* or the selection mode is <code>DISCONTIGUOUS_TREE_SELECTION</code>, or |
|
968 |
* adding the paths to the current selection still results in a |
|
969 |
* contiguous set of <code>TreePath</code>s. |
|
970 |
*/ |
|
971 |
protected boolean canPathsBeAdded(TreePath[] paths) { |
|
972 |
if(paths == null || paths.length == 0 || rowMapper == null || |
|
973 |
selection == null || selectionMode == |
|
974 |
TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) |
|
975 |
return true; |
|
976 |
else { |
|
977 |
BitSet bitSet = new BitSet(); |
|
978 |
DefaultListSelectionModel lModel = listSelectionModel; |
|
979 |
int anIndex; |
|
980 |
int counter; |
|
981 |
int min = lModel.getMinSelectionIndex(); |
|
982 |
int max = lModel.getMaxSelectionIndex(); |
|
983 |
TreePath[] tempPath = new TreePath[1]; |
|
984 |
||
985 |
if(min != -1) { |
|
986 |
for(counter = min; counter <= max; counter++) { |
|
987 |
if(lModel.isSelectedIndex(counter)) |
|
988 |
bitSet.set(counter); |
|
989 |
} |
|
990 |
} |
|
991 |
else { |
|
992 |
tempPath[0] = paths[0]; |
|
993 |
min = max = rowMapper.getRowsForPaths(tempPath)[0]; |
|
994 |
} |
|
995 |
for(counter = paths.length - 1; counter >= 0; counter--) { |
|
996 |
if(paths[counter] != null) { |
|
997 |
tempPath[0] = paths[counter]; |
|
998 |
int[] rows = rowMapper.getRowsForPaths(tempPath); |
|
999 |
if (rows == null) { |
|
1000 |
return false; |
|
1001 |
} |
|
1002 |
anIndex = rows[0]; |
|
1003 |
min = Math.min(anIndex, min); |
|
1004 |
max = Math.max(anIndex, max); |
|
1005 |
if(anIndex == -1) |
|
1006 |
return false; |
|
1007 |
bitSet.set(anIndex); |
|
1008 |
} |
|
1009 |
} |
|
1010 |
for(counter = min; counter <= max; counter++) |
|
1011 |
if(!bitSet.get(counter)) |
|
1012 |
return false; |
|
1013 |
} |
|
1014 |
return true; |
|
1015 |
} |
|
1016 |
||
1017 |
/** |
|
1018 |
* Returns true if the paths can be removed without breaking the |
|
1019 |
* continuity of the model. |
|
1020 |
* This is rather expensive. |
|
1021 |
*/ |
|
1022 |
protected boolean canPathsBeRemoved(TreePath[] paths) { |
|
1023 |
if(rowMapper == null || selection == null || |
|
1024 |
selectionMode == TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION) |
|
1025 |
return true; |
|
1026 |
else { |
|
1027 |
BitSet bitSet = new BitSet(); |
|
1028 |
int counter; |
|
1029 |
int pathCount = paths.length; |
|
1030 |
int anIndex; |
|
1031 |
int min = -1; |
|
1032 |
int validCount = 0; |
|
1033 |
TreePath[] tempPath = new TreePath[1]; |
|
1034 |
int[] rows; |
|
1035 |
||
1036 |
/* Determine the rows for the removed entries. */ |
|
1037 |
lastPaths.clear(); |
|
1038 |
for (counter = 0; counter < pathCount; counter++) { |
|
1039 |
if (paths[counter] != null) { |
|
1040 |
lastPaths.put(paths[counter], Boolean.TRUE); |
|
1041 |
} |
|
1042 |
} |
|
1043 |
for(counter = selection.length - 1; counter >= 0; counter--) { |
|
1044 |
if(lastPaths.get(selection[counter]) == null) { |
|
1045 |
tempPath[0] = selection[counter]; |
|
1046 |
rows = rowMapper.getRowsForPaths(tempPath); |
|
1047 |
if(rows != null && rows[0] != -1 && !bitSet.get(rows[0])) { |
|
1048 |
validCount++; |
|
1049 |
if(min == -1) |
|
1050 |
min = rows[0]; |
|
1051 |
else |
|
1052 |
min = Math.min(min, rows[0]); |
|
1053 |
bitSet.set(rows[0]); |
|
1054 |
} |
|
1055 |
} |
|
1056 |
} |
|
1057 |
lastPaths.clear(); |
|
1058 |
/* Make sure they are contiguous. */ |
|
1059 |
if(validCount > 1) { |
|
1060 |
for(counter = min + validCount - 1; counter >= min; |
|
1061 |
counter--) |
|
1062 |
if(!bitSet.get(counter)) |
|
1063 |
return false; |
|
1064 |
} |
|
1065 |
} |
|
1066 |
return true; |
|
1067 |
} |
|
1068 |
||
1069 |
/** |
|
3747
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1070 |
* Notifies listeners of a change in path. changePaths should contain |
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1071 |
* instances of PathPlaceHolder. |
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1072 |
* |
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1073 |
* @deprecated As of JDK version 1.7 |
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1074 |
*/ |
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1075 |
@Deprecated |
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1076 |
protected void notifyPathChange(Vector changedPaths, |
2 | 1077 |
TreePath oldLeadSelection) { |
1078 |
int cPathCount = changedPaths.size(); |
|
1079 |
boolean[] newness = new boolean[cPathCount]; |
|
1080 |
TreePath[] paths = new TreePath[cPathCount]; |
|
1081 |
PathPlaceHolder placeholder; |
|
1082 |
||
1083 |
for(int counter = 0; counter < cPathCount; counter++) { |
|
3747
760e072cc617
6387579: Usage of package-private class as parameter of a method (javax.swing.tree.DefaultTreeSelectionModel)
peterz
parents:
1301
diff
changeset
|
1084 |
placeholder = (PathPlaceHolder) changedPaths.elementAt(counter); |
2 | 1085 |
newness[counter] = placeholder.isNew; |
1086 |
paths[counter] = placeholder.path; |
|
1087 |
} |
|
1088 |
||
1089 |
TreeSelectionEvent event = new TreeSelectionEvent |
|
1090 |
(this, paths, newness, oldLeadSelection, leadPath); |
|
1091 |
||
1092 |
fireValueChanged(event); |
|
1093 |
} |
|
1094 |
||
1095 |
/** |
|
1096 |
* Updates the leadIndex instance variable. |
|
1097 |
*/ |
|
1098 |
protected void updateLeadIndex() { |
|
1099 |
if(leadPath != null) { |
|
1100 |
if(selection == null) { |
|
1101 |
leadPath = null; |
|
1102 |
leadIndex = leadRow = -1; |
|
1103 |
} |
|
1104 |
else { |
|
1105 |
leadRow = leadIndex = -1; |
|
1106 |
for(int counter = selection.length - 1; counter >= 0; |
|
1107 |
counter--) { |
|
1108 |
// Can use == here since we know leadPath came from |
|
1109 |
// selection |
|
1110 |
if(selection[counter] == leadPath) { |
|
1111 |
leadIndex = counter; |
|
1112 |
break; |
|
1113 |
} |
|
1114 |
} |
|
1115 |
} |
|
1116 |
} |
|
1117 |
else { |
|
1118 |
leadIndex = -1; |
|
1119 |
} |
|
1120 |
} |
|
1121 |
||
1122 |
/** |
|
1123 |
* This method is obsolete and its implementation is now a noop. It's |
|
1124 |
* still called by setSelectionPaths and addSelectionPaths, but only |
|
1125 |
* for backwards compatability. |
|
1126 |
*/ |
|
1127 |
protected void insureUniqueness() { |
|
1128 |
} |
|
1129 |
||
1130 |
||
1131 |
/** |
|
1132 |
* Returns a string that displays and identifies this |
|
1133 |
* object's properties. |
|
1134 |
* |
|
1135 |
* @return a String representation of this object |
|
1136 |
*/ |
|
1137 |
public String toString() { |
|
1138 |
int selCount = getSelectionCount(); |
|
1139 |
StringBuffer retBuffer = new StringBuffer(); |
|
1140 |
int[] rows; |
|
1141 |
||
1142 |
if(rowMapper != null) |
|
1143 |
rows = rowMapper.getRowsForPaths(selection); |
|
1144 |
else |
|
1145 |
rows = null; |
|
1146 |
retBuffer.append(getClass().getName() + " " + hashCode() + " [ "); |
|
1147 |
for(int counter = 0; counter < selCount; counter++) { |
|
1148 |
if(rows != null) |
|
1149 |
retBuffer.append(selection[counter].toString() + "@" + |
|
1150 |
Integer.toString(rows[counter])+ " "); |
|
1151 |
else |
|
1152 |
retBuffer.append(selection[counter].toString() + " "); |
|
1153 |
} |
|
1154 |
retBuffer.append("]"); |
|
1155 |
return retBuffer.toString(); |
|
1156 |
} |
|
1157 |
||
1158 |
/** |
|
1159 |
* Returns a clone of this object with the same selection. |
|
1160 |
* This method does not duplicate |
|
1161 |
* selection listeners and property listeners. |
|
1162 |
* |
|
1163 |
* @exception CloneNotSupportedException never thrown by instances of |
|
1164 |
* this class |
|
1165 |
*/ |
|
1166 |
public Object clone() throws CloneNotSupportedException { |
|
1167 |
DefaultTreeSelectionModel clone = (DefaultTreeSelectionModel) |
|
1168 |
super.clone(); |
|
1169 |
||
1170 |
clone.changeSupport = null; |
|
1171 |
if(selection != null) { |
|
1172 |
int selLength = selection.length; |
|
1173 |
||
1174 |
clone.selection = new TreePath[selLength]; |
|
1175 |
System.arraycopy(selection, 0, clone.selection, 0, selLength); |
|
1176 |
} |
|
1177 |
clone.listenerList = new EventListenerList(); |
|
1178 |
clone.listSelectionModel = (DefaultListSelectionModel) |
|
1179 |
listSelectionModel.clone(); |
|
1301
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
1180 |
clone.uniquePaths = new Hashtable<TreePath, Boolean>(); |
15e81207e1f2
6727662: Code improvement and warnings removing from swing packages
rupashka
parents:
715
diff
changeset
|
1181 |
clone.lastPaths = new Hashtable<TreePath, Boolean>(); |
2 | 1182 |
clone.tempPaths = new TreePath[1]; |
1183 |
return clone; |
|
1184 |
} |
|
1185 |
||
1186 |
// Serialization support. |
|
1187 |
private void writeObject(ObjectOutputStream s) throws IOException { |
|
1188 |
Object[] tValues; |
|
1189 |
||
1190 |
s.defaultWriteObject(); |
|
1191 |
// Save the rowMapper, if it implements Serializable |
|
1192 |
if(rowMapper != null && rowMapper instanceof Serializable) { |
|
1193 |
tValues = new Object[2]; |
|
1194 |
tValues[0] = "rowMapper"; |
|
1195 |
tValues[1] = rowMapper; |
|
1196 |
} |
|
1197 |
else |
|
1198 |
tValues = new Object[0]; |
|
1199 |
s.writeObject(tValues); |
|
1200 |
} |
|
1201 |
||
1202 |
||
1203 |
private void readObject(ObjectInputStream s) |
|
1204 |
throws IOException, ClassNotFoundException { |
|
1205 |
Object[] tValues; |
|
1206 |
||
1207 |
s.defaultReadObject(); |
|
1208 |
||
1209 |
tValues = (Object[])s.readObject(); |
|
1210 |
||
1211 |
if(tValues.length > 0 && tValues[0].equals("rowMapper")) |
|
1212 |
rowMapper = (RowMapper)tValues[1]; |
|
1213 |
} |
|
1214 |
} |
|
1215 |
||
1216 |
/** |
|
1217 |
* Holds a path and whether or not it is new. |
|
1218 |
*/ |
|
1219 |
class PathPlaceHolder { |
|
1220 |
protected boolean isNew; |
|
1221 |
protected TreePath path; |
|
1222 |
||
1223 |
PathPlaceHolder(TreePath path, boolean isNew) { |
|
1224 |
this.path = path; |
|
1225 |
this.isNew = isNew; |
|
1226 |
} |
|
1227 |
} |