/* * This file is part of WebLookAndFeel library. * * WebLookAndFeel library 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 3 of the License, or * (at your option) any later version. * * WebLookAndFeel library 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 WebLookAndFeel library. If not, see . */ package com.alee.laf.text; import com.alee.extended.painter.Painter; import com.alee.extended.painter.PainterSupport; import com.alee.global.StyleConstants; import com.alee.laf.WebLookAndFeel; import com.alee.managers.language.LM; import com.alee.utils.GraphicsUtils; import com.alee.utils.LafUtils; import com.alee.utils.SwingUtils; import com.alee.utils.laf.ShapeProvider; import com.alee.utils.swing.BorderMethods; import javax.swing.*; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTextFieldUI; import javax.swing.text.JTextComponent; import java.awt.*; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Map; /** * User: mgarin Date: 16.05.11 Time: 16:39 */ public class WebTextFieldUI extends BasicTextFieldUI implements ShapeProvider, SwingConstants, BorderMethods { private JTextField textField = null; private boolean drawBorder = WebTextFieldStyle.drawBorder; private boolean drawFocus = WebTextFieldStyle.drawFocus; private int round = WebTextFieldStyle.round; private boolean drawShade = WebTextFieldStyle.drawShade; private int shadeWidth = WebTextFieldStyle.shadeWidth; private boolean drawBackground = WebTextFieldStyle.drawBackground; private boolean webColored = WebTextFieldStyle.webColored; private Insets fieldMargin = WebTextFieldStyle.fieldMargin; private String inputPrompt = WebTextFieldStyle.inputPrompt; private Font inputPromptFont = WebTextFieldStyle.inputPromptFont; private Color inputPromptForeground = WebTextFieldStyle.inputPromptForeground; private int inputPromptPosition = WebTextFieldStyle.inputPromptPosition; private boolean hideInputPromptOnFocus = WebTextFieldStyle.hideInputPromptOnFocus; private Painter painter = WebTextFieldStyle.painter; private JComponent leadingComponent = null; private JComponent trailingComponent = null; private boolean inputPromptSet = false; private FocusListener focusListener; private PropertyChangeListener accessibleChangeListener; private PropertyChangeListener orientationChangeListener; private PropertyChangeListener marginChangeListener; private ComponentAdapter componentResizeListener; @SuppressWarnings ( "UnusedParameters" ) public static ComponentUI createUI ( final JComponent c ) { return new WebTextFieldUI (); } @Override public void installUI ( final JComponent c ) { super.installUI ( c ); this.textField = ( JTextField ) c; // Default settings SwingUtils.setOrientation ( textField ); LookAndFeel.installProperty ( textField, WebLookAndFeel.OPAQUE_PROPERTY, Boolean.FALSE ); textField.putClientProperty ( SwingUtils.HANDLES_ENABLE_STATE, true ); textField.setFocusable ( true ); textField.setMargin ( WebTextFieldStyle.margin ); textField.setBackground ( Color.WHITE ); textField.setSelectionColor ( StyleConstants.textSelectionColor ); textField.setForeground ( Color.BLACK ); textField.setSelectedTextColor ( Color.BLACK ); textField.setCaretColor ( Color.GRAY ); textField.setLayout ( new TextComponentLayout ( textField ) ); PainterSupport.installPainter ( textField, this.painter ); // Updating border updateBorder (); focusListener = new FocusListener () { @Override public void focusLost ( final FocusEvent e ) { textField.repaint (); } @Override public void focusGained ( final FocusEvent e ) { textField.repaint (); } }; textField.addFocusListener ( focusListener ); accessibleChangeListener = new PropertyChangeListener () { @Override public void propertyChange ( final PropertyChangeEvent evt ) { updateInnerComponents (); } }; textField.addPropertyChangeListener ( WebLookAndFeel.ENABLED_PROPERTY, accessibleChangeListener ); orientationChangeListener = new PropertyChangeListener () { @Override public void propertyChange ( final PropertyChangeEvent evt ) { updateBorder (); } }; textField.addPropertyChangeListener ( WebLookAndFeel.ORIENTATION_PROPERTY, orientationChangeListener ); marginChangeListener = new PropertyChangeListener () { @Override public void propertyChange ( final PropertyChangeEvent evt ) { updateBorder (); } }; textField.addPropertyChangeListener ( WebLookAndFeel.MARGIN_PROPERTY, marginChangeListener ); componentResizeListener = new ComponentAdapter () { @Override public void componentResized ( final ComponentEvent e ) { updateBorder (); } }; } @Override public void uninstallUI ( final JComponent c ) { PainterSupport.uninstallPainter ( textField, this.painter ); textField.putClientProperty ( SwingUtils.HANDLES_ENABLE_STATE, null ); textField.removeFocusListener ( focusListener ); textField.removePropertyChangeListener ( WebLookAndFeel.ENABLED_PROPERTY, accessibleChangeListener ); textField.removePropertyChangeListener ( WebLookAndFeel.ORIENTATION_PROPERTY, orientationChangeListener ); textField.removePropertyChangeListener ( WebLookAndFeel.MARGIN_PROPERTY, marginChangeListener ); cleanupLeadingComponent (); cleanupTrailingComponent (); textField.setLayout ( null ); this.textField = null; super.uninstallUI ( c ); } @Override public Shape provideShape () { if ( drawBorder ) { return LafUtils.getWebBorderShape ( textField, shadeWidth, round ); } else { return SwingUtils.size ( textField ); } } private void updateInnerComponents () { if ( leadingComponent != null ) { leadingComponent.setEnabled ( textField.isEnabled () ); } if ( trailingComponent != null ) { trailingComponent.setEnabled ( textField.isEnabled () ); } } public JComponent getLeadingComponent () { return leadingComponent; } public void setLeadingComponent ( final JComponent leadingComponent ) { if ( this.leadingComponent == leadingComponent ) { return; } // Removing old leading component cleanupLeadingComponent (); // New leading component if ( leadingComponent != null ) { this.leadingComponent = leadingComponent; // Registering resize listener this.leadingComponent.addComponentListener ( componentResizeListener ); // Adding component textField.add ( leadingComponent, TextComponentLayout.LEADING ); // Updating components state updateInnerComponents (); } // Updating layout textField.revalidate (); // Updating border updateBorder (); } private void cleanupLeadingComponent () { if ( this.leadingComponent != null ) { this.leadingComponent.removeComponentListener ( componentResizeListener ); textField.remove ( this.leadingComponent ); this.leadingComponent = null; } } public JComponent getTrailingComponent () { return trailingComponent; } public void setTrailingComponent ( final JComponent trailingComponent ) { if ( this.trailingComponent == trailingComponent ) { return; } // Removing old trailing component cleanupTrailingComponent (); // New trailing component if ( trailingComponent != null ) { this.trailingComponent = trailingComponent; // Registering resize listener this.trailingComponent.addComponentListener ( componentResizeListener ); // Adding component textField.add ( trailingComponent, TextComponentLayout.TRAILING ); // Updating components state updateInnerComponents (); } // Updating layout textField.revalidate (); // Updating border updateBorder (); } private void cleanupTrailingComponent () { if ( this.trailingComponent != null ) { this.trailingComponent.removeComponentListener ( componentResizeListener ); textField.remove ( this.trailingComponent ); this.trailingComponent = null; } } public void setFieldMargin ( final Insets margin ) { this.fieldMargin = margin; updateBorder (); } public Insets getFieldMargin () { return fieldMargin; } public String getInputPrompt () { return inputPrompt; } public void setInputPrompt ( final String inputPrompt ) { this.inputPrompt = inputPrompt; this.inputPromptSet = inputPrompt != null && !inputPrompt.trim ().equals ( "" ); updateInputPromptView (); } public Font getInputPromptFont () { return inputPromptFont; } public void setInputPromptFont ( final Font inputPromptFont ) { this.inputPromptFont = inputPromptFont; updateInputPromptView (); } public Color getInputPromptForeground () { return inputPromptForeground; } public void setInputPromptForeground ( final Color inputPromptForeground ) { this.inputPromptForeground = inputPromptForeground; updateInputPromptView (); } public int getInputPromptPosition () { return inputPromptPosition; } public void setInputPromptPosition ( final int inputPromptPosition ) { this.inputPromptPosition = inputPromptPosition; updateInputPromptView (); } public boolean isHideInputPromptOnFocus () { return hideInputPromptOnFocus; } public void setHideInputPromptOnFocus ( final boolean hideInputPromptOnFocus ) { this.hideInputPromptOnFocus = hideInputPromptOnFocus; updateInputPromptView (); } public boolean isDrawShade () { return drawShade; } public void setDrawShade ( final boolean drawShade ) { this.drawShade = drawShade; } public int getShadeWidth () { return shadeWidth; } public void setShadeWidth ( final int shadeWidth ) { this.shadeWidth = shadeWidth; updateBorder (); } public boolean isDrawBackground () { return drawBackground; } public void setDrawBackground ( final boolean drawBackground ) { this.drawBackground = drawBackground; updateView (); } public boolean isWebColored () { return webColored; } public void setWebColored ( final boolean webColored ) { this.webColored = webColored; updateView (); } public int getRound () { return round; } public void setRound ( final int round ) { this.round = round; updateView (); } public boolean isDrawBorder () { return drawBorder; } public void setDrawBorder ( final boolean drawBorder ) { this.drawBorder = drawBorder; updateBorder (); } public boolean isDrawFocus () { return drawFocus; } public void setDrawFocus ( final boolean drawFocus ) { this.drawFocus = drawFocus; updateView (); } public Painter getPainter () { return painter; } public void setPainter ( final Painter painter ) { PainterSupport.uninstallPainter ( textField, this.painter ); this.painter = painter; getComponent ().setOpaque ( painter == null || painter.isOpaque ( textField ) ); PainterSupport.installPainter ( textField, this.painter ); updateBorder (); } private void updateInputPromptView () { if ( isInputPromptVisible ( getComponent () ) ) { updateView (); } } private boolean isInputPromptVisible ( final JTextComponent c ) { return inputPromptSet && c.isEditable () && c.isEnabled () && ( !hideInputPromptOnFocus || !c.isFocusOwner () ) && c.getText ().equals ( "" ); } private void updateView () { if ( textField != null ) { textField.repaint (); } } /** * {@inheritDoc} */ @Override public void updateBorder () { if ( textField != null ) { // Preserve old borders if ( SwingUtils.isPreserveBorders ( textField ) ) { return; } // Style border final Insets m; if ( painter != null ) { m = painter.getMargin ( getComponent () ); } else if ( drawBorder ) { m = new Insets ( shadeWidth + 1, shadeWidth + 1, shadeWidth + 1, shadeWidth + 1 ); } else { m = new Insets ( 0, 0, 0, 0 ); } // Taking margins into account final boolean ltr = textField.getComponentOrientation ().isLeftToRight (); final Insets margin = textField.getMargin (); if ( margin != null ) { m.top += margin.top; m.left += ltr ? margin.left : margin.right; m.bottom += margin.bottom; m.right += ltr ? margin.right : margin.left; } if ( fieldMargin != null ) { m.top += fieldMargin.top; m.left += ltr ? fieldMargin.left : fieldMargin.right; m.bottom += fieldMargin.bottom; m.right += ltr ? fieldMargin.right : fieldMargin.left; } // Adding component sizes into border final Component lc = ltr ? leadingComponent : trailingComponent; final Component tc = ltr ? trailingComponent : leadingComponent; if ( lc != null ) { m.left += lc.getPreferredSize ().width; } if ( tc != null ) { m.right += tc.getPreferredSize ().width; } // Final border textField.setBorder ( LafUtils.createWebBorder ( m ) ); } } @Override protected void paintSafely ( final Graphics g ) { final JTextComponent c = getComponent (); final Graphics2D g2d = ( Graphics2D ) g; if ( c.isOpaque () && ( painter == null || !painter.isOpaque ( textField ) ) ) { // Paint default background g.setColor ( c.getBackground () ); g.fillRect ( 0, 0, c.getWidth (), c.getHeight () ); } if ( painter != null || drawBorder ) { final Object aa = GraphicsUtils.setupAntialias ( g2d ); if ( painter != null ) { // Use background painter instead of default UI graphics painter.paint ( g2d, SwingUtils.size ( c ), c ); } else if ( drawBorder ) { // Border, background and shade final Color shadeColor; if ( drawShade ) { shadeColor = drawFocus && c.isFocusOwner () ? StyleConstants.fieldFocusColor : StyleConstants.shadeColor; } else { shadeColor = null; } LafUtils.drawWebStyle ( g2d, c, shadeColor, shadeWidth, round, drawBackground, webColored ); } GraphicsUtils.restoreAntialias ( g2d, aa ); } final Map hints = SwingUtils.setupTextAntialias ( g2d ); super.paintSafely ( g ); if ( isInputPromptVisible ( c ) ) { final boolean ltr = c.getComponentOrientation ().isLeftToRight (); final Rectangle b = getVisibleEditorRect (); final Shape oc = GraphicsUtils.intersectClip ( g2d, b ); g2d.setFont ( inputPromptFont != null ? inputPromptFont : c.getFont () ); g2d.setPaint ( inputPromptForeground != null ? inputPromptForeground : c.getForeground () ); final String text = LM.get ( inputPrompt ); final FontMetrics fm = g2d.getFontMetrics (); final int x; if ( inputPromptPosition == CENTER ) { x = b.x + b.width / 2 - fm.stringWidth ( text ) / 2; } else if ( ltr && inputPromptPosition == LEADING || !ltr && inputPromptPosition == TRAILING || inputPromptPosition == LEFT ) { x = b.x; } else { x = b.x + b.width - fm.stringWidth ( text ); } g2d.drawString ( text, x, getBaseline ( c, c.getWidth (), c.getHeight () ) ); g2d.setClip ( oc ); } SwingUtils.restoreTextAntialias ( g2d, hints ); } @Override protected void paintBackground ( final Graphics g ) { // Do not paint anything here } @Override public Dimension getPreferredSize ( final JComponent c ) { Dimension ps = super.getPreferredSize ( c ); // Fix for Swing bug with pointless scrolling when field's default preferred size is already reached ps.width += 1; // Height might be changed due to inner components if ( leadingComponent != null || trailingComponent != null ) { final Dimension lps = c.getLayout ().preferredLayoutSize ( c ); ps.height = Math.max ( ps.height, lps.height ); } // Background painter preferred size if ( painter != null ) { ps = SwingUtils.max ( ps, painter.getPreferredSize ( c ) ); } return ps; } }