Path: blob/master/src/java.desktop/macosx/classes/com/apple/laf/AquaCaret.java
41154 views
/*1* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.apple.laf;2627import java.awt.Graphics;28import java.awt.Insets;29import java.awt.Rectangle;30import java.awt.event.FocusEvent;31import java.awt.event.MouseEvent;32import java.awt.geom.Rectangle2D;33import java.beans.PropertyChangeEvent;34import java.beans.PropertyChangeListener;3536import javax.swing.JEditorPane;37import javax.swing.JTextArea;38import javax.swing.border.Border;39import javax.swing.plaf.UIResource;40import javax.swing.text.DefaultCaret;41import javax.swing.text.Highlighter;42import javax.swing.text.JTextComponent;43import javax.swing.SwingUtilities;4445@SuppressWarnings("serial") // Superclass is not serializable across versions46public class AquaCaret extends DefaultCaret47implements UIResource, PropertyChangeListener {4849private boolean isMultiLineEditor;50private boolean mFocused = false;51private boolean fPainting = false;5253@Override54public void install(final JTextComponent c) {55super.install(c);56isMultiLineEditor = c instanceof JTextArea || c instanceof JEditorPane;57c.addPropertyChangeListener(this);58}5960@Override61public void deinstall(final JTextComponent c) {62c.removePropertyChangeListener(this);63super.deinstall(c);64}6566@Override67protected Highlighter.HighlightPainter getSelectionPainter() {68return AquaHighlighter.getInstance();69}7071/**72* Only show the flashing caret if the selection range is zero73*/74@Override75public void setVisible(boolean e) {76if (e) e = getDot() == getMark();77super.setVisible(e);78}7980@Override81protected void fireStateChanged() {82// If we have focus the caret should only flash if the range length is zero83if (mFocused) setVisible(getComponent().isEditable());8485super.fireStateChanged();86}8788@Override89public void propertyChange(final PropertyChangeEvent evt) {90final String propertyName = evt.getPropertyName();9192if (AquaFocusHandler.FRAME_ACTIVE_PROPERTY.equals(propertyName)) {93final JTextComponent comp = ((JTextComponent)evt.getSource());9495if (evt.getNewValue() == Boolean.TRUE) {96setVisible(comp.hasFocus());97} else {98setVisible(false);99}100101if (getDot() != getMark()) comp.getUI().damageRange(comp, getDot(), getMark());102}103}104105// --- FocusListener methods --------------------------106107private boolean shouldSelectAllOnFocus = true;108@Override109public void focusGained(final FocusEvent e) {110final JTextComponent component = getComponent();111if (!component.isEnabled() || !component.isEditable()) {112super.focusGained(e);113return;114}115116mFocused = true;117if (!shouldSelectAllOnFocus) {118shouldSelectAllOnFocus = true;119super.focusGained(e);120return;121}122123if (isMultiLineEditor) {124super.focusGained(e);125return;126}127128final int end = component.getDocument().getLength();129final int dot = getDot();130final int mark = getMark();131if (dot == mark) {132if (dot == 0) {133component.setCaretPosition(end);134component.moveCaretPosition(0);135} else if (dot == end) {136component.setCaretPosition(0);137component.moveCaretPosition(end);138}139}140141super.focusGained(e);142}143144@Override145public void focusLost(final FocusEvent e) {146mFocused = false;147shouldSelectAllOnFocus = true;148if (isMultiLineEditor) {149setVisible(false);150getComponent().repaint();151} else {152super.focusLost(e);153}154}155156// This fixes the problem where when on the mac you have to ctrl left click to157// get popup triggers the caret has code that only looks at button number.158// see radar # 3125390159@Override160public void mousePressed(final MouseEvent e) {161if (!e.isPopupTrigger() && !(SwingUtilities.isLeftMouseButton(e) &&162e.getClickCount() == 3)) {163super.mousePressed(e);164shouldSelectAllOnFocus = false;165}166}167168/**169* Damages the area surrounding the caret to cause170* it to be repainted in a new location. If paint()171* is reimplemented, this method should also be172* reimplemented. This method should update the173* caret bounds (x, y, width, and height).174*175* @param r the current location of the caret176* @see #paint177*/178@Override179protected synchronized void damage(final Rectangle r) {180if (r == null || fPainting) return;181182x = r.x - 4;183y = r.y;184width = 10;185height = r.height;186187// Don't damage the border area. We can't paint a partial border, so get the188// intersection of the caret rectangle and the component less the border, if any.189final Rectangle caretRect = new Rectangle(x, y, width, height);190final Border border = getComponent().getBorder();191if (border != null) {192final Rectangle alloc = getComponent().getBounds();193alloc.x = alloc.y = 0;194final Insets borderInsets = border.getBorderInsets(getComponent());195alloc.x += borderInsets.left;196alloc.y += borderInsets.top;197alloc.width -= borderInsets.left + borderInsets.right;198alloc.height -= borderInsets.top + borderInsets.bottom;199Rectangle2D.intersect(caretRect, alloc, caretRect);200}201x = caretRect.x;202y = caretRect.y;203width = Math.max(caretRect.width, 1);204height = Math.max(caretRect.height, 1);205repaint();206}207208// See <rdar://problem/3833837> 1.4.2_05-141.3: JTextField performance with209// Aqua L&F. We are getting into a circular condition with the BasicCaret210// paint code since it doesn't know about the fact that our damage routine211// above elminates the border. Sadly we can't easily change either one, so212// we will add a painting flag and not damage during a repaint.213@Override214public void paint(final Graphics g) {215if (isVisible()) {216fPainting = true;217super.paint(g);218fPainting = false;219}220}221}222223224