1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package javax.swing.border;
  26 
  27 import java.awt.Graphics;
  28 import java.awt.Insets;
  29 import java.awt.Component;
  30 import java.beans.ConstructorProperties;
  31 
  32 /**
  33  * A composite Border class used to compose two Border objects
  34  * into a single border by nesting an inside Border object within
  35  * the insets of an outside Border object.
  36  *
  37  * For example, this class may be used to add blank margin space
  38  * to a component with an existing decorative border:
  39  *
  40  * <pre>
  41  *    Border border = comp.getBorder();
  42  *    Border margin = new EmptyBorder(10,10,10,10);
  43  *    comp.setBorder(new CompoundBorder(border, margin));
  44  * </pre>
  45  * <p>
  46  * <strong>Warning:</strong>
  47  * Serialized objects of this class will not be compatible with
  48  * future Swing releases. The current serialization support is
  49  * appropriate for short term storage or RMI between applications running
  50  * the same version of Swing.  As of 1.4, support for long term storage
  51  * of all JavaBeans&trade;
  52  * has been added to the <code>java.beans</code> package.
  53  * Please see {@link java.beans.XMLEncoder}.
  54  *
  55  * @author David Kloba
  56  */
  57 @SuppressWarnings("serial")
  58 public class CompoundBorder extends AbstractBorder {
  59     /**
  60      * The outside border.
  61      */
  62     protected Border outsideBorder;
  63     /**
  64      * The inside border.
  65      */
  66     protected Border insideBorder;
  67 
  68     /**
  69      * Creates a compound border with null outside and inside borders.
  70      */
  71     public CompoundBorder() {
  72         this.outsideBorder = null;
  73         this.insideBorder = null;
  74     }
  75 
  76     /**
  77      * Creates a compound border with the specified outside and
  78      * inside borders.  Either border may be null.
  79      * @param outsideBorder the outside border
  80      * @param insideBorder the inside border to be nested
  81      */
  82     @ConstructorProperties({"outsideBorder", "insideBorder"})
  83     public CompoundBorder(Border outsideBorder, Border insideBorder) {
  84         this.outsideBorder = outsideBorder;
  85         this.insideBorder = insideBorder;
  86     }
  87 
  88     /**
  89      * Returns whether or not the compound border is opaque.
  90      *
  91      * @return {@code true} if the inside and outside borders
  92      *         are each either {@code null} or opaque;
  93      *         or {@code false} otherwise
  94      */
  95     @Override
  96     public boolean isBorderOpaque() {
  97         return (outsideBorder == null || outsideBorder.isBorderOpaque()) &&
  98                (insideBorder == null || insideBorder.isBorderOpaque());
  99     }
 100 
 101     /**
 102      * Paints the compound border by painting the outside border
 103      * with the specified position and size and then painting the
 104      * inside border at the specified position and size offset by
 105      * the insets of the outside border.
 106      * @param c the component for which this border is being painted
 107      * @param g the paint graphics
 108      * @param x the x position of the painted border
 109      * @param y the y position of the painted border
 110      * @param width the width of the painted border
 111      * @param height the height of the painted border
 112      */
 113     public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
 114         Insets  nextInsets;
 115         int px, py, pw, ph;
 116 
 117         px = x;
 118         py = y;
 119         pw = width;
 120         ph = height;
 121 
 122         if(outsideBorder != null) {
 123             outsideBorder.paintBorder(c, g, px, py, pw, ph);
 124 
 125             nextInsets = outsideBorder.getBorderInsets(c);
 126             px += nextInsets.left;
 127             py += nextInsets.top;
 128             pw = pw - nextInsets.right - nextInsets.left;
 129             ph = ph - nextInsets.bottom - nextInsets.top;
 130         }
 131         if(insideBorder != null)
 132             insideBorder.paintBorder(c, g, px, py, pw, ph);
 133 
 134     }
 135 
 136     /**
 137      * Reinitialize the insets parameter with this Border's current Insets.
 138      * @param c the component for which this border insets value applies
 139      * @param insets the object to be reinitialized
 140      */
 141     public Insets getBorderInsets(Component c, Insets insets) {
 142         Insets  nextInsets;
 143 
 144         insets.top = insets.left = insets.right = insets.bottom = 0;
 145         if(outsideBorder != null) {
 146             nextInsets = outsideBorder.getBorderInsets(c);
 147             insets.top += nextInsets.top;
 148             insets.left += nextInsets.left;
 149             insets.right += nextInsets.right;
 150             insets.bottom += nextInsets.bottom;
 151         }
 152         if(insideBorder != null) {
 153             nextInsets = insideBorder.getBorderInsets(c);
 154             insets.top += nextInsets.top;
 155             insets.left += nextInsets.left;
 156             insets.right += nextInsets.right;
 157             insets.bottom += nextInsets.bottom;
 158         }
 159         return insets;
 160     }
 161 
 162     /**
 163      * Returns the outside border object.
 164      *
 165      * @return the outside {@code Border} object
 166      */
 167     public Border getOutsideBorder() {
 168         return outsideBorder;
 169     }
 170 
 171     /**
 172      * Returns the inside border object.
 173      *
 174      * @return the inside {@code Border} object
 175      */
 176     public Border getInsideBorder() {
 177         return insideBorder;
 178     }
 179 }