source: trunk/gli/src/org/greenstone/gatherer/util/DragTreeSelectionModel.java@ 4293

Last change on this file since 4293 was 4293, checked in by jmt12, 21 years ago

Initial revision

  • Property svn:keywords set to Author Date Id Revision
File size: 10.1 KB
Line 
1package org.greenstone.gatherer.util;
2/**
3 *#########################################################################
4 *
5 * A component of the Gatherer application, part of the Greenstone digital
6 * library suite from the New Zealand Digital Library Project at the
7 * University of Waikato, New Zealand.
8 *
9 * <BR><BR>
10 *
11 * Author: John Thompson, Greenstone Digital Library, University of Waikato
12 *
13 * <BR><BR>
14 *
15 * Copyright (C) 1999 New Zealand Digital Library Project
16 *
17 * <BR><BR>
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * <BR><BR>
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * <BR><BR>
32 *
33 * You should have received a copy of the GNU General Public License
34 * along with this program; if not, write to the Free Software
35 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 *########################################################################
37 */
38
39import java.awt.Point;
40import java.awt.event.*;
41import javax.swing.tree.*;
42import org.greenstone.gatherer.Dictionary;
43import org.greenstone.gatherer.Gatherer;
44import org.greenstone.gatherer.gui.tree.DragTree;
45
46public class DragTreeSelectionModel
47 extends DefaultTreeSelectionModel
48 implements MouseListener {
49
50 boolean immediate = false;
51
52 private int type = -1;
53
54 private String suffix = null;
55
56 private TreePath temp_path = null;
57 private TreePath temp_paths[] = null;
58
59 static private final int NONE = -1;
60 static private final int ADD = 0;
61 static private final int SET = 1;
62
63 public DragTreeSelectionModel(DragTree tree) {
64 super();
65 setSelectionMode(DISCONTIGUOUS_TREE_SELECTION);
66 tree.addMouseListener(this);
67 }
68
69 public void addSelectionPath(TreePath path) {
70 if(!immediate) {
71 this.temp_path = path;
72 this.type = this.ADD;
73 }
74 else if(isAppropriate(path)) {
75 temp_path = null;
76 super.addSelectionPath(path);
77 suffix = null;
78 }
79 }
80
81 public void addSelectionPaths(TreePath paths[]) {
82 if(!immediate) {
83 this.temp_paths = paths;
84 this.type = this.ADD;
85 }
86 else if(isAppropriate(paths, true)) {
87 temp_paths = null;
88 super.setSelectionPaths(paths);
89 suffix = null;
90 }
91 }
92
93 public String getDetails() {
94 if(suffix == null) {
95 int file_count = 0;
96 int folder_count = 0;
97 for(int i = 0; selection != null && i < selection.length; i++) {
98 TreeNode node = (TreeNode) selection[i].getLastPathComponent();
99 if(node.isLeaf()) {
100 file_count++;
101 }
102 else {
103 folder_count++;
104 }
105 }
106 // Update the metaaudit_suffix
107 String args[] = null;
108 if(file_count > 0 && folder_count > 0) {
109 if(file_count > 1 && folder_count > 1) {
110 args = new String[2];
111 args[0] = String.valueOf(file_count);
112 args[1] = String.valueOf(folder_count);
113 suffix = Gatherer.dictionary.get("FileActions.Selected", args);
114 }
115 else if(file_count > 1) {
116 args = new String[1];
117 args[0] = String.valueOf(file_count);
118 suffix = Gatherer.dictionary.get("FileActions.Files_And_Directory_Selected", args);
119 }
120 else if(folder_count > 1) {
121 args = new String[1];
122 args[0] = String.valueOf(folder_count);
123 suffix = Gatherer.dictionary.get("FileActions.File_And_Directories_Selected", args);
124 }
125 else {
126 suffix = Gatherer.dictionary.get("FileActions.File_And_Directory_Selected");
127 }
128 }
129 else if(file_count > 0) {
130 if(file_count > 1) {
131 args = new String[1];
132 args[0] = String.valueOf(file_count);
133 suffix = Gatherer.dictionary.get("FileActions.Files_Selected", args);
134 }
135 else if(file_count == 1) {
136 suffix = Gatherer.dictionary.get("FileActions.File_Selected");
137 }
138 }
139 else if(folder_count > 0) {
140 if(folder_count > 1) {
141 args = new String[1];
142 args[0] = String.valueOf(folder_count);
143 suffix = Gatherer.dictionary.get("FileActions.Directories_Selected", args);
144 }
145 else {
146 suffix = Gatherer.dictionary.get("FileActions.Directory_Selected");
147 }
148 }
149 else {
150 Gatherer.dictionary.get("FileActions.No_Selection");
151 }
152 args = null;
153 }
154 return suffix;
155 }
156
157 /** Any implementation of MouseListener must include this method so
158 * we can be informed when the mouse is clicked.
159 * @param event A MouseEvent containing all the information about
160 * this mouse click.
161 */
162 public void mouseClicked(MouseEvent event) {
163 }
164
165 /** Any implementation of MouseListener must include this method so
166 * we can be informed when the mouse enters a component.
167 * @param event A MouseEvent containing all the information about
168 * this mouse action.
169 */
170 public void mouseEntered(MouseEvent event) {
171 }
172
173 /** Any implementation of MouseListener must include this method so
174 * we can be informed when the mouse exits a component.
175 * @param event A MouseEvent containing all the information about
176 * this mouse action.
177 */
178 public void mouseExited(MouseEvent event) {
179 }
180
181 /** Any implementation of MouseListener must include this method so
182 * we can be informed when the mouse is pressed (start of click).
183 * @param event A MouseEvent containing all the information about
184 * this mouse action.
185 */
186 public void mousePressed(MouseEvent event) {
187 }
188
189 /** Any implementation of MouseListener must include this method so
190 * we can be informed when the mouse is released (end of click).
191 * @param event A MouseEvent containing all the information about
192 * this mouse action.
193 */
194 public void mouseReleased(MouseEvent event) {
195 switch(this.type) {
196 case 0: // this.ADD
197 if(this.temp_path != null && isAppropriate(temp_path)) {
198 super.addSelectionPath(this.temp_path);
199 this.temp_path = null;
200 }
201 if(this.temp_paths != null && isAppropriate(temp_paths, true)) {
202 super.addSelectionPaths(this.temp_paths);
203 this.temp_paths = null;
204 }
205 this.type = this.NONE;
206 suffix = null;
207 break;
208 case 1: // this.SET
209 if(this.temp_path != null) {
210 super.setSelectionPath(this.temp_path);
211 this.temp_path = null;
212 }
213 if(this.temp_paths != null && isAppropriate(temp_paths, false)) {
214 super.setSelectionPaths(this.temp_paths);
215 this.temp_paths = null;
216 }
217 this.type = this.NONE;
218 suffix = null;
219 break;
220 }
221 }
222
223 public void setImmediate(boolean value) {
224 immediate = value;
225 }
226
227 public void setSelectionPath(TreePath path) {
228 // Since this is only a single path we don't need to check whether its an appropriate selection.
229 if(!immediate) {
230 this.temp_path = path;
231 this.type = this.SET;
232 }
233 else {
234 temp_path = null;
235 super.setSelectionPath(path);
236 suffix = null;
237 }
238 }
239
240 public void setSelectionPaths(TreePath paths[]) {
241 if(!immediate) {
242 this.temp_paths = paths;
243 this.type = this.SET;
244 }
245 else if(isAppropriate(paths, false)) {
246 temp_paths = null;
247 super.setSelectionPaths(paths);
248 suffix = null;
249 }
250 }
251
252 /** Ensure that the given path is appropriate to add to the current selection, preventing mixed selections of files and folder. We also must check that no path is a ancestor/descendant of another. There is also a slight optimization in that if the current selection contains only files (which if the rules are followed, and the first 'test' node is a file, then it must) there is no point in checking the remaining files in the selection. Its a different story for folders however as we have to ensure no folder is in the lineage of another, even if they are all folders! */
253 private boolean isAppropriate(TreePath path) {
254 boolean appropriate = true;
255 TreeNode new_node = (TreeNode) path.getLastPathComponent();
256 if(selection != null && selection.length > 0) {
257 TreeNode test_node = (TreeNode) selection[0].getLastPathComponent();
258 appropriate = appropriate && (new_node.isLeaf() == test_node.isLeaf());
259 if(!test_node.isLeaf()) {
260 appropriate = appropriate && !path.isDescendant(selection[0]) && !selection[0].isDescendant(path);
261 for(int i = 1; appropriate && selection != null && i < selection.length; i++) {
262 TreeNode current_node = (TreeNode) selection[i].getLastPathComponent();
263 appropriate = appropriate && (new_node.isLeaf() == current_node.isLeaf());
264 appropriate = appropriate && !path.isDescendant(selection[i]) && !selection[i].isDescendant(path);
265 }
266 }
267 }
268 return appropriate;
269 }
270 /** Ensure that the given paths are appropriate to add to the current selection, preventing mixed selections of files and folder. We also must check that no path is a ancestor/descendant of another. One last detail to keep in mind is that adding selections depends upon the current selection, whereas set the selection paths doesn't (replaces them instead) and thus no check of the current paths is needed. */
271 private boolean isAppropriate(TreePath[] paths, boolean check_current) {
272 boolean appropriate = true;
273 if(paths != null) {
274 if(paths.length >= 2) {
275 // Prevent folders being added to a previous selection of files and vice-versa
276 // First check that the new selection are all of the same type
277 for(int i = 0; appropriate && paths != null && i < paths.length - 1; i++) {
278 TreeNode one_node = (TreeNode) paths[i].getLastPathComponent();
279 TreeNode other_node = (TreeNode) paths[i+1].getLastPathComponent();
280 appropriate = appropriate && (one_node.isLeaf() == other_node.isLeaf());
281 appropriate = appropriate && !paths[i].isDescendant(paths[i+1]) && !paths[i+1].isDescendant(paths[i]);
282 }
283 }
284 // Now we check the current selection against the first node in our new selection
285 if(appropriate && check_current) {
286 appropriate = isAppropriate(paths[0]);
287 }
288 }
289 return appropriate;
290 }
291}
292
Note: See TracBrowser for help on using the repository browser.