PageRenderTime 812ms CodeModel.GetById 141ms app.highlight 36ms RepoModel.GetById 1ms 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
  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 5053 2004-05-29 01:55:26Z 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,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		String symlinkBrowserDir;
222		if(MiscUtilities.isURL(browserDir))
223		{
224			symlinkBrowserDir = browserDir;
225		}
226		else
227		{
228			symlinkBrowserDir = MiscUtilities.resolveSymlinks(
229				browserDir);
230		}
231
232		if(VFSBrowser.pathsEqual(path,symlinkBrowserDir))
233		{
234			saveExpansionState();
235			loadDirectory(null,browserDir);
236		}
237
238		// because this method is called for *every* VFS update,
239		// we don't want to scan the tree all the time. So we
240		// use the following algorithm to determine if the path
241		// might be part of the tree:
242		// - if the path starts with the browser's current directory,
243		//   we do the tree scan
244		// - if the browser's directory is 'favorites:' -- we have to
245		//   do the tree scan, as every path can appear under the
246		//   favorites list
247		// - if the browser's directory is 'roots:' and path is on
248		//   the local filesystem, do a tree scan
249
250		if(!browserDir.startsWith(FavoritesVFS.PROTOCOL)
251			&& !browserDir.startsWith(FileRootsVFS.PROTOCOL)
252			&& !path.startsWith(symlinkBrowserDir))
253			return;
254
255		if(browserDir.startsWith(FileRootsVFS.PROTOCOL)
256			&& MiscUtilities.isURL(path)
257			&& !MiscUtilities.getProtocolOfURL(path)
258			.equals("file"))
259			return;
260
261		table.maybeReloadDirectory(path);
262	} //}}}
263
264	//{{{ propertiesChanged() method
265	public void propertiesChanged()
266	{
267		showIcons = jEdit.getBooleanProperty("vfs.browser.showIcons");
268		table.propertiesChanged();
269
270		splitPane.setBorder(null);
271	} //}}}
272
273	//{{{ getBrowser() method
274	/**
275	 * Returns the associated <code>VFSBrowser</code> instance.
276	 * @since jEdit 4.2pre1
277	 */
278	public VFSBrowser getBrowser()
279	{
280		return browser;
281	} //}}}
282
283	//{{{ getTable() method
284	public VFSDirectoryEntryTable getTable()
285	{
286		return table;
287	} //}}}
288
289	//{{{ getParentDirectoryList() method
290	public JList getParentDirectoryList()
291	{
292		return parentDirectories;
293	} //}}}
294
295	//{{{ Private members
296
297	//{{{ Instance variables
298	private VFSBrowser browser;
299
300	private JSplitPane splitPane;
301	private JList parentDirectories;
302	private VFSDirectoryEntryTable table;
303	private Set tmpExpanded;
304	private BrowserCommandsMenu popup;
305	private boolean showIcons;
306	//}}}
307
308	//{{{ showFilePopup() method
309	private void showFilePopup(VFS.DirectoryEntry[] files, Component comp,
310		Point point)
311	{
312		popup = new BrowserCommandsMenu(browser,files);
313		// for the parent directory right-click; on the click we select
314		// the clicked item, but when the popup goes away we select the
315		// currently showing directory.
316		popup.addPopupMenuListener(new PopupMenuListener()
317		{
318			public void popupMenuCanceled(PopupMenuEvent e) {}
319
320			public void popupMenuWillBecomeVisible(PopupMenuEvent e) {}
321
322			public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
323			{
324				// we use SwingUtilities.invokeLater()
325				// so that the action is executed before
326				// the popup is hidden.
327				SwingUtilities.invokeLater(new Runnable()
328				{
329					public void run()
330					{
331						int index = parentDirectories
332							.getModel()
333							.getSize() - 1;
334						parentDirectories.setSelectedIndex(index);
335					}
336				});
337			}
338		});
339		GUIUtilities.showPopupMenu(popup,comp,point.x,point.y);
340	} //}}}
341
342	//}}}
343
344	//{{{ Inner classes
345
346	//{{{ ParentDirectoryRenderer class
347	class ParentDirectoryRenderer extends DefaultListCellRenderer
348	{
349		Font plainFont, boldFont;
350
351		ParentDirectoryRenderer()
352		{
353			plainFont = UIManager.getFont("Tree.font");
354			if(plainFont == null)
355				plainFont = jEdit.getFontProperty("metal.secondary.font");
356			boldFont = new Font(plainFont.getName(),Font.BOLD,plainFont.getSize());
357		}
358
359		public Component getListCellRendererComponent(
360			JList list,
361			Object value,
362			int index,
363			boolean isSelected,
364			boolean cellHasFocus)
365		{
366			super.getListCellRendererComponent(list,value,index,
367				isSelected,cellHasFocus);
368
369			ParentDirectoryRenderer.this.setBorder(new EmptyBorder(
370				1,index * 5 + 1,1,1));
371
372			if(value instanceof LoadingPlaceholder)
373			{
374				ParentDirectoryRenderer.this.setFont(plainFont);
375
376				setIcon(showIcons ? FileCellRenderer.loadingIcon : null);
377				setText(jEdit.getProperty("vfs.browser.tree.loading"));
378			}
379			else if(value instanceof VFS.DirectoryEntry)
380			{
381				VFS.DirectoryEntry dirEntry = (VFS.DirectoryEntry)value;
382				ParentDirectoryRenderer.this.setFont(boldFont);
383
384				setIcon(showIcons ? FileCellRenderer.getIconForFile(dirEntry,true)
385					: null);
386				setText(dirEntry.name);
387			}
388			else if(value == null)
389				setText("VFS does not follow VFS API");
390
391			return this;
392		}
393	} //}}}
394
395	//{{{ ParentMouseHandler class
396	class ParentMouseHandler extends MouseAdapter
397	{
398		public void mousePressed(MouseEvent evt)
399		{
400			int row = parentDirectories.locationToIndex(evt.getPoint());
401			if(row != -1)
402			{
403				Object obj = parentDirectories.getModel()
404					.getElementAt(row);
405				if(obj instanceof VFS.DirectoryEntry)
406				{
407					VFS.DirectoryEntry dirEntry = ((VFS.DirectoryEntry)obj);
408					if(GUIUtilities.isPopupTrigger(evt))
409					{
410						if(popup != null && popup.isVisible())
411						{
412							popup.setVisible(false);
413							popup = null;
414						}
415						else
416						{
417							parentDirectories.setSelectedIndex(row);
418							showFilePopup(new VFS.DirectoryEntry[] {
419								dirEntry },parentDirectories,
420								evt.getPoint());
421						}
422					}
423				}
424			}
425		}
426
427		public void mouseReleased(MouseEvent evt)
428		{
429			if(evt.getClickCount() % 2 != 0 &&
430				!GUIUtilities.isMiddleButton(evt.getModifiers()))
431				return;
432
433			int row = parentDirectories.locationToIndex(evt.getPoint());
434			if(row != -1)
435			{
436				Object obj = parentDirectories.getModel()
437					.getElementAt(row);
438				if(obj instanceof VFS.DirectoryEntry)
439				{
440					VFS.DirectoryEntry dirEntry = ((VFS.DirectoryEntry)obj);
441					if(!GUIUtilities.isPopupTrigger(evt))
442					{
443						browser.setDirectory(dirEntry.path);
444						if(browser.getMode() == VFSBrowser.BROWSER)
445						focusOnFileView();
446					}
447				}
448			}
449		}
450	} //}}}
451
452	//{{{ TableMouseHandler class
453	class TableMouseHandler extends MouseAdapter
454	{
455		//{{{ mouseClicked() method
456		public void mouseClicked(MouseEvent evt)
457		{
458			Point p = evt.getPoint();
459			int row = table.rowAtPoint(p);
460			int column = table.columnAtPoint(p);
461			if(row == -1)
462				return;
463			if(column == 0)
464			{
465				VFSDirectoryEntryTableModel.Entry entry
466					= (VFSDirectoryEntryTableModel.Entry)
467					table.getModel().getValueAt(row,0);
468				if(FileCellRenderer.ExpansionToggleBorder
469					.isExpansionToggle(entry.level,p.x))
470				{
471					return;
472				}
473			}
474
475			if((evt.getModifiers() & MouseEvent.BUTTON1_MASK) != 0
476				&& evt.getClickCount() % 2 == 0)
477			{
478				browser.filesActivated((evt.isShiftDown()
479					? VFSBrowser.M_OPEN_NEW_VIEW
480					: VFSBrowser.M_OPEN),true);
481			}
482			else if(GUIUtilities.isMiddleButton(evt.getModifiers()))
483			{
484				if(evt.isShiftDown())
485					table.getSelectionModel().addSelectionInterval(row,row);
486				else
487					table.getSelectionModel().setSelectionInterval(row,row);
488				browser.filesActivated((evt.isShiftDown()
489					? VFSBrowser.M_OPEN_NEW_VIEW
490					: VFSBrowser.M_OPEN),true);
491			}
492		} //}}}
493
494		//{{{ mousePressed() method
495		public void mousePressed(MouseEvent evt)
496		{
497			Point p = evt.getPoint();
498			if(evt.getSource() != table)
499			{
500				p.x -= table.getX();
501				p.y -= table.getY();
502			}
503
504			int row = table.rowAtPoint(p);
505			int column = table.columnAtPoint(p);
506			if(column == 0 && row != -1)
507			{
508				VFSDirectoryEntryTableModel.Entry entry
509					= (VFSDirectoryEntryTableModel.Entry)
510					table.getModel().getValueAt(row,0);
511				if(FileCellRenderer.ExpansionToggleBorder
512					.isExpansionToggle(entry.level,p.x))
513				{
514					table.toggleExpanded(row);
515					return;
516				}
517			}
518
519			if(GUIUtilities.isMiddleButton(evt.getModifiers()))
520			{
521				if(row == -1)
522					/* nothing */;
523				else if(evt.isShiftDown())
524					table.getSelectionModel().addSelectionInterval(row,row);
525				else
526					table.getSelectionModel().setSelectionInterval(row,row);
527			}
528			else if(GUIUtilities.isPopupTrigger(evt))
529			{
530				if(popup != null && popup.isVisible())
531				{
532					popup.setVisible(false);
533					popup = null;
534					return;
535				}
536
537				if(row == -1)
538					showFilePopup(null,table,evt.getPoint());
539				else
540				{
541					if(!table.getSelectionModel().isSelectedIndex(row))
542						table.getSelectionModel().setSelectionInterval(row,row);
543					showFilePopup(getSelectedFiles(),table,evt.getPoint());
544				}
545			}
546		} //}}}
547
548		//{{{ mouseReleased() method
549		public void mouseReleased(MouseEvent evt)
550		{
551			if(!GUIUtilities.isPopupTrigger(evt)
552				&& table.getSelectedRow() != -1)
553			{
554				browser.filesSelected();
555			}
556		} //}}}
557	} //}}}
558
559	static class LoadingPlaceholder {}
560	//}}}
561}