source: trunk/src/org/expeditee/importer/FrameDNDTransferHandler.java@ 253

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