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

Last change on this file since 1102 was 1102, checked in by davidb, 6 years ago

Reworking of the code-base to separate logic from graphics. This version of Expeditee now supports a JFX graphics as an alternative to SWING

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