PageRenderTime 50ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-3-pre5/org/gjt/sp/jedit/browser/BrowserView.java

#
Java | 562 lines | 408 code | 72 blank | 82 comment | 78 complexity | e656ffa6c6171e24a58af520ca1e5418 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 5197 2005-03-09 23:46:09Z 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 VFSFile[] 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. boolean addToHistory)
  125. {
  126. path = MiscUtilities.constructPath(browser.getDirectory(),path);
  127. VFS vfs = VFSManager.getVFSForPath(path);
  128. Object session = vfs.createVFSSession(path,this);
  129. if(session == null)
  130. return;
  131. if(node == null)
  132. {
  133. parentDirectories.setListData(new Object[] {
  134. new LoadingPlaceholder() });
  135. }
  136. Object[] loadInfo = new Object[2];
  137. VFSManager.runInWorkThread(new BrowserIORequest(
  138. BrowserIORequest.LIST_DIRECTORY,browser,
  139. session,vfs,path,null,loadInfo));
  140. browser.directoryLoaded(node,loadInfo,addToHistory);
  141. } //}}}
  142. //{{{ directoryLoaded() method
  143. public void directoryLoaded(Object node, String path, ArrayList directory)
  144. {
  145. //{{{ If reloading root, update parent directory list
  146. if(node == null)
  147. {
  148. DefaultListModel parentList = new DefaultListModel();
  149. String parent = path;
  150. for(;;)
  151. {
  152. VFS _vfs = VFSManager.getVFSForPath(
  153. parent);
  154. // create a DirectoryEntry manually
  155. // instead of using _vfs._getFile()
  156. // since so many VFS's have broken
  157. // implementations of this method
  158. parentList.insertElementAt(new VFSFile(
  159. _vfs.getFileName(parent),
  160. parent,parent,
  161. VFSFile.DIRECTORY,
  162. 0L,false),0);
  163. String newParent = _vfs.getParentOfPath(parent);
  164. if(newParent == null ||
  165. MiscUtilities.pathsEqual(parent,newParent))
  166. break;
  167. else
  168. parent = newParent;
  169. }
  170. parentDirectories.setModel(parentList);
  171. int index = parentList.getSize() - 1;
  172. parentDirectories.setSelectedIndex(index);
  173. parentDirectories.ensureIndexIsVisible(index);
  174. } //}}}
  175. table.setDirectory(VFSManager.getVFSForPath(path),
  176. node,directory,tmpExpanded);
  177. } //}}}
  178. //{{{ updateFileView() method
  179. public void updateFileView()
  180. {
  181. table.repaint();
  182. } //}}}
  183. //{{{ maybeReloadDirectory() method
  184. public void maybeReloadDirectory(String path)
  185. {
  186. String browserDir = browser.getDirectory();
  187. String symlinkBrowserDir;
  188. if(MiscUtilities.isURL(browserDir))
  189. {
  190. symlinkBrowserDir = browserDir;
  191. }
  192. else
  193. {
  194. symlinkBrowserDir = MiscUtilities.resolveSymlinks(
  195. browserDir);
  196. }
  197. if(MiscUtilities.pathsEqual(path,symlinkBrowserDir))
  198. {
  199. saveExpansionState();
  200. loadDirectory(null,browserDir,false);
  201. }
  202. // because this method is called for *every* VFS update,
  203. // we don't want to scan the tree all the time. So we
  204. // use the following algorithm to determine if the path
  205. // might be part of the tree:
  206. // - if the path starts with the browser's current directory,
  207. // we do the tree scan
  208. // - if the browser's directory is 'favorites:' -- we have to
  209. // do the tree scan, as every path can appear under the
  210. // favorites list
  211. // - if the browser's directory is 'roots:' and path is on
  212. // the local filesystem, do a tree scan
  213. if(!browserDir.startsWith(FavoritesVFS.PROTOCOL)
  214. && !browserDir.startsWith(FileRootsVFS.PROTOCOL)
  215. && !path.startsWith(symlinkBrowserDir))
  216. return;
  217. if(browserDir.startsWith(FileRootsVFS.PROTOCOL)
  218. && MiscUtilities.isURL(path)
  219. && !MiscUtilities.getProtocolOfURL(path)
  220. .equals("file"))
  221. return;
  222. table.maybeReloadDirectory(path);
  223. } //}}}
  224. //{{{ propertiesChanged() method
  225. public void propertiesChanged()
  226. {
  227. showIcons = jEdit.getBooleanProperty("vfs.browser.showIcons");
  228. table.propertiesChanged();
  229. splitPane.setBorder(null);
  230. } //}}}
  231. //{{{ getBrowser() method
  232. /**
  233. * Returns the associated <code>VFSBrowser</code> instance.
  234. * @since jEdit 4.2pre1
  235. */
  236. public VFSBrowser getBrowser()
  237. {
  238. return browser;
  239. } //}}}
  240. //{{{ getTable() method
  241. public VFSDirectoryEntryTable getTable()
  242. {
  243. return table;
  244. } //}}}
  245. //{{{ getParentDirectoryList() method
  246. public JList getParentDirectoryList()
  247. {
  248. return parentDirectories;
  249. } //}}}
  250. //{{{ Private members
  251. //{{{ Instance variables
  252. private VFSBrowser browser;
  253. private JSplitPane splitPane;
  254. private JList parentDirectories;
  255. private VFSDirectoryEntryTable table;
  256. private Set tmpExpanded;
  257. private BrowserCommandsMenu popup;
  258. private boolean showIcons;
  259. //}}}
  260. //{{{ showFilePopup() method
  261. private void showFilePopup(VFSFile[] files, Component comp,
  262. Point point)
  263. {
  264. popup = new BrowserCommandsMenu(browser,files);
  265. // for the parent directory right-click; on the click we select
  266. // the clicked item, but when the popup goes away we select the
  267. // currently showing directory.
  268. popup.addPopupMenuListener(new PopupMenuListener()
  269. {
  270. public void popupMenuCanceled(PopupMenuEvent e) {}
  271. public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
  272. public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
  273. {
  274. // we use SwingUtilities.invokeLater()
  275. // so that the action is executed before
  276. // the popup is hidden.
  277. SwingUtilities.invokeLater(new Runnable()
  278. {
  279. public void run()
  280. {
  281. int index = parentDirectories
  282. .getModel()
  283. .getSize() - 1;
  284. parentDirectories.setSelectedIndex(index);
  285. }
  286. });
  287. }
  288. });
  289. GUIUtilities.showPopupMenu(popup,comp,point.x,point.y);
  290. } //}}}
  291. //}}}
  292. //{{{ Inner classes
  293. //{{{ ParentDirectoryRenderer class
  294. class ParentDirectoryRenderer extends DefaultListCellRenderer
  295. {
  296. Font plainFont, boldFont;
  297. ParentDirectoryRenderer()
  298. {
  299. plainFont = UIManager.getFont("Tree.font");
  300. if(plainFont == null)
  301. plainFont = jEdit.getFontProperty("metal.secondary.font");
  302. boldFont = new Font(plainFont.getName(),Font.BOLD,plainFont.getSize());
  303. }
  304. public Component getListCellRendererComponent(
  305. JList list,
  306. Object value,
  307. int index,
  308. boolean isSelected,
  309. boolean cellHasFocus)
  310. {
  311. super.getListCellRendererComponent(list,value,index,
  312. isSelected,cellHasFocus);
  313. ParentDirectoryRenderer.this.setBorder(new EmptyBorder(
  314. 1,index * 5 + 1,1,1));
  315. if(value instanceof LoadingPlaceholder)
  316. {
  317. ParentDirectoryRenderer.this.setFont(plainFont);
  318. setIcon(showIcons ? FileCellRenderer.loadingIcon : null);
  319. setText(jEdit.getProperty("vfs.browser.tree.loading"));
  320. }
  321. else if(value instanceof VFSFile)
  322. {
  323. VFSFile dirEntry = (VFSFile)value;
  324. ParentDirectoryRenderer.this.setFont(boldFont);
  325. setIcon(showIcons ? FileCellRenderer.getIconForFile(dirEntry,true)
  326. : null);
  327. setText(dirEntry.getName());
  328. }
  329. else if(value == null)
  330. setText("VFS does not follow VFS API");
  331. return this;
  332. }
  333. } //}}}
  334. //{{{ ParentMouseHandler class
  335. class ParentMouseHandler extends MouseAdapter
  336. {
  337. public void mousePressed(MouseEvent evt)
  338. {
  339. int row = parentDirectories.locationToIndex(evt.getPoint());
  340. if(row != -1)
  341. {
  342. Object obj = parentDirectories.getModel()
  343. .getElementAt(row);
  344. if(obj instanceof VFSFile)
  345. {
  346. VFSFile dirEntry = ((VFSFile)obj);
  347. if(GUIUtilities.isPopupTrigger(evt))
  348. {
  349. if(popup != null && popup.isVisible())
  350. {
  351. popup.setVisible(false);
  352. popup = null;
  353. }
  354. else
  355. {
  356. parentDirectories.setSelectedIndex(row);
  357. showFilePopup(new VFSFile[] {
  358. dirEntry },parentDirectories,
  359. evt.getPoint());
  360. }
  361. }
  362. }
  363. }
  364. }
  365. public void mouseReleased(MouseEvent evt)
  366. {
  367. if(evt.getClickCount() % 2 != 0 &&
  368. !GUIUtilities.isMiddleButton(evt.getModifiers()))
  369. return;
  370. int row = parentDirectories.locationToIndex(evt.getPoint());
  371. if(row != -1)
  372. {
  373. Object obj = parentDirectories.getModel()
  374. .getElementAt(row);
  375. if(obj instanceof VFSFile)
  376. {
  377. VFSFile dirEntry = ((VFSFile)obj);
  378. if(!GUIUtilities.isPopupTrigger(evt))
  379. {
  380. browser.setDirectory(dirEntry.getPath());
  381. if(browser.getMode() == VFSBrowser.BROWSER)
  382. focusOnFileView();
  383. }
  384. }
  385. }
  386. }
  387. } //}}}
  388. //{{{ TableMouseHandler class
  389. class TableMouseHandler extends MouseAdapter
  390. {
  391. //{{{ mouseClicked() method
  392. public void mouseClicked(MouseEvent evt)
  393. {
  394. Point p = evt.getPoint();
  395. int row = table.rowAtPoint(p);
  396. int column = table.columnAtPoint(p);
  397. if(row == -1)
  398. return;
  399. if(column == 0)
  400. {
  401. VFSDirectoryEntryTableModel.Entry entry
  402. = (VFSDirectoryEntryTableModel.Entry)
  403. table.getModel().getValueAt(row,0);
  404. if(FileCellRenderer.ExpansionToggleBorder
  405. .isExpansionToggle(entry.level,p.x))
  406. {
  407. return;
  408. }
  409. }
  410. if((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0
  411. && evt.getClickCount() % 2 == 0)
  412. {
  413. browser.filesActivated((evt.isShiftDown()
  414. ? VFSBrowser.M_OPEN_NEW_VIEW
  415. : VFSBrowser.M_OPEN),true);
  416. }
  417. else if(GUIUtilities.isMiddleButton(evt.getModifiers()))
  418. {
  419. if(evt.isShiftDown())
  420. table.getSelectionModel().addSelectionInterval(row,row);
  421. else
  422. table.getSelectionModel().setSelectionInterval(row,row);
  423. browser.filesActivated((evt.isShiftDown()
  424. ? VFSBrowser.M_OPEN_NEW_VIEW
  425. : VFSBrowser.M_OPEN),true);
  426. }
  427. } //}}}
  428. //{{{ mousePressed() method
  429. public void mousePressed(MouseEvent evt)
  430. {
  431. Point p = evt.getPoint();
  432. if(evt.getSource() != table)
  433. {
  434. p.x -= table.getX();
  435. p.y -= table.getY();
  436. }
  437. int row = table.rowAtPoint(p);
  438. int column = table.columnAtPoint(p);
  439. if(column == 0 && row != -1)
  440. {
  441. VFSDirectoryEntryTableModel.Entry entry
  442. = (VFSDirectoryEntryTableModel.Entry)
  443. table.getModel().getValueAt(row,0);
  444. if(FileCellRenderer.ExpansionToggleBorder
  445. .isExpansionToggle(entry.level,p.x))
  446. {
  447. table.toggleExpanded(row);
  448. return;
  449. }
  450. }
  451. if(GUIUtilities.isMiddleButton(evt.getModifiers()))
  452. {
  453. if(row == -1)
  454. /* nothing */;
  455. else if(evt.isShiftDown())
  456. table.getSelectionModel().addSelectionInterval(row,row);
  457. else
  458. table.getSelectionModel().setSelectionInterval(row,row);
  459. }
  460. else if(GUIUtilities.isPopupTrigger(evt))
  461. {
  462. if(popup != null && popup.isVisible())
  463. {
  464. popup.setVisible(false);
  465. popup = null;
  466. return;
  467. }
  468. if(row == -1)
  469. showFilePopup(null,table,evt.getPoint());
  470. else
  471. {
  472. if(!table.getSelectionModel().isSelectedIndex(row))
  473. table.getSelectionModel().setSelectionInterval(row,row);
  474. showFilePopup(getSelectedFiles(),table,evt.getPoint());
  475. }
  476. }
  477. } //}}}
  478. //{{{ mouseReleased() method
  479. public void mouseReleased(MouseEvent evt)
  480. {
  481. if(!GUIUtilities.isPopupTrigger(evt)
  482. && table.getSelectedRow() != -1)
  483. {
  484. browser.filesSelected();
  485. }
  486. } //}}}
  487. } //}}}
  488. static class LoadingPlaceholder {}
  489. //}}}
  490. }