jdk/src/share/classes/javax/swing/border/TitledBorder.java
changeset 5953 33ad0303d717
parent 5506 202f599c92aa
child 7263 3da4189127ac
equal deleted inserted replaced
5952:d3bfe856b893 5953:33ad0303d717
     1 /*
     1 /*
     2  * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     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
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    22  * or visit www.oracle.com if you need additional information or have any
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    23  * questions.
    24  */
    24  */
    25 package javax.swing.border;
    25 package javax.swing.border;
    26 
    26 
    27 import sun.swing.SwingUtilities2;
    27 import java.awt.Color;
    28 
    28 import java.awt.Component;
       
    29 import java.awt.Dimension;
       
    30 import java.awt.Font;
    29 import java.awt.Graphics;
    31 import java.awt.Graphics;
       
    32 import java.awt.Graphics2D;
    30 import java.awt.Insets;
    33 import java.awt.Insets;
    31 import java.awt.Rectangle;
    34 import java.awt.Rectangle;
    32 import java.awt.Color;
    35 import java.awt.geom.Path2D;
    33 import java.awt.Font;
       
    34 import java.awt.FontMetrics;
       
    35 import java.awt.Point;
       
    36 import java.awt.Toolkit;
       
    37 import java.awt.Component;
       
    38 import java.awt.Dimension;
       
    39 import java.beans.ConstructorProperties;
    36 import java.beans.ConstructorProperties;
    40 
       
    41 import javax.swing.JComponent;
    37 import javax.swing.JComponent;
       
    38 import javax.swing.JLabel;
    42 import javax.swing.UIManager;
    39 import javax.swing.UIManager;
       
    40 import javax.swing.plaf.basic.BasicHTML;
    43 
    41 
    44 /**
    42 /**
    45  * A class which implements an arbitrary border
    43  * A class which implements an arbitrary border
    46  * with the addition of a String title in a
    44  * with the addition of a String title in a
    47  * specified position and justification.
    45  * specified position and justification.
    71  */
    69  */
    72 public class TitledBorder extends AbstractBorder
    70 public class TitledBorder extends AbstractBorder
    73 {
    71 {
    74     protected String title;
    72     protected String title;
    75     protected Border border;
    73     protected Border border;
    76     protected int    titlePosition;
    74     protected int titlePosition;
    77     protected int    titleJustification;
    75     protected int titleJustification;
    78     protected Font   titleFont;
    76     protected Font titleFont;
    79     protected Color  titleColor;
    77     protected Color titleColor;
    80 
    78 
    81     private Point textLoc = new Point();
    79     private final JLabel label;
    82 
    80 
    83     /**
    81     /**
    84      * Use the default vertical orientation for the title text.
    82      * Use the default vertical orientation for the title text.
    85      */
    83      */
    86     static public final int     DEFAULT_POSITION        = 0;
    84     static public final int     DEFAULT_POSITION        = 0;
    87     /** Position the title above the border's top line. */
    85     /** Position the title above the border's top line. */
    88     static public final int     ABOVE_TOP       = 1;
    86     static public final int     ABOVE_TOP               = 1;
    89     /** Position the title in the middle of the border's top line. */
    87     /** Position the title in the middle of the border's top line. */
    90     static public final int     TOP             = 2;
    88     static public final int     TOP                     = 2;
    91     /** Position the title below the border's top line. */
    89     /** Position the title below the border's top line. */
    92     static public final int     BELOW_TOP       = 3;
    90     static public final int     BELOW_TOP               = 3;
    93     /** Position the title above the border's bottom line. */
    91     /** Position the title above the border's bottom line. */
    94     static public final int     ABOVE_BOTTOM    = 4;
    92     static public final int     ABOVE_BOTTOM            = 4;
    95     /** Position the title in the middle of the border's bottom line. */
    93     /** Position the title in the middle of the border's bottom line. */
    96     static public final int     BOTTOM          = 5;
    94     static public final int     BOTTOM                  = 5;
    97     /** Position the title below the border's bottom line. */
    95     /** Position the title below the border's bottom line. */
    98     static public final int     BELOW_BOTTOM    = 6;
    96     static public final int     BELOW_BOTTOM            = 6;
    99 
    97 
   100     /**
    98     /**
   101      * Use the default justification for the title text.
    99      * Use the default justification for the title text.
   102      */
   100      */
   103     static public final int     DEFAULT_JUSTIFICATION   = 0;
   101     static public final int     DEFAULT_JUSTIFICATION   = 0;
   104     /** Position title text at the left side of the border line. */
   102     /** Position title text at the left side of the border line. */
   105     static public final int     LEFT    = 1;
   103     static public final int     LEFT                    = 1;
   106     /** Position title text in the center of the border line. */
   104     /** Position title text in the center of the border line. */
   107     static public final int     CENTER  = 2;
   105     static public final int     CENTER                  = 2;
   108     /** Position title text at the right side of the border line. */
   106     /** Position title text at the right side of the border line. */
   109     static public final int     RIGHT   = 3;
   107     static public final int     RIGHT                   = 3;
   110     /** Position title text at the left side of the border line
   108     /** Position title text at the left side of the border line
   111      *  for left to right orientation, at the right side of the
   109      *  for left to right orientation, at the right side of the
   112      *  border line for right to left orientation.
   110      *  border line for right to left orientation.
   113      */
   111      */
   114     static public final int     LEADING = 4;
   112     static public final int     LEADING = 4;
   130     /**
   128     /**
   131      * Creates a TitledBorder instance.
   129      * Creates a TitledBorder instance.
   132      *
   130      *
   133      * @param title  the title the border should display
   131      * @param title  the title the border should display
   134      */
   132      */
   135     public TitledBorder(String title)     {
   133     public TitledBorder(String title) {
   136         this(null, title, LEADING, DEFAULT_POSITION, null, null);
   134         this(null, title, LEADING, DEFAULT_POSITION, null, null);
   137     }
   135     }
   138 
   136 
   139     /**
   137     /**
   140      * Creates a TitledBorder instance with the specified border
   138      * Creates a TitledBorder instance with the specified border
   141      * and an empty title.
   139      * and an empty title.
   142      *
   140      *
   143      * @param border  the border
   141      * @param border  the border
   144      */
   142      */
   145     public TitledBorder(Border border)       {
   143     public TitledBorder(Border border) {
   146         this(border, "", LEADING, DEFAULT_POSITION, null, null);
   144         this(border, "", LEADING, DEFAULT_POSITION, null, null);
   147     }
   145     }
   148 
   146 
   149     /**
   147     /**
   150      * Creates a TitledBorder instance with the specified border
   148      * Creates a TitledBorder instance with the specified border
   165      * @param title  the title the border should display
   163      * @param title  the title the border should display
   166      * @param titleJustification the justification for the title
   164      * @param titleJustification the justification for the title
   167      * @param titlePosition the position for the title
   165      * @param titlePosition the position for the title
   168      */
   166      */
   169     public TitledBorder(Border border,
   167     public TitledBorder(Border border,
   170                         String title,
   168                          String title,
   171                         int titleJustification,
   169                          int titleJustification,
   172                         int titlePosition)      {
   170                          int titlePosition) {
   173         this(border, title, titleJustification,
   171         this(border, title, titleJustification,
   174                         titlePosition, null, null);
   172                         titlePosition, null, null);
   175     }
   173     }
   176 
   174 
   177     /**
   175     /**
   183      * @param titleJustification the justification for the title
   181      * @param titleJustification the justification for the title
   184      * @param titlePosition the position for the title
   182      * @param titlePosition the position for the title
   185      * @param titleFont the font for rendering the title
   183      * @param titleFont the font for rendering the title
   186      */
   184      */
   187     public TitledBorder(Border border,
   185     public TitledBorder(Border border,
   188                         String title,
   186                          String title,
   189                         int titleJustification,
   187                          int titleJustification,
   190                         int titlePosition,
   188                          int titlePosition,
   191                         Font titleFont) {
   189                          Font titleFont) {
   192         this(border, title, titleJustification,
   190         this(border, title, titleJustification,
   193                         titlePosition, titleFont, null);
   191                         titlePosition, titleFont, null);
   194     }
   192     }
   195 
   193 
   196     /**
   194     /**
   205      * @param titleFont the font of the title
   203      * @param titleFont the font of the title
   206      * @param titleColor the color of the title
   204      * @param titleColor the color of the title
   207      */
   205      */
   208     @ConstructorProperties({"border", "title", "titleJustification", "titlePosition", "titleFont", "titleColor"})
   206     @ConstructorProperties({"border", "title", "titleJustification", "titlePosition", "titleFont", "titleColor"})
   209     public TitledBorder(Border border,
   207     public TitledBorder(Border border,
   210                         String title,
   208                          String title,
   211                         int titleJustification,
   209                          int titleJustification,
   212                         int titlePosition,
   210                          int titlePosition,
   213                         Font titleFont,
   211                          Font titleFont,
   214                         Color titleColor)       {
   212                          Color titleColor) {
   215         this.title = title;
   213         this.title = title;
   216         this.border = border;
   214         this.border = border;
   217         this.titleFont = titleFont;
   215         this.titleFont = titleFont;
   218         this.titleColor = titleColor;
   216         this.titleColor = titleColor;
   219 
   217 
   220         setTitleJustification(titleJustification);
   218         setTitleJustification(titleJustification);
   221         setTitlePosition(titlePosition);
   219         setTitlePosition(titlePosition);
       
   220 
       
   221         this.label = new JLabel();
       
   222         this.label.setOpaque(false);
       
   223         this.label.putClientProperty(BasicHTML.propertyKey, null);
   222     }
   224     }
   223 
   225 
   224     /**
   226     /**
   225      * Paints the border for the specified component with the
   227      * Paints the border for the specified component with the
   226      * specified position and size.
   228      * specified position and size.
   230      * @param y the y position of the painted border
   232      * @param y the y position of the painted border
   231      * @param width the width of the painted border
   233      * @param width the width of the painted border
   232      * @param height the height of the painted border
   234      * @param height the height of the painted border
   233      */
   235      */
   234     public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
   236     public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
   235 
   237         Border border = getBorderUI();
   236         Border border = getBorder();
   238         String title = getTitle();
   237 
   239         if ((title != null) && !title.isEmpty()) {
   238         if (getTitle() == null || getTitle().equals("")) {
   240             int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING;
       
   241             JLabel label = getLabel(c);
       
   242             Dimension size = label.getPreferredSize();
       
   243             Insets insets = (border != null)
       
   244                     ? border.getBorderInsets(c)
       
   245                     : new Insets(0, 0, 0, 0);
       
   246 
       
   247             int borderX = x + edge;
       
   248             int borderY = y + edge;
       
   249             int borderW = width - edge - edge;
       
   250             int borderH = height - edge - edge;
       
   251 
       
   252             int labelY = y;
       
   253             int labelH = size.height;
       
   254             int position = getPosition();
       
   255             switch (position) {
       
   256                 case ABOVE_TOP:
       
   257                     insets.left = 0;
       
   258                     insets.right = 0;
       
   259                     borderY += labelH - edge;
       
   260                     borderH -= labelH - edge;
       
   261                     break;
       
   262                 case TOP:
       
   263                     insets.top = edge + insets.top/2 - labelH/2;
       
   264                     if (insets.top < edge) {
       
   265                         borderY -= insets.top;
       
   266                         borderH += insets.top;
       
   267                     }
       
   268                     else {
       
   269                         labelY += insets.top;
       
   270                     }
       
   271                     break;
       
   272                 case BELOW_TOP:
       
   273                     labelY += insets.top + edge;
       
   274                     break;
       
   275                 case ABOVE_BOTTOM:
       
   276                     labelY += height - labelH - insets.bottom - edge;
       
   277                     break;
       
   278                 case BOTTOM:
       
   279                     labelY += height - labelH;
       
   280                     insets.bottom = edge + (insets.bottom - labelH) / 2;
       
   281                     if (insets.bottom < edge) {
       
   282                         borderH += insets.bottom;
       
   283                     }
       
   284                     else {
       
   285                         labelY -= insets.bottom;
       
   286                     }
       
   287                     break;
       
   288                 case BELOW_BOTTOM:
       
   289                     insets.left = 0;
       
   290                     insets.right = 0;
       
   291                     labelY += height - labelH;
       
   292                     borderH -= labelH - edge;
       
   293                     break;
       
   294             }
       
   295             insets.left += edge + TEXT_INSET_H;
       
   296             insets.right += edge + TEXT_INSET_H;
       
   297 
       
   298             int labelX = x;
       
   299             int labelW = width - insets.left - insets.right;
       
   300             if (labelW > size.width) {
       
   301                 labelW = size.width;
       
   302             }
       
   303             switch (getJustification(c)) {
       
   304                 case LEFT:
       
   305                     labelX += insets.left;
       
   306                     break;
       
   307                 case RIGHT:
       
   308                     labelX += width - insets.right - labelW;
       
   309                     break;
       
   310                 case CENTER:
       
   311                     labelX += (width - labelW) / 2;
       
   312                     break;
       
   313             }
       
   314 
   239             if (border != null) {
   315             if (border != null) {
   240                 border.paintBorder(c, g, x, y, width, height);
   316                 if ((position != TOP) && (position != BOTTOM)) {
   241             }
   317                     border.paintBorder(c, g, borderX, borderY, borderW, borderH);
   242             return;
       
   243         }
       
   244 
       
   245         Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING,
       
   246                                              width - (EDGE_SPACING * 2),
       
   247                                              height - (EDGE_SPACING * 2));
       
   248         Font font = g.getFont();
       
   249         Color color = g.getColor();
       
   250 
       
   251         g.setFont(getFont(c));
       
   252 
       
   253         JComponent jc = (c instanceof JComponent) ? (JComponent)c : null;
       
   254         FontMetrics fm = SwingUtilities2.getFontMetrics(jc, g);
       
   255         int         fontHeight = fm.getHeight();
       
   256         int         descent = fm.getDescent();
       
   257         int         ascent = fm.getAscent();
       
   258         int         diff;
       
   259         int         stringWidth = SwingUtilities2.stringWidth(jc, fm,
       
   260                                                               getTitle());
       
   261         Insets      insets;
       
   262 
       
   263         if (border != null) {
       
   264             insets = border.getBorderInsets(c);
       
   265         } else {
       
   266             insets = new Insets(0, 0, 0, 0);
       
   267         }
       
   268 
       
   269         int titlePos = getTitlePosition();
       
   270         switch (titlePos) {
       
   271             case ABOVE_TOP:
       
   272                 diff = ascent + descent + (Math.max(EDGE_SPACING,
       
   273                                  TEXT_SPACING*2) - EDGE_SPACING);
       
   274                 grooveRect.y += diff;
       
   275                 grooveRect.height -= diff;
       
   276                 textLoc.y = grooveRect.y - (descent + TEXT_SPACING);
       
   277                 break;
       
   278             case TOP:
       
   279             case DEFAULT_POSITION:
       
   280                 diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - EDGE_SPACING);
       
   281                 grooveRect.y += diff;
       
   282                 grooveRect.height -= diff;
       
   283                 textLoc.y = (grooveRect.y - descent) +
       
   284                 (insets.top + ascent + descent)/2;
       
   285                 break;
       
   286             case BELOW_TOP:
       
   287                 textLoc.y = grooveRect.y + insets.top + ascent + TEXT_SPACING;
       
   288                 break;
       
   289             case ABOVE_BOTTOM:
       
   290                 textLoc.y = (grooveRect.y + grooveRect.height) -
       
   291                 (insets.bottom + descent + TEXT_SPACING);
       
   292                 break;
       
   293             case BOTTOM:
       
   294                 grooveRect.height -= fontHeight/2;
       
   295                 textLoc.y = ((grooveRect.y + grooveRect.height) - descent) +
       
   296                         ((ascent + descent) - insets.bottom)/2;
       
   297                 break;
       
   298             case BELOW_BOTTOM:
       
   299                 grooveRect.height -= fontHeight;
       
   300                 textLoc.y = grooveRect.y + grooveRect.height + ascent +
       
   301                         TEXT_SPACING;
       
   302                 break;
       
   303         }
       
   304 
       
   305         int justification = getTitleJustification();
       
   306         if(isLeftToRight(c)) {
       
   307             if(justification==LEADING ||
       
   308                justification==DEFAULT_JUSTIFICATION) {
       
   309                 justification = LEFT;
       
   310             }
       
   311             else if(justification==TRAILING) {
       
   312                 justification = RIGHT;
       
   313             }
       
   314         }
       
   315         else {
       
   316             if(justification==LEADING ||
       
   317                justification==DEFAULT_JUSTIFICATION) {
       
   318                 justification = RIGHT;
       
   319             }
       
   320             else if(justification==TRAILING) {
       
   321                 justification = LEFT;
       
   322             }
       
   323         }
       
   324 
       
   325         switch (justification) {
       
   326             case LEFT:
       
   327                 textLoc.x = grooveRect.x + TEXT_INSET_H + insets.left;
       
   328                 break;
       
   329             case RIGHT:
       
   330                 textLoc.x = (grooveRect.x + grooveRect.width) -
       
   331                         (stringWidth + TEXT_INSET_H + insets.right);
       
   332                 break;
       
   333             case CENTER:
       
   334                 textLoc.x = grooveRect.x +
       
   335                         ((grooveRect.width - stringWidth) / 2);
       
   336                 break;
       
   337         }
       
   338 
       
   339         // If title is positioned in middle of border AND its fontsize
       
   340         // is greater than the border's thickness, we'll need to paint
       
   341         // the border in sections to leave space for the component's background
       
   342         // to show through the title.
       
   343         //
       
   344         if (border != null) {
       
   345             if (((titlePos == TOP || titlePos == DEFAULT_POSITION) &&
       
   346                   (grooveRect.y > textLoc.y - ascent)) ||
       
   347                  (titlePos == BOTTOM &&
       
   348                   (grooveRect.y + grooveRect.height < textLoc.y + descent))) {
       
   349 
       
   350                 Rectangle clipRect = new Rectangle();
       
   351 
       
   352                 // save original clip
       
   353                 Rectangle saveClip = g.getClipBounds();
       
   354 
       
   355                 // paint strip left of text
       
   356                 clipRect.setBounds(saveClip);
       
   357                 if (computeIntersection(clipRect, x, y, textLoc.x-1-x, height)) {
       
   358                     g.setClip(clipRect);
       
   359                     border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   360                                   grooveRect.width, grooveRect.height);
       
   361                 }
   318                 }
   362 
   319                 else {
   363                 // paint strip right of text
   320                     Graphics g2 = g.create();
   364                 clipRect.setBounds(saveClip);
   321                     if (g2 instanceof Graphics2D) {
   365                 if (computeIntersection(clipRect, textLoc.x+stringWidth+1, y,
   322                         Graphics2D g2d = (Graphics2D) g2;
   366                                x+width-(textLoc.x+stringWidth+1), height)) {
   323                         Path2D path = new Path2D.Float();
   367                     g.setClip(clipRect);
   324                         path.append(new Rectangle(borderX, borderY, borderW, labelY - borderY), false);
   368                     border.paintBorder(c, g, grooveRect.x, grooveRect.y,
   325                         path.append(new Rectangle(borderX, labelY, labelX - borderX - TEXT_SPACING, labelH), false);
   369                                   grooveRect.width, grooveRect.height);
   326                         path.append(new Rectangle(labelX + labelW + TEXT_SPACING, labelY, borderX - labelX + borderW - labelW - TEXT_SPACING, labelH), false);
       
   327                         path.append(new Rectangle(borderX, labelY + labelH, borderW, borderY - labelY + borderH - labelH), false);
       
   328                         g2d.clip(path);
       
   329                     }
       
   330                     border.paintBorder(c, g2, borderX, borderY, borderW, borderH);
       
   331                     g2.dispose();
   370                 }
   332                 }
   371 
   333             }
   372                 if (titlePos == TOP || titlePos == DEFAULT_POSITION) {
   334             g.translate(labelX, labelY);
   373                     // paint strip below text
   335             label.setSize(labelW, labelH);
   374                     clipRect.setBounds(saveClip);
   336             label.paint(g);
   375                     if (computeIntersection(clipRect, textLoc.x-1, textLoc.y+descent,
   337             g.translate(-labelX, -labelY);
   376                                         stringWidth+2, y+height-textLoc.y-descent)) {
   338         }
   377                         g.setClip(clipRect);
   339         else if (border != null) {
   378                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
   340             border.paintBorder(c, g, x, y, width, height);
   379                                   grooveRect.width, grooveRect.height);
   341         }
   380                     }
       
   381 
       
   382                 } else { // titlePos == BOTTOM
       
   383                   // paint strip above text
       
   384                     clipRect.setBounds(saveClip);
       
   385                     if (computeIntersection(clipRect, textLoc.x-1, y,
       
   386                           stringWidth+2, textLoc.y - ascent - y)) {
       
   387                         g.setClip(clipRect);
       
   388                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   389                                   grooveRect.width, grooveRect.height);
       
   390                     }
       
   391                 }
       
   392 
       
   393                 // restore clip
       
   394                 g.setClip(saveClip);
       
   395 
       
   396             } else {
       
   397                 border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   398                                   grooveRect.width, grooveRect.height);
       
   399             }
       
   400         }
       
   401 
       
   402         g.setColor(getTitleColor());
       
   403         SwingUtilities2.drawString(jc, g, getTitle(), textLoc.x, textLoc.y);
       
   404 
       
   405         g.setFont(font);
       
   406         g.setColor(color);
       
   407     }
   342     }
   408 
   343 
   409     /**
   344     /**
   410      * Reinitialize the insets parameter with this Border's current Insets.
   345      * Reinitialize the insets parameter with this Border's current Insets.
   411      * @param c the component for which this border insets value applies
   346      * @param c the component for which this border insets value applies
   412      * @param insets the object to be reinitialized
   347      * @param insets the object to be reinitialized
   413      */
   348      */
   414     public Insets getBorderInsets(Component c, Insets insets) {
   349     public Insets getBorderInsets(Component c, Insets insets) {
   415         FontMetrics fm;
   350         Border border = getBorderUI();
   416         int         descent = 0;
   351         if (border == null) {
   417         int         ascent = 16;
   352             insets.set(0, 0, 0, 0);
   418         int         height = 16;
   353         }
   419 
   354         else if (border instanceof AbstractBorder) {
   420         Border border = getBorder();
   355             AbstractBorder ab = (AbstractBorder) border;
   421         if (border != null) {
   356             insets = ab.getBorderInsets(c, insets);
   422             if (border instanceof AbstractBorder) {
   357         }
   423                 ((AbstractBorder)border).getBorderInsets(c, insets);
   358         else {
   424             } else {
   359             Insets i = border.getBorderInsets(c);
   425                 // Can't reuse border insets because the Border interface
   360             insets.set(i.top, i.left, i.bottom, i.right);
   426                 // can't be enhanced.
   361         }
   427                 Insets i = border.getBorderInsets(c);
   362         String title = getTitle();
   428                 insets.top = i.top;
   363         if ((title != null) && !title.isEmpty()) {
   429                 insets.right = i.right;
   364             int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING;
   430                 insets.bottom = i.bottom;
   365             JLabel label = getLabel(c);
   431                 insets.left = i.left;
   366             Dimension size = label.getPreferredSize();
   432             }
   367 
   433         } else {
   368             switch (getPosition()) {
   434             insets.left = insets.top = insets.right = insets.bottom = 0;
   369                 case ABOVE_TOP:
   435         }
   370                     insets.top += size.height - edge;
   436 
   371                     break;
   437         insets.left += EDGE_SPACING + TEXT_SPACING;
   372                 case TOP: {
   438         insets.right += EDGE_SPACING + TEXT_SPACING;
   373                     if (insets.top < size.height) {
   439         insets.top += EDGE_SPACING + TEXT_SPACING;
   374                         insets.top = size.height - edge;
   440         insets.bottom += EDGE_SPACING + TEXT_SPACING;
   375                     }
   441 
   376                     break;
   442         if(c == null || getTitle() == null || getTitle().equals(""))    {
   377                 }
   443             return insets;
   378                 case BELOW_TOP:
   444         }
   379                     insets.top += size.height;
   445 
   380                     break;
   446         Font font = getFont(c);
   381                 case ABOVE_BOTTOM:
   447 
   382                     insets.bottom += size.height;
   448         fm = c.getFontMetrics(font);
   383                     break;
   449 
   384                 case BOTTOM: {
   450         if(fm != null) {
   385                     if (insets.bottom < size.height) {
   451            descent = fm.getDescent();
   386                         insets.bottom = size.height - edge;
   452            ascent = fm.getAscent();
   387                     }
   453            height = fm.getHeight();
   388                     break;
   454         }
   389                 }
   455 
   390                 case BELOW_BOTTOM:
   456         switch (getTitlePosition()) {
   391                     insets.bottom += size.height - edge;
   457           case ABOVE_TOP:
   392                     break;
   458               insets.top += ascent + descent
   393             }
   459                             + (Math.max(EDGE_SPACING, TEXT_SPACING*2)
   394             insets.top += edge + TEXT_SPACING;
   460                             - EDGE_SPACING);
   395             insets.left += edge + TEXT_SPACING;
   461               break;
   396             insets.right += edge + TEXT_SPACING;
   462           case TOP:
   397             insets.bottom += edge + TEXT_SPACING;
   463           case DEFAULT_POSITION:
       
   464               insets.top += ascent + descent;
       
   465               break;
       
   466           case BELOW_TOP:
       
   467               insets.top += ascent + descent + TEXT_SPACING;
       
   468               break;
       
   469           case ABOVE_BOTTOM:
       
   470               insets.bottom += ascent + descent + TEXT_SPACING;
       
   471               break;
       
   472           case BOTTOM:
       
   473               insets.bottom += ascent + descent;
       
   474               break;
       
   475           case BELOW_BOTTOM:
       
   476               insets.bottom += height;
       
   477               break;
       
   478         }
   398         }
   479         return insets;
   399         return insets;
   480     }
   400     }
   481 
   401 
   482     /**
   402     /**
   490     public String getTitle()        {       return title;   }
   410     public String getTitle()        {       return title;   }
   491 
   411 
   492     /**
   412     /**
   493      * Returns the border of the titled border.
   413      * Returns the border of the titled border.
   494      */
   414      */
   495     public Border getBorder()       {
   415     public Border getBorder() {
   496         Border b = border;
   416         return border;
   497         if (b == null)
       
   498             b = UIManager.getBorder("TitledBorder.border");
       
   499         return b;
       
   500     }
   417     }
   501 
   418 
   502     /**
   419     /**
   503      * Returns the title-position of the titled border.
   420      * Returns the title-position of the titled border.
   504      */
   421      */
   505     public int getTitlePosition() {
   422     public int getTitlePosition() {
   506         if (titlePosition == DEFAULT_POSITION) {
       
   507             Object value = UIManager.get("TitledBorder.position");
       
   508             if (value instanceof String) {
       
   509                 String s = (String)value;
       
   510                 if ("ABOVE_TOP".equalsIgnoreCase(s)) {
       
   511                     return ABOVE_TOP;
       
   512                 } else if ("TOP".equalsIgnoreCase(s)) {
       
   513                     return TOP;
       
   514                 } else if ("BELOW_TOP".equalsIgnoreCase(s)) {
       
   515                     return BELOW_TOP;
       
   516                 } else if ("ABOVE_BOTTOM".equalsIgnoreCase(s)) {
       
   517                     return ABOVE_BOTTOM;
       
   518                 } else if ("BOTTOM".equalsIgnoreCase(s)) {
       
   519                     return BOTTOM;
       
   520                 } else if ("BELOW_BOTTOM".equalsIgnoreCase(s)) {
       
   521                     return BELOW_BOTTOM;
       
   522                 }
       
   523             } else if (value instanceof Integer) {
       
   524                 int i = (Integer)value;
       
   525                 if (i >= 0 && i <= 6) {
       
   526                     return i;
       
   527                 }
       
   528             }
       
   529         }
       
   530         return titlePosition;
   423         return titlePosition;
   531     }
   424     }
   532 
   425 
   533     /**
   426     /**
   534      * Returns the title-justification of the titled border.
   427      * Returns the title-justification of the titled border.
   537 
   430 
   538     /**
   431     /**
   539      * Returns the title-font of the titled border.
   432      * Returns the title-font of the titled border.
   540      */
   433      */
   541     public Font getTitleFont()      {
   434     public Font getTitleFont()      {
   542         Font f = titleFont;
   435         return titleFont;
   543         if (f == null)
       
   544             f = UIManager.getFont("TitledBorder.font");
       
   545         return f;
       
   546     }
   436     }
   547 
   437 
   548     /**
   438     /**
   549      * Returns the title-color of the titled border.
   439      * Returns the title-color of the titled border.
   550      */
   440      */
   551     public Color getTitleColor()    {
   441     public Color getTitleColor()    {
   552         Color c = titleColor;
   442         return titleColor;
   553         if (c == null)
       
   554             c = UIManager.getColor("TitledBorder.titleColor");
       
   555         return c;
       
   556     }
   443     }
   557 
   444 
   558 
   445 
   559     // REMIND(aim): remove all or some of these set methods?
   446     // REMIND(aim): remove all or some of these set methods?
   560 
   447 
   574      * Sets the title-position of the titled border.
   461      * Sets the title-position of the titled border.
   575      * @param titlePosition the position for the border
   462      * @param titlePosition the position for the border
   576      */
   463      */
   577     public void setTitlePosition(int titlePosition) {
   464     public void setTitlePosition(int titlePosition) {
   578         switch (titlePosition) {
   465         switch (titlePosition) {
   579           case ABOVE_TOP:
   466             case ABOVE_TOP:
   580           case TOP:
   467             case TOP:
   581           case BELOW_TOP:
   468             case BELOW_TOP:
   582           case ABOVE_BOTTOM:
   469             case ABOVE_BOTTOM:
   583           case BOTTOM:
   470             case BOTTOM:
   584           case BELOW_BOTTOM:
   471             case BELOW_BOTTOM:
   585           case DEFAULT_POSITION:
   472             case DEFAULT_POSITION:
   586                 this.titlePosition = titlePosition;
   473                 this.titlePosition = titlePosition;
   587                 break;
   474                 break;
   588           default:
   475             default:
   589             throw new IllegalArgumentException(titlePosition +
   476                 throw new IllegalArgumentException(titlePosition +
   590                                         " is not a valid title position.");
   477                         " is not a valid title position.");
   591         }
   478         }
   592     }
   479     }
   593 
   480 
   594     /**
   481     /**
   595      * Sets the title-justification of the titled border.
   482      * Sets the title-justification of the titled border.
   622     /**
   509     /**
   623      * Sets the title-color of the titled border.
   510      * Sets the title-color of the titled border.
   624      * @param titleColor the color for the border title
   511      * @param titleColor the color for the border title
   625      */
   512      */
   626     public void setTitleColor(Color titleColor) {
   513     public void setTitleColor(Color titleColor) {
   627       this.titleColor = titleColor;
   514         this.titleColor = titleColor;
   628     }
   515     }
   629 
   516 
   630     /**
   517     /**
   631      * Returns the minimum dimensions this border requires
   518      * Returns the minimum dimensions this border requires
   632      * in order to fully display the border and title.
   519      * in order to fully display the border and title.
   634      */
   521      */
   635     public Dimension getMinimumSize(Component c) {
   522     public Dimension getMinimumSize(Component c) {
   636         Insets insets = getBorderInsets(c);
   523         Insets insets = getBorderInsets(c);
   637         Dimension minSize = new Dimension(insets.right+insets.left,
   524         Dimension minSize = new Dimension(insets.right+insets.left,
   638                                           insets.top+insets.bottom);
   525                                           insets.top+insets.bottom);
   639         Font font = getFont(c);
   526         String title = getTitle();
   640         FontMetrics fm = c.getFontMetrics(font);
   527         if ((title != null) && !title.isEmpty()) {
   641         JComponent jc = (c instanceof JComponent) ? (JComponent)c : null;
   528             JLabel label = getLabel(c);
   642         switch (getTitlePosition()) {
   529             Dimension size = label.getPreferredSize();
   643           case ABOVE_TOP:
   530 
   644           case BELOW_BOTTOM:
   531             int position = getPosition();
   645               minSize.width = Math.max(SwingUtilities2.stringWidth(jc, fm,
   532             if ((position != ABOVE_TOP) && (position != BELOW_BOTTOM)) {
   646                                        getTitle()), minSize.width);
   533                 minSize.width += size.width;
   647               break;
   534             }
   648           case BELOW_TOP:
   535             else if (minSize.width < size.width) {
   649           case ABOVE_BOTTOM:
   536                 minSize.width += size.width;
   650           case TOP:
   537             }
   651           case BOTTOM:
       
   652           case DEFAULT_POSITION:
       
   653           default:
       
   654               minSize.width += SwingUtilities2.stringWidth(jc, fm, getTitle());
       
   655         }
   538         }
   656         return minSize;
   539         return minSize;
   657     }
   540     }
   658 
   541 
   659     /**
   542     /**
   672             throw new IllegalArgumentException("Width must be >= 0");
   555             throw new IllegalArgumentException("Width must be >= 0");
   673         }
   556         }
   674         if (height < 0) {
   557         if (height < 0) {
   675             throw new IllegalArgumentException("Height must be >= 0");
   558             throw new IllegalArgumentException("Height must be >= 0");
   676         }
   559         }
       
   560         Border border = getBorderUI();
   677         String title = getTitle();
   561         String title = getTitle();
   678         if (title != null && !"".equals(title)) {
   562         if ((title != null) && !title.isEmpty()) {
   679             Font font = getFont(c);
   563             int edge = (border instanceof TitledBorder) ? 0 : EDGE_SPACING;
   680             Border border2 = getBorder();
   564             JLabel label = getLabel(c);
   681             Insets borderInsets;
   565             Dimension size = label.getPreferredSize();
   682             if (border2 != null) {
   566             Insets insets = (border != null)
   683                 borderInsets = border2.getBorderInsets(c);
   567                     ? border.getBorderInsets(c)
   684             }
   568                     : new Insets(0, 0, 0, 0);
   685             else {
   569 
   686                 borderInsets = new Insets(0, 0, 0, 0);
   570             int baseline = label.getBaseline(size.width, size.height);
   687             }
   571             switch (getPosition()) {
   688             FontMetrics fm = c.getFontMetrics(font);
   572                 case ABOVE_TOP:
   689             int fontHeight = fm.getHeight();
   573                     return baseline;
   690             int descent = fm.getDescent();
   574                 case TOP:
   691             int ascent = fm.getAscent();
   575                     insets.top = edge + (insets.top - size.height) / 2;
   692             int y = EDGE_SPACING;
   576                     return (insets.top < edge)
   693             int h = height - EDGE_SPACING * 2;
   577                             ? baseline
   694             int diff;
   578                             : baseline + insets.top;
   695             switch (getTitlePosition()) {
   579                 case BELOW_TOP:
   696             case ABOVE_TOP:
   580                     return baseline + insets.top + edge;
   697                 diff = ascent + descent + (Math.max(EDGE_SPACING,
   581                 case ABOVE_BOTTOM:
   698                                                     TEXT_SPACING * 2) -
   582                     return baseline + height - size.height - insets.bottom - edge;
   699                                            EDGE_SPACING);
   583                 case BOTTOM:
   700                 return y + diff - (descent + TEXT_SPACING);
   584                     insets.bottom = edge + (insets.bottom - size.height) / 2;
   701             case TOP:
   585                     return (insets.bottom < edge)
   702             case DEFAULT_POSITION:
   586                             ? baseline + height - size.height
   703                 diff = Math.max(0, ((ascent/2) + TEXT_SPACING) -
   587                             : baseline + height - size.height + insets.bottom;
   704                                 EDGE_SPACING);
   588                 case BELOW_BOTTOM:
   705                 return (y + diff - descent) +
   589                     return baseline + height - size.height;
   706                     (borderInsets.top + ascent + descent)/2;
       
   707             case BELOW_TOP:
       
   708                 return y + borderInsets.top + ascent + TEXT_SPACING;
       
   709             case ABOVE_BOTTOM:
       
   710                 return (y + h) - (borderInsets.bottom + descent +
       
   711                                   TEXT_SPACING);
       
   712             case BOTTOM:
       
   713                 h -= fontHeight / 2;
       
   714                 return ((y + h) - descent) +
       
   715                         ((ascent + descent) - borderInsets.bottom)/2;
       
   716             case BELOW_BOTTOM:
       
   717                 h -= fontHeight;
       
   718                 return y + h + ascent + TEXT_SPACING;
       
   719             }
   590             }
   720         }
   591         }
   721         return -1;
   592         return -1;
   722     }
   593     }
   723 
   594 
   730      * @since 1.6
   601      * @since 1.6
   731      */
   602      */
   732     public Component.BaselineResizeBehavior getBaselineResizeBehavior(
   603     public Component.BaselineResizeBehavior getBaselineResizeBehavior(
   733             Component c) {
   604             Component c) {
   734         super.getBaselineResizeBehavior(c);
   605         super.getBaselineResizeBehavior(c);
   735         switch(getTitlePosition()) {
   606         switch (getPosition()) {
   736         case TitledBorder.ABOVE_TOP:
   607             case TitledBorder.ABOVE_TOP:
   737         case TitledBorder.TOP:
   608             case TitledBorder.TOP:
   738         case TitledBorder.DEFAULT_POSITION:
   609             case TitledBorder.BELOW_TOP:
   739         case TitledBorder.BELOW_TOP:
   610                 return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
   740             return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
   611             case TitledBorder.ABOVE_BOTTOM:
   741         case TitledBorder.ABOVE_BOTTOM:
   612             case TitledBorder.BOTTOM:
   742         case TitledBorder.BOTTOM:
   613             case TitledBorder.BELOW_BOTTOM:
   743         case TitledBorder.BELOW_BOTTOM:
   614                 return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT;
   744             return JComponent.BaselineResizeBehavior.CONSTANT_DESCENT;
       
   745         }
   615         }
   746         return Component.BaselineResizeBehavior.OTHER;
   616         return Component.BaselineResizeBehavior.OTHER;
   747     }
   617     }
   748 
   618 
       
   619     private Border getBorderUI() {
       
   620         Border border = getBorder();
       
   621         return border != null
       
   622                 ? border
       
   623                 : UIManager.getBorder("TitledBorder.border");
       
   624     }
       
   625 
       
   626     private int getPosition() {
       
   627         int position = getTitlePosition();
       
   628         if (position != DEFAULT_POSITION) {
       
   629             return position;
       
   630         }
       
   631         Object value = UIManager.get("TitledBorder.position");
       
   632         if (value instanceof Integer) {
       
   633             int i = (Integer) value;
       
   634             if ((0 < i) && (i <= 6)) {
       
   635                 return i;
       
   636             }
       
   637         }
       
   638         else if (value instanceof String) {
       
   639             String s = (String) value;
       
   640             if (s.equalsIgnoreCase("ABOVE_TOP")) {
       
   641                 return ABOVE_TOP;
       
   642             }
       
   643             if (s.equalsIgnoreCase("TOP")) {
       
   644                 return TOP;
       
   645             }
       
   646             if (s.equalsIgnoreCase("BELOW_TOP")) {
       
   647                 return BELOW_TOP;
       
   648             }
       
   649             if (s.equalsIgnoreCase("ABOVE_BOTTOM")) {
       
   650                 return ABOVE_BOTTOM;
       
   651             }
       
   652             if (s.equalsIgnoreCase("BOTTOM")) {
       
   653                 return BOTTOM;
       
   654             }
       
   655             if (s.equalsIgnoreCase("BELOW_BOTTOM")) {
       
   656                 return BELOW_BOTTOM;
       
   657             }
       
   658         }
       
   659         return TOP;
       
   660     }
       
   661 
       
   662     private int getJustification(Component c) {
       
   663         int justification = getTitleJustification();
       
   664         if ((justification == LEADING) || (justification == DEFAULT_JUSTIFICATION)) {
       
   665             return c.getComponentOrientation().isLeftToRight() ? LEFT : RIGHT;
       
   666         }
       
   667         if (justification == TRAILING) {
       
   668             return c.getComponentOrientation().isLeftToRight() ? RIGHT : LEFT;
       
   669         }
       
   670         return justification;
       
   671     }
       
   672 
   749     protected Font getFont(Component c) {
   673     protected Font getFont(Component c) {
   750         Font font;
   674         Font font = getTitleFont();
   751         if ((font = getTitleFont()) != null) {
   675         if (font != null) {
   752             return font;
   676             return font;
   753         } else if (c != null && (font = c.getFont()) != null) {
   677         }
       
   678         font = UIManager.getFont("TitledBorder.font");
       
   679         if (font != null) {
   754             return font;
   680             return font;
   755         }
   681         }
       
   682         if (c != null) {
       
   683             font = c.getFont();
       
   684             if (font != null) {
       
   685                 return font;
       
   686             }
       
   687         }
   756         return new Font(Font.DIALOG, Font.PLAIN, 12);
   688         return new Font(Font.DIALOG, Font.PLAIN, 12);
   757     }
   689     }
   758 
   690 
   759     private static boolean computeIntersection(Rectangle dest,
   691     private Color getColor(Component c) {
   760                                                int rx, int ry, int rw, int rh) {
   692         Color color = getTitleColor();
   761         int x1 = Math.max(rx, dest.x);
   693         if (color != null) {
   762         int x2 = Math.min(rx + rw, dest.x + dest.width);
   694             return color;
   763         int y1 = Math.max(ry, dest.y);
   695         }
   764         int y2 = Math.min(ry + rh, dest.y + dest.height);
   696         color = UIManager.getColor("TitledBorder.titleColor");
   765         dest.x = x1;
   697         if (color != null) {
   766         dest.y = y1;
   698             return color;
   767         dest.width = x2 - x1;
   699         }
   768         dest.height = y2 - y1;
   700         return (c != null)
   769 
   701                 ? c.getForeground()
   770         if (dest.width <= 0 || dest.height <= 0) {
   702                 : null;
   771             return false;
   703     }
   772         }
   704 
   773         return true;
   705     private JLabel getLabel(Component c) {
       
   706         this.label.setText(getTitle());
       
   707         this.label.setFont(getFont(c));
       
   708         this.label.setForeground(getColor(c));
       
   709         this.label.setComponentOrientation(c.getComponentOrientation());
       
   710         this.label.setEnabled(c.isEnabled());
       
   711         return this.label;
   774     }
   712     }
   775 }
   713 }