001    /* CompoundBorder.java -- 
002       Copyright (C) 2003 Free Software Foundation, Inc.
003    
004    This file is part of GNU Classpath.
005    
006    GNU Classpath is free software; you can redistribute it and/or modify
007    it under the terms of the GNU General Public License as published by
008    the Free Software Foundation; either version 2, or (at your option)
009    any later version.
010    
011    GNU Classpath is distributed in the hope that it will be useful, but
012    WITHOUT ANY WARRANTY; without even the implied warranty of
013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014    General Public License for more details.
015    
016    You should have received a copy of the GNU General Public License
017    along with GNU Classpath; see the file COPYING.  If not, write to the
018    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019    02110-1301 USA.
020    
021    Linking this library statically or dynamically with other modules is
022    making a combined work based on this library.  Thus, the terms and
023    conditions of the GNU General Public License cover the whole
024    combination.
025    
026    As a special exception, the copyright holders of this library give you
027    permission to link this library with independent modules to produce an
028    executable, regardless of the license terms of these independent
029    modules, and to copy and distribute the resulting executable under
030    terms of your choice, provided that you also meet, for each linked
031    independent module, the terms and conditions of the license of that
032    module.  An independent module is a module which is not derived from
033    or based on this library.  If you modify this library, you may extend
034    this exception to your version of the library, but you are not
035    obligated to do so.  If you do not wish to do so, delete this
036    exception statement from your version. */
037    
038    
039    package javax.swing.border;
040    
041    import java.awt.Component;
042    import java.awt.Graphics;
043    import 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     */
051    public 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    }