001/* CompoundBorder.java -- 
002   Copyright (C) 2003 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.border;
040
041import java.awt.Component;
042import java.awt.Graphics;
043import java.awt.Insets;
044
045/**
046 * A Border that is composed of an interior and an exterior border,
047 * where the interior border is tightly nested into the exterior.
048 *
049 * @author Sascha Brawer (brawer@dandelis.ch)
050 */
051public class CompoundBorder extends AbstractBorder
052{
053  /**
054   * Determined using the <code>serialver</code> tool
055   * of Apple/Sun JDK 1.3.1 on MacOS X 10.1.5.
056   */
057  static final long serialVersionUID = 9054540377030555103L;
058
059  /**
060   * The inside border, which is painted between the bordered
061   * Component and the outside border. It is valid for
062   * <code>insideBorder</code> to be <code>null</code>.
063   */
064  protected Border insideBorder;
065
066  /**
067   * The outside border, which is painted outside both the
068   * bordered Component and the inside border. It is valid for
069   * <code>outsideBorder</code> to be <code>null</code>.
070   */
071  protected Border outsideBorder;
072
073  /**
074   * Constructs a CompoundBorder whose inside and outside borders
075   * are both <code>null</code>. While this does not really make
076   * any sense (there exists a class EmptyBorder as well, and not
077   * every Component needs to have a border at all), the API
078   * specification requires the existence of this constructor.
079   *
080   * @see EmptyBorder
081   */
082  public CompoundBorder()
083  {
084    this (null, null);
085  }
086
087  /**
088   * Constructs a CompoundBorder with the specified inside and
089   * outside borders.
090   *
091   * @param outsideBorder the outside border, which is painted to the
092   *        outside of both <code>insideBorder</code> and the enclosed
093   *        component. It is acceptable to pass <code>null</code>, in
094   *        which case no outside border is painted.
095   *
096   * @param insideBorder the inside border, which is painted to
097   *        between <code>outsideBorder</code> and the enclosed
098   *        component. It is acceptable to pass <code>null</code>, in
099   *        which case no inside border is painted.
100   */
101  public CompoundBorder(Border outsideBorder, Border insideBorder)
102  {
103    this.outsideBorder = outsideBorder;
104    this.insideBorder = insideBorder;
105  }
106
107  /**
108   * Determines whether or not this border is opaque. An opaque
109   * border fills every pixel in its area when painting. Partially
110   * translucent borders must return <code>false</code>, or ugly
111   * artifacts can appear on screen.
112   *
113   * @return <code>true</code> if both the inside and outside borders
114   *         are opaque, or <code>false</code> otherwise.
115   */
116  public boolean isBorderOpaque()
117  {
118    // Although the API specification states that this method 
119    // returns true if both the inside and outside borders are non-null
120    // and opaque, and false otherwise, a mauve test shows that if both
121    // the inside or outside borders are null, then true is returned.
122    if ((insideBorder == null) && (outsideBorder == null))
123      return true;
124
125    // A mauve test shows that if the inside border has a null value,
126    // then true is returned if the outside border is opaque; if the
127    // outside border has a null value, then true is returned if the
128    // inside border is opaque; else, true is returned if both the
129    // inside and outside borders are opaque.
130    if (insideBorder == null)
131      return outsideBorder.isBorderOpaque();
132    else if (outsideBorder == null)
133      return insideBorder.isBorderOpaque();
134    else
135      return insideBorder.isBorderOpaque() && outsideBorder.isBorderOpaque();
136  }
137
138  /**
139   * Paints the compound border by first painting the outside border,
140   * then painting the inside border tightly nested into the outside. 
141   *
142   * @param c the component whose border is to be painted.
143   * @param g the graphics for painting.
144   * @param x the horizontal position for painting the border.
145   * @param y the vertical position for painting the border.
146   * @param width the width of the available area for painting the border.
147   * @param height the height of the available area for painting the border.
148   */
149  public void paintBorder(Component c, Graphics g,
150                          int x, int y, int width, int height)
151  {
152    // If there is an outside border, paint it and reduce the
153    // bounding box by its insets.
154    //
155    if (outsideBorder != null)
156    {
157      Insets outsideInsets;
158
159      outsideBorder.paintBorder(c, g, x, y, width, height);
160      outsideInsets = outsideBorder.getBorderInsets(c);
161
162      x += outsideInsets.left;
163      y += outsideInsets.top;
164
165      // Reduce width and height by the respective extent of the
166      // outside border.
167      width -= outsideInsets.left + outsideInsets.right;
168      height -= outsideInsets.top + outsideInsets.bottom;
169    }
170
171    if (insideBorder != null)
172      insideBorder.paintBorder(c, g, x, y, width, height);
173  }
174
175  /**
176   * Changes the specified insets to the insets of this border,
177   * which is the sum of the insets of the inside and the outside
178   * border.
179   *
180   * @param c the component in the center of this border.
181   * @param insets an Insets object for holding the added insets.
182   *
183   * @return the <code>insets</code> object.
184   */
185  public Insets getBorderInsets(Component c, Insets insets)
186  {
187    Insets borderInsets;
188
189    if (insets == null)
190      insets = new Insets(0, 0, 0, 0);
191    else
192      insets.left = insets.right = insets.top = insets.bottom = 0;
193
194    // If there is an outside border, add it to insets.
195    if (outsideBorder != null)
196    {
197      borderInsets = outsideBorder.getBorderInsets(c);
198      insets.left += borderInsets.left;
199      insets.right += borderInsets.right;
200      insets.top += borderInsets.top;
201      insets.bottom += borderInsets.bottom;
202    }
203
204    // If there is an inside border, add it to insets.
205    if (insideBorder != null)
206    {
207      borderInsets = insideBorder.getBorderInsets(c);
208      insets.left += borderInsets.left;
209      insets.right += borderInsets.right;
210      insets.top += borderInsets.top;
211      insets.bottom += borderInsets.bottom;
212    }
213
214    return insets;
215  }
216
217  /**
218   * Determines the insets of this border, which is the sum of the
219   * insets of the inside and the outside border.
220   *
221   * @param c the component in the center of this border.
222   */
223  public Insets getBorderInsets(Component c)
224  {
225    // It is not clear why CompoundBorder does not simply inherit
226    // the implementation from AbstractBorder. However, we want
227    // to be compatible with the API specification, which overrides
228    // the getBorderInsets(Component) method.
229    return getBorderInsets(c, null);
230  }
231
232  /**
233   * Returns the outside border, which is painted outside both the
234   * bordered Component and the inside border. It is valid for the
235   * result to be <code>null</code>.
236   * 
237   * @return The outside border (possibly <code>null</code>).
238   */
239  public Border getOutsideBorder()
240  {
241    return outsideBorder;
242  }
243
244  /**
245   * Returns the inside border, which is painted between the bordered
246   * Component and the outside border. It is valid for the result to
247   * be <code>null</code>.
248   * 
249   * @return The inside border (possibly <code>null</code>).
250   */
251  public Border getInsideBorder()
252  {
253    return insideBorder;
254  }
255}