PageRenderTime 130ms CodeModel.GetById 43ms app.highlight 68ms RepoModel.GetById 1ms app.codeStats 1ms

/jEdit/tags/jedit-4-2-pre4/org/gjt/sp/jedit/jEdit.java

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

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