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

Last change on this file since 504 was 504, checked in by jts21, 11 years ago

New copy/paste handling, add pdfImporter, add dictionary and documentation to resources, other small changes

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