PageRenderTime 41ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/textarea/TextAreaTransferHandler.java

#
Java | 502 lines | 379 code | 54 blank | 69 comment | 65 complexity | 111084fe9d17a1a472eb92b812f139e9 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. package org.gjt.sp.jedit.textarea;
  23. //{{{ Imports
  24. import org.gjt.sp.jedit.*;
  25. import org.gjt.sp.jedit.bufferset.BufferSetManager;
  26. import org.gjt.sp.jedit.browser.VFSBrowser;
  27. import org.gjt.sp.jedit.io.FileVFS;
  28. import org.gjt.sp.jedit.io.VFS;
  29. import org.gjt.sp.jedit.io.VFSManager;
  30. import org.gjt.sp.util.Log;
  31. import org.gjt.sp.util.WorkRequest;
  32. import javax.swing.*;
  33. import java.awt.datatransfer.DataFlavor;
  34. import java.awt.datatransfer.StringSelection;
  35. import java.awt.datatransfer.Transferable;
  36. import java.io.File;
  37. import java.net.URI;
  38. import java.util.List;
  39. //}}}
  40. /**
  41. * @author Slava Pestov
  42. * @version $Id: TextAreaTransferHandler.java 19698 2011-07-23 12:22:01Z shlomy $
  43. */
  44. public class TextAreaTransferHandler extends TransferHandler
  45. {
  46. /* I assume that there can be only one drag operation at the time */
  47. private static JEditTextArea dragSource;
  48. private static boolean compoundEdit;
  49. private static boolean sameTextArea;
  50. private static int insertPos;
  51. private static int insertOffset;
  52. // 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.
  53. /*
  54. protected static DataFlavor textURIlistDataFlavor = null;
  55. static {
  56. try {
  57. textURIlistDataFlavor = new DataFlavor("text/uri-list;representationclass=java.lang.String");
  58. } catch (ClassNotFoundException e) {
  59. throw new RuntimeException("Cannot create DataFlavor. This should not happen.",e);
  60. }
  61. }
  62. */
  63. //{{{ createTransferable
  64. @Override
  65. protected Transferable createTransferable(JComponent c)
  66. {
  67. Log.log(Log.DEBUG,this,"createTransferable()");
  68. JEditTextArea textArea = (JEditTextArea)c;
  69. if(textArea.getSelectionCount() == 0)
  70. return null;
  71. else
  72. {
  73. dragSource = textArea;
  74. return new TextAreaSelection(textArea);
  75. }
  76. } //}}}
  77. //{{{ getSourceActions
  78. @Override
  79. public int getSourceActions(JComponent c)
  80. {
  81. return COPY_OR_MOVE;
  82. } //}}}
  83. //{{{ importData
  84. @Override
  85. public boolean importData(JComponent c, Transferable t)
  86. {
  87. Log.log(Log.DEBUG,this,"Import data");
  88. // Log.log(Log.DEBUG,this,"Import data: t.isDataFlavorSupported("+textURIlistDataFlavor+")="+t.isDataFlavorSupported(textURIlistDataFlavor)+".");
  89. if(!canImport(c,t.getTransferDataFlavors()))
  90. return false;
  91. boolean returnValue;
  92. try
  93. {
  94. if(t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
  95. {
  96. returnValue = importFile(c,t);
  97. }
  98. else
  99. {
  100. DataFlavor uriListStringDataFlavor = null;
  101. DataFlavor[] dataFlavors = t.getTransferDataFlavors();
  102. for (DataFlavor dataFlavor : dataFlavors)
  103. {
  104. if (isUriList(dataFlavor))
  105. {
  106. uriListStringDataFlavor = dataFlavor;
  107. break;
  108. }
  109. }
  110. if (uriListStringDataFlavor != null &&t.isDataFlavorSupported(uriListStringDataFlavor))
  111. {
  112. returnValue = importURIList(c,t,uriListStringDataFlavor);
  113. }
  114. else
  115. {
  116. returnValue = importText(c,t);
  117. }
  118. }
  119. }
  120. catch(Exception e)
  121. {
  122. Log.log(Log.ERROR,this,e);
  123. returnValue = false;
  124. }
  125. GUIUtilities.getView(c).toFront();
  126. GUIUtilities.getView(c).requestFocus();
  127. c.requestFocus();
  128. return returnValue;
  129. } //}}}
  130. //{{{ importFile
  131. private boolean importFile(JComponent c, Transferable t)
  132. throws Exception
  133. {
  134. Log.log(Log.DEBUG,this,"=> File list");
  135. EditPane editPane = (EditPane)
  136. GUIUtilities.getComponentParent(
  137. c,EditPane.class);
  138. View view = editPane.getView();
  139. Buffer buffer = null;
  140. // per the Java API, javaFileListFlavor guarantees that a
  141. // List<File> will be returned. So suppress warning for this
  142. // statement. We know what we're doing.
  143. @SuppressWarnings("unchecked")
  144. List<File> data = (List<File>) t.getTransferData(DataFlavor.javaFileListFlavor);
  145. boolean browsedDirectory = false;
  146. BufferSetManager bufferSetManager = jEdit.getBufferSetManager();
  147. for (File file : data)
  148. {
  149. if (file.isDirectory())
  150. {
  151. if (!browsedDirectory)
  152. {
  153. VFSBrowser.browseDirectory(view, file.getPath());
  154. browsedDirectory = true;
  155. }
  156. continue;
  157. }
  158. Buffer _buffer = jEdit.openFile(editPane, file.getPath());
  159. if (_buffer != null)
  160. {
  161. buffer = _buffer;
  162. bufferSetManager.addBuffer(editPane, buffer);
  163. }
  164. }
  165. if(buffer != null)
  166. editPane.setBuffer(buffer);
  167. view.toFront();
  168. view.requestFocus();
  169. editPane.requestFocus();
  170. return true;
  171. } //}}}
  172. //{{{ importURIList
  173. private boolean importURIList(JComponent c, Transferable t,DataFlavor uriListStringDataFlavor)
  174. throws Exception
  175. {
  176. String str = (String) t.getTransferData(uriListStringDataFlavor);
  177. Log.log(Log.DEBUG,this,"=> URIList \""+str+ '\"');
  178. EditPane editPane = (EditPane) GUIUtilities.getComponentParent(c, EditPane.class);
  179. View view = editPane.getView();
  180. JEditTextArea textArea = (JEditTextArea) c;
  181. if (dragSource == null)
  182. {
  183. boolean found = false;
  184. String[] components = str.split("\r\n");
  185. boolean browsedDirectory = false;
  186. for (int i = 0;i<components.length;i++)
  187. {
  188. String str0 = components[i];
  189. // gnome-commander adds a 0 byte at the end of the file name, discard it
  190. int len = str0.length();
  191. if (len > 0 && (int)str0.charAt(len - 1) == 0)
  192. str0 = str0.substring(0, len - 1);
  193. if (str0.length() > 0)
  194. {
  195. URI uri = new URI(str0); // this handles the URI-decoding
  196. if ("file".equals(uri.getScheme()))
  197. {
  198. File file = new File(uri.getPath());
  199. if (file.isDirectory())
  200. {
  201. if (!browsedDirectory)
  202. {
  203. VFSBrowser.browseDirectory(view, file.getPath());
  204. browsedDirectory = true;
  205. }
  206. }
  207. else
  208. {
  209. VFSManager.runInAWTThread(new DraggedURLLoader(textArea,uri.getPath()));
  210. }
  211. found = true;
  212. }
  213. else
  214. {
  215. Log.log(Log.DEBUG,this,"I do not know how to handle this URI "+uri+", ignoring.");
  216. }
  217. }
  218. else
  219. {
  220. // This should be the last component, because every URI in the list is terminated with a "\r\n", even the last one.
  221. if (i!=components.length-1)
  222. {
  223. Log.log(Log.DEBUG,this,"Odd: there is an empty line in the uri list which is not the last line.");
  224. }
  225. }
  226. }
  227. if (found)
  228. {
  229. return true;
  230. }
  231. }
  232. return true;
  233. } //}}}
  234. //{{{ importText
  235. private boolean importText(JComponent c, Transferable t)
  236. throws Exception
  237. {
  238. String str = (String)t.getTransferData(
  239. DataFlavor.stringFlavor);
  240. str = str.trim();
  241. Log.log(Log.DEBUG,this,"=> String \""+str+ '\"');
  242. JEditTextArea textArea = (JEditTextArea)c;
  243. if (dragSource == null)
  244. {
  245. boolean found = false;
  246. String[] components = str.split("\n");
  247. for (String str0 : components)
  248. {
  249. // Only examine the string for a URL if it came from
  250. // outside of jEdit.
  251. VFS vfs = VFSManager.getVFSForPath(str0);
  252. if (!(vfs instanceof FileVFS) || str.startsWith("file://"))
  253. {
  254. // str = str.replace('\n',' ').replace('\r',' ').trim();
  255. if (str0.startsWith("file://"))
  256. {
  257. str0 = str0.substring(7);
  258. }
  259. VFSManager.runInWorkThread(new DraggedURLLoader(textArea, str0));
  260. }
  261. found = true;
  262. }
  263. if (found)
  264. return true;
  265. }
  266. if(dragSource != null
  267. && textArea.getBuffer()
  268. == dragSource.getBuffer())
  269. {
  270. compoundEdit = true;
  271. textArea.getBuffer().beginCompoundEdit();
  272. }
  273. sameTextArea = textArea == dragSource;
  274. int caret = textArea.getCaretPosition();
  275. Selection s = textArea.getSelectionAtOffset(caret);
  276. /* if user drops into the same
  277. selection where they started, do
  278. nothing. */
  279. if(s != null)
  280. {
  281. if(sameTextArea)
  282. return false;
  283. /* if user drops into a selection,
  284. replace selection */
  285. int startPos = s.start;
  286. textArea.setSelectedText(s,str);
  287. textArea.setSelection(new Selection.Range(startPos,startPos+str.length()));
  288. }
  289. /* otherwise just insert the text */
  290. else
  291. {
  292. if (sameTextArea)
  293. {
  294. insertPos = caret;
  295. insertOffset = 0;
  296. Selection[] selections = textArea.getSelection();
  297. for (Selection selection : selections)
  298. {
  299. if (selection.end < insertPos + insertOffset)
  300. insertOffset -= selection.end - selection.start;
  301. }
  302. }
  303. else
  304. {
  305. textArea.getBuffer().insert(caret,str);
  306. textArea.setSelection(new Selection.Range(caret,caret+str.length()));
  307. }
  308. }
  309. textArea.scrollToCaret(true);
  310. return true;
  311. } //}}}
  312. //{{{ exportDone() method
  313. @Override
  314. protected void exportDone(JComponent c, Transferable t,
  315. int action)
  316. {
  317. Log.log(Log.DEBUG,this,"Export done");
  318. JEditTextArea textArea = (JEditTextArea)c;
  319. try
  320. {
  321. // This happens if importData returns false. For example if you drop into the Selection
  322. if (action == NONE)
  323. {
  324. Log.log(Log.DEBUG,this,"Export impossible");
  325. return;
  326. }
  327. if(t == null)
  328. {
  329. Log.log(Log.DEBUG,this,"=> Null transferrable");
  330. textArea.selectNone();
  331. }
  332. else if(t.isDataFlavorSupported(
  333. DataFlavor.stringFlavor))
  334. {
  335. Log.log(Log.DEBUG,this,"=> String");
  336. if (sameTextArea)
  337. {
  338. if(action == MOVE)
  339. {
  340. textArea.setSelectedText(null,false);
  341. insertPos += insertOffset;
  342. }
  343. try
  344. {
  345. String str = (String)t.getTransferData(DataFlavor.stringFlavor);
  346. textArea.getBuffer().insert(insertPos,str);
  347. textArea.setSelection(new Selection.Range(insertPos,insertPos+str.length()));
  348. }
  349. catch(Exception e)
  350. {
  351. Log.log(Log.DEBUG,this,"exportDone in sameTextArea");
  352. Log.log(Log.DEBUG,this,e);
  353. }
  354. }
  355. else
  356. {
  357. if(action == MOVE)
  358. textArea.setSelectedText(null,false);
  359. else
  360. textArea.selectNone();
  361. }
  362. }
  363. }
  364. finally
  365. {
  366. if(compoundEdit)
  367. {
  368. compoundEdit = false;
  369. textArea.getBuffer().endCompoundEdit();
  370. }
  371. }
  372. dragSource = null;
  373. } //}}}
  374. //{{{ isUriList() method
  375. private boolean isUriList(DataFlavor flavor)
  376. {
  377. return ("text".equals(flavor.getPrimaryType()) &&
  378. "uri-list".equals(flavor.getSubType()) &&
  379. flavor.getRepresentationClass() == String.class);
  380. } //}}}
  381. //{{{ canImport() methods
  382. @Override
  383. public boolean canImport(TransferSupport support)
  384. {
  385. if (dragSource != null)
  386. return true;
  387. else
  388. {
  389. support.setDropAction(COPY);
  390. return super.canImport(support);
  391. }
  392. }
  393. @Override
  394. public boolean canImport(JComponent c, DataFlavor[] flavors)
  395. {
  396. JEditTextArea textArea = (JEditTextArea)c;
  397. // correctly handle text flavor + file list flavor
  398. // + text area read only, do an or of all flags
  399. boolean returnValue = false;
  400. for (DataFlavor flavor : flavors)
  401. {
  402. if (flavor.equals(DataFlavor.javaFileListFlavor) ||
  403. isUriList(flavor))
  404. {
  405. returnValue = true;
  406. break;
  407. } else if (flavor.equals(
  408. DataFlavor.stringFlavor))
  409. {
  410. if (textArea.isEditable())
  411. {
  412. returnValue = true;
  413. break;
  414. }
  415. }
  416. }
  417. Log.log(Log.DEBUG,this,"canImport() returning "
  418. + returnValue);
  419. return returnValue;
  420. } //}}}
  421. //{{{ TextAreaSelection class
  422. private static class TextAreaSelection extends StringSelection
  423. {
  424. final JEditTextArea textArea;
  425. TextAreaSelection(JEditTextArea textArea)
  426. {
  427. super(textArea.getSelectedText());
  428. this.textArea = textArea;
  429. }
  430. } //}}}
  431. //{{{ DraggedURLLoader class
  432. private static class DraggedURLLoader extends WorkRequest
  433. {
  434. private final JEditTextArea textArea;
  435. private final String url;
  436. DraggedURLLoader(JEditTextArea textArea, String url)
  437. {
  438. this.textArea = textArea;
  439. this.url = url;
  440. }
  441. public void run()
  442. {
  443. EditPane editPane = EditPane.get(textArea);
  444. jEdit.openFile(editPane,url);
  445. }
  446. } //}}}
  447. }