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