1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51:
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57:
58:
67: public class DefaultTreeSelectionModel
68: implements Cloneable, Serializable, TreeSelectionModel
69: {
70:
71:
74: static final long serialVersionUID = 3288129636638950196L;
75:
76:
79: public static final String SELECTION_MODE_PROPERTY = "selectionMode";
80:
81:
84: protected SwingPropertyChangeSupport changeSupport;
85:
86:
89: protected TreePath[] selection;
90:
91:
94: protected EventListenerList listenerList;
95:
96:
99: protected transient RowMapper rowMapper;
100:
101:
104: protected DefaultListSelectionModel listSelectionModel;
105:
106:
109: protected int selectionMode;
110:
111:
114: protected TreePath leadPath;
115:
116:
119: protected int leadIndex;
120:
121:
124: protected int leadRow = -1;
125:
126:
129: public DefaultTreeSelectionModel()
130: {
131: setSelectionMode(DISCONTIGUOUS_TREE_SELECTION);
132: listenerList = new EventListenerList();
133: }
134:
135:
143: public Object clone() throws CloneNotSupportedException
144: {
145: DefaultTreeSelectionModel cloned =
146: (DefaultTreeSelectionModel) super.clone();
147:
148:
149: cloned.selection = (TreePath[]) selection.clone();
150: if (listSelectionModel != null)
151: cloned.listSelectionModel
152: = (DefaultListSelectionModel) listSelectionModel.clone();
153: return cloned;
154: }
155:
156:
162: public String toString()
163: {
164: if (isSelectionEmpty())
165: return "[selection empty]";
166: else
167: {
168: StringBuffer b = new StringBuffer("selected rows: [");
169: for (int i = 0; i < selection.length; i++)
170: {
171: b.append(getRow(selection[i]));
172: b.append(' ');
173: }
174: b.append(", lead " + getLeadSelectionRow());
175: return b.toString();
176: }
177: }
178:
179:
185: private void writeObject(ObjectOutputStream value0) throws IOException
186: {
187:
188: }
189:
190:
197: private void readObject(ObjectInputStream value0) throws IOException,
198: ClassNotFoundException
199: {
200:
201: }
202:
203:
209: public void setRowMapper(RowMapper mapper)
210: {
211: rowMapper = mapper;
212: }
213:
214:
221: public RowMapper getRowMapper()
222: {
223: return rowMapper;
224: }
225:
226:
237: public void setSelectionMode(int mode)
238: {
239: selectionMode = mode;
240: insureRowContinuity();
241: }
242:
243:
252: public int getSelectionMode()
253: {
254: return selectionMode;
255: }
256:
257:
263: public void setSelectionPath(TreePath path)
264: {
265:
266: TreePath[] ose = selection;
267: selection = new TreePath[] { path };
268: TreePath oldLead = leadPath;
269: leadIndex = 0;
270: leadRow = getRow(path);
271: leadPath = path;
272:
273: TreeSelectionEvent event;
274:
275: if (ose != null && ose.length > 0)
276: {
277:
278:
279: TreePath[] changed = new TreePath[ose.length + 1];
280: boolean[] news = new boolean[changed.length];
281: news[0] = true;
282: changed[0] = path;
283: System.arraycopy(ose, 0, changed, 1, ose.length);
284: event = new TreeSelectionEvent(this, changed, news, oldLead, path);
285: }
286: else
287: {
288: event = new TreeSelectionEvent(this, path, true, oldLead, path);
289: }
290: fireValueChanged(event);
291: }
292:
293:
299: int getRow(TreePath path)
300: {
301: RowMapper mapper = getRowMapper();
302:
303: if (mapper instanceof AbstractLayoutCache)
304: {
305:
306:
307: AbstractLayoutCache ama = (AbstractLayoutCache) mapper;
308: return ama.getRowForPath(path);
309: }
310: else
311: {
312:
313: int[] rows = mapper.getRowsForPaths(new TreePath[] { path });
314: if (rows.length == 0)
315: return - 1;
316: else
317: return rows[0];
318: }
319: }
320:
321:
328: public void setSelectionPaths(TreePath[] paths)
329: {
330:
331: insureUniqueness();
332: clearSelection();
333: addSelectionPaths(paths);
334: }
335:
336:
346: public void addSelectionPath(TreePath path)
347: {
348: if (! isPathSelected(path))
349: {
350: if (selectionMode == SINGLE_TREE_SELECTION || isSelectionEmpty()
351: || ! canPathBeAdded(path))
352: setSelectionPath(path);
353: else
354: {
355: TreePath[] temp = new TreePath[selection.length + 1];
356: System.arraycopy(selection, 0, temp, 0, selection.length);
357: temp[temp.length - 1] = path;
358: selection = new TreePath[temp.length];
359: System.arraycopy(temp, 0, selection, 0, temp.length);
360: }
361: }
362:
363: if (path != leadPath)
364: {
365: TreePath oldLead = leadPath;
366: leadPath = path;
367: leadRow = getRow(path);
368: leadIndex = selection.length - 1;
369: fireValueChanged(new TreeSelectionEvent(this, path, true, oldLead,
370: leadPath));
371: }
372: }
373:
374:
381: public void addSelectionPaths(TreePath[] paths)
382: {
383:
384: insureUniqueness();
385:
386: if (paths != null)
387: {
388: TreePath v0 = null;
389: for (int i = 0; i < paths.length; i++)
390: {
391: v0 = paths[i];
392: if (! isPathSelected(v0))
393: {
394: if (isSelectionEmpty())
395: setSelectionPath(v0);
396: else
397: {
398: TreePath[] temp = new TreePath[selection.length + 1];
399: System.arraycopy(selection, 0, temp, 0, selection.length);
400: temp[temp.length - 1] = v0;
401: selection = new TreePath[temp.length];
402: System.arraycopy(temp, 0, selection, 0, temp.length);
403: }
404: TreePath oldLead = leadPath;
405: leadPath = paths[paths.length - 1];
406: leadRow = getRow(leadPath);
407: leadIndex = selection.length - 1;
408:
409: fireValueChanged(new TreeSelectionEvent(this, v0, true,
410: oldLead, leadPath));
411: }
412: }
413: insureRowContinuity();
414: }
415: }
416:
417:
423: public void removeSelectionPath(TreePath path)
424: {
425: if (isSelectionEmpty())
426: return;
427:
428: int index = - 1;
429: if (isPathSelected(path))
430: {
431: for (int i = 0; i < selection.length; i++)
432: {
433: if (selection[i].equals(path))
434: {
435: index = i;
436: break;
437: }
438: }
439: TreePath[] temp = new TreePath[selection.length - 1];
440: System.arraycopy(selection, 0, temp, 0, index);
441: System.arraycopy(selection, index + 1, temp, index, selection.length
442: - index - 1);
443: selection = new TreePath[temp.length];
444: System.arraycopy(temp, 0, selection, 0, temp.length);
445:
446:
447: TreePath oldLead = leadPath;
448: if (path != null && leadPath != null && path.equals(leadPath))
449: leadPath = null;
450:
451: fireValueChanged(new TreeSelectionEvent(this, path, false, oldLead,
452: leadPath));
453: insureRowContinuity();
454: }
455: }
456:
457:
463: public void removeSelectionPaths(TreePath[] paths)
464: {
465: if (isSelectionEmpty())
466: return;
467: if (paths != null)
468: {
469: int index = - 1;
470: TreePath v0 = null;
471: TreePath oldLead = leadPath;
472: for (int i = 0; i < paths.length; i++)
473: {
474: v0 = paths[i];
475: if (isPathSelected(v0))
476: {
477: for (int x = 0; x < selection.length; x++)
478: {
479: if (selection[i].equals(v0))
480: {
481: index = x;
482: break;
483: }
484: if (leadPath != null && leadPath.equals(v0))
485: leadPath = null;
486: }
487: TreePath[] temp = new TreePath[selection.length - 1];
488: System.arraycopy(selection, 0, temp, 0, index);
489: System.arraycopy(selection, index + 1, temp, index,
490: selection.length - index - 1);
491: selection = new TreePath[temp.length];
492: System.arraycopy(temp, 0, selection, 0, temp.length);
493:
494: fireValueChanged(new TreeSelectionEvent(this, v0, false,
495: oldLead, leadPath));
496: }
497: }
498: insureRowContinuity();
499: }
500: }
501:
502:
508: public TreePath getSelectionPath()
509: {
510: if ((selection == null) || (selection.length == 0))
511: return null;
512: else
513: return selection[0];
514: }
515:
516:
521: public TreePath[] getSelectionPaths()
522: {
523: return selection;
524: }
525:
526:
531: public int getSelectionCount()
532: {
533: if (selection == null)
534: return 0;
535: else
536: return selection.length;
537: }
538:
539:
546: public boolean isPathSelected(TreePath path)
547: {
548: if (selection == null)
549: return false;
550:
551: for (int i = 0; i < selection.length; i++)
552: {
553: if (selection[i].equals(path))
554: return true;
555: }
556: return false;
557: }
558:
559:
565: public boolean isSelectionEmpty()
566: {
567: return (selection == null) || (selection.length == 0);
568: }
569:
570:
573: public void clearSelection()
574: {
575: if (! isSelectionEmpty())
576: {
577: TreeSelectionEvent event = new TreeSelectionEvent(
578: this, selection, new boolean[selection.length], leadPath, null);
579: leadPath = null;
580: selection = null;
581: fireValueChanged(event);
582: }
583: else
584: {
585: leadPath = null;
586: selection = null;
587: }
588: }
589:
590:
595: public void addTreeSelectionListener(TreeSelectionListener listener)
596: {
597: listenerList.add(TreeSelectionListener.class, listener);
598: }
599:
600:
605: public void removeTreeSelectionListener(TreeSelectionListener listener)
606: {
607: listenerList.remove(TreeSelectionListener.class, listener);
608: }
609:
610:
616: public TreeSelectionListener[] getTreeSelectionListeners()
617: {
618: return (TreeSelectionListener[]) getListeners(TreeSelectionListener.class);
619: }
620:
621:
626: protected void fireValueChanged(TreeSelectionEvent event)
627: {
628: TreeSelectionListener[] listeners = getTreeSelectionListeners();
629:
630: for (int i = 0; i < listeners.length; ++i)
631: listeners[i].valueChanged(event);
632: }
633:
634:
641: public EventListener[] getListeners(Class listenerType)
642: {
643: return listenerList.getListeners(listenerType);
644: }
645:
646:
651: public int[] getSelectionRows()
652: {
653: if (rowMapper == null)
654: return null;
655: else
656: return rowMapper.getRowsForPaths(selection);
657: }
658:
659:
664: public int getMinSelectionRow()
665: {
666: if ((rowMapper == null) || (selection == null) || (selection.length == 0))
667: return - 1;
668: else
669: {
670: int[] rows = rowMapper.getRowsForPaths(selection);
671: int minRow = Integer.MAX_VALUE;
672: for (int index = 0; index < rows.length; index++)
673: minRow = Math.min(minRow, rows[index]);
674: return minRow;
675: }
676: }
677:
678:
683: public int getMaxSelectionRow()
684: {
685: if ((rowMapper == null) || (selection == null) || (selection.length == 0))
686: return - 1;
687: else
688: {
689: int[] rows = rowMapper.getRowsForPaths(selection);
690: int maxRow = - 1;
691: for (int index = 0; index < rows.length; index++)
692: maxRow = Math.max(maxRow, rows[index]);
693: return maxRow;
694: }
695: }
696:
697:
707: public boolean isRowSelected(int row)
708: {
709:
710: if (isSelectionEmpty())
711: return false;
712:
713: RowMapper mapper = getRowMapper();
714:
715: if (mapper instanceof AbstractLayoutCache)
716: {
717:
718:
719: AbstractLayoutCache ama = (AbstractLayoutCache) mapper;
720: TreePath path = ama.getPathForRow(row);
721: return isPathSelected(path);
722: }
723: else
724: {
725:
726: int[] rows = mapper.getRowsForPaths(selection);
727: for (int i = 0; i < rows.length; i++)
728: if (rows[i] == row)
729: return true;
730: return false;
731: }
732: }
733:
734:
737: public void resetRowSelection()
738: {
739:
740: }
741:
742:
747: public int getLeadSelectionRow()
748: {
749: return leadRow;
750: }
751:
752:
757: public TreePath getLeadSelectionPath()
758: {
759: return leadPath;
760: }
761:
762:
767: public void addPropertyChangeListener(PropertyChangeListener listener)
768: {
769: changeSupport.addPropertyChangeListener(listener);
770: }
771:
772:
777: public void removePropertyChangeListener(PropertyChangeListener listener)
778: {
779: changeSupport.removePropertyChangeListener(listener);
780: }
781:
782:
788: public PropertyChangeListener[] getPropertyChangeListeners()
789: {
790: return changeSupport.getPropertyChangeListeners();
791: }
792:
793:
802: protected void insureRowContinuity()
803: {
804: if (selection == null || selection.length < 2)
805: return;
806: else if (selectionMode == CONTIGUOUS_TREE_SELECTION)
807: {
808: if (rowMapper == null)
809:
810: selectOne();
811: else
812: {
813: int[] rows = rowMapper.getRowsForPaths(selection);
814: Arrays.sort(rows);
815: int i;
816: for (i = 1; i < rows.length; i++)
817: {
818: if (rows[i - 1] != rows[i] - 1)
819:
820: break;
821: }
822:
823: if (i < rows.length)
824: {
825: TreePath[] ns = new TreePath[i];
826: for (int j = 0; j < ns.length; j++)
827: ns[i] = getPath(j);
828: setSelectionPaths(ns);
829: }
830: }
831: }
832: else if (selectionMode == SINGLE_TREE_SELECTION)
833: selectOne();
834: }
835:
836:
839: private void selectOne()
840: {
841: if (leadIndex > 0 && leadIndex < selection.length)
842: setSelectionPath(selection[leadIndex]);
843: else
844: setSelectionPath(selection[selection.length - 1]);
845: }
846:
847:
850: private TreePath getPath(int row)
851: {
852: if (rowMapper instanceof AbstractLayoutCache)
853: return ((AbstractLayoutCache) rowMapper).getPathForRow(row);
854: else
855: {
856: int[] rows = rowMapper.getRowsForPaths(selection);
857: for (int i = 0; i < rows.length; i++)
858: if (rows[i] == row)
859: return selection[i];
860: }
861: throw new InternalError(row + " not in selection");
862: }
863:
864:
873: protected boolean arePathsContiguous(TreePath[] paths)
874: {
875: if (rowMapper == null || paths.length < 2)
876: return true;
877:
878: int[] rows = rowMapper.getRowsForPaths(paths);
879:
880:
881: Arrays.sort(rows);
882:
883: for (int i = 1; i < rows.length; i++)
884: {
885: if (rows[i - 1] != rows[i] - 1)
886: return false;
887: }
888: return true;
889: }
890:
891:
905: protected boolean canPathsBeAdded(TreePath[] paths)
906: {
907: if (rowMapper == null || isSelectionEmpty()
908: || selectionMode == DISCONTIGUOUS_TREE_SELECTION)
909: return true;
910:
911: TreePath [] all = new TreePath[paths.length + selection.length];
912: System.arraycopy(paths, 0, all, 0, paths.length);
913: System.arraycopy(selection, 0, all, paths.length, selection.length);
914:
915: return arePathsContiguous(all);
916: }
917:
918:
921: private boolean canPathBeAdded(TreePath path)
922: {
923: if (rowMapper == null || isSelectionEmpty()
924: || selectionMode == DISCONTIGUOUS_TREE_SELECTION)
925: return true;
926:
927: TreePath[] all = new TreePath[selection.length + 1];
928: System.arraycopy(selection, 0, all, 0, selection.length);
929: all[all.length - 1] = path;
930:
931: return arePathsContiguous(all);
932: }
933:
934:
942: protected boolean canPathsBeRemoved(TreePath[] paths)
943: {
944: if (rowMapper == null || isSelectionEmpty()
945: || selectionMode == DISCONTIGUOUS_TREE_SELECTION)
946: return true;
947:
948: HashSet set = new HashSet();
949: for (int i = 0; i < selection.length; i++)
950: set.add(selection[i]);
951:
952: for (int i = 0; i < paths.length; i++)
953: set.remove(paths[i]);
954:
955: TreePath[] remaining = new TreePath[set.size()];
956: Iterator iter = set.iterator();
957:
958: for (int i = 0; i < remaining.length; i++)
959: remaining[i] = (TreePath) iter.next();
960:
961: return arePathsContiguous(remaining);
962: }
963:
964:
972: protected void notifyPathChange(Vector vPathes, TreePath oldLeadSelection)
973: {
974: TreePath[] pathes = new TreePath[vPathes.size()];
975: for (int i = 0; i < pathes.length; i++)
976: pathes[i] = (TreePath) vPathes.get(i);
977:
978: boolean[] news = new boolean[pathes.length];
979: for (int i = 0; i < news.length; i++)
980: news[i] = isPathSelected(pathes[i]);
981:
982: TreeSelectionEvent event = new TreeSelectionEvent(this, pathes, news,
983: oldLeadSelection,
984: leadPath);
985: fireValueChanged(event);
986: }
987:
988:
992: protected void updateLeadIndex()
993: {
994: if (isSelectionEmpty())
995: {
996: leadRow = leadIndex = - 1;
997: }
998: else
999: {
1000: leadRow = getRow(leadPath);
1001: for (int i = 0; i < selection.length; i++)
1002: {
1003: if (selection[i].equals(leadPath))
1004: {
1005: leadIndex = i;
1006: break;
1007: }
1008: }
1009: leadIndex = leadRow;
1010: }
1011: }
1012:
1013:
1019: protected void insureUniqueness()
1020: {
1021:
1022: }
1023: }