PageRenderTime 2304ms CodeModel.GetById 50ms RepoModel.GetById 25ms app.codeStats 1ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/browser/VFSBrowser.java

#
Java | 2155 lines | 1529 code | 257 blank | 369 comment | 291 complexity | 15dc66f0952c8924559cde89524bee3c 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

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * VFSBrowser.java - VFS browser
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 2000, 2003 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.browser;
  23. //{{{ Imports
  24. import org.gjt.sp.jedit.EditBus.EBHandler;
  25. import org.gjt.sp.jedit.bsh.*;
  26. import javax.swing.border.EmptyBorder;
  27. import javax.swing.event.*;
  28. import javax.swing.*;
  29. import java.awt.event.*;
  30. import java.awt.*;
  31. import java.io.File;
  32. import java.util.*;
  33. import java.util.List;
  34. import java.util.concurrent.CountDownLatch;
  35. import org.gjt.sp.jedit.io.*;
  36. import org.gjt.sp.jedit.gui.*;
  37. import org.gjt.sp.jedit.msg.*;
  38. import org.gjt.sp.jedit.search.*;
  39. import org.gjt.sp.jedit.*;
  40. import org.gjt.sp.jedit.buffer.JEditBuffer;
  41. import org.gjt.sp.util.*;
  42. import org.gjt.sp.jedit.menu.MenuItemTextComparator;
  43. //}}}
  44. /**
  45. * The main class of the VFS browser.
  46. * Used as dockable, and also embedded inside the
  47. * VFSFileChooserDialog.
  48. *
  49. * @author Slava Pestov
  50. * @version $Id: VFSBrowser.java 19949 2011-09-10 08:37:05Z kpouer $
  51. */
  52. public class VFSBrowser extends JPanel implements DefaultFocusComponent,
  53. DockableWindow
  54. {
  55. public static final String NAME = "vfs.browser";
  56. //{{{ Browser modes
  57. /**
  58. * Open file dialog mode. Equals JFileChooser.OPEN_DIALOG for
  59. * backwards compatibility.
  60. */
  61. public static final int OPEN_DIALOG = 0;
  62. /**
  63. * Save file dialog mode. Equals JFileChooser.SAVE_DIALOG for
  64. * backwards compatibility.
  65. */
  66. public static final int SAVE_DIALOG = 1;
  67. /**
  68. * Choose directory dialog mode.
  69. */
  70. public static final int BROWSER_DIALOG = 4;
  71. /**
  72. * Choose directory dialog mode.
  73. */
  74. public static final int CHOOSE_DIRECTORY_DIALOG = 3;
  75. /**
  76. * Stand-alone dockable browser mode.
  77. */
  78. public static final int BROWSER = 2;
  79. //}}}
  80. //{{{ browseDirectoryInNewWindow() method
  81. /**
  82. * Opens the specified directory in a new, floating, file system browser.
  83. * @param view The view
  84. * @param path The directory's path
  85. * @since jEdit 4.1pre2
  86. */
  87. public static void browseDirectoryInNewWindow(View view, String path)
  88. {
  89. DockableWindowManager wm = view.getDockableWindowManager();
  90. if(path != null)
  91. {
  92. // this is such a bad way of doing it, but oh well...
  93. jEdit.setTemporaryProperty("vfs.browser.path.tmp",path);
  94. }
  95. wm.floatDockableWindow("vfs.browser");
  96. jEdit.unsetProperty("vfs.browser.path.tmp");
  97. } //}}}
  98. //{{{ browseDirectory() method
  99. /**
  100. * Opens the specified directory in a file system browser.
  101. * @param view The view
  102. * @param path The directory's path
  103. * @since jEdit 4.0pre3
  104. */
  105. public static void browseDirectory(View view, String path)
  106. {
  107. DockableWindowManager wm = view.getDockableWindowManager();
  108. VFSBrowser browser = (VFSBrowser)wm.getDockable(NAME);
  109. if(browser != null)
  110. {
  111. wm.showDockableWindow(NAME);
  112. browser.setDirectory(path);
  113. }
  114. else
  115. {
  116. if(path != null)
  117. {
  118. // this is such a bad way of doing it, but oh well...
  119. jEdit.setTemporaryProperty("vfs.browser.path.tmp",path);
  120. }
  121. wm.addDockableWindow("vfs.browser");
  122. jEdit.unsetProperty("vfs.browser.path.tmp");
  123. }
  124. } //}}}
  125. //{{{ getActionContext() method
  126. /**
  127. * Returns the browser action context.
  128. * @since jEdit 4.2pre1
  129. */
  130. public static ActionContext getActionContext()
  131. {
  132. return actionContext;
  133. } //}}}
  134. //{{{ VFSBrowser constructor
  135. /**
  136. * Creates a new VFS browser.
  137. * @param view The view to open buffers in by default
  138. */
  139. public VFSBrowser(View view, String position)
  140. {
  141. this(view,null,BROWSER,true,position);
  142. } //}}}
  143. //{{{ VFSBrowser constructor
  144. /**
  145. * Creates a new VFS browser.
  146. * @param view The view to open buffers in by default
  147. * @param path The path to display
  148. * @param mode The browser mode
  149. * @param multipleSelection True if multiple selection should be allowed
  150. * @param position Where the browser is located
  151. * @since jEdit 4.2pre1
  152. */
  153. public VFSBrowser(View view, String path, int mode,
  154. boolean multipleSelection, String position)
  155. {
  156. super(new BorderLayout());
  157. listenerList = new EventListenerList();
  158. this.mode = mode;
  159. this.multipleSelection = multipleSelection;
  160. this.view = view;
  161. currentEncoding = null;
  162. autoDetectEncoding = jEdit.getBooleanProperty(
  163. "buffer.encodingAutodetect");
  164. ActionHandler actionHandler = new ActionHandler();
  165. topBox = new Box(BoxLayout.Y_AXIS);
  166. horizontalLayout = mode != BROWSER
  167. || DockableWindowManager.TOP.equals(position)
  168. || DockableWindowManager.BOTTOM.equals(position);
  169. toolbarBox = new Box(horizontalLayout
  170. ? BoxLayout.X_AXIS
  171. : BoxLayout.Y_AXIS);
  172. topBox.add(toolbarBox);
  173. GridBagLayout layout = new GridBagLayout();
  174. pathAndFilterPanel = new JPanel(layout);
  175. if(isHorizontalLayout())
  176. pathAndFilterPanel.setBorder(new EmptyBorder(12,12,12,12));
  177. GridBagConstraints cons = new GridBagConstraints();
  178. cons.gridwidth = cons.gridheight = 1;
  179. cons.gridx = cons.gridy = 0;
  180. cons.fill = GridBagConstraints.BOTH;
  181. cons.anchor = GridBagConstraints.EAST;
  182. JLabel label = new JLabel(jEdit.getProperty("vfs.browser.path"),
  183. SwingConstants.RIGHT);
  184. label.setBorder(new EmptyBorder(0,0,0,12));
  185. layout.setConstraints(label,cons);
  186. pathAndFilterPanel.add(label);
  187. pathField = new HistoryTextField("vfs.browser.path");
  188. pathField.setName("path");
  189. pathField.setInstantPopups(true);
  190. pathField.setEnterAddsToHistory(false);
  191. pathField.setSelectAllOnFocus(true);
  192. // because its preferred size can be quite wide, we
  193. // don't want it to make the browser way too big,
  194. // so set the preferred width to 0.
  195. Dimension prefSize = pathField.getPreferredSize();
  196. prefSize.width = 0;
  197. pathField.setPreferredSize(prefSize);
  198. pathField.addActionListener(actionHandler);
  199. cons.gridx = 1;
  200. cons.weightx = 1.0;
  201. cons.gridwidth = GridBagConstraints.REMAINDER;
  202. layout.setConstraints(pathField,cons);
  203. pathAndFilterPanel.add(pathField);
  204. filterCheckbox = new JCheckBox(jEdit.getProperty("vfs.browser.filter"));
  205. filterCheckbox.setMargin(new Insets(0,0,0,0));
  206. // filterCheckbox.setRequestFocusEnabled(false);
  207. filterCheckbox.setBorder(new EmptyBorder(0,0,0,12));
  208. filterCheckbox.setSelected(jEdit.getBooleanProperty(
  209. "vfs.browser.filter-enabled"));
  210. filterCheckbox.addActionListener(actionHandler);
  211. filterCheckbox.setName("filter-checkbox");
  212. if(mode != CHOOSE_DIRECTORY_DIALOG)
  213. {
  214. cons.gridwidth = 1;
  215. cons.gridx = 0;
  216. cons.weightx = 0.0;
  217. cons.gridy = 1;
  218. layout.setConstraints(filterCheckbox,cons);
  219. pathAndFilterPanel.add(filterCheckbox);
  220. }
  221. filterField = new JComboBox();
  222. filterEditor = new HistoryComboBoxEditor("vfs.browser.filter");
  223. filterEditor.setToolTipText(jEdit.getProperty("glob.tooltip"));
  224. filterEditor.setInstantPopups(true);
  225. filterEditor.setSelectAllOnFocus(true);
  226. filterEditor.addActionListener(actionHandler);
  227. filterField.setName("filter-field");
  228. if (mode == BROWSER)
  229. {
  230. DockableWindowManager dwm = view.getDockableWindowManager();
  231. KeyListener keyListener = dwm.closeListener(NAME);
  232. filterCheckbox.addKeyListener(keyListener);
  233. addKeyListener(keyListener);
  234. filterEditor.addKeyListener(keyListener);
  235. pathField.addKeyListener(keyListener);
  236. // save the location on close of dockable.
  237. pathField.addKeyListener(new KeyAdapter()
  238. {
  239. @Override
  240. public void keyReleased(KeyEvent e)
  241. {
  242. if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
  243. {
  244. pathField.setText(VFSBrowser.this.path);
  245. }
  246. }
  247. });
  248. }
  249. String filter;
  250. if(mode == BROWSER || !jEdit.getBooleanProperty(
  251. "vfs.browser.currentBufferFilter"))
  252. {
  253. filter = jEdit.getProperty("vfs.browser.last-filter");
  254. if(filter == null)
  255. filter = jEdit.getProperty("vfs.browser.default-filter");
  256. }
  257. else
  258. {
  259. String ext = MiscUtilities.getFileExtension(
  260. view.getBuffer().getName());
  261. if(ext.length() == 0)
  262. filter = jEdit.getProperty("vfs.browser.default-filter");
  263. else
  264. filter = '*' + ext;
  265. }
  266. // filterField.getEditor().setItem(new GlobVFSFileFilter(filter));
  267. // filterField.addItem(filterField.getEditor().getItem());
  268. filterEditor.setItem(new GlobVFSFileFilter(filter));
  269. filterField.addItem(filterEditor.getItem());
  270. filterField.addItemListener(actionHandler);
  271. filterField.setRenderer(new VFSFileFilterRenderer());
  272. // loads the registered VFSFileFilter services.
  273. String[] _filters = ServiceManager.getServiceNames(VFSFileFilter.SERVICE_NAME);
  274. for (int i = 0; i < _filters.length; i++)
  275. {
  276. VFSFileFilter _filter = (VFSFileFilter)
  277. ServiceManager.getService(VFSFileFilter.SERVICE_NAME, _filters[i]);
  278. filterField.addItem(_filter);
  279. }
  280. if(mode != CHOOSE_DIRECTORY_DIALOG)
  281. {
  282. cons.gridwidth = GridBagConstraints.REMAINDER;
  283. cons.fill = GridBagConstraints.HORIZONTAL;
  284. cons.gridx = 1;
  285. cons.weightx = 1.0;
  286. if (filterField.getItemCount() > 1)
  287. {
  288. filterField.setEditor(filterEditor);
  289. filterField.setEditable(true);
  290. layout.setConstraints(filterField,cons);
  291. pathAndFilterPanel.add(filterField);
  292. }
  293. else
  294. {
  295. layout.setConstraints(filterEditor,cons);
  296. pathAndFilterPanel.add(filterEditor);
  297. }
  298. }
  299. topBox.add(pathAndFilterPanel);
  300. add(BorderLayout.NORTH,topBox);
  301. add(BorderLayout.CENTER,browserView = new BrowserView(this));
  302. if(isHorizontalLayout())
  303. browserView.setBorder(new EmptyBorder(0,12,0,12));
  304. defaultFocusComponent = browserView.getTable();
  305. propertiesChanged();
  306. updateFilterEnabled();
  307. setFocusTraversalPolicy(new LayoutFocusTraversalPolicy());
  308. // see VFSBrowser.browseDirectory()
  309. if(path == null)
  310. path = jEdit.getProperty("vfs.browser.path.tmp");
  311. if(path == null || path.isEmpty())
  312. {
  313. String userHome = System.getProperty("user.home");
  314. String defaultPath = jEdit.getProperty("vfs.browser.defaultPath");
  315. if("home".equals(defaultPath))
  316. path = userHome;
  317. else if("working".equals(defaultPath))
  318. path = System.getProperty("user.dir");
  319. else if("buffer".equals(defaultPath))
  320. {
  321. Buffer buffer = view.getBuffer();
  322. boolean browseable = (buffer.getVFS().getCapabilities() & VFS.BROWSE_CAP) != 0;
  323. if (browseable)
  324. path = buffer.getDirectory();
  325. }
  326. else if("last".equals(defaultPath))
  327. {
  328. HistoryModel pathModel = HistoryModel.getModel("vfs.browser.path");
  329. if(pathModel.getSize() == 0)
  330. path = "~";
  331. else
  332. path = pathModel.getItem(0);
  333. }
  334. else if("favorites".equals(defaultPath))
  335. path = "favorites:";
  336. if (path == null || path.isEmpty())
  337. {
  338. // unknown value??!!!
  339. path = userHome;
  340. }
  341. }
  342. final String _path = path;
  343. ThreadUtilities.runInDispatchThread(new Runnable()
  344. {
  345. @Override
  346. public void run()
  347. {
  348. setDirectory(_path);
  349. }
  350. });
  351. } //}}}
  352. //{{{ focusOnDefaultComponent() method
  353. @Override
  354. public void focusOnDefaultComponent()
  355. {
  356. // pathField.requestFocus();
  357. defaultFocusComponent.requestFocus();
  358. } //}}}
  359. // {{{ setDefaultFocusComponent()
  360. /** Only used by VFSFileChooserDialog, since it embeds this in a dialog
  361. */
  362. void setDefaultFocusComponent(JComponent c)
  363. {
  364. defaultFocusComponent = c;
  365. }// }}}
  366. //{{{ addNotify() method
  367. @Override
  368. public void addNotify()
  369. {
  370. super.addNotify();
  371. EditBus.addToBus(this);
  372. } //}}}
  373. //{{{ removeNotify() method
  374. @Override
  375. public void removeNotify()
  376. {
  377. super.removeNotify();
  378. jEdit.setBooleanProperty("vfs.browser.filter-enabled",
  379. filterCheckbox.isSelected());
  380. if(mode == BROWSER || !jEdit.getBooleanProperty(
  381. "vfs.browser.currentBufferFilter"))
  382. {
  383. VFSFileFilter selectedFilter =
  384. (VFSFileFilter) filterField.getSelectedItem();
  385. if (selectedFilter instanceof GlobVFSFileFilter)
  386. jEdit.setProperty("vfs.browser.last-filter",
  387. ((GlobVFSFileFilter)selectedFilter).getGlob());
  388. }
  389. EditBus.removeFromBus(this);
  390. } //}}}
  391. //{{{ handlePropertiesChanged() method
  392. @EBHandler
  393. public void handlePropertiesChanged(PropertiesChanged msg)
  394. {
  395. propertiesChanged();
  396. } //}}}
  397. //{{{ handleBufferUpdate() method
  398. @EBHandler
  399. public void handleBufferUpdate(BufferUpdate bmsg)
  400. {
  401. if (bmsg.getWhat() == BufferUpdate.CREATED ||
  402. bmsg.getWhat() == BufferUpdate.CLOSED)
  403. {
  404. browserView.updateFileView();
  405. }
  406. } //}}}
  407. //{{{ handlePluginUpdate() method
  408. @EBHandler
  409. public void handlePluginUpdate(PluginUpdate pmsg)
  410. {
  411. if((pmsg.getWhat() == PluginUpdate.LOADED ||
  412. pmsg.getWhat() == PluginUpdate.UNLOADED) &&
  413. plugins != null /* plugins can be null if the VFSBrowser menu bar is hidden */)
  414. {
  415. plugins.updatePopupMenu();
  416. }
  417. } //}}}
  418. //{{{ handleVFSUpdate() method
  419. @EBHandler
  420. public void handleVFSUpdate(VFSUpdate msg)
  421. {
  422. maybeReloadDirectory(msg.getPath());
  423. } //}}}
  424. //{{{ getView() method
  425. public View getView()
  426. {
  427. return view;
  428. } //}}}
  429. //{{{ getMode() method
  430. public int getMode()
  431. {
  432. return mode;
  433. } //}}}
  434. //{{{ isMultipleSelectionEnabled() method
  435. public boolean isMultipleSelectionEnabled()
  436. {
  437. return multipleSelection;
  438. } //}}}
  439. //{{{ isHorizontalLayout() method
  440. public boolean isHorizontalLayout()
  441. {
  442. return horizontalLayout;
  443. } //}}}
  444. //{{{ getShowHiddenFiles() method
  445. public boolean getShowHiddenFiles()
  446. {
  447. return showHiddenFiles;
  448. } //}}}
  449. //{{{ setShowHiddenFiles() method
  450. public void setShowHiddenFiles(boolean showHiddenFiles)
  451. {
  452. this.showHiddenFiles = showHiddenFiles;
  453. } //}}}
  454. //{{{ getVFSFileFilter() method
  455. /**
  456. * Returns the currently active VFSFileFilter.
  457. *
  458. * @since jEdit 4.3pre7
  459. */
  460. public VFSFileFilter getVFSFileFilter()
  461. {
  462. if (mode == CHOOSE_DIRECTORY_DIALOG)
  463. return new DirectoriesOnlyFilter();
  464. return (VFSFileFilter) filterField.getSelectedItem();
  465. } //}}}
  466. //{{{ addVFSFileFilter() method
  467. /**
  468. * Adds a file filter to the browser.
  469. *
  470. * @since jEdit 4.3pre7
  471. */
  472. public void addVFSFileFilter(VFSFileFilter filter)
  473. {
  474. filterField.addItem(filter);
  475. if (filterField.getItemCount() == 2)
  476. {
  477. filterField.setEditor(filterEditor);
  478. filterField.setEditable(true);
  479. GridBagLayout layout = (GridBagLayout) pathAndFilterPanel.getLayout();
  480. GridBagConstraints cons =layout.getConstraints(filterEditor);
  481. cons.gridwidth = GridBagConstraints.REMAINDER;
  482. cons.fill = GridBagConstraints.HORIZONTAL;
  483. cons.gridx = 1;
  484. cons.weightx = 1;
  485. pathAndFilterPanel.remove(filterEditor);
  486. layout.setConstraints(filterField, cons);
  487. pathAndFilterPanel.add(filterField);
  488. pathAndFilterPanel.validate();
  489. pathAndFilterPanel.repaint();
  490. }
  491. } //}}}
  492. //{{{ setFilenameFilter() method
  493. public void setFilenameFilter(String filter)
  494. {
  495. if(filter == null || filter.length() == 0 || "*".equals(filter))
  496. filterCheckbox.setSelected(false);
  497. else
  498. {
  499. filterCheckbox.setSelected(true);
  500. filterEditor.setItem(new GlobVFSFileFilter(filter));
  501. }
  502. } //}}}
  503. //{{{ getDirectoryField() method
  504. public HistoryTextField getDirectoryField()
  505. {
  506. return pathField;
  507. } //}}}
  508. //{{{ getDirectory() method
  509. public String getDirectory()
  510. {
  511. return path;
  512. } //}}}
  513. // {{{ Directory Stack operations
  514. /**
  515. * @since jedit 4.3pre15
  516. */
  517. public void previousDirectory()
  518. {
  519. if (historyStack.size() > 1)
  520. {
  521. historyStack.pop();
  522. nextDirectoryStack.push(path);
  523. setDirectory(historyStack.peek());
  524. historyStack.pop();
  525. }
  526. }
  527. /**
  528. * @since jEdit 4.3pre15
  529. */
  530. public void nextDirectory()
  531. {
  532. if (!nextDirectoryStack.isEmpty())
  533. {
  534. setDirectory(nextDirectoryStack.pop());
  535. }
  536. }
  537. // }}}
  538. //{{{ setDirectory() method
  539. public void setDirectory(String path)
  540. {
  541. if(path.startsWith("file:"))
  542. path = path.substring(5);
  543. path = MiscUtilities.expandVariables(path);
  544. pathField.setText(path);
  545. if(!startRequest())
  546. return;
  547. historyStack.push(path);
  548. browserView.saveExpansionState();
  549. Runnable delayedAWTRequest = new DelayedEndRequest();
  550. browserView.loadDirectory(null,path,true, delayedAWTRequest);
  551. this.path = path;
  552. } //}}}
  553. //{{{ getRootDirectory() method
  554. public static String getRootDirectory()
  555. {
  556. if(OperatingSystem.isMacOS() || OperatingSystem.isDOSDerived())
  557. return FileRootsVFS.PROTOCOL + ':';
  558. else
  559. return "/";
  560. } //}}}
  561. //{{{ rootDirectory() method
  562. /**
  563. * Goes to the local drives directory.
  564. * @since jEdit 4.0pre4
  565. */
  566. public void rootDirectory()
  567. {
  568. setDirectory(getRootDirectory());
  569. } //}}}
  570. //{{{ reloadDirectory() method
  571. public void reloadDirectory()
  572. {
  573. // used by FTP plugin to clear directory cache
  574. VFSManager.getVFSForPath(path).reloadDirectory(path);
  575. browserView.saveExpansionState();
  576. browserView.loadDirectory(null,path,false);
  577. } //}}}
  578. //{{{ delete() method
  579. /**
  580. * Note that all files must be on the same VFS.
  581. * @since jEdit 4.3pre2
  582. */
  583. public void delete(VFSFile[] files)
  584. {
  585. String dialogType;
  586. if(MiscUtilities.isURL(files[0].getDeletePath())
  587. && FavoritesVFS.PROTOCOL.equals(
  588. MiscUtilities.getProtocolOfURL(files[0].getDeletePath())))
  589. {
  590. dialogType = "vfs.browser.delete-favorites";
  591. }
  592. else
  593. {
  594. dialogType = "vfs.browser.delete-confirm";
  595. }
  596. StringBuilder buf = new StringBuilder();
  597. String typeStr = "files";
  598. for(int i = 0; i < files.length; i++)
  599. {
  600. buf.append(files[i].getPath());
  601. buf.append('\n');
  602. if (files[i].getType() == VFSFile.DIRECTORY)
  603. typeStr = "directories and their contents";
  604. }
  605. Object[] args = { buf.toString(), typeStr};
  606. int result = GUIUtilities.confirm(this,dialogType,args,
  607. JOptionPane.YES_NO_OPTION,
  608. JOptionPane.WARNING_MESSAGE);
  609. if(result != JOptionPane.YES_OPTION)
  610. return;
  611. VFS vfs = VFSManager.getVFSForPath(files[0].getDeletePath());
  612. if(!startRequest())
  613. return;
  614. final CountDownLatch latch = new CountDownLatch(files.length);
  615. for(int i = 0; i < files.length; i++)
  616. {
  617. Object session = vfs.createVFSSession(files[i].getDeletePath(),this);
  618. if(session == null)
  619. {
  620. latch.countDown();
  621. continue;
  622. }
  623. final Task task = new DeleteBrowserTask(this, session, vfs, files[i].getDeletePath());
  624. TaskManager.instance.addTaskListener(new TaskAdapter()
  625. {
  626. @Override
  627. public void done(Task t)
  628. {
  629. if (task == t)
  630. {
  631. latch.countDown();
  632. TaskManager.instance.removeTaskListener(this);
  633. }
  634. }
  635. });
  636. ThreadUtilities.runInBackground(task);
  637. }
  638. try
  639. {
  640. latch.await();
  641. }
  642. catch (InterruptedException e)
  643. {
  644. Log.log(Log.ERROR, this, e, e);
  645. }
  646. Runnable delayedAWTRequest = new DelayedEndRequest();
  647. EventQueue.invokeLater(delayedAWTRequest);
  648. } //}}}
  649. //{{{ rename() methods
  650. /**
  651. * Rename a file.
  652. * It will prompt for the new name.
  653. * @param from the file to rename
  654. * @since jEdit 4.5pre1
  655. */
  656. public void rename(VFSFile from)
  657. {
  658. String filename;
  659. if (from instanceof FavoritesVFS.Favorite)
  660. {
  661. FavoritesVFS.Favorite favorite = (FavoritesVFS.Favorite) from;
  662. filename = favorite.getLabel();
  663. }
  664. else
  665. {
  666. filename = from.getName();
  667. }
  668. String[] args = { filename };
  669. String to = GUIUtilities.input(this,"vfs.browser.rename",
  670. args,filename);
  671. if (to == null)
  672. return;
  673. rename(from.getVFS(), from.getPath(), to);
  674. }
  675. /**
  676. * Rename a file.
  677. * It will prompt for the new name.
  678. * @param from the file to rename
  679. * @param from to the target name
  680. * @since jEdit 4.5pre1
  681. */
  682. public void rename(VFSFile from, String to)
  683. {
  684. rename(from.getVFS(), from.getPath(), to);
  685. }
  686. public void rename(String from)
  687. {
  688. VFS vfs = VFSManager.getVFSForPath(from);
  689. String filename = vfs.getFileName(from);
  690. String[] args = { filename };
  691. String to = GUIUtilities.input(this,"vfs.browser.rename",
  692. args,filename);
  693. if (to == null)
  694. return;
  695. rename(from, to);
  696. }
  697. /**
  698. * Rename a file
  699. * @param vfs the VFS. It may be strange to give the VFS, but in
  700. * case of FavoriteVFS we cannot know that it is favorite.
  701. * @param from the full path name of the file to be renamed
  702. * @param newname the new name (only filename, not full path)
  703. * @since jEdit 4.5pre1
  704. */
  705. private void rename(VFS vfs, String from, String newname)
  706. {
  707. String filename = vfs.getFileName(from);
  708. String to = newname;
  709. if(to == null)
  710. return;
  711. if (!(vfs instanceof FavoritesVFS))
  712. {
  713. if (filename.equals(newname))
  714. return;
  715. to = MiscUtilities.constructPath(vfs.getParentOfPath(from),to);
  716. }
  717. Object session = vfs.createVFSSession(from,this);
  718. if(session == null)
  719. return;
  720. if(!startRequest())
  721. return;
  722. Runnable delayedAWTRequest = new DelayedEndRequest();
  723. Task renameTask = new RenameBrowserTask(this, session, vfs, from, to, delayedAWTRequest);
  724. ThreadUtilities.runInBackground(renameTask);
  725. }
  726. /**
  727. * Rename a file
  728. * @param from the full path name of the file to be renamed
  729. * @param newname the new name (only filename, not full path)
  730. */
  731. public void rename(String from, String newname)
  732. {
  733. VFS vfs = VFSManager.getVFSForPath(from);
  734. rename(vfs, from, newname);
  735. } //}}}
  736. //{{{ mkdir() method
  737. public void mkdir()
  738. {
  739. String newDirectory = GUIUtilities.input(this,"vfs.browser.mkdir",null);
  740. if(newDirectory == null)
  741. return;
  742. // if a directory is selected, create new dir in there.
  743. // if a file is selected, create new dir inside its parent.
  744. final VFSFile[] selected = getSelectedFiles();
  745. String parent;
  746. if(selected.length == 0)
  747. parent = path;
  748. else if(selected[0].getType() == VFSFile.FILE)
  749. {
  750. parent = selected[0].getPath();
  751. parent = VFSManager.getVFSForPath(parent)
  752. .getParentOfPath(parent);
  753. }
  754. else
  755. parent = selected[0].getPath();
  756. VFS vfs = VFSManager.getVFSForPath(parent);
  757. // path is the currently viewed directory in the browser
  758. newDirectory = MiscUtilities.constructPath(parent,newDirectory);
  759. Object session = vfs.createVFSSession(newDirectory,this);
  760. if(session == null)
  761. return;
  762. if(!startRequest())
  763. return;
  764. Runnable runnable = new Runnable()
  765. {
  766. @Override
  767. public void run()
  768. {
  769. endRequest();
  770. if (selected.length != 0 && selected[0].getType() != VFSFile.FILE)
  771. {
  772. VFSDirectoryEntryTable directoryEntryTable = browserView.getTable();
  773. int selectedRow = directoryEntryTable.getSelectedRow();
  774. VFSDirectoryEntryTableModel model = (VFSDirectoryEntryTableModel) directoryEntryTable.getModel();
  775. VFSDirectoryEntryTableModel.Entry entry = model.files[selectedRow];
  776. if (!entry.expanded)
  777. {
  778. browserView.clearExpansionState();
  779. browserView.loadDirectory(entry,entry.dirEntry.getPath(),
  780. false);
  781. }
  782. }
  783. }
  784. };
  785. Task mkdirTask = new MkDirBrowserTask(this, session, vfs, newDirectory, runnable);
  786. ThreadUtilities.runInBackground(mkdirTask);
  787. } //}}}
  788. //{{{ newFile() method
  789. /**
  790. * Creates a new file in the current directory.
  791. * @since jEdit 4.0pre2
  792. */
  793. public void newFile()
  794. {
  795. VFSFile[] selected = getSelectedFiles();
  796. if(selected.length >= 1)
  797. {
  798. VFSFile file = selected[0];
  799. if(file.getType() == VFSFile.DIRECTORY)
  800. jEdit.newFile(view,file.getPath());
  801. else
  802. {
  803. VFS vfs = VFSManager.getVFSForPath(file.getPath());
  804. jEdit.newFile(view,vfs.getParentOfPath(file.getPath()));
  805. }
  806. }
  807. else
  808. jEdit.newFile(view,path);
  809. } //}}}
  810. //{{{ fileProperties() method
  811. /**
  812. * Show selected file's properties.
  813. */
  814. public void fileProperties(VFSFile[] files)
  815. {
  816. new FilePropertiesDialog(view, this, files);
  817. } //}}}
  818. //{{{ searchInDirectory() method
  819. /**
  820. * Opens a directory search in the current directory.
  821. * @since jEdit 4.0pre2
  822. */
  823. public void searchInDirectory()
  824. {
  825. VFSFile[] selected = getSelectedFiles();
  826. if(selected.length >= 1)
  827. {
  828. VFSFile file = selected[0];
  829. searchInDirectory(file.getPath(),file.getType() != VFSFile.FILE);
  830. }
  831. else
  832. {
  833. searchInDirectory(path,true);
  834. }
  835. } //}}}
  836. //{{{ searchInDirectory() method
  837. /**
  838. * Opens a directory search in the specified directory.
  839. * @param path The path name
  840. * @param directory True if the path is a directory, false if it is a file
  841. * @since jEdit 4.2pre1
  842. */
  843. public void searchInDirectory(String path, boolean directory)
  844. {
  845. String filter;
  846. VFSFileFilter vfsff = getVFSFileFilter();
  847. if (vfsff instanceof GlobVFSFileFilter)
  848. filter = ((GlobVFSFileFilter)vfsff).getGlob();
  849. else
  850. filter = "*";
  851. if (!directory)
  852. {
  853. String name = MiscUtilities.getFileName(path);
  854. String ext = MiscUtilities.getFileExtension(name);
  855. filter = ext == null || ext.length() == 0
  856. ? filter : '*' + ext;
  857. path = MiscUtilities.getParentOfPath(path);
  858. }
  859. SearchAndReplace.setSearchFileSet(new DirectoryListSet(
  860. path,filter,true));
  861. SearchDialog.showSearchDialog(view,null,SearchDialog.DIRECTORY);
  862. } //}}}
  863. //{{{ getBrowserView() method
  864. BrowserView getBrowserView()
  865. {
  866. return browserView;
  867. } //}}}
  868. //{{{ getSelectedFiles() method
  869. /**
  870. * Return the selected files in the lower browser tree.
  871. * @since jEdit 4.3pre2
  872. */
  873. public VFSFile[] getSelectedFiles()
  874. {
  875. return browserView.getSelectedFiles();
  876. } //}}}
  877. //{{{ getSelectedFiles() method
  878. /**
  879. * Return the selected files from the point of view of the
  880. * given component. This may be the selected directory from the
  881. * upper tree component of the browser (directory tree) or
  882. * the selected files in the bottom tree component.
  883. * This method is to be used by code running inside VFSBrowser
  884. * such as a DynamicMenuProvider. Use the other method otherwise.
  885. * The main difference is this function searches the component
  886. * hierarchy for a {@link BrowserView.ParentDirectoryList} to get
  887. * the list of currently selected files from there. Otherwise, it
  888. * returns what {@link #getSelectedFiles()} would return.
  889. * @param source the source component to start from when
  890. * navigating the component hierarchy
  891. * @since jEdit 4.4pre1
  892. */
  893. public VFSFile[] getSelectedFiles(Component source)
  894. {
  895. if(GUIUtilities.getComponentParent(source, BrowserView.ParentDirectoryList.class)
  896. != null)
  897. {
  898. Object[] selected = getBrowserView()
  899. .getParentDirectoryList()
  900. .getSelectedValues();
  901. VFSFile[] returnValue = new VFSFile[
  902. selected.length];
  903. System.arraycopy(selected,0,returnValue,0,
  904. selected.length);
  905. return returnValue;
  906. }
  907. else
  908. {
  909. return getSelectedFiles();
  910. }
  911. } //}}}
  912. //{{{ locateFile() method
  913. /**
  914. * Goes to the given file's directory and selects the file in the list.
  915. * @param path The file
  916. * @since jEdit 4.2pre2
  917. */
  918. public void locateFile(final String path)
  919. {
  920. VFSFileFilter filter = getVFSFileFilter();
  921. if(!filter.accept(MiscUtilities.getFileName(path)))
  922. setFilenameFilter(null);
  923. setDirectory(MiscUtilities.getParentOfPath(path));
  924. // Do not change this until all VFS Browser tasks are
  925. // done in ThreadUtilities
  926. VFSManager.runInAWTThread(new Runnable()
  927. {
  928. public void run()
  929. {
  930. browserView.getTable().selectFile(path);
  931. }
  932. });
  933. } //}}}
  934. //{{{ createPluginsMenu() method
  935. public JComponent createPluginsMenu(JComponent pluginMenu, boolean showManagerOptions)
  936. {
  937. if(showManagerOptions && getMode() == BROWSER)
  938. {
  939. pluginMenu.add(GUIUtilities.loadMenuItem("plugin-manager",false));
  940. pluginMenu.add(GUIUtilities.loadMenuItem("plugin-options",false));
  941. if (pluginMenu instanceof JMenu)
  942. ((JMenu)pluginMenu).addSeparator();
  943. else if (pluginMenu instanceof JPopupMenu)
  944. ((JPopupMenu)pluginMenu).addSeparator();
  945. }
  946. else
  947. /* we're in a modal dialog */;
  948. List<JMenuItem> vec = new ArrayList<JMenuItem>();
  949. //{{{ new API
  950. EditPlugin[] plugins = jEdit.getPlugins();
  951. for (int i = 0; i < plugins.length; i++)
  952. {
  953. JMenuItem menuItem = plugins[i].createBrowserMenuItems();
  954. if(menuItem != null)
  955. vec.add(menuItem);
  956. } //}}}
  957. if (!vec.isEmpty())
  958. {
  959. Collections.sort(vec,new MenuItemTextComparator());
  960. for(int i = 0; i < vec.size(); i++)
  961. pluginMenu.add(vec.get(i));
  962. }
  963. else
  964. {
  965. JMenuItem mi = new JMenuItem(jEdit.getProperty(
  966. "vfs.browser.plugins.no-plugins.label"));
  967. mi.setEnabled(false);
  968. pluginMenu.add(mi);
  969. }
  970. return pluginMenu;
  971. } //}}}
  972. //{{{ addBrowserListener() method
  973. public void addBrowserListener(BrowserListener l)
  974. {
  975. listenerList.add(BrowserListener.class,l);
  976. } //}}}
  977. //{{{ removeBrowserListener() method
  978. public void removeBrowserListener(BrowserListener l)
  979. {
  980. listenerList.remove(BrowserListener.class,l);
  981. } //}}}
  982. //{{{ filesActivated() method
  983. // canDoubleClickClose set to false when ENTER pressed
  984. public static final int M_OPEN = 0;
  985. public static final int M_OPEN_NEW_VIEW = 1;
  986. public static final int M_OPEN_NEW_PLAIN_VIEW = 2;
  987. public static final int M_OPEN_NEW_SPLIT = 3;
  988. public static final int M_INSERT = 4;
  989. /**
  990. * This method does the "double-click" handling. It is public so that
  991. * <code>browser.actions.xml</code> can bind to it.
  992. * @since jEdit 4.2pre2
  993. */
  994. public void filesActivated(int mode, boolean canDoubleClickClose)
  995. {
  996. VFSFile[] selectedFiles = browserView.getSelectedFiles();
  997. Buffer buffer = null;
  998. check_selected: for(int i = 0; i < selectedFiles.length; i++)
  999. {
  1000. VFSFile file = selectedFiles[i];
  1001. if(file.getType() == VFSFile.DIRECTORY
  1002. || file.getType() == VFSFile.FILESYSTEM)
  1003. {
  1004. if(mode == M_OPEN_NEW_VIEW && this.mode == BROWSER)
  1005. browseDirectoryInNewWindow(view,file.getPath());
  1006. else
  1007. setDirectory(file.getPath());
  1008. }
  1009. else if(this.mode == BROWSER || this.mode == BROWSER_DIALOG)
  1010. {
  1011. if(mode == M_INSERT)
  1012. {
  1013. view.getBuffer().insertFile(view,
  1014. file.getPath());
  1015. continue check_selected;
  1016. }
  1017. Buffer _buffer = jEdit.getBuffer(file.getPath());
  1018. if(_buffer == null)
  1019. {
  1020. Hashtable<String, Object> props = new Hashtable<String, Object>();
  1021. if(currentEncoding != null)
  1022. {
  1023. props.put(JEditBuffer.ENCODING,currentEncoding);
  1024. }
  1025. props.put(Buffer.ENCODING_AUTODETECT,
  1026. autoDetectEncoding);
  1027. _buffer = jEdit.openFile(view, null,
  1028. file.getPath(),false,props);
  1029. }
  1030. else if(doubleClickClose && canDoubleClickClose
  1031. && this.mode != BROWSER_DIALOG
  1032. && selectedFiles.length == 1)
  1033. {
  1034. // close if this buffer is currently
  1035. // visible in the view.
  1036. EditPane[] editPanes = view.getEditPanes();
  1037. for(int j = 0; j < editPanes.length; j++)
  1038. {
  1039. if(editPanes[j].getBuffer() == _buffer)
  1040. {
  1041. jEdit.closeBuffer(view,_buffer);
  1042. return;
  1043. }
  1044. }
  1045. }
  1046. if(_buffer != null)
  1047. buffer = _buffer;
  1048. }
  1049. else
  1050. {
  1051. // if a file is selected in OPEN_DIALOG or
  1052. // SAVE_DIALOG mode, just let the listener(s)
  1053. // handle it
  1054. }
  1055. }
  1056. if(buffer != null)
  1057. {
  1058. switch(mode)
  1059. {
  1060. case M_OPEN:
  1061. view.setBuffer(buffer);
  1062. break;
  1063. case M_OPEN_NEW_VIEW:
  1064. jEdit.newView(view,buffer,false);
  1065. break;
  1066. case M_OPEN_NEW_PLAIN_VIEW:
  1067. jEdit.newView(view,buffer,true);
  1068. break;
  1069. case M_OPEN_NEW_SPLIT:
  1070. view.splitHorizontally().setBuffer(buffer);
  1071. break;
  1072. }
  1073. }
  1074. Object[] listeners = listenerList.getListenerList();
  1075. for(int i = 0; i < listeners.length; i++)
  1076. {
  1077. if(listeners[i] == BrowserListener.class)
  1078. {
  1079. BrowserListener l = (BrowserListener)listeners[i+1];
  1080. l.filesActivated(this,selectedFiles);
  1081. }
  1082. }
  1083. } //}}}
  1084. //{{{ dispose() method
  1085. /** Disposes the browser, regardless of whether it is a dialog or a dockable
  1086. */
  1087. public void dispose()
  1088. {
  1089. if (mode == BROWSER)
  1090. {
  1091. view.getDockableWindowManager().hideDockableWindow(NAME);
  1092. }
  1093. else
  1094. {
  1095. GUIUtilities.getParentDialog(this).dispose();
  1096. }
  1097. }//}}}
  1098. //{{{ move() method
  1099. @Override
  1100. public void move(String newPosition)
  1101. {
  1102. boolean horz = mode != BROWSER
  1103. || DockableWindowManager.TOP.equals(newPosition)
  1104. || DockableWindowManager.BOTTOM.equals(newPosition);
  1105. if (horz == horizontalLayout)
  1106. return;
  1107. horizontalLayout = horz;
  1108. topBox.remove(toolbarBox);
  1109. toolbarBox = new Box(horizontalLayout
  1110. ? BoxLayout.X_AXIS
  1111. : BoxLayout.Y_AXIS);
  1112. topBox.add(toolbarBox, 0);
  1113. propertiesChanged();
  1114. } //}}}
  1115. //{{{ Package-private members
  1116. // This can be null untill an user explicitly selects an encoding
  1117. // so that this don't overwrite more accurate encoding information
  1118. // like buffer histories.
  1119. String currentEncoding;
  1120. boolean autoDetectEncoding;
  1121. //{{{ directoryLoaded() method
  1122. void directoryLoaded(Object node, Object[] loadInfo,
  1123. boolean addToHistory)
  1124. {
  1125. String path = (String)loadInfo[0];
  1126. if(path == null)
  1127. {
  1128. // there was an error
  1129. return;
  1130. }
  1131. VFSFile[] list = (VFSFile[])loadInfo[1];
  1132. if(node == null)
  1133. {
  1134. // This is the new, canonical path
  1135. VFSBrowser.this.path = path;
  1136. if(!pathField.getText().equals(path))
  1137. pathField.setText(path);
  1138. if(path.endsWith("/") ||
  1139. path.endsWith(File.separator))
  1140. {
  1141. // ensure consistent history;
  1142. // eg we don't want both
  1143. // foo/ and foo
  1144. path = path.substring(0,
  1145. path.length() - 1);
  1146. }
  1147. if(addToHistory)
  1148. {
  1149. HistoryModel.getModel("vfs.browser.path")
  1150. .addItem(path);
  1151. }
  1152. }
  1153. boolean filterEnabled = filterCheckbox.isSelected();
  1154. List<VFSFile> directoryList = new ArrayList<VFSFile>();
  1155. int directories = 0;
  1156. int files = 0;
  1157. int invisible = 0;
  1158. if(list != null)
  1159. {
  1160. VFSFileFilter filter = getVFSFileFilter();
  1161. for(int i = 0; i < list.length; i++)
  1162. {
  1163. VFSFile file = list[i];
  1164. if(file.isHidden() && !showHiddenFiles)
  1165. {
  1166. invisible++;
  1167. continue;
  1168. }
  1169. if (filter != null && (filterEnabled || filter instanceof DirectoriesOnlyFilter)
  1170. && !filter.accept(file))
  1171. {
  1172. invisible++;
  1173. continue;
  1174. }
  1175. if(file.getType() == VFSFile.FILE)
  1176. files++;
  1177. else
  1178. directories++;
  1179. directoryList.add(file);
  1180. }
  1181. Collections.sort(directoryList,
  1182. new VFS.DirectoryEntryCompare(
  1183. sortMixFilesAndDirs,
  1184. sortIgnoreCase));
  1185. }
  1186. browserView.directoryLoaded(node,path,
  1187. directoryList);
  1188. // to notify listeners that any existing
  1189. // selection has been deactivated
  1190. // turns out under some circumstances this
  1191. // method can switch the current buffer in
  1192. // BROWSER mode.
  1193. // in any case, this is only needed for the
  1194. // directory chooser (why?), so we add a
  1195. // check. otherwise poor Rick will go insane.
  1196. if(mode == CHOOSE_DIRECTORY_DIALOG)
  1197. filesSelected();
  1198. } //}}}
  1199. //{{{ filesSelected() method
  1200. void filesSelected()
  1201. {
  1202. VFSFile[] selectedFiles = browserView.getSelectedFiles();
  1203. if(mode == BROWSER)
  1204. {
  1205. for(int i = 0; i < selectedFiles.length; i++)
  1206. {
  1207. VFSFile file = selectedFiles[i];
  1208. Buffer buffer = jEdit.getBuffer(file.getPath());
  1209. if(buffer != null && view != null)
  1210. view.setBuffer(buffer);
  1211. }
  1212. }
  1213. Object[] listeners = listenerList.getListenerList();
  1214. for(int i = 0; i < listeners.length; i++)
  1215. {
  1216. if(listeners[i] == BrowserListener.class)
  1217. {
  1218. BrowserListener l = (BrowserListener)listeners[i+1];
  1219. l.filesSelected(this,selectedFiles);
  1220. }
  1221. }
  1222. } //}}}
  1223. //{{{ endRequest() method
  1224. void endRequest()
  1225. {
  1226. requestRunning = false;
  1227. } //}}}
  1228. //}}}
  1229. //{{{ Private members
  1230. private static final ActionContext actionContext;
  1231. static
  1232. {
  1233. actionContext = new BrowserActionContext();
  1234. ActionSet builtInActionSet = new ActionSet(null,null,null,
  1235. jEdit.class.getResource("browser.actions.xml"));
  1236. builtInActionSet.setLabel(jEdit.getProperty("action-set.browser"));
  1237. builtInActionSet.load();
  1238. actionContext.addActionSet(builtInActionSet);
  1239. }
  1240. //{{{ Instance variables
  1241. private EventListenerList listenerList;
  1242. private View view;
  1243. private boolean horizontalLayout;
  1244. private String path;
  1245. private JPanel pathAndFilterPanel;
  1246. private HistoryTextField pathField;
  1247. private JComponent defaultFocusComponent;
  1248. private JCheckBox filterCheckbox;
  1249. private HistoryComboBoxEditor filterEditor;
  1250. private JComboBox filterField;
  1251. private Box toolbarBox;
  1252. private Box topBox;
  1253. private FavoritesMenuButton favorites;
  1254. private PluginsMenuButton plugins;
  1255. private BrowserView browserView;
  1256. private int mode;
  1257. private boolean multipleSelection;
  1258. private boolean showHiddenFiles;
  1259. private boolean sortMixFilesAndDirs;
  1260. private boolean sortIgnoreCase;
  1261. private boolean doubleClickClose;
  1262. private boolean requestRunning;
  1263. private boolean maybeReloadRequestRunning;
  1264. private final Stack<String> historyStack = new Stack<String>();
  1265. private final Stack<String> nextDirectoryStack = new Stack<String>();
  1266. //}}}
  1267. //{{{ createMenuBar() method
  1268. private Container createMenuBar()
  1269. {
  1270. JToolBar menuBar = new JToolBar();
  1271. menuBar.setFloatable(false);
  1272. menuBar.add(new CommandsMenuButton());
  1273. menuBar.add(Box.createHorizontalStrut(3));
  1274. menuBar.add(plugins = new PluginsMenuButton());
  1275. menuBar.add(Box.createHorizontalStrut(3));
  1276. menuBar.add(favorites = new FavoritesMenuButton());
  1277. return menuBar;
  1278. } //}}}
  1279. //{{{ createToolBar() method
  1280. private Container createToolBar()
  1281. {
  1282. if(mode == BROWSER)
  1283. return GUIUtilities.loadToolBar(actionContext,
  1284. "vfs.browser.toolbar-browser");
  1285. else
  1286. return GUIUtilities.loadToolBar(actionContext,
  1287. "vfs.browser.toolbar-dialog");
  1288. } //}}}
  1289. //{{{ propertiesChanged() method
  1290. private void propertiesChanged()
  1291. {
  1292. showHiddenFiles = jEdit.getBooleanProperty("vfs.browser.showHiddenFiles");
  1293. sortMixFilesAndDirs = jEdit.getBooleanProperty("vfs.browser.sortMixFilesAndDirs");
  1294. sortIgnoreCase = jEdit.getBooleanProperty("vfs.browser.sortIgnoreCase");
  1295. doubleClickClose = jEdit.getBooleanProperty("vfs.browser.doubleClickClose");
  1296. browserView.propertiesChanged();
  1297. toolbarBox.removeAll();
  1298. if(jEdit.getBooleanProperty("vfs.browser.showToolbar"))
  1299. {
  1300. Container toolbar = createToolBar();
  1301. toolbarBox.add(toolbar);
  1302. }
  1303. if(jEdit.getBooleanProperty("vfs.browser.showMenubar"))
  1304. {
  1305. Container menubar = createMenuBar();
  1306. if(horizontalLayout)
  1307. {
  1308. toolbarBox.add(menubar,0);
  1309. }
  1310. else
  1311. {
  1312. menubar.add(Box.createGlue());
  1313. toolbarBox.add(menubar);
  1314. }
  1315. }
  1316. else
  1317. {
  1318. plugins = null;
  1319. favorites = null;
  1320. }
  1321. revalidate();
  1322. if(path != null)
  1323. reloadDirectory();
  1324. } //}}}
  1325. /* We do this stuff because the browser is not able to handle
  1326. * more than one request yet */
  1327. //{{{ startRequest() method
  1328. private boolean startRequest()
  1329. {
  1330. if(requestRunning)
  1331. {
  1332. // dump stack trace for debugging purposes
  1333. Log.log(Log.DEBUG,this,new Throwable("For debugging purposes"));
  1334. GUIUtilities.error(this,"browser-multiple-io",null);
  1335. return false;
  1336. }
  1337. else
  1338. {
  1339. requestRunning = true;
  1340. return true;
  1341. }
  1342. } //}}}
  1343. //{{{ updateFilterEnabled() method
  1344. private void updateFilterEnabled()
  1345. {
  1346. filterField.setEnabled(filterCheckbox.isSelected());
  1347. filterEditor.setEnabled(filterCheckbox.isSelected());
  1348. } //}}}
  1349. //{{{ maybeReloadDirectory() method
  1350. private void maybeReloadDirectory(String dir)
  1351. {
  1352. if(MiscUtilities.isURL(dir)
  1353. && MiscUtilities.getProtocolOfURL(dir).equals(
  1354. FavoritesVFS.PROTOCOL))
  1355. {
  1356. if(favorites != null)
  1357. favorites.popup = null;
  1358. }
  1359. // this is a dirty hack and it relies on the fact
  1360. // that updates for parents are sent before updates
  1361. // for the changed nodes themselves (if this was not
  1362. // the case, the browser wouldn't be updated properly
  1363. // on delete, etc).
  1364. //
  1365. // to avoid causing '> 1 request' errors, don't reload
  1366. // directory if request already active
  1367. if(maybeReloadRequestRunning)
  1368. {
  1369. //Log.log(Log.WARNING,this,"VFS update: request already in progress");
  1370. return;
  1371. }
  1372. // save a file -> sends vfs update. if a VFS file dialog box
  1373. // is shown from the same event frame as the save, the
  1374. // VFSUpdate will be delivered before the directory is loaded,
  1375. // and before the path is set.
  1376. if(path != null)
  1377. {
  1378. try
  1379. {
  1380. maybeReloadRequestRunning = true;
  1381. browserView.maybeReloadDirectory(dir);
  1382. }
  1383. finally
  1384. {
  1385. // Do not change this until all VFS Browser tasks are
  1386. // done in ThreadUtilities
  1387. VFSManager.runInAWTThread(new Runnable()
  1388. {
  1389. public void run()
  1390. {
  1391. maybeReloadRequestRunning = false;
  1392. }
  1393. });
  1394. }
  1395. }
  1396. } //}}}
  1397. //}}}
  1398. //{{{ Inner classes
  1399. //{{{ ActionHandler class
  1400. class ActionHandler implements ActionListener, ItemListener
  1401. {
  1402. @Override
  1403. public void actionPerformed(ActionEvent evt)
  1404. {
  1405. if (isProcessingEvent)
  1406. return;
  1407. Object source = evt.getSource();
  1408. if (source == pathField
  1409. || source == filterCheckbox)
  1410. {
  1411. isProcessingEvent = true;
  1412. resetLater();
  1413. updateFilterEnabled();
  1414. String p = pathField.getText();
  1415. if(p != null)
  1416. setDirectory(p);
  1417. browserView.focusOnFileView();
  1418. }
  1419. else if (source == filterField.getEditor())
  1420. {
  1421. // force the editor to refresh.
  1422. filterField.getEditor().setItem(
  1423. filterField.getEditor().getItem());
  1424. }
  1425. // depending on Swing look & feel, filterField.getEditor()
  1426. // returns some ComboBoxUI
  1427. else if (source == filterEditor)
  1428. {
  1429. // force the editor to refresh.
  1430. filterEditor.setItem(
  1431. filterEditor.getItem());
  1432. filterField.setSelectedItem(
  1433. filterEditor.getItem());
  1434. // ### ugly:
  1435. // itemStateChanged does not seem to get fired
  1436. itemStateChanged(new ItemEvent(filterField,
  1437. ItemEvent.ITEM_STATE_CHANGED,
  1438. filterEditor.getItem(),
  1439. ItemEvent.SELECTED));
  1440. }
  1441. }
  1442. @Override
  1443. public void itemStateChanged(ItemEvent e)
  1444. {
  1445. if (isProcessingEvent)
  1446. return;
  1447. if (e.getStateChange() != ItemEvent.SELECTED)
  1448. return;
  1449. isProcessingEvent = true;
  1450. resetLater();
  1451. filterField.setEditable(e.getItem() instanceof GlobVFSFileFilter);
  1452. updateFilterEnabled();
  1453. String path = pathField.getText();
  1454. if(path != null)
  1455. setDirectory(path);
  1456. browserView.focusOnFileView();
  1457. }
  1458. /**
  1459. * Why this method exists: since both actionPerformed()
  1460. * and itemStateChanged() above can change the combo box,
  1461. * executing one of them can cause a chain reaction causing
  1462. * the other method to be called. This would cause the
  1463. * VFS subsystem to be called several times, which would
  1464. * cause a warning to show up if the first operation is
  1465. * still in progress, or cause a second operation to happen
  1466. * which is not really wanted especially if we're talking
  1467. * about a remove VFS. So the methods set a flag saying
  1468. * that something is going on, and this method resets
  1469. * the flag after the AWT thread is done with the
  1470. * current events.
  1471. */
  1472. private void resetLater()
  1473. {
  1474. ThreadUtilities.runInDispatchThread(new Runnable()
  1475. {
  1476. @Override
  1477. public void run()
  1478. {
  1479. isProcessingEvent = false;
  1480. }
  1481. }
  1482. );
  1483. }
  1484. private boolean isProcessingEvent;
  1485. } //}}}
  1486. //{{{ CommandsMenuButton class
  1487. class CommandsMenuButton extends RolloverButton
  1488. {
  1489. //{{{ CommandsMenuButton constructor
  1490. CommandsMenuButton()
  1491. {
  1492. setText(jEdit.getProperty("vfs.browser.commands.label"));
  1493. setIcon(GUIUtilities.loadIcon(jEdit.getProperty("dropdown-arrow.icon")));
  1494. setHorizontalTextPosition(SwingConstants.LEADING);
  1495. setName("commands");
  1496. popup = new BrowserCommandsMenu(VFSBrowser.this,null);
  1497. CommandsMenuButton.this.setRequestFocusEnabled(false);
  1498. setMargin(new Insets(1,1,1,1));
  1499. CommandsMenuButton.this.addMouseListener(new MouseHandler());
  1500. if(OperatingSystem.isMacOSLF())
  1501. CommandsMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
  1502. } //}}}
  1503. BrowserCommandsMenu popup;
  1504. //{{{ MouseHandler class
  1505. class MouseHandler extends MouseAdapter
  1506. {
  1507. @Override
  1508. public void mousePressed(MouseEvent evt)
  1509. {
  1510. if(!popup.isVisible())
  1511. {
  1512. popup.update();
  1513. GUIUtilities.showPopupMenu(
  1514. popup,CommandsMenuButton.this,0,
  1515. CommandsMenuButton.this.getHeight(),
  1516. false);
  1517. }
  1518. else
  1519. {
  1520. popup.setVisible(false);
  1521. }
  1522. }
  1523. } //}}}
  1524. } //}}}
  1525. //{{{ PluginsMenuButton class
  1526. class PluginsMenuButton extends RolloverButton
  1527. {
  1528. //{{{ PluginsMenuButton constructor
  1529. PluginsMenuButton()
  1530. {
  1531. setText(jEdit.getProperty("vfs.browser.plugins.label"));
  1532. setIcon(GUIUtilities.loadIcon(jEdit.getProperty("dropdown-arrow.icon")));
  1533. setHorizontalTextPosition(SwingConstants.LEADING);
  1534. setName("plugins");
  1535. PluginsMenuButton.this.setRequestFocusEnabled(false);
  1536. setMargin(new Insets(1,1,1,1));
  1537. PluginsMenuButton.this.addMouseListener(new MouseHandler());
  1538. if(OperatingSystem.isMacOSLF())
  1539. PluginsMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
  1540. } //}}}
  1541. JPopupMenu popup;
  1542. //{{{ updatePopupMenu() method
  1543. void updatePopupMenu()
  1544. {
  1545. popup = null;
  1546. } //}}}
  1547. //{{{ createPopupMenu() method
  1548. private void createPopupMenu()
  1549. {
  1550. if(popup != null)
  1551. return;
  1552. popup = (JPopupMenu)createPluginsMenu(new JPopupMenu(),true);
  1553. } //}}}
  1554. //{{{ MouseHandler class
  1555. class MouseHandler extends MouseAdapter
  1556. {
  1557. @Override
  1558. public void mousePressed(MouseEvent evt)
  1559. {
  1560. createPopupMenu();
  1561. if(!popup.isVisible())
  1562. {
  1563. GUIUtilities.showPopupMenu(
  1564. popup,PluginsMenuButton.this,0,
  1565. PluginsMenuButton.this.getHeight(),
  1566. false);
  1567. }
  1568. else
  1569. {
  1570. popup.setVisible(false);
  1571. }
  1572. }
  1573. } //}}}
  1574. } //}}}
  1575. //{{{ FavoritesMenuButton class
  1576. class FavoritesMenuButton extends RolloverButton
  1577. {
  1578. //{{{ FavoritesMenuButton constructor
  1579. FavoritesMenuButton()
  1580. {
  1581. setText(jEdit.getProperty("vfs.browser.favorites.label"));
  1582. setIcon(GUIUtilities.loadIcon(jEdit.getProperty("dropdown-arrow.icon")));
  1583. setHorizontalTextPosition(SwingConstants.LEADING);
  1584. setName("favorites");
  1585. FavoritesMenuButton.this.setRequestFocusEnabled(false);
  1586. setMargin(new Insets(1,1,1,1));
  1587. FavoritesMenuButton.this.addMouseListener(new MouseHandler());
  1588. if(OperatingSystem.isMacOSLF())
  1589. FavoritesMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
  1590. } //}}}
  1591. JPopupMenu popup;
  1592. //{{{ createPopupMenu() method
  1593. void createPopupMenu()
  1594. {
  1595. popup = new JPopupMenu();
  1596. ActionHandler actionHandler = new ActionHandler();
  1597. JMenuItem mi = new JMenuItem(
  1598. jEdit.getProperty(
  1599. "vfs.browser.favorites"
  1600. + ".add-to-favorites.label"));
  1601. mi.setActionCommand("add-to-favorites");
  1602. mi.addActionListener(actionHandler);
  1603. popup.add(mi);
  1604. mi = new JMenuItem(
  1605. jEdit.getProperty(
  1606. "vfs.browser.favorites"
  1607. + ".edit-favorites.label"));
  1608. mi.setActionCommand("dir@favorites:");
  1609. mi.addActionListener(actionHandler);
  1610. popup.add(mi);
  1611. popup.addSeparator();
  1612. VFSFile[] favorites = FavoritesVFS.getFavorites();
  1613. if(favorites.length == 0)
  1614. {
  1615. mi = new JMenuItem(
  1616. jEdit.getProperty(
  1617. "vfs.browser.favorites"
  1618. + ".no-favorites.label"));
  1619. mi.setEnabled(false);
  1620. popup.add(mi);
  1621. }
  1622. else
  1623. {
  1624. Arrays.sort(favorites,
  1625. new VFS.DirectoryEntryCompare(
  1626. sortMixFilesAndDirs,
  1627. sortIgnoreCase));
  1628. for(int i = 0; i < favorites.length; i++)
  1629. {
  1630. FavoritesVFS.Favorite favorite = (FavoritesVFS.Favorite) favorites[i];
  1631. mi = new JMenuItem(favorite.getLabel());
  1632. mi.setIcon(FileCellRenderer
  1633. .getIconForFile(
  1634. favorite,false));
  1635. String cmd = (favorite.getType() ==
  1636. VFSFile.FILE
  1637. ? "file@" : "dir@")
  1638. + favorite.getPath();
  1639. mi.setActionCommand(cmd);
  1640. mi.addActionListener(actionHandler);
  1641. popup.add(mi);
  1642. }
  1643. }
  1644. } //}}}
  1645. //{{{ ActionHandler class
  1646. class ActionHandler implements ActionListener
  1647. {
  1648. @Override
  1649. public void actionPerformed(ActionEvent evt)
  1650. {
  1651. String actionCommand = evt.getActionCommand();
  1652. if("add-to-favorites".equals(actionCommand))
  1653. {
  1654. // if any directories are selected, add
  1655. // them, otherwise add current directory
  1656. VFSFile[] selected = getSelectedFiles();
  1657. if(selected == null || selected.length == 0)
  1658. {
  1659. if(path.equals(FavoritesVFS.PROTOCOL + ':'))
  1660. {
  1661. GUIUtilities.error(VFSBrowser.this,
  1662. "vfs.browser.recurse-favorites",
  1663. null);
  1664. }
  1665. else
  1666. {
  1667. FavoritesVFS.addToFavorites(path,
  1668. VFSFile.DIRECTORY);
  1669. }
  1670. }
  1671. else
  1672. {
  1673. for(int i = 0; i < selected.length; i++)
  1674. {
  1675. VFSFile file = selected[i];
  1676. FavoritesVFS.addToFavorites(file.getPath(),
  1677. file.getType());
  1678. }
  1679. }
  1680. }
  1681. else if(actionCommand.startsWith("dir@"))
  1682. {
  1683. setDirectory(actionCommand.substring(4));
  1684. }
  1685. else if(actionCommand.startsWith("file@"))
  1686. {
  1687. switch(getMode())
  1688. {
  1689. case BROWSER:
  1690. jEdit.openFile(view,actionCommand.substring(5));
  1691. break;
  1692. default:
  1693. locateFile(actionCommand.substring(5));
  1694. break;
  1695. }
  1696. }
  1697. }
  1698. } //}}}
  1699. //{{{ MouseHandler class
  1700. class MouseHandler extends MouseAdapter
  1701. {
  1702. @Override
  1703. public void mousePressed(MouseEvent evt)
  1704. {
  1705. if(popup != null && popup.isVisible())
  1706. {
  1707. popup.setVisible(false);
  1708. return;
  1709. }
  1710. if(popup == null)
  1711. createPopupMenu();
  1712. GUIUtilities.showPopupMenu(
  1713. popup,FavoritesMenuButton.this,0,
  1714. FavoritesMenuButton.this.getHeight(),
  1715. false);
  1716. }
  1717. } //}}}
  1718. } //}}}
  1719. //{{{ BrowserActionContext class
  1720. static class BrowserActionContext extends ActionContext
  1721. {
  1722. @Override
  1723. public void invokeAction(EventObject evt, EditAction action)
  1724. {
  1725. Component source = (Component)evt.getSource();
  1726. VFSBrowser browser = (VFSBrowser)
  1727. GUIUtilities.getComponentParent(
  1728. source,
  1729. VFSBrowser.class);
  1730. VFSFile[] files = browser.getSelectedFiles(source);
  1731. // in the future we will want something better,
  1732. // eg. having an 'evt' object passed to
  1733. // EditAction.invoke().
  1734. // for now, since all browser actions are
  1735. // written in beanshell we set the 'browser'
  1736. // variable directly.
  1737. NameSpace global = BeanShell.getNameSpace();
  1738. try
  1739. {
  1740. global.setVariable("browser",browser);
  1741. global.setVariable("files",files);
  1742. View view = browser.getView();
  1743. // I guess ideally all browsers
  1744. // should have views, but since they
  1745. // don't, we just use the active view
  1746. // in that…

Large files files are truncated, but you can click here to view the full file