| /* |
| * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code 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 |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.awt.X11; |
| |
| import java.awt.*; |
| import java.awt.peer.ComponentPeer; |
| import java.awt.peer.TextAreaPeer; |
| import java.awt.event.*; |
| import javax.swing.event.DocumentListener; |
| import javax.swing.event.DocumentEvent; |
| import javax.swing.JTextArea; |
| import javax.swing.JComponent; |
| import javax.swing.JScrollPane; |
| import javax.swing.JScrollBar; |
| import javax.swing.plaf.ComponentUI; |
| import com.sun.java.swing.plaf.motif.MotifTextAreaUI; |
| import javax.swing.plaf.UIResource; |
| import javax.swing.UIDefaults; |
| import javax.swing.border.Border; |
| import javax.swing.border.EmptyBorder; |
| import javax.swing.border.CompoundBorder; |
| import javax.swing.border.AbstractBorder; |
| import javax.swing.JButton; |
| import javax.swing.JViewport; |
| import javax.swing.InputMap; |
| import javax.swing.SwingUtilities; |
| import javax.swing.TransferHandler; |
| import javax.swing.plaf.basic.BasicArrowButton; |
| import javax.swing.plaf.basic.BasicScrollBarUI; |
| import javax.swing.plaf.basic.BasicScrollPaneUI; |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import javax.swing.text.Caret; |
| import javax.swing.text.DefaultCaret; |
| import javax.swing.text.JTextComponent; |
| |
| import javax.swing.plaf.BorderUIResource; |
| import java.awt.im.InputMethodRequests; |
| import sun.awt.AWTAccessor; |
| import sun.awt.SunToolkit; |
| |
| final class XTextAreaPeer extends XComponentPeer implements TextAreaPeer { |
| |
| private final AWTTextPane textPane; |
| private final AWTTextArea jtext; |
| private final boolean firstChangeSkipped; |
| |
| private final JavaMouseEventHandler javaMouseEventHandler = |
| new JavaMouseEventHandler(this); |
| |
| /** |
| * Create a Text area. |
| */ |
| XTextAreaPeer(TextArea target) { |
| super(target); |
| |
| // some initializations require that target be set even |
| // though init(target) has not been called |
| this.target = target; |
| |
| //ComponentAccessor.enableEvents(target,AWTEvent.MOUSE_WHEEL_EVENT_MASK); |
| |
| String text = target.getText(); |
| jtext = new AWTTextArea(text, this); |
| jtext.setWrapStyleWord(true); |
| jtext.getDocument().addDocumentListener(jtext); |
| XToolkit.specialPeerMap.put(jtext,this); |
| textPane = new AWTTextPane(jtext,this, target.getParent()); |
| |
| setBounds(x, y, width, height, SET_BOUNDS); |
| textPane.setVisible(true); |
| textPane.validate(); |
| |
| AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); |
| foreground = compAccessor.getForeground(target); |
| if (foreground == null) { |
| foreground = SystemColor.textText; |
| } |
| setForeground(foreground); |
| |
| background = compAccessor.getBackground(target); |
| if (background == null) { |
| if (target.isEditable()) background = SystemColor.text; |
| else background = SystemColor.control; |
| } |
| setBackground(background); |
| |
| if (!target.isBackgroundSet()) { |
| // This is a way to set the background color of the TextArea |
| // without calling setBackground - go through accessor |
| compAccessor.setBackground(target, background); |
| } |
| if (!target.isForegroundSet()) { |
| target.setForeground(SystemColor.textText); |
| } |
| |
| setFont(font); |
| |
| // set the text of this object to the text of its target |
| setTextImpl(target.getText()); //?? should this be setText |
| |
| int start = target.getSelectionStart(); |
| int end = target.getSelectionEnd(); |
| // Fix for 5100200 |
| // Restoring Motif behaviour |
| // Since the end position of the selected text can be greater than the length of the text, |
| // so we should set caret to max position of the text |
| setCaretPosition(Math.min(end, text.length())); |
| if (end > start) { |
| // Should be called after setText() and setCaretPosition() |
| select(start, end); |
| } |
| setEditable(target.isEditable()); |
| setScrollBarVisibility(); |
| // After this line we should not change the component's text |
| firstChangeSkipped = true; |
| compAccessor.setPeer(textPane, this); |
| } |
| |
| @Override |
| public void dispose() { |
| XToolkit.specialPeerMap.remove(jtext); |
| // visible caret has a timer thread which must be stopped |
| jtext.getCaret().setVisible(false); |
| jtext.removeNotify(); |
| super.dispose(); |
| } |
| |
| /* |
| * The method overrides one from XComponentPeer |
| * If ignoreSubComponents=={@code true} it calls super. |
| * If ignoreSubComponents=={@code false} it uses the XTextArea machinery |
| * to change cursor appropriately. In particular it changes the cursor to |
| * default if over scrollbars. |
| */ |
| @Override |
| public void pSetCursor(Cursor cursor, boolean ignoreSubComponents) { |
| if (ignoreSubComponents || |
| javaMouseEventHandler == null) { |
| super.pSetCursor(cursor, true); |
| return; |
| } |
| |
| Point cursorPos = new Point(); |
| ((XGlobalCursorManager)XGlobalCursorManager.getCursorManager()).getCursorPos(cursorPos); |
| |
| final Point onScreen = getLocationOnScreen(); |
| Point localPoint = new Point(cursorPos.x - onScreen.x, cursorPos.y - onScreen.y ); |
| |
| javaMouseEventHandler.setPointerToUnderPoint(localPoint); |
| javaMouseEventHandler.setCursor(); |
| } |
| |
| private void setScrollBarVisibility() { |
| int visibility = ((TextArea)target).getScrollbarVisibility(); |
| jtext.setLineWrap(false); |
| |
| if (visibility == TextArea.SCROLLBARS_NONE) { |
| textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); |
| textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); |
| jtext.setLineWrap(true); |
| } |
| else if (visibility == TextArea.SCROLLBARS_BOTH) { |
| |
| textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); |
| textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); |
| } |
| else if (visibility == TextArea.SCROLLBARS_VERTICAL_ONLY) { |
| textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); |
| textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); |
| jtext.setLineWrap(true); |
| } |
| else if (visibility == TextArea.SCROLLBARS_HORIZONTAL_ONLY) { |
| textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); |
| textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); |
| } |
| } |
| |
| /** |
| * Compute minimum size. |
| */ |
| @Override |
| public Dimension getMinimumSize() { |
| return getMinimumSize(10, 60); |
| } |
| |
| @Override |
| public Dimension getPreferredSize(int rows, int cols) { |
| return getMinimumSize(rows, cols); |
| } |
| |
| /** |
| * @see java.awt.peer.TextAreaPeer |
| */ |
| @Override |
| public Dimension getMinimumSize(int rows, int cols) { |
| /* Dimension d = null; |
| if (jtext != null) { |
| d = jtext.getMinimumSize(rows,cols); |
| } |
| return d; |
| */ |
| |
| int vsbwidth=0; |
| int hsbheight=0; |
| |
| JScrollBar vsb = textPane.getVerticalScrollBar(); |
| if (vsb != null) { |
| vsbwidth = vsb.getMinimumSize().width; |
| } |
| |
| JScrollBar hsb = textPane.getHorizontalScrollBar(); |
| if (hsb != null) { |
| hsbheight = hsb.getMinimumSize().height; |
| } |
| |
| Font f = jtext.getFont(); |
| FontMetrics fm = jtext.getFontMetrics(f); |
| |
| return new Dimension(fm.charWidth('0') * cols + /*2*XMARGIN +*/ vsbwidth, |
| fm.getHeight() * rows + /*2*YMARGIN +*/ hsbheight); |
| } |
| |
| @Override |
| public boolean isFocusable() { |
| return true; |
| } |
| |
| @Override |
| public void setVisible(boolean b) { |
| super.setVisible(b); |
| if (textPane != null) |
| textPane.setVisible(b); |
| } |
| |
| void repaintText() { |
| jtext.repaintNow(); |
| } |
| |
| @Override |
| public void focusGained(FocusEvent e) { |
| super.focusGained(e); |
| jtext.forwardFocusGained(e); |
| } |
| |
| @Override |
| public void focusLost(FocusEvent e) { |
| super.focusLost(e); |
| jtext.forwardFocusLost(e); |
| } |
| |
| /** |
| * Paint the component |
| * this method is called when the repaint instruction has been used |
| */ |
| @Override |
| public void repaint() { |
| if (textPane != null) { |
| //textPane.validate(); |
| textPane.repaint(); |
| } |
| } |
| |
| @Override |
| void paintPeer(final Graphics g) { |
| if (textPane != null) { |
| textPane.paint(g); |
| } |
| } |
| |
| @Override |
| public void setBounds(int x, int y, int width, int height, int op) { |
| super.setBounds(x, y, width, height, op); |
| if (textPane != null) { |
| /* |
| * Fixed 6277332, 6198290: |
| * the coordinates is coming (to peer): relatively to closest HW parent |
| * the coordinates is setting (to textPane): relatively to closest ANY parent |
| * the parent of peer is target.getParent() |
| * the parent of textPane is the same |
| * see 6277332, 6198290 for more information |
| */ |
| int childX = x; |
| int childY = y; |
| Component parent = target.getParent(); |
| // we up to heavyweight parent in order to be sure |
| // that the coordinates of the text pane is relatively to closest parent |
| while (parent.isLightweight()){ |
| childX -= parent.getX(); |
| childY -= parent.getY(); |
| parent = parent.getParent(); |
| } |
| textPane.setBounds(childX,childY,width,height); |
| textPane.validate(); |
| } |
| } |
| |
| @Override |
| void handleJavaKeyEvent(KeyEvent e) { |
| AWTAccessor.getComponentAccessor().processEvent(jtext,e); |
| } |
| |
| @Override |
| public boolean handlesWheelScrolling() { return true; } |
| |
| @Override |
| void handleJavaMouseWheelEvent(MouseWheelEvent e) { |
| AWTAccessor.getComponentAccessor().processEvent(textPane, e); |
| } |
| |
| @Override |
| public void handleJavaMouseEvent( MouseEvent e ) { |
| super.handleJavaMouseEvent( e ); |
| javaMouseEventHandler.handle( e ); |
| } |
| |
| @Override |
| void handleJavaInputMethodEvent(InputMethodEvent e) { |
| if (jtext != null) |
| jtext.processInputMethodEventPublic(e); |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public void select(int s, int e) { |
| jtext.select(s, e); |
| // Fixed 5100806 |
| // We must take care that Swing components repainted correctly |
| jtext.repaint(); |
| } |
| |
| @Override |
| public void setBackground(Color c) { |
| super.setBackground(c); |
| // synchronized (getStateLock()) { |
| // background = c; |
| // } |
| if (jtext != null) { |
| jtext.setBackground(c); |
| jtext.setSelectedTextColor(c); |
| } |
| // repaintText(); |
| } |
| |
| @Override |
| public void setForeground(Color c) { |
| super.setForeground(c); |
| // synchronized (getStateLock()) { |
| // foreground = c; |
| // } |
| if (jtext != null) { |
| jtext.setForeground(foreground); |
| jtext.setSelectionColor(foreground); |
| jtext.setCaretColor(foreground); |
| } |
| // repaintText(); |
| } |
| |
| @Override |
| public void setFont(Font f) { |
| super.setFont(f); |
| // synchronized (getStateLock()) { |
| // font = f; |
| // } |
| if (jtext != null) { |
| jtext.setFont(font); |
| } |
| textPane.validate(); |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public void setEditable(boolean editable) { |
| if (jtext != null) jtext.setEditable(editable); |
| repaintText(); |
| } |
| |
| /** |
| * @see java.awt.peer.ComponentPeer |
| */ |
| @Override |
| public void setEnabled(boolean enabled) { |
| super.setEnabled(enabled); |
| if (jtext != null) { |
| jtext.setEnabled(enabled); |
| jtext.repaint(); |
| } |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public InputMethodRequests getInputMethodRequests() { |
| if (jtext != null) return jtext.getInputMethodRequests(); |
| else return null; |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public int getSelectionStart() { |
| return jtext.getSelectionStart(); |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public int getSelectionEnd() { |
| return jtext.getSelectionEnd(); |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public String getText() { |
| return jtext.getText(); |
| } |
| |
| /** |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public void setText(String text) { |
| setTextImpl(text); |
| repaintText(); |
| } |
| |
| private void setTextImpl(String txt) { |
| if (jtext != null) { |
| // JTextArea.setText() posts two different events (remove & insert). |
| // Since we make no differences between text events, |
| // the document listener has to be disabled while |
| // JTextArea.setText() is called. |
| jtext.getDocument().removeDocumentListener(jtext); |
| jtext.setText(txt); |
| if (firstChangeSkipped) { |
| postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); |
| } |
| jtext.getDocument().addDocumentListener(jtext); |
| } |
| } |
| |
| /** |
| * insert the text "txt on position "pos" in the array lines |
| * @see java.awt.peer.TextAreaPeer |
| */ |
| @Override |
| public void insert(String txt, int p) { |
| if (jtext != null) { |
| boolean doScroll = (p >= jtext.getDocument().getLength() && jtext.getDocument().getLength() != 0); |
| jtext.insert(txt,p); |
| textPane.validate(); |
| if (doScroll) { |
| JScrollBar bar = textPane.getVerticalScrollBar(); |
| if (bar != null) { |
| bar.setValue(bar.getMaximum()-bar.getVisibleAmount()); |
| } |
| } |
| } |
| } |
| |
| /** |
| * replace the text between the position "s" and "e" with "txt" |
| * @see java.awt.peer.TextAreaPeer |
| */ |
| @Override |
| public void replaceRange(String txt, int s, int e) { |
| if (jtext != null) { |
| // JTextArea.replaceRange() posts two different events. |
| // Since we make no differences between text events, |
| // the document listener has to be disabled while |
| // JTextArea.replaceRange() is called. |
| jtext.getDocument().removeDocumentListener(jtext); |
| jtext.replaceRange(txt, s, e); |
| postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); |
| jtext.getDocument().addDocumentListener(jtext); |
| } |
| } |
| |
| /** |
| * to be implemented. |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public void setCaretPosition(int position) { |
| jtext.setCaretPosition(position); |
| } |
| |
| /** |
| * to be implemented. |
| * @see java.awt.peer.TextComponentPeer |
| */ |
| @Override |
| public int getCaretPosition() { |
| return jtext.getCaretPosition(); |
| } |
| |
| final class AWTTextAreaUI extends MotifTextAreaUI { |
| |
| private JTextArea jta; |
| |
| @Override |
| protected String getPropertyPrefix() { return "TextArea"; } |
| |
| @Override |
| public void installUI(JComponent c) { |
| super.installUI(c); |
| |
| jta = (JTextArea) c; |
| |
| JTextArea editor = jta; |
| |
| UIDefaults uidefaults = XToolkit.getUIDefaults(); |
| |
| String prefix = getPropertyPrefix(); |
| Font f = editor.getFont(); |
| if ((f == null) || (f instanceof UIResource)) { |
| editor.setFont(uidefaults.getFont(prefix + ".font")); |
| } |
| |
| Color bg = editor.getBackground(); |
| if ((bg == null) || (bg instanceof UIResource)) { |
| editor.setBackground(uidefaults.getColor(prefix + ".background")); |
| } |
| |
| Color fg = editor.getForeground(); |
| if ((fg == null) || (fg instanceof UIResource)) { |
| editor.setForeground(uidefaults.getColor(prefix + ".foreground")); |
| } |
| |
| Color color = editor.getCaretColor(); |
| if ((color == null) || (color instanceof UIResource)) { |
| editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground")); |
| } |
| |
| Color s = editor.getSelectionColor(); |
| if ((s == null) || (s instanceof UIResource)) { |
| editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground")); |
| } |
| |
| Color sfg = editor.getSelectedTextColor(); |
| if ((sfg == null) || (sfg instanceof UIResource)) { |
| editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground")); |
| } |
| |
| Color dfg = editor.getDisabledTextColor(); |
| if ((dfg == null) || (dfg instanceof UIResource)) { |
| editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground")); |
| } |
| |
| Border b = new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight); |
| editor.setBorder(new BorderUIResource.CompoundBorderUIResource( |
| b,new EmptyBorder(2, 2, 2, 2))); |
| |
| Insets margin = editor.getMargin(); |
| if (margin == null || margin instanceof UIResource) { |
| editor.setMargin(uidefaults.getInsets(prefix + ".margin")); |
| } |
| } |
| |
| @Override |
| protected void installKeyboardActions() { |
| super.installKeyboardActions(); |
| |
| JTextComponent comp = getComponent(); |
| |
| UIDefaults uidefaults = XToolkit.getUIDefaults(); |
| |
| String prefix = getPropertyPrefix(); |
| |
| InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap"); |
| |
| if (map != null) { |
| SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, |
| map); |
| } |
| } |
| |
| @Override |
| protected Caret createCaret() { |
| return new XAWTCaret(); |
| } |
| } |
| |
| @SuppressWarnings("serial") // JDK-implementation class |
| static final class XAWTCaret extends DefaultCaret { |
| @Override |
| public void focusGained(FocusEvent e) { |
| super.focusGained(e); |
| if (getComponent().isEnabled()){ |
| // Make sure the cursor is visible in case of non-editable TextArea |
| super.setVisible(true); |
| } |
| getComponent().repaint(); |
| } |
| |
| @Override |
| public void focusLost(FocusEvent e) { |
| super.focusLost(e); |
| getComponent().repaint(); |
| } |
| |
| // Fix for 5100950: textarea.getSelectedText() returns the de-selected text, on XToolkit |
| // Restoring Motif behaviour |
| // If the text is unhighlighted then we should sets the selection range to zero |
| @Override |
| public void setSelectionVisible(boolean vis) { |
| if (vis){ |
| super.setSelectionVisible(vis); |
| }else{ |
| // In order to de-select the selection |
| setDot(getDot()); |
| } |
| } |
| } |
| |
| @SuppressWarnings("serial") // JDK-implementation class |
| final class XAWTScrollBarButton extends BasicArrowButton { |
| |
| private UIDefaults uidefaults = XToolkit.getUIDefaults(); |
| private Color darkShadow = SystemColor.controlShadow; |
| private Color lightShadow = SystemColor.controlLtHighlight; |
| private Color buttonBack = uidefaults.getColor("ScrollBar.track"); |
| |
| XAWTScrollBarButton(int direction) { |
| super(direction); |
| |
| switch (direction) { |
| case NORTH: |
| case SOUTH: |
| case EAST: |
| case WEST: |
| this.direction = direction; |
| break; |
| default: |
| throw new IllegalArgumentException("invalid direction"); |
| } |
| |
| setRequestFocusEnabled(false); |
| setOpaque(true); |
| setBackground(uidefaults.getColor("ScrollBar.thumb")); |
| setForeground(uidefaults.getColor("ScrollBar.foreground")); |
| } |
| |
| @Override |
| public Dimension getPreferredSize() { |
| switch (direction) { |
| case NORTH: |
| case SOUTH: |
| return new Dimension(11, 12); |
| case EAST: |
| case WEST: |
| default: |
| return new Dimension(12, 11); |
| } |
| } |
| |
| @Override |
| public Dimension getMinimumSize() { |
| return getPreferredSize(); |
| } |
| |
| @Override |
| public Dimension getMaximumSize() { |
| return getPreferredSize(); |
| } |
| |
| @Override |
| public boolean isFocusTraversable() { |
| return false; |
| } |
| |
| @Override |
| public void paint(Graphics g) |
| { |
| int w = getWidth(); |
| int h = getHeight(); |
| |
| if (isOpaque()) { |
| g.setColor(buttonBack); |
| g.fillRect(0, 0, w, h); |
| } |
| |
| boolean isPressed = getModel().isPressed(); |
| Color lead = (isPressed) ? darkShadow : lightShadow; |
| Color trail = (isPressed) ? lightShadow : darkShadow; |
| Color fill = getBackground(); |
| |
| int cx = w / 2; |
| int cy = h / 2; |
| int s = Math.min(w, h); |
| |
| switch (direction) { |
| case NORTH: |
| g.setColor(lead); |
| g.drawLine(cx, 0, cx, 0); |
| for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) { |
| g.setColor(lead); |
| g.drawLine(x, y, x, y); |
| if (y >= (s - 2)) { |
| g.drawLine(x, y + 1, x, y + 1); |
| } |
| g.setColor(fill); |
| g.drawLine(x + 1, y, x + dx, y); |
| if (y < (s - 2)) { |
| g.drawLine(x, y + 1, x + dx + 1, y + 1); |
| } |
| g.setColor(trail); |
| g.drawLine(x + dx + 1, y, x + dx + 1, y); |
| if (y >= (s - 2)) { |
| g.drawLine(x + 1, y + 1, x + dx + 1, y + 1); |
| } |
| dx += 2; |
| x -= 1; |
| } |
| break; |
| |
| case SOUTH: |
| g.setColor(trail); |
| g.drawLine(cx, s, cx, s); |
| for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) { |
| g.setColor(lead); |
| g.drawLine(x, y, x, y); |
| if (y <= 2) { |
| g.drawLine(x, y - 1, x + dx + 1, y - 1); |
| } |
| g.setColor(fill); |
| g.drawLine(x + 1, y, x + dx, y); |
| if (y > 2) { |
| g.drawLine(x, y - 1, x + dx + 1, y - 1); |
| } |
| g.setColor(trail); |
| g.drawLine(x + dx + 1, y, x + dx + 1, y); |
| |
| dx += 2; |
| x -= 1; |
| } |
| break; |
| |
| case EAST: |
| g.setColor(lead); |
| g.drawLine(s, cy, s, cy); |
| for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) { |
| g.setColor(lead); |
| g.drawLine(x, y, x, y); |
| if (x <= 2) { |
| g.drawLine(x - 1, y, x - 1, y + dy + 1); |
| } |
| g.setColor(fill); |
| g.drawLine(x, y + 1, x, y + dy); |
| if (x > 2) { |
| g.drawLine(x - 1, y, x - 1, y + dy + 1); |
| } |
| g.setColor(trail); |
| g.drawLine(x, y + dy + 1, x, y + dy + 1); |
| |
| dy += 2; |
| y -= 1; |
| } |
| break; |
| |
| case WEST: |
| g.setColor(trail); |
| g.drawLine(0, cy, 0, cy); |
| for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) { |
| g.setColor(lead); |
| g.drawLine(x, y, x, y); |
| if (x >= (s - 2)) { |
| g.drawLine(x + 1, y, x + 1, y); |
| } |
| g.setColor(fill); |
| g.drawLine(x, y + 1, x, y + dy); |
| if (x < (s - 2)) { |
| g.drawLine(x + 1, y, x + 1, y + dy + 1); |
| } |
| g.setColor(trail); |
| g.drawLine(x, y + dy + 1, x, y + dy + 1); |
| if (x >= (s - 2)) { |
| g.drawLine(x + 1, y + 1, x + 1, y + dy + 1); |
| } |
| dy += 2; |
| y -= 1; |
| } |
| break; |
| } |
| } |
| } |
| |
| final class XAWTScrollBarUI extends BasicScrollBarUI { |
| |
| @Override |
| protected void installDefaults() |
| { |
| super.installDefaults(); |
| scrollbar.setBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); |
| } |
| |
| @Override |
| protected void configureScrollBarColors() { |
| UIDefaults uidefaults = XToolkit.getUIDefaults(); |
| Color bg = scrollbar.getBackground(); |
| if (bg == null || bg instanceof UIResource) { |
| scrollbar.setBackground(uidefaults.getColor("ScrollBar.background")); |
| } |
| |
| Color fg = scrollbar.getForeground(); |
| if (fg == null || fg instanceof UIResource) { |
| scrollbar.setForeground(uidefaults.getColor("ScrollBar.foreground")); |
| } |
| |
| thumbHighlightColor = uidefaults.getColor("ScrollBar.thumbHighlight"); |
| thumbLightShadowColor = uidefaults.getColor("ScrollBar.thumbShadow"); |
| thumbDarkShadowColor = uidefaults.getColor("ScrollBar.thumbDarkShadow"); |
| thumbColor = uidefaults.getColor("ScrollBar.thumb"); |
| trackColor = uidefaults.getColor("ScrollBar.track"); |
| |
| trackHighlightColor = uidefaults.getColor("ScrollBar.trackHighlight"); |
| |
| } |
| |
| @Override |
| protected JButton createDecreaseButton(int orientation) { |
| JButton b = new XAWTScrollBarButton(orientation); |
| return b; |
| |
| } |
| |
| @Override |
| protected JButton createIncreaseButton(int orientation) { |
| JButton b = new XAWTScrollBarButton(orientation); |
| return b; |
| } |
| |
| public JButton getDecreaseButton(){ |
| return decrButton; |
| } |
| |
| public JButton getIncreaseButton(){ |
| return incrButton; |
| } |
| |
| @Override |
| public void paint(Graphics g, JComponent c) { |
| paintTrack(g, c, getTrackBounds()); |
| Rectangle thumbBounds = getThumbBounds(); |
| paintThumb(g, c, thumbBounds); |
| } |
| |
| @Override |
| public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) |
| { |
| if(!scrollbar.isEnabled()) { |
| return; |
| } |
| |
| if (thumbBounds.isEmpty()) |
| thumbBounds = getTrackBounds(); |
| |
| int w = thumbBounds.width; |
| int h = thumbBounds.height; |
| |
| g.translate(thumbBounds.x, thumbBounds.y); |
| g.setColor(thumbColor); |
| g.fillRect(0, 0, w-1, h-1); |
| |
| g.setColor(thumbHighlightColor); |
| g.drawLine(0, 0, 0, h-1); |
| g.drawLine(1, 0, w-1, 0); |
| |
| g.setColor(thumbLightShadowColor); |
| g.drawLine(1, h-1, w-1, h-1); |
| g.drawLine(w-1, 1, w-1, h-2); |
| |
| g.translate(-thumbBounds.x, -thumbBounds.y); |
| } |
| } |
| |
| @SuppressWarnings("serial") // JDK-implementation class |
| final class AWTTextArea extends JTextArea implements DocumentListener { |
| |
| private boolean isFocused = false; |
| private final XTextAreaPeer peer; |
| |
| AWTTextArea(String text, XTextAreaPeer peer) { |
| super(text); |
| setFocusable(false); |
| this.peer = peer; |
| } |
| |
| @Override |
| public void insertUpdate(DocumentEvent e) { |
| if (peer != null) { |
| peer.postEvent(new TextEvent(peer.target, |
| TextEvent.TEXT_VALUE_CHANGED)); |
| } |
| } |
| |
| @Override |
| public void removeUpdate(DocumentEvent e) { |
| if (peer != null) { |
| peer.postEvent(new TextEvent(peer.target, |
| TextEvent.TEXT_VALUE_CHANGED)); |
| } |
| } |
| |
| @Override |
| public void changedUpdate(DocumentEvent e) { |
| if (peer != null) { |
| peer.postEvent(new TextEvent(peer.target, |
| TextEvent.TEXT_VALUE_CHANGED)); |
| } |
| } |
| |
| void forwardFocusGained( FocusEvent e) { |
| isFocused = true; |
| FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), |
| e.getOppositeComponent(), e.getCause()); |
| super.processFocusEvent(fe); |
| } |
| |
| |
| void forwardFocusLost( FocusEvent e) { |
| isFocused = false; |
| FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), |
| e.getOppositeComponent(), e.getCause()); |
| super.processFocusEvent(fe); |
| } |
| |
| @Override |
| public boolean hasFocus() { |
| return isFocused; |
| } |
| |
| public void repaintNow() { |
| paintImmediately(getBounds()); |
| } |
| |
| public void processMouseEventPublic(MouseEvent e) { |
| processMouseEvent(e); |
| } |
| |
| public void processMouseMotionEventPublic(MouseEvent e) { |
| processMouseMotionEvent(e); |
| } |
| |
| public void processInputMethodEventPublic(InputMethodEvent e) { |
| processInputMethodEvent(e); |
| } |
| |
| @Override |
| public void updateUI() { |
| ComponentUI ui = new AWTTextAreaUI(); |
| setUI(ui); |
| } |
| |
| // Fix for 4915454 - override the default implementation to avoid |
| // loading SystemFlavorMap and associated classes. |
| @Override |
| public void setTransferHandler(TransferHandler newHandler) { |
| TransferHandler oldHandler = (TransferHandler) |
| getClientProperty(AWTAccessor.getClientPropertyKeyAccessor() |
| .getJComponent_TRANSFER_HANDLER()); |
| putClientProperty(AWTAccessor.getClientPropertyKeyAccessor() |
| .getJComponent_TRANSFER_HANDLER(), |
| newHandler); |
| |
| firePropertyChange("transferHandler", oldHandler, newHandler); |
| } |
| } |
| |
| final class XAWTScrollPaneUI extends BasicScrollPaneUI { |
| |
| private final Border vsbMarginBorderR = new EmptyBorder(0, 2, 0, 0); |
| private final Border vsbMarginBorderL = new EmptyBorder(0, 0, 0, 2); |
| private final Border hsbMarginBorder = new EmptyBorder(2, 0, 0, 0); |
| |
| private Border vsbBorder; |
| private Border hsbBorder; |
| |
| private PropertyChangeListener propertyChangeHandler; |
| |
| @Override |
| protected void installListeners(JScrollPane scrollPane) { |
| super.installListeners(scrollPane); |
| propertyChangeHandler = createPropertyChangeHandler(); |
| scrollPane.addPropertyChangeListener(propertyChangeHandler); |
| } |
| |
| @Override |
| public void paint(Graphics g, JComponent c) { |
| Border vpBorder = scrollpane.getViewportBorder(); |
| if (vpBorder != null) { |
| Rectangle r = scrollpane.getViewportBorderBounds(); |
| vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); |
| } |
| } |
| |
| @Override |
| protected void uninstallListeners(JComponent scrollPane) { |
| super.uninstallListeners(scrollPane); |
| scrollPane.removePropertyChangeListener(propertyChangeHandler); |
| } |
| |
| private PropertyChangeListener createPropertyChangeHandler() { |
| return new PropertyChangeListener() { |
| @Override |
| public void propertyChange(PropertyChangeEvent e) { |
| String propertyName = e.getPropertyName(); |
| |
| if (propertyName.equals("componentOrientation")) { |
| JScrollPane pane = (JScrollPane)e.getSource(); |
| JScrollBar vsb = pane.getVerticalScrollBar(); |
| if (vsb != null) { |
| if (isLeftToRight(pane)) { |
| vsbBorder = new CompoundBorder(new EmptyBorder(0, 4, 0, -4), |
| vsb.getBorder()); |
| } else { |
| vsbBorder = new CompoundBorder(new EmptyBorder(0, -4, 0, 4), |
| vsb.getBorder()); |
| } |
| vsb.setBorder(vsbBorder); |
| } |
| } |
| }}; |
| } |
| |
| boolean isLeftToRight( Component c ) { |
| return c.getComponentOrientation().isLeftToRight(); |
| } |
| |
| @Override |
| protected void installDefaults(JScrollPane scrollpane) { |
| Border b = scrollpane.getBorder(); |
| UIDefaults uidefaults = XToolkit.getUIDefaults(); |
| scrollpane.setBorder(uidefaults.getBorder("ScrollPane.border")); |
| scrollpane.setBackground(uidefaults.getColor("ScrollPane.background")); |
| scrollpane.setViewportBorder(uidefaults.getBorder("TextField.border")); |
| JScrollBar vsb = scrollpane.getVerticalScrollBar(); |
| if (vsb != null) { |
| if (isLeftToRight(scrollpane)) { |
| vsbBorder = new CompoundBorder(vsbMarginBorderR, |
| vsb.getBorder()); |
| } |
| else { |
| vsbBorder = new CompoundBorder(vsbMarginBorderL, |
| vsb.getBorder()); |
| } |
| vsb.setBorder(vsbBorder); |
| } |
| |
| JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
| if (hsb != null) { |
| hsbBorder = new CompoundBorder(hsbMarginBorder, hsb.getBorder()); |
| hsb.setBorder(hsbBorder); |
| } |
| } |
| |
| @Override |
| protected void uninstallDefaults(JScrollPane c) { |
| super.uninstallDefaults(c); |
| |
| JScrollBar vsb = scrollpane.getVerticalScrollBar(); |
| if (vsb != null) { |
| if (vsb.getBorder() == vsbBorder) { |
| vsb.setBorder(null); |
| } |
| vsbBorder = null; |
| } |
| |
| JScrollBar hsb = scrollpane.getHorizontalScrollBar(); |
| if (hsb != null) { |
| if (hsb.getBorder() == hsbBorder) { |
| hsb.setBorder(null); |
| } |
| hsbBorder = null; |
| } |
| } |
| } |
| |
| @SuppressWarnings("serial") // JDK-implementation class |
| private class AWTTextPane extends JScrollPane implements FocusListener { |
| |
| private final JTextArea jtext; |
| private final XWindow xwin; |
| |
| private final Color control = SystemColor.control; |
| private final Color focus = SystemColor.activeCaptionBorder; |
| |
| AWTTextPane(JTextArea jt, XWindow xwin, Container parent) { |
| super(jt); |
| this.xwin = xwin; |
| setDoubleBuffered(true); |
| jt.addFocusListener(this); |
| AWTAccessor.getComponentAccessor().setParent(this,parent); |
| setViewportBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); |
| this.jtext = jt; |
| setFocusable(false); |
| addNotify(); |
| } |
| |
| @Override |
| public void invalidate() { |
| synchronized (getTreeLock()) { |
| final Container parent = getParent(); |
| AWTAccessor.getComponentAccessor().setParent(this, null); |
| try { |
| super.invalidate(); |
| } finally { |
| AWTAccessor.getComponentAccessor().setParent(this, parent); |
| } |
| } |
| } |
| |
| @Override |
| public void focusGained(FocusEvent e) { |
| Graphics g = getGraphics(); |
| Rectangle r = getViewportBorderBounds(); |
| g.setColor(focus); |
| g.drawRect(r.x,r.y,r.width,r.height); |
| g.dispose(); |
| } |
| |
| @Override |
| public void focusLost(FocusEvent e) { |
| Graphics g = getGraphics(); |
| Rectangle r = getViewportBorderBounds(); |
| g.setColor(control); |
| g.drawRect(r.x,r.y,r.width,r.height); |
| g.dispose(); |
| } |
| |
| public Window getRealParent() { |
| return (Window) xwin.target; |
| } |
| |
| @Override |
| public void updateUI() { |
| ComponentUI ui = new XAWTScrollPaneUI(); |
| setUI(ui); |
| } |
| |
| @Override |
| public JScrollBar createVerticalScrollBar() { |
| return new XAWTScrollBar(JScrollBar.VERTICAL); |
| } |
| |
| @Override |
| public JScrollBar createHorizontalScrollBar() { |
| return new XAWTScrollBar(JScrollBar.HORIZONTAL); |
| } |
| |
| public JTextArea getTextArea () { |
| return this.jtext; |
| } |
| |
| @Override |
| public Graphics getGraphics() { |
| return xwin.getGraphics(); |
| } |
| |
| @SuppressWarnings("serial") // JDK-implementation class |
| final class XAWTScrollBar extends ScrollBar { |
| |
| XAWTScrollBar(int i) { |
| super(i); |
| setFocusable(false); |
| } |
| |
| @Override |
| public void updateUI() { |
| ComponentUI ui = new XAWTScrollBarUI(); |
| setUI(ui); |
| } |
| } |
| } |
| |
| @SuppressWarnings("serial") // JDK-implementation class |
| static class BevelBorder extends AbstractBorder implements UIResource { |
| private Color darkShadow = SystemColor.controlDkShadow; |
| private Color lightShadow = SystemColor.controlLtHighlight; |
| private Color control = SystemColor.controlShadow; |
| private boolean isRaised; |
| |
| BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) { |
| this.isRaised = isRaised; |
| this.darkShadow = darkShadow; |
| this.lightShadow = lightShadow; |
| } |
| |
| @Override |
| public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { |
| g.setColor((isRaised) ? lightShadow : darkShadow); |
| g.drawLine(x, y, x+w-1, y); // top |
| g.drawLine(x, y+h-1, x, y+1); // left |
| |
| g.setColor(control); |
| g.drawLine(x+1, y+1, x+w-2, y+1); // top |
| g.drawLine(x+1, y+h-1, x+1, y+1); // left |
| |
| g.setColor((isRaised) ? darkShadow : lightShadow); |
| g.drawLine(x+1, y+h-1, x+w-1, y+h-1); // bottom |
| g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right |
| |
| g.setColor(control); |
| g.drawLine(x+1, y+h-2, x+w-2, y+h-2); // bottom |
| g.drawLine(x+w-2, y+h-2, x+w-2, y+1); // right |
| } |
| |
| @Override |
| public Insets getBorderInsets(Component c) { |
| return getBorderInsets(c, new Insets(0,0,0,0)); |
| } |
| |
| @Override |
| public Insets getBorderInsets(Component c, Insets insets) { |
| insets.top = insets.left = insets.bottom = insets.right = 2; |
| return insets; |
| } |
| |
| public boolean isOpaque(Component c) { |
| return true; |
| } |
| } |
| |
| |
| // This class dispatches 'MouseEvent's to 'XTextAreaPeer''s (hidden) |
| // subcomponents, and overrides mouse cursor, e.g. for scrollbars. |
| // |
| // However, current dispatching is a kind of fake, and is tuned to do only |
| // what is necessary/possible. E.g. no additional mouse-exited/entered |
| // events are generated, when mouse exits scrollbar and enters viewport |
| // with JTextArea inside. Actually, no events are ever generated here (for |
| // now). They are only dispatched as correctly as possible/neccessary. |
| // |
| // In future, it would be better to replace fake-emulation of grab-detection |
| // and event-dispatching here, by reusing some common implementation of this |
| // functionality. Mouse-cursor setting should also be freed of hacked |
| // overloading here. |
| |
| private static final class JavaMouseEventHandler { |
| private final XTextAreaPeer outer; |
| private final Pointer current = new Pointer(); |
| private boolean grabbed = false; |
| |
| JavaMouseEventHandler( XTextAreaPeer outer ) { |
| this.outer = outer; |
| } |
| |
| |
| // 1. We can make grab-tracking emulation here more robust to variations in |
| // in mouse-events order and consistence. E.g. by using such code: |
| // if( grabbed && event.getID()==MouseEvent.MOUSE_MOVED ) grabbed = false; |
| // Or we can also use 'assert'ions. |
| // 2. WARNING: Currently, while grab-detection mechanism _here_ says, that |
| // grab is in progress, we do not update 'current'. In case 'current' |
| // is set to a scrollbar or to a scroll-button, then references to their |
| // 'Component'-instances are "remembered". And events are dispatched to |
| // these remembered components, without checking, if XTextAreaPeer has |
| // replaced these instances with another ones. This also aplies to |
| // mouse-drags-from-outside (see comment in 'grabbed_update' method). |
| |
| void handle( MouseEvent event ) { |
| if ( ! grabbed ) { |
| // dispatch() needs up-to-date pointer in ungrabbed case. |
| setPointerToUnderPoint( event.getPoint() ); |
| } |
| dispatch( event ); |
| boolean wasGrabbed = grabbed; |
| grabbed_update( event ); |
| if ( wasGrabbed && ! grabbed ) { |
| setPointerToUnderPoint( event.getPoint() ); |
| } |
| setCursor(); |
| } |
| |
| // Following is internally private: |
| |
| // Here dispatching is performed, of 'MouseEvent's to (some) |
| // 'XTextAreaPeer''s (hidden) subcomponents. |
| private void dispatch( MouseEvent event ) { |
| switch( current.getType() ) |
| { |
| case TEXT: |
| Point point = toViewportChildLocalSpace( |
| outer.textPane.getViewport(), event.getPoint() ); |
| XTextAreaPeer.AWTTextArea jtext = outer.jtext; |
| MouseEvent newEvent = newMouseEvent( jtext, point, event ); |
| int id = newEvent.getID(); |
| if ( id==MouseEvent.MOUSE_MOVED || id==MouseEvent.MOUSE_DRAGGED ) { |
| jtext.processMouseMotionEventPublic( newEvent ); |
| } else { |
| jtext.processMouseEventPublic( newEvent ); |
| } |
| break; |
| |
| // We perform (additional) dispatching of events to buttons of |
| // scrollbar, instead of leaving it to JScrollbar. This is |
| // required, because of different listeners in Swing and AWT, |
| // which trigger scrolling (ArrowButtonListener vs. TrackListener, |
| // accordingly). So we dispatch events to scroll-buttons, to |
| // invoke a correct Swing button listener. |
| // See CR 6175401 for more information. |
| case BAR: |
| case BUTTON: |
| Component c = current.getBar(); |
| Point p = toLocalSpace( c, event.getPoint() ); |
| if ( current.getType()==Pointer.Type.BUTTON ) { |
| c = current.getButton(); |
| p = toLocalSpace( c, p ); |
| } |
| AWTAccessor.getComponentAccessor().processEvent( c, newMouseEvent( c, p, event ) ); |
| break; |
| } |
| } |
| |
| @SuppressWarnings("deprecation") |
| private static MouseEvent newMouseEvent( |
| Component source, Point point, MouseEvent template ) |
| { |
| MouseEvent e = template; |
| MouseEvent nme = new MouseEvent( |
| source, |
| e.getID(), e.getWhen(), |
| e.getModifiersEx() | e.getModifiers(), |
| point.x, point.y, |
| e.getXOnScreen(), e.getYOnScreen(), |
| e.getClickCount(), e.isPopupTrigger(), e.getButton() ); |
| // Because these MouseEvents are dispatched directly to |
| // their target, we need to mark them as being |
| // system-generated here |
| SunToolkit.setSystemGenerated(nme); |
| return nme; |
| } |
| |
| private void setCursor() { |
| if ( current.getType()==Pointer.Type.TEXT ) { |
| // 'target.getCursor()' is also applied from elsewhere |
| // (at least now), but only when mouse "entered", and |
| // before 'XTextAreaPeer.handleJavaMouseEvent' is invoked. |
| outer.pSetCursor( outer.target.getCursor(), true ); |
| } |
| else { |
| // We can write here a more intelligent cursor selection |
| // mechanism, like getting cursor from 'current' component. |
| // However, I see no point in doing so now. But if you feel |
| // like implementing it, you'll probably need to introduce |
| // 'Pointer.Type.PANEL'. |
| outer.pSetCursor( outer.textPane.getCursor(), true ); |
| } |
| } |
| |
| |
| // Current way of grab-detection causes interesting (but harmless) |
| // side-effect. If mouse is draged from outside to inside of TextArea, |
| // we will then (in some cases) be asked to dispatch mouse-entered/exited |
| // events. But, as at least one mouse-button is down, we will detect |
| // grab-mode is on (though the grab isn't ours). |
| // |
| // Thus, we will not update 'current' (see 'handle' method), and will |
| // dispatch events to the last subcomponent, the 'current' was set to. |
| // As always, we set cursor in this case also. But, all this seems |
| // harmless, because mouse entered/exited events seem to have no effect |
| // here, and cursor setting is ignored in case of drags from outside. |
| // |
| // Grab-detection can be further improved, e.g. by taking into account |
| // current event-ID, but I see not point in doing it now. |
| |
| private void grabbed_update( MouseEvent event ) { |
| final int allButtonsMask |
| = MouseEvent.BUTTON1_DOWN_MASK |
| | MouseEvent.BUTTON2_DOWN_MASK |
| | MouseEvent.BUTTON3_DOWN_MASK; |
| grabbed = ( (event.getModifiersEx() & allButtonsMask) != 0 ); |
| } |
| |
| // 'toLocalSpace' and 'toViewportChildLocalSpace' can be "optimized" to |
| // 'return' 'void' and use 'Point' input-argument also as output. |
| private static Point toLocalSpace( Component local, Point inParentSpace ) |
| { |
| Point p = inParentSpace; |
| Point l = local.getLocation(); |
| return new Point( p.x - l.x, p.y - l.y ); |
| } |
| private static Point toViewportChildLocalSpace( JViewport v, Point inViewportParentSpace ) |
| { |
| Point l = toLocalSpace(v, inViewportParentSpace); |
| Point p = v.getViewPosition(); |
| l.x += p.x; |
| l.y += p.y; |
| return l; |
| } |
| |
| private void setPointerToUnderPoint( Point point ) { |
| if ( outer.textPane.getViewport().getBounds().contains( point ) ) { |
| current.setText(); |
| } |
| else if ( ! setPointerIfPointOverScrollbar( |
| outer.textPane.getVerticalScrollBar(), point ) ) |
| { |
| if ( ! setPointerIfPointOverScrollbar( |
| outer.textPane.getHorizontalScrollBar(), point ) ) |
| { |
| current.setNone(); |
| } |
| } |
| } |
| |
| private boolean setPointerIfPointOverScrollbar( JScrollBar bar, Point point ) { |
| if ( ! bar.getBounds().contains( point ) ) { |
| return false; |
| } |
| current.setBar( bar ); |
| Point local = toLocalSpace( bar, point ); |
| |
| XTextAreaPeer.XAWTScrollBarUI ui = |
| (XTextAreaPeer.XAWTScrollBarUI) bar.getUI(); |
| |
| if ( ! setPointerIfPointOverButton( ui.getIncreaseButton(), local ) ) { |
| setPointerIfPointOverButton( ui.getDecreaseButton(), local ); |
| } |
| |
| return true; |
| } |
| |
| private boolean setPointerIfPointOverButton( JButton button, Point point ) { |
| if ( ! button.getBounds().contains( point ) ) { |
| return false; |
| } |
| current.setButton( button ); |
| return true; |
| } |
| |
| private static final class Pointer { |
| static enum Type { |
| NONE, TEXT, BAR, BUTTON // , PANEL |
| } |
| Type getType() { |
| return type; |
| } |
| boolean isNone() { |
| return type==Type.NONE; |
| } |
| JScrollBar getBar() { |
| boolean ok = type==Type.BAR || type==Type.BUTTON; |
| assert ok; |
| return ok ? bar : null; |
| } |
| JButton getButton() { |
| boolean ok = type==Type.BUTTON; |
| assert ok; |
| return ok ? button : null; |
| } |
| void setNone() { |
| type = Type.NONE; |
| } |
| void setText() { |
| type = Type.TEXT; |
| } |
| void setBar( JScrollBar bar ) { |
| this.bar=bar; |
| type=Type.BAR; |
| } |
| void setButton( JButton button ) { |
| this.button=button; |
| type=Type.BUTTON; |
| } |
| |
| private Type type; |
| private JScrollBar bar; |
| private JButton button; |
| } |
| } |
| } |