PageRenderTime 226ms CodeModel.GetById 174ms app.highlight 44ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-0-pre3/org/gjt/sp/jedit/browser/VFSBrowser.java

#
Java | 1345 lines | 1011 code | 170 blank | 164 comment | 238 complexity | 2b2f1867f6821289df8128720c2cd8ab MD5 | raw file
   1/*
   2 * VFSBrowser.java - VFS browser
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 2000, 2001 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 gnu.regexp.*;
  27import javax.swing.border.EmptyBorder;
  28import javax.swing.event.*;
  29import javax.swing.*;
  30import java.awt.event.*;
  31import java.awt.*;
  32import java.io.File;
  33import java.util.Enumeration;
  34import java.util.Hashtable;
  35import java.util.Vector;
  36import org.gjt.sp.jedit.io.*;
  37import org.gjt.sp.jedit.gui.*;
  38import org.gjt.sp.jedit.msg.*;
  39import org.gjt.sp.jedit.search.*;
  40import org.gjt.sp.jedit.*;
  41import org.gjt.sp.util.Log;
  42//}}}
  43
  44/**
  45 * The main class of the VFS browser.
  46 * @author Slava Pestov
  47 * @version $Id: VFSBrowser.java 3931 2001-12-02 11:40:51Z spestov $
  48 */
  49public class VFSBrowser extends JPanel implements EBComponent
  50{
  51	public static final String NAME = "vfs.browser";
  52
  53	//{{{ Browser types
  54	/**
  55	 * Open file dialog mode. Equals JFileChooser.OPEN_DIALOG for
  56	 * backwards compatibility.
  57	 */
  58	public static final int OPEN_DIALOG = 0;
  59
  60	/**
  61	 * Save file dialog mode. Equals JFileChooser.SAVE_DIALOG for
  62	 * backwards compatibility.
  63	 */
  64	public static final int SAVE_DIALOG = 1;
  65
  66	/**
  67	 * Stand-alone browser mode.
  68	 */
  69	public static final int BROWSER = 2;
  70	//}}}
  71
  72	//{{{ browseDirectory() method
  73	/**
  74	 * Opens the specified directory in a file system browser.
  75	 * @param view The view
  76	 * @param path The directory's path
  77	 * @since jEdit 4.0pre3
  78	 */
  79	public static void browseDirectory(View view, String path)
  80	{
  81		DockableWindowManager wm = view.getDockableWindowManager();
  82		VFSBrowser browser = (VFSBrowser)wm.getDockable(NAME);
  83		if(browser != null)
  84		{
  85			wm.showDockableWindow(NAME);
  86			browser.setDirectory(path);
  87		}
  88		else
  89		{
  90			if(path != null)
  91			{
  92				// this is such a bad way of doing it, but oh well...
  93				jEdit.setTemporaryProperty("vfs.browser.path.tmp",path);
  94			}
  95			wm.addDockableWindow("vfs.browser");
  96			jEdit.unsetProperty("vfs.browser.path.tmp");
  97		}
  98	} //}}}
  99
 100	//{{{ VFSBrowser constructor
 101	/**
 102	 * Creates a new VFS browser.
 103	 * @param view The view to open buffers in by default
 104	 * @param path The path to display
 105	 * @param mode The browser mode
 106	 * @param multipleSelection True if multiple selection should be allowed
 107	 * @param floating True if this browser instance is floating
 108	 */
 109	public VFSBrowser(View view, String path, int mode, boolean multipleSelection,
 110		boolean floating)
 111	{
 112		super(new BorderLayout());
 113
 114		listenerList = new EventListenerList();
 115
 116		this.mode = mode;
 117		this.multipleSelection = multipleSelection;
 118		this.floating = floating;
 119		this.view = view;
 120
 121		ActionHandler actionHandler = new ActionHandler();
 122
 123		Box topBox = new Box(BoxLayout.Y_AXIS);
 124
 125		// this is tricky, because in BROWSER mode, the menu bar
 126		// and tool bar are stacked on top of each other, and
 127		// the user can toggle the tool bar. In dialog modes,
 128		// the two are side by side and the tool bar is always
 129		// visible.
 130		toolbarBox = new Box(mode == BROWSER
 131			? BoxLayout.Y_AXIS
 132			: BoxLayout.X_AXIS);
 133		JToolBar menuBar = createMenuBar();
 134		if(mode == BROWSER)
 135			menuBar.add(Box.createGlue());
 136		toolbarBox.add(menuBar);
 137		if(mode != BROWSER)
 138		{
 139			toolbarBox.add(Box.createHorizontalStrut(6));
 140			toolbarBox.add(createToolBar());
 141			toolbarBox.add(Box.createGlue());
 142		}
 143
 144		topBox.add(toolbarBox);
 145
 146		GridBagLayout layout = new GridBagLayout();
 147		JPanel pathAndFilterPanel = new JPanel(layout);
 148
 149		GridBagConstraints cons = new GridBagConstraints();
 150		cons.gridwidth = cons.gridheight = 1;
 151		cons.gridx = cons.gridy = 0;
 152		cons.fill = GridBagConstraints.BOTH;
 153		cons.anchor = GridBagConstraints.EAST;
 154		JLabel label = new JLabel(jEdit.getProperty("vfs.browser.path"),
 155			SwingConstants.RIGHT);
 156		label.setBorder(new EmptyBorder(0,0,0,12));
 157		layout.setConstraints(label,cons);
 158		pathAndFilterPanel.add(label);
 159
 160		pathField = new HistoryTextField("vfs.browser.path");
 161		pathField.setInstantPopups(true);
 162		pathField.setEnterAddsToHistory(false);
 163		pathField.setSelectAllOnFocus(true);
 164
 165		if(floating)
 166		{
 167			label.setDisplayedMnemonic(jEdit.getProperty(
 168				"vfs.browser.path.mnemonic").charAt(0));
 169			label.setLabelFor(pathField);
 170		}
 171
 172		// because its preferred size can be quite wide, we
 173		// don't want it to make the browser way too big,
 174		// so set the preferred width to 0.
 175		Dimension prefSize = pathField.getPreferredSize();
 176		prefSize.width = 0;
 177		pathField.setPreferredSize(prefSize);
 178		pathField.addActionListener(actionHandler);
 179		pathField.addFocusListener(new FocusHandler());
 180		cons.gridx = 1;
 181		cons.weightx = 1.0f;
 182
 183		layout.setConstraints(pathField,cons);
 184		pathAndFilterPanel.add(pathField);
 185
 186		filterCheckbox = new JCheckBox(jEdit.getProperty("vfs.browser.filter"));
 187		filterCheckbox.setMargin(new Insets(0,0,0,0));
 188		filterCheckbox.setRequestFocusEnabled(false);
 189		filterCheckbox.setBorder(new EmptyBorder(0,0,0,12));
 190		filterCheckbox.setSelected(mode != BROWSER ||
 191			jEdit.getBooleanProperty("vfs.browser.filter-enabled"));
 192
 193		filterCheckbox.addActionListener(actionHandler);
 194		cons.gridx = 0;
 195		cons.weightx = 0.0f;
 196		cons.gridy = 1;
 197		layout.setConstraints(filterCheckbox,cons);
 198		pathAndFilterPanel.add(filterCheckbox);
 199
 200		filterField = new HistoryTextField("vfs.browser.filter");
 201		filterField.setInstantPopups(true);
 202		filterField.setSelectAllOnFocus(true);
 203		filterField.addActionListener(actionHandler);
 204
 205		cons.gridx = 1;
 206		cons.weightx = 1.0f;
 207		layout.setConstraints(filterField,cons);
 208		pathAndFilterPanel.add(filterField);
 209
 210		topBox.add(pathAndFilterPanel);
 211		add(BorderLayout.NORTH,topBox);
 212
 213		add(BorderLayout.CENTER,browserView = new BrowserView(this));
 214
 215		propertiesChanged();
 216
 217		HistoryModel filterModel = HistoryModel.getModel("vfs.browser.filter");
 218		String filter;
 219		if(mode == BROWSER || view == null || !jEdit.getBooleanProperty(
 220			"vfs.browser.currentBufferFilter"))
 221		{
 222			filter = jEdit.getProperty("vfs.browser.last-filter");
 223			if(filter == null)
 224				filter = jEdit.getProperty("vfs.browser.default-filter");
 225		}
 226		else
 227		{
 228			String name = view.getBuffer().getName();
 229			int index = name.lastIndexOf('.');
 230
 231			if(index == -1)
 232				filter = jEdit.getProperty("vfs.browser.default-filter");
 233			else
 234			{
 235				String ext = name.substring(index);
 236				filter = "*" + ext;
 237			}
 238		}
 239
 240		filterField.setText(filter);
 241		filterField.addCurrentToHistory();
 242
 243		updateFilterEnabled();
 244
 245		// see VFSBrowser.browseDirectory()
 246		if(path == null)
 247			path = jEdit.getProperty("vfs.browser.path.tmp");
 248
 249		if(path == null || path.length() == 0)
 250		{
 251			String userHome = System.getProperty("user.home");
 252			String defaultPath = jEdit.getProperty("vfs.browser.defaultPath");
 253			if(defaultPath.equals("home"))
 254				path = userHome;
 255			else if(defaultPath.equals("buffer"))
 256			{
 257				if(view != null)
 258				{
 259					Buffer buffer = view.getBuffer();
 260					path = buffer.getVFS().getParentOfPath(
 261						buffer.getPath());
 262				}
 263				else
 264					path = userHome;
 265			}
 266			else if(defaultPath.equals("last"))
 267			{
 268				HistoryModel pathModel = HistoryModel.getModel("vfs.browser.path");
 269				if(pathModel.getSize() == 0)
 270					path = "~";
 271				else
 272					path = pathModel.getItem(0);
 273			}
 274			else if(defaultPath.equals("favorites"))
 275				path = "favorites:";
 276			else
 277			{
 278				// unknown value??!!!
 279				path = userHome;
 280			}
 281		}
 282
 283		setDirectory(path);
 284	} //}}}
 285
 286	//{{{ requestDefaultFocus() method
 287	public boolean requestDefaultFocus()
 288	{
 289		return browserView.requestDefaultFocus();
 290	} //}}}
 291
 292	//{{{ addNotify() method
 293	public void addNotify()
 294	{
 295		super.addNotify();
 296		EditBus.addToBus(this);
 297	} //}}}
 298
 299	//{{{ removeNotify() method
 300	public void removeNotify()
 301	{
 302		super.removeNotify();
 303		jEdit.setBooleanProperty("vfs.browser.filter-enabled",
 304			filterCheckbox.isSelected());
 305		if(mode == BROWSER || !jEdit.getBooleanProperty(
 306			"vfs.browser.currentBufferFilter"))
 307		{
 308			jEdit.setProperty("vfs.browser.last-filter",
 309				filterField.getText());
 310		}
 311		EditBus.removeFromBus(this);
 312	} //}}}
 313
 314	//{{{ handleMessage() method
 315	public void handleMessage(EBMessage msg)
 316	{
 317		if(msg instanceof ViewUpdate)
 318			handleViewUpdate((ViewUpdate)msg);
 319		else if(msg instanceof BufferUpdate)
 320			handleBufferUpdate((BufferUpdate)msg);
 321		else if(msg instanceof PropertiesChanged)
 322			propertiesChanged();
 323		else if(msg instanceof VFSUpdate)
 324		{
 325			// this is a dirty hack and it relies on the fact
 326			// that updates for parents are sent before updates
 327			// for the changed nodes themselves (if this was not
 328			// the case, the browser wouldn't be updated properly
 329			// on delete, etc).
 330			//
 331			// to avoid causing '> 1 request' errors, don't reload
 332			// directory if request already active
 333			if(requestRunning)
 334				return;
 335
 336			browserView.maybeReloadDirectory(((VFSUpdate)msg).getPath());
 337		}
 338	} //}}}
 339
 340	//{{{ getView() method
 341	public View getView()
 342	{
 343		return view;
 344	} //}}}
 345
 346	//{{{ getMode() method
 347	public int getMode()
 348	{
 349		return mode;
 350	} //}}}
 351
 352	//{{{ isMultipleSelectionEnabled() method
 353	public boolean isMultipleSelectionEnabled()
 354	{
 355		return multipleSelection;
 356	} //}}}
 357
 358	//{{{ getShowHiddenFiles() method
 359	public boolean getShowHiddenFiles()
 360	{
 361		return showHiddenFiles;
 362	} //}}}
 363
 364	//{{{ setShowHiddenFiles() method
 365	public void setShowHiddenFiles(boolean showHiddenFiles)
 366	{
 367		this.showHiddenFiles = showHiddenFiles;
 368	} //}}}
 369
 370	//{{{ getFilenameFilter() method
 371	/**
 372	 * Returns the file name filter glob.
 373	 * @since jEdit 3.2pre2
 374	 */
 375	public String getFilenameFilter()
 376	{
 377		if(filterCheckbox.isSelected())
 378		{
 379			String filter = filterField.getText();
 380			if(filter.length() == 0)
 381				return "*";
 382			else
 383				return filter;
 384		}
 385		else
 386			return "*";
 387	} //}}}
 388
 389	//{{{ setFilenameFilter() method
 390	public void setFilenameFilter(String filter)
 391	{
 392		if(filter == null || filter.length() == 0 || filter.equals("*"))
 393			filterCheckbox.setSelected(false);
 394		else
 395		{
 396			filterCheckbox.setSelected(true);
 397			filterField.setText(filter);
 398		}
 399	} //}}}
 400
 401	//{{{ getDirectory() method
 402	public String getDirectory()
 403	{
 404		return path;
 405	} //}}}
 406
 407	//{{{ setDirectory() method
 408	public void setDirectory(String path)
 409	{
 410		// have to do this hack until VFSPath class is written
 411		if(path.length() != 1 && (path.endsWith("/")
 412			|| path.endsWith(java.io.File.separator)))
 413			path = path.substring(0,path.length() - 1);
 414
 415		if(path.startsWith("file:"))
 416			path = path.substring(5);
 417
 418		pathField.setText(path);
 419
 420		browserView.loadDirectory(path);
 421	} //}}}
 422
 423	//{{{ reloadDirectory() method
 424	public void reloadDirectory()
 425	{
 426		// used by FTP plugin to clear directory cache
 427		VFSManager.getVFSForPath(path).reloadDirectory(path);
 428
 429		browserView.loadDirectory(path);
 430	} //}}}
 431
 432	//{{{ delete() method
 433	public void delete(String path)
 434	{
 435		if(MiscUtilities.isURL(path) && FavoritesVFS.PROTOCOL.equals(
 436			MiscUtilities.getProtocolOfURL(path)))
 437		{
 438			Object[] args = { path.substring(FavoritesVFS.PROTOCOL.length() + 1) };
 439			int result = GUIUtilities.confirm(this,
 440				"vfs.browser.delete-favorites",args,
 441				JOptionPane.YES_NO_OPTION,
 442				JOptionPane.WARNING_MESSAGE);
 443			if(result != JOptionPane.YES_OPTION)
 444				return;
 445		}
 446		else
 447		{
 448			Object[] args = { path };
 449			int result = GUIUtilities.confirm(this,
 450				"vfs.browser.delete-confirm",args,
 451				JOptionPane.YES_NO_OPTION,
 452				JOptionPane.WARNING_MESSAGE);
 453			if(result != JOptionPane.YES_OPTION)
 454				return;
 455		}
 456
 457		VFS vfs = VFSManager.getVFSForPath(path);
 458
 459		Object session = vfs.createVFSSession(path,this);
 460		if(session == null)
 461			return;
 462
 463		if(!startRequest())
 464			return;
 465
 466		VFSManager.runInWorkThread(new BrowserIORequest(
 467			BrowserIORequest.DELETE,this,
 468			session,vfs,path,null));
 469	} //}}}
 470
 471	//{{{ rename() method
 472	public void rename(String from)
 473	{
 474		VFS vfs = VFSManager.getVFSForPath(from);
 475
 476		String filename = vfs.getFileName(from);
 477		String[] args = { filename };
 478		String to = GUIUtilities.input(this,"vfs.browser.rename",
 479			args,filename);
 480		if(to == null)
 481			return;
 482
 483		to = vfs.constructPath(vfs.getParentOfPath(from),to);
 484
 485		Object session = vfs.createVFSSession(from,this);
 486		if(session == null)
 487			return;
 488
 489		if(!startRequest())
 490			return;
 491
 492		VFSManager.runInWorkThread(new BrowserIORequest(
 493			BrowserIORequest.RENAME,this,
 494			session,vfs,from,to));
 495	} //}}}
 496
 497	//{{{ mkdir() method
 498	public void mkdir()
 499	{
 500		String newDirectory = GUIUtilities.input(this,"vfs.browser.mkdir",null);
 501		if(newDirectory == null)
 502			return;
 503
 504		// if a directory is selected, create new dir in there.
 505		// if a file is selected, create new dir inside its parent.
 506		VFS.DirectoryEntry[] selected = getSelectedFiles();
 507		String parent;
 508		if(selected.length == 0)
 509			parent = path;
 510		else if(selected[0].type == VFS.DirectoryEntry.FILE)
 511		{
 512			parent = selected[0].path;
 513			parent = VFSManager.getVFSForPath(parent)
 514				.getParentOfPath(parent);
 515		}
 516		else
 517			parent = selected[0].path;
 518
 519		VFS vfs = VFSManager.getVFSForPath(parent);
 520
 521		// path is the currently viewed directory in the browser
 522		newDirectory = vfs.constructPath(parent,newDirectory);
 523
 524		Object session = vfs.createVFSSession(newDirectory,this);
 525		if(session == null)
 526			return;
 527
 528		if(!startRequest())
 529			return;
 530
 531		VFSManager.runInWorkThread(new BrowserIORequest(
 532			BrowserIORequest.MKDIR,this,
 533			session,vfs,newDirectory,null));
 534	} //}}}
 535
 536	//{{{ newFile() method
 537	/**
 538	 * Creates a new file in the current directory.
 539	 * @since jEdit 4.0pre2
 540	 */
 541	public void newFile()
 542	{
 543		VFS.DirectoryEntry[] selected = getSelectedFiles();
 544		if(selected.length >= 1)
 545		{
 546			VFS.DirectoryEntry file = selected[0];
 547			if(file.type == VFS.DirectoryEntry.DIRECTORY)
 548				jEdit.newFile(view,file.path);
 549			else
 550			{
 551				VFS vfs = VFSManager.getVFSForPath(file.path);
 552				jEdit.newFile(view,vfs.getParentOfPath(file.path));
 553			}
 554		}
 555		else
 556			jEdit.newFile(view,path);
 557	} //}}}
 558
 559	//{{{ searchInDirectory() method
 560	/**
 561	 * Opens a directory search in the current directory.
 562	 * @since jEdit 4.0pre2
 563	 */
 564	public void searchInDirectory()
 565	{
 566		String path, filter;
 567
 568		VFS.DirectoryEntry[] selected = getSelectedFiles();
 569		if(selected.length >= 1)
 570		{
 571			VFS.DirectoryEntry file = selected[0];
 572			if(file.type == VFS.DirectoryEntry.DIRECTORY)
 573			{
 574				path = file.path;
 575				filter = getFilenameFilter();
 576			}
 577			else
 578			{
 579				VFS vfs = VFSManager.getVFSForPath(file.path);
 580				path = vfs.getParentOfPath(file.path);
 581				String name = MiscUtilities.getFileName(path);
 582				String ext = MiscUtilities.getFileExtension(name);
 583				filter = (ext == null || ext.length() == 0
 584					? getFilenameFilter()
 585					: "*." + ext);
 586			}
 587		}
 588		else
 589		{
 590			path = this.path;
 591			filter = getFilenameFilter();
 592		}
 593
 594		if(!(VFSManager.getVFSForPath(path) instanceof FileVFS))
 595		{
 596			getToolkit().beep();
 597			return;
 598		}
 599
 600		SearchAndReplace.setSearchFileSet(new DirectoryListSet(
 601			path,filter,true));
 602		new SearchDialog(view,null,SearchDialog.DIRECTORY);
 603	} //}}}
 604
 605	//{{{ getBrowserView() method
 606	public BrowserView getBrowserView()
 607	{
 608		return browserView;
 609	} //}}}
 610
 611	//{{{ getSelectedFiles() method
 612	public VFS.DirectoryEntry[] getSelectedFiles()
 613	{
 614		return browserView.getSelectedFiles();
 615	} //}}}
 616
 617	//{{{ addBrowserListener() method
 618	public void addBrowserListener(BrowserListener l)
 619	{
 620		listenerList.add(BrowserListener.class,l);
 621	} //}}}
 622
 623	//{{{ removeBrowserListener() method
 624	public void removeBrowserListener(BrowserListener l)
 625	{
 626		listenerList.remove(BrowserListener.class,l);
 627	} //}}}
 628
 629	//{{{ Package-private members
 630
 631	//{{{ loadDirectory() method
 632	void loadDirectory(String path, boolean root)
 633	{
 634		loadingRoot = root;
 635
 636		try
 637		{
 638			String filter = filterField.getText();
 639			if(filter.length() == 0)
 640				filter = "*";
 641			filenameFilter = new RE(MiscUtilities.globToRE(filter),RE.REG_ICASE);
 642		}
 643		catch(Exception e)
 644		{
 645			Log.log(Log.ERROR,VFSBrowser.this,e);
 646			String[] args = { filterField.getText(),
 647				e.getMessage() };
 648			GUIUtilities.error(this,"vfs.browser.bad-filter",args);
 649		}
 650
 651		path = MiscUtilities.constructPath(this.path,path);
 652		VFS vfs = VFSManager.getVFSForPath(path);
 653
 654		Object session = vfs.createVFSSession(path,this);
 655		if(session == null)
 656			return;
 657
 658		if(!startRequest())
 659			return;
 660
 661		VFSManager.runInWorkThread(new BrowserIORequest(
 662			BrowserIORequest.LIST_DIRECTORY,this,
 663			session,vfs,path,null));
 664	} //}}}
 665
 666	//{{{ directoryLoaded() method
 667	void directoryLoaded(final String path, final VFS.DirectoryEntry[] list)
 668	{
 669		SwingUtilities.invokeLater(new Runnable()
 670		{
 671			public void run()
 672			{
 673				if(loadingRoot)
 674				{
 675					// This is the new, canonical path
 676					VFSBrowser.this.path = path;
 677					if(!pathField.getText().equals(path))
 678						pathField.setText(path);
 679					pathField.addCurrentToHistory();
 680				}
 681
 682				boolean filterEnabled = filterCheckbox.isSelected();
 683
 684				Vector directoryVector = new Vector();
 685
 686				int directories = 0;
 687				int files = 0;
 688				int invisible = 0;
 689
 690				if(list != null)
 691				{
 692					for(int i = 0; i < list.length; i++)
 693					{
 694						VFS.DirectoryEntry file = list[i];
 695						if(file.hidden && !showHiddenFiles)
 696						{
 697							invisible++;
 698							continue;
 699						}
 700
 701						if(file.type == VFS.DirectoryEntry.FILE
 702							&& filterEnabled
 703							&& filenameFilter != null
 704							&& !filenameFilter.isMatch(file.name))
 705						{
 706							invisible++;
 707							continue;
 708						}
 709
 710						if(file.type == VFS.DirectoryEntry.FILE)
 711							files++;
 712						else
 713							directories++;
 714
 715						directoryVector.addElement(file);
 716					}
 717
 718					if(sortFiles)
 719					{
 720						MiscUtilities.quicksort(directoryVector,
 721							new FileCompare());
 722					}
 723				}
 724
 725				browserView.directoryLoaded(path,directoryVector);
 726			}
 727		});
 728	} //}}}
 729
 730	//{{{ FileCompare class
 731	class FileCompare implements MiscUtilities.Compare
 732	{
 733		public int compare(Object obj1, Object obj2)
 734		{
 735			VFS.DirectoryEntry file1 = (VFS.DirectoryEntry)obj1;
 736			VFS.DirectoryEntry file2 = (VFS.DirectoryEntry)obj2;
 737
 738			if(!sortMixFilesAndDirs)
 739			{
 740				if(file1.type != file2.type)
 741					return file2.type - file1.type;
 742			}
 743
 744			return MiscUtilities.compareStrings(file1.name,
 745				file2.name,sortIgnoreCase);
 746		}
 747	} //}}}
 748
 749	//{{{ filesSelected() method
 750	void filesSelected()
 751	{
 752		VFS.DirectoryEntry[] selectedFiles = browserView.getSelectedFiles();
 753
 754		if(mode == BROWSER)
 755		{
 756			for(int i = 0; i < selectedFiles.length; i++)
 757			{
 758				VFS.DirectoryEntry file = selectedFiles[i];
 759				Buffer buffer = jEdit.getBuffer(file.path);
 760				if(buffer != null && view != null)
 761					view.setBuffer(buffer);
 762			}
 763		}
 764
 765		Object[] listeners = listenerList.getListenerList();
 766		for(int i = 0; i < listeners.length; i++)
 767		{
 768			if(listeners[i] == BrowserListener.class)
 769			{
 770				BrowserListener l = (BrowserListener)listeners[i+1];
 771				l.filesSelected(this,selectedFiles);
 772			}
 773		}
 774	} //}}}
 775
 776	//{{{ filesActivated() method
 777	void filesActivated()
 778	{
 779		VFS.DirectoryEntry[] selectedFiles = browserView.getSelectedFiles();
 780
 781		for(int i = 0; i < selectedFiles.length; i++)
 782		{
 783			VFS.DirectoryEntry file = selectedFiles[i];
 784
 785			if(file.type == VFS.DirectoryEntry.DIRECTORY
 786				|| file.type == VFS.DirectoryEntry.FILESYSTEM)
 787				setDirectory(file.path);
 788			else if(mode == BROWSER)
 789			{
 790				Buffer buffer = jEdit.getBuffer(file.path);
 791				if(buffer == null)
 792					buffer = jEdit.openFile(null,file.path);
 793				else if(doubleClickClose)
 794				{
 795					jEdit.closeBuffer(view,buffer);
 796					break;
 797				}
 798
 799				if(buffer != null)
 800				{
 801					if(view == null)
 802						view = jEdit.newView(null,buffer);
 803					else
 804						view.setBuffer(buffer);
 805				}
 806			}
 807			else
 808			{
 809				// if a file is selected in OPEN_DIALOG or
 810				// SAVE_DIALOG mode, just let the listener(s)
 811				// handle it
 812			}
 813		}
 814
 815		Object[] listeners = listenerList.getListenerList();
 816		for(int i = 0; i < listeners.length; i++)
 817		{
 818			if(listeners[i] == BrowserListener.class)
 819			{
 820				BrowserListener l = (BrowserListener)listeners[i+1];
 821				l.filesActivated(this,selectedFiles);
 822			}
 823		}
 824	} //}}}
 825
 826	//{{{ endRequest() method
 827	void endRequest()
 828	{
 829		requestRunning = false;
 830	} //}}}
 831
 832	//}}}
 833
 834	//{{{ Private members
 835
 836	//{{{ Instance variables
 837	private EventListenerList listenerList;
 838	private View view;
 839	private boolean floating;
 840	private String path;
 841	private HistoryTextField pathField;
 842	private JCheckBox filterCheckbox;
 843	private HistoryTextField filterField;
 844	private Box toolbarBox;
 845	private JToolBar toolbar;
 846	private JButton up, reload, roots, home, synchronize,
 847		newFile, newDirectory, searchInDirectory;
 848	private BrowserView browserView;
 849	private RE filenameFilter;
 850	private int mode;
 851	private boolean multipleSelection;
 852
 853	private boolean showHiddenFiles;
 854	private boolean sortFiles;
 855	private boolean sortMixFilesAndDirs;
 856	private boolean sortIgnoreCase;
 857	private boolean doubleClickClose;
 858
 859	private boolean requestRunning;
 860	private boolean loadingRoot;
 861	//}}}
 862
 863	//{{{ createMenuBar() method
 864	private JToolBar createMenuBar()
 865	{
 866		JToolBar toolBar = new JToolBar();
 867		toolBar.setFloatable(false);
 868		toolBar.putClientProperty("JToolBar.isRollover",Boolean.TRUE);
 869
 870		toolBar.add(new CommandsMenuButton());
 871		toolBar.add(Box.createHorizontalStrut(3));
 872		toolBar.add(new PluginsMenuButton());
 873		toolBar.add(Box.createHorizontalStrut(3));
 874		toolBar.add(new FavoritesMenuButton());
 875
 876		return toolBar;
 877	} //}}}
 878
 879	//{{{ createToolBar() method
 880	private JToolBar createToolBar()
 881	{
 882		JToolBar toolBar = new JToolBar();
 883		toolBar.setFloatable(false);
 884		toolBar.putClientProperty("JToolBar.isRollover",Boolean.TRUE);
 885
 886		toolBar.add(up = createToolButton("up"));
 887		toolBar.add(reload = createToolButton("reload"));
 888		toolBar.add(roots = createToolButton("roots"));
 889		toolBar.add(home = createToolButton("home"));
 890		toolBar.add(synchronize = createToolButton("synchronize"));
 891		if(mode == BROWSER)
 892			toolBar.add(newFile = createToolButton("new-file"));
 893		toolBar.add(newDirectory = createToolButton("new-directory"));
 894		if(mode == BROWSER)
 895			toolBar.add(searchInDirectory = createToolButton("search-in-directory"));
 896
 897		return toolBar;
 898	} //}}}
 899
 900	//{{{ createToolButton() method
 901	private JButton createToolButton(String name)
 902	{
 903		JButton button = new JButton();
 904		String prefix = "vfs.browser.commands.";
 905
 906		String iconName = jEdit.getProperty(
 907			prefix + name + ".icon");
 908		if(iconName != null)
 909		{
 910			Icon icon = GUIUtilities.loadIcon(iconName);
 911			if(icon != null)
 912				button.setIcon(icon);
 913			else
 914			{
 915				Log.log(Log.ERROR,this,"Missing icon: "
 916					+ iconName);
 917			}
 918		}
 919		else
 920			Log.log(Log.ERROR,this,"Missing icon name: " + name);
 921
 922		button.setToolTipText(jEdit.getProperty(prefix + name + ".label"));
 923
 924		button.setRequestFocusEnabled(false);
 925		button.setMargin(new Insets(0,0,0,0));
 926		button.addActionListener(new ActionHandler());
 927
 928		return button;
 929	} //}}}
 930
 931	//{{{ handleViewUpdate() method
 932	private void handleViewUpdate(ViewUpdate vmsg)
 933	{
 934		if(vmsg.getWhat() == ViewUpdate.CLOSED
 935			&& vmsg.getView() == view)
 936			view = null;
 937	} //}}}
 938
 939	//{{{ handleBufferUpdate() method
 940	private void handleBufferUpdate(BufferUpdate bmsg)
 941	{
 942		if(bmsg.getWhat() == BufferUpdate.CREATED
 943			|| bmsg.getWhat() == BufferUpdate.CLOSED)
 944			browserView.updateFileView();
 945		else if(bmsg.getWhat() == BufferUpdate.DIRTY_CHANGED)
 946		{
 947			// if a buffer becomes clean, it means it was
 948			// saved. So we repaint the browser view, in
 949			// case it was a 'save as'
 950			if(!bmsg.getBuffer().isDirty())
 951				browserView.updateFileView();
 952		}
 953	} //}}}
 954
 955	//{{{ propertiesChanged() method
 956	private void propertiesChanged()
 957	{
 958		showHiddenFiles = jEdit.getBooleanProperty("vfs.browser.showHiddenFiles");
 959		sortFiles = jEdit.getBooleanProperty("vfs.browser.sortFiles");
 960		sortMixFilesAndDirs = jEdit.getBooleanProperty("vfs.browser.sortMixFilesAndDirs");
 961		sortIgnoreCase = jEdit.getBooleanProperty("vfs.browser.sortIgnoreCase");
 962		doubleClickClose = jEdit.getBooleanProperty("vfs.browser.doubleClickClose");
 963
 964		browserView.propertiesChanged();
 965
 966		if(mode == BROWSER)
 967		{
 968			boolean showToolbar = jEdit.getBooleanProperty("vfs.browser.showToolbar");
 969			if(showToolbar && toolbar == null)
 970			{
 971				toolbar = createToolBar();
 972				toolbar.add(Box.createGlue());
 973				toolbarBox.add(toolbar);
 974				revalidate();
 975			}
 976			else if(!showToolbar && toolbar != null)
 977			{
 978				toolbarBox.remove(toolbar);
 979				toolbar = null;
 980				revalidate();
 981			}
 982		}
 983
 984		if(path != null)
 985			reloadDirectory();
 986	} //}}}
 987
 988	/* We do this stuff because the browser is not able to handle
 989	 * more than one request yet */
 990
 991	//{{{ startRequest() method
 992	private boolean startRequest()
 993	{
 994		if(requestRunning)
 995		{
 996			// dump stack trace for debugging purposes
 997			Log.log(Log.DEBUG,this,new Throwable("For debugging purposes"));
 998
 999			GUIUtilities.error(this,"browser-multiple-io",null);
1000			return false;
1001		}
1002		else
1003		{
1004			requestRunning = true;
1005			return true;
1006		}
1007	} //}}}
1008
1009	//{{{ updateFilterEnabled() method
1010	private void updateFilterEnabled()
1011	{
1012		filterField.setEnabled(filterCheckbox.isSelected());
1013	} //}}}
1014
1015	//}}}
1016
1017	//{{{ Inner classes
1018
1019	//{{{ ActionHandler class
1020	class ActionHandler implements ActionListener
1021	{
1022		public void actionPerformed(ActionEvent evt)
1023		{
1024			Object source = evt.getSource();
1025			if(source == pathField || source == filterField
1026				|| source == filterCheckbox)
1027			{
1028				updateFilterEnabled();
1029
1030				String path = pathField.getText();
1031				if(path != null)
1032					setDirectory(path);
1033
1034				browserView.requestDefaultFocus();
1035			}
1036			else if(source == up)
1037			{
1038				VFS vfs = VFSManager.getVFSForPath(path);
1039				setDirectory(vfs.getParentOfPath(path));
1040			}
1041			else if(source == reload)
1042				reloadDirectory();
1043			else if(source == roots)
1044				setDirectory(FileRootsVFS.PROTOCOL + ":");
1045			else if(source == home)
1046				setDirectory(System.getProperty("user.home"));
1047			else if(source == synchronize)
1048			{
1049				Buffer buffer = view.getBuffer();
1050				setDirectory(buffer.getVFS().getParentOfPath(
1051					buffer.getPath()));
1052			}
1053			else if(source == newFile)
1054				newFile();
1055			else if(source == newDirectory)
1056				mkdir();
1057			else if(source == searchInDirectory)
1058				searchInDirectory();
1059		}
1060	} //}}}
1061
1062	//{{{ FocusHandler class
1063	class FocusHandler extends FocusAdapter
1064	{
1065		public void focusLost(FocusEvent evt)
1066		{
1067			if(!requestRunning && !pathField.getText().equals(path))
1068				pathField.setText(path);
1069		}
1070	} //}}}
1071
1072	//{{{ CommandsMenuButton class
1073	class CommandsMenuButton extends JButton
1074	{
1075		//{{{ CommandsMenuButton constructor
1076		CommandsMenuButton()
1077		{
1078			setText(jEdit.getProperty("vfs.browser.commands.label"));
1079			setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1080			setHorizontalTextPosition(SwingConstants.LEADING);
1081
1082			popup = new BrowserCommandsMenu(VFSBrowser.this,null);
1083
1084			CommandsMenuButton.this.setRequestFocusEnabled(false);
1085			setMargin(new Insets(0,0,0,0));
1086			CommandsMenuButton.this.addMouseListener(new MouseHandler());
1087		} //}}}
1088
1089		JPopupMenu popup;
1090
1091		//{{{ MouseHandler class
1092		class MouseHandler extends MouseAdapter
1093		{
1094			public void mousePressed(MouseEvent evt)
1095			{
1096				if(!popup.isVisible())
1097				{
1098					GUIUtilities.showPopupMenu(
1099						popup,CommandsMenuButton.this,0,
1100						CommandsMenuButton.this.getHeight());
1101				}
1102				else
1103				{
1104					popup.setVisible(false);
1105				}
1106			}
1107		} //}}}
1108	} //}}}
1109
1110	//{{{ PluginsMenuButton class
1111	class PluginsMenuButton extends JButton
1112	{
1113		//{{{ PluginsMenuButton constructor
1114		PluginsMenuButton()
1115		{
1116			setText(jEdit.getProperty("vfs.browser.plugins.label"));
1117			setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1118			setHorizontalTextPosition(SwingConstants.LEADING);
1119
1120			PluginsMenuButton.this.setRequestFocusEnabled(false);
1121			setMargin(new Insets(0,0,0,0));
1122			PluginsMenuButton.this.addMouseListener(new MouseHandler());
1123
1124			popup = new JPopupMenu();
1125			ActionHandler actionHandler = new ActionHandler();
1126
1127			JMenuItem mi = new JMenuItem(jEdit.getProperty(
1128				"vfs.browser.plugins.plugin-manager.label"));
1129			mi.setActionCommand("plugin-manager");
1130			mi.addActionListener(actionHandler);
1131
1132			popup.add(mi);
1133			popup.addSeparator();
1134
1135			// put them in a vector for sorting
1136			Vector vec = new Vector();
1137			Enumeration enum = VFSManager.getFilesystems();
1138
1139			while(enum.hasMoreElements())
1140			{
1141				VFS vfs = (VFS)enum.nextElement();
1142				if((vfs.getCapabilities() & VFS.BROWSE_CAP) == 0)
1143					continue;
1144
1145				JMenuItem menuItem = new JMenuItem(jEdit.getProperty(
1146					"vfs." + vfs.getName() + ".label"));
1147				menuItem.setActionCommand(vfs.getName());
1148				menuItem.addActionListener(actionHandler);
1149				vec.addElement(menuItem);
1150			}
1151
1152			if(vec.size() != 0)
1153			{
1154				MiscUtilities.quicksort(vec,new MiscUtilities.MenuItemCompare());
1155				for(int i = 0; i < vec.size(); i++)
1156					popup.add((JMenuItem)vec.elementAt(i));
1157			}
1158			else
1159			{
1160				mi = new JMenuItem(jEdit.getProperty(
1161					"vfs.browser.plugins.no-plugins.label"));
1162				mi.setEnabled(false);
1163				popup.add(mi);
1164			}
1165		} //}}}
1166
1167		JPopupMenu popup;
1168
1169		//{{{ ActionHandler class
1170		class ActionHandler implements ActionListener
1171		{
1172			public void actionPerformed(ActionEvent evt)
1173			{
1174				if(evt.getActionCommand().equals("plugin-manager"))
1175				{
1176					new org.gjt.sp.jedit.pluginmgr.PluginManager(
1177						JOptionPane.getFrameForComponent(
1178						VFSBrowser.this));
1179				}
1180				else
1181				{
1182					VFS vfs = VFSManager.getVFSByName(evt.getActionCommand());
1183					String directory = vfs.showBrowseDialog(null,
1184						VFSBrowser.this);
1185					if(directory != null)
1186						setDirectory(directory);
1187				}
1188			}
1189		} //}}}
1190
1191		//{{{ MouseHandler class
1192		class MouseHandler extends MouseAdapter
1193		{
1194			public void mousePressed(MouseEvent evt)
1195			{
1196				if(!popup.isVisible())
1197				{
1198					GUIUtilities.showPopupMenu(
1199						popup,PluginsMenuButton.this,0,
1200						PluginsMenuButton.this.getHeight());
1201				}
1202				else
1203				{
1204					popup.setVisible(false);
1205				}
1206			}
1207		} //}}}
1208	} //}}}
1209
1210	//{{{ FavoritesMenuButton class
1211	class FavoritesMenuButton extends JButton
1212	{
1213		//{{{ FavoritesMenuButton constructor
1214		FavoritesMenuButton()
1215		{
1216			setText(jEdit.getProperty("vfs.browser.favorites.label"));
1217			setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1218			setHorizontalTextPosition(SwingConstants.LEADING);
1219
1220			FavoritesMenuButton.this.setRequestFocusEnabled(false);
1221			setMargin(new Insets(0,0,0,0));
1222			FavoritesMenuButton.this.addMouseListener(new MouseHandler());
1223		} //}}}
1224
1225		JPopupMenu popup;
1226
1227		//{{{ ActionHandler class
1228		class ActionHandler implements ActionListener
1229		{
1230			public void actionPerformed(ActionEvent evt)
1231			{
1232				String actionCommand = evt.getActionCommand();
1233				if(actionCommand.equals("add-to-favorites"))
1234				{
1235					// if any directories are selected, add
1236					// them, otherwise add current directory
1237					Vector toAdd = new Vector();
1238					VFS.DirectoryEntry[] selected = getSelectedFiles();
1239					for(int i = 0; i < selected.length; i++)
1240					{
1241						VFS.DirectoryEntry file = selected[i];
1242						if(file.type == VFS.DirectoryEntry.FILE)
1243						{
1244							GUIUtilities.error(
1245								VFSBrowser.this,
1246								"vfs.browser.files-favorites",
1247								null);
1248							return;
1249						}
1250						else
1251							toAdd.addElement(file.path);
1252					}
1253
1254					if(toAdd.size() != 0)
1255					{
1256						for(int i = 0; i < toAdd.size(); i++)
1257						{
1258							FavoritesVFS.addToFavorites((String)toAdd.elementAt(i));
1259						}
1260					}
1261					else
1262					{
1263						if(path.equals(FavoritesVFS.PROTOCOL + ":"))
1264						{
1265							GUIUtilities.error(VFSBrowser.this,
1266								"vfs.browser.recurse-favorites",
1267								null);
1268						}
1269						else
1270						{
1271							FavoritesVFS.addToFavorites(path);
1272						}
1273					}
1274				}
1275				else
1276					setDirectory(actionCommand);
1277			}
1278		} //}}}
1279
1280		//{{{ MouseHandler class
1281		class MouseHandler extends MouseAdapter
1282		{
1283			public void mousePressed(MouseEvent evt)
1284			{
1285				if(popup == null || !popup.isVisible())
1286				{
1287					popup = new JPopupMenu();
1288					ActionHandler actionHandler = new ActionHandler();
1289
1290					JMenuItem mi = new JMenuItem(
1291						jEdit.getProperty(
1292						"vfs.browser.favorites"
1293						+ ".add-to-favorites.label"));
1294					mi.setActionCommand("add-to-favorites");
1295					mi.addActionListener(actionHandler);
1296					popup.add(mi);
1297
1298					mi = new JMenuItem(
1299						jEdit.getProperty(
1300						"vfs.browser.favorites"
1301						+ ".edit-favorites.label"));
1302					mi.setActionCommand("favorites:");
1303					mi.addActionListener(actionHandler);
1304					popup.add(mi);
1305
1306					popup.addSeparator();
1307
1308					String[] favorites = FavoritesVFS.getFavorites();
1309					if(favorites.length == 0)
1310					{
1311						mi = new JMenuItem(
1312							jEdit.getProperty(
1313							"vfs.browser.favorites"
1314							+ ".no-favorites.label"));
1315						mi.setEnabled(false);
1316						popup.add(mi);
1317					}
1318					else
1319					{
1320						MiscUtilities.quicksort(favorites,
1321							new MiscUtilities.StringCompare());
1322						for(int i = 0; i < favorites.length; i++)
1323						{
1324							mi = new JMenuItem(favorites[i]);
1325							mi.setIcon(FileCellRenderer.dirIcon);
1326							mi.addActionListener(actionHandler);
1327							popup.add(mi);
1328						}
1329					}
1330
1331					GUIUtilities.showPopupMenu(
1332						popup,FavoritesMenuButton.this,0,
1333						FavoritesMenuButton.this.getHeight());
1334				}
1335				else
1336				{
1337					popup.setVisible(false);
1338					popup = null;
1339				}
1340			}
1341		} //}}}
1342	} //}}}
1343
1344	//}}}
1345}