Package org.gjt.sp.jedit

Source Code of org.gjt.sp.jedit.View$ViewConfig

/*
* View.java - jEdit view
* :tabSize=8:indentSize=8:noTabs=false:
* :folding=explicit:collapseFolds=1:
*
* Copyright (C) 1998, 2003 Slava Pestov
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

package org.gjt.sp.jedit;

//{{{ Imports
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.net.Socket;
import java.util.*;
import org.gjt.sp.jedit.msg.*;
import org.gjt.sp.jedit.gui.*;
import org.gjt.sp.jedit.search.*;
import org.gjt.sp.jedit.textarea.*;
import org.gjt.sp.util.Log;
//}}}

/**
* A <code>View</code> is jEdit's top-level frame window.<p>
*
* In a BeanShell script, you can obtain the current view instance from the
* <code>view</code> variable.<p>
*
* The largest component it contains is an {@link EditPane} that in turn
* contains a {@link org.gjt.sp.jedit.textarea.JEditTextArea} that displays a
* {@link Buffer}.
* A view can have more than one edit pane in a split window configuration.
* A view also contains a menu bar, an optional toolbar and other window
* decorations, as well as docked windows.<p>
*
* The <b>View</b> class performs two important operations
* dealing with plugins: creating plugin menu items, and managing dockable
* windows.
*
* <ul>
* <li>When a view is being created, its initialization routine
* iterates through the collection of loaded plugins and constructs the
* <b>Plugins</b> menu using the properties as specified in the
* {@link EditPlugin} class.</li>
* <li>The view also creates and initializes a
* {@link org.gjt.sp.jedit.gui.DockableWindowManager}
* object.  This object is
* responsible for creating, closing and managing dockable windows.</li>
* </ul>
*
* This class does not have a public constructor.
* Views can be opened and closed using methods in the <code>jEdit</code>
* class.
*
* @see org.gjt.sp.jedit.jEdit#newView(View)
* @see org.gjt.sp.jedit.jEdit#newView(View,Buffer)
* @see org.gjt.sp.jedit.jEdit#newView(View,Buffer,boolean)
* @see org.gjt.sp.jedit.jEdit#closeView(View)
*
* @author Slava Pestov
* @author John Gellene (API documentation)
* @version $Id: View.java,v 1.111 2004/05/06 22:35:11 spestov Exp $
*/
public class View extends JFrame implements EBComponent
{
  //{{{ User interface

  //{{{ ToolBar-related constants

  //{{{ Groups
  /**
   * The group of tool bars above the DockableWindowManager
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int TOP_GROUP = 0;

  /**
   * The group of tool bars below the DockableWindowManager
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int BOTTOM_GROUP = 1;
  public static final int DEFAULT_GROUP = TOP_GROUP;
  //}}}

  //{{{ Layers

  // Common layers
  /**
   * The highest possible layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int TOP_LAYER = Integer.MAX_VALUE;

  /**
   * The default layer for tool bars with no preference.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int DEFAULT_LAYER = 0;

  /**
   * The lowest possible layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int BOTTOM_LAYER = Integer.MIN_VALUE;

  // Layers for top group
  /**
   * Above system tool bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int ABOVE_SYSTEM_BAR_LAYER = 150;

  /**
   * System tool bar layer.
   * jEdit uses this for the main tool bar.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int SYSTEM_BAR_LAYER = 100;

  /**
   * Below system tool bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int BELOW_SYSTEM_BAR_LAYER = 75;

  /**
   * Search bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int SEARCH_BAR_LAYER = 75;

  /**
   * Below search bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.0pre7
   */
  public static final int BELOW_SEARCH_BAR_LAYER = 50;

  // Layers for bottom group
  /**
   * @deprecated Status bar no longer added as a tool bar.
   */
  public static final int ABOVE_ACTION_BAR_LAYER = -50;

  /**
   * Action bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.2pre1
   */
  public static final int ACTION_BAR_LAYER = -75;

  /**
   * Status bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.2pre1
   */
  public static final int STATUS_BAR_LAYER = -100;

  /**
   * Status bar layer.
   * @see #addToolBar(int,int,java.awt.Component)
   * @since jEdit 4.2pre1
   */
  public static final int BELOW_STATUS_BAR_LAYER = -150;
  //}}}

  //}}}

  //{{{ getDockableWindowManager() method
  /**
   * Returns the dockable window manager associated with this view.
   * @since jEdit 2.6pre3
   */
  public DockableWindowManager getDockableWindowManager()
  {
    return dockableWindowManager;
  } //}}}

  //{{{ getToolBar() method
  /**
   * Returns the view's tool bar.
   * @since jEdit 4.2pre1
   */
  public Box getToolBar()
  {
    return toolBar;
  } //}}}

  //{{{ addToolBar() method
  /**
   * Adds a tool bar to this view.
   * @param toolBar The tool bar
   */
  public void addToolBar(Component toolBar)
  {
    addToolBar(DEFAULT_GROUP, DEFAULT_LAYER, toolBar);
  } //}}}

  //{{{ addToolBar() method
  /**
   * Adds a tool bar to this view.
   * @param group The tool bar group to add to
   * @param toolBar The tool bar
   * @see org.gjt.sp.jedit.gui.ToolBarManager
   * @since jEdit 4.0pre7
   */
  public void addToolBar(int group, Component toolBar)
  {
    addToolBar(group, DEFAULT_LAYER, toolBar);
  } //}}}

  //{{{ addToolBar() method
  /**
   * Adds a tool bar to this view.
   * @param group The tool bar group to add to
   * @param layer The layer of the group to add to
   * @param toolBar The tool bar
   * @see org.gjt.sp.jedit.gui.ToolBarManager
   * @since jEdit 4.0pre7
   */
  public void addToolBar(int group, int layer, Component toolBar)
  {
    toolBarManager.addToolBar(group, layer, toolBar);
    getRootPane().revalidate();
  } //}}}

  //{{{ removeToolBar() method
  /**
   * Removes a tool bar from this view.
   * @param toolBar The tool bar
   */
  public void removeToolBar(Component toolBar)
  {
    toolBarManager.removeToolBar(toolBar);
    getRootPane().revalidate();
  } //}}}

  //{{{ showWaitCursor() method
  /**
   * Shows the wait cursor. This method and
   * {@link #hideWaitCursor()} are implemented using a reference
   * count of requests for wait cursors, so that nested calls work
   * correctly; however, you should be careful to use these methods in
   * tandem.<p>
   *
   * To ensure that {@link #hideWaitCursor()} is always called
   * after a {@link #showWaitCursor()}, use a
   * <code>try</code>/<code>finally</code> block, like this:
   * <pre>try
   *{
   *    view.showWaitCursor();
   *    // ...
   *}
   *finally
   *{
   *    view.hideWaitCursor();
   *}</pre>
   */
  public synchronized void showWaitCursor()
  {
    if(waitCount++ == 0)
    {
      Cursor cursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
      setCursor(cursor);
      EditPane[] editPanes = getEditPanes();
      for(int i = 0; i < editPanes.length; i++)
      {
        EditPane editPane = editPanes[i];
        editPane.getTextArea().getPainter()
          .setCursor(cursor);
      }
    }
  } //}}}

  //{{{ hideWaitCursor() method
  /**
   * Hides the wait cursor.
   */
  public synchronized void hideWaitCursor()
  {
    if(waitCount > 0)
      waitCount--;

    if(waitCount == 0)
    {
      // still needed even though glass pane
      // has a wait cursor
      Cursor cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
      setCursor(cursor);
      cursor = Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR);
      EditPane[] editPanes = getEditPanes();
      for(int i = 0; i < editPanes.length; i++)
      {
        EditPane editPane = editPanes[i];
        editPane.getTextArea().getPainter()
          .setCursor(cursor);
      }
    }
  } //}}}

  //{{{ getSearchBar() method
  /**
   * Returns the search bar.
   * @since jEdit 2.4pre4
   */
  public final SearchBar getSearchBar()
  {
    return searchBar;
  } //}}}

  //{{{ getActionBar() method
  /**
   * Returns the action bar.
   * @since jEdit 4.2pre3
   */
  public final ActionBar getActionBar()
  {
    return actionBar;
  } //}}}

  //{{{ getStatus() method
  /**
   * Returns the status bar. The
   * {@link org.gjt.sp.jedit.gui.StatusBar#setMessage(String)} and
   * {@link org.gjt.sp.jedit.gui.StatusBar#setMessageAndClear(String)} methods can
   * be called on the return value of this method to display status
   * information to the user.
   * @since jEdit 3.2pre2
   */
  public StatusBar getStatus()
  {
    return status;
  } //}}}

  //{{{ quickIncrementalSearch() method
  /**
   * Quick search.
   * @since jEdit 4.0pre3
   */
  public void quickIncrementalSearch(boolean word)
  {
    if(searchBar == null)
      searchBar = new SearchBar(this,true);
    if(searchBar.getParent() == null)
      addToolBar(TOP_GROUP,SEARCH_BAR_LAYER,searchBar);

    searchBar.setHyperSearch(false);

    JEditTextArea textArea = getTextArea();

    if(word)
    {
      String text = textArea.getSelectedText();
      if(text == null)
      {
        textArea.selectWord();
        text = textArea.getSelectedText();
      }
      else if(text.indexOf('\n') != -1)
        text = null;

      searchBar.getField().setText(text);
    }

    searchBar.getField().requestFocus();
    searchBar.getField().selectAll();
  } //}}}

  //{{{ quickHyperSearch() method
  /**
   * Quick HyperSearch.
   * @since jEdit 4.0pre3
   */
  public void quickHyperSearch(boolean word)
  {
    JEditTextArea textArea = getTextArea();

    if(word)
    {
      String text = textArea.getSelectedText();
      if(text == null)
      {
        textArea.selectWord();
        text = textArea.getSelectedText();
      }

      if(text != null && text.indexOf('\n') == -1)
      {
        HistoryModel.getModel("find").addItem(text);
        SearchAndReplace.setSearchString(text);
        SearchAndReplace.setSearchFileSet(new CurrentBufferSet());
        SearchAndReplace.hyperSearch(this);

        return;
      }
    }

    if(searchBar == null)
      searchBar = new SearchBar(this,true);
    if(searchBar.getParent() == null)
      addToolBar(TOP_GROUP,SEARCH_BAR_LAYER,searchBar);

    searchBar.setHyperSearch(true);
    searchBar.getField().setText(null);
    searchBar.getField().requestFocus();
    searchBar.getField().selectAll();
  } //}}}

  //{{{ actionBar() method
  /**
   * Shows the action bar if needed, and sends keyboard focus there.
   * @since jEdit 4.2pre1
   */
  public void actionBar()
  {
    if(actionBar == null)
      actionBar = new ActionBar(this,true);
    if(actionBar.getParent() == null)
      addToolBar(BOTTOM_GROUP,ACTION_BAR_LAYER,actionBar);

    actionBar.goToActionBar();
  } //}}}

  //}}}

  //{{{ Input handling

  //{{{ getKeyEventInterceptor() method
  /**
   * Returns the listener that will handle all key events in this
   * view, if any.
   */
  public KeyListener getKeyEventInterceptor()
  {
    return keyEventInterceptor;
  } //}}}

  //{{{ setKeyEventInterceptor() method
  /**
   * Sets the listener that will handle all key events in this
   * view. For example, the complete word command uses this so
   * that all key events are passed to the word list popup while
   * it is visible.
   * @param listener The key event interceptor.
   */
  public void setKeyEventInterceptor(KeyListener listener)
  {
    this.keyEventInterceptor = listener;
  } //}}}

  //{{{ getInputHandler() method
  /**
   * Returns the input handler.
   */
  public InputHandler getInputHandler()
  {
    return inputHandler;
  } //}}}

  //{{{ setInputHandler() method
  /**
   * Sets the input handler.
   * @param inputHandler The new input handler
   */
  public void setInputHandler(InputHandler inputHandler)
  {
    this.inputHandler = inputHandler;
  } //}}}

  //{{{ getMacroRecorder() method
  /**
   * Returns the macro recorder.
   */
  public Macros.Recorder getMacroRecorder()
  {
    return recorder;
  } //}}}

  //{{{ setMacroRecorder() method
  /**
   * Sets the macro recorder.
   * @param recorder The macro recorder
   */
  public void setMacroRecorder(Macros.Recorder recorder)
  {
    this.recorder = recorder;
  } //}}}

  //{{{ processKeyEvent() method
  /**
   * Forwards key events directly to the input handler.
   * This is slightly faster than using a KeyListener
   * because some Swing overhead is avoided.
   */
  public void processKeyEvent(KeyEvent evt)
  {
    processKeyEvent(evt,VIEW);
  } //}}}

  //{{{ processKeyEvent() method
  /**
   * Forwards key events directly to the input handler.
   * This is slightly faster than using a KeyListener
   * because some Swing overhead is avoided.
   */
  public void processKeyEvent(KeyEvent evt, boolean calledFromTextArea)
  {
    processKeyEvent(evt,calledFromTextArea
      ? TEXT_AREA
      : VIEW);
  } //}}}

  //{{{ processKeyEvent() method
  public static final int VIEW = 0;
  public static final int TEXT_AREA = 1;
  public static final int ACTION_BAR = 2;
  /**
   * Forwards key events directly to the input handler.
   * This is slightly faster than using a KeyListener
   * because some Swing overhead is avoided.
   */
  public void processKeyEvent(KeyEvent evt, int from)
  {
    if(Debug.DUMP_KEY_EVENTS && from != VIEW)
    {
      Log.log(Log.DEBUG,this,"Key event: "
        + GrabKeyDialog.toString(evt));
    }

    if(getTextArea().hasFocus() && from == VIEW)
      return;

    evt = _preprocessKeyEvent(evt);
    if(evt == null)
      return;

    if(Debug.DUMP_KEY_EVENTS && from != VIEW)
    {
      Log.log(Log.DEBUG,this,"Key event after workaround: "
        + GrabKeyDialog.toString(evt));
    }

    switch(evt.getID())
    {
    case KeyEvent.KEY_TYPED:
      boolean focusOnTextArea = false;
      // if the user pressed eg C+e n n in the
      // search bar we want focus to go back there
      // after the prefix is done
      if(prefixFocusOwner != null)
      {
        if(prefixFocusOwner.isShowing())
        {
          prefixFocusOwner.requestFocus();
          focusOnTextArea = true;
        }
      }

      if(keyEventInterceptor != null)
        keyEventInterceptor.keyTyped(evt);
      else if(from == ACTION_BAR
        || inputHandler.isPrefixActive()
        || getTextArea().hasFocus())
      {
        KeyEventTranslator.Key keyStroke
          = KeyEventTranslator
          .translateKeyEvent(evt);
        if(keyStroke != null)
        {
          if(Debug.DUMP_KEY_EVENTS
            && from != VIEW)
          {
            Log.log(Log.DEBUG,this,
              "Translated: "
              + keyStroke);
          }
          if(inputHandler.handleKey(keyStroke))
            evt.consume();
        }
      }

      // we might have been closed as a result of
      // the above
      if(isClosed())
        return;

      // this is a weird hack.
      // we don't want C+e a to insert 'a' in the
      // search bar if the search bar has focus...
      if(inputHandler.isPrefixActive())
      {
        if(getFocusOwner() instanceof JTextComponent)
        {
          prefixFocusOwner = getFocusOwner();
          getTextArea().requestFocus();
        }
        else if(focusOnTextArea)
        {
          getTextArea().requestFocus();
        }
        else
        {
          prefixFocusOwner = null;
        }
      }
      else
      {
        prefixFocusOwner = null;
      }

      break;
    case KeyEvent.KEY_PRESSED:
      if(keyEventInterceptor != null)
        keyEventInterceptor.keyPressed(evt);
      else
      {
        /* boolean */ focusOnTextArea = false;
        if(prefixFocusOwner != null)
        {
          if(prefixFocusOwner.isShowing())
          {
            prefixFocusOwner.requestFocus();
            focusOnTextArea = true;
          }
          prefixFocusOwner = null;
        }

        KeyEventTranslator.Key keyStroke
          = KeyEventTranslator
          .translateKeyEvent(evt);
        if(keyStroke != null)
        {
          if(Debug.DUMP_KEY_EVENTS
            && from != VIEW)
          {
            Log.log(Log.DEBUG,this,
              "Translated: "
              + keyStroke);
          }
          if(inputHandler.handleKey(keyStroke))
            evt.consume();
        }

        // we might have been closed as a result of
        // the above
        if(isClosed())
          return;

        // this is a weird hack.
        // we don't want C+e a to insert 'a' in the
        // search bar if the search bar has focus...
        if(inputHandler.isPrefixActive())
        {
          if(getFocusOwner() instanceof JTextComponent)
          {
            prefixFocusOwner = getFocusOwner();
            getTextArea().requestFocus();
          }
          else if(focusOnTextArea)
          {
            getTextArea().requestFocus();
          }
          else
          {
            prefixFocusOwner = null;
          }
        }
        else
        {
          prefixFocusOwner = null;
        }
      }
      break;
    case KeyEvent.KEY_RELEASED:
      if(keyEventInterceptor != null)
        keyEventInterceptor.keyReleased(evt);
      break;
    }

    if(!evt.isConsumed())
      super.processKeyEvent(evt);
  } //}}}

  //}}}

  //{{{ Buffers, edit panes, split panes

  //{{{ splitHorizontally() method
  /**
   * Splits the view horizontally.
   * @since jEdit 4.1pre2
   */
  public EditPane splitHorizontally()
  {
    return split(JSplitPane.VERTICAL_SPLIT);
  } //}}}

  //{{{ splitVertically() method
  /**
   * Splits the view vertically.
   * @since jEdit 4.1pre2
   */
  public EditPane splitVertically()
  {
    return split(JSplitPane.HORIZONTAL_SPLIT);
  } //}}}

  //{{{ split() method
  /**
   * Splits the view.
   * @since jEdit 4.1pre2
   */
  public EditPane split(int orientation)
  {
    PerspectiveManager.setPerspectiveDirty(true);

    editPane.saveCaretInfo();
    EditPane oldEditPane = editPane;
    setEditPane(createEditPane(oldEditPane.getBuffer()));
    editPane.loadCaretInfo();

    JComponent oldParent = (JComponent)oldEditPane.getParent();

    final JSplitPane newSplitPane = new JSplitPane(orientation);
    newSplitPane.setOneTouchExpandable(true);
    newSplitPane.setBorder(null);
    newSplitPane.setMinimumSize(new Dimension(0,0));

    int parentSize = (orientation == JSplitPane.VERTICAL_SPLIT
      ? oldEditPane.getHeight() : oldEditPane.getWidth());
    final int dividerPosition = (int)((double)(parentSize
      - newSplitPane.getDividerSize()) * 0.5);
    newSplitPane.setDividerLocation(dividerPosition);

    if(oldParent instanceof JSplitPane)
    {
      JSplitPane oldSplitPane = (JSplitPane)oldParent;
      int dividerPos = oldSplitPane.getDividerLocation();

      Component left = oldSplitPane.getLeftComponent();

      if(left == oldEditPane)
        oldSplitPane.setLeftComponent(newSplitPane);
      else
        oldSplitPane.setRightComponent(newSplitPane);

      newSplitPane.setLeftComponent(oldEditPane);
      newSplitPane.setRightComponent(editPane);

      oldSplitPane.setDividerLocation(dividerPos);
    }
    else
    {
      this.splitPane = newSplitPane;

      newSplitPane.setLeftComponent(oldEditPane);
      newSplitPane.setRightComponent(editPane);

      oldParent.add(newSplitPane,0);
      oldParent.revalidate();
    }

    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        newSplitPane.setDividerLocation(dividerPosition);
      }
    });

    editPane.focusOnTextArea();

    return editPane;
  } //}}}

  //{{{ unsplit() method
  /**
   * Unsplits the view.
   * @since jEdit 2.3pre2
   */
  public void unsplit()
  {
    if(splitPane != null)
    {
      PerspectiveManager.setPerspectiveDirty(true);

      EditPane[] editPanes = getEditPanes();
      for(int i = 0; i < editPanes.length; i++)
      {
        EditPane _editPane = editPanes[i];
        if(editPane != _editPane)
          _editPane.close();
      }

      JComponent parent = (JComponent)splitPane.getParent();

      parent.remove(splitPane);
      parent.add(editPane,0);
      parent.revalidate();

      splitPane = null;
      updateTitle();

      editPane.focusOnTextArea();
    }
    else
      getToolkit().beep();
  } //}}}

  //{{{ unsplitCurrent() method
  /**
   * Removes the current split.
   * @since jEdit 2.3pre2
   */
  public void unsplitCurrent()
  {
    if(splitPane != null)
    {
      PerspectiveManager.setPerspectiveDirty(true);

      // find first split pane parenting current edit pane
      Component comp = editPane;
      while(!(comp instanceof JSplitPane))
      {
        comp = comp.getParent();
      }

      // get rid of any edit pane that is a child
      // of the current edit pane's parent splitter
      EditPane[] editPanes = getEditPanes();
      for(int i = 0; i < editPanes.length; i++)
      {
        EditPane _editPane = editPanes[i];
        if(GUIUtilities.isAncestorOf(comp,_editPane)
          && _editPane != editPane)
          _editPane.close();
      }

      JComponent parent = (JComponent)comp.getParent();

      if(parent instanceof JSplitPane)
      {
        JSplitPane parentSplit = (JSplitPane)parent;
        int pos = parentSplit.getDividerLocation();
        if(parentSplit.getLeftComponent() == comp)
          parentSplit.setLeftComponent(editPane);
        else
          parentSplit.setRightComponent(editPane);
        parentSplit.setDividerLocation(pos);
      }
      else
      {
        parent.remove(comp);
        parent.add(editPane,0);
        splitPane = null;
      }

      parent.revalidate();

      updateTitle();

      editPane.focusOnTextArea();
    }
    else
      getToolkit().beep();
  } //}}}

  //{{{ nextTextArea() method
  /**
   * Moves keyboard focus to the next text area.
   * @since jEdit 2.7pre4
   */
  public void nextTextArea()
  {
    EditPane[] editPanes = getEditPanes();
    for(int i = 0; i < editPanes.length; i++)
    {
      if(editPane == editPanes[i])
      {
        if(i == editPanes.length - 1)
          editPanes[0].focusOnTextArea();
        else
          editPanes[i+1].focusOnTextArea();
        break;
      }
    }
  } //}}}

  //{{{ prevTextArea() method
  /**
   * Moves keyboard focus to the previous text area.
   * @since jEdit 2.7pre4
   */
  public void prevTextArea()
  {
    EditPane[] editPanes = getEditPanes();
    for(int i = 0; i < editPanes.length; i++)
    {
      if(editPane == editPanes[i])
      {
        if(i == 0)
          editPanes[editPanes.length - 1].focusOnTextArea();
        else
          editPanes[i-1].focusOnTextArea();
        break;
      }
    }
  } //}}}

  //{{{ getSplitPane() method
  /**
   * Returns the top-level split pane, if any.
   * @since jEdit 2.3pre2
   */
  public JSplitPane getSplitPane()
  {
    return splitPane;
  } //}}}

  //{{{ getBuffer() method
  /**
   * Returns the current edit pane's buffer.
   */
  public Buffer getBuffer()
  {
    if(editPane == null)
      return null;
    else
      return editPane.getBuffer();
  } //}}}

  //{{{ setBuffer() method
  /**
   * Sets the current edit pane's buffer.
   */
  public void setBuffer(Buffer buffer)
  {
    editPane.setBuffer(buffer);
  } //}}}

  //{{{ goToBuffer() method
  /**
   * If this buffer is open in one of the view's edit panes, sets focus
   * to that edit pane. Otherwise, opens the buffer in the currently
   * active edit pane.
   * @param buffer The buffer
   * @since jEdit 4.2pre1
   */
  public EditPane goToBuffer(Buffer buffer)
  {
    if(editPane.getBuffer() == buffer)
    {
      editPane.focusOnTextArea();
      return editPane;
    }

    EditPane[] editPanes = getEditPanes();
    for(int i = 0; i < editPanes.length; i++)
    {
      EditPane ep = editPanes[i];
      if(ep.getBuffer() == buffer
        /* ignore zero-height splits, etc */
        && ep.getTextArea().getVisibleLines() > 1)
      {
        setEditPane(ep);
        ep.focusOnTextArea();
        return ep;
      }
    }
    setBuffer(buffer);
    return editPane;
  } //}}}

  //{{{ getTextArea() method
  /**
   * Returns the current edit pane's text area.
   */
  public JEditTextArea getTextArea()
  {
    if(editPane == null)
      return null;
    else
      return editPane.getTextArea();
  } //}}}

  //{{{ getEditPane() method
  /**
   * Returns the current edit pane.
   * @since jEdit 2.5pre2
   */
  public EditPane getEditPane()
  {
    return editPane;
  } //}}}

  //{{{ getEditPanes() method
  /**
   * Returns all edit panes.
   * @since jEdit 2.5pre2
   */
  public EditPane[] getEditPanes()
  {
    if(splitPane == null)
    {
      EditPane[] ep = { editPane };
      return ep;
    }
    else
    {
      Vector vec = new Vector();
      getEditPanes(vec,splitPane);
      EditPane[] ep = new EditPane[vec.size()];
      vec.copyInto(ep);
      return ep;
    }
  } //}}}

  //{{{ getViewConfig() method
  /**
   * @since jEdit 4.2pre1
   */
  public ViewConfig getViewConfig()
  {
    StringBuffer splitConfig = new StringBuffer();
    if(splitPane != null)
      getSplitConfig(splitPane,splitConfig);
    else
    {
      splitConfig.append('"');
      splitConfig.append(MiscUtilities.charsToEscapes(
        getBuffer().getPath()));
      splitConfig.append("\" buffer");
    }

    ViewConfig config = new ViewConfig();
    config.plainView = isPlainView();
    config.splitConfig = splitConfig.toString();
    config.x = getX();
    config.y = getY();
    config.width = getWidth();
    config.height = getHeight();
    config.extState = GUIUtilities.getExtendedState(this);

    config.top = dockableWindowManager.getTopDockingArea().getCurrent();
    config.left = dockableWindowManager.getLeftDockingArea().getCurrent();
    config.bottom = dockableWindowManager.getBottomDockingArea().getCurrent();
    config.right = dockableWindowManager.getRightDockingArea().getCurrent();

    config.topPos = dockableWindowManager.getTopDockingArea().getDimension();
    config.leftPos = dockableWindowManager.getLeftDockingArea().getDimension();
    config.bottomPos = dockableWindowManager.getBottomDockingArea().getDimension();
    config.rightPos = dockableWindowManager.getRightDockingArea().getDimension();

    return config;
  } //}}}

  //}}}

  //{{{ isClosed() method
  /**
   * Returns true if this view has been closed with
   * {@link jEdit#closeView(View)}.
   */
  public boolean isClosed()
  {
    return closed;
  } //}}}

  //{{{ isPlainView() method
  /**
   * Returns true if this is an auxilliary view with no dockable windows.
   * @since jEdit 4.1pre2
   */
  public boolean isPlainView()
  {
    return plainView;
  } //}}}

  //{{{ getNext() method
  /**
   * Returns the next view in the list.
   */
  public View getNext()
  {
    return next;
  } //}}}

  //{{{ getPrev() method
  /**
   * Returns the previous view in the list.
   */
  public View getPrev()
  {
    return prev;
  } //}}}

  //{{{ handleMessage() method
  public void handleMessage(EBMessage msg)
  {
    if(msg instanceof PropertiesChanged)
      propertiesChanged();
    else if(msg instanceof SearchSettingsChanged)
    {
      if(searchBar != null)
        searchBar.update();
    }
    else if(msg instanceof BufferUpdate)
      handleBufferUpdate((BufferUpdate)msg);
    else if(msg instanceof EditPaneUpdate)
      handleEditPaneUpdate((EditPaneUpdate)msg);
  } //}}}

  //{{{ getMinimumSize() method
  public Dimension getMinimumSize()
  {
    return new Dimension(0,0);
  } //}}}

  //{{{ setWaitSocket() method
  /**
   * This socket is closed when the buffer is closed.
   */
  public void setWaitSocket(Socket waitSocket)
  {
    this.waitSocket = waitSocket;
  } //}}}

  //{{{ toString() method
  public String toString()
  {
    return getClass().getName() + "["
      + (jEdit.getActiveView() == this
      ? "active" : "inactive")
      + "]";
  } //}}}

  //{{{ Package-private members
  View prev;
  View next;

  //{{{ View constructor
  View(Buffer buffer, ViewConfig config)
  {
    this.plainView = config.plainView;

    enableEvents(AWTEvent.KEY_EVENT_MASK);

    setIconImage(GUIUtilities.getEditorIcon());

    dockableWindowManager = new DockableWindowManager(this,config);

    topToolBars = new JPanel(new VariableGridLayout(
      VariableGridLayout.FIXED_NUM_COLUMNS,
      1));
    bottomToolBars = new JPanel(new VariableGridLayout(
      VariableGridLayout.FIXED_NUM_COLUMNS,
      1));

    toolBarManager = new ToolBarManager(topToolBars, bottomToolBars);

    status = new StatusBar(this);

    inputHandler = new DefaultInputHandler(this,(DefaultInputHandler)
      jEdit.getInputHandler());

    try
    {
      Component comp = restoreSplitConfig(buffer,config.splitConfig);
      dockableWindowManager.add(comp,0);
    }
    catch(IOException e)
    {
      // this should never throw an exception.
      throw new InternalError();
    }

    getContentPane().add(BorderLayout.CENTER,dockableWindowManager);

    dockableWindowManager.init();

    // tool bar and status bar gets added in propertiesChanged()
    // depending in the 'tool bar alternate layout' setting.
    propertiesChanged();

    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    addWindowListener(new WindowHandler());

    EditBus.addToBus(this);

    SearchDialog.preloadSearchDialog(this);
  } //}}}

  //{{{ close() method
  void close()
  {
    GUIUtilities.saveGeometry(this,plainView ? "plain-view" : "view");
    closed = true;

    // save dockable window geometry, and close 'em
    dockableWindowManager.close();

    EditBus.removeFromBus(this);
    dispose();

    EditPane[] editPanes = getEditPanes();
    for(int i = 0; i < editPanes.length; i++)
      editPanes[i].close();

    // null some variables so that retaining references
    // to closed views won't hurt as much.
    toolBarManager = null;
    toolBar = null;
    searchBar = null;
    splitPane = null;
    inputHandler = null;
    recorder = null;

    getContentPane().removeAll();

    // notify clients with -wait
    if(waitSocket != null)
    {
      try
      {
        waitSocket.getOutputStream().write('\0');
        waitSocket.getOutputStream().flush();
        waitSocket.getInputStream().close();
        waitSocket.getOutputStream().close();
        waitSocket.close();
      }
      catch(IOException io)
      {
        //Log.log(Log.ERROR,this,io);
      }
    }
  } //}}}

  //{{{ updateTitle() method
  /**
   * Updates the title bar.
   */
  void updateTitle()
  {
    Vector buffers = new Vector();
    EditPane[] editPanes = getEditPanes();
    for(int i = 0; i < editPanes.length; i++)
    {
      Buffer buffer = editPanes[i].getBuffer();
      if(buffers.indexOf(buffer) == -1)
        buffers.addElement(buffer);
    }

    StringBuffer title = new StringBuffer(jEdit.getProperty("view.title"));
    for(int i = 0; i < buffers.size(); i++)
    {
      if(i != 0)
        title.append(", ");

      Buffer buffer = (Buffer)buffers.elementAt(i);
      title.append((showFullPath && !buffer.isNewFile())
        ? buffer.getPath() : buffer.getName());
      if(buffer.isDirty())
        title.append(jEdit.getProperty("view.title.dirty"));
    }
    setTitle(title.toString());
  } //}}}

  //}}}

  //{{{ Private members

  //{{{ Instance variables
  private boolean closed;

  private DockableWindowManager dockableWindowManager;

  private JPanel topToolBars;
  private JPanel bottomToolBars;
  private ToolBarManager toolBarManager;

  private Box toolBar;
  private SearchBar searchBar;
  private ActionBar actionBar;

  private EditPane editPane;
  private JSplitPane splitPane;

  private StatusBar status;

  private KeyListener keyEventInterceptor;
  private InputHandler inputHandler;
  private Macros.Recorder recorder;
  private Component prefixFocusOwner;

  private int waitCount;

  private boolean showFullPath;

  private boolean plainView;

  private Socket waitSocket;
  //}}}

  //{{{ getEditPanes() method
  private void getEditPanes(Vector vec, Component comp)
  {
    if(comp instanceof EditPane)
      vec.addElement(comp);
    else if(comp instanceof JSplitPane)
    {
      JSplitPane split = (JSplitPane)comp;
      getEditPanes(vec,split.getLeftComponent());
      getEditPanes(vec,split.getRightComponent());
    }
  } //}}}

  //{{{ getSplitConfig() method
  /*
   * The split config is recorded in a simple RPN "language".
   */
  private void getSplitConfig(JSplitPane splitPane,
    StringBuffer splitConfig)
  {
    Component right = splitPane.getRightComponent();
    if(right instanceof JSplitPane)
      getSplitConfig((JSplitPane)right,splitConfig);
    else
    {
      splitConfig.append('"');
      splitConfig.append(MiscUtilities.charsToEscapes(
        ((EditPane)right).getBuffer().getPath()));
      splitConfig.append("\" buffer");
    }

    splitConfig.append(' ');

    Component left = splitPane.getLeftComponent();
    if(left instanceof JSplitPane)
      getSplitConfig((JSplitPane)left,splitConfig);
    else
    {
      splitConfig.append('"');
      splitConfig.append(MiscUtilities.charsToEscapes(
        ((EditPane)left).getBuffer().getPath()));
      splitConfig.append("\" buffer");
    }

    splitConfig.append(' ');
    splitConfig.append(splitPane.getDividerLocation());
    splitConfig.append(' ');
    splitConfig.append(splitPane.getOrientation()
      == JSplitPane.VERTICAL_SPLIT ? "vertical" : "horizontal");
  } //}}}

  //{{{ restoreSplitConfig() method
  private Component restoreSplitConfig(Buffer buffer, String splitConfig)
    throws IOException
  // this is where checked exceptions piss me off. this method only uses
  // a StringReader which can never throw an exception...
  {
    if(buffer != null)
      return (editPane = createEditPane(buffer));
    else if(splitConfig == null)
      return (editPane = createEditPane(jEdit.getFirstBuffer()));

    Buffer[] buffers = jEdit.getBuffers();

    Stack stack = new Stack();

    // we create a stream tokenizer for parsing a simple
    // stack-based language
    StreamTokenizer st = new StreamTokenizer(new StringReader(
      splitConfig));
    st.whitespaceChars(0,' ');
    /* all printable ASCII characters */
    st.wordChars('#','~');
    st.commentChar('!');
    st.quoteChar('"');
    st.eolIsSignificant(false);

loop:    for(;;)
    {
      switch(st.nextToken())
      {
      case StreamTokenizer.TT_EOF:
        break loop;
      case StreamTokenizer.TT_WORD:
        if(st.sval.equals("vertical") ||
          st.sval.equals("horizontal"))
        {
          int orientation
            = (st.sval.equals("vertical")
            ? JSplitPane.VERTICAL_SPLIT
            : JSplitPane.HORIZONTAL_SPLIT);
          int divider = ((Integer)stack.pop())
            .intValue();
          stack.push(splitPane = new JSplitPane(
            orientation,
            (Component)stack.pop(),
            (Component)stack.pop()));
          splitPane.setOneTouchExpandable(true);
          splitPane.setBorder(null);
          splitPane.setMinimumSize(
            new Dimension(0,0));
          splitPane.setDividerLocation(divider);
        }
        else if(st.sval.equals("buffer"))
        {
          Object obj = stack.pop();
          if(obj instanceof Integer)
          {
            int index = ((Integer)obj).intValue();
            if(index >= 0 && index < buffers.length)
              buffer = buffers[index];
          }
          else if(obj instanceof String)
          {
            String path = (String)obj;
            buffer = jEdit.getBuffer(path);
          }

          if(buffer == null)
            buffer = jEdit.getFirstBuffer();

          stack.push(editPane = createEditPane(
            buffer));
        }
        break;
      case StreamTokenizer.TT_NUMBER:
        stack.push(new Integer((int)st.nval));
        break;
      case '"':
        stack.push(st.sval);
        break;
      }
    }

    updateGutterBorders();

    return (Component)stack.peek();
  } //}}}

  //{{{ propertiesChanged() method
  /**
   * Reloads various settings from the properties.
   */
  private void propertiesChanged()
  {
    setJMenuBar(GUIUtilities.loadMenuBar("view.mbar"));

    loadToolBars();

    showFullPath = jEdit.getBooleanProperty("view.showFullPath");
    updateTitle();

    status.propertiesChanged();

    removeToolBar(status);
    getContentPane().remove(status);

    if(jEdit.getBooleanProperty("view.toolbar.alternateLayout"))
    {
      getContentPane().add(BorderLayout.NORTH,topToolBars);
      getContentPane().add(BorderLayout.SOUTH,bottomToolBars);
      if(!plainView && jEdit.getBooleanProperty("view.status.visible"))
        addToolBar(BOTTOM_GROUP,STATUS_BAR_LAYER,status);
    }
    else
    {
      dockableWindowManager.add(topToolBars,
        DockableWindowManager.DockableLayout
        .TOP_TOOLBARS,0);
      dockableWindowManager.add(bottomToolBars,
        DockableWindowManager.DockableLayout
        .BOTTOM_TOOLBARS,0);
      if(!plainView && jEdit.getBooleanProperty("view.status.visible"))
        getContentPane().add(BorderLayout.SOUTH,status);
    }

    getRootPane().revalidate();

    //SwingUtilities.updateComponentTreeUI(getRootPane());
  } //}}}

  //{{{ loadToolBars() method
  private void loadToolBars()
  {
    if(jEdit.getBooleanProperty("view.showToolbar") && !plainView)
    {
      if(toolBar != null)
        toolBarManager.removeToolBar(toolBar);

      toolBar = GUIUtilities.loadToolBar("view.toolbar");

      addToolBar(TOP_GROUP, SYSTEM_BAR_LAYER, toolBar);
    }
    else if(toolBar != null)
    {
      removeToolBar(toolBar);
      toolBar = null;
    }

    if(searchBar != null)
      removeToolBar(searchBar);

    if(jEdit.getBooleanProperty("view.showSearchbar") && !plainView)
    {
      if(searchBar == null)
        searchBar = new SearchBar(this,false);
      searchBar.propertiesChanged();
      addToolBar(TOP_GROUP,SEARCH_BAR_LAYER,searchBar);
    }
  } //}}}

  //{{{ createEditPane() method
  private EditPane createEditPane(Buffer buffer)
  {
    EditPane editPane = new EditPane(this,buffer);
    JEditTextArea textArea = editPane.getTextArea();
    textArea.addFocusListener(new FocusHandler());
    textArea.addCaretListener(new CaretHandler());
    textArea.addScrollListener(new ScrollHandler());
    EditBus.send(new EditPaneUpdate(editPane,EditPaneUpdate.CREATED));
    return editPane;
  } //}}}

  //{{{ setEditPane() method
  private void setEditPane(EditPane editPane)
  {
    this.editPane = editPane;
    status.updateCaretStatus();
    status.updateBufferStatus();
    status.updateMiscStatus();

    // repaint the gutter so that the border color
    // reflects the focus state
    updateGutterBorders();

    EditBus.send(new ViewUpdate(this,ViewUpdate.EDIT_PANE_CHANGED));
  } //}}}

  //{{{ handleBufferUpdate() method
  private void handleBufferUpdate(BufferUpdate msg)
  {
    Buffer buffer = msg.getBuffer();
    if(msg.getWhat() == BufferUpdate.DIRTY_CHANGED
      || msg.getWhat() == BufferUpdate.LOADED)
    {
      EditPane[] editPanes = getEditPanes();
      for(int i = 0; i < editPanes.length; i++)
      {
        if(editPanes[i].getBuffer() == buffer)
        {
          updateTitle();
          break;
        }
      }
    }
  } //}}}

  //{{{ handleEditPaneUpdate() method
  private void handleEditPaneUpdate(EditPaneUpdate msg)
  {
    EditPane editPane = msg.getEditPane();
    if(editPane.getView() == this
      && msg.getWhat() == EditPaneUpdate.BUFFER_CHANGED
      && editPane.getBuffer().isLoaded())
    {
      status.updateCaretStatus();
      status.updateBufferStatus();
      status.updateMiscStatus();
    }
  } //}}}

  //{{{ updateGutterBorders() method
  /**
   * Updates the borders of all gutters in this view to reflect the
   * currently focused text area.
   * @since jEdit 2.6final
   */
  private void updateGutterBorders()
  {
    EditPane[] editPanes = getEditPanes();
    for(int i = 0; i < editPanes.length; i++)
      editPanes[i].getTextArea().getGutter().updateBorder();
  } //}}}

  //{{{ _preprocessKeyEvent() method
  private KeyEvent _preprocessKeyEvent(KeyEvent evt)
  {
    if(isClosed())
      return null;

    if(getFocusOwner() instanceof JComponent)
    {
      JComponent comp = (JComponent)getFocusOwner();
      InputMap map = comp.getInputMap();
      ActionMap am = comp.getActionMap();

      if(map != null && am != null && comp.isEnabled())
      {
        Object binding = map.get(KeyStroke.getKeyStrokeForEvent(evt));
        if(binding != null && am.get(binding) != null)
        {
          return null;
        }
      }
    }

    if(getFocusOwner() instanceof JTextComponent)
    {
      // fix for the bug where key events in JTextComponents
      // inside views are also handled by the input handler
      if(evt.getID() == KeyEvent.KEY_PRESSED)
      {
        switch(evt.getKeyCode())
        {
        case KeyEvent.VK_ENTER:
        case KeyEvent.VK_TAB:
        case KeyEvent.VK_BACK_SPACE:
        case KeyEvent.VK_SPACE:
          return null;
        }
      }
    }

    if(evt.isConsumed())
      return null;

    return KeyEventWorkaround.processKeyEvent(evt);
  } //}}}

  //}}}

  //{{{ Inner classes

  //{{{ CaretHandler class
  class CaretHandler implements CaretListener
  {
    public void caretUpdate(CaretEvent evt)
    {
      if(evt.getSource() == getTextArea())
        status.updateCaretStatus();
    }
  } //}}}

  //{{{ FocusHandler class
  class FocusHandler extends FocusAdapter
  {
    public void focusGained(FocusEvent evt)
    {
      // walk up hierarchy, looking for an EditPane
      Component comp = (Component)evt.getSource();
      while(!(comp instanceof EditPane))
      {
        if(comp == null)
          return;

        comp = comp.getParent();
      }

      if(comp != editPane)
        setEditPane((EditPane)comp);
      else
        updateGutterBorders();
    }
  } //}}}

  //{{{ ScrollHandler class
  class ScrollHandler implements ScrollListener
  {
    public void scrolledVertically(JEditTextArea textArea)
    {
      if(getTextArea() == textArea)
        status.updateCaretStatus();
    }

    public void scrolledHorizontally(JEditTextArea textArea) {}
  } //}}}

  //{{{ WindowHandler class
  class WindowHandler extends WindowAdapter
  {
    public void windowActivated(WindowEvent evt)
    {
      jEdit.setActiveView(View.this);

      // People have reported hangs with JDK 1.4; might be
      // caused by modal dialogs being displayed from
      // windowActivated()
      SwingUtilities.invokeLater(new Runnable()
      {
        public void run()
        {
          jEdit.checkBufferStatus(View.this);
        }
      });
    }

    public void windowClosing(WindowEvent evt)
    {
      jEdit.closeView(View.this);
    }
  } //}}}

  //{{{ ViewConfig class
  public static class ViewConfig
  {
    public boolean plainView;
    public String splitConfig;
    public int x, y, width, height, extState;

    // dockables
    public String top, left, bottom, right;
    public int topPos, leftPos, bottomPos, rightPos;

    public ViewConfig()
    {
    }

    public ViewConfig(boolean plainView)
    {
      this.plainView = plainView;
      String prefix = (plainView ? "plain-view" : "view");
      x = jEdit.getIntegerProperty(prefix + ".x",0);
      y = jEdit.getIntegerProperty(prefix + ".y",0);
      width = jEdit.getIntegerProperty(prefix + ".width",0);
      height = jEdit.getIntegerProperty(prefix + ".height",0);
    }

    public ViewConfig(boolean plainView, String splitConfig,
      int x, int y, int width, int height, int extState)
    {
      this.plainView = plainView;
      this.splitConfig = splitConfig;
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
      this.extState = extState;
    }
  } //}}}

  //}}}
}
TOP

Related Classes of org.gjt.sp.jedit.View$ViewConfig

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.