/jEdit/tags/jedit-4-3-pre11/org/gjt/sp/jedit/browser/VFSBrowser.java

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