source: trunk/src/org/expeditee/FrameDNDTransferHandler.java@ 139

Last change on this file since 139 was 139, checked in by bjn8, 16 years ago
File size: 8.0 KB
Line 
1package org.expeditee;
2
3import java.awt.Point;
4import java.awt.datatransfer.DataFlavor;
5import java.awt.datatransfer.UnsupportedFlavorException;
6import java.io.File;
7import java.io.IOException;
8import java.net.URI;
9import java.net.URISyntaxException;
10import java.util.LinkedList;
11import java.util.List;
12import java.util.StringTokenizer;
13
14import javax.swing.TransferHandler;
15
16import org.expeditee.gui.Browser;
17import org.expeditee.gui.DisplayIO;
18import org.expeditee.gui.MessageBay;
19import org.expeditee.io.FileImporter;
20import org.expeditee.io.FilePathImporter;
21import org.expeditee.items.Text;
22
23/**
24 *
25 * Expeditee's transfer handler (swing's drag and drop scheme) for importing data into frames.
26 *
27 * @author Brook Novak
28 *
29 */
30public class FrameDNDTransferHandler extends TransferHandler {
31
32 private static final long serialVersionUID = 1L;
33
34 private List<FileImporter> _customFileImporters = new LinkedList<FileImporter>();
35 private List<FileImporter> _standardFileImporters = new LinkedList<FileImporter>();
36
37 // GNOME and KDE desktops have a specialized way of DNDing files
38 private DataFlavor _URIListDataflavor;
39
40 private static FrameDNDTransferHandler _instance = new FrameDNDTransferHandler();
41 public static FrameDNDTransferHandler getInstance() {
42 return _instance;
43 }
44
45 private FrameDNDTransferHandler() {
46
47 // Add standard file importers - order from most ideal to last resort (if competing)
48
49 // TODO: Image
50 _standardFileImporters.add(new FilePathImporter()); // Filepath importer as last resort
51
52 try {
53 _URIListDataflavor = new DataFlavor("text/uri-list;class=java.lang.String");
54 } catch (ClassNotFoundException e) { // This would never happen, java.lang.String is always present
55 e.printStackTrace();
56 _URIListDataflavor = null;
57 }
58 assert(_URIListDataflavor != null);
59 }
60
61 /**
62 * Adds a custom importer. If an importer competes with another importer for
63 * handling the same file types, the importer that was added first will have
64 * first serve.
65 *
66 * @param importer
67 * The importer to add. Must not be null
68 *
69 * @throws NullPointerException
70 * if importer is null.
71 */
72 public void addCustomFileImporter(FileImporter importer) {
73 if (importer == null) throw new NullPointerException("importer");
74 if (!_customFileImporters.contains(importer))
75 _customFileImporters.add(importer);
76 }
77
78 /**
79 * Removes a custom importer.
80 *
81 * @param importer
82 * The importer to remove.
83 *
84 * @throws NullPointerException
85 * if importer is null.
86 */
87 public void removeCustomFileImporter(FileImporter importer) {
88 if (importer == null) throw new NullPointerException("importer");
89 _customFileImporters.remove(importer);
90 }
91
92 @Override
93 public boolean canImport(TransferSupport support) {
94
95 if (!support.isDrop()) {
96 return false;
97 }
98
99 // we only import Strings
100 if (support.isDataFlavorSupported(DataFlavor.stringFlavor)
101 || support.isDataFlavorSupported(DataFlavor.javaFileListFlavor)
102 || support.isDataFlavorSupported(_URIListDataflavor)) {
103
104 // check if the source actions (a bitwise-OR of supported actions)
105 // contains the COPY action
106 boolean copySupported = (COPY & support.getSourceDropActions()) == COPY;
107 if (copySupported) {
108 support.setDropAction(COPY);
109 return true;
110 }
111 }
112
113 // Reject transfer
114 return false;
115 }
116
117 @Override
118 public boolean importData(TransferSupport support) {
119
120 if (!canImport(support) ||
121 DisplayIO.getCurrentFrame() == null) return false;
122
123 // Get the drop location of where to lot the import
124 DropLocation location = support.getDropLocation();
125
126 // Covert it into expeditee space
127 Point expediteeDropPoint = location.getDropPoint();
128
129 try {
130
131 // The list of data flavors are ordered by most rich to least .. keep trying until first
132 // data flavor recognized.
133 for (DataFlavor df : support.getTransferable().getTransferDataFlavors()) {
134
135 if (df == DataFlavor.stringFlavor) { // import as text item
136
137 String str = (String)support.getTransferable().getTransferData(DataFlavor.stringFlavor);
138
139 if (str != null && str.length() > 0) {
140 importString(str,expediteeDropPoint);
141 return true;
142 }
143
144 // Usually Windows and MAC enviroments
145 } else if (df == DataFlavor.javaFileListFlavor ||
146 df.getSubType().equals("x-java-file-list")) { // Windows has other random types...
147
148 List<? extends File> files = (List<? extends File>)support.getTransferable().getTransferData(DataFlavor.javaFileListFlavor);
149
150 importFileList(files, expediteeDropPoint);
151
152 return true;
153
154 // Usually GNOME and KDE enviroments
155 } else if (df.equals(_URIListDataflavor)) {
156
157 String data = (String)support.getTransferable().getTransferData(
158 _URIListDataflavor);
159
160 List<File> files = textURIListToFileList(data);
161
162 importFileList(files, expediteeDropPoint);
163
164 return true;
165
166 }
167
168 }
169
170 } catch (UnsupportedFlavorException e) {
171 MessageBay.displayMessage("Drag and drop for that type of data is not supported");
172 } catch (IOException e) {
173 e.printStackTrace();
174 MessageBay.displayMessage("Failed to import data in Expeditee");
175 }
176
177 return false;
178 }
179
180 /**
181 * Imports a string into expeditee's current frame
182 *
183 * @param text
184 * The text content.
185 *
186 * @param expediteeDropPoint
187 * The location in the current ecpeditee frame of where to drop the text item.
188 */
189 public static void importString(String text, Point expediteeDropPoint) {
190
191 assert(DisplayIO.getCurrentFrame() != null);
192 assert(text != null && text.length() > 0);
193
194 Text importedTextItem = new Text(DisplayIO.getCurrentFrame().getNextItemID(), text);
195 importedTextItem.setPosition(expediteeDropPoint);
196
197 DisplayIO.getCurrentFrame().addItem(importedTextItem);
198
199 }
200
201 private void importFileList(List<? extends File> files, Point expediteeDropPoint) throws IOException {
202
203 Point currentPoint = expediteeDropPoint.getLocation();
204
205 for (File fileToImport : files) { // import files one by one
206
207 importFile(fileToImport, currentPoint);
208
209 currentPoint.y += 30;
210
211 // TODO: Better placement strategy
212 if (currentPoint.y > (Browser._theBrowser.getHeight() - 20))
213 currentPoint.y = Browser._theBrowser.getHeight() - 20;
214 }
215 }
216
217 /**
218 * Imports a file into expeditee.
219 *
220 * @param f
221 * The file to import.
222 *
223 * @param expediteeDropPoint
224 *
225 * @throws IOException
226 */
227 public void importFile(File f, Point expediteeDropPoint) throws IOException {
228 assert(f != null);
229
230 // Check for custom importers first. They get preference to standard
231 // importing routines...
232 if (!performFileImport(_customFileImporters, f, expediteeDropPoint)) {
233
234 // Standard file importing
235 performFileImport(_standardFileImporters, f, expediteeDropPoint);
236
237 }
238
239 }
240
241 private boolean performFileImport(List<FileImporter> importers, File f, Point expediteeDropPoint) throws IOException {
242
243 for (FileImporter fi : importers) {
244 if (fi.importFile(f, expediteeDropPoint)) return true;
245 }
246
247 return false;
248 }
249
250 /**
251 * Code adopted from SUN - java BUG ID 4899516 workaround for KDE/GNOME Desktops
252 *
253 * @param uriListString
254 * Formatted according to RFC 2483
255 *
256 * @return
257 * The list of FILES in the uriListString. Never null.
258 */
259 private List<File> textURIListToFileList(String uriListString) {
260
261 List<File> fileList = new LinkedList<File>();
262
263 for (StringTokenizer st = new StringTokenizer(uriListString, "\r\n"); st.hasMoreTokens(); ) {
264
265 String s = st.nextToken();
266
267 if (s.startsWith("#")) {
268 // the line is a comment (as per the RFC 2483)
269 continue;
270 }
271
272 try {
273
274 URI uri = new URI(s);
275 File file = new File(uri);
276 fileList.add(file);
277
278 } catch (URISyntaxException e) {
279 // malformed URI
280 } catch (IllegalArgumentException e) {
281 // the URI is not a valid 'file:' URI
282 }
283 }
284
285 return fileList;
286 }
287}
Note: See TracBrowser for help on using the repository browser.