gt:             textRect.x = textRect.y = textRect.width = textRect.height = 0;
context: /*
   * $Id: JXButton.java 4257 2012-11-14 17:08:20Z kschaefe $
   *
   * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,
   * Santa Clara, California 95054, U.S.A. All rights reserved.
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This 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
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  
  package org.jdesktop.swingx;
  
  import java.awt.Color;
  import java.awt.Dimension;
  import java.awt.Font;
  import java.awt.Graphics;
  import java.awt.Graphics2D;
  import java.awt.Insets;
  import java.awt.Rectangle;
  import java.awt.image.BufferedImage;
  import java.awt.image.BufferedImageOp;
  
  import javax.swing.Action;
  import javax.swing.ButtonModel;
  import javax.swing.CellRendererPane;
  import javax.swing.Icon;
  import javax.swing.JButton;
  import javax.swing.SwingUtilities;
  import javax.swing.plaf.basic.BasicGraphicsUtils;
  
  import org.jdesktop.beans.JavaBean;
  import org.jdesktop.swingx.graphics.FilterComposite;
  import org.jdesktop.swingx.painter.AbstractPainter;
  import org.jdesktop.swingx.painter.Painter;
  import org.jdesktop.swingx.painter.PainterPaint;
  import org.jdesktop.swingx.util.GraphicsUtilities;
  import org.jdesktop.swingx.util.PaintUtils;
  
  /**
   * <p>A {@link org.jdesktop.swingx.painter.Painter} enabled subclass of {@link javax.swing.JButton}.
   * This class supports setting the foreground and background painters of the button separately.</p>
   *
   * <p>For example, if you wanted to blur <em>just the text</em> on the button, and let everything else be
   * handled by the UI delegate for your look and feel, then you could:
   * <pre><code>
   *  JXButton b = new JXButton("Execute");
   *  AbstractPainter fgPainter = (AbstractPainter)b.getForegroundPainter();
   *  StackBlurFilter filter = new StackBlurFilter();
   *  fgPainter.setFilters(filter);
   * </code></pre>
   *
   * <p>If <em>either</em> the foreground painter or the background painter is set,
   * then super.paintComponent() is not called. By setting both the foreground and background
   * painters to null, you get <em>exactly</em> the same painting behavior as JButton.</p>
   *
   * @author rbair
   * @author rah003
   * @author Jan Stola
   * @author Karl George Schaefer
   */
  @JavaBean
  @SuppressWarnings({ "nls", "serial" })
  public class JXButton extends JButton implements BackgroundPaintable {
      private class BackgroundButton extends JButton {
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isDefaultButton() {
              return JXButton.this.isDefaultButton();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getDisabledIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getDisabledSelectedIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getDisplayedMnemonicIndex() {
              return -1;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getHorizontalAlignment() {
              return JXButton.this.getHorizontalAlignment();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getHorizontalTextPosition() {
              return JXButton.this.getHorizontalTextPosition();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getIconTextGap() {
              return JXButton.this.getIconTextGap();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Insets getMargin() {
              return JXButton.this.getMargin();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getMnemonic() {
              return -1;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public ButtonModel getModel() {
              return JXButton.this.getModel();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getPressedIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getRolloverIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getRolloverSelectedIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getSelectedIcon() {
              return null;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public String getText() {
              return "";
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getVerticalAlignment() {
              return JXButton.this.getVerticalAlignment();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public int getVerticalTextPosition() {
              return JXButton.this.getVerticalTextPosition();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isBorderPainted() {
              return JXButton.this.isBorderPainted();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isContentAreaFilled() {
              return JXButton.this.isContentAreaFilled();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isFocusPainted() {
              return false;
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isRolloverEnabled() {
              return JXButton.this.isRolloverEnabled();
          }
  
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isSelected() {
              return JXButton.this.isSelected();
          }
          
      }
      
      private class ForegroundButton extends JButton {
          @Override
          public Font getFont() {
              return JXButton.this.getFont();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Color getForeground() {
              if (fgPainter == null) {
                  return JXButton.this.getForeground();
              }
              
              return PaintUtils.setAlpha(JXButton.this.getForeground(), 0);
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isDefaultButton() {
              return JXButton.this.isDefaultButton();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getDisabledIcon() {
              return JXButton.this.getDisabledIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getDisabledSelectedIcon() {
              return JXButton.this.getDisabledSelectedIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getDisplayedMnemonicIndex() {
              return JXButton.this.getDisplayedMnemonicIndex();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getHorizontalAlignment() {
              return JXButton.this.getHorizontalAlignment();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getHorizontalTextPosition() {
              return JXButton.this.getHorizontalTextPosition();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getIcon() {
              return JXButton.this.getIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getIconTextGap() {
              return JXButton.this.getIconTextGap();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Insets getMargin() {
              return JXButton.this.getMargin();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getMnemonic() {
              return JXButton.this.getMnemonic();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public ButtonModel getModel() {
              return JXButton.this.getModel();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getPressedIcon() {
              return JXButton.this.getPressedIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getRolloverIcon() {
              return JXButton.this.getRolloverIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getRolloverSelectedIcon() {
              return JXButton.this.getRolloverSelectedIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public Icon getSelectedIcon() {
              return JXButton.this.getSelectedIcon();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public String getText() {
              return JXButton.this.getText();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getVerticalAlignment() {
              return JXButton.this.getVerticalAlignment();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public int getVerticalTextPosition() {
              return JXButton.this.getVerticalTextPosition();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isBorderPainted() {
              return JXButton.this.isBorderPainted();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isContentAreaFilled() {
              return false;
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean hasFocus() {
              return JXButton.this.hasFocus();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isFocusPainted() {
              return JXButton.this.isFocusPainted();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isRolloverEnabled() {
              return JXButton.this.isRolloverEnabled();
          }
          
          /**
           * {@inheritDoc}
           */
          @Override
          public boolean isSelected() {
              return JXButton.this.isSelected();
          }
      }
      
      private ForegroundButton fgStamp;
      @SuppressWarnings("rawtypes")
      private Painter fgPainter;
      @SuppressWarnings("rawtypes")
      private PainterPaint fgPaint;
      private BackgroundButton bgStamp;
      @SuppressWarnings("rawtypes")
      private Painter bgPainter;
      
      private boolean paintBorderInsets = true;
  
      private Rectangle viewRect = new Rectangle();
      private Rectangle textRect = new Rectangle();
      private Rectangle iconRect = new Rectangle();
      
      /**
       * Creates a button with no set text or icon.
       */
      public JXButton() {
          init();
      }
  
      /**
       * Creates a button with text.
       * 
       * @param text
       *            the text of the button
       */
      public JXButton(String text) {
          super(text);
          init();
      }
  
      /**
       * Creates a button where properties are taken from the {@code Action} supplied.
       * 
       * @param a
       *            the {@code Action} used to specify the new button
       */
      public JXButton(Action a) {
          super(a);
          init();
      }
  
      /**
       * Creates a button with an icon.
       * 
       * @param icon
       *            the Icon image to display on the button
       */
      public JXButton(Icon icon) {
          super(icon);
          init();
      }
  
      /**
       * Creates a button with initial text and an icon.
       * 
       * @param text
       *            the text of the button
       * @param icon
       *            the Icon image to display on the button
       */
      public JXButton(String text, Icon icon) {
          super(text, icon);
          init();
      }
      
      private void init() {
          fgStamp = new ForegroundButton();
      }
      
      /**
       * {@inheritDoc}
       */
      @Override
      @SuppressWarnings("rawtypes")
      public Painter getBackgroundPainter() {
          return bgPainter;
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      @SuppressWarnings("rawtypes")
      public void setBackgroundPainter(Painter p) {
          Painter old = getBackgroundPainter();
          this.bgPainter = p;
          firePropertyChange("backgroundPainter", old, getBackgroundPainter());
          repaint();
      }
      
      /**
       * @return the foreground painter for this button
       */
      @SuppressWarnings("rawtypes")
      public Painter getForegroundPainter() {
          return fgPainter;
      }
  
      @SuppressWarnings({ "unchecked", "rawtypes" })
      public void setForegroundPainter(Painter p) {
          Painter old = getForegroundPainter();
          this.fgPainter = p;
          
          if (fgPainter == null) {
              fgPaint = null;
          } else {
              fgPaint = new PainterPaint(fgPainter, this);
              
              if (bgStamp == null) {
                  bgStamp = new BackgroundButton();
              }
          }
          
          firePropertyChange("foregroundPainter", old, getForegroundPainter());
          repaint();
      }
  
      /**
       * Returns true if the background painter should paint where the border is
       * or false if it should only paint inside the border. This property is
       * true by default. This property affects the width, height,
       * and initial transform passed to the background painter.
       */
      @Override
      public boolean isPaintBorderInsets() {
          return paintBorderInsets;
      }
  
      /**
       * Sets the paintBorderInsets property.
       * Set to true if the background painter should paint where the border is
       * or false if it should only paint inside the border. This property is true by default.
       * This property affects the width, height,
       * and initial transform passed to the background painter.
       *
       * This is a bound property.
       */
      @Override
      public void setPaintBorderInsets(boolean paintBorderInsets) {
          boolean old = this.isPaintBorderInsets();
          this.paintBorderInsets = paintBorderInsets;
          firePropertyChange("paintBorderInsets", old, isPaintBorderInsets());
      }
      
      /**
       * {@inheritDoc}
       */
      @Override
      public Dimension getPreferredSize() {
          if (getComponentCount() == 1 && getComponent(0) instanceof CellRendererPane) {
              return BasicGraphicsUtils.getPreferredButtonSize(fgStamp, getIconTextGap());
          }
          
          return super.getPreferredSize();
      }
  
      /**
       * {@inheritDoc}
       */
      @Override
      protected void paintComponent(Graphics g) {
          if (fgPainter == null && bgPainter == null) {
              super.paintComponent(g);
          } else {
              if (fgPainter == null) {
                  Graphics2D g2d = (Graphics2D) g.create();
                  
                  try{
                      paintWithoutForegroundPainter(g2d);
                  } finally {
                      g2d.dispose();
                  }
              } else if (fgPainter instanceof AbstractPainter && ((AbstractPainter<?>) fgPainter).getFilters().length > 0) {
                  paintWithForegroundPainterWithFilters(g);
              } else {
                  Graphics2D g2d = (Graphics2D) g.create();
                  
                  try {
                      paintWithForegroundPainterWithoutFilters(g2d);
                  } finally {
                      g2d.dispose();
                  }
              }
          }
      }
      
      private void paintWithoutForegroundPainter(Graphics2D g2d) {
          if (bgPainter == null) {
              SwingUtilities.paintComponent(g2d, bgStamp, this, 0, 0, getWidth(), getHeight());
          } else {
              SwingXUtilities.paintBackground(this, g2d);
          }
          
          SwingUtilities.paintComponent(g2d, fgStamp, this, 0, 0, getWidth(), getHeight());
      }
      
      private void paintWithForegroundPainterWithoutFilters(Graphics2D g2d) {
          paintWithoutForegroundPainter(g2d);
          
          if (getText() != null && !getText().isEmpty()) {
              Insets i = getInsets();
              viewRect.x = i.left;
              viewRect.y = i.top;
              viewRect.width = getWidth() - (i.right + viewRect.x);
              viewRect.height = getHeight() - (i.bottom + viewRect.y);
  
  