PageRenderTime 59ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/browser/BrowserView.java

#
Java | 561 lines | 407 code | 72 blank | 82 comment | 78 complexity | 7237060cf1a47a88b3ba702078839ec7 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * BrowserView.java
  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 javax.swing.border.EmptyBorder;
  25. import javax.swing.event.*;
  26. import javax.swing.*;
  27. import java.awt.event.*;
  28. import java.awt.*;
  29. import java.io.File;
  30. import java.util.*;
  31. import org.gjt.sp.jedit.io.*;
  32. import org.gjt.sp.jedit.*;
  33. //}}}
  34. /**
  35. * VFS browser tree view.
  36. * @author Slava Pestov
  37. * @version $Id: BrowserView.java 5053 2004-05-29 01:55:26Z spestov $
  38. */
  39. class BrowserView extends JPanel
  40. {
  41. //{{{ BrowserView constructor
  42. public BrowserView(final VFSBrowser browser)
  43. {
  44. this.browser = browser;
  45. tmpExpanded = new HashSet();
  46. parentDirectories = new JList();
  47. parentDirectories.getSelectionModel().setSelectionMode(
  48. ListSelectionModel.SINGLE_SELECTION);
  49. parentDirectories.setCellRenderer(new ParentDirectoryRenderer());
  50. parentDirectories.setVisibleRowCount(5);
  51. parentDirectories.addMouseListener(new ParentMouseHandler());
  52. final JScrollPane parentScroller = new JScrollPane(parentDirectories);
  53. parentScroller.setMinimumSize(new Dimension(0,0));
  54. table = new VFSDirectoryEntryTable(this);
  55. table.addMouseListener(new TableMouseHandler());
  56. JScrollPane tableScroller = new JScrollPane(table);
  57. tableScroller.setMinimumSize(new Dimension(0,0));
  58. tableScroller.getViewport().setBackground(table.getBackground());
  59. tableScroller.getViewport().addMouseListener(new TableMouseHandler());
  60. splitPane = new JSplitPane(
  61. browser.isHorizontalLayout()
  62. ? JSplitPane.HORIZONTAL_SPLIT : JSplitPane.VERTICAL_SPLIT,
  63. parentScroller,tableScroller);
  64. splitPane.setOneTouchExpandable(true);
  65. SwingUtilities.invokeLater(new Runnable()
  66. {
  67. public void run()
  68. {
  69. String prop = browser.isHorizontalLayout() ? "vfs.browser.horizontalSplitter" : "vfs.browser.splitter";
  70. int loc = jEdit.getIntegerProperty(prop,-1);
  71. if(loc == -1)
  72. loc = parentScroller.getPreferredSize().height;
  73. splitPane.setDividerLocation(loc);
  74. parentDirectories.ensureIndexIsVisible(
  75. parentDirectories.getModel()
  76. .getSize());
  77. }
  78. });
  79. if(browser.isMultipleSelectionEnabled())
  80. table.getSelectionModel().setSelectionMode(
  81. ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
  82. else
  83. table.getSelectionModel().setSelectionMode(
  84. ListSelectionModel.SINGLE_SELECTION);
  85. setLayout(new BorderLayout());
  86. add(BorderLayout.CENTER,splitPane);
  87. propertiesChanged();
  88. } //}}}
  89. //{{{ focusOnFileView() method
  90. public void focusOnFileView()
  91. {
  92. table.requestFocus();
  93. } //}}}
  94. //{{{ removeNotify() method
  95. public void removeNotify()
  96. {
  97. String prop = browser.isHorizontalLayout() ? "vfs.browser.horizontalSplitter" : "vfs.browser.splitter";
  98. jEdit.setIntegerProperty(prop,splitPane.getDividerLocation());
  99. super.removeNotify();
  100. } //}}}
  101. //{{{ getSelectedFiles() method
  102. public VFS.DirectoryEntry[] getSelectedFiles()
  103. {
  104. return table.getSelectedFiles();
  105. } //}}}
  106. //{{{ selectNone() method
  107. public void selectNone()
  108. {
  109. table.clearSelection();
  110. } //}}}
  111. //{{{ saveExpansionState() method
  112. public void saveExpansionState()
  113. {
  114. tmpExpanded.clear();
  115. table.getExpandedDirectories(tmpExpanded);
  116. } //}}}
  117. //{{{ clearExpansionState() method
  118. public void clearExpansionState()
  119. {
  120. tmpExpanded.clear();
  121. } //}}}
  122. //{{{ loadDirectory() method
  123. public void loadDirectory(Object node, String path)
  124. {
  125. path = MiscUtilities.constructPath(browser.getDirectory(),path);
  126. VFS vfs = VFSManager.getVFSForPath(path);
  127. Object session = vfs.createVFSSession(path,this);
  128. if(session == null)
  129. return;
  130. if(node == null)
  131. {
  132. parentDirectories.setListData(new Object[] {
  133. new LoadingPlaceholder() });
  134. }
  135. Object[] loadInfo = new Object[2];
  136. VFSManager.runInWorkThread(new BrowserIORequest(
  137. BrowserIORequest.LIST_DIRECTORY,browser,
  138. session,vfs,path,null,loadInfo));
  139. browser.directoryLoaded(node,loadInfo);
  140. } //}}}
  141. //{{{ directoryLoaded() method
  142. public void directoryLoaded(Object node, String path, ArrayList directory)
  143. {
  144. //{{{ If reloading root, update parent directory list
  145. if(node == null)
  146. {
  147. DefaultListModel parentList = new DefaultListModel();
  148. String parent = path;
  149. for(;;)
  150. {
  151. VFS _vfs = VFSManager.getVFSForPath(
  152. parent);
  153. // create a DirectoryEntry manually
  154. // instead of using _vfs._getDirectoryEntry()
  155. // since so many VFS's have broken
  156. // implementations of this method
  157. parentList.insertElementAt(new VFS.DirectoryEntry(
  158. _vfs.getFileName(parent),
  159. parent,parent,
  160. VFS.DirectoryEntry.DIRECTORY,
  161. 0L,false),0);
  162. String newParent = _vfs.getParentOfPath(parent);
  163. if(newParent == null ||
  164. VFSBrowser.pathsEqual(parent,newParent))
  165. break;
  166. else
  167. parent = newParent;
  168. }
  169. parentDirectories.setModel(parentList);
  170. int index = parentList.getSize() - 1;
  171. parentDirectories.setSelectedIndex(index);
  172. parentDirectories.ensureIndexIsVisible(index);
  173. } //}}}
  174. table.setDirectory(VFSManager.getVFSForPath(path),
  175. node,directory,tmpExpanded);
  176. } //}}}
  177. //{{{ updateFileView() method
  178. public void updateFileView()
  179. {
  180. table.repaint();
  181. } //}}}
  182. //{{{ maybeReloadDirectory() method
  183. public void maybeReloadDirectory(String path)
  184. {
  185. String browserDir = browser.getDirectory();
  186. String symlinkBrowserDir;
  187. if(MiscUtilities.isURL(browserDir))
  188. {
  189. symlinkBrowserDir = browserDir;
  190. }
  191. else
  192. {
  193. symlinkBrowserDir = MiscUtilities.resolveSymlinks(
  194. browserDir);
  195. }
  196. if(VFSBrowser.pathsEqual(path,symlinkBrowserDir))
  197. {
  198. saveExpansionState();
  199. loadDirectory(null,browserDir);
  200. }
  201. // because this method is called for *every* VFS update,
  202. // we don't want to scan the tree all the time. So we
  203. // use the following algorithm to determine if the path
  204. // might be part of the tree:
  205. // - if the path starts with the browser's current directory,
  206. // we do the tree scan
  207. // - if the browser's directory is 'favorites:' -- we have to
  208. // do the tree scan, as every path can appear under the
  209. // favorites list
  210. // - if the browser's directory is 'roots:' and path is on
  211. // the local filesystem, do a tree scan
  212. if(!browserDir.startsWith(FavoritesVFS.PROTOCOL)
  213. && !browserDir.startsWith(FileRootsVFS.PROTOCOL)
  214. && !path.startsWith(symlinkBrowserDir))
  215. return;
  216. if(browserDir.startsWith(FileRootsVFS.PROTOCOL)
  217. && MiscUtilities.isURL(path)
  218. && !MiscUtilities.getProtocolOfURL(path)
  219. .equals("file"))
  220. return;
  221. table.maybeReloadDirectory(path);
  222. } //}}}
  223. //{{{ propertiesChanged() method
  224. public void propertiesChanged()
  225. {
  226. showIcons = jEdit.getBooleanProperty("vfs.browser.showIcons");
  227. table.propertiesChanged();
  228. splitPane.setBorder(null);
  229. } //}}}
  230. //{{{ getBrowser() method
  231. /**
  232. * Returns the associated <code>VFSBrowser</code> instance.
  233. * @since jEdit 4.2pre1
  234. */
  235. public VFSBrowser getBrowser()
  236. {
  237. return browser;
  238. } //}}}
  239. //{{{ getTable() method
  240. public VFSDirectoryEntryTable getTable()
  241. {
  242. return table;
  243. } //}}}
  244. //{{{ getParentDirectoryList() method
  245. public JList getParentDirectoryList()
  246. {
  247. return parentDirectories;
  248. } //}}}
  249. //{{{ Private members
  250. //{{{ Instance variables
  251. private VFSBrowser browser;
  252. private JSplitPane splitPane;
  253. private JList parentDirectories;
  254. private VFSDirectoryEntryTable table;
  255. private Set tmpExpanded;
  256. private BrowserCommandsMenu popup;
  257. private boolean showIcons;
  258. //}}}
  259. //{{{ showFilePopup() method
  260. private void showFilePopup(VFS.DirectoryEntry[] files, Component comp,
  261. Point point)
  262. {
  263. popup = new BrowserCommandsMenu(browser,files);
  264. // for the parent directory right-click; on the click we select
  265. // the clicked item, but when the popup goes away we select the
  266. // currently showing directory.
  267. popup.addPopupMenuListener(new PopupMenuListener()
  268. {
  269. public void popupMenuCanceled(PopupMenuEvent e) {}
  270. public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
  271. public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
  272. {
  273. // we use SwingUtilities.invokeLater()
  274. // so that the action is executed before
  275. // the popup is hidden.
  276. SwingUtilities.invokeLater(new Runnable()
  277. {
  278. public void run()
  279. {
  280. int index = parentDirectories
  281. .getModel()
  282. .getSize() - 1;
  283. parentDirectories.setSelectedIndex(index);
  284. }
  285. });
  286. }
  287. });
  288. GUIUtilities.showPopupMenu(popup,comp,point.x,point.y);
  289. } //}}}
  290. //}}}
  291. //{{{ Inner classes
  292. //{{{ ParentDirectoryRenderer class
  293. class ParentDirectoryRenderer extends DefaultListCellRenderer
  294. {
  295. Font plainFont, boldFont;
  296. ParentDirectoryRenderer()
  297. {
  298. plainFont = UIManager.getFont("Tree.font");
  299. if(plainFont == null)
  300. plainFont = jEdit.getFontProperty("metal.secondary.font");
  301. boldFont = new Font(plainFont.getName(),Font.BOLD,plainFont.getSize());
  302. }
  303. public Component getListCellRendererComponent(
  304. JList list,
  305. Object value,
  306. int index,
  307. boolean isSelected,
  308. boolean cellHasFocus)
  309. {
  310. super.getListCellRendererComponent(list,value,index,
  311. isSelected,cellHasFocus);
  312. ParentDirectoryRenderer.this.setBorder(new EmptyBorder(
  313. 1,index * 5 + 1,1,1));
  314. if(value instanceof LoadingPlaceholder)
  315. {
  316. ParentDirectoryRenderer.this.setFont(plainFont);
  317. setIcon(showIcons ? FileCellRenderer.loadingIcon : null);
  318. setText(jEdit.getProperty("vfs.browser.tree.loading"));
  319. }
  320. else if(value instanceof VFS.DirectoryEntry)
  321. {
  322. VFS.DirectoryEntry dirEntry = (VFS.DirectoryEntry)value;
  323. ParentDirectoryRenderer.this.setFont(boldFont);
  324. setIcon(showIcons ? FileCellRenderer.getIconForFile(dirEntry,true)
  325. : null);
  326. setText(dirEntry.name);
  327. }
  328. else if(value == null)
  329. setText("VFS does not follow VFS API");
  330. return this;
  331. }
  332. } //}}}
  333. //{{{ ParentMouseHandler class
  334. class ParentMouseHandler extends MouseAdapter
  335. {
  336. public void mousePressed(MouseEvent evt)
  337. {
  338. int row = parentDirectories.locationToIndex(evt.getPoint());
  339. if(row != -1)
  340. {
  341. Object obj = parentDirectories.getModel()
  342. .getElementAt(row);
  343. if(obj instanceof VFS.DirectoryEntry)
  344. {
  345. VFS.DirectoryEntry dirEntry = ((VFS.DirectoryEntry)obj);
  346. if(GUIUtilities.isPopupTrigger(evt))
  347. {
  348. if(popup != null && popup.isVisible())
  349. {
  350. popup.setVisible(false);
  351. popup = null;
  352. }
  353. else
  354. {
  355. parentDirectories.setSelectedIndex(row);
  356. showFilePopup(new VFS.DirectoryEntry[] {
  357. dirEntry },parentDirectories,
  358. evt.getPoint());
  359. }
  360. }
  361. }
  362. }
  363. }
  364. public void mouseReleased(MouseEvent evt)
  365. {
  366. if(evt.getClickCount() % 2 != 0 &&
  367. !GUIUtilities.isMiddleButton(evt.getModifiers()))
  368. return;
  369. int row = parentDirectories.locationToIndex(evt.getPoint());
  370. if(row != -1)
  371. {
  372. Object obj = parentDirectories.getModel()
  373. .getElementAt(row);
  374. if(obj instanceof VFS.DirectoryEntry)
  375. {
  376. VFS.DirectoryEntry dirEntry = ((VFS.DirectoryEntry)obj);
  377. if(!GUIUtilities.isPopupTrigger(evt))
  378. {
  379. browser.setDirectory(dirEntry.path);
  380. if(browser.getMode() == VFSBrowser.BROWSER)
  381. focusOnFileView();
  382. }
  383. }
  384. }
  385. }
  386. } //}}}
  387. //{{{ TableMouseHandler class
  388. class TableMouseHandler extends MouseAdapter
  389. {
  390. //{{{ mouseClicked() method
  391. public void mouseClicked(MouseEvent evt)
  392. {
  393. Point p = evt.getPoint();
  394. int row = table.rowAtPoint(p);
  395. int column = table.columnAtPoint(p);
  396. if(row == -1)
  397. return;
  398. if(column == 0)
  399. {
  400. VFSDirectoryEntryTableModel.Entry entry
  401. = (VFSDirectoryEntryTableModel.Entry)
  402. table.getModel().getValueAt(row,0);
  403. if(FileCellRenderer.ExpansionToggleBorder
  404. .isExpansionToggle(entry.level,p.x))
  405. {
  406. return;
  407. }
  408. }
  409. if((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0
  410. && evt.getClickCount() % 2 == 0)
  411. {
  412. browser.filesActivated((evt.isShiftDown()
  413. ? VFSBrowser.M_OPEN_NEW_VIEW
  414. : VFSBrowser.M_OPEN),true);
  415. }
  416. else if(GUIUtilities.isMiddleButton(evt.getModifiers()))
  417. {
  418. if(evt.isShiftDown())
  419. table.getSelectionModel().addSelectionInterval(row,row);
  420. else
  421. table.getSelectionModel().setSelectionInterval(row,row);
  422. browser.filesActivated((evt.isShiftDown()
  423. ? VFSBrowser.M_OPEN_NEW_VIEW
  424. : VFSBrowser.M_OPEN),true);
  425. }
  426. } //}}}
  427. //{{{ mousePressed() method
  428. public void mousePressed(MouseEvent evt)
  429. {
  430. Point p = evt.getPoint();
  431. if(evt.getSource() != table)
  432. {
  433. p.x -= table.getX();
  434. p.y -= table.getY();
  435. }
  436. int row = table.rowAtPoint(p);
  437. int column = table.columnAtPoint(p);
  438. if(column == 0 && row != -1)
  439. {
  440. VFSDirectoryEntryTableModel.Entry entry
  441. = (VFSDirectoryEntryTableModel.Entry)
  442. table.getModel().getValueAt(row,0);
  443. if(FileCellRenderer.ExpansionToggleBorder
  444. .isExpansionToggle(entry.level,p.x))
  445. {
  446. table.toggleExpanded(row);
  447. return;
  448. }
  449. }
  450. if(GUIUtilities.isMiddleButton(evt.getModifiers()))
  451. {
  452. if(row == -1)
  453. /* nothing */;
  454. else if(evt.isShiftDown())
  455. table.getSelectionModel().addSelectionInterval(row,row);
  456. else
  457. table.getSelectionModel().setSelectionInterval(row,row);
  458. }
  459. else if(GUIUtilities.isPopupTrigger(evt))
  460. {
  461. if(popup != null && popup.isVisible())
  462. {
  463. popup.setVisible(false);
  464. popup = null;
  465. return;
  466. }
  467. if(row == -1)
  468. showFilePopup(null,table,evt.getPoint());
  469. else
  470. {
  471. if(!table.getSelectionModel().isSelectedIndex(row))
  472. table.getSelectionModel().setSelectionInterval(row,row);
  473. showFilePopup(getSelectedFiles(),table,evt.getPoint());
  474. }
  475. }
  476. } //}}}
  477. //{{{ mouseReleased() method
  478. public void mouseReleased(MouseEvent evt)
  479. {
  480. if(!GUIUtilities.isPopupTrigger(evt)
  481. && table.getSelectedRow() != -1)
  482. {
  483. browser.filesSelected();
  484. }
  485. } //}}}
  486. } //}}}
  487. static class LoadingPlaceholder {}
  488. //}}}
  489. }