1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.xnap.gui.tree;
21
22 import java.awt.Component;
23 import java.awt.event.ActionEvent;
24 import java.beans.PropertyChangeEvent;
25 import java.beans.PropertyChangeListener;
26 import java.io.File;
27 import java.util.Arrays;
28 import java.util.LinkedList;
29 import java.util.List;
30
31 import javax.swing.AbstractAction;
32 import javax.swing.*;
33 import javax.swing.JPopupMenu;
34 import javax.swing.tree.TreePath;
35 import javax.swing.tree.TreeSelectionModel;
36
37 import org.apache.log4j.Logger;
38 import org.xnap.XNap;
39 import org.xnap.gui.*;
40 import org.xnap.gui.StatusBar;
41 import org.xnap.gui.action.EnqueueDirectoryAction;
42 import org.xnap.gui.action.PlayDirectoryAction;
43 import org.xnap.gui.component.XNapMenuItem;
44 import org.xnap.gui.event.PopupListener;
45 import org.xnap.gui.util.*;
46 import org.xnap.search.MediaType;
47 import org.xnap.search.SearchManager;
48 import org.xnap.util.Preferences;
49
50 /***
51 * LibraryTree handles all things having to do with the tree on the left side
52 * of the {@link org.xnap.gui.LibraryPanel}.
53 */
54 public class LibraryTree extends DroppableTree
55 implements PropertyChangeListener, DirectoryProvider
56 {
57
58
59
60
61
62 private FileTreeModel ftm;
63 private JPopupMenu popup = new JPopupMenu();
64 private Preferences prefs = Preferences.getInstance();
65
66 private static Logger logger = Logger.getLogger(LibraryTree.class);
67
68
69
70 public LibraryTree(Component parent)
71 {
72 super(new FileTreeModel(XNap.tr("Files")), parent);
73 ftm = (FileTreeModel)getModel();
74 initialize();
75 prefs.addPropertyChangeListener(this);
76 }
77
78
79
80 private void initialize()
81 {
82 setCellRenderer(new FileCellRenderer());
83 putClientProperty("JTree.lineStyle", "Angled");
84
85
86 popup.add(new XNapMenuItem(new PlayDirectoryAction(this)));
87 popup.add(new XNapMenuItem(new EnqueueDirectoryAction(this)));
88 popup.addSeparator();
89 popup.add(new XNapMenuItem(new ShareDirectoryAction()));
90 popup.add(new XNapMenuItem(new UnshareDirectoryAction()));
91 popup.add(new XNapMenuItem(new UnshareAllDirectoriesAction()));
92 popup.addSeparator();
93 popup.add(new XNapMenuItem(new AddToLibraryAction()));
94 popup.add(new XNapMenuItem(new RemoveFromLibraryAction()));
95 popup.addSeparator();
96 popup.add(new XNapMenuItem(new ReloadTreeAction()));
97
98 addMouseListener(new PopupListener(popup));
99
100
101 getSelectionModel().setSelectionMode
102 (TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
103
104 updateTree();
105 }
106
107 /***
108 * Adds the main download directory and all configured media type download
109 * directories to the tree.
110 */
111 private void addDownloadDirs()
112 {
113
114 ftm.addChildOfSubRoot(new File(prefs.getDownloadDir()),
115 XNap.tr("Downloaded Files"));
116
117 MediaType[] types = SearchManager.DEFAULT_MEDIA_TYPES;
118 for (int i = 1; i < types.length; i++) {
119 String dir = prefs.getMediaTypeDownloadDir(types[i].getRealm());
120
121 if (dir.length() > 0) {
122 ftm.addChildOfSubRoot(new File(dir),
123 XNap.tr("Downloaded Files"),
124 " (" + types[i].getName() + ")");
125 }
126 }
127 }
128
129 /***
130 * Returns the menu which pops up over the tree.
131 */
132 public JPopupMenu getPopupMenu()
133 {
134 return popup;
135 }
136
137 /***
138 * Returns the currently selected directory.
139 *
140 * Implements the {@link DirectoryProvider} interface.
141 */
142 public File getDirectory()
143 {
144 TreePath selected = getSelectionPath();
145 if (selected != null) {
146 Object o = selected.getLastPathComponent();
147 if (o instanceof File) {
148 return (File)o;
149 }
150 }
151 return null;
152 }
153
154 /***
155 * Implements the {@link DirectoryProvider} interface.
156 *
157 * Since we don't care for the content of the directories we don't do
158 * anything here.
159 */
160 public void hasChanged(File directory)
161 {
162
163 }
164
165 /***
166 * Implements the {@link PropertyChangeListener} interface.
167 */
168 public void propertyChange(PropertyChangeEvent e)
169 {
170 String p = e.getPropertyName();
171
172 if (e.getSource() == prefs) {
173 if (p.equals("incompleteDir")) {
174 ftm.removeChildrenOfSubRoot(XNap.tr("Incomplete Files"));
175 ftm.addChildOfSubRoot(new File(prefs.getIncompleteDir()),
176 XNap.tr("Incomplete Files"));
177 }
178 else if (p.equals("libraryDirs")) {
179 ftm.removeChildrenOfSubRoot(XNap.tr("Library Directories"));
180 String[] dirs = prefs.getLibraryDirs();
181 for (int i = 0; i < dirs.length; i++) {
182 ftm.addChildOfSubRoot(new File(dirs[i]),
183 XNap.tr("Library Directories"));
184 }
185 }
186 else if (p.equals("uploadDirs")) {
187 ftm.removeChildrenOfSubRoot(XNap.tr("Shared Directories"));
188 String[] dirs = prefs.getUploadDirs();
189 for (int i = 0; i < dirs.length; i++) {
190 ftm.addChildOfSubRoot(new File(dirs[i]),
191 XNap.tr("Shared Directories"));
192 }
193 }
194 else if (p.equals("downloadDir") || p.indexOf("DownloadDir")
195 != -1) {
196 ftm.removeChildrenOfSubRoot(XNap.tr("Downloaded Files"));
197 addDownloadDirs();
198 }
199 }
200 }
201
202 /***
203 * Clears the tree and adds a couple of nodes.
204 */
205 public void updateTree()
206 {
207 ftm.removeSubRoots();
208
209 int failed = 0;
210 String[] nodes = prefs.getLibraryTreeNodesArray();
211 for (int j = 0; j < nodes.length; j++) {
212 if (nodes[j].equals("library")) {
213
214 ftm.addSubRoot(XNap.tr("Library Directories"));
215 String[] dirs = prefs.getLibraryDirs();
216 for (int i = 0; i < dirs.length; i++) {
217 ftm.addChildOfSubRoot(new File(dirs[i]),
218 XNap.tr("Library Directories"));
219 }
220 expandRow(getRowCount() - 1);
221 }
222 else if (nodes[j].equals("shares")) {
223
224 ftm.addSubRoot(XNap.tr("Shared Directories"));
225 String[] dirs = prefs.getUploadDirs();
226 for (int i = 0; i < dirs.length; i++) {
227 ftm.addChildOfSubRoot(new File(dirs[i]),
228 XNap.tr("Shared Directories"));
229 }
230 expandRow(getRowCount() - 1);
231 }
232 else if (nodes[j].equals("incompletes")) {
233
234 ftm.addChildOfSubRoot(new File(prefs.getIncompleteDir()),
235 XNap.tr("Incomplete Files"));
236
237 expandRow(getRowCount() - 1);
238 }
239 else if (nodes[j].equals("downloads")) {
240 addDownloadDirs();
241 expandRow(getRowCount() - 1);
242 }
243 else if (nodes[j].equals("home")) {
244 ftm.addChildOfSubRoot(new File
245 (System.getProperty("user.home")),
246 XNap.tr("Home Directory"));
247 expandRow(getRowCount() - 1);
248 }
249 else if (nodes[j].equals("root")) {
250
251 File[] roots = File.listRoots();
252 for (int i = 0; i < roots.length; i++) {
253 ftm.addChildOfSubRoot(roots[i], XNap.tr("Root Directory"));
254 }
255 expandRow(getRowCount() - 1);
256 }
257 else {
258 failed++;
259 }
260 }
261
262 if (failed == nodes.length) {
263
264 ftm.addSubRoot(XNap.tr("Root Directory"));
265 File[] roots = File.listRoots();
266 for (int i = 0; i < roots.length; i++) {
267 ftm.addChildOfSubRoot(roots[i], XNap.tr("Root Directory"));
268 }
269 expandRow(getRowCount() - 1);
270 }
271 }
272
273
274 /***
275 * Adds selected directories to the {@link org.xnap.gui.LibraryPanel}.
276 */
277 private class AddToLibraryAction extends AbstractAction
278 {
279 public AddToLibraryAction()
280 {
281 putValue(Action.NAME, XNap.tr("Add Directory To Library"));
282 putValue(Action.SHORT_DESCRIPTION,
283 XNap.tr("Add selected directories to the Library."));
284 putValue(IconHelper.XNAP_ICON, "edit_add.png");
285 }
286
287 public void actionPerformed(ActionEvent event)
288 {
289 TreePath[] selected = getSelectionPaths();
290
291 if (selected == null)
292 return;
293
294 List dirs = new LinkedList(Arrays.asList(prefs.getLibraryDirs()));
295
296 for (int i = 0; i < selected.length; i++) {
297 Object o = selected[i].getLastPathComponent();
298 if (o instanceof FileNode) {
299 String path = ((FileNode)o).getAbsolutePath();
300 if (!dirs.contains(path)) {
301 dirs.add(path);
302 }
303 else {
304 StatusBar.setText(XNap.tr("\"{0}\" is already in Library",
305 o));
306 }
307 }
308 else {
309 StatusBar.setText(XNap.tr("\"{0}\" is not a directory",
310 o));
311 }
312 }
313 prefs.setLibraryDirs((String[])dirs.toArray(new String[0]));
314 }
315 }
316
317 /***
318 * Remove selected directories from the {@link org.xnap.gui.LibraryPanel}.
319 */
320 private class RemoveFromLibraryAction extends AbstractAction
321 {
322
323 public RemoveFromLibraryAction()
324 {
325 putValue(Action.NAME, XNap.tr("Remove Directory From Library"));
326 putValue(Action.SHORT_DESCRIPTION,
327 XNap.tr("Remove selected directories from the Library."));
328 putValue(IconHelper.XNAP_ICON, "edit_remove.png");
329 }
330
331 public void actionPerformed(ActionEvent event)
332 {
333 TreePath[] selected = getSelectionPaths();
334
335 if (selected == null)
336 return;
337
338 List dirs = new LinkedList(Arrays.asList(prefs.getLibraryDirs()));
339
340 for (int i = 0; i < selected.length; i++) {
341 Object o = selected[i].getLastPathComponent();
342 if (o instanceof FileNode) {
343 if (!dirs.remove(((FileNode)o).getAbsolutePath())) {
344 StatusBar.setText(XNap.tr("Could not remove \"{0}\"",
345 o));
346 }
347 }
348 }
349 prefs.setLibraryDirs((String[])dirs.toArray(new String[0]));
350 }
351 }
352
353 /***
354 * Share selected directories.
355 */
356 private class ShareDirectoryAction extends AbstractAction
357 {
358
359 public ShareDirectoryAction()
360 {
361 putValue(Action.NAME, XNap.tr("Share Directory"));
362 putValue(Action.SHORT_DESCRIPTION,
363 XNap.tr("Shares selected directory."));
364 putValue(IconHelper.XNAP_ICON, "connect_established.png");
365 }
366
367 public void actionPerformed(ActionEvent event)
368 {
369 int response = Dialogs.showConfirmDialog
370 (XNapFrame.getInstance(), "ShareFolder",
371 XNap.tr("Share Directory"),
372 XNap.tr("Please note: Directories are shared <b>recursively</b>, all subdirectories and their content may be publicly accessible to anyone. <br><p><b>Please make sure you act in accordance to your local copyright law when sharing data.</b>"),
373
374 JOptionPane.OK_CANCEL_OPTION, prefs);
375 if (response == JOptionPane.CANCEL_OPTION) {
376 return;
377 }
378
379 TreePath[] selected = getSelectionPaths();
380
381 if (selected == null)
382 return;
383
384 List dirs = new LinkedList(Arrays.asList(prefs.getUploadDirs()));
385
386 for (int i = 0; i < selected.length; i++) {
387 Object o = selected[i].getLastPathComponent();
388 if (o instanceof FileNode) {
389 String path = ((FileNode)o).getAbsolutePath();
390 if (!dirs.contains(path)) {
391 dirs.add(path);
392 }
393 else {
394 StatusBar.setText(XNap.tr("\"{0}\" is already shared",
395 o));
396 }
397 }
398 else {
399 StatusBar.setText(XNap.tr("\"{0}\" is not a directory",
400 o));
401 }
402 }
403 prefs.setUploadDirs((String[])dirs.toArray(new String[0]));
404 }
405 }
406
407 /***
408 * Unshare selected directories.
409 */
410 private class UnshareDirectoryAction extends AbstractAction
411 {
412
413 public UnshareDirectoryAction()
414 {
415 putValue(Action.NAME, XNap.tr("Unshare Directory"));
416 putValue(Action.SHORT_DESCRIPTION,
417 XNap.tr("Unshares selected directory."));
418 putValue(IconHelper.XNAP_ICON, "connect_no.png");
419 }
420
421 public void actionPerformed(ActionEvent event)
422 {
423 TreePath[] selected = getSelectionPaths();
424
425 if (selected == null)
426 return;
427
428 List dirs = new LinkedList(Arrays.asList(prefs.getUploadDirs()));
429
430 for (int i = 0; i < selected.length; i++) {
431 Object o = selected[i].getLastPathComponent();
432 if (o instanceof FileNode) {
433 if (!dirs.remove(((FileNode)o).getAbsolutePath())) {
434 StatusBar.setText(XNap.tr("Could not unshare \"{0}\".",
435 o));
436 }
437 }
438 }
439 prefs.setUploadDirs((String[])dirs.toArray(new String[0]));
440 }
441 }
442
443 /***
444 * Unshare selected directories.
445 */
446 private class UnshareAllDirectoriesAction extends AbstractAction
447 {
448
449 public UnshareAllDirectoriesAction()
450 {
451 putValue(Action.NAME, XNap.tr("Unshare All Directories"));
452 putValue(Action.SHORT_DESCRIPTION,
453 XNap.tr("Unshares all directories."));
454 putValue(IconHelper.XNAP_ICON, "connect_no.png");
455 }
456
457 public void actionPerformed(ActionEvent event)
458 {
459 prefs.setUploadDirs(new String[0]);
460 }
461 }
462
463 /***
464 * Refresh file and directory listings
465 */
466 private class ReloadTreeAction extends AbstractAction
467 {
468
469 public ReloadTreeAction()
470 {
471 putValue(Action.NAME, XNap.tr("Reload Tree"));
472 putValue(Action.SHORT_DESCRIPTION,
473 XNap.tr("Reload Tree"));
474 putValue(IconHelper.XNAP_ICON, "reload.png");
475 }
476
477 public void actionPerformed(ActionEvent event)
478 {
479 ftm.reload();
480 }
481 }
482 }
483
484
485