PageRenderTime 260ms CodeModel.GetById 236ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 1ms

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