View Javadoc

1   package org.xnap.commons.gui.dnd;
2   
3   import java.awt.Component;
4   import java.awt.datatransfer.Transferable;
5   import java.io.File;
6   import java.util.ArrayList;
7   import java.util.List;
8   import javax.swing.JComponent;
9   import javax.swing.JTree;
10  import javax.swing.tree.TreePath;
11  import org.xnap.commons.gui.Dialogs;
12  import org.xnap.commons.i18n.I18n;
13  import org.xnap.commons.i18n.I18nFactory;
14  import org.xnap.commons.io.Job;
15  import org.xnap.commons.io.JobExecutor;
16  import org.xnap.commons.io.ProgressMonitor;
17  import org.xnap.commons.io.SubTaskProgressMonitor;
18  import org.xnap.commons.settings.BooleanSetting;
19  import org.xnap.commons.settings.PropertyResource;
20  import org.xnap.commons.util.FileHelper;
21  
22  /***
23   * Provides a default file transfer handler for {@link JTree}s.
24   * <p>
25   * When a drag from a tree is initiated all selected paths are collected and
26   * their {@link TreePath#getLastPathComponent() last path components}, if
27   * they are files, are added to the {@link FileTransferable} that is created.
28   * <p>
29   * To support dragging of files you have to enable it for the tree, see
30   * {@link JTree#setDragEnabled(boolean)}.
31   * <p> 
32   * When a transferable with files is dropped on the tree, the handler tries to
33   * copy the dropped files to the first directory that is selected in the tree. A
34   * confirmation dialog is shown before copying if the boolean setting 
35   * {@link #getShowCopyDialogSetting()} is true.
36   * 
37   * @author Felix Berger
38   */
39  public class DefaultTreeFileTransferHandler extends AbstractFileTransferHandler 
40  {
41  
42  	private final static I18n i18n = 
43  		I18nFactory.getI18n(DefaultTreeFileTransferHandler.class);
44  	
45  	private BooleanSetting showCopyDialog;
46  	
47  	/***
48  	 * Constructs a file transfer handler for {@link JTree}s.
49  	 * @param showCopyDialog the boolean setting which decides if a
50  	 * confirmation dialog is shown before dropped files are copied to the
51  	 * selected directory in the tree.
52  	 * 
53  	 * @throws NullPointerException if <code>showCopyDialog</code> is null.
54  	 */
55  	public DefaultTreeFileTransferHandler(BooleanSetting showCopyDialog)
56  	{
57  		if (showCopyDialog == null) {
58  			throw new NullPointerException("showCopyDialog must not be null");
59  		}
60  		this.showCopyDialog = showCopyDialog;
61  	}
62  	
63  	/***
64  	 * Convenience constructor which creates a dummy boolean setting that
65  	 * says the copy confirmation dialog should not be shown.
66  	 * <p>
67  	 * See {@link #DefaultTreeFileTransferHandler(BooleanSetting)} and
68  	 * {@link Dialogs#showCopyDialog(Component, File[], File, BooleanSetting)}. 
69  	 */
70  	public DefaultTreeFileTransferHandler()
71  	{
72  		this(new BooleanSetting(new PropertyResource(), "dummy", 
73  				Boolean.FALSE));
74  	}
75  	
76  	/***
77  	 * Sets the boolean setting which decides if a confirmation dialog is 
78  	 * shown before any files are copied.
79  	 * <p>
80  	 * See {@link Dialogs#showCopyDialog(Component, File[], File, BooleanSetting)}.
81  	 * 
82  	 * @throws NullPointerException if <code>setting</code> is null.
83  	 */
84  	public void setShowCopyDialogSetting(BooleanSetting setting)
85  	{
86  		if (setting == null) {
87  			throw new NullPointerException("setting must not be null");
88  		}
89  		showCopyDialog = setting;
90  	}
91  
92  	/***
93  	 * Returns the boolean setting which decides if a confirmation dialog
94  	 * is shown before any files are copied.
95  	 */
96  	public BooleanSetting getShowCopyDialogSetting()
97  	{
98  		return showCopyDialog;
99  	}
100 	
101 	/***
102 	 * 
103 	 * 
104 	 */
105 	@Override
106 	protected Transferable createTransferable(JComponent c) 
107 	{
108 		JTree tree = (JTree)c;
109 		TreePath[] selectedPaths = tree.getSelectionPaths();
110 		List<File> files = new ArrayList<File>(selectedPaths.length);
111 		for (TreePath path : selectedPaths) {
112 			if (path.getLastPathComponent() instanceof File) {
113 				files.add((File)path.getLastPathComponent());
114 			}
115 		}
116 		if (!files.isEmpty()) {
117 			return new FileTransferable(files);
118 		}
119 		return null;
120 	}
121 
122 	/***
123 	 * Returns <code>false</code> if no directory is selected in the tree 
124 	 * where the files could be dropped into or the selected file is not an
125 	 * existent directory. 
126 	 * <p>
127 	 * Otherwise <code>files</code> are copied to the specified directory
128 	 * while a progress dialog is displayed.
129 	 */
130 	@Override
131 	public boolean importFiles(JComponent comp, List<File> files) 
132 	{
133 		final JTree tree = (JTree)comp;
134 		TreePath selectedPath = tree.getSelectionPath();
135 		if (selectedPath == null) {
136 			return  false;
137 		}
138 		final File dir = (File)selectedPath.getLastPathComponent();
139 		if (!dir.isDirectory()) {
140 			return false;
141 		}
142 		final File[] filesToCopy = Dialogs.showCopyDialog
143 			(tree, files.toArray(new File[0]), dir, 
144 					new BooleanSetting(new PropertyResource(), "dummy", 
145 							Boolean.TRUE));
146 		
147 		try {
148 			JobExecutor.run(i18n.tr("Copying Files"), new CopyRunner(filesToCopy, dir));
149 		}
150 		catch (Exception e) {
151 			Dialogs.showError(tree, i18n.tr("Error copying files"), e);
152 		}
153 		return false;
154 	}
155 	
156 	private class CopyRunner implements Job<Object>
157 	{
158 		private File[] files;
159 		private File targetPath;
160 
161 		public CopyRunner(File[] files, File targetPath)
162 		{
163 			this.files = files;
164 			this.targetPath = targetPath;
165 		}
166 
167 		public Object run(ProgressMonitor monitor) throws Exception
168 		{
169 			monitor.setTotalSteps(files.length * 100);
170 			for (File file : files) {
171 				File dest = FileHelper.createUnique(targetPath, file.getName());
172 				monitor.setText(i18n.tr("Copying<br>{0}<br>to<br>{1}...", file, dest));
173 				FileHelper.copy(file, dest,	new SubTaskProgressMonitor(monitor, 
174 						100, file.length()));
175 				if (monitor.isCancelled()) {
176 					return null;
177 				}
178 			}
179 			return null;
180 		}
181 	}
182 }