PageRenderTime 83ms CodeModel.GetById 11ms app.highlight 58ms RepoModel.GetById 1ms app.codeStats 0ms

/jEdit/tags/jedit-4-0-pre5/org/gjt/sp/jedit/jEdit.java

#
Java | 2685 lines | 1633 code | 344 blank | 708 comment | 356 complexity | 6b40781f3f9f633c64c71b15a8c0057d MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1/*
   2 * jEdit.java - Main class of the jEdit editor
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 1998, 1999, 2000, 2001, 2002 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;
  24
  25//{{{ Imports
  26import com.microstar.xml.*;
  27import javax.swing.plaf.metal.*;
  28import javax.swing.plaf.FontUIResource;
  29import javax.swing.text.Element;
  30import javax.swing.*;
  31import java.awt.*;
  32import java.awt.event.*;
  33import java.io.*;
  34import java.net.*;
  35import java.text.MessageFormat;
  36import java.util.*;
  37import org.gjt.sp.jedit.browser.VFSBrowser;
  38import org.gjt.sp.jedit.msg.*;
  39import org.gjt.sp.jedit.gui.*;
  40import org.gjt.sp.jedit.io.*;
  41import org.gjt.sp.jedit.search.SearchAndReplace;
  42import org.gjt.sp.jedit.syntax.*;
  43import org.gjt.sp.jedit.textarea.*;
  44import org.gjt.sp.util.Log;
  45//}}}
  46
  47/**
  48 * The main class of the jEdit text editor.
  49 * @author Slava Pestov
  50 * @version $Id: jEdit.java 4007 2002-02-04 06:26:10Z spestov $
  51 */
  52public class jEdit
  53{
  54	//{{{ getVersion() method
  55	/**
  56	 * Returns the jEdit version as a human-readable string.
  57	 */
  58	public static String getVersion()
  59	{
  60		return MiscUtilities.buildToVersion(getBuild());
  61	} //}}}
  62
  63	//{{{ getBuild() method
  64	/**
  65	 * Returns the internal version. MiscUtilities.compareStrings() can be used
  66	 * to compare different internal versions.
  67	 */
  68	public static String getBuild()
  69	{
  70		// (major).(minor).(<99 = preX, 99 = final).(bug fix)
  71		return "04.00.05.00";
  72	} //}}}
  73
  74	//{{{ main() method
  75	/**
  76	 * The main method of the jEdit application.
  77	 * This should never be invoked directly.
  78	 * @param args The command line arguments
  79	 */
  80	public static void main(String[] args)
  81	{
  82		String javaVersion = System.getProperty("java.version");
  83		if(javaVersion.compareTo("1.3") < 0)
  84		{
  85			System.err.println("You are running Java version "
  86				+ javaVersion + ".");
  87			System.err.println("jEdit requires Java 1.3 or later.");
  88			System.exit(1);
  89		}
  90
  91		//{{{ Parse command line
  92		int level = Log.WARNING;
  93		if(args.length >= 1)
  94		{
  95			String levelStr = args[0];
  96			if(levelStr.length() == 1 && Character.isDigit(
  97				levelStr.charAt(0)))
  98			{
  99				level = Integer.parseInt(levelStr);
 100				args[0] = null;
 101			}
 102		}
 103
 104		boolean endOpts = false;
 105		settingsDirectory = MiscUtilities.constructPath(
 106			System.getProperty("user.home"),".jedit");
 107		String portFile = "server";
 108		boolean restore = true;
 109		boolean gui = true; // open initial view?
 110		boolean noPlugins = false;
 111		boolean noStartupScripts = false;
 112		String userDir = System.getProperty("user.dir");
 113
 114		// script to run
 115		String scriptFile = null;
 116
 117		for(int i = 0; i < args.length; i++)
 118		{
 119			String arg = args[i];
 120			if(arg == null)
 121				continue;
 122			else if(arg.length() == 0)
 123				args[i] = null;
 124			else if(arg.startsWith("-") && !endOpts)
 125			{
 126				if(arg.equals("--"))
 127					endOpts = true;
 128				else if(arg.equals("-usage"))
 129				{
 130					version();
 131					System.err.println();
 132					usage();
 133					System.exit(1);
 134				}
 135				else if(arg.equals("-version"))
 136				{
 137					version();
 138					System.exit(1);
 139				}
 140				else if(arg.equals("-nosettings"))
 141					settingsDirectory = null;
 142				else if(arg.startsWith("-settings="))
 143					settingsDirectory = arg.substring(10);
 144				else if(arg.startsWith("-noserver"))
 145					portFile = null;
 146				else if(arg.equals("-server"))
 147					portFile = "server";
 148				else if(arg.startsWith("-server="))
 149					portFile = arg.substring(8);
 150				else if(arg.startsWith("-background"))
 151					background = true;
 152				else if(arg.equals("-nogui"))
 153					gui = false;
 154				else if(arg.equals("-norestore"))
 155					restore = false;
 156				else if(arg.equals("-noplugins"))
 157					noPlugins = true;
 158				else if(arg.equals("-nostartupscripts"))
 159					noStartupScripts = true;
 160				else if(arg.startsWith("-run="))
 161					scriptFile = arg.substring(5);
 162				else
 163				{
 164					System.err.println("Unknown option: "
 165						+ arg);
 166					usage();
 167					System.exit(1);
 168				}
 169				args[i] = null;
 170			}
 171		} //}}}
 172
 173		if(settingsDirectory != null && portFile != null)
 174			portFile = MiscUtilities.constructPath(settingsDirectory,portFile);
 175		else
 176			portFile = null;
 177
 178		Log.init(true,level);
 179
 180		//{{{ Try connecting to another running jEdit instance
 181		if(portFile != null && new File(portFile).exists())
 182		{
 183			int port, key;
 184			try
 185			{
 186				BufferedReader in = new BufferedReader(new FileReader(portFile));
 187				String check = in.readLine();
 188				if(!check.equals("b"))
 189					throw new Exception("Wrong port file format");
 190
 191				port = Integer.parseInt(in.readLine());
 192				key = Integer.parseInt(in.readLine());
 193				in.close();
 194
 195				Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),port);
 196				DataOutputStream out = new DataOutputStream(
 197					socket.getOutputStream());
 198				out.writeInt(key);
 199
 200				String script = makeServerScript(restore,args,scriptFile);
 201
 202				out.writeUTF(script);
 203
 204				out.close();
 205
 206				System.exit(0);
 207			}
 208			catch(Exception e)
 209			{
 210				// ok, this one seems to confuse newbies
 211				// endlessly, so log it as NOTICE, not
 212				// ERROR
 213				Log.log(Log.NOTICE,jEdit.class,"An error occurred"
 214					+ " while connecting to the jEdit server instance.");
 215				Log.log(Log.NOTICE,jEdit.class,"This probably means that"
 216					+ " jEdit crashed and/or exited abnormally");
 217				Log.log(Log.NOTICE,jEdit.class,"the last time it was run.");
 218				Log.log(Log.NOTICE,jEdit.class,"If you don't"
 219					+ " know what this means, don't worry.");
 220				Log.log(Log.NOTICE,jEdit.class,e);
 221			}
 222		} //}}}
 223
 224		// don't show splash screen if there is a file named
 225		// 'nosplash' in the settings directory
 226		if(!new File(settingsDirectory,"nosplash").exists())
 227			GUIUtilities.showSplashScreen();
 228
 229		//{{{ Initialize settings directory
 230		Writer stream;
 231		if(settingsDirectory != null)
 232		{
 233			File _settingsDirectory = new File(settingsDirectory);
 234			if(!_settingsDirectory.exists())
 235				_settingsDirectory.mkdirs();
 236			File _macrosDirectory = new File(settingsDirectory,"macros");
 237			if(!_macrosDirectory.exists())
 238				_macrosDirectory.mkdir();
 239
 240			String logPath = MiscUtilities.constructPath(
 241				settingsDirectory,"activity.log");
 242
 243			backupSettingsFile(new File(logPath));
 244
 245			try
 246			{
 247				stream = new BufferedWriter(new FileWriter(logPath));
 248			}
 249			catch(Exception e)
 250			{
 251				e.printStackTrace();
 252				stream = null;
 253			}
 254		}
 255		else
 256		{
 257			stream = null;
 258		} //}}}
 259
 260		Log.setLogWriter(stream);
 261
 262		Log.log(Log.NOTICE,jEdit.class,"jEdit version " + getVersion());
 263		Log.log(Log.MESSAGE,jEdit.class,"Settings directory is "
 264			+ settingsDirectory);
 265
 266		//{{{ Initialize server
 267		if(portFile != null)
 268		{
 269			server = new EditServer(portFile);
 270			if(!server.isOK())
 271				server = null;
 272		}
 273		else
 274		{
 275			if(background)
 276			{
 277				background = false;
 278				System.err.println("You cannot specify both the"
 279					+ " -background and -noserver switches");
 280			}
 281		} //}}}
 282
 283		//{{{ Get things rolling
 284		initMisc();
 285		initSystemProperties();
 286		if(jEditHome != null)
 287			initSiteProperties();
 288		GUIUtilities.advanceSplashProgress();
 289
 290		BeanShell.init();
 291
 292		initUserProperties();
 293		initPLAF();
 294
 295		if(OperatingSystem.hasJava14())
 296		{
 297			try
 298			{
 299				ClassLoader loader = jEdit.class.getClassLoader();
 300				Class clazz;
 301				if(loader != null)
 302					clazz = loader.loadClass("org.gjt.sp.jedit.Java14");
 303				else
 304					clazz = Class.forName("org.gjt.sp.jedit.Java14");
 305				java.lang.reflect.Method meth = clazz
 306					.getMethod("init",new Class[0]);
 307				meth.invoke(null,new Object[0]);
 308			}
 309			catch(Exception e)
 310			{
 311				Log.log(Log.ERROR,jEdit.class,e);
 312				System.exit(1);
 313			}
 314		}
 315
 316		initActions();
 317		initDockables();
 318
 319		GUIUtilities.advanceSplashProgress();
 320
 321		VFSManager.init();
 322
 323		if(!noPlugins)
 324			initPlugins();
 325
 326		if(settingsDirectory != null)
 327		{
 328			File history = new File(MiscUtilities.constructPath(
 329				settingsDirectory,"history"));
 330			if(history.exists())
 331				historyModTime = history.lastModified();
 332			HistoryModel.loadHistory(history);
 333
 334			File recent = new File(MiscUtilities.constructPath(
 335				settingsDirectory,"recent.xml"));
 336			if(recent.exists())
 337				recentModTime = recent.lastModified();
 338			BufferHistory.load(recent);
 339		}
 340
 341		GUIUtilities.advanceSplashProgress();
 342
 343		// Buffer sort
 344		sortBuffers = getBooleanProperty("sortBuffers");
 345		sortByName = getBooleanProperty("sortByName");
 346
 347		reloadModes();
 348
 349		GUIUtilities.advanceSplashProgress();
 350
 351		SearchAndReplace.load();
 352		Macros.loadMacros();
 353
 354		GUIUtilities.advanceSplashProgress();
 355		//}}}
 356
 357		//{{{ Start plugins
 358		for(int i = 0; i < jars.size(); i++)
 359		{
 360			((EditPlugin.JAR)jars.elementAt(i)).getClassLoader()
 361				.startAllPlugins();
 362		} //}}}
 363
 364		//{{{ Run startup scripts, after plugins and settings are loaded
 365		if(!noStartupScripts && jEditHome != null)
 366		{
 367			String path = MiscUtilities.constructPath(jEditHome,"startup");
 368			File file = new File(path);
 369			if(file.exists())
 370				runStartupScripts(file);
 371		}
 372
 373		if(!noStartupScripts && settingsDirectory != null)
 374		{
 375			String path = MiscUtilities.constructPath(settingsDirectory,"startup");
 376			File file = new File(path);
 377			if(!file.exists())
 378				file.mkdirs();
 379			else
 380				runStartupScripts(file);
 381		} //}}}
 382
 383		//{{{ Run script specified with -run= parameter
 384		if(scriptFile != null)
 385		{
 386			scriptFile = MiscUtilities.constructPath(userDir,scriptFile);
 387			BeanShell.runScript(null,scriptFile,false,false);
 388		} //}}}
 389
 390		// Must be after plugins are started!!!
 391		propertiesChanged();
 392
 393		GUIUtilities.advanceSplashProgress();
 394
 395		//{{{ Open files
 396		Buffer buffer = openFiles(null,userDir,args);
 397		if(buffer != null)
 398		{
 399			// files specified on command line; force initial view
 400			// to open
 401			gui = true;
 402		}
 403
 404		String splitConfig = null;
 405
 406		if(restore && settingsDirectory != null
 407			&& jEdit.getBooleanProperty("restore")
 408			&& (bufferCount == 0 || jEdit.getBooleanProperty("restore.cli")))
 409		{
 410			splitConfig = restoreOpenFiles();
 411		}
 412
 413		if(bufferCount == 0 && gui)
 414			newFile(null);
 415		//}}}
 416
 417		//{{{ Create the view and hide the splash screen.
 418		final Buffer _buffer = buffer;
 419		final String _splitConfig = splitConfig;
 420		final boolean _gui = gui;
 421
 422		GUIUtilities.advanceSplashProgress();
 423
 424		SwingUtilities.invokeLater(new Runnable() {
 425			public void run()
 426			{
 427				EditBus.send(new EditorStarted(null));
 428
 429				if(_gui)
 430				{
 431					View view;
 432					if(_buffer != null)
 433						view = newView(null,_buffer);
 434					else
 435						view = newView(null,_splitConfig);
 436				}
 437
 438				// Start I/O threads
 439				VFSManager.start();
 440
 441				// Start edit server
 442				if(server != null)
 443					server.start();
 444
 445				GUIUtilities.hideSplashScreen();
 446
 447				Log.log(Log.MESSAGE,jEdit.class,"Startup "
 448					+ "complete");
 449
 450				//{{{ Report any plugin errors
 451				if(pluginErrors != null)
 452				{
 453					String caption = jEdit.getProperty(
 454						"plugin-error.caption" + (pluginErrors.size() == 1
 455						? "-1" : ""),new Integer[] {
 456						new Integer(pluginErrors.size()) });
 457
 458					new ErrorListDialog(
 459						jEdit.getFirstView(),
 460						jEdit.getProperty("plugin-error.title"),
 461						caption,pluginErrors,true);
 462					pluginErrors.removeAllElements();
 463				} //}}}
 464			}
 465		}); //}}}
 466	} //}}}
 467
 468	//{{{ Property methods
 469
 470	//{{{ getProperties() method
 471	/**
 472	 * Returns the properties object which contains all known
 473	 * jEdit properties.
 474	 * @since jEdit 3.1pre4
 475	 */
 476	public static final Properties getProperties()
 477	{
 478		return props;
 479	} //}}}
 480
 481	//{{{ getProperty() method
 482	/**
 483	 * Fetches a property, returning null if it's not defined.
 484	 * @param name The property
 485	 */
 486	public static final String getProperty(String name)
 487	{
 488		return props.getProperty(name);
 489	} //}}}
 490
 491	//{{{ getProperty() method
 492	/**
 493	 * Fetches a property, returning the default value if it's not
 494	 * defined.
 495	 * @param name The property
 496	 * @param def The default value
 497	 */
 498	public static final String getProperty(String name, String def)
 499	{
 500		return props.getProperty(name,def);
 501	} //}}}
 502
 503	//{{{ getProperty() method
 504	/**
 505	 * Returns the property with the specified name, formatting it with
 506	 * the <code>java.text.MessageFormat.format()</code> method.
 507	 * @param name The property
 508	 * @param args The positional parameters
 509	 */
 510	public static final String getProperty(String name, Object[] args)
 511	{
 512		if(name == null)
 513			return null;
 514		if(args == null)
 515			return props.getProperty(name);
 516		else
 517		{
 518			String value = props.getProperty(name);
 519			if(value == null)
 520				return null;
 521			else
 522				return MessageFormat.format(value,args);
 523		}
 524	} //}}}
 525
 526	//{{{ getBooleanProperty() method
 527	/**
 528	 * Returns the value of a boolean property.
 529	 * @param name The property
 530	 */
 531	public static final boolean getBooleanProperty(String name)
 532	{
 533		return getBooleanProperty(name,false);
 534	} //}}}
 535
 536	//{{{ getBooleanProperty() method
 537	/**
 538	 * Returns the value of a boolean property.
 539	 * @param name The property
 540	 * @param def The default value
 541	 */
 542	public static final boolean getBooleanProperty(String name, boolean def)
 543	{
 544		String value = getProperty(name);
 545		if(value == null)
 546			return def;
 547		else if(value.equals("true") || value.equals("yes")
 548			|| value.equals("on"))
 549			return true;
 550		else if(value.equals("false") || value.equals("no")
 551			|| value.equals("off"))
 552			return false;
 553		else
 554			return def;
 555	} //}}}
 556
 557	//{{{ getIntegerProperty() method
 558	/**
 559	 * Returns the value of an integer property.
 560	 * @param name The property
 561	 * @param def The default value
 562	 * @since jEdit 4.0pre1
 563	 */
 564	public static final int getIntegerProperty(String name, int def)
 565	{
 566		String value = getProperty(name);
 567		if(value == null)
 568			return def;
 569		else
 570		{
 571			try
 572			{
 573				return Integer.parseInt(value);
 574			}
 575			catch(NumberFormatException nf)
 576			{
 577				return def;
 578			}
 579		}
 580	} //}}}
 581
 582	//{{{ getFontProperty() method
 583	/**
 584	 * Returns the value of a font property. The family is stored
 585	 * in the <code><i>name</i></code> property, the font size is stored
 586	 * in the <code><i>name</i>size</code> property, and the font style is
 587	 * stored in <code><i>name</i>style</code>. For example, if
 588	 * <code><i>name</i></code> is <code>view.gutter.font</code>, the
 589	 * properties will be named <code>view.gutter.font</code>,
 590	 * <code>view.gutter.fontsize</code>, and
 591	 * <code>view.gutter.fontstyle</code>.
 592	 *
 593	 * @param name The property
 594	 * @since jEdit 4.0pre1
 595	 */
 596	public static final Font getFontProperty(String name)
 597	{
 598		return getFontProperty(name,null);
 599	} //}}}
 600
 601	//{{{ getFontProperty() method
 602	/**
 603	 * Returns the value of a font property. The family is stored
 604	 * in the <code><i>name</i></code> property, the font size is stored
 605	 * in the <code><i>name</i>size</code> property, and the font style is
 606	 * stored in <code><i>name</i>style</code>. For example, if
 607	 * <code><i>name</i></code> is <code>view.gutter.font</code>, the
 608	 * properties will be named <code>view.gutter.font</code>,
 609	 * <code>view.gutter.fontsize</code>, and
 610	 * <code>view.gutter.fontstyle</code>.
 611	 *
 612	 * @param name The property
 613	 * @param def The default value
 614	 * @since jEdit 4.0pre1
 615	 */
 616	public static final Font getFontProperty(String name, Font def)
 617	{
 618		String family = getProperty(name);
 619		String sizeString = getProperty(name + "size");
 620		String styleString = getProperty(name + "style");
 621
 622		if(family == null || sizeString == null || styleString == null)
 623			return def;
 624		else
 625		{
 626			int size, style;
 627
 628			try
 629			{
 630				size = Integer.parseInt(sizeString);
 631			}
 632			catch(NumberFormatException nf)
 633			{
 634				return def;
 635			}
 636
 637			try
 638			{
 639				style = Integer.parseInt(styleString);
 640			}
 641			catch(NumberFormatException nf)
 642			{
 643				return def;
 644			}
 645
 646			return new Font(family,style,size);
 647		}
 648	} //}}}
 649
 650	//{{{ getColorProperty() method
 651	/**
 652	 * Returns the value of a color property.
 653	 * @param name The property name
 654	 * @since jEdit 4.0pre1
 655	 */
 656	public static Color getColorProperty(String name)
 657	{
 658		return getColorProperty(name,Color.black);
 659	} //}}}
 660
 661	//{{{ getColorProperty() method
 662	/**
 663	 * Returns the value of a color property.
 664	 * @param name The property name
 665	 * @param def The default value
 666	 * @since jEdit 4.0pre1
 667	 */
 668	public static Color getColorProperty(String name, Color def)
 669	{
 670		String value = getProperty(name);
 671		if(value == null)
 672			return def;
 673		else
 674			return GUIUtilities.parseColor(value,def);
 675	} //}}}
 676
 677	//{{{ setColorProperty() method
 678	/**
 679	 * Sets the value of a color property.
 680	 * @param name The property name
 681	 * @param value The value
 682	 * @since jEdit 4.0pre1
 683	 */
 684	public static void setColorProperty(String name, Color value)
 685	{
 686		setProperty(name,GUIUtilities.getColorHexString(value));
 687	} //}}}
 688
 689	//{{{ setProperty() method
 690	/**
 691	 * Sets a property to a new value.
 692	 * @param name The property
 693	 * @param value The new value
 694	 */
 695	public static final void setProperty(String name, String value)
 696	{
 697		/* if value is null:
 698		 * - if default is null, unset user prop
 699		 * - else set user prop to ""
 700		 * else
 701		 * - if default equals value, ignore
 702		 * - if default doesn't equal value, set user
 703		 */
 704		if(value == null || value.length() == 0)
 705		{
 706			String prop = (String)defaultProps.get(name);
 707			if(prop == null || prop.length() == 0)
 708				props.remove(name);
 709			else
 710				props.put(name,"");
 711		}
 712		else
 713		{
 714			String prop = (String)defaultProps.get(name);
 715			if(value.equals(prop))
 716				props.remove(name);
 717			else
 718				props.put(name,value);
 719		}
 720	} //}}}
 721
 722	//{{{ setTemporaryProperty() method
 723	/**
 724	 * Sets a property to a new value. Properties set using this
 725	 * method are not saved to the user properties list.
 726	 * @param name The property
 727	 * @param value The new value
 728	 * @since jEdit 2.3final
 729	 */
 730	public static final void setTemporaryProperty(String name, String value)
 731	{
 732		props.remove(name);
 733		defaultProps.put(name,value);
 734	} //}}}
 735
 736	//{{{ setBooleanProperty() method
 737	/**
 738	 * Sets a boolean property.
 739	 * @param name The property
 740	 * @param value The value
 741	 */
 742	public static final void setBooleanProperty(String name, boolean value)
 743	{
 744		setProperty(name,value ? "true" : "false");
 745	} //}}}
 746
 747	//{{{ setIntegerProperty() method
 748	/**
 749	 * Sets the value of an integer property.
 750	 * @param name The property
 751	 * @param value The value
 752	 * @since jEdit 4.0pre1
 753	 */
 754	public static final void setIntegerProperty(String name, int value)
 755	{
 756		setProperty(name,String.valueOf(value));
 757	} //}}}
 758
 759	//{{{ setFontProperty() method
 760	/**
 761	 * Sets the value of a font property. The family is stored
 762	 * in the <code><i>name</i></code> property, the font size is stored
 763	 * in the <code><i>name</i>size</code> property, and the font style is
 764	 * stored in <code><i>name</i>style</code>. For example, if
 765	 * <code><i>name</i></code> is <code>view.gutter.font</code>, the
 766	 * properties will be named <code>view.gutter.font</code>,
 767	 * <code>view.gutter.fontsize</code>, and
 768	 * <code>view.gutter.fontstyle</code>.
 769	 *
 770	 * @param name The property
 771	 * @param value The value
 772	 * @since jEdit 4.0pre1
 773	 */
 774	public static final void setFontProperty(String name, Font value)
 775	{
 776		setProperty(name,value.getFamily());
 777		setIntegerProperty(name + "size",value.getSize());
 778		setIntegerProperty(name + "style",value.getStyle());
 779	} //}}}
 780
 781	//{{{ unsetProperty() method
 782	/**
 783	 * Unsets (clears) a property.
 784	 * @param name The property
 785	 */
 786	public static final void unsetProperty(String name)
 787	{
 788		if(defaultProps.get(name) != null)
 789			props.put(name,"");
 790		else
 791			props.remove(name);
 792	} //}}}
 793
 794	//{{{ resetProperty() method
 795	/**
 796	 * Resets a property to its default value.
 797	 * @param name The property
 798	 *
 799	 * @since jEdit 2.5pre3
 800	 */
 801	public static final void resetProperty(String name)
 802	{
 803		props.remove(name);
 804	} //}}}
 805
 806	//{{{ propertiesChanged() method
 807	/**
 808	 * Reloads various settings from the properties.
 809	 */
 810	public static void propertiesChanged()
 811	{
 812		initKeyBindings();
 813
 814		Autosave.setInterval(getIntegerProperty("autosave",30));
 815
 816		saveCaret = getBooleanProperty("saveCaret");
 817
 818		//theme = new JEditMetalTheme();
 819		//theme.propertiesChanged();
 820		//MetalLookAndFeel.setCurrentTheme(theme);
 821
 822		UIDefaults defaults = UIManager.getDefaults();
 823
 824		// give all Swing components our colors
 825		if(jEdit.getBooleanProperty("textColors"))
 826		{
 827			Color background = new javax.swing.plaf.ColorUIResource(
 828				jEdit.getColorProperty("view.bgColor"));
 829			Color foreground = new javax.swing.plaf.ColorUIResource(
 830				jEdit.getColorProperty("view.fgColor"));
 831			Color caretColor = new javax.swing.plaf.ColorUIResource(
 832				jEdit.getColorProperty("view.caretColor"));
 833			Color selectionColor = new javax.swing.plaf.ColorUIResource(
 834				jEdit.getColorProperty("view.selectionColor"));
 835
 836			String[] prefixes = { "TextField", "TextArea", "List", "Table" };
 837			for(int i = 0; i < prefixes.length; i++)
 838			{
 839				String prefix = prefixes[i];
 840				defaults.put(prefix + ".disabledBackground",background);
 841				defaults.put(prefix + ".background",background);
 842				defaults.put(prefix + ".disabledForeground",foreground);
 843				defaults.put(prefix + ".foreground",foreground);
 844				defaults.put(prefix + ".caretForeground",caretColor);
 845				defaults.put(prefix + ".selectionForeground",foreground);
 846				defaults.put(prefix + ".selectionBackground",selectionColor);
 847				//defaults.put(prefix + ".inactiveForeground",foreground);
 848			}
 849
 850			defaults.put("Tree.background",background);
 851			defaults.put("Tree.foreground",foreground);
 852			defaults.put("Tree.textBackground",background);
 853			defaults.put("Tree.textForeground",foreground);
 854			defaults.put("Tree.selectionForeground",foreground);
 855			defaults.put("Tree.selectionBackground",selectionColor);
 856		}
 857
 858		// give all text areas the same font
 859		Font font = getFontProperty("view.font");
 860
 861		//defaults.put("TextField.font",font);
 862		defaults.put("TextArea.font",font);
 863		defaults.put("TextPane.font",font);
 864
 865		initProxy();
 866
 867		EditBus.send(new PropertiesChanged(null));
 868	} //}}}
 869
 870	//}}}
 871
 872	//{{{ Plugin management methods
 873
 874	//{{{ getNotLoadedPluginJARs() method
 875	/**
 876	 * Returns a list of plugin JARs that are not currently loaded
 877	 * by examining the user and system plugin directories.
 878	 * @since jEdit 3.2pre1
 879	 */
 880	public static String[] getNotLoadedPluginJARs()
 881	{
 882		Vector returnValue = new Vector();
 883
 884		if(jEditHome != null)
 885		{
 886			String systemPluginDir = MiscUtilities
 887				.constructPath(jEditHome,"jars");
 888
 889			String[] list = new File(systemPluginDir).list();
 890			if(list != null)
 891				getNotLoadedPluginJARs(returnValue,systemPluginDir,list);
 892		}
 893
 894		if(settingsDirectory != null)
 895		{
 896			String userPluginDir = MiscUtilities
 897				.constructPath(settingsDirectory,"jars");
 898			String[] list = new File(userPluginDir).list();
 899			if(list != null)
 900			{
 901				getNotLoadedPluginJARs(returnValue,
 902					userPluginDir,list);
 903			}
 904		}
 905
 906		String[] _returnValue = new String[returnValue.size()];
 907		returnValue.copyInto(_returnValue);
 908		return _returnValue;
 909	} //}}}
 910
 911	//{{{ getPlugin() method
 912	/**
 913	 * Returns the plugin with the specified class name.
 914	 */
 915	public static EditPlugin getPlugin(String name)
 916	{
 917		EditPlugin[] plugins = getPlugins();
 918		for(int i = 0; i < plugins.length; i++)
 919		{
 920			if(plugins[i].getClassName().equals(name))
 921				return plugins[i];
 922		}
 923
 924		return null;
 925	} //}}}
 926
 927	//{{{ getPlugins() method
 928	/**
 929	 * Returns an array of installed plugins.
 930	 */
 931	public static EditPlugin[] getPlugins()
 932	{
 933		Vector vector = new Vector();
 934		for(int i = 0; i < jars.size(); i++)
 935		{
 936			((EditPlugin.JAR)jars.elementAt(i)).getPlugins(vector);
 937		}
 938
 939		EditPlugin[] array = new EditPlugin[vector.size()];
 940		vector.copyInto(array);
 941		return array;
 942	} //}}}
 943
 944	//{{{ getPluginJARs() method
 945	/**
 946	 * Returns an array of installed plugins.
 947	 * @since jEdit 2.5pre3
 948	 */
 949	public static EditPlugin.JAR[] getPluginJARs()
 950	{
 951		EditPlugin.JAR[] array = new EditPlugin.JAR[jars.size()];
 952		jars.copyInto(array);
 953		return array;
 954	} //}}}
 955
 956	//{{{ getPluginJAR() method
 957	/**
 958	 * Returns the JAR with the specified path name.
 959	 * @param path The path name
 960	 * @since jEdit 2.6pre1
 961	 */
 962	public static EditPlugin.JAR getPluginJAR(String path)
 963	{
 964		for(int i = 0; i < jars.size(); i++)
 965		{
 966			EditPlugin.JAR jar = (EditPlugin.JAR)jars.elementAt(i);
 967			if(jar.getPath().equals(path))
 968				return jar;
 969		}
 970
 971		return null;
 972	} //}}}
 973
 974	//{{{ addPluginJAR() method
 975	/**
 976	 * Adds a plugin JAR to the editor.
 977	 * @param plugin The plugin
 978	 * @since jEdit 3.2pre10
 979	 */
 980	public static void addPluginJAR(EditPlugin.JAR plugin)
 981	{
 982		addActionSet(plugin.getActions());
 983		jars.addElement(plugin);
 984	} //}}}
 985
 986	//}}}
 987
 988	//{{{ Action methods
 989
 990	//{{{ addActionSet() method
 991	/**
 992	 * Adds a new action set to jEdit's list. Plugins probably won't
 993	 * need to call this method.
 994	 * @since jEdit 4.0pre1
 995	 */
 996	public static void addActionSet(ActionSet actionSet)
 997	{
 998		actionSets.addElement(actionSet);
 999	} //}}}
1000
1001	//{{{ getActionSets() method
1002	/**
1003	 * Returns all registered action sets.
1004	 * @since jEdit 4.0pre1
1005	 */
1006	public static ActionSet[] getActionSets()
1007	{
1008		ActionSet[] retVal = new ActionSet[actionSets.size()];
1009		actionSets.copyInto(retVal);
1010		return retVal;
1011	} //}}}
1012
1013	//{{{ getAction() method
1014	/**
1015	 * Returns the specified action.
1016	 * @param name The action name
1017	 */
1018	public static EditAction getAction(String name)
1019	{
1020		for(int i = 0; i < actionSets.size(); i++)
1021		{
1022			EditAction action = ((ActionSet)actionSets.elementAt(i))
1023				.getAction(name);
1024			if(action != null)
1025				return action;
1026		}
1027
1028		return null;
1029	} //}}}
1030
1031	//{{{ getActionSetForAction() method
1032	/**
1033	 * Returns the action set that contains the specified action.
1034	 * @param action The action
1035	 * @since jEdit 4.0pre1
1036	 */
1037	public static ActionSet getActionSetForAction(EditAction action)
1038	{
1039		for(int i = 0; i < actionSets.size(); i++)
1040		{
1041			ActionSet set = (ActionSet)actionSets.elementAt(i);
1042			if(set.contains(action))
1043				return set;
1044		}
1045
1046		return null;
1047	} //}}}
1048
1049	//{{{ getActions() method
1050	/**
1051	 * Returns the list of actions registered with the editor.
1052	 */
1053	public static EditAction[] getActions()
1054	{
1055		Vector vec = new Vector();
1056		for(int i = 0; i < actionSets.size(); i++)
1057			((ActionSet)actionSets.elementAt(i)).getActions(vec);
1058
1059		EditAction[] retVal = new EditAction[vec.size()];
1060		vec.copyInto(retVal);
1061		return retVal;
1062	} //}}}
1063
1064	//}}}
1065
1066	//{{{ Edit mode methods
1067
1068	//{{{ reloadModes() method
1069	/**
1070	 * Reloads all edit modes.
1071	 * @since jEdit 3.2pre2
1072	 */
1073	public static void reloadModes()
1074	{
1075		/* Try to guess the eventual size to avoid unnecessary
1076		 * copying */
1077		modes = new Vector(50);
1078
1079		//{{{ Load the global catalog
1080		if(jEditHome == null)
1081			loadModeCatalog("/modes/catalog",true);
1082		else
1083		{
1084			loadModeCatalog(MiscUtilities.constructPath(jEditHome,
1085				"modes","catalog"),false);
1086		} //}}}
1087
1088		//{{{ Load user catalog
1089		if(settingsDirectory != null)
1090		{
1091			File userModeDir = new File(MiscUtilities.constructPath(
1092				settingsDirectory,"modes"));
1093			if(!userModeDir.exists())
1094				userModeDir.mkdirs();
1095
1096			File userCatalog = new File(MiscUtilities.constructPath(
1097				settingsDirectory,"modes","catalog"));
1098			if(!userCatalog.exists())
1099			{
1100				// create dummy catalog
1101				try
1102				{
1103					FileWriter out = new FileWriter(userCatalog);
1104					out.write(jEdit.getProperty("defaultCatalog"));
1105					out.close();
1106				}
1107				catch(IOException io)
1108				{
1109					Log.log(Log.ERROR,jEdit.class,io);
1110				}
1111			}
1112
1113			loadModeCatalog(userCatalog.getPath(),false);
1114		} //}}}
1115
1116		Buffer buffer = buffersFirst;
1117		while(buffer != null)
1118		{
1119			// This reloads the token marker and sends a message
1120			// which causes edit panes to repaint their text areas
1121			buffer.setMode();
1122
1123			buffer = buffer.next;
1124		}
1125	} //}}}
1126
1127	//{{{ getMode() method
1128	/**
1129	 * Returns the edit mode with the specified name.
1130	 * @param name The edit mode
1131	 */
1132	public static Mode getMode(String name)
1133	{
1134		for(int i = 0; i < modes.size(); i++)
1135		{
1136			Mode mode = (Mode)modes.elementAt(i);
1137			if(mode.getName().equals(name))
1138				return mode;
1139		}
1140		return null;
1141	} //}}}
1142
1143	//{{{ getModes() method
1144	/**
1145	 * Returns an array of installed edit modes.
1146	 */
1147	public static Mode[] getModes()
1148	{
1149		Mode[] array = new Mode[modes.size()];
1150		modes.copyInto(array);
1151		return array;
1152	} //}}}
1153
1154	//}}}
1155
1156	//{{{ Buffer creation methods
1157
1158	//{{{ showOpenFileDialog() method
1159	/**
1160	 * Displays the open file dialog box, and opens any selected files.
1161	 *
1162	 * @param view The view
1163	 * @since jEdit 2.7pre2
1164	 */
1165	public static void showOpenFileDialog(View view)
1166	{
1167		showOpenFileDialog(view,null);
1168	} //}}}
1169
1170	//{{{ showOpenFileWithOtherEncodingDialog() method
1171	/**
1172	 * Displays the open file dialog box, and opens any selected files,
1173	 * but first prompts for a character encoding to use.
1174	 *
1175	 * @param view The view
1176	 * @since jEdit 2.7pre2
1177	 */
1178	public static void showOpenFileWithOtherEncodingDialog(View view)
1179	{
1180		String encoding = GUIUtilities.input(view,"encoding-prompt",null,
1181			jEdit.getProperty("buffer.encoding",
1182			System.getProperty("file.encoding")));
1183		if(encoding == null)
1184			return;
1185
1186		Macros.Recorder recorder = view.getMacroRecorder();
1187		if(recorder != null)
1188		{
1189			recorder.record("props = new Hashtable();");
1190			recorder.record("props.put(\"encoding\",\"" + encoding + "\");");
1191			recorder.record("jEdit.showOpenFileDialog(view,props);");
1192		}
1193
1194		Hashtable props = new Hashtable();
1195		props.put(Buffer.ENCODING,encoding);
1196		showOpenFileDialog(view,props);
1197	} //}}}
1198
1199	//{{{ showOpenFileDialog() method
1200	/**
1201	 * Displays the open file dialog box, and opens any selected files,
1202	 * setting the properties specified in the hash table in the buffers.
1203	 *
1204	 * @param view The view
1205	 * @param props The properties to set in the buffer
1206	 * @since jEdit 3.2pre2
1207	 */
1208	public static void showOpenFileDialog(View view, Hashtable props)
1209	{
1210		String[] files = GUIUtilities.showVFSFileDialog(view,null,
1211			VFSBrowser.OPEN_DIALOG,true);
1212
1213		Buffer buffer = null;
1214		if(files != null)
1215		{
1216			for(int i = 0; i < files.length; i++)
1217			{
1218				Buffer newBuffer = openFile(null,null,files[i],
1219					false,props);
1220				if(newBuffer != null)
1221					buffer = newBuffer;
1222			}
1223		}
1224
1225		if(buffer != null)
1226			view.setBuffer(buffer);
1227	} //}}}
1228
1229	//{{{ restoreOpenFiles() method
1230	/**
1231	 * Opens files that were open last time.
1232	 * @since jEdit 3.2pre2
1233	 */
1234	public static String restoreOpenFiles()
1235	{
1236		if(settingsDirectory == null)
1237			return null;
1238
1239		File session = new File(MiscUtilities.constructPath(
1240			settingsDirectory,"session"));
1241
1242		if(!session.exists())
1243			return null;
1244
1245		String splitConfig = null;
1246
1247		try
1248		{
1249			BufferedReader in = new BufferedReader(new FileReader(
1250				session));
1251
1252			String line;
1253			while((line = in.readLine()) != null)
1254			{
1255				if(line.startsWith("splits\t"))
1256					splitConfig = line.substring(7);
1257				else
1258					openFile(null,line);
1259			}
1260
1261			in.close();
1262		}
1263		catch(IOException io)
1264		{
1265			Log.log(Log.ERROR,jEdit.class,"Error while loading " + session);
1266			Log.log(Log.ERROR,jEdit.class,io);
1267		}
1268
1269		return splitConfig;
1270	} //}}}
1271
1272	//{{{ saveOpenFiles() method
1273	/**
1274	 * Saves the list of open files.
1275	 * @since jEdit 3.1pre5
1276	 */
1277	public static void saveOpenFiles(View view)
1278	{
1279		if(settingsDirectory == null)
1280			return;
1281
1282		view.getEditPane().saveCaretInfo();
1283		Buffer current = view.getBuffer();
1284
1285		File session = new File(MiscUtilities.constructPath(
1286			settingsDirectory,"session"));
1287
1288		// maybe not, since it's autosaved now
1289		//backupSettingsFile(session);
1290
1291		try
1292		{
1293			String lineSep = System.getProperty("line.separator");
1294
1295			BufferedWriter out = new BufferedWriter(new FileWriter(
1296				session));
1297			Buffer buffer = buffersFirst;
1298			while(buffer != null)
1299			{
1300				if(!buffer.isUntitled())
1301				{
1302					out.write(buffer.getPath());
1303					out.write(lineSep);
1304				}
1305
1306				buffer = buffer.next;
1307			}
1308
1309			out.write("splits\t");
1310			out.write(view.getSplitConfig());
1311			out.write(lineSep);
1312
1313			out.close();
1314		}
1315		catch(IOException io)
1316		{
1317			Log.log(Log.ERROR,jEdit.class,"Error while saving " + session);
1318			Log.log(Log.ERROR,jEdit.class,io);
1319		}
1320	} //}}}
1321
1322	//{{{ openFiles() method
1323	/**
1324	 * Opens the file names specified in the argument array. This
1325	 * handles +line and +marker arguments just like the command
1326	 * line parser.
1327	 * @param parent The parent directory
1328	 * @param args The file names to open
1329	 * @since jEdit 3.2pre4
1330	 */
1331	public static Buffer openFiles(View view, String parent, String[] args)
1332	{
1333		Buffer retVal = null;
1334		Buffer lastBuffer = null;
1335
1336		for(int i = 0; i < args.length; i++)
1337		{
1338			String arg = args[i];
1339			if(arg == null)
1340				continue;
1341			else if(arg.startsWith("+line:") || arg.startsWith("+marker:"))
1342			{
1343				if(lastBuffer != null)
1344					gotoMarker(view,lastBuffer,arg);
1345				continue;
1346			}
1347
1348			lastBuffer = openFile(null,parent,arg,false,null);
1349
1350			if(retVal == null && lastBuffer != null)
1351				retVal = lastBuffer;
1352		}
1353
1354		if(view != null && retVal != null)
1355			view.setBuffer(retVal);
1356
1357		return retVal;
1358	} //}}}
1359
1360	//{{{ openFile() method
1361	/**
1362	 * Opens a file. Note that as of jEdit 2.5pre1, this may return
1363	 * null if the buffer could not be opened.
1364	 * @param view The view to open the file in
1365	 * @param path The file path
1366	 *
1367	 * @since jEdit 2.4pre1
1368	 */
1369	public static Buffer openFile(View view, String path)
1370	{
1371		return openFile(view,null,path,false,new Hashtable());
1372	} //}}}
1373
1374	//{{{ openFile() method
1375	/**
1376	 * @deprecated The openFile() forms with the readOnly parameter
1377	 * should not be used. The readOnly prameter is no longer supported.
1378	 */
1379	public static Buffer openFile(View view, String parent,
1380		String path, boolean readOnly, boolean newFile)
1381	{
1382		return openFile(view,parent,path,newFile,new Hashtable());
1383	} //}}}
1384
1385	//{{{ openFile() method
1386	/**
1387	 * @deprecated The openFile() forms with the readOnly parameter
1388	 * should not be used. The readOnly prameter is no longer supported.
1389	 */
1390	public static Buffer openFile(View view, String parent,
1391		String path, boolean readOnly, boolean newFile,
1392		Hashtable props)
1393	{
1394		return openFile(view,parent,path,newFile,props);
1395	} //}}}
1396
1397	//{{{ openFile() method
1398	/**
1399	 * Opens a file. This may return null if the buffer could not be
1400	 * opened for some reason.
1401	 * @param view The view to open the file in
1402	 * @param parent The parent directory of the file
1403	 * @param path The path name of the file
1404	 * @param newFile True if the file should not be loaded from disk
1405	 * be prompted if it should be reloaded
1406	 * @param props Buffer-local properties to set in the buffer
1407	 *
1408	 * @since jEdit 3.2pre10
1409	 */
1410	public static Buffer openFile(View view, String parent,
1411		String path, boolean newFile, Hashtable props)
1412	{
1413		if(view != null && parent == null)
1414			parent = MiscUtilities.getParentOfPath(view.getBuffer().getPath());
1415
1416		if(MiscUtilities.isURL(path))
1417		{
1418			if(MiscUtilities.getProtocolOfURL(path).equals("file"))
1419				path = path.substring(5);
1420		}
1421
1422		path = MiscUtilities.constructPath(parent,path);
1423
1424		if(!MiscUtilities.isURL(path))
1425			path = MiscUtilities.canonPath(path);
1426
1427		synchronized(bufferListLock)
1428		{
1429			Buffer buffer = getBuffer(path);
1430			if(buffer != null)
1431			{
1432				if(view != null)
1433					view.setBuffer(buffer);
1434
1435				return buffer;
1436			}
1437
1438			if(props == null)
1439				props = new Hashtable();
1440
1441			BufferHistory.Entry entry = BufferHistory.getEntry(path);
1442
1443			if(entry != null && saveCaret && props.get(Buffer.CARET) == null)
1444			{
1445				int caret = entry.caret;
1446				props.put(Buffer.CARET,new Integer(entry.caret));
1447				if(entry.selection != null)
1448				{
1449					// getSelection() converts from string to
1450					// Selection[]
1451					props.put(Buffer.SELECTION,entry.getSelection());
1452				}
1453			}
1454
1455			if(entry != null && props.get(Buffer.ENCODING) == null)
1456			{
1457				if(entry.encoding != null)
1458					props.put(Buffer.ENCODING,entry.encoding);
1459			}
1460
1461			Buffer newBuffer = new Buffer(view,path,newFile,false,props);
1462
1463			if(!newBuffer.load(view,false))
1464				return null;
1465
1466			addBufferToList(newBuffer);
1467
1468			EditBus.send(new BufferUpdate(newBuffer,view,BufferUpdate.CREATED));
1469
1470			if(view != null)
1471				view.setBuffer(newBuffer);
1472
1473			return newBuffer;
1474		}
1475	} //}}}
1476
1477	//{{{ openTemporary() method
1478	/**
1479	 * Opens a temporary buffer. A temporary buffer is like a normal
1480	 * buffer, except that an event is not fired, the the buffer is
1481	 * not added to the buffers list.
1482	 *
1483	 * @param view The view to open the file in
1484	 * @param parent The parent directory of the file
1485	 * @param path The path name of the file
1486	 * @param readOnly True if the file should be read only
1487	 * @param newFile True if the file should not be loaded from disk
1488	 *
1489	 * @since jEdit 3.2pre10
1490	 */
1491	public static Buffer openTemporary(View view, String parent,
1492		String path, boolean newFile)
1493	{
1494		if(view != null && parent == null)
1495			parent = MiscUtilities.getParentOfPath(view.getBuffer().getPath());
1496
1497		if(MiscUtilities.isURL(path))
1498		{
1499			if(MiscUtilities.getProtocolOfURL(path).equals("file"))
1500				path = path.substring(5);
1501		}
1502
1503		path = MiscUtilities.constructPath(parent,path);
1504
1505		synchronized(bufferListLock)
1506		{
1507			Buffer buffer = getBuffer(path);
1508			if(buffer != null)
1509				return buffer;
1510
1511			buffer = new Buffer(null,path,newFile,true,new Hashtable());
1512			if(!buffer.load(view,false))
1513				return null;
1514			else
1515				return buffer;
1516		}
1517	} //}}}
1518
1519	//{{{ commitTemporary() method
1520	/**
1521	 * Adds a temporary buffer to the buffer list. This must be done
1522	 * before allowing the user to interact with the buffer in any
1523	 * way.
1524	 * @param buffer The buffer
1525	 */
1526	public static void commitTemporary(Buffer buffer)
1527	{
1528		if(!buffer.isTemporary())
1529			return;
1530
1531		addBufferToList(buffer);
1532		buffer.commitTemporary();
1533
1534		EditBus.send(new BufferUpdate(buffer,null,BufferUpdate.CREATED));
1535	} //}}}
1536
1537	//{{{ newFile() method
1538	/**
1539	 * Creates a new `untitled' file.
1540	 * @param view The view to create the file in
1541	 */
1542	public static Buffer newFile(View view)
1543	{
1544		return newFile(view,null);
1545	} //}}}
1546
1547	//{{{ newFile() method
1548	/**
1549	 * Creates a new `untitled' file.
1550	 * @param view The view to create the file in
1551	 * @param dir The directory to create the file in
1552	 * @since jEdit 3.1pre2
1553	 */
1554	public static Buffer newFile(View view, String dir)
1555	{
1556		// If only one new file is open which is clean, just close
1557		// it, which will create an 'Untitled-1'
1558		if(dir != null
1559			&& buffersFirst != null
1560			&& buffersFirst == buffersLast
1561			&& buffersFirst.isUntitled()
1562			&& !buffersFirst.isDirty())
1563		{
1564			closeBuffer(view,buffersFirst);
1565			// return the newly created 'untitled-1'
1566			return buffersFirst;
1567		}
1568
1569		// Find the highest Untitled-n file
1570		int untitledCount = 0;
1571		Buffer buffer = buffersFirst;
1572		while(buffer != null)
1573		{
1574			if(buffer.getName().startsWith("Untitled-"))
1575			{
1576				try
1577				{
1578					untitledCount = Math.max(untitledCount,
1579						Integer.parseInt(buffer.getName()
1580						.substring(9)));
1581				}
1582				catch(NumberFormatException nf)
1583				{
1584				}
1585			}
1586			buffer = buffer.next;
1587		}
1588
1589		return openFile(view,dir,"Untitled-" + (untitledCount+1),true,null);
1590	} //}}}
1591
1592	//}}}
1593
1594	//{{{ Buffer management methods
1595
1596	//{{{ closeBuffer() method
1597	/**
1598	 * Closes a buffer. If there are unsaved changes, the user is
1599	 * prompted if they should be saved first.
1600	 * @param view The view
1601	 * @param buffer The buffer
1602	 * @return True if the buffer was really closed, false otherwise
1603	 */
1604	public static boolean closeBuffer(View view, Buffer buffer)
1605	{
1606		// Wait for pending I/O requests
1607		if(buffer.isPerformingIO())
1608		{
1609			VFSManager.waitForRequests();
1610			if(VFSManager.errorOccurred())
1611				return false;
1612		}
1613
1614		if(buffer.isDirty())
1615		{
1616			Object[] args = { buffer.getName() };
1617			int result = GUIUtilities.confirm(view,"notsaved",args,
1618				JOptionPane.YES_NO_CANCEL_OPTION,
1619				JOptionPane.WARNING_MESSAGE);
1620			if(result == JOptionPane.YES_OPTION)
1621			{
1622				if(!buffer.save(view,null,true))
1623					return false;
1624			}
1625			else if(result != JOptionPane.NO_OPTION)
1626				return false;
1627		}
1628
1629		_closeBuffer(view,buffer);
1630
1631		return true;
1632	} //}}}
1633
1634	//{{{ _closeBuffer() method
1635	/**
1636	 * Closes the buffer, even if it has unsaved changes.
1637	 * @param view The view
1638	 * @param buffer The buffer
1639	 *
1640	 * @since jEdit 2.2pre1
1641	 */
1642	public static void _closeBuffer(View view, Buffer buffer)
1643	{
1644		if(buffer.isClosed())
1645		{
1646			// can happen if the user presses C+w twice real
1647			// quick and the buffer has unsaved changes
1648			return;
1649		}
1650
1651		if(!buffer.isNewFile())
1652		{
1653			view.getEditPane().saveCaretInfo();
1654			Integer _caret = (Integer)buffer.getProperty(Buffer.CARET);
1655			int caret = (_caret == null ? 0 : _caret.intValue());
1656
1657			BufferHistory.setEntry(buffer.getPath(),caret,
1658				(Selection[])buffer.getProperty(Buffer.SELECTION),
1659				(String)buffer.getProperty(Buffer.ENCODING));
1660		}
1661
1662		removeBufferFromList(buffer);
1663		buffer.close();
1664
1665		EditBus.send(new BufferUpdate(buffer,view,BufferUpdate.CLOSED));
1666
1667		// Create a new file when the last is closed
1668		if(buffersFirst == null && buffersLast == null)
1669			newFile(view);
1670	} //}}}
1671
1672	//{{{ closeAllBuffers() method
1673	/**
1674	 * Closes all open buffers.
1675	 * @param view The view
1676	 */
1677	public static boolean closeAllBuffers(View view)
1678	{
1679		return closeAllBuffers(view,false);
1680	} //}}}
1681
1682	//{{{ closeAllBuffers() method
1683	/**
1684	 * Closes all open buffers.
1685	 * @param view The view
1686	 * @param isExiting This must be false unless this method is
1687	 * being called by the exit() method
1688	 */
1689	public static boolean closeAllBuffers(View view, boolean isExiting)
1690	{
1691		boolean dirty = false;
1692
1693		Buffer buffer = buffersFirst;
1694		while(buffer != null)
1695		{
1696			if(buffer.isDirty())
1697			{
1698				dirty = true;
1699				break;
1700			}
1701			buffer = buffer.next;
1702		}
1703
1704		if(dirty)
1705		{
1706			boolean ok = new CloseDialog(view).isOK();
1707			if(!ok)
1708				return false;
1709		}
1710
1711		// Wait for pending I/O requests
1712		VFSManager.waitForRequests();
1713		if(VFSManager.errorOccurred())
1714			return false;
1715
1716		// close remaining buffers (the close dialog only deals with
1717		// dirty ones)
1718
1719		buffer = buffersFirst;
1720
1721		// zero it here so that BufferTabs doesn't have any problems
1722		buffersFirst = buffersLast = null;
1723		bufferCount = 0;
1724
1725		while(buffer != null)
1726		{
1727			if(!buffer.isNewFile())
1728			{
1729				Integer _caret = (Integer)buffer.getProperty(Buffer.CARET);
1730				int caret = (_caret == null ? 0 : _caret.intValue());
1731				BufferHistory.setEntry(buffer.getPath(),caret,
1732					(Selection[])buffer.getProperty(Buffer.SELECTION),
1733					(String)buffer.getProperty(Buffer.ENCODING));
1734			}
1735
1736			buffer.close();
1737			if(!isExiting)
1738			{
1739				EditBus.send(new BufferUpdate(buffer,view,
1740					BufferUpdate.CLOSED));
1741			}
1742			buffer = buffer.next;
1743		}
1744
1745		if(!isExiting)
1746			newFile(view);
1747
1748		return true;
1749	} //}}}
1750
1751	//{{{ saveAllBuffers() method
1752	/**
1753	 * Saves all open buffers.
1754	 * @param view The view
1755	 * @param confirm If true, a confirmation dialog will be shown first
1756	 * @since jEdit 2.7pre2
1757	 */
1758	public static void saveAllBuffers(View view, boolean confirm)
1759	{
1760		if(confirm)
1761		{
1762			int result = GUIUtilities.confirm(view,"saveall",null,
1763				JOptionPane.YES_NO_OPTION,
1764				JOptionPane.QUESTION_MESSAGE);
1765			if(result != JOptionPane.YES_OPTION)
1766				return;
1767		}
1768
1769		Buffer current = view.getBuffer();
1770
1771		Buffer buffer = buffersFirst;
1772		while(buffer != null)
1773		{
1774			if(buffer.isDirty())
1775			{
1776				if(buffer.isNewFile())
1777					view.setBuffer(buffer);
1778				buffer.save(view,null,true);
1779			}
1780
1781			buffer = buffer.next;
1782		}
1783
1784		view.setBuffer(current);
1785	} //}}}
1786
1787	//{{{ reloadAllBuffers() method
1788	/**
1789	 * Reloads all open buffers.
1790	 * @param view The view
1791	 * @param confirm If true, a confirmation dialog will be shown first
1792	 * @since jEdit 2.7pre2
1793	 */
1794	public static void reloadAllBuffers(final View view, boolean confirm)
1795	{
1796		if(confirm)
1797		{
1798			int result = GUIUtilities.confirm(view,"reload-all",null,
1799				JOptionPane.YES_NO_OPTION,
1800				JOptionPane.QUESTION_MESSAGE);
1801			if(result != JOptionPane.YES_OPTION)
1802				return;
1803		}
1804
1805		// save caret info. Buffer.load() will load it.
1806		View _view = viewsFirst;
1807		while(_view != null)
1808		{
1809			EditPane[] panes = _view.getEditPanes();
1810			for(int i = 0; i < panes.length; i++)
1811			{
1812				panes[i].saveCaretInfo();
1813			}
1814
1815			_view = _view.next;
1816		}
1817
1818		Buffer[] buffers = jEdit.getBuffers();
1819		for(int i = 0; i < buffers.length; i++)
1820		{
1821			Buffer buffer = buffers[i];
1822			buffer.load(view,true);
1823		}
1824	} //}}}
1825
1826	//{{{ getBuffer() method
1827	/**
1828	 * Returns the buffer with the specified path name. The path name
1829	 * must be an absolute, canonical, path.
1830	 * @param path The path name
1831	 * @see MiscUtilities#constructPath(String,String)
1832	 */
1833	public static Buffer getBuffer(String path)
1834	{
1835		boolean caseInsensitiveFilesystem = (File.separatorChar == '\\'
1836			|| File.separatorChar == ':' /* Windows or MacOS */);
1837
1838		synchronized(bufferListLock)
1839		{
1840			Buffer buffer = buffersFirst;
1841			while(buffer != null)
1842			{
1843				String _path = buffer.getPath();
1844				if(caseInsensitiveFilesystem)
1845				{
1846					if(_path.equalsIgnoreCase(path))
1847						return buffer;
1848				}
1849				else
1850				{
1851					if(_path.equals(path))
1852						return buffer;
1853				}
1854				buffer = buffer.next;
1855			}
1856		}
1857
1858		return null;
1859	} //}}}
1860
1861	//{{{ getBuffers() method
1862	/**
1863	 * Returns an array of open buffers.
1864	 */
1865	public static Buffer[] getBuffers()
1866	{
1867		Buffer[] buffers = new Buffer[bufferCount];
1868		Buffer buffer = buffersFirst;
1869		for(int i = 0; i < bufferCount; i++)
1870		{
1871			buffers[i] = buffer;
1872			buffer = buffer.next;
1873		}
1874		return buffers;
1875	} //}}}
1876
1877	//{{{ getBufferCount() method
1878	/**
1879	 * Returns the number of open buffers.
1880	 */
1881	public static int getBufferCount()
1882	{
1883		return bufferCount;
1884	} //}}}
1885
1886	//{{{ getFirstBuffer() method
1887	/**
1888	 * Returns the first buffer.
1889	 */
1890	public static Buffer getFirstBuffer()
1891	{
1892		return buffersFirst;
1893	} //}}}
1894
1895	//{{{ getLastBuffer() method
1896	/**
1897	 * Returns the last buffer.
1898	 */
1899	public static Buffer getLastBuffer()
1900	{
1901		return buffersLast;
1902	} //}}}
1903
1904	//}}}
1905
1906	//{{{ View methods
1907
1908	//{{{ getInputHandler() method
1909	/**
1910	 * Returns the current input handler (key binding to action mapping)
1911	 * @see org.gjt.sp.jedit.gui.InputHandler
1912	 */
1913	public static InputHandler getInputHandler()
1914	{
1915		return inputHandler;
1916	} //}}}
1917
1918	//{{{ newView() method
1919	/**
1920	 * Creates a new view of a buffer.
1921	 * @param view An existing view
1922	 * @param buffer The buffer
1923	 */
1924	public static View newView(View view, Buffer buffer)
1925	{
1926		if(view != null)
1927		{
1928			view.showWaitCursor();
1929			view.getEditPane().saveCaretInfo();
1930		}
1931
1932		View newView = new View(buffer,null);
1933
1934		// Do this crap here so that the view is created
1935		// and added to the list before it is shown
1936		// (for the sake of plugins that add stuff to views)
1937		newView.pack();
1938
1939		// newView.setSize(view.getSize()) creates incorrectly
1940		// sized views, for some reason...
1941		if(view != null)
1942		{
1943			GUIUtilities.saveGeometry(view,"view");
1944			view.hideWaitCursor();
1945		}
1946
1947		GUIUtilities.loadGeometry(newView,"view");
1948
1949		addViewToList(newView);
1950		EditBus.send(new ViewUpdate(newView,ViewUpdate.CREATED));
1951
1952		GUIUtilities.requestFocus(newView,newView.getTextArea());
1953		newView.show();
1954
1955		// show tip of the day
1956		if(newView == viewsFirst)
1957		{
1958			// Don't show the welcome message if jEdit was started
1959			// with the -nosettings switch
1960			if(settingsDirectory != null && getBooleanProperty("firstTime"))
1961				new HelpViewer();
1962			else if(jEdit.getBooleanProperty("tip.show"))
1963				new TipOfTheDay(newView);
1964
1965			setBooleanProperty("firstTime",false);
1966		}
1967
1968		return newView;
1969	} //}}}
1970
1971	//{{{ newView() method
1972	/**
1973	 * Creates a new view.
1974	 * @param view An existing view
1975	 * @since jEdit 3.2pre2
1976	 */
1977	public static View newView(View view)
1978	{
1979		return newView(view,view.getSplitConfig());
1980	} //}}}
1981
1982	//{{{ newView() method
1983	/**
1984	 * Creates a new view.
1985	 * @param view An existing view
1986	 * @param splitConfig The split configuration
1987	 * @since jEdit 3.2pre2
1988	 */
1989	public static View newView(View view, String splitConfig)
1990	{
1991		if(view != null)
1992		{
1993			view.showWaitCursor();
1994			view.getEditPane().saveCaretInfo();
1995		}
1996
1997		View newView = new View(null,splitConfig);
1998
1999		// Do this crap here so that the view is created
2000		// and added to the list before it is shown
2001		// (for the sake of plugins that add stuff to views)
2002		newView.pack();
2003
2004		// newView.setSize(view.getSize()) creates incorrectly
2005		// sized views, for some reason...
2006		if(view != null)
2007		{
2008			GUIUtilities.saveGeometry(view,"view");
2009			view.hideWaitCursor();
2010		}
2011
2012		GUIUtilities.loadGeometry(newView,"view");
2013
2014		addViewToList(newView);
2015		EditBus.send(new ViewUpdate(newView,ViewUpdate.CREATED));
2016
2017		GUIUtilities.requestFocus(newView,newView.getTextArea());
2018		newView.show();
2019
2020		// show tip of the day
2021		if(newView == viewsFirst)
2022		{
2023			// Don't show the welcome message if jEdit was started
2024			// with the -nosettings switch
2025			if(settingsDirectory != null && getBooleanProperty("firstTime"))
2026				new HelpViewer("jeditresource:/doc/welcome.html");
2027			else if(jEdit.getBooleanProperty("tip.show"))
2028				new TipOfTheDay(newView);
2029
2030			setBooleanProperty("firstTime",false);
2031		}
2032
2033		return newView;
2034	} //}}}
2035
2036	//{{{ closeView() method
2037	/**
2038	 * Closes a view. jEdit will exit if this was the last open view.
2039	 */
2040	public static void closeView(View view)
2041	{
2042		closeView(view,true);
2043	} //}}}
2044
2045	//{{{ getViews() method
2046	/**
2047	 * Returns an array of all open views.
2048	 */
2049	public static View[] getViews()
2050	{
2051		View[] views = new View[viewCount];
2052		View view = viewsFirst;
2053		for(int i = 0; i < viewCount; i++)
2054		{
2055			views[i] = view;
2056			view = view.next;
2057		}
2058		return views;
2059	} //}}}
2060
2061	//{{{ getViewCount() method
2062	/**
2063	 * Returns the number of open views.
2064	 */
2065	public static int getViewCount()
2066	{
2067		return viewCount;
2068	} //}}}
2069
2070	//{{{ getFirstView() method
2071	/**
2072	 * Returns the first view.
2073	 */
2074	public static View getFirstView()
2075	{
2076		return viewsFirst;
2077	} //}}}
2078
2079	//{{{ getLastView() method
2080	/**
2081	 * Returns the last view.
2082	 */
2083	public static View getLastView()
2084	{
2085		return viewsLast;
2086	} //}}}
2087
2088	//}}}
2089
2090	//{{{ Miscellaneous methods
2091
2092	//{{{ isBackgroundMode() method
2093	/**
2094	 * Returns true if jEdit was started with the <code>-background</code>
2095	 * command-line switch.
2096	

Large files files are truncated, but you can click here to view the full file