0N/A/*
2362N/A * Copyright (c) 2004, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage sun.tools.jconsole;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.*;
0N/A
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.border.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.plaf.basic.BasicGraphicsUtils;
0N/A
5335N/A
0N/Aimport static javax.swing.SwingConstants.*;
0N/A
0N/Aimport static sun.tools.jconsole.JConsole.*;
0N/A
0N/A@SuppressWarnings("serial")
0N/Apublic class BorderedComponent extends JPanel implements ActionListener {
0N/A JButton moreOrLessButton;
0N/A String valueLabelStr;
0N/A JLabel label;
0N/A JComponent comp;
0N/A boolean collapsed = false;
0N/A
0N/A private Icon collapseIcon;
0N/A private Icon expandIcon;
0N/A
0N/A private static Image getImage(String name) {
0N/A Toolkit tk = Toolkit.getDefaultToolkit();
0N/A name = "resources/" + name + ".png";
0N/A return tk.getImage(BorderedComponent.class.getResource(name));
0N/A }
0N/A
0N/A public BorderedComponent(String text) {
0N/A this(text, null, false);
0N/A }
0N/A
0N/A public BorderedComponent(String text, JComponent comp) {
0N/A this(text, comp, false);
0N/A }
0N/A
0N/A public BorderedComponent(String text, JComponent comp, boolean collapsible) {
0N/A super(null);
0N/A
0N/A this.comp = comp;
0N/A
0N/A // Only add border if text is not null
0N/A if (text != null) {
0N/A TitledBorder border;
0N/A if (collapsible) {
0N/A final JLabel textLabel = new JLabel(text);
0N/A JPanel borderLabel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 0)) {
0N/A public int getBaseline(int w, int h) {
0N/A Dimension dim = textLabel.getPreferredSize();
0N/A return textLabel.getBaseline(dim.width, dim.height) + textLabel.getY();
0N/A }
0N/A };
0N/A borderLabel.add(textLabel);
0N/A border = new LabeledBorder(borderLabel);
0N/A textLabel.setForeground(border.getTitleColor());
0N/A
0N/A if (IS_WIN) {
0N/A collapseIcon = new ImageIcon(getImage("collapse-winlf"));
0N/A expandIcon = new ImageIcon(getImage("expand-winlf"));
0N/A } else {
0N/A collapseIcon = new ArrowIcon(SOUTH, textLabel);
0N/A expandIcon = new ArrowIcon(EAST, textLabel);
0N/A }
0N/A
0N/A moreOrLessButton = new JButton(collapseIcon);
0N/A moreOrLessButton.setContentAreaFilled(false);
0N/A moreOrLessButton.setBorderPainted(false);
0N/A moreOrLessButton.setMargin(new Insets(0, 0, 0, 0));
0N/A moreOrLessButton.addActionListener(this);
0N/A String toolTip =
5335N/A Messages.BORDERED_COMPONENT_MORE_OR_LESS_BUTTON_TOOLTIP;
0N/A moreOrLessButton.setToolTipText(toolTip);
0N/A borderLabel.add(moreOrLessButton);
0N/A borderLabel.setSize(borderLabel.getPreferredSize());
0N/A add(borderLabel);
0N/A } else {
0N/A border = new TitledBorder(text);
0N/A }
0N/A setBorder(new CompoundBorder(new FocusBorder(this), border));
0N/A } else {
0N/A setBorder(new FocusBorder(this));
0N/A }
0N/A if (comp != null) {
0N/A add(comp);
0N/A }
0N/A }
0N/A
0N/A public void setComponent(JComponent comp) {
0N/A if (this.comp != null) {
0N/A remove(this.comp);
0N/A }
0N/A this.comp = comp;
0N/A if (!collapsed) {
0N/A LayoutManager lm = getLayout();
0N/A if (lm instanceof BorderLayout) {
0N/A add(comp, BorderLayout.CENTER);
0N/A } else {
0N/A add(comp);
0N/A }
0N/A }
0N/A revalidate();
0N/A }
0N/A
0N/A public void setValueLabel(String str) {
0N/A this.valueLabelStr = str;
0N/A if (label != null) {
5335N/A label.setText(Resources.format(Messages.CURRENT_VALUE,
5335N/A valueLabelStr));
0N/A }
0N/A }
0N/A
0N/A public void actionPerformed(ActionEvent ev) {
0N/A if (collapsed) {
0N/A if (label != null) {
0N/A remove(label);
0N/A }
0N/A add(comp);
0N/A moreOrLessButton.setIcon(collapseIcon);
0N/A } else {
0N/A remove(comp);
0N/A if (valueLabelStr != null) {
0N/A if (label == null) {
5335N/A label = new JLabel(Resources.format(Messages.CURRENT_VALUE,
5335N/A valueLabelStr));
0N/A }
0N/A add(label);
0N/A }
0N/A moreOrLessButton.setIcon(expandIcon);
0N/A }
0N/A collapsed = !collapsed;
0N/A
0N/A JComponent container = (JComponent)getParent();
0N/A if (container != null &&
0N/A container.getLayout() instanceof VariableGridLayout) {
0N/A
0N/A ((VariableGridLayout)container.getLayout()).setFillRow(this, !collapsed);
0N/A container.revalidate();
0N/A }
0N/A }
0N/A
0N/A public Dimension getMinimumSize() {
0N/A if (getLayout() != null) {
0N/A // A layout manager has been set, so delegate to it
0N/A return super.getMinimumSize();
0N/A }
0N/A
0N/A if (moreOrLessButton != null) {
0N/A Dimension d = moreOrLessButton.getMinimumSize();
0N/A Insets i = getInsets();
0N/A d.width += i.left + i.right;
0N/A d.height += i.top + i.bottom;
0N/A return d;
0N/A } else {
0N/A return super.getMinimumSize();
0N/A }
0N/A }
0N/A
0N/A public void doLayout() {
0N/A if (getLayout() != null) {
0N/A // A layout manager has been set, so delegate to it
0N/A super.doLayout();
0N/A return;
0N/A }
0N/A
0N/A Dimension d = getSize();
0N/A Insets i = getInsets();
0N/A
0N/A if (collapsed) {
0N/A if (label != null) {
0N/A Dimension p = label.getPreferredSize();
0N/A label.setBounds(i.left,
0N/A i.top + (d.height - i.top - i.bottom - p.height) / 2,
0N/A p.width,
0N/A p.height);
0N/A }
0N/A } else {
0N/A if (comp != null) {
0N/A comp.setBounds(i.left,
0N/A i.top,
0N/A d.width - i.left - i.right,
0N/A d.height - i.top - i.bottom);
0N/A }
0N/A }
0N/A }
0N/A
0N/A private static class ArrowIcon implements Icon {
0N/A private int direction;
0N/A private JLabel textLabel;
0N/A
0N/A public ArrowIcon(int direction, JLabel textLabel) {
0N/A this.direction = direction;
0N/A this.textLabel = textLabel;
0N/A }
0N/A
0N/A public void paintIcon(Component c, Graphics g, int x, int y) {
0N/A int w = getIconWidth();
0N/A int h = w;
0N/A Polygon p = new Polygon();
0N/A switch (direction) {
0N/A case EAST:
0N/A p.addPoint(x + 2, y);
0N/A p.addPoint(x + w - 2, y + h / 2);
0N/A p.addPoint(x + 2, y + h - 1);
0N/A break;
0N/A
0N/A case SOUTH:
0N/A p.addPoint(x, y + 2);
0N/A p.addPoint(x + w / 2, y + h - 2);
0N/A p.addPoint(x + w - 1, y + 2);
0N/A break;
0N/A }
0N/A g.fillPolygon(p);
0N/A }
0N/A
0N/A public int getIconWidth() {
0N/A return getIconHeight();
0N/A }
0N/A
0N/A public int getIconHeight() {
0N/A Graphics g = textLabel.getGraphics();
0N/A if (g != null) {
0N/A int h = g.getFontMetrics(textLabel.getFont()).getAscent() * 6/10;
0N/A if (h % 2 == 0) {
0N/A h += 1; // Make it odd
0N/A }
0N/A return h;
0N/A } else {
0N/A return 7;
0N/A }
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * A subclass of <code>TitledBorder</code> which implements an arbitrary border
0N/A * with the addition of a JComponent (JLabel, JPanel, etc) in the
0N/A * default position.
0N/A * <p>
0N/A * If the border property value is not
0N/A * specified in the constuctor or by invoking the appropriate
0N/A * set method, the property value will be defined by the current
0N/A * look and feel, using the following property name in the
0N/A * Defaults Table:
0N/A * <ul>
0N/A * <li>&quot;TitledBorder.border&quot;
0N/A * </ul>
0N/A */
0N/A protected static class LabeledBorder extends TitledBorder {
0N/A protected JComponent label;
0N/A
0N/A private Point compLoc = new Point();
0N/A
0N/A /**
0N/A * Creates a LabeledBorder instance.
0N/A *
0N/A * @param label the label the border should display
0N/A */
0N/A public LabeledBorder(JComponent label) {
0N/A this(null, label);
0N/A }
0N/A
0N/A /**
0N/A * Creates a LabeledBorder instance with the specified border
0N/A * and an empty label.
0N/A *
0N/A * @param border the border
0N/A */
0N/A public LabeledBorder(Border border) {
0N/A this(border, null);
0N/A }
0N/A
0N/A /**
0N/A * Creates a LabeledBorder instance with the specified border and
0N/A * label.
0N/A *
0N/A * @param border the border
0N/A * @param label the label the border should display
0N/A */
0N/A public LabeledBorder(Border border, JComponent label) {
0N/A super(border);
0N/A
0N/A this.label = label;
0N/A
0N/A if (label instanceof JLabel &&
0N/A label.getForeground() instanceof ColorUIResource) {
0N/A
0N/A label.setForeground(getTitleColor());
0N/A }
0N/A
0N/A }
0N/A
0N/A /**
0N/A * Paints the border for the specified component with the
0N/A * specified position and size.
0N/A * @param c the component for which this border is being painted
0N/A * @param g the paint graphics
0N/A * @param x the x position of the painted border
0N/A * @param y the y position of the painted border
0N/A * @param width the width of the painted border
0N/A * @param height the height of the painted border
0N/A */
0N/A public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
0N/A
0N/A Border border = getBorder();
0N/A
0N/A if (label == null) {
0N/A if (border != null) {
0N/A border.paintBorder(c, g, x, y, width, height);
0N/A }
0N/A return;
0N/A }
0N/A
0N/A Rectangle grooveRect = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING,
0N/A width - (EDGE_SPACING * 2),
0N/A height - (EDGE_SPACING * 2));
0N/A
0N/A Dimension labelDim = label.getPreferredSize();
0N/A int baseline = label.getBaseline(labelDim.width, labelDim.height);
0N/A int ascent = Math.max(0, baseline);
0N/A int descent = labelDim.height - ascent;
0N/A int diff;
0N/A Insets insets;
0N/A
0N/A if (border != null) {
0N/A insets = border.getBorderInsets(c);
0N/A } else {
0N/A insets = new Insets(0, 0, 0, 0);
0N/A }
0N/A
0N/A diff = Math.max(0, ascent/2 + TEXT_SPACING - EDGE_SPACING);
0N/A grooveRect.y += diff;
0N/A grooveRect.height -= diff;
0N/A compLoc.y = grooveRect.y + insets.top/2 - (ascent + descent) / 2 - 1;
0N/A
0N/A int justification;
0N/A if (c.getComponentOrientation().isLeftToRight()) {
0N/A justification = LEFT;
0N/A } else {
0N/A justification = RIGHT;
0N/A }
0N/A
0N/A switch (justification) {
0N/A case LEFT:
0N/A compLoc.x = grooveRect.x + TEXT_INSET_H + insets.left;
0N/A break;
0N/A case RIGHT:
0N/A compLoc.x = (grooveRect.x + grooveRect.width
0N/A - (labelDim.width + TEXT_INSET_H + insets.right));
0N/A break;
0N/A }
0N/A
0N/A // If title is positioned in middle of border AND its fontsize
0N/A // is greater than the border's thickness, we'll need to paint
0N/A // the border in sections to leave space for the component's background
0N/A // to show through the title.
0N/A //
0N/A if (border != null) {
0N/A if (grooveRect.y > compLoc.y - ascent) {
0N/A Rectangle clipRect = new Rectangle();
0N/A
0N/A // save original clip
0N/A Rectangle saveClip = g.getClipBounds();
0N/A
0N/A // paint strip left of text
0N/A clipRect.setBounds(saveClip);
0N/A if (computeIntersection(clipRect, x, y, compLoc.x-1-x, height)) {
0N/A g.setClip(clipRect);
0N/A border.paintBorder(c, g, grooveRect.x, grooveRect.y,
0N/A grooveRect.width, grooveRect.height);
0N/A }
0N/A
0N/A // paint strip right of text
0N/A clipRect.setBounds(saveClip);
0N/A if (computeIntersection(clipRect, compLoc.x+ labelDim.width +1, y,
0N/A x+width-(compLoc.x+ labelDim.width +1), height)) {
0N/A g.setClip(clipRect);
0N/A border.paintBorder(c, g, grooveRect.x, grooveRect.y,
0N/A grooveRect.width, grooveRect.height);
0N/A }
0N/A
0N/A // paint strip below text
0N/A clipRect.setBounds(saveClip);
0N/A if (computeIntersection(clipRect,
0N/A compLoc.x - 1, compLoc.y + ascent + descent,
0N/A labelDim.width + 2,
0N/A y + height - compLoc.y - ascent - descent)) {
0N/A g.setClip(clipRect);
0N/A border.paintBorder(c, g, grooveRect.x, grooveRect.y,
0N/A grooveRect.width, grooveRect.height);
0N/A }
0N/A
0N/A // restore clip
0N/A g.setClip(saveClip);
0N/A
0N/A } else {
0N/A border.paintBorder(c, g, grooveRect.x, grooveRect.y,
0N/A grooveRect.width, grooveRect.height);
0N/A }
0N/A
0N/A label.setLocation(compLoc);
0N/A label.setSize(labelDim);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Reinitialize the insets parameter with this Border's current Insets.
0N/A * @param c the component for which this border insets value applies
0N/A * @param insets the object to be reinitialized
0N/A */
0N/A public Insets getBorderInsets(Component c, Insets insets) {
0N/A Border border = getBorder();
0N/A if (border != null) {
0N/A if (border instanceof AbstractBorder) {
0N/A ((AbstractBorder)border).getBorderInsets(c, insets);
0N/A } else {
0N/A // Can't reuse border insets because the Border interface
0N/A // can't be enhanced.
0N/A Insets i = border.getBorderInsets(c);
0N/A insets.top = i.top;
0N/A insets.right = i.right;
0N/A insets.bottom = i.bottom;
0N/A insets.left = i.left;
0N/A }
0N/A } else {
0N/A insets.left = insets.top = insets.right = insets.bottom = 0;
0N/A }
0N/A
0N/A insets.left += EDGE_SPACING + TEXT_SPACING;
0N/A insets.right += EDGE_SPACING + TEXT_SPACING;
0N/A insets.top += EDGE_SPACING + TEXT_SPACING;
0N/A insets.bottom += EDGE_SPACING + TEXT_SPACING;
0N/A
0N/A if (c == null || label == null) {
0N/A return insets;
0N/A }
0N/A
0N/A insets.top += label.getHeight();
0N/A
0N/A return insets;
0N/A }
0N/A
0N/A /**
0N/A * Returns the label of the labeled border.
0N/A */
0N/A public JComponent getLabel() {
0N/A return label;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Sets the title of the titled border.
0N/A * param title the title for the border
0N/A */
0N/A public void setLabel(JComponent label) {
0N/A this.label = label;
0N/A }
0N/A
0N/A
0N/A
0N/A /**
0N/A * Returns the minimum dimensions this border requires
0N/A * in order to fully display the border and title.
0N/A * @param c the component where this border will be drawn
0N/A */
0N/A public Dimension getMinimumSize(Component c) {
0N/A Insets insets = getBorderInsets(c);
0N/A Dimension minSize = new Dimension(insets.right + insets.left,
0N/A insets.top + insets.bottom);
0N/A minSize.width += label.getWidth();
0N/A
0N/A return minSize;
0N/A }
0N/A
0N/A
0N/A private static boolean computeIntersection(Rectangle dest,
0N/A int rx, int ry, int rw, int rh) {
0N/A int x1 = Math.max(rx, dest.x);
0N/A int x2 = Math.min(rx + rw, dest.x + dest.width);
0N/A int y1 = Math.max(ry, dest.y);
0N/A int y2 = Math.min(ry + rh, dest.y + dest.height);
0N/A dest.x = x1;
0N/A dest.y = y1;
0N/A dest.width = x2 - x1;
0N/A dest.height = y2 - y1;
0N/A
0N/A if (dest.width <= 0 || dest.height <= 0) {
0N/A return false;
0N/A }
0N/A return true;
0N/A }
0N/A }
0N/A
0N/A
0N/A protected static class FocusBorder extends AbstractBorder implements FocusListener {
0N/A private Component comp;
0N/A private Color focusColor;
0N/A private boolean focusLostTemporarily = false;
0N/A
0N/A public FocusBorder(Component comp) {
0N/A this.comp = comp;
0N/A
0N/A comp.addFocusListener(this);
0N/A
0N/A // This is the best guess for a L&F specific color
0N/A focusColor = UIManager.getColor("TabbedPane.focus");
0N/A }
0N/A
0N/A public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) {
0N/A if (comp.hasFocus() || focusLostTemporarily) {
0N/A Color color = g.getColor();
0N/A g.setColor(focusColor);
0N/A BasicGraphicsUtils.drawDashedRect(g, x, y, width, height);
0N/A g.setColor(color);
0N/A }
0N/A }
0N/A
0N/A public Insets getBorderInsets(Component c, Insets insets) {
0N/A insets.set(2, 2, 2, 2);
0N/A return insets;
0N/A }
0N/A
0N/A
0N/A public void focusGained(FocusEvent e) {
0N/A comp.repaint();
0N/A }
0N/A
0N/A public void focusLost(FocusEvent e) {
0N/A // We will still paint focus even if lost temporarily
0N/A focusLostTemporarily = e.isTemporary();
0N/A if (!focusLostTemporarily) {
0N/A comp.repaint();
0N/A }
0N/A }
0N/A }
0N/A}