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

# · Java · 1493 lines · 1081 code · 189 blank · 223 comment · 211 complexity · adcf3f62739cdcfffed67aab628ce486 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.EvalError;
  25. import bsh.NameSpace;
  26. import gnu.regexp.*;
  27. import javax.swing.border.EmptyBorder;
  28. import javax.swing.event.*;
  29. import javax.swing.tree.DefaultMutableTreeNode;
  30. import javax.swing.*;
  31. import java.awt.event.*;
  32. import java.awt.*;
  33. import java.io.File;
  34. import java.util.*;
  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.util.Log;
  41. //}}}
  42. /**
  43. * The main class of the VFS browser.
  44. * @author Slava Pestov
  45. * @version $Id: VFSBrowser.java 4665 2003-04-30 05:28:55Z spestov $
  46. */
  47. public class VFSBrowser extends JPanel implements EBComponent, DefaultFocusComponent
  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, boolean multipleSelection,
  148. String position)
  149. {
  150. super(new BorderLayout());
  151. listenerList = new EventListenerList();
  152. this.mode = mode;
  153. this.multipleSelection = multipleSelection;
  154. this.floating = floating;
  155. this.view = view;
  156. currentEncoding = jEdit.getProperty("buffer.encoding",
  157. System.getProperty("file.encoding"));
  158. ActionHandler actionHandler = new ActionHandler();
  159. Box topBox = new Box(BoxLayout.Y_AXIS);
  160. horizontalLayout = (mode != BROWSER
  161. || DockableWindowManager.TOP.equals(position)
  162. || DockableWindowManager.BOTTOM.equals(position));
  163. toolbarBox = new Box(horizontalLayout
  164. ? BoxLayout.X_AXIS
  165. : BoxLayout.Y_AXIS);
  166. topBox.add(toolbarBox);
  167. GridBagLayout layout = new GridBagLayout();
  168. JPanel pathAndFilterPanel = new JPanel(layout);
  169. GridBagConstraints cons = new GridBagConstraints();
  170. cons.gridwidth = cons.gridheight = 1;
  171. cons.gridx = cons.gridy = 0;
  172. cons.fill = GridBagConstraints.BOTH;
  173. cons.anchor = GridBagConstraints.EAST;
  174. JLabel label = new JLabel(jEdit.getProperty("vfs.browser.path"),
  175. SwingConstants.RIGHT);
  176. label.setBorder(new EmptyBorder(0,0,0,12));
  177. layout.setConstraints(label,cons);
  178. pathAndFilterPanel.add(label);
  179. pathField = new HistoryTextField("vfs.browser.path");
  180. pathField.setInstantPopups(true);
  181. pathField.setEnterAddsToHistory(false);
  182. pathField.setSelectAllOnFocus(true);
  183. if(floating)
  184. {
  185. label.setDisplayedMnemonic(jEdit.getProperty(
  186. "vfs.browser.path.mnemonic").charAt(0));
  187. label.setLabelFor(pathField);
  188. }
  189. // because its preferred size can be quite wide, we
  190. // don't want it to make the browser way too big,
  191. // so set the preferred width to 0.
  192. Dimension prefSize = pathField.getPreferredSize();
  193. prefSize.width = 0;
  194. pathField.setPreferredSize(prefSize);
  195. pathField.addActionListener(actionHandler);
  196. cons.gridx = 1;
  197. cons.weightx = 1.0f;
  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. if(mode != CHOOSE_DIRECTORY_DIALOG)
  208. {
  209. cons.gridx = 0;
  210. cons.weightx = 0.0f;
  211. cons.gridy = 1;
  212. layout.setConstraints(filterCheckbox,cons);
  213. pathAndFilterPanel.add(filterCheckbox);
  214. }
  215. filterField = new HistoryTextField("vfs.browser.filter");
  216. filterField.setInstantPopups(true);
  217. filterField.setSelectAllOnFocus(true);
  218. filterField.addActionListener(actionHandler);
  219. if(mode != CHOOSE_DIRECTORY_DIALOG)
  220. {
  221. cons.gridx = 1;
  222. cons.weightx = 1.0f;
  223. layout.setConstraints(filterField,cons);
  224. pathAndFilterPanel.add(filterField);
  225. }
  226. topBox.add(pathAndFilterPanel);
  227. add(BorderLayout.NORTH,topBox);
  228. add(BorderLayout.CENTER,browserView = new BrowserView(this));
  229. propertiesChanged();
  230. String filter;
  231. if(mode == BROWSER || !jEdit.getBooleanProperty(
  232. "vfs.browser.currentBufferFilter"))
  233. {
  234. filter = jEdit.getProperty("vfs.browser.last-filter");
  235. if(filter == null)
  236. filter = jEdit.getProperty("vfs.browser.default-filter");
  237. }
  238. else
  239. {
  240. String ext = MiscUtilities.getFileExtension(
  241. view.getBuffer().getName());
  242. if(ext.length() == 0)
  243. filter = jEdit.getProperty("vfs.browser.default-filter");
  244. else
  245. filter = "*" + ext;
  246. }
  247. filterField.setText(filter);
  248. filterField.addCurrentToHistory();
  249. updateFilterEnabled();
  250. // see VFSBrowser.browseDirectory()
  251. if(path == null)
  252. path = jEdit.getProperty("vfs.browser.path.tmp");
  253. if(path == null || path.length() == 0)
  254. {
  255. String userHome = System.getProperty("user.home");
  256. String defaultPath = jEdit.getProperty("vfs.browser.defaultPath");
  257. if(defaultPath.equals("home"))
  258. path = userHome;
  259. else if(defaultPath.equals("working"))
  260. path = System.getProperty("user.dir");
  261. else if(defaultPath.equals("buffer"))
  262. {
  263. if(view != null)
  264. {
  265. Buffer buffer = view.getBuffer();
  266. path = buffer.getDirectory();
  267. }
  268. else
  269. path = userHome;
  270. }
  271. else if(defaultPath.equals("last"))
  272. {
  273. HistoryModel pathModel = HistoryModel.getModel("vfs.browser.path");
  274. if(pathModel.getSize() == 0)
  275. path = "~";
  276. else
  277. path = pathModel.getItem(0);
  278. }
  279. else if(defaultPath.equals("favorites"))
  280. path = "favorites:";
  281. else
  282. {
  283. // unknown value??!!!
  284. path = userHome;
  285. }
  286. }
  287. final String _path = path;
  288. SwingUtilities.invokeLater(new Runnable()
  289. {
  290. public void run()
  291. {
  292. setDirectory(_path);
  293. }
  294. });
  295. } //}}}
  296. //{{{ focusOnDefaultComponent() method
  297. public void focusOnDefaultComponent()
  298. {
  299. browserView.focusOnFileView();
  300. } //}}}
  301. //{{{ addNotify() method
  302. public void addNotify()
  303. {
  304. super.addNotify();
  305. EditBus.addToBus(this);
  306. } //}}}
  307. //{{{ removeNotify() method
  308. public void removeNotify()
  309. {
  310. super.removeNotify();
  311. jEdit.setBooleanProperty("vfs.browser.filter-enabled",
  312. filterCheckbox.isSelected());
  313. if(mode == BROWSER || !jEdit.getBooleanProperty(
  314. "vfs.browser.currentBufferFilter"))
  315. {
  316. jEdit.setProperty("vfs.browser.last-filter",
  317. filterField.getText());
  318. }
  319. EditBus.removeFromBus(this);
  320. } //}}}
  321. //{{{ handleMessage() method
  322. public void handleMessage(EBMessage msg)
  323. {
  324. if(msg instanceof PropertiesChanged)
  325. propertiesChanged();
  326. else if(msg instanceof BufferUpdate)
  327. {
  328. BufferUpdate bmsg = (BufferUpdate)msg;
  329. if(bmsg.getWhat() == BufferUpdate.CREATED
  330. || bmsg.getWhat() == BufferUpdate.CLOSED)
  331. browserView.updateFileView();
  332. // hacked BufferIORequest to send VFSUpdates in case
  333. // two stage save is off now...
  334. /* else if(bmsg.getWhat() == BufferUpdate.SAVED)
  335. {
  336. maybeReloadDirectory(MiscUtilities.getParentOfPath(
  337. bmsg.getBuffer().getPath()));
  338. } */
  339. }
  340. else if(msg instanceof VFSUpdate)
  341. {
  342. maybeReloadDirectory(((VFSUpdate)msg).getPath());
  343. }
  344. } //}}}
  345. //{{{ getView() method
  346. public View getView()
  347. {
  348. return view;
  349. } //}}}
  350. //{{{ getMode() method
  351. public int getMode()
  352. {
  353. return mode;
  354. } //}}}
  355. //{{{ isMultipleSelectionEnabled() method
  356. public boolean isMultipleSelectionEnabled()
  357. {
  358. return multipleSelection;
  359. } //}}}
  360. //{{{ isHorizontalLayout() method
  361. public boolean isHorizontalLayout()
  362. {
  363. return horizontalLayout;
  364. } //}}}
  365. //{{{ getShowHiddenFiles() method
  366. public boolean getShowHiddenFiles()
  367. {
  368. return showHiddenFiles;
  369. } //}}}
  370. //{{{ setShowHiddenFiles() method
  371. public void setShowHiddenFiles(boolean showHiddenFiles)
  372. {
  373. this.showHiddenFiles = showHiddenFiles;
  374. } //}}}
  375. //{{{ getFilenameFilter() method
  376. /**
  377. * Returns the file name filter glob.
  378. * @since jEdit 3.2pre2
  379. */
  380. public String getFilenameFilter()
  381. {
  382. if(filterCheckbox.isSelected())
  383. {
  384. String filter = filterField.getText();
  385. if(filter.length() == 0)
  386. return "*";
  387. else
  388. return filter;
  389. }
  390. else
  391. return "*";
  392. } //}}}
  393. //{{{ setFilenameFilter() method
  394. public void setFilenameFilter(String filter)
  395. {
  396. if(filter == null || filter.length() == 0 || filter.equals("*"))
  397. filterCheckbox.setSelected(false);
  398. else
  399. {
  400. filterCheckbox.setSelected(true);
  401. filterField.setText(filter);
  402. }
  403. } //}}}
  404. //{{{ getDirectoryField() method
  405. public HistoryTextField getDirectoryField()
  406. {
  407. return pathField;
  408. } //}}}
  409. //{{{ getDirectory() method
  410. public String getDirectory()
  411. {
  412. return path;
  413. } //}}}
  414. //{{{ setDirectory() method
  415. public void setDirectory(String path)
  416. {
  417. if(path.startsWith("file:"))
  418. path = path.substring(5);
  419. pathField.setText(path);
  420. if(!startRequest())
  421. return;
  422. updateFilenameFilter();
  423. browserView.loadDirectory(null,path);
  424. this.path = path;
  425. VFSManager.runInAWTThread(new Runnable()
  426. {
  427. public void run()
  428. {
  429. endRequest();
  430. }
  431. });
  432. } //}}}
  433. //{{{ rootDirectory() method
  434. /**
  435. * Goes to the local drives directory.
  436. * @since jEdit 4.0pre4
  437. */
  438. public void rootDirectory()
  439. {
  440. if(OperatingSystem.isMacOS() || OperatingSystem.isDOSDerived())
  441. setDirectory(FileRootsVFS.PROTOCOL + ":");
  442. else
  443. setDirectory("/");
  444. } //}}}
  445. //{{{ reloadDirectory() method
  446. public void reloadDirectory()
  447. {
  448. // used by FTP plugin to clear directory cache
  449. VFSManager.getVFSForPath(path).reloadDirectory(path);
  450. updateFilenameFilter();
  451. browserView.loadDirectory(null,path);
  452. } //}}}
  453. //{{{ delete() method
  454. /**
  455. * Note that all files must be on the same VFS.
  456. */
  457. public void delete(VFS.DirectoryEntry[] files)
  458. {
  459. String dialogType;
  460. if(MiscUtilities.isURL(files[0].deletePath)
  461. && FavoritesVFS.PROTOCOL.equals(
  462. MiscUtilities.getProtocolOfURL(files[0].deletePath)))
  463. {
  464. dialogType = "vfs.browser.delete-favorites";
  465. }
  466. else
  467. {
  468. dialogType = "vfs.browser.delete-confirm";
  469. }
  470. StringBuffer buf = new StringBuffer();
  471. for(int i = 0; i < files.length; i++)
  472. {
  473. buf.append(files[i].path);
  474. buf.append('\n');
  475. }
  476. Object[] args = { buf.toString() };
  477. int result = GUIUtilities.confirm(this,dialogType,args,
  478. JOptionPane.YES_NO_OPTION,
  479. JOptionPane.WARNING_MESSAGE);
  480. if(result != JOptionPane.YES_OPTION)
  481. return;
  482. VFS vfs = VFSManager.getVFSForPath(files[0].deletePath);
  483. if(!startRequest())
  484. return;
  485. for(int i = 0; i < files.length; i++)
  486. {
  487. Object session = vfs.createVFSSession(files[i].deletePath,this);
  488. if(session == null)
  489. continue;
  490. VFSManager.runInWorkThread(new BrowserIORequest(
  491. BrowserIORequest.DELETE,this,
  492. session,vfs,files[i].deletePath,
  493. null,null));
  494. }
  495. } //}}}
  496. //{{{ rename() method
  497. public void rename(String from)
  498. {
  499. VFS vfs = VFSManager.getVFSForPath(from);
  500. String filename = vfs.getFileName(from);
  501. String[] args = { filename };
  502. String to = GUIUtilities.input(this,"vfs.browser.rename",
  503. args,filename);
  504. if(to == null)
  505. return;
  506. to = MiscUtilities.constructPath(vfs.getParentOfPath(from),to);
  507. Object session = vfs.createVFSSession(from,this);
  508. if(session == null)
  509. return;
  510. if(!startRequest())
  511. return;
  512. VFSManager.runInWorkThread(new BrowserIORequest(
  513. BrowserIORequest.RENAME,this,
  514. session,vfs,from,to,null));
  515. } //}}}
  516. //{{{ mkdir() method
  517. public void mkdir()
  518. {
  519. String newDirectory = GUIUtilities.input(this,"vfs.browser.mkdir",null);
  520. if(newDirectory == null)
  521. return;
  522. // if a directory is selected, create new dir in there.
  523. // if a file is selected, create new dir inside its parent.
  524. VFS.DirectoryEntry[] selected = getSelectedFiles();
  525. String parent;
  526. if(selected.length == 0)
  527. parent = path;
  528. else if(selected[0].type == VFS.DirectoryEntry.FILE)
  529. {
  530. parent = selected[0].path;
  531. parent = VFSManager.getVFSForPath(parent)
  532. .getParentOfPath(parent);
  533. }
  534. else
  535. parent = selected[0].path;
  536. VFS vfs = VFSManager.getVFSForPath(parent);
  537. // path is the currently viewed directory in the browser
  538. newDirectory = MiscUtilities.constructPath(parent,newDirectory);
  539. Object session = vfs.createVFSSession(newDirectory,this);
  540. if(session == null)
  541. return;
  542. if(!startRequest())
  543. return;
  544. VFSManager.runInWorkThread(new BrowserIORequest(
  545. BrowserIORequest.MKDIR,this,
  546. session,vfs,newDirectory,null,null));
  547. } //}}}
  548. //{{{ newFile() method
  549. /**
  550. * Creates a new file in the current directory.
  551. * @since jEdit 4.0pre2
  552. */
  553. public void newFile()
  554. {
  555. VFS.DirectoryEntry[] selected = getSelectedFiles();
  556. if(selected.length >= 1)
  557. {
  558. VFS.DirectoryEntry file = selected[0];
  559. if(file.type == VFS.DirectoryEntry.DIRECTORY)
  560. jEdit.newFile(view,file.path);
  561. else
  562. {
  563. VFS vfs = VFSManager.getVFSForPath(file.path);
  564. jEdit.newFile(view,vfs.getParentOfPath(file.path));
  565. }
  566. }
  567. else
  568. jEdit.newFile(view,path);
  569. } //}}}
  570. //{{{ searchInDirectory() method
  571. /**
  572. * Opens a directory search in the current directory.
  573. * @since jEdit 4.0pre2
  574. */
  575. public void searchInDirectory()
  576. {
  577. VFS.DirectoryEntry[] selected = getSelectedFiles();
  578. if(selected.length >= 1)
  579. {
  580. VFS.DirectoryEntry file = selected[0];
  581. searchInDirectory(file.path,file.type != VFS.DirectoryEntry.FILE);
  582. }
  583. else
  584. {
  585. searchInDirectory(this.path,true);
  586. }
  587. } //}}}
  588. //{{{ searchInDirectory() method
  589. /**
  590. * Opens a directory search in the specified directory.
  591. * @param path The path name
  592. * @param directory True if the path is a directory, false if it is a file
  593. * @since jEdit 4.2pre1
  594. */
  595. public void searchInDirectory(String path, boolean directory)
  596. {
  597. String filter;
  598. if(directory)
  599. {
  600. filter = getFilenameFilter();
  601. }
  602. else
  603. {
  604. VFS vfs = VFSManager.getVFSForPath(path);
  605. path = vfs.getParentOfPath(path);
  606. String name = MiscUtilities.getFileName(path);
  607. String ext = MiscUtilities.getFileExtension(name);
  608. filter = (ext == null || ext.length() == 0
  609. ? getFilenameFilter()
  610. : "*" + ext);
  611. }
  612. SearchAndReplace.setSearchFileSet(new DirectoryListSet(
  613. path,filter,true));
  614. new SearchDialog(view,null,SearchDialog.DIRECTORY);
  615. } //}}}
  616. //{{{ getBrowserView() method
  617. public BrowserView getBrowserView()
  618. {
  619. return browserView;
  620. } //}}}
  621. //{{{ getSelectedFiles() method
  622. public VFS.DirectoryEntry[] getSelectedFiles()
  623. {
  624. return browserView.getSelectedFiles();
  625. } //}}}
  626. //{{{ addBrowserListener() method
  627. public void addBrowserListener(BrowserListener l)
  628. {
  629. listenerList.add(BrowserListener.class,l);
  630. } //}}}
  631. //{{{ removeBrowserListener() method
  632. public void removeBrowserListener(BrowserListener l)
  633. {
  634. listenerList.remove(BrowserListener.class,l);
  635. } //}}}
  636. //{{{ Package-private members
  637. String currentEncoding;
  638. //{{{ updateFilenameFilter() method
  639. void updateFilenameFilter()
  640. {
  641. try
  642. {
  643. String filter = filterField.getText();
  644. if(filter.length() == 0)
  645. filter = "*";
  646. filenameFilter = new RE(MiscUtilities.globToRE(filter),RE.REG_ICASE);
  647. }
  648. catch(Exception e)
  649. {
  650. Log.log(Log.ERROR,VFSBrowser.this,e);
  651. String[] args = { filterField.getText(),
  652. e.getMessage() };
  653. GUIUtilities.error(this,"vfs.browser.bad-filter",args);
  654. }
  655. } //}}}
  656. //{{{ directoryLoaded() method
  657. void directoryLoaded(final Object node,
  658. final String path,
  659. final VFS.DirectoryEntry[] list)
  660. {
  661. VFSManager.runInAWTThread(new Runnable()
  662. {
  663. public void run()
  664. {
  665. if(node == null)
  666. {
  667. // This is the new, canonical path
  668. VFSBrowser.this.path = path;
  669. if(!pathField.getText().equals(path))
  670. pathField.setText(path);
  671. pathField.addCurrentToHistory();
  672. }
  673. boolean filterEnabled = filterCheckbox.isSelected();
  674. ArrayList directoryVector = new ArrayList();
  675. int directories = 0;
  676. int files = 0;
  677. int invisible = 0;
  678. if(list != null)
  679. {
  680. for(int i = 0; i < list.length; i++)
  681. {
  682. VFS.DirectoryEntry file = list[i];
  683. if(file.hidden && !showHiddenFiles)
  684. {
  685. invisible++;
  686. continue;
  687. }
  688. if(file.type == VFS.DirectoryEntry.FILE
  689. && filterEnabled
  690. && filenameFilter != null
  691. && !filenameFilter.isMatch(file.name))
  692. {
  693. invisible++;
  694. continue;
  695. }
  696. if(file.type == VFS.DirectoryEntry.FILE)
  697. files++;
  698. else
  699. directories++;
  700. directoryVector.add(file);
  701. }
  702. MiscUtilities.quicksort(directoryVector,
  703. new VFS.DirectoryEntryCompare(
  704. sortMixFilesAndDirs,
  705. sortIgnoreCase));
  706. }
  707. browserView.directoryLoaded(node,path,
  708. directoryVector);
  709. // to notify listeners that any existing
  710. // selection has been deactivated
  711. // turns out under some circumstances this
  712. // method can switch the current buffer in
  713. // BROWSER mode.
  714. // in any case, this is only needed for the
  715. // directory chooser (why?), so we add a
  716. // check. otherwise poor Rick will go insane.
  717. if(mode == CHOOSE_DIRECTORY_DIALOG)
  718. filesSelected();
  719. }
  720. });
  721. } //}}}
  722. //{{{ filesSelected() method
  723. void filesSelected()
  724. {
  725. VFS.DirectoryEntry[] selectedFiles = browserView.getSelectedFiles();
  726. if(mode == BROWSER)
  727. {
  728. for(int i = 0; i < selectedFiles.length; i++)
  729. {
  730. VFS.DirectoryEntry file = selectedFiles[i];
  731. Buffer buffer = jEdit.getBuffer(file.path);
  732. if(buffer != null && view != null)
  733. view.setBuffer(buffer);
  734. }
  735. }
  736. Object[] listeners = listenerList.getListenerList();
  737. for(int i = 0; i < listeners.length; i++)
  738. {
  739. if(listeners[i] == BrowserListener.class)
  740. {
  741. BrowserListener l = (BrowserListener)listeners[i+1];
  742. l.filesSelected(this,selectedFiles);
  743. }
  744. }
  745. } //}}}
  746. //{{{ filesActivated() method
  747. // canDoubleClickClose set to false when ENTER pressed
  748. static final int M_OPEN = 0;
  749. static final int M_OPEN_NEW_VIEW = 1;
  750. static final int M_OPEN_NEW_PLAIN_VIEW = 2;
  751. static final int M_OPEN_NEW_SPLIT = 3;
  752. void filesActivated(int mode, boolean canDoubleClickClose)
  753. {
  754. VFS.DirectoryEntry[] selectedFiles = browserView.getSelectedFiles();
  755. Buffer buffer = null;
  756. check_selected: for(int i = 0; i < selectedFiles.length; i++)
  757. {
  758. VFS.DirectoryEntry file = selectedFiles[i];
  759. if(file.type == VFS.DirectoryEntry.DIRECTORY
  760. || file.type == VFS.DirectoryEntry.FILESYSTEM)
  761. {
  762. if(mode == M_OPEN_NEW_VIEW && this.mode == BROWSER)
  763. browseDirectoryInNewWindow(view,file.path);
  764. else
  765. setDirectory(file.path);
  766. }
  767. else if(this.mode == BROWSER || this.mode == BROWSER_DIALOG)
  768. {
  769. Buffer _buffer = jEdit.getBuffer(file.path);
  770. if(_buffer == null)
  771. {
  772. Hashtable props = new Hashtable();
  773. props.put(Buffer.ENCODING,currentEncoding);
  774. _buffer = jEdit.openFile(null,null,file.path,
  775. false,props);
  776. }
  777. else if(doubleClickClose && canDoubleClickClose
  778. && this.mode != BROWSER_DIALOG
  779. && selectedFiles.length == 1)
  780. {
  781. // close if this buffer is currently
  782. // visible in the view.
  783. EditPane[] editPanes = view.getEditPanes();
  784. for(int j = 0; j < editPanes.length; j++)
  785. {
  786. if(editPanes[j].getBuffer() == _buffer)
  787. {
  788. jEdit.closeBuffer(view,_buffer);
  789. return;
  790. }
  791. }
  792. }
  793. if(_buffer != null)
  794. buffer = _buffer;
  795. }
  796. else
  797. {
  798. // if a file is selected in OPEN_DIALOG or
  799. // SAVE_DIALOG mode, just let the listener(s)
  800. // handle it
  801. }
  802. }
  803. if(buffer != null)
  804. {
  805. switch(mode)
  806. {
  807. case M_OPEN:
  808. view.setBuffer(buffer);
  809. break;
  810. case M_OPEN_NEW_VIEW:
  811. jEdit.newView(view,buffer,false);
  812. break;
  813. case M_OPEN_NEW_PLAIN_VIEW:
  814. jEdit.newView(view,buffer,true);
  815. break;
  816. case M_OPEN_NEW_SPLIT:
  817. view.splitHorizontally().setBuffer(buffer);
  818. break;
  819. }
  820. }
  821. Object[] listeners = listenerList.getListenerList();
  822. for(int i = 0; i < listeners.length; i++)
  823. {
  824. if(listeners[i] == BrowserListener.class)
  825. {
  826. BrowserListener l = (BrowserListener)listeners[i+1];
  827. l.filesActivated(this,selectedFiles);
  828. }
  829. }
  830. } //}}}
  831. //{{{ endRequest() method
  832. void endRequest()
  833. {
  834. requestRunning = false;
  835. } //}}}
  836. //}}}
  837. //{{{ Private members
  838. private static ActionContext actionContext;
  839. static
  840. {
  841. actionContext = new ActionContext()
  842. {
  843. public void invokeAction(EventObject evt,
  844. EditAction action)
  845. {
  846. VFSBrowser browser = (VFSBrowser)
  847. GUIUtilities.getComponentParent(
  848. (Component)evt.getSource(),
  849. VFSBrowser.class);
  850. // in the future we will want something better,
  851. // eg. having an 'evt' object passed to
  852. // EditAction.invoke().
  853. // for now, since all browser actions are
  854. // written in beanshell we set the 'browser'
  855. // variable directly.
  856. NameSpace global = BeanShell.getNameSpace();
  857. try
  858. {
  859. global.setVariable("browser",
  860. browser);
  861. global.setVariable("files",
  862. browser.getSelectedFiles());
  863. action.invoke(browser.getView());
  864. }
  865. catch(EvalError err)
  866. {
  867. Log.log(Log.ERROR,this,err);
  868. }
  869. finally
  870. {
  871. try
  872. {
  873. global.setVariable("browser",null);
  874. global.setVariable("files",null);
  875. }
  876. catch(EvalError err)
  877. {
  878. Log.log(Log.ERROR,this,err);
  879. }
  880. }
  881. }
  882. };
  883. ActionSet builtInActionSet = new ActionSet(null,null,
  884. jEdit.class.getResource("browser.actions.xml"));
  885. builtInActionSet.load();
  886. actionContext.addActionSet(builtInActionSet);
  887. }
  888. //{{{ Instance variables
  889. private EventListenerList listenerList;
  890. private View view;
  891. private boolean floating;
  892. private boolean horizontalLayout;
  893. private String path;
  894. private HistoryTextField pathField;
  895. private JCheckBox filterCheckbox;
  896. private HistoryTextField filterField;
  897. private Box toolbarBox;
  898. private JToolBar toolbar;
  899. private BrowserView browserView;
  900. private RE filenameFilter;
  901. private int mode;
  902. private boolean multipleSelection;
  903. private boolean showHiddenFiles;
  904. private boolean sortMixFilesAndDirs;
  905. private boolean sortIgnoreCase;
  906. private boolean doubleClickClose;
  907. private boolean requestRunning;
  908. //}}}
  909. //{{{ createMenuBar() method
  910. private JPanel createMenuBar()
  911. {
  912. JPanel menuBar = new JPanel();
  913. menuBar.setLayout(new BoxLayout(menuBar,BoxLayout.X_AXIS));
  914. menuBar.setBorder(new EmptyBorder(0,3,1,0));
  915. menuBar.add(new CommandsMenuButton());
  916. menuBar.add(Box.createHorizontalStrut(3));
  917. menuBar.add(new PluginsMenuButton());
  918. menuBar.add(Box.createHorizontalStrut(3));
  919. menuBar.add(new FavoritesMenuButton());
  920. return menuBar;
  921. } //}}}
  922. //{{{ createToolBar() method
  923. private JToolBar createToolBar()
  924. {
  925. if(mode == BROWSER)
  926. return GUIUtilities.loadToolBar(actionContext,
  927. "vfs.browser.toolbar-browser");
  928. else
  929. return GUIUtilities.loadToolBar(actionContext,
  930. "vfs.browser.toolbar-dialog");
  931. } //}}}
  932. //{{{ propertiesChanged() method
  933. private void propertiesChanged()
  934. {
  935. showHiddenFiles = jEdit.getBooleanProperty("vfs.browser.showHiddenFiles");
  936. sortMixFilesAndDirs = jEdit.getBooleanProperty("vfs.browser.sortMixFilesAndDirs");
  937. sortIgnoreCase = jEdit.getBooleanProperty("vfs.browser.sortIgnoreCase");
  938. doubleClickClose = jEdit.getBooleanProperty("vfs.browser.doubleClickClose");
  939. browserView.propertiesChanged();
  940. toolbarBox.removeAll();
  941. if(jEdit.getBooleanProperty("vfs.browser.showToolbar"))
  942. {
  943. JToolBar toolbar = createToolBar();
  944. if(horizontalLayout)
  945. toolbarBox.add(toolbar);
  946. else
  947. {
  948. toolbar.add(Box.createGlue());
  949. toolbarBox.add(toolbar);
  950. }
  951. }
  952. if(jEdit.getBooleanProperty("vfs.browser.showMenubar"))
  953. {
  954. JPanel menubar = createMenuBar();
  955. if(horizontalLayout)
  956. {
  957. toolbarBox.add(Box.createHorizontalStrut(6));
  958. toolbarBox.add(menubar,0);
  959. }
  960. else
  961. {
  962. menubar.add(Box.createGlue());
  963. toolbarBox.add(menubar);
  964. }
  965. }
  966. toolbarBox.add(Box.createGlue());
  967. revalidate();
  968. if(path != null)
  969. reloadDirectory();
  970. } //}}}
  971. /* We do this stuff because the browser is not able to handle
  972. * more than one request yet */
  973. //{{{ startRequest() method
  974. private boolean startRequest()
  975. {
  976. if(requestRunning)
  977. {
  978. // dump stack trace for debugging purposes
  979. Log.log(Log.DEBUG,this,new Throwable("For debugging purposes"));
  980. GUIUtilities.error(this,"browser-multiple-io",null);
  981. return false;
  982. }
  983. else
  984. {
  985. requestRunning = true;
  986. return true;
  987. }
  988. } //}}}
  989. //{{{ updateFilterEnabled() method
  990. private void updateFilterEnabled()
  991. {
  992. filterField.setEnabled(filterCheckbox.isSelected());
  993. } //}}}
  994. //{{{ maybeReloadDirectory() method
  995. private void maybeReloadDirectory(String dir)
  996. {
  997. // this is a dirty hack and it relies on the fact
  998. // that updates for parents are sent before updates
  999. // for the changed nodes themselves (if this was not
  1000. // the case, the browser wouldn't be updated properly
  1001. // on delete, etc).
  1002. //
  1003. // to avoid causing '> 1 request' errors, don't reload
  1004. // directory if request already active
  1005. if(requestRunning)
  1006. return;
  1007. // save a file -> sends vfs update. if a VFS file dialog box
  1008. // is shown from the same event frame as the save, the
  1009. // VFSUpdate will be delivered before the directory is loaded,
  1010. // and before the path is set.
  1011. if(path != null)
  1012. {
  1013. try
  1014. {
  1015. requestRunning = true;
  1016. browserView.maybeReloadDirectory(dir);
  1017. }
  1018. finally
  1019. {
  1020. VFSManager.runInAWTThread(new Runnable()
  1021. {
  1022. public void run()
  1023. {
  1024. requestRunning = false;
  1025. }
  1026. });
  1027. }
  1028. }
  1029. } //}}}
  1030. //}}}
  1031. //{{{ Inner classes
  1032. //{{{ ActionHandler class
  1033. class ActionHandler implements ActionListener
  1034. {
  1035. public void actionPerformed(ActionEvent evt)
  1036. {
  1037. Object source = evt.getSource();
  1038. if(source == pathField || source == filterField
  1039. || source == filterCheckbox)
  1040. {
  1041. updateFilterEnabled();
  1042. String path = pathField.getText();
  1043. if(path != null)
  1044. setDirectory(path);
  1045. browserView.focusOnFileView();
  1046. }
  1047. }
  1048. } //}}}
  1049. //{{{ CommandsMenuButton class
  1050. class CommandsMenuButton extends JButton
  1051. {
  1052. //{{{ CommandsMenuButton constructor
  1053. CommandsMenuButton()
  1054. {
  1055. setText(jEdit.getProperty("vfs.browser.commands.label"));
  1056. setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
  1057. setHorizontalTextPosition(SwingConstants.LEADING);
  1058. popup = new BrowserCommandsMenu(VFSBrowser.this,null);
  1059. CommandsMenuButton.this.setRequestFocusEnabled(false);
  1060. setMargin(new Insets(1,1,1,1));
  1061. CommandsMenuButton.this.addMouseListener(new MouseHandler());
  1062. if(OperatingSystem.isMacOSLF())
  1063. CommandsMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
  1064. } //}}}
  1065. BrowserCommandsMenu popup;
  1066. //{{{ MouseHandler class
  1067. class MouseHandler extends MouseAdapter
  1068. {
  1069. public void mousePressed(MouseEvent evt)
  1070. {
  1071. if(!popup.isVisible())
  1072. {
  1073. popup.update();
  1074. GUIUtilities.showPopupMenu(
  1075. popup,CommandsMenuButton.this,0,
  1076. CommandsMenuButton.this.getHeight(),
  1077. false);
  1078. }
  1079. else
  1080. {
  1081. popup.setVisible(false);
  1082. }
  1083. }
  1084. } //}}}
  1085. } //}}}
  1086. //{{{ PluginsMenuButton class
  1087. class PluginsMenuButton extends JButton
  1088. {
  1089. //{{{ PluginsMenuButton constructor
  1090. PluginsMenuButton()
  1091. {
  1092. setText(jEdit.getProperty("vfs.browser.plugins.label"));
  1093. setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
  1094. setHorizontalTextPosition(SwingConstants.LEADING);
  1095. PluginsMenuButton.this.setRequestFocusEnabled(false);
  1096. setMargin(new Insets(1,1,1,1));
  1097. PluginsMenuButton.this.addMouseListener(new MouseHandler());
  1098. if(OperatingSystem.isMacOSLF())
  1099. PluginsMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
  1100. } //}}}
  1101. JPopupMenu popup;
  1102. //{{{ createPopupMenu() method
  1103. private void createPopupMenu()
  1104. {
  1105. if(popup != null)
  1106. return;
  1107. popup = new JPopupMenu();
  1108. ActionHandler actionHandler = new ActionHandler();
  1109. popup.add(GUIUtilities.loadMenuItem("plugin-manager",false));
  1110. popup.add(GUIUtilities.loadMenuItem("plugin-options",false));
  1111. popup.addSeparator();
  1112. ArrayList vec = new ArrayList();
  1113. //{{{ old API
  1114. Enumeration enum = VFSManager.getFilesystems();
  1115. while(enum.hasMoreElements())
  1116. {
  1117. VFS vfs = (VFS)enum.nextElement();
  1118. if((vfs.getCapabilities() & VFS.BROWSE_CAP) == 0)
  1119. continue;
  1120. JMenuItem menuItem = new JMenuItem(jEdit.getProperty(
  1121. "vfs." + vfs.getName() + ".label"));
  1122. menuItem.setActionCommand(vfs.getName());
  1123. menuItem.addActionListener(actionHandler);
  1124. vec.add(menuItem);
  1125. } //}}}
  1126. //{{{ new API
  1127. EditPlugin[] plugins = jEdit.getPlugins();
  1128. for(int i = 0; i < plugins.length; i++)
  1129. {
  1130. JMenuItem menuItem = plugins[i].createBrowserMenuItems();
  1131. if(menuItem != null)
  1132. vec.add(menuItem);
  1133. } //}}}
  1134. if(vec.size() != 0)
  1135. {
  1136. MiscUtilities.quicksort(vec,new MiscUtilities.MenuItemCompare());
  1137. for(int i = 0; i < vec.size(); i++)
  1138. popup.add((JMenuItem)vec.get(i));
  1139. }
  1140. else
  1141. {
  1142. JMenuItem mi = new JMenuItem(jEdit.getProperty(
  1143. "vfs.browser.plugins.no-plugins.label"));
  1144. mi.setEnabled(false);
  1145. popup.add(mi);
  1146. }
  1147. } //}}}
  1148. //{{{ ActionHandler class
  1149. class ActionHandler implements ActionListener
  1150. {
  1151. public void actionPerformed(ActionEvent evt)
  1152. {
  1153. VFS vfs = VFSManager.getVFSByName(evt.getActionCommand());
  1154. String directory = vfs.showBrowseDialog(null,
  1155. VFSBrowser.this);
  1156. if(directory != null)
  1157. setDirectory(directory);
  1158. }
  1159. } //}}}
  1160. //{{{ MouseHandler class
  1161. class MouseHandler extends MouseAdapter
  1162. {
  1163. public void mousePressed(MouseEvent evt)
  1164. {
  1165. createPopupMenu();
  1166. if(!popup.isVisible())
  1167. {
  1168. GUIUtilities.showPopupMenu(
  1169. popup,PluginsMenuButton.this,0,
  1170. PluginsMenuButton.this.getHeight(),
  1171. false);
  1172. }
  1173. else
  1174. {
  1175. popup.setVisible(false);
  1176. }
  1177. }
  1178. } //}}}
  1179. } //}}}
  1180. //{{{ FavoritesMenuButton class
  1181. class FavoritesMenuButton extends JButton
  1182. {
  1183. //{{{ FavoritesMenuButton constructor
  1184. FavoritesMenuButton()
  1185. {
  1186. setText(jEdit.getProperty("vfs.browser.favorites.label"));
  1187. setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
  1188. setHorizontalTextPosition(SwingConstants.LEADING);
  1189. FavoritesMenuButton.this.setRequestFocusEnabled(false);
  1190. setMargin(new Insets(1,1,1,1));
  1191. FavoritesMenuButton.this.addMouseListener(new MouseHandler());
  1192. if(OperatingSystem.isMacOSLF())
  1193. FavoritesMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
  1194. } //}}}
  1195. JPopupMenu popup;
  1196. //{{{ ActionHandler class
  1197. class ActionHandler implements ActionListener
  1198. {
  1199. public void actionPerformed(ActionEvent evt)
  1200. {
  1201. String actionCommand = evt.getActionCommand();
  1202. if(actionCommand.equals("add-to-favorites"))
  1203. {
  1204. // if any directories are selected, add
  1205. // them, otherwise add current directory
  1206. ArrayList toAdd = new ArrayList();
  1207. VFS.DirectoryEntry[] selected = getSelectedFiles();
  1208. for(int i = 0; i < selected.length; i++)
  1209. {
  1210. VFS.DirectoryEntry file = selected[i];
  1211. if(file.type == VFS.DirectoryEntry.FILE)
  1212. {
  1213. toAdd.add(MiscUtilities
  1214. .getParentOfPath(file.path));
  1215. }
  1216. else
  1217. toAdd.add(file.path);
  1218. }
  1219. if(toAdd.size() != 0)
  1220. {
  1221. for(int i = 0; i < toAdd.size(); i++)
  1222. {
  1223. FavoritesVFS.addToFavorites((String)toAdd.get(i));
  1224. }
  1225. }
  1226. else
  1227. {
  1228. if(path.equals(FavoritesVFS.PROTOCOL + ":"))
  1229. {
  1230. GUIUtilities.error(VFSBrowser.this,
  1231. "vfs.browser.recurse-favorites",
  1232. null);
  1233. }
  1234. else
  1235. {
  1236. FavoritesVFS.addToFavorites(path);
  1237. }
  1238. }
  1239. }
  1240. else
  1241. setDirectory(actionCommand);
  1242. }
  1243. } //}}}
  1244. //{{{ MouseHandler class
  1245. class MouseHandler extends MouseAdapter
  1246. {
  1247. public void mousePressed(MouseEvent evt)
  1248. {
  1249. if(popup == null || !popup.isVisible())
  1250. {
  1251. popup = new JPopupMenu();
  1252. ActionHandler actionHandler = new ActionHandler();
  1253. JMenuItem mi = new JMenuItem(
  1254. jEdit.getProperty(
  1255. "vfs.browser.favorites"
  1256. + ".add-to-favorites.label"));
  1257. mi.setActionCommand("add-to-favorites");
  1258. mi.addActionListener(actionHandler);
  1259. popup.add(mi);
  1260. mi = new JMenuItem(
  1261. jEdit.getProperty(
  1262. "vfs.browser.favorites"
  1263. + ".edit-favorites.label"));
  1264. mi.setActionCommand("favorites:");
  1265. mi.addActionListener(actionHandler);
  1266. popup.add(mi);
  1267. popup.addSeparator();
  1268. Object[] favorites = FavoritesVFS.getFavorites();
  1269. if(favorites.length == 0)
  1270. {
  1271. mi = new JMenuItem(
  1272. jEdit.getProperty(
  1273. "vfs.browser.favorites"
  1274. + ".no-favorites.label"));
  1275. mi.setEnabled(false);
  1276. popup.add(mi);
  1277. }
  1278. else
  1279. {
  1280. MiscUtilities.quicksort(favorites,
  1281. new MiscUtilities.StringICaseCompare());
  1282. for(int i = 0; i < favorites.length; i++)
  1283. {
  1284. mi = new JMenuItem(favorites[i].toString());
  1285. mi.setIcon(FileCellRenderer.dirIcon);
  1286. mi.addActionListener(actionHandler);
  1287. popup.add(mi);
  1288. }
  1289. }
  1290. GUIUtilities.showPopupMenu(
  1291. popup,FavoritesMenuButton.this,0,
  1292. FavoritesMenuButton.this.getHeight(),
  1293. false);
  1294. }
  1295. else
  1296. {
  1297. popup.setVisible(false);
  1298. popup = null;
  1299. }
  1300. }
  1301. } //}}}
  1302. } //}}}
  1303. //}}}
  1304. }