jdk/src/share/classes/sun/tools/jconsole/BorderedComponent.java
changeset 2 90ce3da70b43
child 5506 202f599c92aa
equal deleted inserted replaced
0:fd16c54261b3 2:90ce3da70b43
       
     1 /*
       
     2  * Copyright 2004-2006 Sun Microsystems, Inc.  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.  Sun designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
       
    22  * CA 95054 USA or visit www.sun.com if you need additional information or
       
    23  * have any questions.
       
    24  */
       
    25 
       
    26 package sun.tools.jconsole;
       
    27 
       
    28 import java.awt.*;
       
    29 import java.awt.event.*;
       
    30 
       
    31 import javax.swing.*;
       
    32 import javax.swing.border.*;
       
    33 import javax.swing.plaf.*;
       
    34 import javax.swing.plaf.basic.BasicGraphicsUtils;
       
    35 
       
    36 import static javax.swing.SwingConstants.*;
       
    37 
       
    38 import static sun.tools.jconsole.JConsole.*;
       
    39 import static sun.tools.jconsole.Resources.*;
       
    40 import static sun.tools.jconsole.Utilities.*;
       
    41 
       
    42 @SuppressWarnings("serial")
       
    43 public class BorderedComponent extends JPanel implements ActionListener {
       
    44     JButton moreOrLessButton;
       
    45     String valueLabelStr;
       
    46     JLabel label;
       
    47     JComponent comp;
       
    48     boolean collapsed = false;
       
    49 
       
    50     private JPopupMenu popupMenu;
       
    51 
       
    52     private Icon collapseIcon;
       
    53     private Icon expandIcon;
       
    54 
       
    55     private static Image getImage(String name) {
       
    56         Toolkit tk = Toolkit.getDefaultToolkit();
       
    57         name = "resources/" + name + ".png";
       
    58         return tk.getImage(BorderedComponent.class.getResource(name));
       
    59     }
       
    60 
       
    61     public BorderedComponent(String text) {
       
    62         this(text, null, false);
       
    63     }
       
    64 
       
    65     public BorderedComponent(String text, JComponent comp) {
       
    66         this(text, comp, false);
       
    67     }
       
    68 
       
    69     public BorderedComponent(String text, JComponent comp, boolean collapsible) {
       
    70         super(null);
       
    71 
       
    72         this.comp = comp;
       
    73 
       
    74         // Only add border if text is not null
       
    75         if (text != null) {
       
    76             TitledBorder border;
       
    77             if (collapsible) {
       
    78                 final JLabel textLabel = new JLabel(text);
       
    79                 JPanel borderLabel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0)) {
       
    80                     public int getBaseline(int w, int h) {
       
    81                         Dimension dim = textLabel.getPreferredSize();
       
    82                         return textLabel.getBaseline(dim.width, dim.height) + textLabel.getY();
       
    83                     }
       
    84                 };
       
    85                 borderLabel.add(textLabel);
       
    86                 border = new LabeledBorder(borderLabel);
       
    87                 textLabel.setForeground(border.getTitleColor());
       
    88 
       
    89                 if (IS_WIN) {
       
    90                     collapseIcon = new ImageIcon(getImage("collapse-winlf"));
       
    91                     expandIcon = new ImageIcon(getImage("expand-winlf"));
       
    92                 } else {
       
    93                     collapseIcon = new ArrowIcon(SOUTH, textLabel);
       
    94                     expandIcon = new ArrowIcon(EAST, textLabel);
       
    95                 }
       
    96 
       
    97                 moreOrLessButton = new JButton(collapseIcon);
       
    98                 moreOrLessButton.setContentAreaFilled(false);
       
    99                 moreOrLessButton.setBorderPainted(false);
       
   100                 moreOrLessButton.setMargin(new Insets(0, 0, 0, 0));
       
   101                 moreOrLessButton.addActionListener(this);
       
   102                 String toolTip =
       
   103                     getText("BorderedComponent.moreOrLessButton.toolTip");
       
   104                 moreOrLessButton.setToolTipText(toolTip);
       
   105                 borderLabel.add(moreOrLessButton);
       
   106                 borderLabel.setSize(borderLabel.getPreferredSize());
       
   107                 add(borderLabel);
       
   108             } else {
       
   109                 border = new TitledBorder(text);
       
   110             }
       
   111             setBorder(new CompoundBorder(new FocusBorder(this), border));
       
   112         } else {
       
   113             setBorder(new FocusBorder(this));
       
   114         }
       
   115         if (comp != null) {
       
   116             add(comp);
       
   117         }
       
   118     }
       
   119 
       
   120     public void setComponent(JComponent comp) {
       
   121         if (this.comp != null) {
       
   122             remove(this.comp);
       
   123         }
       
   124         this.comp = comp;
       
   125         if (!collapsed) {
       
   126             LayoutManager lm = getLayout();
       
   127             if (lm instanceof BorderLayout) {
       
   128                 add(comp, BorderLayout.CENTER);
       
   129             } else {
       
   130                 add(comp);
       
   131             }
       
   132         }
       
   133         revalidate();
       
   134     }
       
   135 
       
   136     public void setValueLabel(String str) {
       
   137         this.valueLabelStr = str;
       
   138         if (label != null) {
       
   139             label.setText(Resources.getText("Current value",valueLabelStr));
       
   140         }
       
   141     }
       
   142 
       
   143     public void actionPerformed(ActionEvent ev) {
       
   144         if (collapsed) {
       
   145             if (label != null) {
       
   146                 remove(label);
       
   147             }
       
   148             add(comp);
       
   149             moreOrLessButton.setIcon(collapseIcon);
       
   150         } else {
       
   151             remove(comp);
       
   152             if (valueLabelStr != null) {
       
   153                 if (label == null) {
       
   154                     label = new JLabel(Resources.getText("Current value",
       
   155                                                          valueLabelStr));
       
   156                 }
       
   157                 add(label);
       
   158             }
       
   159             moreOrLessButton.setIcon(expandIcon);
       
   160         }
       
   161         collapsed = !collapsed;
       
   162 
       
   163         JComponent container = (JComponent)getParent();
       
   164         if (container != null &&
       
   165             container.getLayout() instanceof VariableGridLayout) {
       
   166 
       
   167             ((VariableGridLayout)container.getLayout()).setFillRow(this, !collapsed);
       
   168             container.revalidate();
       
   169         }
       
   170     }
       
   171 
       
   172     public Dimension getMinimumSize() {
       
   173         if (getLayout() != null) {
       
   174             // A layout manager has been set, so delegate to it
       
   175             return super.getMinimumSize();
       
   176         }
       
   177 
       
   178         if (moreOrLessButton != null) {
       
   179             Dimension d = moreOrLessButton.getMinimumSize();
       
   180             Insets i = getInsets();
       
   181             d.width  += i.left + i.right;
       
   182             d.height += i.top + i.bottom;
       
   183             return d;
       
   184         } else {
       
   185             return super.getMinimumSize();
       
   186         }
       
   187     }
       
   188 
       
   189     public void doLayout() {
       
   190         if (getLayout() != null) {
       
   191             // A layout manager has been set, so delegate to it
       
   192             super.doLayout();
       
   193             return;
       
   194         }
       
   195 
       
   196         Dimension d = getSize();
       
   197         Insets i = getInsets();
       
   198 
       
   199         if (collapsed) {
       
   200             if (label != null) {
       
   201                 Dimension p = label.getPreferredSize();
       
   202                 label.setBounds(i.left,
       
   203                                 i.top + (d.height - i.top - i.bottom - p.height) / 2,
       
   204                                 p.width,
       
   205                                 p.height);
       
   206             }
       
   207         } else {
       
   208             if (comp != null) {
       
   209                 comp.setBounds(i.left,
       
   210                                i.top,
       
   211                                d.width - i.left - i.right,
       
   212                                d.height - i.top - i.bottom);
       
   213             }
       
   214         }
       
   215     }
       
   216 
       
   217     private static class ArrowIcon implements Icon {
       
   218         private int direction;
       
   219         private JLabel textLabel;
       
   220 
       
   221         public ArrowIcon(int direction, JLabel textLabel) {
       
   222             this.direction = direction;
       
   223             this.textLabel = textLabel;
       
   224         }
       
   225 
       
   226         public void paintIcon(Component c, Graphics g, int x, int y) {
       
   227             int w = getIconWidth();
       
   228             int h = w;
       
   229             Polygon p = new Polygon();
       
   230             switch (direction) {
       
   231               case EAST:
       
   232                 p.addPoint(x + 2,     y);
       
   233                 p.addPoint(x + w - 2, y + h / 2);
       
   234                 p.addPoint(x + 2,     y + h - 1);
       
   235                 break;
       
   236 
       
   237               case SOUTH:
       
   238                 p.addPoint(x,         y + 2);
       
   239                 p.addPoint(x + w / 2, y + h - 2);
       
   240                 p.addPoint(x + w - 1, y + 2);
       
   241                 break;
       
   242             }
       
   243             g.fillPolygon(p);
       
   244         }
       
   245 
       
   246         public int getIconWidth() {
       
   247             return getIconHeight();
       
   248         }
       
   249 
       
   250         public int getIconHeight() {
       
   251             Graphics g = textLabel.getGraphics();
       
   252             if (g != null) {
       
   253                 int h = g.getFontMetrics(textLabel.getFont()).getAscent() * 6/10;
       
   254                 if (h % 2 == 0) {
       
   255                     h += 1;     // Make it odd
       
   256                 }
       
   257                 return h;
       
   258             } else {
       
   259                 return 7;
       
   260             }
       
   261         }
       
   262     }
       
   263 
       
   264 
       
   265     /**
       
   266      * A subclass of <code>TitledBorder</code> which implements an arbitrary border
       
   267      * with the addition of a JComponent (JLabel, JPanel, etc) in the
       
   268      * default position.
       
   269      * <p>
       
   270      * If the border property value is not
       
   271      * specified in the constuctor or by invoking the appropriate
       
   272      * set method, the property value will be defined by the current
       
   273      * look and feel, using the following property name in the
       
   274      * Defaults Table:
       
   275      * <ul>
       
   276      * <li>&quot;TitledBorder.border&quot;
       
   277      * </ul>
       
   278      */
       
   279     protected static class LabeledBorder extends TitledBorder {
       
   280         protected JComponent label;
       
   281 
       
   282         private Point compLoc = new Point();
       
   283 
       
   284         /**
       
   285          * Creates a LabeledBorder instance.
       
   286          *
       
   287          * @param label  the label the border should display
       
   288          */
       
   289         public LabeledBorder(JComponent label)     {
       
   290             this(null, label);
       
   291         }
       
   292 
       
   293         /**
       
   294          * Creates a LabeledBorder instance with the specified border
       
   295          * and an empty label.
       
   296          *
       
   297          * @param border  the border
       
   298          */
       
   299         public LabeledBorder(Border border)       {
       
   300             this(border, null);
       
   301         }
       
   302 
       
   303         /**
       
   304          * Creates a LabeledBorder instance with the specified border and
       
   305          * label.
       
   306          *
       
   307          * @param border  the border
       
   308          * @param label  the label the border should display
       
   309          */
       
   310         public LabeledBorder(Border border, JComponent label) {
       
   311             super(border);
       
   312 
       
   313             this.label = label;
       
   314 
       
   315             if (label instanceof JLabel &&
       
   316                 label.getForeground() instanceof ColorUIResource) {
       
   317 
       
   318                 label.setForeground(getTitleColor());
       
   319             }
       
   320 
       
   321         }
       
   322 
       
   323         /**
       
   324          * Paints the border for the specified component with the
       
   325          * specified position and size.
       
   326          * @param c the component for which this border is being painted
       
   327          * @param g the paint graphics
       
   328          * @param x the x position of the painted border
       
   329          * @param y the y position of the painted border
       
   330          * @param width the width of the painted border
       
   331          * @param height the height of the painted border
       
   332          */
       
   333         public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
       
   334 
       
   335             Border border = getBorder();
       
   336 
       
   337             if (label == null) {
       
   338                 if (border != null) {
       
   339                     border.paintBorder(c, g, x, y, width, height);
       
   340                 }
       
   341                 return;
       
   342             }
       
   343 
       
   344             Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING,
       
   345                                                  width - (EDGE_SPACING * 2),
       
   346                                                  height - (EDGE_SPACING * 2));
       
   347 
       
   348             Dimension   labelDim = label.getPreferredSize();
       
   349             int baseline = label.getBaseline(labelDim.width, labelDim.height);
       
   350             int         ascent = Math.max(0, baseline);
       
   351             int         descent = labelDim.height - ascent;
       
   352             int         diff;
       
   353             Insets      insets;
       
   354 
       
   355             if (border != null) {
       
   356                 insets = border.getBorderInsets(c);
       
   357             } else {
       
   358                 insets = new Insets(0, 0, 0, 0);
       
   359             }
       
   360 
       
   361             diff = Math.max(0, ascent/2 + TEXT_SPACING - EDGE_SPACING);
       
   362             grooveRect.y += diff;
       
   363             grooveRect.height -= diff;
       
   364             compLoc.y = grooveRect.y + insets.top/2 - (ascent + descent) / 2 - 1;
       
   365 
       
   366             int justification;
       
   367             if (c.getComponentOrientation().isLeftToRight()) {
       
   368                 justification = LEFT;
       
   369             } else {
       
   370                 justification = RIGHT;
       
   371             }
       
   372 
       
   373             switch (justification) {
       
   374                 case LEFT:
       
   375                     compLoc.x = grooveRect.x + TEXT_INSET_H + insets.left;
       
   376                     break;
       
   377                 case RIGHT:
       
   378                     compLoc.x = (grooveRect.x + grooveRect.width
       
   379                                  - (labelDim.width + TEXT_INSET_H + insets.right));
       
   380                     break;
       
   381             }
       
   382 
       
   383             // If title is positioned in middle of border AND its fontsize
       
   384             // is greater than the border's thickness, we'll need to paint
       
   385             // the border in sections to leave space for the component's background
       
   386             // to show through the title.
       
   387             //
       
   388             if (border != null) {
       
   389                 if (grooveRect.y > compLoc.y - ascent) {
       
   390                     Rectangle clipRect = new Rectangle();
       
   391 
       
   392                     // save original clip
       
   393                     Rectangle saveClip = g.getClipBounds();
       
   394 
       
   395                     // paint strip left of text
       
   396                     clipRect.setBounds(saveClip);
       
   397                     if (computeIntersection(clipRect, x, y, compLoc.x-1-x, height)) {
       
   398                         g.setClip(clipRect);
       
   399                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   400                                       grooveRect.width, grooveRect.height);
       
   401                     }
       
   402 
       
   403                     // paint strip right of text
       
   404                     clipRect.setBounds(saveClip);
       
   405                     if (computeIntersection(clipRect, compLoc.x+ labelDim.width +1, y,
       
   406                                    x+width-(compLoc.x+ labelDim.width +1), height)) {
       
   407                         g.setClip(clipRect);
       
   408                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   409                                       grooveRect.width, grooveRect.height);
       
   410                     }
       
   411 
       
   412                     // paint strip below text
       
   413                     clipRect.setBounds(saveClip);
       
   414                     if (computeIntersection(clipRect,
       
   415                                             compLoc.x - 1, compLoc.y + ascent + descent,
       
   416                                             labelDim.width + 2,
       
   417                                             y + height - compLoc.y - ascent - descent)) {
       
   418                         g.setClip(clipRect);
       
   419                         border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   420                                   grooveRect.width, grooveRect.height);
       
   421                     }
       
   422 
       
   423                     // restore clip
       
   424                     g.setClip(saveClip);
       
   425 
       
   426                 } else {
       
   427                     border.paintBorder(c, g, grooveRect.x, grooveRect.y,
       
   428                                       grooveRect.width, grooveRect.height);
       
   429                 }
       
   430 
       
   431                 label.setLocation(compLoc);
       
   432                 label.setSize(labelDim);
       
   433             }
       
   434         }
       
   435 
       
   436         /**
       
   437          * Reinitialize the insets parameter with this Border's current Insets.
       
   438          * @param c the component for which this border insets value applies
       
   439          * @param insets the object to be reinitialized
       
   440          */
       
   441         public Insets getBorderInsets(Component c, Insets insets) {
       
   442             int height = 16;
       
   443 
       
   444             Border border = getBorder();
       
   445             if (border != null) {
       
   446                 if (border instanceof AbstractBorder) {
       
   447                     ((AbstractBorder)border).getBorderInsets(c, insets);
       
   448                 } else {
       
   449                     // Can't reuse border insets because the Border interface
       
   450                     // can't be enhanced.
       
   451                     Insets i = border.getBorderInsets(c);
       
   452                     insets.top = i.top;
       
   453                     insets.right = i.right;
       
   454                     insets.bottom = i.bottom;
       
   455                     insets.left = i.left;
       
   456                 }
       
   457             } else {
       
   458                 insets.left = insets.top = insets.right = insets.bottom = 0;
       
   459             }
       
   460 
       
   461             insets.left += EDGE_SPACING + TEXT_SPACING;
       
   462             insets.right += EDGE_SPACING + TEXT_SPACING;
       
   463             insets.top += EDGE_SPACING + TEXT_SPACING;
       
   464             insets.bottom += EDGE_SPACING + TEXT_SPACING;
       
   465 
       
   466             if (c == null || label == null) {
       
   467                 return insets;
       
   468             }
       
   469 
       
   470             insets.top += label.getHeight();
       
   471 
       
   472             return insets;
       
   473         }
       
   474 
       
   475         /**
       
   476          * Returns the label of the labeled border.
       
   477          */
       
   478         public JComponent getLabel() {
       
   479             return label;
       
   480         }
       
   481 
       
   482 
       
   483         /**
       
   484          * Sets the title of the titled border.
       
   485          * param title the title for the border
       
   486          */
       
   487         public void setLabel(JComponent label) {
       
   488             this.label = label;
       
   489         }
       
   490 
       
   491 
       
   492 
       
   493         /**
       
   494          * Returns the minimum dimensions this border requires
       
   495          * in order to fully display the border and title.
       
   496          * @param c the component where this border will be drawn
       
   497          */
       
   498         public Dimension getMinimumSize(Component c) {
       
   499             Insets insets = getBorderInsets(c);
       
   500             Dimension minSize = new Dimension(insets.right + insets.left,
       
   501                                               insets.top + insets.bottom);
       
   502             minSize.width += label.getWidth();
       
   503 
       
   504             return minSize;
       
   505         }
       
   506 
       
   507 
       
   508         private static boolean computeIntersection(Rectangle dest,
       
   509                                                    int rx, int ry, int rw, int rh) {
       
   510             int x1 = Math.max(rx, dest.x);
       
   511             int x2 = Math.min(rx + rw, dest.x + dest.width);
       
   512             int y1 = Math.max(ry, dest.y);
       
   513             int y2 = Math.min(ry + rh, dest.y + dest.height);
       
   514             dest.x = x1;
       
   515             dest.y = y1;
       
   516             dest.width = x2 - x1;
       
   517             dest.height = y2 - y1;
       
   518 
       
   519             if (dest.width <= 0 || dest.height <= 0) {
       
   520                 return false;
       
   521             }
       
   522             return true;
       
   523         }
       
   524     }
       
   525 
       
   526 
       
   527     protected static class FocusBorder extends AbstractBorder implements FocusListener {
       
   528         private Component comp;
       
   529         private Color focusColor;
       
   530         private boolean focusLostTemporarily = false;
       
   531 
       
   532         public FocusBorder(Component comp) {
       
   533             this.comp = comp;
       
   534 
       
   535             comp.addFocusListener(this);
       
   536 
       
   537             // This is the best guess for a L&F specific color
       
   538             focusColor = UIManager.getColor("TabbedPane.focus");
       
   539         }
       
   540 
       
   541         public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
       
   542             if (comp.hasFocus() || focusLostTemporarily) {
       
   543                 Color color = g.getColor();
       
   544                 g.setColor(focusColor);
       
   545                 BasicGraphicsUtils.drawDashedRect(g, x, y, width, height);
       
   546                 g.setColor(color);
       
   547             }
       
   548         }
       
   549 
       
   550         public Insets getBorderInsets(Component c, Insets insets) {
       
   551             insets.set(2, 2, 2, 2);
       
   552             return insets;
       
   553         }
       
   554 
       
   555 
       
   556         public void focusGained(FocusEvent e) {
       
   557             comp.repaint();
       
   558         }
       
   559 
       
   560         public void focusLost(FocusEvent e) {
       
   561             // We will still paint focus even if lost temporarily
       
   562             focusLostTemporarily = e.isTemporary();
       
   563             if (!focusLostTemporarily) {
       
   564                 comp.repaint();
       
   565             }
       
   566         }
       
   567     }
       
   568 }