PageRenderTime 31ms CodeModel.GetById 10ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

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

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