1 /*
   2  * Copyright (c) 2005, 2011, 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 sun.swing;
  26 
  27 import java.awt.Container;
  28 import java.awt.Insets;
  29 import javax.swing.*;
  30 import javax.swing.LayoutStyle.ComponentPlacement;
  31 import javax.swing.border.Border;
  32 import javax.swing.plaf.UIResource;
  33 
  34 /**
  35  * An implementation of {@code LayoutStyle} that returns 6 for related
  36  * components, otherwise 12.  This class also provides helper methods for
  37  * subclasses.
  38  *
  39  */
  40 public class DefaultLayoutStyle extends LayoutStyle {
  41     private static final DefaultLayoutStyle INSTANCE =
  42             new DefaultLayoutStyle();
  43 
  44     public static LayoutStyle getInstance() {
  45         return INSTANCE;
  46     }
  47 
  48     @Override
  49     public int getPreferredGap(JComponent component1, JComponent component2,
  50             ComponentPlacement type, int position, Container parent) {
  51         if (component1 == null || component2 == null || type == null) {
  52             throw new NullPointerException();
  53         }
  54 
  55         checkPosition(position);
  56 
  57         if (type == ComponentPlacement.INDENT &&
  58                 (position == SwingConstants.EAST ||
  59                  position == SwingConstants.WEST)) {
  60             int indent = getIndent(component1, position);
  61             if (indent > 0) {
  62                 return indent;
  63             }
  64         }
  65         return (type == ComponentPlacement.UNRELATED) ? 12 : 6;
  66     }
  67 
  68     @Override
  69     public int getContainerGap(JComponent component, int position,
  70                                Container parent) {
  71         if (component == null) {
  72             throw new NullPointerException();
  73         }
  74         checkPosition(position);
  75         return 6;
  76     }
  77 
  78     /**
  79      * Returns true if the classes identify a JLabel and a non-JLabel
  80      * along the horizontal axis.
  81      */
  82     protected boolean isLabelAndNonlabel(JComponent c1, JComponent c2,
  83                                          int position) {
  84         if (position == SwingConstants.EAST ||
  85                 position == SwingConstants.WEST) {
  86             boolean c1Label = (c1 instanceof JLabel);
  87             boolean c2Label = (c2 instanceof JLabel);
  88             return ((c1Label || c2Label) && (c1Label != c2Label));
  89         }
  90         return false;
  91     }
  92 
  93     /**
  94      * For some look and feels check boxs and radio buttons typically
  95      * don't paint the border, yet they have padding for a border.  Look
  96      * and feel guidelines generally don't include this space.  Use
  97      * this method to subtract this space from the specified
  98      * components.
  99      *
 100      * @param source First component
 101      * @param target Second component
 102      * @param position Position doing layout along.
 103      * @param offset Ideal offset, not including border/margin
 104      * @return offset - border/margin around the component.
 105      */
 106     protected int getButtonGap(JComponent source, JComponent target,
 107                                int position, int offset) {
 108         offset -= getButtonGap(source, position);
 109         if (offset > 0) {
 110             offset -= getButtonGap(target, flipDirection(position));
 111         }
 112         if (offset < 0) {
 113             return 0;
 114         }
 115         return offset;
 116     }
 117 
 118     /**
 119      * For some look and feels check boxs and radio buttons typically
 120      * don't paint the border, yet they have padding for a border.  Look
 121      * and feel guidelines generally don't include this space.  Use
 122      * this method to subtract this space from the specified
 123      * components.
 124      *
 125      * @param source Component
 126      * @param position Position doing layout along.
 127      * @param offset Ideal offset, not including border/margin
 128      * @return offset - border/margin around the component.
 129      */
 130     protected int getButtonGap(JComponent source, int position, int offset) {
 131         offset -= getButtonGap(source, position);
 132         return Math.max(offset, 0);
 133     }
 134 
 135     /**
 136      * If {@code c} is a check box or radio button, and the border is
 137      * not painted this returns the inset along the specified axis.
 138      */
 139     public int getButtonGap(JComponent c, int position) {
 140         String classID = c.getUIClassID();
 141         if ((classID == "CheckBoxUI" || classID == "RadioButtonUI") &&
 142                 !((AbstractButton)c).isBorderPainted()) {
 143             Border border = c.getBorder();
 144             if (border instanceof UIResource) {
 145                 return getInset(c, position);
 146             }
 147         }
 148         return 0;
 149     }
 150 
 151     private void checkPosition(int position) {
 152         if (position != SwingConstants.NORTH &&
 153                 position != SwingConstants.SOUTH &&
 154                 position != SwingConstants.WEST &&
 155                 position != SwingConstants.EAST) {
 156             throw new IllegalArgumentException();
 157         }
 158     }
 159 
 160     protected int flipDirection(int position) {
 161         switch(position) {
 162         case SwingConstants.NORTH:
 163             return SwingConstants.SOUTH;
 164         case SwingConstants.SOUTH:
 165             return SwingConstants.NORTH;
 166         case SwingConstants.EAST:
 167             return SwingConstants.WEST;
 168         case SwingConstants.WEST:
 169             return SwingConstants.EAST;
 170         }
 171         assert false;
 172         return 0;
 173     }
 174 
 175     /**
 176      * Returns the amount to indent the specified component if it's
 177      * a JCheckBox or JRadioButton.  If the component is not a JCheckBox or
 178      * JRadioButton, 0 will be returned.
 179      */
 180     protected int getIndent(JComponent c, int position) {
 181         String classID = c.getUIClassID();
 182         if (classID == "CheckBoxUI" || classID == "RadioButtonUI") {
 183             AbstractButton button = (AbstractButton)c;
 184             Insets insets = c.getInsets();
 185             Icon icon = getIcon(button);
 186             int gap = button.getIconTextGap();
 187             if (isLeftAligned(button, position)) {
 188                 return insets.left + icon.getIconWidth() + gap;
 189             } else if (isRightAligned(button, position)) {
 190                 return insets.right + icon.getIconWidth() + gap;
 191             }
 192         }
 193         return 0;
 194     }
 195 
 196     private Icon getIcon(AbstractButton button) {
 197         Icon icon = button.getIcon();
 198         if (icon != null) {
 199             return icon;
 200         }
 201         String key = null;
 202         if (button instanceof JCheckBox) {
 203             key = "CheckBox.icon";
 204         } else if (button instanceof JRadioButton) {
 205             key = "RadioButton.icon";
 206         }
 207         if (key != null) {
 208             Object oIcon = UIManager.get(key);
 209             if (oIcon instanceof Icon) {
 210                 return (Icon)oIcon;
 211             }
 212         }
 213         return null;
 214     }
 215 
 216     private boolean isLeftAligned(AbstractButton button, int position) {
 217         if (position == SwingConstants.WEST) {
 218             boolean ltr = button.getComponentOrientation().isLeftToRight();
 219             int hAlign = button.getHorizontalAlignment();
 220             return ((ltr && (hAlign == SwingConstants.LEFT ||
 221                              hAlign == SwingConstants.LEADING)) ||
 222                     (!ltr && (hAlign == SwingConstants.TRAILING)));
 223         }
 224         return false;
 225     }
 226 
 227     private boolean isRightAligned(AbstractButton button, int position) {
 228         if (position == SwingConstants.EAST) {
 229             boolean ltr = button.getComponentOrientation().isLeftToRight();
 230             int hAlign = button.getHorizontalAlignment();
 231             return ((ltr && (hAlign == SwingConstants.RIGHT ||
 232                              hAlign == SwingConstants.TRAILING)) ||
 233                     (!ltr && (hAlign == SwingConstants.LEADING)));
 234         }
 235         return false;
 236     }
 237 
 238     private int getInset(JComponent c, int position) {
 239         return getInset(c.getInsets(), position);
 240     }
 241 
 242     private int getInset(Insets insets, int position) {
 243         if (insets == null) {
 244             return 0;
 245         }
 246         switch(position) {
 247         case SwingConstants.NORTH:
 248             return insets.top;
 249         case SwingConstants.SOUTH:
 250             return insets.bottom;
 251         case SwingConstants.EAST:
 252             return insets.right;
 253         case SwingConstants.WEST:
 254             return insets.left;
 255         }
 256         assert false;
 257         return 0;
 258     }
 259 }
--- EOF ---