PageRenderTime 136ms CodeModel.GetById 59ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 0ms

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

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