source: trunk/src/org/expeditee/dnd/FrameDNDTransferHandler.java@ 244

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