/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/textarea/TextAreaTransferHandler.java
Java | 438 lines | 323 code | 55 blank | 60 comment | 54 complexity | aeb04be21c7a0d80364b2e64bfe33c4b MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
1/*
2 * TextAreaTransferHandler.java - Drag and drop support
3 * :tabSize=8:indentSize=8:noTabs=false:
4 * :folding=explicit:collapseFolds=1:
5 *
6 * Copyright (C) 2004 Slava Pestov
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23package org.gjt.sp.jedit.textarea;
24
25//{{{ Imports
26import javax.swing.*;
27import java.awt.datatransfer.*;
28import java.io.File;
29import java.util.Iterator;
30import java.util.List;
31import java.net.URI;
32import org.gjt.sp.jedit.Buffer;
33import org.gjt.sp.jedit.EditPane;
34import org.gjt.sp.jedit.GUIUtilities;
35import org.gjt.sp.jedit.jEdit;
36import org.gjt.sp.util.Log;
37//}}}
38
39class TextAreaTransferHandler extends TransferHandler
40{
41 /* I assume that there can be only one drag operation at the time */
42 private static JEditTextArea dragSource;
43 private static boolean compoundEdit;
44 private static boolean sameTextArea;
45 private static int insertPos;
46 private static int insertOffset;
47
48 // Unfortunately, this does not work, as this DataFlavor is internally changed into another DataFlavor which does not match the intented DataFlavor anymore. :-( So, below, we are iterating.
49 /*
50 protected static DataFlavor textURIlistDataFlavor = null;
51
52 static {
53 try {
54 textURIlistDataFlavor = new DataFlavor("text/uri-list;representationclass=java.lang.String");
55 } catch (ClassNotFoundException e) {
56 throw new RuntimeException("Cannot create DataFlavor. This should not happen.",e);
57 }
58 }
59 */
60
61 //{{{ createTransferable
62 protected Transferable createTransferable(JComponent c)
63 {
64 Log.log(Log.DEBUG,this,"createTransferable()");
65 JEditTextArea textArea = (JEditTextArea)c;
66 if(textArea.getSelectionCount() == 0)
67 return null;
68 else
69 {
70 dragSource = textArea;
71 return new TextAreaSelection(textArea);
72 }
73 } //}}}
74
75 //{{{ getSourceActions
76 public int getSourceActions(JComponent c)
77 {
78 return COPY_OR_MOVE;
79 } //}}}
80
81 //{{{ importData
82 public boolean importData(JComponent c, Transferable t)
83 {
84 Log.log(Log.DEBUG,this,"Import data");
85// Log.log(Log.DEBUG,this,"Import data: t.isDataFlavorSupported("+textURIlistDataFlavor+")="+t.isDataFlavorSupported(textURIlistDataFlavor)+".");
86 if(!canImport(c,t.getTransferDataFlavors()))
87 return false;
88
89 boolean returnValue;
90
91 try
92 {
93 if(t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
94 {
95 returnValue = importFile(c,t);
96 }
97 else {
98 DataFlavor uriListStringDataFlavor = null;
99 DataFlavor[] dataFlavors = t.getTransferDataFlavors();
100
101 for (int i = 0;i<dataFlavors.length;i++) {
102 DataFlavor dataFlavor = dataFlavors[i];
103 if (dataFlavor.getPrimaryType().equals("text")&&dataFlavor.getSubType().equals("uri-list")&&(dataFlavor.getRepresentationClass()==String.class)) {
104 uriListStringDataFlavor = dataFlavor;
105 break;
106 }
107 }
108
109 if ((uriListStringDataFlavor!=null)&&t.isDataFlavorSupported(uriListStringDataFlavor))
110 {
111 returnValue = importURIList(c,t,uriListStringDataFlavor);
112 }
113 else
114 {
115 returnValue = importText(c,t);
116 }
117 }
118 }
119 catch(Exception e)
120 {
121 Log.log(Log.ERROR,this,e);
122 returnValue = false;
123 }
124
125 GUIUtilities.getView(c).toFront();
126 GUIUtilities.getView(c).requestFocus();
127 c.requestFocus();
128
129 return returnValue;
130 } //}}}
131
132 //{{{ importFile
133 private boolean importFile(JComponent c, Transferable t)
134 throws Exception
135 {
136 Log.log(Log.DEBUG,this,"=> File list");
137 EditPane editPane = (EditPane)
138 GUIUtilities.getComponentParent(
139 c,EditPane.class);
140
141 Buffer buffer = null;
142
143 Object data = t.getTransferData(
144 DataFlavor.javaFileListFlavor);
145
146 Iterator iterator = ((List)data)
147 .iterator();
148
149 while(iterator.hasNext())
150 {
151 File file = (File)
152 iterator.next();
153 Buffer _buffer = jEdit.openFile(null,
154 file.getPath());
155 if(_buffer != null)
156 buffer = _buffer;
157 }
158
159 if(buffer != null)
160 editPane.setBuffer(buffer);
161 editPane.getView().toFront();
162 editPane.getView().requestFocus();
163 editPane.requestFocus();
164
165 return true;
166 } //}}}
167
168 //{{{ importText
169 private boolean importURIList(JComponent c, Transferable t,DataFlavor uriListStringDataFlavor)
170 throws Exception
171 {
172 String str = (String) t.getTransferData(uriListStringDataFlavor);
173
174 Log.log(Log.DEBUG,this,"=> URIList \""+str+"\"");
175
176 JEditTextArea textArea = (JEditTextArea) c;
177 if (dragSource == null)
178 {
179 String maybeManyFileURI = str;
180 boolean found = false;
181 String[] components = str.split("\r\n");
182
183 for (int i = 0;i<components.length;i++)
184 {
185 String str0 = components[i];
186
187 if (str0.length()>0) {
188 URI uri = new URI(str0); // this handles the URI-decoding
189
190 if ("file".equals(uri.getScheme()))
191 {
192 org.gjt.sp.jedit.io.VFSManager.runInWorkThread(new DraggedURLLoader(textArea,uri.getPath()));
193 found = true;
194 }
195 else
196 {
197 Log.log(Log.DEBUG,this,"I do not know how to handle this URI "+uri+", ignoring.");
198 }
199 }
200 else
201 {
202 // This should be the last component, because every URI in the list is terminated with a "\r\n", even the last one.
203 if (i!=components.length-1)
204 {
205 Log.log(Log.DEBUG,this,"Odd: there is an empty line in the uri list which is not the last line.");
206 }
207 }
208 }
209
210 if (found)
211 {
212 return true;
213 }
214 }
215
216 return true;
217 }
218
219 //{{{ importText
220 private boolean importText(JComponent c, Transferable t)
221 throws Exception
222 {
223 String str = (String)t.getTransferData(
224 DataFlavor.stringFlavor);
225 str = str.trim();
226 Log.log(Log.DEBUG,this,"=> String \""+str+"\"");
227
228 JEditTextArea textArea = (JEditTextArea)c;
229 if (dragSource == null)
230 {
231 String maybeManyFileNames = str;
232 boolean found = false;
233 String[] components = str.split("\n");
234
235 for (int i = 0;i<components.length;i++)
236 {
237 String str0 = components[i];
238 // Only examine the string for a URL if it came from
239 // outside of jEdit.
240 org.gjt.sp.jedit.io.VFS vfs = org.gjt.sp.jedit.io.VFSManager.getVFSForPath(str0);
241 if (!(vfs instanceof org.gjt.sp.jedit.io.FileVFS) || str.startsWith("file://"))
242 {
243
244// str = str.replace('\n',' ').replace('\r',' ').trim();
245 if (str0.startsWith("file://"))
246 {
247 str0 = str0.substring(7);
248 }
249
250 org.gjt.sp.jedit.io.VFSManager.runInWorkThread(new DraggedURLLoader(textArea,str0));
251 }
252 found = true;
253
254 }
255
256 if (found) {
257 return true;
258 }
259 }
260
261 if(dragSource != null
262 && textArea.getBuffer()
263 == dragSource.getBuffer())
264 {
265 compoundEdit = true;
266 textArea.getBuffer().beginCompoundEdit();
267 }
268
269
270 sameTextArea = (textArea == dragSource);
271
272 int caret = textArea.getCaretPosition();
273 Selection s = textArea.getSelectionAtOffset(caret);
274
275 /* if user drops into the same
276 selection where they started, do
277 nothing. */
278 if(s != null)
279 {
280 if(sameTextArea)
281 return false;
282 /* if user drops into a selection,
283 replace selection */
284 int startPos = s.start;
285 textArea.setSelectedText(s,str);
286 textArea.setSelection(new Selection.Range(startPos,startPos+str.length()));
287 }
288 /* otherwise just insert the text */
289 else
290 {
291 if (sameTextArea)
292 {
293 insertPos = caret;
294 insertOffset = 0;
295 Selection[] selections = textArea.getSelection();
296 for (int i=0;i<selections.length;i++)
297 {
298 if (selections[i].end<(insertPos+insertOffset))
299 insertOffset-=(selections[i].end-selections[i].start);
300 }
301 }
302 else
303 {
304 textArea.getBuffer().insert(caret,str);
305 textArea.setSelection(new Selection.Range(caret,caret+str.length()));
306 }
307 }
308 textArea.scrollToCaret(true);
309
310 return true;
311 } //}}}
312
313 //{{{ exportDone
314 protected void exportDone(JComponent c, Transferable t,
315 int action)
316 {
317 Log.log(Log.DEBUG,this,"Export done");
318
319 JEditTextArea textArea = (JEditTextArea)c;
320
321 try
322 {
323 // This happens if importData returns false. For example if you drop into the Selection
324 if (action == NONE)
325 {
326 Log.log(Log.DEBUG,this,"Export impossible");
327 return;
328 }
329
330 if(t == null)
331 {
332 Log.log(Log.DEBUG,this,"=> Null transferrable");
333 textArea.selectNone();
334 }
335 else if(t.isDataFlavorSupported(
336 DataFlavor.stringFlavor))
337 {
338 Log.log(Log.DEBUG,this,"=> String");
339 if (sameTextArea)
340 {
341 if(action == MOVE)
342 {
343 textArea.setSelectedText(null,false);
344 insertPos += insertOffset;
345 }
346 try
347 {
348 String str = (String)t.getTransferData(DataFlavor.stringFlavor);
349 textArea.getBuffer().insert(insertPos,str);
350 textArea.setSelection(new Selection.Range(insertPos,insertPos+str.length()));
351 }
352 catch(Exception e)
353 {
354 Log.log(Log.DEBUG,this,"exportDone in sameTextArea");
355 Log.log(Log.DEBUG,this,e);
356 }
357 }
358 else
359 {
360 if(action == MOVE)
361 textArea.setSelectedText(null,false);
362 else
363 textArea.selectNone();
364 }
365 }
366 }
367 finally
368 {
369 if(compoundEdit)
370 {
371 compoundEdit = false;
372 textArea.getBuffer().endCompoundEdit();
373 }
374 }
375
376 dragSource = null;
377 } //}}}
378
379 //{{{ canImport
380 public boolean canImport(JComponent c, DataFlavor[] flavors)
381 {
382 JEditTextArea textArea = (JEditTextArea)c;
383
384 // correctly handle text flavor + file list flavor
385 // + text area read only, do an or of all flags
386 boolean returnValue = false;
387
388 for(int i = 0; i < flavors.length; i++)
389 {
390 if(flavors[i].equals(
391 DataFlavor.javaFileListFlavor))
392 {
393 returnValue = true;
394 }
395 else if(flavors[i].equals(
396 DataFlavor.stringFlavor))
397 {
398 if(textArea.isEditable())
399 returnValue = true;
400 }
401 }
402
403 Log.log(Log.DEBUG,this,"canImport() returning "
404 + returnValue);
405 return returnValue;
406 } //}}}
407
408 //{{{ TextAreaSelection class
409 static class TextAreaSelection extends StringSelection
410 {
411 JEditTextArea textArea;
412
413 TextAreaSelection(JEditTextArea textArea)
414 {
415 super(textArea.getSelectedText());
416 this.textArea = textArea;
417 }
418 } //}}}
419
420 //{{{ DraggedURLLoader
421 class DraggedURLLoader extends org.gjt.sp.util.WorkRequest
422 {
423 private JEditTextArea textArea;
424 private String url;
425
426 public DraggedURLLoader(JEditTextArea textArea, String url)
427 {
428 super();
429 this.textArea = textArea;
430 this.url = url;
431 }
432 public void run()
433 {
434 jEdit.openFile(textArea.getView(),url);
435 }
436 } //}}}
437
438}