⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 configurablecaret.java

📁 具有不同语法高亮的编辑器实例
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
   * <p>
   * Here's a list showing the potential return values of both
   * <code>isActive</code> and <code>isVisible</code>
   * after calling this method:
   * <p>
   * <b><code>setVisible(true)</code></b>:
   * <ul>
   *     <li>isActive(): true</li>
   *     <li>isVisible(): true or false depending on whether
   *         or not the caret is blinked on or off</li>
   * </ul>
   * <p>
   * <b><code>setVisible(false)</code></b>:
   * <ul>
   *     <li>isActive(): false</li>
   *     <li>isVisible(): false</li>
   * </ul>
   *
   * @param e the visibility specifier
   * @see #isActive
   * @see Caret#setVisible
   */
  public void setVisible(boolean e) {

    // focus lost notification can come in later after the
    // caret has been deinstalled, in which case the component
    // will be null.
    if (component != null) {

      active = e;
      TextUI mapper = component.getUI();

      if (visible != e) {
        visible = e;
        // repaint the caret
        try {
          Rectangle loc = mapper.modelToView(component, dot);
          validateWidth(loc);
          damage(loc);
        }
        catch (BadLocationException badloc) {
          // hmm... not legally positioned
        }
      }

    } // End of if (component != null).

    if (flasher != null) {
      if (visible) {
        flasher.start();
      }
      else {
        flasher.stop();
      }
    }

  }

      /*****************************************************************************/

  public String toString() {
    String s = "Dot=" + dot;
    s += " Mark=" + mark;
    return s;
  }

      /*****************************************************************************/

  private void updateSystemSelection() {
    if (this.dot != this.mark && component != null) {
      Clipboard clip = getSystemSelection();
      if (clip != null) {
        String selectedText = null;
        selectedText = component.getSelectedText();
        clip.setContents(new StringSelection(selectedText),
                         getClipboardOwner());
        ownsSelection = true;
      }
    }
  }

      /*****************************************************************************/

  /**
   * Helper function used by the block and underline carets to
   * ensure the width of the painted caret is valid.  This is
   * done for the following reasons:
   *
   * <ul>
   *   <li>The <code>View</code> classes in the javax.swing.text
   *       package always return a width of "1" when
   *       <code>modelToView</code> is called.  We'll be needing
   *       the actual width.</li>
   *   <li>Even in smart views, such as
   *       <code>RSyntaxTextArea</code>'s <code>SyntaxView</code>
   *       and <code>WrappedSyntaxView</code> that return the
   *       width of the current character, if the caret is at
   *       the end of a line for example, the width returned
   *       from <code>modelToView</code> will be 0 (as the width
   *       of unprintable characters such as '\n' is calculated
   *       as 0).  In this case, we'll use a default width
   *       value.</li>
   * </ul>
   *
   * @param rect The rectangle returned by the current
   *             <code>View</code>'s <code>modelToView</code>
   *             method for the caret position.
   */
  private final void validateWidth(Rectangle rect) {

    // If the width value > 1, we assume the View is
    // a "smart" view that returned the proper width.
    // So only worry about this stuff if width <= 1.
    if (rect != null && rect.width <= 1) {

      // The width is either 1 (most likely, we're
      // using a "dumb" view like those in
      // javax.swing.text) or 0 (most likely,
      // we're using a "smart" view like
      // org.fife.ui.rsyntaxtextarea.SyntaxView,
      // we're at the end of a line, and the
      // width of '\n' is being computed as 0).

      try {

        // Try to get a width for the character
        // at the caret position.  We use the text
        // area's font instead of g's because
        // g's may vary in an RSyntaxTextArea.
        component.getDocument().getText(dot, 1, seg);
        Font font = component.getFont();
        FontMetrics fm = component.
            getFontMetrics(font);
        rect.width = fm.charWidth(
            seg.array[seg.offset]);

        // This width being returned 0 likely means
        // that it is an unprintable character (which
        // is almost 100% to be a newline char, i.e.,
        // we're at the end of a line).  So, just use
        // the width of a space.
        if (rect.width == 0) {
          rect.width = fm.charWidth(' ');
        }

      }
      catch (BadLocationException ble) {
        // This shouldn't ever happen.
        ble.printStackTrace();
        rect.width = 8;
      }

    } // End of if (rect.width<=1).

  }

      /*****************************************************************************/

  private void writeObject(ObjectOutputStream s) throws IOException {
    s.defaultWriteObject();
    s.writeInt(getStyle());
  }

      /*****************************************************************************/
      /*********************** PRIVATE INNER CLASSES *******************************/
      /*****************************************************************************/

  /**
   * Scrolls the text component that contains this caret so that this
   * caret is visible.  This operation is wrapped in a
   * <code>Runnable</code> so that it is threadsafe.
   */
  class SafeScroller
      implements Runnable {

    private Rectangle r;

    SafeScroller(Rectangle r) {
      this.r = r;
    }

    public void run() {
      if (component != null) {
        component.scrollRectToVisible(r);
      }
    }

  }

      /*****************************************************************************/

  /**
   * Handles many events from this caret.
   */
  class Handler
      implements PropertyChangeListener, DocumentListener,
      ActionListener, ClipboardOwner {

    /**
     * Invoked when the blink timer fires.  This is called
     * asynchronously.  The simply changes the visibility
     * and repaints the rectangle that last bounded the caret.
     *
     * @param e the action event
     */
    public void actionPerformed(ActionEvent e) {
      if (width == 0 || height == 0) {
        // setVisible(true) will cause a scroll, only do this if the
        // new location is really valid.
        if (component != null) {
          TextUI mapper = component.getUI();
          try {
            Rectangle r = mapper.modelToView(component, dot);
            if (r != null && r.width != 0 && r.height != 0) {
              validateWidth(r);
              damage(r);
            }
          }
          catch (BadLocationException ble) {
          }
        }
      }
      visible = !visible;
      repaint();
    }

    /**
     * Updates the dot and mark if they were changed by
     * the insertion.
     *
     * @param e the document event
     * @see DocumentListener#insertUpdate
     */
    public void insertUpdate(DocumentEvent e) {

      if (!SwingUtilities.isEventDispatchThread()) {
        if ( (e.getOffset() <= dot || e.getOffset() <= mark)
            && selectionTag != null) {
          try {
            component.getHighlighter().changeHighlight(selectionTag,
                Math.min(dot, mark), Math.max(dot, mark));
          }
          catch (BadLocationException e1) {
            e1.printStackTrace();
          }
        }
        return;
      }

      int adjust = 0;
      int offset = e.getOffset();
      int length = e.getLength();
      int newDot = dot;
      short changed = 0;

      if (component.inUndoRedo()) {
        setDot(offset + length);
        return;
      }

      if (newDot >= offset) {
        newDot += length;
        changed |= 1;
      }
      int newMark = mark;
      if (newMark >= offset) {
        newMark += length;
        changed |= 2;
      }

      if (changed != 0) {
        if (newMark == newDot) {
          setDot(newDot);
          ensureValidPosition();
        }
        else {
          setDot(newMark);
          if (getDot() == newMark) {
            // Due this test in case the filter vetoed the
            // change in which case this probably won't be
            // valid either.
            moveDot(newDot);
          }
          ensureValidPosition();
        }
      }

    }

    /**
     * Updates the dot and mark if they were changed
     * by the removal.
     *
     * @param e the document event
     * @see DocumentListener#removeUpdate
     */
    public void removeUpdate(DocumentEvent e) {

      if (!SwingUtilities.isEventDispatchThread()) {
        int length = component.getDocument().getLength();
        dot = Math.min(dot, length);
        mark = Math.min(mark, length);
        if ( (e.getOffset() < dot || e.getOffset() < mark)
            && selectionTag != null) {
          try {
            component.getHighlighter().changeHighlight(selectionTag,
                Math.min(dot, mark), Math.max(dot, mark));
          }
          catch (BadLocationException e1) {
            e1.printStackTrace();
          }
        }
        return;
      }

      int offs0 = e.getOffset();
      int offs1 = offs0 + e.getLength();
      int adjust = 0;
      int newDot = dot;
      int newMark = mark;

      if (component.inUndoRedo()) {
        setDot(offs0);
        return;
      }

      if (newDot >= offs1) {
        newDot -= (offs1 - offs0);
      }
      else if (newDot >= offs0) {
        newDot = offs0;

      }
      if (newMark >= offs1) {
        newMark -= (offs1 - offs0);
      }
      else if (newMark >= offs0) {
        newMark = offs0;

      }
      if (newMark == newDot) {
        forceCaretPositionChange = true;
        try {
          setDot(newDot);
        }
        finally {
          forceCaretPositionChange = false;
        }
        ensureValidPosition();
      }
      else {
        setDot(newMark);
        if (getDot() == newMark) {
          // Due this test in case the filter vetoed the change
          // in which case this probably won't be valid either.
          moveDot(newDot);
        }
        ensureValidPosition();
      }

    }

    /**
     * Gives notification that an attribute or set of attributes changed.
     *
     * @param e the document event
     * @see DocumentListener#changedUpdate
     */
    public void changedUpdate(DocumentEvent e) {
      if (!SwingUtilities.isEventDispatchThread()) {
        return;
      }
      if (component.inUndoRedo()) {
        setDot(e.getOffset() + e.getLength());
      }
    }

    /**
     * This method gets called when a bound property is changed.
     * We are looking for document changes on the editor.
     */
    public void propertyChange(PropertyChangeEvent evt) {
      Object oldValue = evt.getOldValue();
      Object newValue = evt.getNewValue();
      if ( (oldValue instanceof Document) || (newValue instanceof Document)) {
        setDot(0);
        if (oldValue != null) {
          ( (Document) oldValue).removeDocumentListener(this);
        }
        if (newValue != null) {
          ( (Document) newValue).addDocumentListener(this);
        }
      }
      else if ("enabled".equals(evt.getPropertyName())) {
        Boolean enabled = (Boolean) evt.getNewValue();
        if (component.isFocusOwner()) {
          if (enabled == Boolean.TRUE) {
            if (component.isEditable()) {
              setVisible(true);
            }
            setSelectionVisible(true);
          }
          else {
            setVisible(false);
            setSelectionVisible(false);
          }
        }
      }
    }

    /**
     * Toggles the visibility of the selection when ownership is lost.
     */
    public void lostOwnership(Clipboard clipboard,
                              Transferable contents) {
      if (ownsSelection) {
        ownsSelection = false;
        if (component != null && !component.hasFocus()) {
          setSelectionVisible(false);
        }
      }
    }

  }

      /*****************************************************************************/

  /**
   * Filter bypass for this caret class.
   */
  private class DefaultFilterBypass
      extends NavigationFilter.FilterBypass {

    public Caret getCaret() {
      return ConfigurableCaret.this;
    }

    public void setDot(int dot, Position.Bias bias) {
      handleSetDot(dot);
    }

    public void moveDot(int dot, Position.Bias bias) {
      handleMoveDot(dot);
    }

  }

      /*****************************************************************************/

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -