Package net.sf.robocode.ui.editor

Source Code of net.sf.robocode.ui.editor.EditorPane$FontHandler

/**
* Copyright (c) 2001-2014 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://robocode.sourceforge.net/license/epl-v10.html
*/
package net.sf.robocode.ui.editor;


import java.awt.Event;
import java.awt.FontMetrics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.IOException;
import java.io.Reader;

import javax.swing.InputMap;
import javax.swing.JTextPane;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import javax.swing.text.DefaultEditorKit;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.TabSet;
import javax.swing.text.TabStop;


/**
* Editor pane used for editing source code.
*
* @author Flemming N. Larsen (original)
*/
@SuppressWarnings("serial")
public class EditorPane extends JTextPane {

  private int tabSize = 4; // Default

  // Key bindings
  private static final KeyStroke CUT_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_X, Event.CTRL_MASK);
  private static final KeyStroke COPY_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_C, Event.CTRL_MASK);
  private static final KeyStroke PASTE_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_V, Event.CTRL_MASK);
  private static final KeyStroke UNDO_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_Z, Event.CTRL_MASK);
  private static final KeyStroke REDO_KEYSTROKE = KeyStroke.getKeyStroke(KeyEvent.VK_Y, Event.CTRL_MASK);

  private final JavaDocument document;

  private final CompoundUndoManager undoManager = new CompoundUndoManager();

  private final TextTool textTool = new TextTool();

  private JViewport viewport;

  public EditorPane(JViewport viewport) {
    super();
    this.viewport = viewport;
    document = new JavaDocument(this);

    DefaultCaret caret = (DefaultCaret) getCaret();
    caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);

    new LineNumberArea(this);

    LineHighlighter.install(this);

    EditorKit editorKit = new StyledEditorKit() {
      @Override
      public Document createDefaultDocument() {
        return document;
      }
    };

    setEditorKitForContentType("text/java", editorKit);
    setContentType("text/java");

    addPropertyChangeListener("font", new FontHandler());
    addKeyListener(new KeyHandler());

    setKeyBindings();
    setActionBindings();

    getDocument().addUndoableEditListener(undoManager);
  }

  public JViewport getViewport() {
    return viewport;
  }

  // No line wrapping!
  @Override
  public boolean getScrollableTracksViewportWidth() {
    return getUI().getPreferredSize(this).width <= getParent().getSize().width;
  }

  // Don't enforce height -> Avoid line height changes
  @Override
  public boolean getScrollableTracksViewportHeight() {
    return false;
  }

  // Make sure to discard all undo/redo edits when text completely replaced
  @Override
  public void setText(final String text) {
    // Adding this call to the EDT prevents problems with deleting text that eats text before the deletion
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        JavaDocument javaDocument = (JavaDocument) getDocument();

        // Bug-357: Tab characters are inserted in the last line of a robot source file when opening it.
        // This bug was fixed by disabling auto-indentation while reading the file.
        javaDocument.setReplacingText(true);
        EditorPane.super.setText(text);
        javaDocument.setReplacingText(false);

        resetCaretPosition();

        undoManager.discardAllEdits();
      }
    });
  }

  // Make sure to discard all undo/redo edits when text is read as one block
  @Override
  public void read(Reader in, Object desc) throws IOException {
    JavaDocument javaDocument = (JavaDocument) getDocument();

    // Bug-357: Tab characters are inserted in the last line of a robot source file when opening it.
    // This bug was fixed by disabling auto-indentation while reading the file.
    javaDocument.setReplacingText(true);
    super.read(in, desc);
    javaDocument.setReplacingText(false);

    resetCaretPosition();

    undoManager.discardAllEdits();
  }

  public boolean isModified() {
    return undoManager.canUndoOrRedo();
  }

  public void undo() {
    if (undoManager.canUndo()) {
      undoManager.undo();
    }
  }
 
  public void redo() {
    if (undoManager.canRedo()) {
      undoManager.redo();
    }
  }

  private void setKeyBindings() {
    InputMap inputMap = this.getInputMap();

    inputMap.put(CUT_KEYSTROKE, DefaultEditorKit.cutAction);
    inputMap.put(COPY_KEYSTROKE, DefaultEditorKit.copyAction);
    inputMap.put(PASTE_KEYSTROKE, DefaultEditorKit.pasteAction);
    inputMap.put(UNDO_KEYSTROKE, undoManager.getUndoAction());
    inputMap.put(REDO_KEYSTROKE, undoManager.getRedoAction());
  }

  private void setActionBindings() {
    getActionMap().put("undo-keystroke", undoManager.getUndoAction());
    getActionMap().put("redo-keystroke", undoManager.getRedoAction());
  }

  private void setTabSize(int tabSize) {
    document.setTabSize(tabSize);

    FontMetrics fm = getFontMetrics(getFont());

    int charWidth = fm.charWidth('#');
    int tabWidth = charWidth * tabSize;

    TabStop[] tabs = new TabStop[100];
    for (int j = 0; j < tabs.length; j++) {
      tabs[j] = new TabStop((j + 1) * tabWidth);
    }

    SimpleAttributeSet attributes = new SimpleAttributeSet();

    StyleConstants.setTabSet(attributes, new TabSet(tabs));

    getDocument().removeUndoableEditListener(undoManager); // Avoid this change to be undone
    getStyledDocument().setParagraphAttributes(0, getDocument().getLength(), attributes, false);
    getDocument().addUndoableEditListener(undoManager);
  }

  private void resetCaretPosition() {
    // Make sure to put this request on the EDT or the caret position might not be reset after all.
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        setCaretPosition(0);
      }
    })
  }

  private void onTabCharPressed(boolean isUnindent) {

    int selectionStart = getSelectionStart();
    int selectionEnd = getSelectionEnd();

    if (selectionStart == selectionEnd) {
      // No selection -> Handle normal tab indentation

      if (isUnindent) {
        textTool.removeLastTab(getCaretPosition());
      } else {
        textTool.insertString(getCaretPosition(), "\t");
      }
    } else {
      // Start block indentation

      // Make sure that the start selection is lesser than the end selection
      if (selectionStart > selectionEnd) {
        // Swap selection start and selection end
        int tmp = selectionStart;

        selectionStart = selectionEnd;
        selectionEnd = tmp;
      }

      StringBuilder newText = new StringBuilder();
      int count = 0;
      boolean stopUnindent = false;

      // Handle each line

      String selectedText = textTool.getSelectedText();

      selectedText = selectedText.replaceAll("\\s*$", "");

      String[] lines = selectedText.split(String.valueOf('\n'));

      // iterate lines, rebuilding tabs and newlines
      for (int i = 0; i < lines.length; i++) {
        String line = lines[i];

        if (isUnindent) {
          if (line.charAt(0) != '\t') {
            stopUnindent = true;
            break;
          } else {
            newText.append(line.substring(1, line.length()));
            count++;
          }
        } else {
          newText.append('\t').append(line);
          count++;
        }
        if (i != lines.length - 1) {
          newText.append('\n');
        }
      }

      if (!stopUnindent) {
        try {
          // Replace the indented/unindented text in one single compound edit
          undoManager.markCompoundStart();
          getDocument().remove(selectionStart, selectedText.length());
          textTool.insertString(selectionStart, newText.toString());
          undoManager.markCompoundStart();
        } catch (BadLocationException e) {
          e.printStackTrace();
        }

        // Compute the new selection
        int mod = isUnindent ? -1 : 1;

        // Make new selection using the EDT, as replacing the text above must run before a new selection can be made

        final int newSelectionStart = selectionStart;
        final int newSelectionEnd = selectionStart + selectedText.length() + count * mod;

        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            setSelectionStart(newSelectionStart);
            setSelectionEnd(newSelectionEnd);
          }
        });
      }
    }
  }

  private class FontHandler implements PropertyChangeListener {
    public void propertyChange(PropertyChangeEvent e) {
      setTabSize(tabSize);
    }
  }


  private class KeyHandler extends KeyAdapter {

    @Override
    public void keyPressed(KeyEvent e) {
      switch (e.getKeyCode()) {
      case KeyEvent.VK_TAB:
        onTabCharPressed(e.isShiftDown());
        e.consume();
        break;
      }
    }
  }


  /**
   * Handy text tool.
   */
  private class TextTool {

    String getSelectedText() {
      int start = getSelectionStart();
      int end = getSelectionEnd();

      try {
        return getDocument().getText(start, end - start);
      } catch (BadLocationException e) {
        e.printStackTrace();
      }
      return null;
    }

    void insertString(int offset, String str) {
      insertString(offset, str, null);
    }

    void insertString(final int offset, final String str, final AttributeSet a) {
      try {
        getDocument().insertString(offset, str, a);
      } catch (BadLocationException e) {
        e.printStackTrace();
      }
    }

    void removeLastTab(int offset) {
      int pos = offset;

      while (--pos >= 0) {
        try {
          char ch = getDocument().getText(pos, 1).charAt(0);

          if (ch == '\t') {
            remove(pos, 1);
            return;
          }
          if (ch == '\n') {
            return;
          }
        } catch (BadLocationException e) {
          e.printStackTrace();
        }
      }
    }
   
    void remove(final int offset, final int len) {
      try {
        getDocument().remove(offset, len);
      } catch (BadLocationException e) {
        e.printStackTrace();
      }
    }
  }
}
TOP

Related Classes of net.sf.robocode.ui.editor.EditorPane$FontHandler

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.