PageRenderTime 71ms CodeModel.GetById 20ms app.highlight 38ms RepoModel.GetById 0ms app.codeStats 0ms

/jEdit/tags/jedit-4-5-pre1/org/gjt/sp/jedit/jEdit.java

#
Java | 2602 lines | 1497 code | 276 blank | 829 comment | 316 complexity | 4f3bb46130d1da504100e24028380e55 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0

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

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