PageRenderTime 144ms CodeModel.GetById 87ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 1699 lines | 1233 code | 212 blank | 254 comment | 242 complexity | 86850756872f828476079623b650ecc5 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, 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 bsh.*;
  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.*;
  34import java.util.regex.Pattern;
  35import org.gjt.sp.jedit.io.*;
  36import org.gjt.sp.jedit.gui.*;
  37import org.gjt.sp.jedit.msg.*;
  38import org.gjt.sp.jedit.search.*;
  39import org.gjt.sp.jedit.*;
  40import org.gjt.sp.util.Log;
  41//}}}
  42
  43/**
  44 * The main class of the VFS browser.
  45 * @author Slava Pestov
  46 * @version $Id: VFSBrowser.java 5487 2006-06-23 22:58:12Z kpouer $
  47 */
  48public class VFSBrowser extends JPanel implements EBComponent, DefaultFocusComponent
  49{
  50	public static final String NAME = "vfs.browser";
  51
  52	//{{{ Browser types
  53	/**
  54	 * Open file dialog mode. Equals JFileChooser.OPEN_DIALOG for
  55	 * backwards compatibility.
  56	 */
  57	public static final int OPEN_DIALOG = 0;
  58
  59	/**
  60	 * Save file dialog mode. Equals JFileChooser.SAVE_DIALOG for
  61	 * backwards compatibility.
  62	 */
  63	public static final int SAVE_DIALOG = 1;
  64	/**
  65	 * Choose directory dialog mode.
  66	 */
  67	public static final int BROWSER_DIALOG = 4;
  68	/**
  69	 * Choose directory dialog mode.
  70	 */
  71	public static final int CHOOSE_DIRECTORY_DIALOG = 3;
  72
  73	/**
  74	 * Stand-alone browser mode.
  75	 */
  76	public static final int BROWSER = 2;
  77	//}}}
  78
  79	//{{{ browseDirectoryInNewWindow() method
  80	/**
  81	 * Opens the specified directory in a new, floating, file system browser.
  82	 * @param view The view
  83	 * @param path The directory's path
  84	 * @since jEdit 4.1pre2
  85	 */
  86	public static void browseDirectoryInNewWindow(View view, String path)
  87	{
  88		DockableWindowManager wm = view.getDockableWindowManager();
  89		if(path != null)
  90		{
  91			// this is such a bad way of doing it, but oh well...
  92			jEdit.setTemporaryProperty("vfs.browser.path.tmp",path);
  93		}
  94		wm.floatDockableWindow("vfs.browser");
  95		jEdit.unsetProperty("vfs.browser.path.tmp");
  96	} //}}}
  97
  98	//{{{ browseDirectory() method
  99	/**
 100	 * Opens the specified directory in a file system browser.
 101	 * @param view The view
 102	 * @param path The directory's path
 103	 * @since jEdit 4.0pre3
 104	 */
 105	public static void browseDirectory(View view, String path)
 106	{
 107		DockableWindowManager wm = view.getDockableWindowManager();
 108		VFSBrowser browser = (VFSBrowser)wm.getDockable(NAME);
 109		if(browser != null)
 110		{
 111			wm.showDockableWindow(NAME);
 112			browser.setDirectory(path);
 113		}
 114		else
 115		{
 116			if(path != null)
 117			{
 118				// this is such a bad way of doing it, but oh well...
 119				jEdit.setTemporaryProperty("vfs.browser.path.tmp",path);
 120			}
 121			wm.addDockableWindow("vfs.browser");
 122			jEdit.unsetProperty("vfs.browser.path.tmp");
 123		}
 124	} //}}}
 125
 126	//{{{ getActionContext() method
 127	/**
 128	 * Returns the browser action context.
 129	 * @since jEdit 4.2pre1
 130	 */
 131	public static ActionContext getActionContext()
 132	{
 133		return actionContext;
 134	} //}}}
 135
 136	//{{{ VFSBrowser constructor
 137	/**
 138	 * Creates a new VFS browser.
 139	 * @param view The view to open buffers in by default
 140	 */
 141	public VFSBrowser(View view, String position)
 142	{
 143		this(view,null,BROWSER,true,position);
 144	} //}}}
 145
 146	//{{{ VFSBrowser constructor
 147	/**
 148	 * Creates a new VFS browser.
 149	 * @param view The view to open buffers in by default
 150	 * @param path The path to display
 151	 * @param mode The browser mode
 152	 * @param multipleSelection True if multiple selection should be allowed
 153	 * @param position Where the browser is located
 154	 * @since jEdit 4.2pre1
 155	 */
 156	public VFSBrowser(View view, String path, int mode,
 157		boolean multipleSelection, String position)
 158	{
 159		super(new BorderLayout());
 160
 161		listenerList = new EventListenerList();
 162
 163		this.mode = mode;
 164		this.multipleSelection = multipleSelection;
 165		this.view = view;
 166
 167		currentEncoding = jEdit.getProperty("buffer.encoding",
 168			System.getProperty("file.encoding"));
 169		autoDetectEncoding = jEdit.getBooleanProperty(
 170			"buffer.encodingAutodetect");
 171
 172		ActionHandler actionHandler = new ActionHandler();
 173
 174		Box topBox = new Box(BoxLayout.Y_AXIS);
 175
 176		horizontalLayout = (mode != BROWSER
 177			|| DockableWindowManager.TOP.equals(position)
 178			|| DockableWindowManager.BOTTOM.equals(position));
 179
 180		toolbarBox = new Box(horizontalLayout
 181			? BoxLayout.X_AXIS
 182			: BoxLayout.Y_AXIS);
 183
 184		topBox.add(toolbarBox);
 185
 186		GridBagLayout layout = new GridBagLayout();
 187		JPanel pathAndFilterPanel = new JPanel(layout);
 188
 189		GridBagConstraints cons = new GridBagConstraints();
 190		cons.gridwidth = cons.gridheight = 1;
 191		cons.gridx = cons.gridy = 0;
 192		cons.fill = GridBagConstraints.BOTH;
 193		cons.anchor = GridBagConstraints.EAST;
 194		JLabel label = new JLabel(jEdit.getProperty("vfs.browser.path"),
 195			SwingConstants.RIGHT);
 196		label.setBorder(new EmptyBorder(0,0,0,12));
 197		layout.setConstraints(label,cons);
 198		pathAndFilterPanel.add(label);
 199
 200		pathField = new HistoryTextField("vfs.browser.path");
 201		pathField.setInstantPopups(true);
 202		pathField.setEnterAddsToHistory(false);
 203		pathField.setSelectAllOnFocus(true);
 204
 205		// because its preferred size can be quite wide, we
 206		// don't want it to make the browser way too big,
 207		// so set the preferred width to 0.
 208		Dimension prefSize = pathField.getPreferredSize();
 209		prefSize.width = 0;
 210		pathField.setPreferredSize(prefSize);
 211		pathField.addActionListener(actionHandler);
 212		cons.gridx = 1;
 213		cons.weightx = 1.0f;
 214
 215		layout.setConstraints(pathField,cons);
 216		pathAndFilterPanel.add(pathField);
 217
 218		filterCheckbox = new JCheckBox(jEdit.getProperty("vfs.browser.filter"));
 219		filterCheckbox.setMargin(new Insets(0,0,0,0));
 220		filterCheckbox.setRequestFocusEnabled(false);
 221		filterCheckbox.setBorder(new EmptyBorder(0,0,0,12));
 222		filterCheckbox.setSelected(jEdit.getBooleanProperty(
 223			"vfs.browser.filter-enabled"));
 224
 225		filterCheckbox.addActionListener(actionHandler);
 226
 227		if(mode != CHOOSE_DIRECTORY_DIALOG)
 228		{
 229			cons.gridx = 0;
 230			cons.weightx = 0.0f;
 231			cons.gridy = 1;
 232			layout.setConstraints(filterCheckbox,cons);
 233			pathAndFilterPanel.add(filterCheckbox);
 234		}
 235
 236		filterField = new HistoryTextField("vfs.browser.filter");
 237		filterField.setInstantPopups(true);
 238		filterField.setSelectAllOnFocus(true);
 239		filterField.addActionListener(actionHandler);
 240
 241		if(mode != CHOOSE_DIRECTORY_DIALOG)
 242		{
 243			cons.gridx = 1;
 244			cons.weightx = 1.0f;
 245			layout.setConstraints(filterField,cons);
 246			pathAndFilterPanel.add(filterField);
 247		}
 248
 249		topBox.add(pathAndFilterPanel);
 250		add(BorderLayout.NORTH,topBox);
 251
 252		add(BorderLayout.CENTER,browserView = new BrowserView(this));
 253
 254		propertiesChanged();
 255
 256		String filter;
 257		if(mode == BROWSER || !jEdit.getBooleanProperty(
 258			"vfs.browser.currentBufferFilter"))
 259		{
 260			filter = jEdit.getProperty("vfs.browser.last-filter");
 261			if(filter == null)
 262				filter = jEdit.getProperty("vfs.browser.default-filter");
 263		}
 264		else
 265		{
 266			String ext = MiscUtilities.getFileExtension(
 267				view.getBuffer().getName());
 268			if(ext.length() == 0)
 269				filter = jEdit.getProperty("vfs.browser.default-filter");
 270			else
 271				filter = "*" + ext;
 272		}
 273
 274		filterField.setText(filter);
 275		filterField.addCurrentToHistory();
 276
 277		updateFilterEnabled();
 278
 279		// see VFSBrowser.browseDirectory()
 280		if(path == null)
 281			path = jEdit.getProperty("vfs.browser.path.tmp");
 282
 283		if(path == null || path.length() == 0)
 284		{
 285			String userHome = System.getProperty("user.home");
 286			String defaultPath = jEdit.getProperty("vfs.browser.defaultPath");
 287			if(defaultPath.equals("home"))
 288				path = userHome;
 289			else if(defaultPath.equals("working"))
 290				path = System.getProperty("user.dir");
 291			else if(defaultPath.equals("buffer"))
 292			{
 293				if(view != null)
 294				{
 295					Buffer buffer = view.getBuffer();
 296					path = buffer.getDirectory();
 297				}
 298				else
 299					path = userHome;
 300			}
 301			else if(defaultPath.equals("last"))
 302			{
 303				HistoryModel pathModel = HistoryModel.getModel("vfs.browser.path");
 304				if(pathModel.getSize() == 0)
 305					path = "~";
 306				else
 307					path = pathModel.getItem(0);
 308			}
 309			else if(defaultPath.equals("favorites"))
 310				path = "favorites:";
 311			else
 312			{
 313				// unknown value??!!!
 314				path = userHome;
 315			}
 316		}
 317
 318		final String _path = path;
 319
 320		SwingUtilities.invokeLater(new Runnable()
 321		{
 322			public void run()
 323			{
 324				setDirectory(_path);
 325			}
 326		});
 327	} //}}}
 328
 329	//{{{ focusOnDefaultComponent() method
 330	public void focusOnDefaultComponent()
 331	{
 332		browserView.focusOnFileView();
 333	} //}}}
 334
 335	//{{{ addNotify() method
 336	public void addNotify()
 337	{
 338		super.addNotify();
 339		EditBus.addToBus(this);
 340	} //}}}
 341
 342	//{{{ removeNotify() method
 343	public void removeNotify()
 344	{
 345		super.removeNotify();
 346		jEdit.setBooleanProperty("vfs.browser.filter-enabled",
 347			filterCheckbox.isSelected());
 348		if(mode == BROWSER || !jEdit.getBooleanProperty(
 349			"vfs.browser.currentBufferFilter"))
 350		{
 351			jEdit.setProperty("vfs.browser.last-filter",
 352				filterField.getText());
 353		}
 354		EditBus.removeFromBus(this);
 355	} //}}}
 356
 357	//{{{ handleMessage() method
 358	public void handleMessage(EBMessage msg)
 359	{
 360		if(msg instanceof PropertiesChanged)
 361			propertiesChanged();
 362		else if(msg instanceof BufferUpdate)
 363		{
 364			BufferUpdate bmsg = (BufferUpdate)msg;
 365			if(bmsg.getWhat() == BufferUpdate.CREATED
 366				|| bmsg.getWhat() == BufferUpdate.CLOSED)
 367				browserView.updateFileView();
 368		}
 369		else if(msg instanceof PluginUpdate)
 370		{
 371			PluginUpdate pmsg = (PluginUpdate)msg;
 372			if(pmsg.getWhat() == PluginUpdate.LOADED
 373				|| pmsg.getWhat() == PluginUpdate.UNLOADED)
 374			{
 375				plugins.updatePopupMenu();
 376			}
 377		}
 378		else if(msg instanceof VFSUpdate)
 379		{
 380			maybeReloadDirectory(((VFSUpdate)msg).getPath());
 381		}
 382	} //}}}
 383
 384	//{{{ getView() method
 385	public View getView()
 386	{
 387		return view;
 388	} //}}}
 389
 390	//{{{ getMode() method
 391	public int getMode()
 392	{
 393		return mode;
 394	} //}}}
 395
 396	//{{{ isMultipleSelectionEnabled() method
 397	public boolean isMultipleSelectionEnabled()
 398	{
 399		return multipleSelection;
 400	} //}}}
 401
 402	//{{{ isHorizontalLayout() method
 403	public boolean isHorizontalLayout()
 404	{
 405		return horizontalLayout;
 406	} //}}}
 407
 408	//{{{ getShowHiddenFiles() method
 409	public boolean getShowHiddenFiles()
 410	{
 411		return showHiddenFiles;
 412	} //}}}
 413
 414	//{{{ setShowHiddenFiles() method
 415	public void setShowHiddenFiles(boolean showHiddenFiles)
 416	{
 417		this.showHiddenFiles = showHiddenFiles;
 418	} //}}}
 419
 420	//{{{ getFilenameFilter() method
 421	/**
 422	 * Returns the file name filter glob.
 423	 * @since jEdit 3.2pre2
 424	 */
 425	public String getFilenameFilter()
 426	{
 427		if(filterCheckbox.isSelected())
 428		{
 429			String filter = filterField.getText();
 430			if(filter.length() == 0)
 431				return "*";
 432			else
 433				return filter;
 434		}
 435		else
 436			return "*";
 437	} //}}}
 438
 439	//{{{ setFilenameFilter() method
 440	public void setFilenameFilter(String filter)
 441	{
 442		if(filter == null || filter.length() == 0 || filter.equals("*"))
 443			filterCheckbox.setSelected(false);
 444		else
 445		{
 446			filterCheckbox.setSelected(true);
 447			filterField.setText(filter);
 448		}
 449	} //}}}
 450
 451	//{{{ getDirectoryField() method
 452	public HistoryTextField getDirectoryField()
 453	{
 454		return pathField;
 455	} //}}}
 456
 457	//{{{ getDirectory() method
 458	public String getDirectory()
 459	{
 460		return path;
 461	} //}}}
 462
 463	//{{{ setDirectory() method
 464	public void setDirectory(String path)
 465	{
 466		if(path.startsWith("file:"))
 467			path = path.substring(5);
 468
 469		pathField.setText(path);
 470
 471		if(!startRequest())
 472			return;
 473
 474		updateFilenameFilter();
 475		browserView.saveExpansionState();
 476		browserView.loadDirectory(null,path,true);
 477		this.path = path;
 478
 479		VFSManager.runInAWTThread(new Runnable()
 480		{
 481			public void run()
 482			{
 483				endRequest();
 484			}
 485		});
 486	} //}}}
 487
 488	//{{{ getRootDirectory() method
 489	public static String getRootDirectory()
 490	{
 491		if(OperatingSystem.isMacOS() || OperatingSystem.isDOSDerived())
 492			return FileRootsVFS.PROTOCOL + ":";
 493		else
 494			return "/";
 495	} //}}}
 496
 497	//{{{ rootDirectory() method
 498	/**
 499	 * Goes to the local drives directory.
 500	 * @since jEdit 4.0pre4
 501	 */
 502	public void rootDirectory()
 503	{
 504		setDirectory(getRootDirectory());
 505	} //}}}
 506
 507	//{{{ reloadDirectory() method
 508	public void reloadDirectory()
 509	{
 510		// used by FTP plugin to clear directory cache
 511		VFSManager.getVFSForPath(path).reloadDirectory(path);
 512
 513		updateFilenameFilter();
 514		browserView.saveExpansionState();
 515		browserView.loadDirectory(null,path,false);
 516	} //}}}
 517
 518	//{{{ delete() method
 519	/**
 520	 * Note that all files must be on the same VFS.
 521	 * @since jEdit 4.3pre2
 522	 */
 523	public void delete(VFSFile[] files)
 524	{
 525		String dialogType;
 526
 527		if(MiscUtilities.isURL(files[0].getDeletePath())
 528			&& FavoritesVFS.PROTOCOL.equals(
 529			MiscUtilities.getProtocolOfURL(files[0].getDeletePath())))
 530		{
 531			dialogType = "vfs.browser.delete-favorites";
 532		}
 533		else
 534		{
 535			dialogType = "vfs.browser.delete-confirm";
 536		}
 537
 538		StringBuffer buf = new StringBuffer();
 539		for(int i = 0; i < files.length; i++)
 540		{
 541			buf.append(files[i].getPath());
 542			buf.append('\n');
 543		}
 544
 545		Object[] args = { buf.toString() };
 546		int result = GUIUtilities.confirm(this,dialogType,args,
 547			JOptionPane.YES_NO_OPTION,
 548			JOptionPane.WARNING_MESSAGE);
 549		if(result != JOptionPane.YES_OPTION)
 550			return;
 551
 552		VFS vfs = VFSManager.getVFSForPath(files[0].getDeletePath());
 553
 554		if(!startRequest())
 555			return;
 556
 557		for(int i = 0; i < files.length; i++)
 558		{
 559			Object session = vfs.createVFSSession(files[i].getDeletePath(),this);
 560			if(session == null)
 561				continue;
 562
 563			VFSManager.runInWorkThread(new BrowserIORequest(
 564				BrowserIORequest.DELETE,this,
 565				session,vfs,files[i].getDeletePath(),
 566				null,null));
 567		}
 568
 569		VFSManager.runInAWTThread(new Runnable()
 570		{
 571			public void run()
 572			{
 573				endRequest();
 574			}
 575		});
 576	} //}}}
 577
 578	//{{{ rename() method
 579	public void rename(String from)
 580	{
 581		VFS vfs = VFSManager.getVFSForPath(from);
 582
 583		String filename = vfs.getFileName(from);
 584		String[] args = { filename };
 585		String to = GUIUtilities.input(this,"vfs.browser.rename",
 586			args,filename);
 587		if(to == null)
 588			return;
 589
 590		to = MiscUtilities.constructPath(vfs.getParentOfPath(from),to);
 591
 592		Object session = vfs.createVFSSession(from,this);
 593		if(session == null)
 594			return;
 595
 596		if(!startRequest())
 597			return;
 598
 599		VFSManager.runInWorkThread(new BrowserIORequest(
 600			BrowserIORequest.RENAME,this,
 601			session,vfs,from,to,null));
 602
 603		VFSManager.runInAWTThread(new Runnable()
 604		{
 605			public void run()
 606			{
 607				endRequest();
 608			}
 609		});
 610	} //}}}
 611
 612	//{{{ mkdir() method
 613	public void mkdir()
 614	{
 615		String newDirectory = GUIUtilities.input(this,"vfs.browser.mkdir",null);
 616		if(newDirectory == null)
 617			return;
 618
 619		// if a directory is selected, create new dir in there.
 620		// if a file is selected, create new dir inside its parent.
 621		VFSFile[] selected = getSelectedFiles();
 622		String parent;
 623		if(selected.length == 0)
 624			parent = path;
 625		else if(selected[0].getType() == VFSFile.FILE)
 626		{
 627			parent = selected[0].getPath();
 628			parent = VFSManager.getVFSForPath(parent)
 629				.getParentOfPath(parent);
 630		}
 631		else
 632			parent = selected[0].getPath();
 633
 634		VFS vfs = VFSManager.getVFSForPath(parent);
 635
 636		// path is the currently viewed directory in the browser
 637		newDirectory = MiscUtilities.constructPath(parent,newDirectory);
 638
 639		Object session = vfs.createVFSSession(newDirectory,this);
 640		if(session == null)
 641			return;
 642
 643		if(!startRequest())
 644			return;
 645
 646		VFSManager.runInWorkThread(new BrowserIORequest(
 647			BrowserIORequest.MKDIR,this,
 648			session,vfs,newDirectory,null,null));
 649
 650		VFSManager.runInAWTThread(new Runnable()
 651		{
 652			public void run()
 653			{
 654				endRequest();
 655			}
 656		});
 657	} //}}}
 658
 659	//{{{ newFile() method
 660	/**
 661	 * Creates a new file in the current directory.
 662	 * @since jEdit 4.0pre2
 663	 */
 664	public void newFile()
 665	{
 666		VFSFile[] selected = getSelectedFiles();
 667		if(selected.length >= 1)
 668		{
 669			VFSFile file = selected[0];
 670			if(file.getType() == VFSFile.DIRECTORY)
 671				jEdit.newFile(view,file.getPath());
 672			else
 673			{
 674				VFS vfs = VFSManager.getVFSForPath(file.getPath());
 675				jEdit.newFile(view,vfs.getParentOfPath(file.getPath()));
 676			}
 677		}
 678		else
 679			jEdit.newFile(view,path);
 680	} //}}}
 681
 682	//{{{ searchInDirectory() method
 683	/**
 684	 * Opens a directory search in the current directory.
 685	 * @since jEdit 4.0pre2
 686	 */
 687	public void searchInDirectory()
 688	{
 689		VFSFile[] selected = getSelectedFiles();
 690		if(selected.length >= 1)
 691		{
 692			VFSFile file = selected[0];
 693			searchInDirectory(file.getPath(),file.getType() != VFSFile.FILE);
 694		}
 695		else
 696		{
 697			searchInDirectory(this.path,true);
 698		}
 699	} //}}}
 700
 701	//{{{ searchInDirectory() method
 702	/**
 703	 * Opens a directory search in the specified directory.
 704	 * @param path The path name
 705	 * @param directory True if the path is a directory, false if it is a file
 706	 * @since jEdit 4.2pre1
 707	 */
 708	public void searchInDirectory(String path, boolean directory)
 709	{
 710		String filter;
 711
 712		if(directory)
 713		{
 714			filter = getFilenameFilter();
 715		}
 716		else
 717		{
 718			String name = MiscUtilities.getFileName(path);
 719			String ext = MiscUtilities.getFileExtension(name);
 720			filter = (ext == null || ext.length() == 0
 721				? getFilenameFilter()
 722				: "*" + ext);
 723			path = MiscUtilities.getParentOfPath(path);
 724		}
 725
 726		SearchAndReplace.setSearchFileSet(new DirectoryListSet(
 727			path,filter,true));
 728		SearchDialog.showSearchDialog(view,null,SearchDialog.DIRECTORY);
 729	} //}}}
 730
 731	//{{{ getBrowserView() method
 732	public BrowserView getBrowserView()
 733	{
 734		return browserView;
 735	} //}}}
 736
 737	//{{{ getSelectedFiles() method
 738	/**
 739	 * @since jEdit 4.3pre2
 740	 */
 741	public VFSFile[] getSelectedFiles()
 742	{
 743		return browserView.getSelectedFiles();
 744	} //}}}
 745
 746	//{{{ locateFile() method
 747	/**
 748	 * Goes to the given file's directory and selects the file in the list.
 749	 * @param path The file
 750	 * @since jEdit 4.2pre2
 751	 */
 752	public void locateFile(final String path)
 753	{
 754		if(!filenameFilter.matcher(MiscUtilities.getFileName(path)).matches())
 755			setFilenameFilter(null);
 756
 757		setDirectory(MiscUtilities.getParentOfPath(path));
 758		VFSManager.runInAWTThread(new Runnable()
 759		{
 760			public void run()
 761			{
 762				browserView.getTable().selectFile(path);
 763			}
 764		});
 765	} //}}}
 766
 767	//{{{ createPluginsMenu() method
 768	public JComponent createPluginsMenu(JComponent pluginMenu, boolean showManagerOptions)
 769	{
 770		ActionHandler actionHandler = new ActionHandler();
 771		if(showManagerOptions && getMode() == VFSBrowser.BROWSER)
 772		{
 773			pluginMenu.add(GUIUtilities.loadMenuItem("plugin-manager",false));
 774			pluginMenu.add(GUIUtilities.loadMenuItem("plugin-options",false));
 775			if (pluginMenu instanceof JMenu)
 776				((JMenu)pluginMenu).addSeparator();
 777			else if (pluginMenu instanceof JPopupMenu)
 778				((JPopupMenu)pluginMenu).addSeparator();
 779
 780		}
 781		else
 782			/* we're in a modal dialog */;
 783
 784		ArrayList vec = new ArrayList();
 785
 786		//{{{ old API
 787		Enumeration e = VFSManager.getFilesystems();
 788
 789		while(e.hasMoreElements())
 790		{
 791			VFS vfs = (VFS)e.nextElement();
 792			if((vfs.getCapabilities() & VFS.BROWSE_CAP) == 0)
 793				continue;
 794
 795				JMenuItem menuItem = new JMenuItem(jEdit.getProperty(
 796						"vfs." + vfs.getName() + ".label"));
 797				menuItem.setActionCommand(vfs.getName());
 798				menuItem.addActionListener(actionHandler);
 799				vec.add(menuItem);
 800		} //}}}
 801
 802		//{{{ new API
 803		EditPlugin[] plugins = jEdit.getPlugins();
 804		for(int i = 0; i < plugins.length; i++)
 805		{
 806			JMenuItem menuItem = plugins[i].createBrowserMenuItems();
 807			if(menuItem != null)
 808				vec.add(menuItem);
 809		} //}}}
 810
 811		if(vec.size() != 0)
 812		{
 813			Collections.sort(vec,new MiscUtilities.MenuItemCompare());
 814			for(int i = 0; i < vec.size(); i++)
 815				pluginMenu.add((JMenuItem)vec.get(i));
 816		}
 817		else
 818		{
 819			JMenuItem mi = new JMenuItem(jEdit.getProperty(
 820					"vfs.browser.plugins.no-plugins.label"));
 821			mi.setEnabled(false);
 822			pluginMenu.add(mi);
 823		}
 824
 825		return pluginMenu;
 826	} //}}}
 827
 828	//{{{ addBrowserListener() method
 829	public void addBrowserListener(BrowserListener l)
 830	{
 831		listenerList.add(BrowserListener.class,l);
 832	} //}}}
 833
 834	//{{{ removeBrowserListener() method
 835	public void removeBrowserListener(BrowserListener l)
 836	{
 837		listenerList.remove(BrowserListener.class,l);
 838	} //}}}
 839
 840	//{{{ filesActivated() method
 841	// canDoubleClickClose set to false when ENTER pressed
 842	public static final int M_OPEN = 0;
 843	public static final int M_OPEN_NEW_VIEW = 1;
 844	public static final int M_OPEN_NEW_PLAIN_VIEW = 2;
 845	public static final int M_OPEN_NEW_SPLIT = 3;
 846	public static final int M_INSERT = 4;
 847
 848	/**
 849	 * This method does the "double-click" handling. It is public so that
 850	 * <code>browser.actions.xml</code> can bind to it.
 851	 * @since jEdit 4.2pre2
 852	 */
 853	public void filesActivated(int mode, boolean canDoubleClickClose)
 854	{
 855		VFSFile[] selectedFiles = browserView.getSelectedFiles();
 856
 857		Buffer buffer = null;
 858
 859check_selected: for(int i = 0; i < selectedFiles.length; i++)
 860		{
 861			VFSFile file = selectedFiles[i];
 862
 863			if(file.getType() == VFSFile.DIRECTORY
 864				|| file.getType() == VFSFile.FILESYSTEM)
 865			{
 866				if(mode == M_OPEN_NEW_VIEW && this.mode == BROWSER)
 867					browseDirectoryInNewWindow(view,file.getPath());
 868				else
 869					setDirectory(file.getPath());
 870			}
 871			else if(this.mode == BROWSER || this.mode == BROWSER_DIALOG)
 872			{
 873				if(mode == M_INSERT)
 874				{
 875					view.getBuffer().insertFile(view,
 876						file.getPath());
 877					continue check_selected;
 878				}
 879
 880				Buffer _buffer = jEdit.getBuffer(file.getPath());
 881				if(_buffer == null)
 882				{
 883					Hashtable props = new Hashtable();
 884					props.put(Buffer.ENCODING,currentEncoding);
 885					props.put(Buffer.ENCODING_AUTODETECT,
 886                              Boolean.valueOf(autoDetectEncoding));
 887					_buffer = jEdit.openFile(null,null,
 888						file.getPath(),false,props);
 889				}
 890				else if(doubleClickClose && canDoubleClickClose
 891					&& this.mode != BROWSER_DIALOG
 892					&& selectedFiles.length == 1)
 893				{
 894					// close if this buffer is currently
 895					// visible in the view.
 896					EditPane[] editPanes = view.getEditPanes();
 897					for(int j = 0; j < editPanes.length; j++)
 898					{
 899						if(editPanes[j].getBuffer() == _buffer)
 900						{
 901							jEdit.closeBuffer(view,_buffer);
 902							return;
 903						}
 904					}
 905				}
 906
 907				if(_buffer != null)
 908					buffer = _buffer;
 909			}
 910			else
 911			{
 912				// if a file is selected in OPEN_DIALOG or
 913				// SAVE_DIALOG mode, just let the listener(s)
 914				// handle it
 915			}
 916		}
 917
 918		if(buffer != null)
 919		{
 920			switch(mode)
 921			{
 922			case M_OPEN:
 923				view.setBuffer(buffer);
 924				break;
 925			case M_OPEN_NEW_VIEW:
 926				jEdit.newView(view,buffer,false);
 927				break;
 928			case M_OPEN_NEW_PLAIN_VIEW:
 929				jEdit.newView(view,buffer,true);
 930				break;
 931			case M_OPEN_NEW_SPLIT:
 932				view.splitHorizontally().setBuffer(buffer);
 933				break;
 934			}
 935		}
 936
 937		Object[] listeners = listenerList.getListenerList();
 938		for(int i = 0; i < listeners.length; i++)
 939		{
 940			if(listeners[i] == BrowserListener.class)
 941			{
 942				BrowserListener l = (BrowserListener)listeners[i+1];
 943				l.filesActivated(this,selectedFiles);
 944			}
 945		}
 946	} //}}}
 947
 948	//{{{ Package-private members
 949	String currentEncoding;
 950	boolean autoDetectEncoding;
 951
 952	//{{{ updateFilenameFilter() method
 953	void updateFilenameFilter()
 954	{
 955		try
 956		{
 957			String filter = filterField.getText();
 958			if(filter.length() == 0)
 959				filter = "*";
 960			filenameFilter = Pattern.compile(MiscUtilities.globToRE(filter),
 961							 Pattern.CASE_INSENSITIVE);
 962		}
 963		catch(Exception e)
 964		{
 965			Log.log(Log.ERROR,VFSBrowser.this,e);
 966			String[] args = { filterField.getText(),
 967				e.getMessage() };
 968			GUIUtilities.error(this,"vfs.browser.bad-filter",args);
 969		}
 970	} //}}}
 971
 972	//{{{ directoryLoaded() method
 973	void directoryLoaded(Object node, Object[] loadInfo,
 974		boolean addToHistory)
 975	{
 976		VFSManager.runInAWTThread(new DirectoryLoadedAWTRequest(
 977			node,loadInfo,addToHistory));
 978	} //}}}
 979
 980	//{{{ filesSelected() method
 981	void filesSelected()
 982	{
 983		VFSFile[] selectedFiles = browserView.getSelectedFiles();
 984
 985		if(mode == BROWSER)
 986		{
 987			for(int i = 0; i < selectedFiles.length; i++)
 988			{
 989				VFSFile file = selectedFiles[i];
 990				Buffer buffer = jEdit.getBuffer(file.getPath());
 991				if(buffer != null && view != null)
 992					view.setBuffer(buffer);
 993			}
 994		}
 995
 996		Object[] listeners = listenerList.getListenerList();
 997		for(int i = 0; i < listeners.length; i++)
 998		{
 999			if(listeners[i] == BrowserListener.class)
1000			{
1001				BrowserListener l = (BrowserListener)listeners[i+1];
1002				l.filesSelected(this,selectedFiles);
1003			}
1004		}
1005	} //}}}
1006
1007	//{{{ endRequest() method
1008	void endRequest()
1009	{
1010		requestRunning = false;
1011	} //}}}
1012
1013	//}}}
1014
1015	//{{{ Private members
1016
1017	private static ActionContext actionContext;
1018
1019	static
1020	{
1021		actionContext = new BrowserActionContext();
1022
1023		ActionSet builtInActionSet = new ActionSet(null,null,null,
1024			jEdit.class.getResource("browser.actions.xml"));
1025		builtInActionSet.setLabel(jEdit.getProperty("action-set.browser"));
1026		builtInActionSet.load();
1027		actionContext.addActionSet(builtInActionSet);
1028	}
1029
1030	//{{{ Instance variables
1031	private EventListenerList listenerList;
1032	private View view;
1033	private boolean horizontalLayout;
1034	private String path;
1035	private HistoryTextField pathField;
1036	private JCheckBox filterCheckbox;
1037	private HistoryTextField filterField;
1038	private Box toolbarBox;
1039	private FavoritesMenuButton favorites;
1040	private PluginsMenuButton plugins;
1041	private BrowserView browserView;
1042	private Pattern filenameFilter;
1043	private int mode;
1044	private boolean multipleSelection;
1045
1046	private boolean showHiddenFiles;
1047	private boolean sortMixFilesAndDirs;
1048	private boolean sortIgnoreCase;
1049	private boolean doubleClickClose;
1050
1051	private boolean requestRunning;
1052	private boolean maybeReloadRequestRunning;
1053	//}}}
1054
1055	//{{{ createMenuBar() method
1056	private JPanel createMenuBar()
1057	{
1058		JPanel menuBar = new JPanel();
1059		menuBar.setLayout(new BoxLayout(menuBar,BoxLayout.X_AXIS));
1060		menuBar.setBorder(new EmptyBorder(0,1,0,3));
1061
1062		menuBar.add(new CommandsMenuButton());
1063		menuBar.add(Box.createHorizontalStrut(3));
1064		menuBar.add(plugins = new PluginsMenuButton());
1065		menuBar.add(Box.createHorizontalStrut(3));
1066		menuBar.add(favorites = new FavoritesMenuButton());
1067
1068		return menuBar;
1069	} //}}}
1070
1071	//{{{ createToolBar() method
1072	private Box createToolBar()
1073	{
1074		if(mode == BROWSER)
1075			return GUIUtilities.loadToolBar(actionContext,
1076				"vfs.browser.toolbar-browser");
1077		else
1078			return GUIUtilities.loadToolBar(actionContext,
1079				"vfs.browser.toolbar-dialog");
1080	} //}}}
1081
1082	//{{{ propertiesChanged() method
1083	private void propertiesChanged()
1084	{
1085		showHiddenFiles = jEdit.getBooleanProperty("vfs.browser.showHiddenFiles");
1086		sortMixFilesAndDirs = jEdit.getBooleanProperty("vfs.browser.sortMixFilesAndDirs");
1087		sortIgnoreCase = jEdit.getBooleanProperty("vfs.browser.sortIgnoreCase");
1088		doubleClickClose = jEdit.getBooleanProperty("vfs.browser.doubleClickClose");
1089
1090		browserView.propertiesChanged();
1091
1092		toolbarBox.removeAll();
1093
1094		if(jEdit.getBooleanProperty("vfs.browser.showToolbar"))
1095		{
1096			Box toolbar = createToolBar();
1097			if(horizontalLayout)
1098				toolbarBox.add(toolbar);
1099			else
1100			{
1101				toolbar.add(Box.createGlue());
1102				toolbarBox.add(toolbar);
1103			}
1104		}
1105
1106		if(jEdit.getBooleanProperty("vfs.browser.showMenubar"))
1107		{
1108			JPanel menubar = createMenuBar();
1109			if(horizontalLayout)
1110			{
1111				toolbarBox.add(Box.createHorizontalStrut(6));
1112				toolbarBox.add(menubar,0);
1113			}
1114			else
1115			{
1116				menubar.add(Box.createGlue());
1117				toolbarBox.add(menubar);
1118			}
1119		}
1120		else
1121			favorites = null;
1122
1123		toolbarBox.add(Box.createGlue());
1124
1125		revalidate();
1126
1127		if(path != null)
1128			reloadDirectory();
1129	} //}}}
1130
1131	/* We do this stuff because the browser is not able to handle
1132	 * more than one request yet */
1133
1134	//{{{ startRequest() method
1135	private boolean startRequest()
1136	{
1137		if(requestRunning)
1138		{
1139			// dump stack trace for debugging purposes
1140			Log.log(Log.DEBUG,this,new Throwable("For debugging purposes"));
1141
1142			GUIUtilities.error(this,"browser-multiple-io",null);
1143			return false;
1144		}
1145		else
1146		{
1147			requestRunning = true;
1148			return true;
1149		}
1150	} //}}}
1151
1152	//{{{ updateFilterEnabled() method
1153	private void updateFilterEnabled()
1154	{
1155		filterField.setEnabled(filterCheckbox.isSelected());
1156	} //}}}
1157
1158	//{{{ maybeReloadDirectory() method
1159	private void maybeReloadDirectory(String dir)
1160	{
1161		if(MiscUtilities.isURL(dir)
1162			&& MiscUtilities.getProtocolOfURL(dir).equals(
1163			FavoritesVFS.PROTOCOL))
1164		{
1165			if(favorites != null)
1166				favorites.popup = null;
1167		}
1168
1169		// this is a dirty hack and it relies on the fact
1170		// that updates for parents are sent before updates
1171		// for the changed nodes themselves (if this was not
1172		// the case, the browser wouldn't be updated properly
1173		// on delete, etc).
1174		//
1175		// to avoid causing '> 1 request' errors, don't reload
1176		// directory if request already active
1177		if(maybeReloadRequestRunning)
1178		{
1179			//Log.log(Log.WARNING,this,"VFS update: request already in progress");
1180			return;
1181		}
1182
1183		// save a file -> sends vfs update. if a VFS file dialog box
1184		// is shown from the same event frame as the save, the
1185		// VFSUpdate will be delivered before the directory is loaded,
1186		// and before the path is set.
1187		if(path != null)
1188		{
1189			try
1190			{
1191				maybeReloadRequestRunning = true;
1192
1193				browserView.maybeReloadDirectory(dir);
1194			}
1195			finally
1196			{
1197				VFSManager.runInAWTThread(new Runnable()
1198				{
1199					public void run()
1200					{
1201						maybeReloadRequestRunning = false;
1202					}
1203				});
1204			}
1205		}
1206	} //}}}
1207
1208	//}}}
1209
1210	//{{{ Inner classes
1211
1212	//{{{ ActionHandler class
1213	class ActionHandler implements ActionListener
1214	{
1215		public void actionPerformed(ActionEvent evt)
1216		{
1217			Object source = evt.getSource();
1218			if(source == pathField || source == filterField
1219				|| source == filterCheckbox)
1220			{
1221				updateFilterEnabled();
1222
1223				String path = pathField.getText();
1224				if(path != null)
1225					setDirectory(path);
1226
1227				browserView.focusOnFileView();
1228			}
1229		}
1230	} //}}}
1231
1232	//{{{ CommandsMenuButton class
1233	class CommandsMenuButton extends JButton
1234	{
1235		//{{{ CommandsMenuButton constructor
1236		CommandsMenuButton()
1237		{
1238			setText(jEdit.getProperty("vfs.browser.commands.label"));
1239			setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1240			setHorizontalTextPosition(SwingConstants.LEADING);
1241
1242			popup = new BrowserCommandsMenu(VFSBrowser.this,null);
1243
1244			CommandsMenuButton.this.setRequestFocusEnabled(false);
1245			setMargin(new Insets(1,1,1,1));
1246			CommandsMenuButton.this.addMouseListener(new MouseHandler());
1247
1248			if(OperatingSystem.isMacOSLF())
1249				CommandsMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
1250		} //}}}
1251
1252		BrowserCommandsMenu popup;
1253
1254		//{{{ MouseHandler class
1255		class MouseHandler extends MouseAdapter
1256		{
1257			public void mousePressed(MouseEvent evt)
1258			{
1259				if(!popup.isVisible())
1260				{
1261					popup.update();
1262
1263					GUIUtilities.showPopupMenu(
1264						popup,CommandsMenuButton.this,0,
1265						CommandsMenuButton.this.getHeight(),
1266						false);
1267				}
1268				else
1269				{
1270					popup.setVisible(false);
1271				}
1272			}
1273		} //}}}
1274	} //}}}
1275
1276	//{{{ PluginsMenuButton class
1277	class PluginsMenuButton extends JButton
1278	{
1279		//{{{ PluginsMenuButton constructor
1280		PluginsMenuButton()
1281		{
1282			setText(jEdit.getProperty("vfs.browser.plugins.label"));
1283			setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1284			setHorizontalTextPosition(SwingConstants.LEADING);
1285
1286			PluginsMenuButton.this.setRequestFocusEnabled(false);
1287			setMargin(new Insets(1,1,1,1));
1288			PluginsMenuButton.this.addMouseListener(new MouseHandler());
1289
1290			if(OperatingSystem.isMacOSLF())
1291				PluginsMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
1292		} //}}}
1293
1294		JPopupMenu popup;
1295
1296		//{{{ updatePopupMenu() method
1297		void updatePopupMenu()
1298		{
1299			popup = null;
1300		} //}}}
1301
1302		//{{{ createPopupMenu() method
1303		private void createPopupMenu()
1304		{
1305			if(popup != null)
1306				return;
1307
1308			popup = (JPopupMenu)createPluginsMenu(new JPopupMenu(),true);
1309		} //}}}
1310
1311		//{{{ ActionHandler class
1312		class ActionHandler implements ActionListener
1313		{
1314			public void actionPerformed(ActionEvent evt)
1315			{
1316				VFS vfs = VFSManager.getVFSByName(evt.getActionCommand());
1317				String directory = vfs.showBrowseDialog(null,
1318					VFSBrowser.this);
1319				if(directory != null)
1320					setDirectory(directory);
1321			}
1322		} //}}}
1323
1324		//{{{ MouseHandler class
1325		class MouseHandler extends MouseAdapter
1326		{
1327			public void mousePressed(MouseEvent evt)
1328			{
1329				createPopupMenu();
1330
1331				if(!popup.isVisible())
1332				{
1333					GUIUtilities.showPopupMenu(
1334						popup,PluginsMenuButton.this,0,
1335						PluginsMenuButton.this.getHeight(),
1336						false);
1337				}
1338				else
1339				{
1340					popup.setVisible(false);
1341				}
1342			}
1343		} //}}}
1344	} //}}}
1345
1346	//{{{ FavoritesMenuButton class
1347	class FavoritesMenuButton extends JButton
1348	{
1349		//{{{ FavoritesMenuButton constructor
1350		FavoritesMenuButton()
1351		{
1352			setText(jEdit.getProperty("vfs.browser.favorites.label"));
1353			setIcon(GUIUtilities.loadIcon("ToolbarMenu.gif"));
1354			setHorizontalTextPosition(SwingConstants.LEADING);
1355
1356			FavoritesMenuButton.this.setRequestFocusEnabled(false);
1357			setMargin(new Insets(1,1,1,1));
1358			FavoritesMenuButton.this.addMouseListener(new MouseHandler());
1359
1360			if(OperatingSystem.isMacOSLF())
1361				FavoritesMenuButton.this.putClientProperty("JButton.buttonType","toolbar");
1362		} //}}}
1363
1364		JPopupMenu popup;
1365
1366		//{{{ createPopupMenu() method
1367		void createPopupMenu()
1368		{
1369			popup = new JPopupMenu();
1370			ActionHandler actionHandler = new ActionHandler();
1371
1372			JMenuItem mi = new JMenuItem(
1373				jEdit.getProperty(
1374				"vfs.browser.favorites"
1375				+ ".add-to-favorites.label"));
1376			mi.setActionCommand("add-to-favorites");
1377			mi.addActionListener(actionHandler);
1378			popup.add(mi);
1379
1380			mi = new JMenuItem(
1381				jEdit.getProperty(
1382				"vfs.browser.favorites"
1383				+ ".edit-favorites.label"));
1384			mi.setActionCommand("dir@favorites:");
1385			mi.addActionListener(actionHandler);
1386			popup.add(mi);
1387
1388			popup.addSeparator();
1389
1390			VFSFile[] favorites = FavoritesVFS.getFavorites();
1391			if(favorites.length == 0)
1392			{
1393				mi = new JMenuItem(
1394					jEdit.getProperty(
1395					"vfs.browser.favorites"
1396					+ ".no-favorites.label"));
1397				mi.setEnabled(false);
1398				popup.add(mi);
1399			}
1400			else
1401			{
1402				Arrays.sort(favorites,
1403					new VFS.DirectoryEntryCompare(
1404					sortMixFilesAndDirs,
1405					sortIgnoreCase));
1406				for(int i = 0; i < favorites.length; i++)
1407				{
1408					VFSFile favorite = favorites[i];
1409					mi = new JMenuItem(favorite.getPath());
1410					mi.setIcon(FileCellRenderer
1411						.getIconForFile(
1412						favorite,false));
1413					String cmd = (favorite.getType() ==
1414						VFSFile.FILE
1415						? "file@" : "dir@")
1416						+ favorite.getPath();
1417					mi.setActionCommand(cmd);
1418					mi.addActionListener(actionHandler);
1419					popup.add(mi);
1420				}
1421			}
1422		} //}}}
1423
1424		//{{{ ActionHandler class
1425		class ActionHandler implements ActionListener
1426		{
1427			public void actionPerformed(ActionEvent evt)
1428			{
1429				String actionCommand = evt.getActionCommand();
1430				if(actionCommand.equals("add-to-favorites"))
1431				{
1432					// if any directories are selected, add
1433					// them, otherwise add current directory
1434					VFSFile[] selected = getSelectedFiles();
1435					if(selected == null || selected.length == 0)
1436					{
1437						if(path.equals(FavoritesVFS.PROTOCOL + ":"))
1438						{
1439							GUIUtilities.error(VFSBrowser.this,
1440								"vfs.browser.recurse-favorites",
1441								null);
1442						}
1443						else
1444						{
1445							FavoritesVFS.addToFavorites(path,
1446								VFSFile.DIRECTORY);
1447						}
1448					}
1449					else
1450					{
1451						for(int i = 0; i < selected.length; i++)
1452						{
1453							VFSFile file = selected[i];
1454							FavoritesVFS.addToFavorites(file.getPath(),
1455								file.getType());
1456						}
1457					}
1458				}
1459				else if(actionCommand.startsWith("dir@"))
1460				{
1461					setDirectory(actionCommand.substring(4));
1462				}
1463				else if(actionCommand.startsWith("file@"))
1464				{
1465					switch(getMode())
1466					{
1467					case BROWSER:
1468						jEdit.openFile(view,actionCommand.substring(5));
1469						break;
1470					default:
1471						locateFile(actionCommand.substring(5));
1472						break;
1473					}
1474				}
1475			}
1476		} //}}}
1477
1478		//{{{ MouseHandler class
1479		class MouseHandler extends MouseAdapter
1480		{
1481			public void mousePressed(MouseEvent evt)
1482			{
1483				if(popup != null && popup.isVisible())
1484				{
1485					popup.setVisible(false);
1486					return;
1487				}
1488
1489				if(popup == null)
1490					createPopupMenu();
1491
1492				GUIUtilities.showPopupMenu(
1493					popup,FavoritesMenuButton.this,0,
1494					FavoritesMenuButton.this.getHeight(),
1495					false);
1496			}
1497		} //}}}
1498	} //}}}
1499
1500	//{{{ DirectoryLoadedAWTRequest class
1501	class DirectoryLoadedAWTRequest implements Runnable
1502	{
1503		private Object node;
1504		private Object[] loadInfo;
1505		private boolean addToHistory;
1506
1507		DirectoryLoadedAWTRequest(Object node, Object[] loadInfo,
1508			boolean addToHistory)
1509		{
1510			this.node = node;
1511			this.loadInfo = loadInfo;
1512			this.addToHistory = addToHistory;
1513		}
1514
1515		public void run()
1516		{
1517			String path = (String)loadInfo[0];
1518			if(path == null)
1519			{
1520				// there was an error
1521				return;
1522			}
1523
1524			VFSFile[] list = (VFSFile[])loadInfo[1];
1525
1526			if(node == null)
1527			{
1528				// This is the new, canonical path
1529				VFSBrowser.this.path = path;
1530				if(!pathField.getText().equals(path))
1531					pathField.setText(path);
1532				if(path.endsWith("/") ||
1533					path.endsWith(File.separator))
1534				{
1535					// ensure consistent history;
1536					// eg we don't want both
1537					// foo/ and foo
1538					path = path.substring(0,
1539						path.length() - 1);
1540				}
1541
1542				if(addToHistory)
1543				{
1544					HistoryModel.getModel("vfs.browser.path")
1545						.addItem(path);
1546				}
1547			}
1548
1549			boolean filterEnabled = filterCheckbox.isSelected();
1550
1551			ArrayList directoryVector = new ArrayList();
1552
1553			int directories = 0;
1554			int files = 0;
1555			int invisible = 0;
1556
1557			if(list != null)
1558			{
1559				for(int i = 0; i < list.length; i++)
1560				{
1561					VFSFile file = list[i];
1562					if(file.isHidden() && !showHiddenFiles)
1563					{
1564						invisible++;
1565						continue;
1566					}
1567
1568					if(file.getType() == VFSFile.FILE
1569						&& filterEnabled
1570						&& filenameFilter != null
1571						&& !filenameFilter.matcher(file.getName()).matches())
1572					{
1573						invisible++;
1574						continue;
1575					}
1576
1577					if(file.getType() == VFSFile.FILE)
1578						files++;
1579					else
1580						directories++;
1581
1582					directoryVector.add(file);
1583				}
1584
1585				Collections.sort(directoryVector,
1586					new VFS.DirectoryEntryCompare(
1587					sortMixFilesAndDirs,
1588					sortIgnoreCase));
1589			}
1590
1591			browserView.directoryLoaded(node,path,
1592				directoryVector);
1593
1594			// to notify listeners that any existing
1595			// selection has been deactivated
1596
1597			// turns out under some circumstances this
1598			// method can switch the current buffer in
1599			// BROWSER mode.
1600
1601			// in any case, this is only needed for the
1602			// directory chooser (why?), so we add a
1603			// check. otherwise poor Rick will go insane.
1604			if(mode == CHOOSE_DIRECTORY_DIALOG)
1605				filesSelected();
1606		}
1607
1608		public String toString()
1609		{
1610			return (String)loadInfo[0];
1611		}
1612	} //}}}
1613
1614	//{{{ BrowserActionContext class
1615	static class BrowserActionContext extends ActionContext
1616	{
1617		/**
1618		 * If event source hierarchy contains a VFSDirectoryEntryTable,
1619		 * this is the currently selected files there. Otherwise, this
1620		 * is the currently selected item in the parent directory list.
1621		 */
1622		private VFSFile[] getSelectedFiles(EventObject evt,
1623			VFSBrowser browser)
1624		{
1625			Component source = (Component)evt.getSource();
1626
1627			if(GUIUtilities.getComponentParent(source,JList.class)
1628				!= null)
1629			{
1630				Object[] selected = browser.getBrowserView()
1631					.getParentDirectoryList()
1632					.getSelectedValues();
1633				VFSFile[] returnValue = new VFSFile[
1634					selected.length];
1635				System.arraycopy(selected,0,returnValue,0,
1636					selected.length);
1637				return returnValue;
1638			}
1639			else
1640			{
1641				return browser.getSelectedFiles();
1642			}
1643		}
1644
1645		public void invokeAction(EventObject evt, EditAction action)
1646		{
1647			VFSBrowser browser = (VFSBrowser)
1648				GUIUtilities.getComponentParent(
1649				(Component)evt.getSource(),
1650				VFSBrowser.class);
1651
1652			VFSFile[] files = getSelectedFiles(evt,browser);
1653
1654			// in the future we will want something better,
1655			// eg. having an 'evt' object passed to
1656			// EditAction.invoke().
1657
1658			// for now, since all browser actions are
1659			// written in beanshell we set the 'browser'
1660			// variable directly.
1661			NameSpace global = BeanShell.getNameSpace();
1662			try
1663			{
1664				global.setVariable("browser",browser);
1665				global.setVariable("files",files);
1666
1667				View view = browser.getView();
1668				// I guess ideally all browsers
1669				// should have views, but since they
1670				// don't, we just use the active view
1671				// in that case, since some actions
1672				// depend on a view being there and
1673				// I don't want to add checks to
1674				// them all
1675				if(view == null)
1676					view = jEdit.getActiveView();
1677				action.invoke(view);
1678			}
1679			catch(UtilEvalError err)
1680			{
1681				Log.log(Log.ERROR,this,err);
1682			}
1683			finally
1684			{
1685				try
1686				{
1687					global.setVariable("browser",null);
1688					global.setVariable("files",null);
1689				}
1690				catch(UtilEvalError err)
1691				{
1692					Log.log(Log.ERROR,this,err);
1693				}
1694			}
1695		}
1696	} //}}}
1697
1698	//}}}
1699}