PageRenderTime 63ms CodeModel.GetById 3ms app.highlight 48ms RepoModel.GetById 1ms app.codeStats 0ms

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

#
Java | 2310 lines | 1581 code | 195 blank | 534 comment | 172 complexity | 00d5bed1be22ed29ebf8b54ae2f9a9af MD5 | raw file

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

   1/*
   2 * View.java - jEdit view
   3 * :tabSize=8:indentSize=8:noTabs=false:
   4 * :folding=explicit:collapseFolds=1:
   5 *
   6 * Copyright (C) 1998, 2004 Slava Pestov
   7 *
   8 * This program is free software; you can redistribute it and/or
   9 * modify it under the terms of the GNU General Public License
  10 * as published by the Free Software Foundation; either version 2
  11 * of the License, or any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21 */
  22
  23package org.gjt.sp.jedit;
  24
  25//{{{ Imports
  26import java.awt.*;
  27import java.awt.event.FocusAdapter;
  28import java.awt.event.FocusEvent;
  29import java.awt.event.KeyEvent;
  30import java.awt.event.KeyListener;
  31import java.awt.event.WindowAdapter;
  32import java.awt.event.WindowEvent;
  33import java.io.IOException;
  34import java.io.StreamTokenizer;
  35import java.io.StringReader;
  36import java.net.Socket;
  37import java.util.ArrayList;
  38import java.util.Arrays;
  39import java.util.HashSet;
  40import java.util.List;
  41import java.util.Set;
  42import java.util.Stack;
  43
  44import javax.swing.JComponent;
  45import javax.swing.JFrame;
  46import javax.swing.JMenu;
  47import javax.swing.JMenuBar;
  48import javax.swing.JMenuItem;
  49import javax.swing.JOptionPane;
  50import javax.swing.JPanel;
  51import javax.swing.JSplitPane;
  52import javax.swing.LayoutFocusTraversalPolicy;
  53import javax.swing.MenuSelectionManager;
  54import javax.swing.event.CaretEvent;
  55import javax.swing.event.CaretListener;
  56
  57import org.gjt.sp.jedit.EditBus.EBHandler;
  58import org.gjt.sp.jedit.bufferset.BufferSet;
  59import org.gjt.sp.jedit.bufferset.BufferSetManager;
  60import org.gjt.sp.jedit.gui.ActionBar;
  61import org.gjt.sp.jedit.gui.CloseDialog;
  62import org.gjt.sp.jedit.gui.DefaultInputHandler;
  63import org.gjt.sp.jedit.gui.DockableWindowFactory;
  64import org.gjt.sp.jedit.gui.DockableWindowManager;
  65import org.gjt.sp.jedit.gui.HistoryModel;
  66import org.gjt.sp.jedit.gui.DockingFrameworkProvider;
  67import org.gjt.sp.jedit.gui.InputHandler;
  68import org.gjt.sp.jedit.gui.StatusBar;
  69import org.gjt.sp.jedit.gui.ToolBarManager;
  70import org.gjt.sp.jedit.gui.VariableGridLayout;
  71import org.gjt.sp.jedit.gui.DockableWindowManager.DockingLayout;
  72import org.gjt.sp.jedit.input.InputHandlerProvider;
  73import org.gjt.sp.jedit.msg.BufferUpdate;
  74import org.gjt.sp.jedit.msg.EditPaneUpdate;
  75import org.gjt.sp.jedit.msg.PropertiesChanged;
  76import org.gjt.sp.jedit.msg.SearchSettingsChanged;
  77import org.gjt.sp.jedit.msg.ViewUpdate;
  78import org.gjt.sp.jedit.options.GeneralOptionPane;
  79import org.gjt.sp.jedit.search.CurrentBufferSet;
  80import org.gjt.sp.jedit.search.SearchAndReplace;
  81import org.gjt.sp.jedit.search.SearchBar;
  82import org.gjt.sp.jedit.textarea.JEditTextArea;
  83import org.gjt.sp.jedit.textarea.ScrollListener;
  84import org.gjt.sp.jedit.textarea.TextArea;
  85import org.gjt.sp.jedit.visitors.JEditVisitor;
  86import org.gjt.sp.jedit.visitors.JEditVisitorAdapter;
  87import org.gjt.sp.util.Log;
  88import org.gjt.sp.util.StandardUtilities;
  89//}}}
  90
  91/**
  92 * A <code>View</code> is jEdit's top-level frame window.<p>
  93 *
  94 * In a BeanShell script, you can obtain the current view instance from the
  95 * <code>view</code> variable.<p>
  96 *
  97 * The largest component it contains is an {@link EditPane} that in turn
  98 * contains a {@link org.gjt.sp.jedit.textarea.JEditTextArea} that displays a
  99 * {@link Buffer}.
 100 * A view can have more than one edit pane in a split window configuration.
 101 * A view also contains a menu bar, an optional toolbar and other window
 102 * decorations, as well as docked windows.<p>
 103 *
 104 * The <b>View</b> class performs two important operations
 105 * dealing with plugins: creating plugin menu items, and managing dockable
 106 * windows.
 107 *
 108 * <ul>
 109 * <li>When a view is being created, its initialization routine
 110 * iterates through the collection of loaded plugins and constructs the
 111 * <b>Plugins</b> menu using the properties as specified in the
 112 * {@link EditPlugin} class.</li>
 113 * <li>The view also creates and initializes a
 114 * {@link org.gjt.sp.jedit.gui.DockableWindowManager}
 115 * object.  This object is
 116 * responsible for creating, closing and managing dockable windows.</li>
 117 * </ul>
 118 *
 119 * This class does not have a public constructor.
 120 * Views can be opened and closed using methods in the <code>jEdit</code>
 121 * class.
 122 *
 123 * @see org.gjt.sp.jedit.jEdit#newView(View)
 124 * @see org.gjt.sp.jedit.jEdit#newView(View,Buffer)
 125 * @see org.gjt.sp.jedit.jEdit#newView(View,Buffer,boolean)
 126 * @see org.gjt.sp.jedit.jEdit#closeView(View)
 127 *
 128 * @author Slava Pestov
 129 * @author John Gellene (API documentation)
 130 * @version $Id: View.java 20108 2011-10-18 12:16:38Z evanpw $
 131 */
 132public class View extends JFrame implements InputHandlerProvider
 133{
 134	//{{{ User interface
 135
 136	//{{{ ToolBar-related constants
 137
 138	public static final String VIEW_DOCKING_FRAMEWORK_PROPERTY = "view.docking.framework";
 139	private static final String ORIGINAL_DOCKING_FRAMEWORK = "Original";
 140	public static final String DOCKING_FRAMEWORK_PROVIDER_SERVICE =
 141		"org.gjt.sp.jedit.gui.DockingFrameworkProvider";
 142	private static DockingFrameworkProvider dockingFrameworkProvider;
 143
 144	//{{{ Groups
 145	/**
 146	 * The group of tool bars above the DockableWindowManager
 147	 * @see #addToolBar(int,int,java.awt.Component)
 148	 * @since jEdit 4.0pre7
 149	 */
 150	public static final int TOP_GROUP = 0;
 151
 152	/**
 153	 * The group of tool bars below the DockableWindowManager
 154	 * @see #addToolBar(int,int,java.awt.Component)
 155	 * @since jEdit 4.0pre7
 156	 */
 157	public static final int BOTTOM_GROUP = 1;
 158	public static final int DEFAULT_GROUP = TOP_GROUP;
 159	//}}}
 160
 161	//{{{ Layers
 162
 163	// Common layers
 164	/**
 165	 * The highest possible layer.
 166	 * @see #addToolBar(int,int,java.awt.Component)
 167	 * @since jEdit 4.0pre7
 168	 */
 169	public static final int TOP_LAYER = Integer.MAX_VALUE;
 170
 171	/**
 172	 * The default layer for tool bars with no preference.
 173	 * @see #addToolBar(int,int,java.awt.Component)
 174	 * @since jEdit 4.0pre7
 175	 */
 176	public static final int DEFAULT_LAYER = 0;
 177
 178	/**
 179	 * The lowest possible layer.
 180	 * @see #addToolBar(int,int,java.awt.Component)
 181	 * @since jEdit 4.0pre7
 182	 */
 183	public static final int BOTTOM_LAYER = Integer.MIN_VALUE;
 184
 185	// Layers for top group
 186	/**
 187	 * Above system tool bar layer.
 188	 * @see #addToolBar(int,int,java.awt.Component)
 189	 * @since jEdit 4.0pre7
 190	 */
 191	public static final int ABOVE_SYSTEM_BAR_LAYER = 150;
 192
 193	/**
 194	 * System tool bar layer.
 195	 * jEdit uses this for the main tool bar.
 196	 * @see #addToolBar(int,int,java.awt.Component)
 197	 * @since jEdit 4.0pre7
 198	 */
 199	public static final int SYSTEM_BAR_LAYER = 100;
 200
 201	/**
 202	 * Below system tool bar layer.
 203	 * @see #addToolBar(int,int,java.awt.Component)
 204	 * @since jEdit 4.0pre7
 205	 */
 206	public static final int BELOW_SYSTEM_BAR_LAYER = 75;
 207
 208	/**
 209	 * Search bar layer.
 210	 * @see #addToolBar(int,int,java.awt.Component)
 211	 * @since jEdit 4.0pre7
 212	 */
 213	public static final int SEARCH_BAR_LAYER = 75;
 214
 215	/**
 216	 * Below search bar layer.
 217	 * @see #addToolBar(int,int,java.awt.Component)
 218	 * @since jEdit 4.0pre7
 219	 */
 220	public static final int BELOW_SEARCH_BAR_LAYER = 50;
 221
 222	// Layers for bottom group
 223	/**
 224	 * Action bar layer.
 225	 * @see #addToolBar(int,int,java.awt.Component)
 226	 * @since jEdit 4.2pre1
 227	 */
 228	public static final int ACTION_BAR_LAYER = -75;
 229
 230	/**
 231	 * Status bar layer.
 232	 * @see #addToolBar(int,int,java.awt.Component)
 233	 * @since jEdit 4.2pre1
 234	 */
 235	public static final int STATUS_BAR_LAYER = -100;
 236
 237	/**
 238	 * Status bar layer.
 239	 * @see #addToolBar(int,int,java.awt.Component)
 240	 * @since jEdit 4.2pre1
 241	 */
 242	public static final int BELOW_STATUS_BAR_LAYER = -150;
 243	//}}}
 244
 245	//}}}
 246
 247	//{{{ getDockableWindowManager() method
 248	/**
 249	 * Returns the dockable window manager associated with this view.
 250	 * @since jEdit 2.6pre3
 251	 */
 252	public DockableWindowManager getDockableWindowManager()
 253	{
 254		return dockableWindowManager;
 255	} //}}}
 256
 257	//{{{ getDockingFrameworkName() method
 258	public static String getDockingFrameworkName()
 259	{
 260		String framework = jEdit.getProperty(
 261				VIEW_DOCKING_FRAMEWORK_PROPERTY, ORIGINAL_DOCKING_FRAMEWORK);
 262		return framework;
 263	} //}}}
 264
 265	//{{{ getDockingFrameworkProvider() method
 266	public static DockingFrameworkProvider getDockingFrameworkProvider()
 267	{
 268		if (dockingFrameworkProvider == null)
 269		{
 270			String framework = getDockingFrameworkName();
 271			dockingFrameworkProvider = (DockingFrameworkProvider)
 272				ServiceManager.getService(
 273					DOCKING_FRAMEWORK_PROVIDER_SERVICE, framework);
 274
 275			if (dockingFrameworkProvider == null)
 276			{
 277				Log.log(Log.ERROR, View.class, "No docking framework " + framework +
 278							       " available, using the original one");
 279				dockingFrameworkProvider = (DockingFrameworkProvider)
 280				ServiceManager.getService(
 281					DOCKING_FRAMEWORK_PROVIDER_SERVICE, ORIGINAL_DOCKING_FRAMEWORK);
 282			}
 283		}
 284		return dockingFrameworkProvider;
 285	} //}}}
 286
 287	//{{{ getToolBar() method
 288	/**
 289	 * Returns the view's tool bar.
 290	 * @since jEdit 4.2pre1
 291	 */
 292	public Container getToolBar()
 293	{
 294		return toolBar;
 295	} //}}}
 296
 297	//{{{ addToolBar() methods
 298	/**
 299	 * Adds a tool bar to this view.
 300	 * @param toolBar The tool bar
 301	 */
 302	public void addToolBar(Component toolBar)
 303	{
 304		addToolBar(DEFAULT_GROUP, DEFAULT_LAYER, toolBar);
 305	}
 306
 307	/**
 308	 * Adds a tool bar to this view.
 309	 * @param group The tool bar group to add to
 310	 * @param toolBar The tool bar
 311	 * @see org.gjt.sp.jedit.gui.ToolBarManager
 312	 * @since jEdit 4.0pre7
 313	 */
 314	public void addToolBar(int group, Component toolBar)
 315	{
 316		addToolBar(group, DEFAULT_LAYER, toolBar);
 317	}
 318	
 319	/**
 320	 * Adds a tool bar to this view.
 321	 * @param group The tool bar group to add to
 322	 * @param layer The layer of the group to add to
 323	 * @param toolBar The tool bar
 324	 * @see org.gjt.sp.jedit.gui.ToolBarManager
 325	 * @since jEdit 4.0pre7
 326	 */
 327	public void addToolBar(int group, int layer, Component toolBar)
 328	{
 329		toolBarManager.addToolBar(group, layer, toolBar);
 330		getRootPane().revalidate();
 331	} //}}}
 332
 333	//{{{ removeToolBar() method
 334	/**
 335	 * Removes a tool bar from this view.
 336	 * @param toolBar The tool bar
 337	 */
 338	public void removeToolBar(Component toolBar)
 339	{
 340		if (toolBarManager == null) return;
 341		if (toolBar == null) return;
 342		toolBarManager.removeToolBar(toolBar);
 343		getRootPane().revalidate();
 344	} //}}}
 345
 346	//{{{ showWaitCursor() method
 347	/**
 348	 * Shows the wait cursor. This method and
 349	 * {@link #hideWaitCursor()} are implemented using a reference
 350	 * count of requests for wait cursors, so that nested calls work
 351	 * correctly; however, you should be careful to use these methods in
 352	 * tandem.<p>
 353	 *
 354	 * To ensure that {@link #hideWaitCursor()} is always called
 355	 * after a {@link #showWaitCursor()}, use a
 356	 * <code>try</code>/<code>finally</code> block, like this:
 357	 * <pre>try
 358	 *{
 359	 *    view.showWaitCursor();
 360	 *    // ...
 361	 *}
 362	 *finally
 363	 *{
 364	 *    view.hideWaitCursor();
 365	 *}</pre>
 366	 */
 367	public synchronized void showWaitCursor()
 368	{
 369		if(waitCount++ == 0)
 370		{
 371			Cursor cursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
 372			setCursor(cursor);
 373			visit(new SetCursorVisitor(cursor));
 374		}
 375	} //}}}
 376
 377	//{{{ hideWaitCursor() method
 378	/**
 379	 * Hides the wait cursor.
 380	 */
 381	public synchronized void hideWaitCursor()
 382	{
 383		if(waitCount > 0)
 384			waitCount--;
 385
 386		if(waitCount == 0)
 387		{
 388			// still needed even though glass pane
 389			// has a wait cursor
 390			Cursor cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
 391			setCursor(cursor);
 392
 393			visit(new SetCursorVisitor(cursor));
 394		}
 395	} //}}}
 396
 397	//{{{ getSearchBar() method
 398	/**
 399	 * Returns the search bar.
 400	 * @since jEdit 2.4pre4
 401	 */
 402	public final SearchBar getSearchBar()
 403	{
 404		return searchBar;
 405	} //}}}
 406
 407	//{{{ getActionBar() method
 408	/**
 409	 * Returns the action bar.
 410	 * @since jEdit 4.2pre3
 411	 */
 412	public final ActionBar getActionBar()
 413	{
 414		return actionBar;
 415	} //}}}
 416
 417	//{{{ getStatus() method
 418	/**
 419	 * Returns the status bar. The
 420	 * {@link org.gjt.sp.jedit.gui.StatusBar#setMessage(String)} and
 421	 * {@link org.gjt.sp.jedit.gui.StatusBar#setMessageAndClear(String)} methods can
 422	 * be called on the return value of this method to display status
 423	 * information to the user.
 424	 * @since jEdit 3.2pre2
 425	 */
 426	public StatusBar getStatus()
 427	{
 428		return status;
 429	} //}}}
 430
 431	//{{{ quickIncrementalSearch() method
 432	/**
 433	 * Quick search.
 434	 * @since jEdit 4.0pre3
 435	 */
 436	public void quickIncrementalSearch(boolean word)
 437	{
 438		if(searchBar == null)
 439			searchBar = new SearchBar(this,true);
 440		if(searchBar.getParent() == null)
 441			addToolBar(TOP_GROUP,SEARCH_BAR_LAYER,searchBar);
 442
 443		searchBar.setHyperSearch(false);
 444
 445		JEditTextArea textArea = getTextArea();
 446
 447		if(word)
 448		{
 449			String text = textArea.getSelectedText();
 450			if(text == null)
 451			{
 452				textArea.selectWord();
 453				text = textArea.getSelectedText();
 454			}
 455			else if(text.indexOf('\n') != -1)
 456				text = null;
 457
 458			if(text != null && SearchAndReplace.getRegexp())
 459				text = SearchAndReplace.escapeRegexp(text,false);
 460
 461			searchBar.getField().setText(text);
 462		}
 463
 464		searchBar.getField().requestFocus();
 465		searchBar.getField().selectAll();
 466	} //}}}
 467
 468	//{{{ quickHyperSearch() method
 469	/**
 470	 * Quick HyperSearch.
 471	 * @since jEdit 4.0pre3
 472	 */
 473	public void quickHyperSearch(boolean word)
 474	{
 475		JEditTextArea textArea = getTextArea();
 476
 477		if(word)
 478		{
 479			String text = textArea.getSelectedText();
 480			if(text == null)
 481			{
 482				textArea.selectWord();
 483				text = textArea.getSelectedText();
 484			}
 485
 486			if(text != null && text.indexOf('\n') == -1)
 487			{
 488				if(SearchAndReplace.getRegexp())
 489				{
 490					text = SearchAndReplace.escapeRegexp(
 491						text,false);
 492				}
 493
 494				HistoryModel.getModel("find").addItem(text);
 495				SearchAndReplace.setSearchString(text);
 496				SearchAndReplace.setSearchFileSet(new CurrentBufferSet());
 497				SearchAndReplace.hyperSearch(this);
 498
 499				return;
 500			}
 501		}
 502
 503		if(searchBar == null)
 504			searchBar = new SearchBar(this,true);
 505		if(searchBar.getParent() == null)
 506			addToolBar(TOP_GROUP,SEARCH_BAR_LAYER,searchBar);
 507
 508		searchBar.setHyperSearch(true);
 509		searchBar.getField().setText(null);
 510		searchBar.getField().requestFocus();
 511		searchBar.getField().selectAll();
 512	} //}}}
 513
 514	//{{{ actionBar() method
 515	/**
 516	 * Shows the action bar if needed, and sends keyboard focus there.
 517	 * @since jEdit 4.2pre1
 518	 */
 519	public void actionBar()
 520	{
 521		if(actionBar == null)
 522			actionBar = new ActionBar(this,true);
 523		if(actionBar.getParent() == null)
 524			addToolBar(BOTTOM_GROUP,ACTION_BAR_LAYER,actionBar);
 525
 526		actionBar.goToActionBar();
 527	} //}}}
 528
 529	//}}}
 530
 531	//{{{ Input handling
 532
 533	//{{{ getKeyEventInterceptor() method
 534	/**
 535	 * Returns the listener that will handle all key events in this
 536	 * view, if any.
 537	 * @return the key event interceptor or null
 538	 */
 539	public KeyListener getKeyEventInterceptor()
 540	{
 541		return inputHandler.getKeyEventInterceptor();
 542	} //}}}
 543
 544	//{{{ setKeyEventInterceptor() method
 545	/**
 546	 * Sets the listener that will handle all key events in this
 547	 * view. For example, the complete word command uses this so
 548	 * that all key events are passed to the word list popup while
 549	 * it is visible.
 550	 * @param listener The key event interceptor.
 551	 */
 552	public void setKeyEventInterceptor(KeyListener listener)
 553	{
 554		inputHandler.setKeyEventInterceptor(listener);
 555	} //}}}
 556
 557	//{{{ getInputHandler() method
 558	/**
 559	 * Returns the input handler.
 560	 */
 561	public InputHandler getInputHandler()
 562	{
 563		return inputHandler;
 564	} //}}}
 565
 566
 567
 568	//{{{ setInputHandler() method
 569	/**
 570	 * Sets the input handler.
 571	 * @param inputHandler The new input handler
 572	 */
 573	public void setInputHandler(InputHandler inputHandler)
 574	{
 575		this.inputHandler = inputHandler;
 576	} //}}}
 577
 578	//{{{ getMacroRecorder() method
 579	/**
 580	 * Returns the macro recorder.
 581	 */
 582	public Macros.Recorder getMacroRecorder()
 583	{
 584		return recorder;
 585	} //}}}
 586
 587	//{{{ setMacroRecorder() method
 588	/**
 589	 * Sets the macro recorder.
 590	 * @param recorder The macro recorder
 591	 */
 592	public void setMacroRecorder(Macros.Recorder recorder)
 593	{
 594		this.recorder = recorder;
 595	} //}}}
 596
 597	//{{{ processKeyEvent() method
 598	/**
 599	 * Forwards key events directly to the input handler.
 600	 * This is slightly faster than using a KeyListener
 601	 * because some Swing overhead is avoided.
 602	 */
 603	@Override
 604	public void processKeyEvent(KeyEvent evt)
 605	{
 606		inputHandler.processKeyEvent(evt,VIEW, false);
 607		if(!evt.isConsumed())
 608			super.processKeyEvent(evt);
 609	} //}}}
 610
 611	//{{{ processKeyEvent() method
 612	/**
 613	 * Forwards key events directly to the input handler.
 614	 * This is slightly faster than using a KeyListener
 615	 * because some Swing overhead is avoided.
 616	 */
 617	public void processKeyEvent(KeyEvent evt, boolean calledFromTextArea)
 618	{
 619		processKeyEvent(evt,calledFromTextArea
 620			? TEXT_AREA
 621			: VIEW);
 622	} //}}}
 623
 624	//{{{ processKeyEvent() method
 625	public static final int VIEW = 0;
 626	public static final int TEXT_AREA = 1;
 627	public static final int ACTION_BAR = 2;
 628	/**
 629	 * Forwards key events directly to the input handler.
 630	 * This is slightly faster than using a KeyListener
 631	 * because some Swing overhead is avoided.
 632	 */
 633	public void processKeyEvent(KeyEvent evt, int from)
 634	{
 635		inputHandler.processKeyEvent(evt, from, false);
 636		if(!evt.isConsumed())
 637			super.processKeyEvent(evt);
 638	}
 639	//}}}
 640
 641	//}}}
 642	
 643	//{{{ Buffers, edit panes, split panes
 644
 645	//{{{ splitHorizontally() method
 646	/**
 647	 * Splits the view horizontally.
 648	 * @return the new editPane
 649	 * @since jEdit 4.1pre2
 650	 */
 651	public EditPane splitHorizontally()
 652	{
 653		return split(JSplitPane.VERTICAL_SPLIT);
 654	} //}}}
 655
 656	//{{{ splitVertically() method
 657	/**
 658	 * Splits the view vertically.
 659	 * @return the new editPane
 660	 * @since jEdit 4.1pre2
 661	 */
 662	public EditPane splitVertically()
 663	{
 664		return split(JSplitPane.HORIZONTAL_SPLIT);
 665	} //}}}
 666
 667	//{{{ split() method
 668	/**
 669	 * Splits the view.
 670	 * @param orientation the orientation {@link javax.swing.JSplitPane#HORIZONTAL_SPLIT} or
 671	 * {@link javax.swing.JSplitPane#VERTICAL_SPLIT}
 672	 * @return the new editPane
 673	 * @since jEdit 4.1pre2
 674	 */
 675	public EditPane split(int orientation)
 676	{
 677		PerspectiveManager.setPerspectiveDirty(true);
 678
 679		editPane.saveCaretInfo();
 680		EditPane oldEditPane = editPane;
 681		EditPane newEditPane = createEditPane(oldEditPane);
 682//		setEditPane(newEditPane);
 683		newEditPane.loadCaretInfo();
 684
 685		JComponent oldParent = (JComponent)oldEditPane.getParent();
 686
 687		final JSplitPane newSplitPane = new JSplitPane(orientation,
 688							       jEdit.getBooleanProperty("appearance.continuousLayout"));
 689		newSplitPane.setOneTouchExpandable(true);
 690		newSplitPane.setBorder(null);
 691		newSplitPane.setMinimumSize(new Dimension(0,0));
 692		newSplitPane.setResizeWeight(0.5);
 693
 694		int parentSize = orientation == JSplitPane.VERTICAL_SPLIT
 695			? oldEditPane.getHeight() : oldEditPane.getWidth();
 696		final int dividerPosition = (int)((parentSize
 697			- newSplitPane.getDividerSize()) * 0.5);
 698		newSplitPane.setDividerLocation(dividerPosition);
 699
 700		if(oldParent instanceof JSplitPane)
 701		{
 702			JSplitPane oldSplitPane = (JSplitPane)oldParent;
 703			int dividerPos = oldSplitPane.getDividerLocation();
 704
 705			Component left = oldSplitPane.getLeftComponent();
 706
 707			if(left == oldEditPane)
 708				oldSplitPane.setLeftComponent(newSplitPane);
 709			else
 710				oldSplitPane.setRightComponent(newSplitPane);
 711
 712			newSplitPane.setLeftComponent(oldEditPane);
 713			newSplitPane.setRightComponent(newEditPane);
 714
 715			oldSplitPane.setDividerLocation(dividerPos);
 716		}
 717		else
 718		{
 719			splitPane = newSplitPane;
 720
 721			newSplitPane.setLeftComponent(oldEditPane);
 722			newSplitPane.setRightComponent(newEditPane);
 723
 724			setMainContent(newSplitPane);
 725
 726		}
 727
 728		EventQueue.invokeLater(new Runnable()
 729		{
 730			public void run()
 731			{
 732				newSplitPane.setDividerLocation(dividerPosition);
 733			}
 734		});
 735
 736		newEditPane.focusOnTextArea();
 737
 738		return newEditPane;
 739	} //}}}
 740
 741	//{{{ unsplit() method
 742	/**
 743	 * Unsplits the view.
 744	 * @since jEdit 2.3pre2
 745	 */
 746	public void unsplit()
 747	{
 748		if(splitPane != null)
 749		{
 750			lastSplitConfig = getSplitConfig();
 751
 752			PerspectiveManager.setPerspectiveDirty(true);
 753			BufferSet.Scope scope = jEdit.getBufferSetManager().getScope();
 754			for(EditPane _editPane: getEditPanes())
 755			{
 756				if(editPane != _editPane)
 757				{
 758					if (scope == BufferSet.Scope.editpane)
 759						mergeBufferSets(editPane, _editPane);
 760					_editPane.close();
 761				}
 762			}
 763
 764			setMainContent(editPane);
 765
 766			splitPane = null;
 767			updateTitle();
 768
 769			editPane.focusOnTextArea();
 770		}
 771		else
 772			getToolkit().beep();
 773	} //}}}
 774
 775	//{{{ unsplitCurrent() method
 776	/**
 777	 * Removes the current split.
 778	 * @since jEdit 2.3pre2
 779	 */
 780	public void unsplitCurrent()
 781	{
 782		if(splitPane != null)
 783		{
 784			lastSplitConfig = getSplitConfig();
 785
 786			PerspectiveManager.setPerspectiveDirty(true);
 787
 788			// find first split pane parenting current edit pane
 789			Component comp = editPane;
 790			while(!(comp instanceof JSplitPane) && comp != null)
 791			{
 792				comp = comp.getParent();
 793			}
 794
 795			BufferSet.Scope scope = jEdit.getBufferSetManager().getScope();
 796			// get rid of any edit pane that is a child
 797			// of the current edit pane's parent splitter
 798			for(EditPane _editPane: getEditPanes())
 799			{
 800				if(GUIUtilities.isAncestorOf(comp,_editPane)
 801					&& _editPane != editPane)
 802				{
 803					if (scope == BufferSet.Scope.editpane)
 804						mergeBufferSets(editPane, _editPane);
 805					_editPane.close();
 806				}
 807			}
 808
 809			JComponent parent = comp == null ? null : (JComponent)comp.getParent();
 810
 811			if(parent instanceof JSplitPane)
 812			{
 813				JSplitPane parentSplit = (JSplitPane)parent;
 814				int pos = parentSplit.getDividerLocation();
 815				if(parentSplit.getLeftComponent() == comp)
 816					parentSplit.setLeftComponent(editPane);
 817				else
 818					parentSplit.setRightComponent(editPane);
 819				parentSplit.setDividerLocation(pos);
 820				parent.revalidate();
 821			}
 822			else
 823			{
 824				setMainContent(editPane);
 825				splitPane = null;
 826			}
 827
 828			updateTitle();
 829
 830			editPane.focusOnTextArea();
 831		}
 832		else
 833			getToolkit().beep();
 834	} //}}}
 835
 836	//{{{ resplit() method
 837	/**
 838	 * Restore the split configuration as it was before unsplitting.
 839	 *
 840	 * @since jEdit 4.3pre1
 841	 */
 842	public void resplit()
 843	{
 844		if(lastSplitConfig == null)
 845			getToolkit().beep();
 846		else
 847			setSplitConfig(null,lastSplitConfig);
 848	} //}}}
 849
 850	//{{{ getSplitConfig() method
 851	/**
 852	*   Split configurations are recorded in a simple RPN "language".
 853	*   @return The split configuration, describing where splitpanes
 854	*           are, which buffers are open in each EditPane, etc.
 855	*
 856	*/
 857	public String getSplitConfig()
 858	{
 859		StringBuilder splitConfig = new StringBuilder();
 860
 861		if(splitPane != null)
 862			getSplitConfig(splitPane,splitConfig);
 863		else
 864		{
 865			appendToSplitConfig(splitConfig, editPane);
 866		}
 867
 868		return splitConfig.toString();
 869	} //}}}
 870
 871	//{{{ setSplitConfig() method
 872	/**
 873	 * sets the split configuration as per the splitConfig.
 874	 *
 875	 * @param buffer if null, checks all buffers to restore View's split config.
 876	 * @param splitConfig the split config, as returned by getSplitConfig()
 877	 */
 878	public void setSplitConfig(Buffer buffer, String splitConfig)
 879	{
 880		try
 881		{
 882			Component comp = restoreSplitConfig(buffer,splitConfig);
 883			setMainContent(comp);
 884			updateTitle();
 885		}
 886		catch(IOException e)
 887		{
 888			// this should never throw an exception.
 889			throw new InternalError();
 890		}
 891	} //}}}
 892
 893	//{{{ nextTextArea() method
 894	/**
 895	 * Moves keyboard focus to the next text area.
 896	 * @since jEdit 2.7pre4
 897	 */
 898	public void nextTextArea()
 899	{
 900		EditPane[] editPanes = getEditPanes();
 901		for(int i = 0; i < editPanes.length; i++)
 902		{
 903			if(editPane == editPanes[i])
 904			{
 905				if(i == editPanes.length - 1)
 906					editPanes[0].focusOnTextArea();
 907				else
 908					editPanes[i+1].focusOnTextArea();
 909				break;
 910			}
 911		}
 912	} //}}}
 913
 914	//{{{ prevTextArea() method
 915	/**
 916	 * Moves keyboard focus to the previous text area.
 917	 * @since jEdit 2.7pre4
 918	 */
 919	public void prevTextArea()
 920	{
 921		EditPane[] editPanes = getEditPanes();
 922		for(int i = 0; i < editPanes.length; i++)
 923		{
 924			if(editPane == editPanes[i])
 925			{
 926				if(i == 0)
 927					editPanes[editPanes.length - 1].focusOnTextArea();
 928				else
 929					editPanes[i-1].focusOnTextArea();
 930				break;
 931			}
 932		}
 933	} //}}}
 934
 935	//{{{ getSplitPane() method
 936	/**
 937	 * Returns the top-level split pane, if any.
 938	 * @return the top JSplitPane if any.
 939	 * @since jEdit 2.3pre2
 940	 */
 941	public JSplitPane getSplitPane()
 942	{
 943		return splitPane;
 944	} //}}}
 945
 946	//{{{ getBuffer() method
 947	/**
 948	 * Returns the current edit pane's buffer.
 949	 * @return the current edit pane's buffer, it can be null
 950	 */
 951	public Buffer getBuffer()
 952	{
 953		if(editPane == null)
 954			return null;
 955		else
 956			return editPane.getBuffer();
 957	} //}}}
 958
 959	//{{{ setBuffer() method
 960	/**
 961	 * Sets the current edit pane's buffer.
 962	 * @param buffer The buffer
 963	 */
 964	public void setBuffer(Buffer buffer)
 965	{
 966		setBuffer(buffer,false);
 967	} //}}}
 968
 969	//{{{ setBuffer() method
 970	/**
 971	 * Sets the current edit pane's buffer.
 972	 * @param buffer The buffer
 973	 * @param disableFileStatusCheck Disables file status checking
 974	 * regardless of the state of the checkFileStatus property
 975	 */
 976	public void setBuffer(Buffer buffer, boolean disableFileStatusCheck)
 977	{
 978		setBuffer(buffer, disableFileStatusCheck, true);
 979	} //}}}
 980
 981	//{{{ setBuffer() method
 982	/**
 983	 * Sets the current edit pane's buffer.
 984	 * @param buffer The buffer
 985	 * @param disableFileStatusCheck Disables file status checking
 986	 * regardless of the state of the checkFileStatus property
 987	 * @param focus Whether the textarea should request focus
 988	 * @since jEdit 4.3pre13
 989	 */
 990	public void setBuffer(Buffer buffer, boolean disableFileStatusCheck, boolean focus)
 991	{
 992		editPane.setBuffer(buffer, focus);
 993		int check = jEdit.getIntegerProperty("checkFileStatus");
 994		if(!disableFileStatusCheck && (check == GeneralOptionPane.checkFileStatus_all ||
 995						  check == GeneralOptionPane.checkFileStatus_operations ||
 996						  check == GeneralOptionPane.checkFileStatus_focusBuffer))
 997			jEdit.checkBufferStatus(this, true);
 998	} //}}}
 999
1000	//{{{ goToBuffer() method
1001	/**
1002	 * If this buffer is open in one of the view's edit panes, sets focus
1003	 * to that edit pane. Otherwise, opens the buffer in the currently
1004	 * active edit pane.
1005	 * @param buffer The buffer
1006	 * @return the current edit pane
1007	 * @since jEdit 4.2pre1
1008	 */
1009	public EditPane goToBuffer(Buffer buffer)
1010	{
1011		return showBuffer(buffer, true);
1012	} //}}}
1013
1014	//{{{ showBuffer() method
1015	/**
1016	 * If this buffer is open in one of the view's edit panes, activates
1017	 * that edit pane. Otherwise, opens the buffer in the currently
1018	 * active edit pane. But the focus is not moved.
1019	 * @param buffer The buffer to show
1020	 * @return the current edit pane
1021	 * @since jEdit 4.3pre13
1022	 */
1023	public EditPane showBuffer(Buffer buffer)
1024	{
1025		return showBuffer(buffer, false);
1026	} //}}}
1027
1028	//{{{ getTextArea() method
1029	/**
1030	 * Returns the current edit pane's text area.
1031	 * @return the current edit pane's text area, or <b>null</b> if there is no edit pane yet
1032	 */
1033	public JEditTextArea getTextArea()
1034	{
1035		if(editPane == null)
1036			return null;
1037		else
1038			return editPane.getTextArea();
1039	} //}}}
1040
1041	//{{{ getEditPane() method
1042	/**
1043	 * Returns the current edit pane.
1044	 * @return the current edit pane
1045	 * @since jEdit 2.5pre2
1046	 */
1047	public EditPane getEditPane()
1048	{
1049		return editPane;
1050	} //}}}
1051
1052	//{{{ getEditPanes() method
1053	/**
1054	 * Returns all edit panes.
1055	 * @return an array of all edit panes in the view
1056	 * @since jEdit 2.5pre2
1057	 */
1058	public EditPane[] getEditPanes()
1059	{
1060		if(splitPane == null)
1061		{
1062			EditPane[] ep = { editPane };
1063			return ep;
1064		}
1065		else
1066		{
1067			List<EditPane> vec = new ArrayList<EditPane>();
1068			getEditPanes(vec,splitPane);
1069			EditPane[] ep = new EditPane[vec.size()];
1070			vec.toArray(ep);
1071			return ep;
1072		}
1073	} //}}}
1074
1075	//{{{ getViewConfig() method
1076	/**
1077	 * @return a ViewConfig instance for the current view
1078	 * @since jEdit 4.2pre1
1079	 */
1080	public ViewConfig getViewConfig()
1081	{
1082		ViewConfig config = new ViewConfig();
1083		config.plainView = isPlainView();
1084		config.splitConfig = getSplitConfig();
1085		config.extState = getExtendedState();
1086		config.docking = dockableWindowManager.getDockingLayout(config);
1087		config.title = userTitle;
1088		String prefix = config.plainView ? "plain-view" : "view";
1089		switch (config.extState)
1090		{
1091			case Frame.MAXIMIZED_BOTH:
1092			case Frame.ICONIFIED:
1093				config.x = jEdit.getIntegerProperty(prefix + ".x",getX());
1094				config.y = jEdit.getIntegerProperty(prefix + ".y",getY());
1095				config.width = jEdit.getIntegerProperty(prefix + ".width",getWidth());
1096				config.height = jEdit.getIntegerProperty(prefix + ".height",getHeight());
1097				break;
1098
1099			case Frame.MAXIMIZED_VERT:
1100				config.x = getX();
1101				config.y = jEdit.getIntegerProperty(prefix + ".y",getY());
1102				config.width = getWidth();
1103				config.height = jEdit.getIntegerProperty(prefix + ".height",getHeight());
1104				break;
1105
1106			case Frame.MAXIMIZED_HORIZ:
1107				config.x = jEdit.getIntegerProperty(prefix + ".x",getX());
1108				config.y = getY();
1109				config.width = jEdit.getIntegerProperty(prefix + ".width",getWidth());
1110				config.height = getHeight();
1111				break;
1112
1113			case Frame.NORMAL:
1114			default:
1115				config.x = getX();
1116				config.y = getY();
1117				config.width = getWidth();
1118				config.height = getHeight();
1119				break;
1120		}
1121		return config;
1122	} //}}}
1123
1124	//}}}
1125
1126	//{{{ isClosed() method
1127	/**
1128	 * Returns true if this view has been closed with
1129	 * {@link jEdit#closeView(View)}.
1130	 * @return true if the view is closed
1131	 */
1132	public boolean isClosed()
1133	{
1134		return closed;
1135	} //}}}
1136
1137	//{{{ isPlainView() method
1138	/**
1139	 * Returns true if this is an auxilliary view with no dockable windows.
1140	 * @return true if the view is plain
1141	 * @since jEdit 4.1pre2
1142	 */
1143	public boolean isPlainView()
1144	{
1145		return plainView;
1146	} //}}}
1147
1148	//{{{ getNext() method
1149	/**
1150	 * Returns the next view in the list.
1151	 * @return the next view
1152	 */
1153	public View getNext()
1154	{
1155		return next;
1156	} //}}}
1157
1158	//{{{ getPrev() method
1159	/**
1160	 * Returns the previous view in the list.
1161	 * @return the preview view
1162	 */
1163	public View getPrev()
1164	{
1165		return prev;
1166	} //}}}
1167
1168	//{{{ handlePropertiesChanged()
1169	@EBHandler
1170	public void handlePropertiesChanged(PropertiesChanged msg)
1171	{
1172		propertiesChanged();
1173	} //}}}
1174
1175	//{{{ handleSearchSettingsChanged() method
1176	@EBHandler
1177	public void handleSearchSettingsChanged(SearchSettingsChanged msg)
1178	{
1179		if(searchBar != null)
1180			searchBar.update();
1181	} //}}}
1182
1183	//{{{ getMinimumSize() method
1184	@Override
1185	public Dimension getMinimumSize()
1186	{
1187		return new Dimension(0,0);
1188	} //}}}
1189
1190	//{{{ setWaitSocket() method
1191	/**
1192	 * This socket is closed when the buffer is closed.
1193	 */
1194	public void setWaitSocket(Socket waitSocket)
1195	{
1196		this.waitSocket = waitSocket;
1197	} //}}}
1198
1199	//{{{ toString() method
1200	@Override
1201	public String toString()
1202	{
1203		return getClass().getName() + '['
1204			+ (jEdit.getActiveView() == this
1205			? "active" : "inactive")
1206			+ ']';
1207	} //}}}
1208
1209	//{{{ updateTitle() method
1210	/**
1211	 * Updates the title bar.
1212	 */
1213	public void updateTitle()
1214	{
1215		List<Buffer> buffers = new ArrayList<Buffer>();
1216		EditPane[] editPanes = getEditPanes();
1217		for(int i = 0; i < editPanes.length; i++)
1218		{
1219			Buffer buffer = editPanes[i].getBuffer();
1220			if(!buffers.contains(buffer))
1221				buffers.add(buffer);
1222		}
1223
1224		StringBuilder title = new StringBuilder();
1225
1226		/* On Mac OS X, apps are not supposed to show their name in the
1227		title bar. */
1228		if(!OperatingSystem.isMacOS())
1229		{
1230			if (userTitle != null)
1231				title.append(userTitle);
1232			else
1233				title.append(jEdit.getProperty("view.title"));
1234		}
1235
1236		for(int i = 0; i < buffers.size(); i++)
1237		{
1238			if(i != 0)
1239				title.append(", ");
1240
1241			Buffer buffer = buffers.get(i);
1242			title.append(showFullPath && !buffer.isNewFile()
1243				? buffer.getPath(true) : buffer.getName());
1244			if(buffer.isDirty())
1245				title.append(jEdit.getProperty("view.title.dirty"));
1246		}
1247
1248		setTitle(title.toString());
1249	} //}}}
1250
1251	//{{{ setUserTitle() method
1252	/**
1253	 * Sets a user-defined title for this view instead of the "view.title" property.
1254	 */
1255	public void setUserTitle(String title)
1256	{
1257		userTitle = title + " - ";
1258		updateTitle();
1259	} //}}}
1260
1261	//{{{ showUserTitleDialog() method
1262	/**
1263	 * Shows a dialog for selecting a user-defined title for this view.
1264	 */
1265	public void showUserTitleDialog()
1266	{
1267		String title = JOptionPane.showInputDialog(this, jEdit.getProperty(
1268			"view.title.select"));
1269		if (title == null)
1270			return;
1271		setUserTitle(title);
1272	} //}}}
1273
1274	//{{{ getPrefixFocusOwner() method
1275	public Component getPrefixFocusOwner()
1276	{
1277		return prefixFocusOwner;
1278	} //}}}
1279
1280	//{{{ setPrefixFocusOwner() method
1281	public void setPrefixFocusOwner(Component prefixFocusOwner)
1282	{
1283		this.prefixFocusOwner = prefixFocusOwner;
1284	} //}}}
1285
1286	//{{{ visit() method
1287	/**
1288	 * Visit the the editpanes and textareas of the view
1289	 * @param visitor the visitor
1290	 * @since jEdit 4.3pre13
1291	 */
1292	public void visit(JEditVisitor visitor)
1293	{
1294		EditPane[] panes = getEditPanes();
1295		for (int i = 0; i < panes.length; i++)
1296		{
1297			EditPane editPane = panes[i];
1298			visitor.visit(editPane);
1299			visitor.visit(editPane.getTextArea());
1300		}
1301	} //}}}
1302
1303	// {{{ closeAllMenus()
1304	/** closes any popup menus that may have been opened 
1305	    @since jEdit 4.4pre1
1306	*/
1307	public void closeAllMenus()
1308	{
1309		MenuSelectionManager.defaultManager().clearSelectedPath();
1310		KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
1311	} // }}}
1312	
1313	//{{{ Package-private members
1314	View prev;
1315	View next;
1316
1317	//{{{ View constructor
1318	View(Buffer buffer, ViewConfig config)
1319	{
1320		fullScreenMode = false;
1321		menuBar = null;
1322		plainView = config.plainView;
1323
1324		enableEvents(AWTEvent.KEY_EVENT_MASK);
1325
1326		setIconImage(GUIUtilities.getEditorIcon());
1327
1328		mainPanel = new JPanel();
1329		mainPanel.setLayout(new BorderLayout());
1330		dockableWindowManager = getDockingFrameworkProvider().create(this,
1331			DockableWindowFactory.getInstance(), config);
1332		userTitle = config.title;
1333		dockableWindowManager.setMainPanel(mainPanel);
1334
1335		topToolBars = new JPanel(new VariableGridLayout(
1336			VariableGridLayout.FIXED_NUM_COLUMNS,
1337			1));
1338		bottomToolBars = new JPanel(new VariableGridLayout(
1339			VariableGridLayout.FIXED_NUM_COLUMNS,
1340			1));
1341
1342		toolBarManager = new ToolBarManager(topToolBars, bottomToolBars);
1343
1344		status = new StatusBar(this);
1345
1346		inputHandler = new DefaultInputHandler(this,(DefaultInputHandler)
1347			jEdit.getInputHandler());
1348
1349		setSplitConfig(buffer,config.splitConfig);
1350
1351		getContentPane().add(BorderLayout.CENTER,dockableWindowManager);
1352
1353		dockableWindowManager.init();
1354
1355		// tool bar and status bar gets added in propertiesChanged()
1356		// depending in the 'tool bar alternate layout' setting.
1357		propertiesChanged();
1358
1359		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
1360		addWindowListener(new WindowHandler());
1361
1362		setFocusTraversalPolicy(new MyFocusTraversalPolicy());
1363
1364		EditBus.addToBus(this);
1365
1366		GUIUtilities.addSizeSaver(this, null, plainView ? "plain-view" : "view");
1367	} //}}}
1368
1369	//{{{ updateFullScreenProps() method
1370	public void updateFullScreenProps()
1371	{
1372		boolean alternateLayout = jEdit.getBooleanProperty(
1373			"view.toolbar.alternateLayout");
1374		boolean showMenu = jEdit.getBooleanProperty("fullScreenIncludesMenu");
1375		boolean showToolbars = jEdit.getBooleanProperty("fullScreenIncludesToolbar");
1376		boolean showStatus = jEdit.getBooleanProperty("fullScreenIncludesStatus");
1377		if (! showMenu)
1378		{
1379			menuBar = getJMenuBar();
1380			setJMenuBar(null);
1381		}
1382		else if (menuBar != null)
1383			setJMenuBar(menuBar);
1384		// Note: Bottom toolbar is the action bar, which is always enabled
1385		loadToolBars();
1386		if (alternateLayout)
1387		{
1388			if (! showStatus)
1389				removeToolBar(status);
1390			else
1391				addToolBar(BOTTOM_GROUP,STATUS_BAR_LAYER,status);
1392		}
1393		else
1394		{
1395			if (! showStatus)
1396				getContentPane().remove(status);
1397			else
1398				getContentPane().add(BorderLayout.SOUTH,status);
1399		}
1400	} //}}}
1401
1402	//{{{ toggleFullScreen() method
1403	public void toggleFullScreen()
1404	{
1405		fullScreenMode = (! fullScreenMode);
1406		GraphicsDevice sd = getGraphicsConfiguration().getDevice();
1407		dispose();
1408		if (fullScreenMode)
1409		{
1410			updateFullScreenProps();
1411			windowedBounds = getBounds();
1412			setUndecorated(true);
1413			setBounds(sd.getDefaultConfiguration().getBounds());
1414			validate();
1415		}
1416		else
1417		{
1418			boolean showStatus = plainView ? jEdit.getBooleanProperty("view.status.plainview.visible") :
1419				jEdit.getBooleanProperty("view.status.visible");
1420			if ((menuBar != null) && (getJMenuBar() != menuBar))
1421				setJMenuBar(menuBar);
1422			boolean alternateLayout = jEdit.getBooleanProperty(
1423				"view.toolbar.alternateLayout");
1424			loadToolBars();
1425			if (showStatus)
1426			{
1427				if (alternateLayout)
1428					addToolBar(BOTTOM_GROUP,STATUS_BAR_LAYER,status);
1429				else
1430					getContentPane().add(BorderLayout.SOUTH,status);
1431			}
1432			setUndecorated(false);
1433			setBounds(windowedBounds);
1434		}
1435		setVisible(true);
1436		toFront();
1437		closeAllMenus();
1438		// so you can keep typing in your editpane afterwards...
1439		editPane.getTextArea().requestFocus();
1440	} //}}}
1441
1442	//{{{ confirmToCloseDirty() methods
1443	/**
1444	 * If the view contains dirty buffers which will be closed on
1445	 * closing the view, show the confirmation dialog for user.
1446	 * @return
1447	 * 	true if there are no such buffers or user select OK
1448	 * 	to close the view; false if user select Cancel
1449	 */
1450	boolean confirmToCloseDirty()
1451	{
1452		Set<Buffer> checkingBuffers = getOpenBuffers();
1453		for (View view: jEdit.getViews())
1454		{
1455			if (view != this)
1456			{
1457				checkingBuffers.removeAll(
1458					view.getOpenBuffers());
1459			}
1460		}
1461		for (Buffer buffer: checkingBuffers)
1462		{
1463			if (buffer.isDirty())
1464			{
1465				return new CloseDialog(this, checkingBuffers).isOK();
1466			}
1467		}
1468		return true;
1469	} //}}}
1470
1471	//{{{ close() method
1472	void close()
1473	{
1474		EditBus.send(new ViewUpdate(this,ViewUpdate.CLOSED));
1475		closed = true;
1476
1477		// save dockable window geometry, and close 'em
1478		dockableWindowManager.close();
1479
1480		EditBus.removeFromBus(this);
1481		dispose();
1482
1483		EditPane[] editPanes = getEditPanes();
1484		for(int i = 0; i < editPanes.length; i++)
1485			editPanes[i].close();
1486
1487		// null some variables so that retaining references
1488		// to closed views won't hurt as much.
1489		toolBarManager = null;
1490		toolBar = null;
1491		searchBar = null;
1492		splitPane = null;
1493		inputHandler = null;
1494		recorder = null;
1495
1496		getContentPane().removeAll();
1497
1498		// notify clients with -wait
1499		if(waitSocket != null)
1500		{
1501			try
1502			{
1503				waitSocket.getOutputStream().write('\0');
1504				waitSocket.getOutputStream().flush();
1505				waitSocket.getInputStream().close();
1506				waitSocket.getOutputStream().close();
1507				waitSocket.close();
1508			}
1509			catch(IOException io)
1510			{
1511				//Log.log(Log.ERROR,this,io);
1512			}
1513		}
1514	} //}}}
1515
1516	//}}}
1517
1518	//{{{ Private members
1519
1520	//{{{ Instance variables
1521	private boolean closed;
1522
1523	private DockableWindowManager dockableWindowManager;
1524	private JPanel mainPanel;
1525
1526	private JPanel topToolBars;
1527	private JPanel bottomToolBars;
1528	private ToolBarManager toolBarManager;
1529
1530	private Container toolBar;
1531	private SearchBar searchBar;
1532	private ActionBar actionBar;
1533
1534	private EditPane editPane;
1535	private JSplitPane splitPane;
1536	private String lastSplitConfig;
1537
1538	private StatusBar status;
1539
1540	private InputHandler inputHandler;
1541	private Macros.Recorder recorder;
1542	private Component prefixFocusOwner;
1543
1544	private int waitCount;
1545
1546	private boolean showFullPath;
1547
1548	private boolean plainView;
1549
1550	private Socket waitSocket;
1551	private Component mainContent;
1552
1553	private boolean fullScreenMode;
1554	private Rectangle windowedBounds;
1555	private JMenuBar menuBar;
1556	private String userTitle;
1557	//}}}
1558
1559	//{{{ setMainContent() method
1560	private void setMainContent(Component c)
1561	{
1562		if (mainContent != null)
1563			mainPanel.remove(mainContent);
1564		mainContent = c;
1565		mainPanel.add(mainContent, BorderLayout.CENTER);
1566		if (c instanceof JSplitPane)
1567		{
1568			splitPane = (JSplitPane)c;	
1569		}
1570		else
1571		{
1572			splitPane = null;
1573			editPane = (EditPane)c;
1574		}
1575		mainPanel.revalidate();
1576		mainPanel.repaint();
1577	} //}}}
1578
1579	//{{{ getEditPanes() method
1580	private static void getEditPanes(List<EditPane> vec, Component comp)
1581	{
1582		if(comp instanceof EditPane)
1583			vec.add((EditPane) comp);
1584		else if(comp instanceof JSplitPane)
1585		{
1586			JSplitPane split = (JSplitPane)comp;
1587			getEditPanes(vec,split.getLeftComponent());
1588			getEditPanes(vec,split.getRightComponent());
1589		}
1590	} //}}}
1591
1592	//{{{ showBuffer() method
1593	private EditPane showBuffer(Buffer buffer, boolean focus)
1594	{
1595		if(editPane.getBuffer() == buffer
1596			&& editPane.getTextArea().getVisibleLines() > 1)
1597		{
1598			if (focus)
1599				editPane.focusOnTextArea();
1600			return editPane;
1601		}
1602
1603		EditPane[] editPanes = getEditPanes();
1604		for(int i = 0; i < editPanes.length; i++)
1605		{
1606			EditPane ep = editPanes[i];
1607			if(ep.getBuffer() == buffer
1608				/* ignore zero-height splits, etc */
1609				&& ep.getTextArea().getVisibleLines() > 1)
1610			{
1611				setEditPane(ep);
1612				if (focus)
1613					ep.focusOnTextArea();
1614				return ep;
1615			}
1616		}
1617
1618		setBuffer(buffer,false, focus);
1619		return editPane;
1620	} //}}}
1621
1622	//{{{ getSplitConfig() method
1623	/*
1624	 * The split config is recorded in a simple RPN "language".
1625	 */
1626	private static void getSplitConfig(JSplitPane splitPane,
1627		StringBuilder splitConfig)
1628	{
1629		Component right = splitPane.getRightComponent();
1630		appendToSplitConfig(splitConfig, right);
1631
1632		splitConfig.append(' ');
1633
1634		Component left = splitPane.getLeftComponent();
1635		appendToSplitConfig(splitConfig, left);
1636
1637		splitConfig.append(' ');
1638		splitConfig.append(splitPane.getDividerLocation());
1639		splitConfig.append(' ');
1640		splitConfig.append(splitPane.getOrientation()
1641			== JSplitPane.VERTICAL_SPLIT ? "vertical" : "horizontal");
1642	} //}}}
1643
1644	//{{{ appendToSplitConfig() method
1645	/**
1646	 * Append the Component to the split config.
1647	 * The component must be a JSplitPane or an EditPane
1648	 *
1649	 * @param splitConfig the split config
1650	 * @param component the component
1651	 */
1652	private static void appendToSplitConfig(StringBuilder splitConfig, Component component)
1653	{
1654		if(component instanceof JSplitPane)
1655		{
1656			// the component is a JSplitPane
1657			getSplitConfig((JSplitPane)component,splitConfig);
1658		}
1659		else
1660		{
1661			// the component is an editPane
1662			EditPane editPane = (EditPane) component;
1663			splitConfig.append('"');
1664			splitConfig.append(StandardUtilities.charsToEscapes(
1665				editPane.getBuffer().getPath()));
1666			splitConfig.append("\" buffer");
1667			BufferSet bufferSet = editPane.getBufferSet();
1668			Buffer[] buffers = bufferSet.getAllBuffers();
1669			for (Buffer buffer : buffers)
1670			{
1671				if (!buffer.isNewFile())
1672				{
1673					splitConfig.append(" \"");
1674					splitConfig.append(StandardUtilities.charsToEscapes(
1675						buffer.getPath()));
1676					splitConfig.append("\" buff");
1677				}
1678			}
1679			splitConfig.append(" \"");
1680			splitConfig.append(jEdit.getBufferSetManager().getScope());
1681			splitConfig.append("\" bufferset");
1682		}
1683	} //}}}
1684
1685	//{{{ restoreSplitConfig() method
1686	private Component restoreSplitConfig(Buffer buffer, String splitConfig)
1687		throws IOException
1688	// this is where checked exceptions piss me off. this method only uses
1689	// a StringReader which can never throw an exception...
1690	{
1691		if(buffer != null)
1692		{
1693			return editPane = createEditPane(buffer);
1694		}
1695		else if(splitConfig == null || splitConfig.trim().length() == 0)
1696		{
1697
1698			Buffer buf = jEdit.getFirstBuffer();
1699			if (buf == null)
1700			{
1701				buf = BufferSetManager.createUntitledBuffer();
1702			}
1703			return editPane = createEditPane(buf);
1704		}
1705		Buffer[] buffers = jEdit.getBuffers();
1706
1707		Stack<Object> stack = new Stack<Object>();
1708
1709		// we create a stream tokenizer for parsing a simple
1710		// stack-based language
1711		StreamTokenizer st = new StreamTokenizer(new StringReader(
1712			splitConfig));
1713		st.whitespaceChars(0,' ');
1714		/* all printable ASCII characters */
1715		st.wordChars('#','~');
1716		st.commentChar('!');
1717		st.quoteChar('"');
1718		st.eolIsSignificant(false);
1719		boolean continuousLayout = jEdit.getBooleanProperty("appearance.continuousLayout");
1720		List<Buffer> editPaneBuffers = new ArrayList<Buffer>();
1721loop:		while (true)
1722		{
1723			switch(st.nextToken())
1724			{
1725			case StreamTokenizer.TT_EOF:
1726				break loop;
1727			case StreamTokenizer.TT_WORD:
1728				if(st.sval.equals("vertical") ||
1729					st.sval.equals("horizontal"))
1730				{
1731					int orientation
1732						= st.sval.equals("vertical")
1733						? JSplitPane.VERTICAL_SPLIT
1734						: JSplitPane.HORIZONTAL_SPLIT;
1735					int divider = ((Integer)stack.pop())
1736						.intValue();
1737					Object obj1 = stack.pop();
1738					Object obj2 = stack.pop();
1739					// Backward compatibility with pre-bufferset versions
1740					if (obj1 instanceof Buffer)
1741					{
1742						Buffer b1 = buffer = (Buffer) obj1;
1743						obj1 = editPane = createEditPane(b1);
1744					}
1745					if (obj2 instanceof Buffer)
1746					{
1747						Buffer b2 = (Buffer) obj2;
1748						obj2 = createEditPane(b2);
1749					}
1750					stack.push(splitPane = new JSplitPane(
1751						orientation,
1752						continuousLayout,
1753						(Component)obj1,
1754						(Component)obj2));
1755					splitPane.setOneTouchExpandable(true);
1756					splitPane.setBorder(null);
1757					splitPane.setMinimumSize(
1758						new Dimension(0,0));
1759					splitPane.setDividerLocation(divider);
1760				}
1761				else if(st.sval.equals("buffer"))
1762				{
1763					Object obj = stack.pop();
1764					if(obj instanceof Integer)
1765					{
1766						int index = ((Integer)obj).intValue();
1767						if(index >= 0 && index < buffers.length)
1768							buffer = buffers[index];
1769					}
1770					else if(obj instanceof String)
1771					{
1772						String path = (String)obj;
1773						buffer = jEdit.getBuffer(path);
1774						if (buffer == null)
1775						{
1776							buffer = jEdit.openTemporary(jEdit.getActiveView(), null,
1777											    path, true, null);
1778							jEdit.commitTemporary(buffer);
1779						}
1780					}
1781
1782					if(buffer == null)
1783						buffer = jEdit.getFirstBuffer();
1784					stack.push(buffer);
1785					editPaneBuffers.add(buffer);
1786				}
1787				else if (st.sval.equals("buff"))
1788				{
1789					String path = (String)stack.pop();
1790					buffer = jEdit.getBuffer(path);
1791					if (buffer == null)
1792					{
1793						Log.log(Log.WARNING, this, "Buffer " + path + " doesn't exist");
1794					}
1795					else
1796					{
1797						editPaneBuffers.add(buffer);
1798					}
1799				}
1800				else if (st.sval.equals("bufferset"))
1801				{
1802					// pop the bufferset scope. Not used anymore but still here for compatibility
1803					// with old perspectives
1804					stack.pop();
1805					buffer = (Buffer) stack.pop();
1806					editPane = createEditPane(buffer);
1807					stack.push(editPane);
1808					BufferSet bufferSet = editPane.getBufferSet();
1809					int i = 0;
1810					for (Buffer buff : editPaneBuffers)
1811					{
1812						bufferSet.addBufferAt(buff,i);
1813						i++;
1814					}
1815					editPaneBuffers.clear();
1816				}
1817				break;
1818			case StreamTokenizer.TT_NUMBER:
1819				stack.push((int)st.nval);
1820				break;
1821			case '"':
1822				stack.push(st.sval);
1823				break;
1824			}
1825		}
1826
1827		// Backward compatibility with pre-bufferset versions
1828		Object obj = stack.peek();
1829		if (obj instanceof Buffer)
1830		{
1831			obj = editPane = createEditPane((Buffer)obj);
1832		}
1833
1834		updateGutterBorders();
1835
1836		return (Component)obj;
1837	} //}}}
1838
1839	//{{{ propertiesChanged() method
1840	/**
1841	 * Reloads various settings from the properties.
1842	 */
1843	private void propertiesChanged()
1844	{
1845		setJMenuBar(GUIUtilities.loadMenuBar("view.mbar"));
1846
1847		loadToolBars();
1848
1849		showFullPath = jEdit.getBooleanProperty("view.showFullPath");
1850		updateTitle();
1851
1852		status.propertiesChanged();
1853
1854		removeToolBar(status);
1855		getContentPane().remove(status);
1856
1857		boolean showStatus = plainView ? jEdit.getBooleanProperty("view.status.plainview.visible") :
1858				    jEdit.getBooleanProperty("view.status.visible");
1859		if (jEdit.getBooleanProperty("view.toolbar.alternateLayout"))
1860		{
1861			getContentPane().add(BorderLayout.NORTH,topToolBars);
1862			getContentPane().add(BorderLayout.SOUTH,bottomToolBars);
1863			if (showStatus)
1864				addToolBar(BOTTOM_GROUP,STATUS_BAR_LAYER,status);
1865		}
1866		else
1867		{
1868			mainPanel.add(topToolBars, BorderLayout.NORTH);
1869			mainPanel.add(bottomToolBars, BorderLayout.SOUTH);
1870			if (showStatus)
1871				getContentPane().add(BorderLayout.SOUTH,status);
1872		}
1873		updateBufferSwitcherStates();
1874
1875		getRootPane().revalidate();
1876
1877		if (splitPane != null)
1878			GUIUtilities.initContinuousLayout(splitPane);
1879		//SwingUtilities.updateComponentTreeUI(getRootPane());
1880
1881		if (fullScreenMode)
1882			updateFullScreenProps();
1883	} //}}}
1884
1885	//{{{ updateBufferSwitcherStates() method
1886	/**
1887	 * Enables or Disables the "Focus Buffer Switcher" menu item in the View menu
1888	 * depending on the visible state of the buffer switcher.  The menu item
1889	 * is intended to have the same effect as clicking on the buffer switcher
1890	 * combo box, and it doesn't make sense to have this action available if
1891	 * the buffer switcher isn't visible.
1892	 * Also shows or hides the Buffer Switcher itself, since this can be invoked after
1893	 * the toggle buffer switcher action.
1894	 */
1895	public void updateBufferSwitcherStates()
1896	{
1897		boolean show = jEdit.getBooleanProperty("view.showBufferSwitcher");
1898		JMenuBar menubar = getJMenuBar();
1899		if (menubar == null)
1900		{
1901			return;
1902		}
1903		String viewmenu_label = jEdit.getProperty("view.label");
1904		viewmenu_label = viewmenu_label.replace("$", "");
1905		String sbs_label = jEdit.getProperty("focus-buffer-switcher.label");
1906		sbs_label = sbs_label.replace("$", "");
1907		JMenu viewmenu = null;
1908		for (int i = 0; i < menubar.getMenuCount(); i++)
1909		{
1910			JMenu menu = menubar.getMenu(i);
1911			if (menu.getText().equals(viewmenu_label))
1912			{
1913				viewmenu = menu;
1914				break;
1915			}
1916		}
1917		if (viewmenu != null)
1918		{
1919			for (int i = 0; i < viewmenu.getMenuComponentCount(); i++)
1920			{
1921				Component item = viewmenu.getMenuComponent(i);
1922				if (item instanceof JMenuItem && ((JMenuItem)item).getText().equals(sbs_label))
1923				{
1924					item.setEnabled(show);
1925					// viewmenu.invalidate();
1926				}
1927			}
1928		}
1929		// Toggle the visibility of the BufferSwitcher itself
1930		for (View v: jEdit.getViews())
1931			for (EditPane ep: v.getEditPanes())
1932				ep.loadBufferSwitcher();
1933	} //}}}
1934
1935
1936	//{{{ loadToolBars() method
1937	private void loadToolBars()
1938	{
1939		if((! plainView) && (fullScreenMode ?
1940			jEdit.getBooleanProperty("fullScreenIncludesToolbar") :
1941			jEdit.getBooleanProperty("view.showToolbar")))
1942		{
1943			if(toolBar != null)
1944				toolBarManager.removeToolBar(toolBar);
1945
1946			toolBar = GUIUtilities.loadToolBar("view.toolbar");
1947
1948			addToolBar(TOP_GROUP, SYSTEM_BAR_LAYER, toolBar);
1949		}
1950		else if(toolBar != null)
1951		{
1952			removeToolBar(toolBar);
1953			toolBar = null;
1954		}
1955
1956		if(searchBar != null)
1957		{
1958			searchBar.propertiesChanged();
1959			removeToolBar(searchBar);
1960		}
1961
1962		if(jEdit.getBooleanProperty("view.showSearchbar") && !plainView)
1963		{
1964			if(searchBar == null)
1965				searchBar = new SearchBar(this,false);
1966			addToolBar(TOP_GROUP,SEARCH_BAR_LAYER,searchBar);
1967		}
1968	} //}}}
1969
1970	//{{{ createEditPane() methods
1971	private EditPane cre

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