All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.layout.AquaBaseline Maven / Gradle / Ivy

Go to download

Swing Layout Extensions goal is to make it easy to create professional cross platform layouts with Swing. This project has an eye towards the needs of GUI builders, such as NetBeans. This project consists of the following pieces: * Ability to get the baseline for components. * Ability to get the preferred gap between components. * A new LayoutManager that utilizes both of these concepts and is tuned toward a free-form drag and drop layout model as can be provided by GUI builders.

There is a newer version: 1.0.2
Show newest version
/*
 * Copyright (C) 2005 Sun Microsystems, Inc. All rights reserved. Use is
 * subject to license terms.
 */ 

package org.jdesktop.layout;

import org.jdesktop.layout.*;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.swing.*;
import javax.swing.text.JTextComponent;
import javax.swing.text.View;
import java.util.Dictionary;
import java.util.Enumeration;
import javax.swing.border.*;
import javax.swing.plaf.metal.MetalLookAndFeel;

/**
 * Convenience class that can be used to determine the baseline of a
 * particular component.
 * 

* This class is primarily useful for JREs prior to 1.6. In 1.6 API for this * was added directly to Component, JComponent and the * appropriate ComponentUIs. When run on a JRE of 1.6 or greater this will directly * call into the getBaseline method of Component. * * @author Werner Randelshofer * @version $Revision$ */ class AquaBaseline extends Baseline { static final AquaBaseline INSTANCE = new AquaBaseline(); // // Used by button and label baseline code, cached to avoid excessive // garbage. // private static final Rectangle viewRect = new Rectangle(); private static final Rectangle textRect = new Rectangle(); private static final Rectangle iconRect = new Rectangle(); // // These come from TitleBorder. NOTE that these are NOT final in // TitledBorder // private static final int EDGE_SPACING = 2; private static final int TEXT_SPACING = 2; private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0); // Prototype label for calculating baseline of tables. private static JLabel TABLE_LABEL; // Prototype label for calculating baseline of lists. private static JLabel LIST_LABEL; // Prototype label for calculating baseline of trees. private static JLabel TREE_LABEL; /** * Returns the baseline for the specified component, or -1 if the * baseline can not be determined. The baseline is measured from * the top of the component. * * @param component JComponent to calculate baseline for * @param width Width of the component to determine baseline for. * @param height Height of the component to determine baseline for. * @return baseline for the specified component */ public int getComponentBaseline(JComponent component, int width, int height) { String uid = component.getUIClassID(); int baseline = -1; if (uid == "ButtonUI" || uid == "ToggleButtonUI") { baseline = getButtonBaseline((AbstractButton)component, height); } else if (uid == "CheckBoxUI" || uid == "RadioButtonUI") { baseline = getCheckBoxBaseline((AbstractButton)component, height) + 1; } else if (uid == "ComboBoxUI") { return getComboBoxBaseline((JComboBox)component, height); } else if (uid == "TextAreaUI") { return getTextAreaBaseline((JTextArea)component, height); } else if (uid == "FormattedTextFieldUI" || uid == "PasswordFieldUI" || uid == "TextFieldUI") { baseline = getSingleLineTextBaseline((JTextComponent)component, height); } else if (uid == "LabelUI") { baseline = getLabelBaseline((JLabel)component, height); } else if (uid == "ListUI") { baseline = getListBaseline((JList)component, height); } else if (uid == "PanelUI") { baseline = getPanelBaseline((JPanel)component, height); } else if (uid == "ProgressBarUI") { baseline = getProgressBarBaseline((JProgressBar)component, height); } else if (uid == "SliderUI") { baseline = getSliderBaseline((JSlider)component, height); } else if (uid == "SpinnerUI") { baseline = getSpinnerBaseline((JSpinner)component, height); } else if (uid == "ScrollPaneUI") { baseline = getScrollPaneBaseline((JScrollPane)component, height); } else if (uid == "TabbedPaneUI") { baseline = getTabbedPaneBaseline((JTabbedPane)component, height); } else if (uid == "TableUI") { baseline = getTableBaseline((JTable)component, height); } else if (uid == "TreeUI") { baseline = getTreeBaseline((JTree)component, height); } return Math.max(baseline, -1); } private static Insets rotateInsets(Insets topInsets, int targetPlacement) { switch(targetPlacement) { case JTabbedPane.LEFT: return new Insets(topInsets.left, topInsets.top, topInsets.right, topInsets.bottom); case JTabbedPane.BOTTOM: return new Insets(topInsets.bottom, topInsets.left, topInsets.top, topInsets.right); case JTabbedPane.RIGHT: return new Insets(topInsets.left, topInsets.bottom, topInsets.right, topInsets.top); default: return new Insets(topInsets.top, topInsets.left, topInsets.bottom, topInsets.right); } } private int getMaxTabHeight(JTabbedPane tp) { int fontHeight = tp.getFontMetrics(tp.getFont()).getHeight(); int height = fontHeight; boolean tallerIcons = false; for (int counter = tp.getTabCount() - 1; counter >= 0; counter--) { Icon icon = tp.getIconAt(counter); if (icon != null) { int iconHeight = icon.getIconHeight(); height = Math.max(height, iconHeight); if (iconHeight > fontHeight) { tallerIcons = true; } } } Insets tabInsets = UIManager.getInsets("TabbedPane.tabInsets"); height += 2; /* if (!isMetal() || !tallerIcons) { height += tabInsets.top + tabInsets.bottom; }*/ return height; } private int getTabbedPaneBaseline(JTabbedPane tp, int height) { if (tp.getTabCount() > 0) { Insets insets = tp.getInsets(); Insets contentBorderInsets = UIManager.getInsets( "TabbedPane.contentBorderInsets"); Insets tabAreaInsets = rotateInsets(UIManager.getInsets( "TabbedPane.tabAreaInsets"), tp.getTabPlacement()); FontMetrics metrics = tp.getFontMetrics(tp.getFont()); int maxHeight = getMaxTabHeight(tp); iconRect.setBounds(0, 0, 0, 0); textRect.setBounds(0, 0, 0, 0); viewRect.setBounds(0, 0, Short.MAX_VALUE, maxHeight); SwingUtilities.layoutCompoundLabel(tp, metrics, "A", null, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.CENTER, SwingUtilities.TRAILING, viewRect, iconRect, textRect, 0); int baseline = textRect.y + metrics.getAscent(); switch(tp.getTabPlacement()) { case JTabbedPane.TOP: baseline += insets.top + tabAreaInsets.top + 3; /* if (isWindows()) { if (tp.getTabCount() > 1) { baseline += 1; } else { baseline -= 1; } }*/ return baseline; case JTabbedPane.BOTTOM: baseline = tp.getHeight() - insets.bottom - tabAreaInsets.bottom - maxHeight + baseline; /* if (isWindows()) { if (tp.getTabCount() > 1) { baseline += -1; } else { baseline += 1; } }*/ return baseline; case JTabbedPane.LEFT: case JTabbedPane.RIGHT: baseline += insets.top + tabAreaInsets.top; /* if (isWindows()) { baseline += (maxHeight % 2); }*/ return baseline; } } return -1; } private int getSliderBaseline(JSlider slider, int height) { if (slider.getPaintLabels()) { FontMetrics metrics = slider.getFontMetrics(slider.getFont()); Insets insets = slider.getInsets(); Insets focusInsets = (Insets)UIManager.get("Slider.focusInsets"); if (slider.getOrientation() == JSlider.HORIZONTAL) { int tickLength = 8; int contentHeight = height - insets.top - insets.bottom - focusInsets.top - focusInsets.bottom; int thumbHeight = 20; /* if (isMetal()) { tickLength = ((Integer)UIManager.get( "Slider.majorTickLength")).intValue() + 5; thumbHeight = UIManager.getIcon( "Slider.horizontalThumbIcon" ).getIconHeight(); } else if (isWindows() && isXP()) { // PENDING: this is not correct, this should come from // the skin (in >= 1.5), but short of reflection // hacks we don't have access to the real value. thumbHeight++; }*/ int centerSpacing = thumbHeight; if (slider.getPaintTicks()) { // centerSpacing += getTickLength(); centerSpacing += tickLength; } // Assume uniform labels. centerSpacing += metrics.getAscent() + metrics.getDescent(); int trackY = insets.top + focusInsets.top + (contentHeight - centerSpacing - 1) / 2; int trackHeight = thumbHeight; int tickY = trackY + trackHeight; int tickHeight = tickLength; if (!slider.getPaintTicks()) { tickHeight = 0; } int labelY = tickY + tickHeight; return labelY + metrics.getAscent(); } else { // vertical boolean inverted = slider.getInverted(); Integer value = inverted ? getMinSliderValue(slider) : getMaxSliderValue(slider); if (value != null) { int thumbHeight = 11; /* if (isMetal()) { thumbHeight = UIManager.getIcon( "Slider.verticalThumbIcon").getIconHeight(); }*/ int trackBuffer = Math.max(metrics.getHeight() / 2, thumbHeight / 2); int contentY = focusInsets.top + insets.top; int trackY = contentY + trackBuffer; int trackHeight = height - focusInsets.top - focusInsets.bottom - insets.top - insets.bottom - trackBuffer - trackBuffer; int maxValue = getMaxSliderValue(slider).intValue(); int min = slider.getMinimum(); int max = slider.getMaximum(); double valueRange = (double)max - (double)min; double pixelsPerValue = (double)trackHeight / (double)valueRange; int trackBottom = trackY + (trackHeight - 1); int yPosition; if (!inverted) { yPosition = trackY; yPosition += Math.round(pixelsPerValue * ((double)max - value.intValue())); } else { yPosition = trackY; yPosition += Math.round(pixelsPerValue * ((double)value.intValue() - min) ); } yPosition = Math.max(trackY, yPosition); yPosition = Math.min(trackBottom, yPosition); return yPosition - metrics.getHeight() / 2 + metrics.getAscent(); } } } return -1; } private Integer getMaxSliderValue(JSlider slider) { Dictionary dictionary = slider.getLabelTable(); if (dictionary != null) { Enumeration keys = dictionary.keys(); int max = slider.getMinimum() - 1; while (keys.hasMoreElements()) { max = Math.max(max, ((Integer)keys.nextElement()).intValue()); } if (max == slider.getMinimum() - 1) { return null; } return new Integer(max); } return null; } private Integer getMinSliderValue(JSlider slider) { Dictionary dictionary = slider.getLabelTable(); if (dictionary != null) { Enumeration keys = dictionary.keys(); int min = slider.getMaximum() + 1; while (keys.hasMoreElements()) { min = Math.min(min, ((Integer)keys.nextElement()).intValue()); } if (min == slider.getMaximum() + 1) { return null; } return new Integer(min); } return null; } private int getProgressBarBaseline(JProgressBar pb, int height) { if (pb.isStringPainted() && pb.getOrientation() == JProgressBar.HORIZONTAL) { FontMetrics metrics = pb.getFontMetrics(pb.getFont()); Insets insets = pb.getInsets(); int y = insets.top; /* if (isWindows() && isXP()) { if (pb.isIndeterminate()) { y = -1; height--; } else { y = 0; height -= 3; } } else if (isGTK()) { return (height - metrics.getAscent() - metrics.getDescent()) / 2 + metrics.getAscent(); } else {*/ height -= insets.top + insets.bottom; //} return y + (height + metrics.getAscent() - metrics.getLeading() - metrics.getDescent()) / 2; } return -1; } private int getTreeBaseline(JTree tree, int height) { int rowHeight = tree.getRowHeight(); if (TREE_LABEL == null) { TREE_LABEL = new JLabel("X"); TREE_LABEL.setIcon(UIManager.getIcon("Tree.closedIcon")); } JLabel label = TREE_LABEL; label.setFont(tree.getFont()); if (rowHeight <= 0) { rowHeight = label.getPreferredSize().height; } return getLabelBaseline(label, rowHeight) + tree.getInsets().top; } private int getTableBaseline(JTable table, int height) { if (TABLE_LABEL == null) { TABLE_LABEL = new JLabel(""); TABLE_LABEL.setBorder(new EmptyBorder(1, 1, 1, 1)); } JLabel label = TABLE_LABEL; label.setFont(table.getFont()); int rowMargin = table.getRowMargin(); int baseline = getLabelBaseline(label, table.getRowHeight() - rowMargin); return baseline += rowMargin / 2; } private int getTextAreaBaseline(JTextArea text, int height) { Insets insets = text.getInsets(); FontMetrics fm = text.getFontMetrics(text.getFont()); return insets.top + fm.getAscent(); } private int getListBaseline(JList list, int height) { int rowHeight = list.getFixedCellHeight(); if (LIST_LABEL == null) { LIST_LABEL = new JLabel("X"); LIST_LABEL.setBorder(new EmptyBorder(1, 1, 1, 1)); } JLabel label = LIST_LABEL; label.setFont(list.getFont()); // JList actually has much more complex behavior here. // If rowHeight != -1 the rowHeight is either the max of all cell // heights (layout orientation != VERTICAL), or is variable depending // upon the cell. We assume a default size. // We could theoretically query the real renderer, but that would // not work for an empty model and the results may vary with // the content. if (rowHeight == -1) { rowHeight = label.getPreferredSize().height; } return getLabelBaseline(label, rowHeight) + list.getInsets().top; } private int getScrollPaneBaseline(JScrollPane sp, int height) { Component view = sp.getViewport().getView(); if (view instanceof JComponent) { int baseline = getBaseline((JComponent)view); if (baseline > 0) { return baseline + sp.getViewport().getY(); } } return -1; } private int getPanelBaseline(JPanel panel, int height) { Border border = panel.getBorder(); if (border instanceof TitledBorder) { TitledBorder titledBorder = (TitledBorder)border; if (titledBorder.getTitle() != null && !"".equals(titledBorder.getTitle())) { Font font = titledBorder.getTitleFont(); if (font == null) { font = panel.getFont(); if (font == null) { font = new Font("Dialog", Font.PLAIN, 12); } } Border border2 = titledBorder.getBorder(); Insets borderInsets; if (border2 != null) { borderInsets = border2.getBorderInsets(panel); } else { borderInsets = EMPTY_INSETS; } FontMetrics fm = panel.getFontMetrics(font); int fontHeight = fm.getHeight(); int descent = fm.getDescent(); int ascent = fm.getAscent(); int y = EDGE_SPACING; int h = height - EDGE_SPACING * 2; int diff; switch (((TitledBorder)border).getTitlePosition()) { case TitledBorder.ABOVE_TOP: diff = ascent + descent + (Math.max(EDGE_SPACING, TEXT_SPACING*2) - EDGE_SPACING); return y + diff - (descent + TEXT_SPACING); case TitledBorder.TOP: case TitledBorder.DEFAULT_POSITION: diff = Math.max(0, ((ascent/2) + TEXT_SPACING) - EDGE_SPACING); return (y + diff - descent) + (borderInsets.top + ascent + descent)/2; case TitledBorder.BELOW_TOP: return y + borderInsets.top + ascent + TEXT_SPACING; case TitledBorder.ABOVE_BOTTOM: return (y + h) - (borderInsets.bottom + descent + TEXT_SPACING); case TitledBorder.BOTTOM: h -= fontHeight / 2; return ((y + h) - descent) + ((ascent + descent) - borderInsets.bottom)/2; case TitledBorder.BELOW_BOTTOM: h -= fontHeight; return y + h + ascent + TEXT_SPACING; } } } return -1; } private int getSpinnerBaseline(JSpinner spinner, int height) { JComponent editor = spinner.getEditor(); if (editor instanceof JSpinner.DefaultEditor) { JSpinner.DefaultEditor defaultEditor = (JSpinner.DefaultEditor) editor; JTextField tf = defaultEditor.getTextField(); Insets spinnerInsets = spinner.getInsets(); Insets editorInsets = defaultEditor.getInsets(); int offset = spinnerInsets.top + editorInsets.top; height -= (offset + spinnerInsets.bottom + editorInsets.bottom); if (height <= 0) { return -1; } return offset + getSingleLineTextBaseline(tf, height); } Insets insets = spinner.getInsets(); FontMetrics fm = spinner.getFontMetrics(spinner.getFont()); return insets.top + fm.getAscent(); } private int getLabelBaseline(JLabel label, int height) { Icon icon = (label.isEnabled()) ? label.getIcon() : label.getDisabledIcon(); FontMetrics fm = label.getFontMetrics(label.getFont()); resetRects(label, height); SwingUtilities.layoutCompoundLabel(label, fm, "a", icon, label.getVerticalAlignment(), label.getHorizontalAlignment(), label.getVerticalTextPosition(), label.getHorizontalTextPosition(), viewRect, iconRect, textRect, label.getIconTextGap()); return textRect.y + fm.getAscent(); } private int getComboBoxBaseline(JComboBox combobox, int height) { Insets insets = combobox.getInsets(); int y = insets.top; height -= (insets.top + insets.bottom); if (combobox.isEditable()) { ComboBoxEditor editor = combobox.getEditor(); if (editor != null && (editor.getEditorComponent() instanceof JTextField)) { JTextField tf = (JTextField)editor.getEditorComponent(); return y + getSingleLineTextBaseline(tf, height); } } y -= 1; // Use the renderer to calculate baseline ListCellRenderer renderer = combobox.getRenderer(); if (renderer instanceof JLabel) { return y + getLabelBaseline((JLabel)renderer, height); } // Renderer isn't a label, use metrics directly. FontMetrics fm = combobox.getFontMetrics(combobox.getFont()); return y + fm.getAscent(); } /** * Returns the baseline for single line text components, like * JTextField. */ private int getSingleLineTextBaseline(JTextComponent textComponent, int h) { View rootView = textComponent.getUI().getRootView(textComponent); if (rootView.getViewCount() > 0) { Insets insets = textComponent.getInsets(); int height = h - insets.top - insets.bottom; int y = insets.top; View fieldView = rootView.getView(0); int vspan = (int)fieldView.getPreferredSpan(View.Y_AXIS); if (height != vspan) { int slop = height - vspan; y += slop / 2; } FontMetrics fm = textComponent.getFontMetrics( textComponent.getFont()); y += fm.getAscent(); return y; } return -1; } /** * Returns the baseline for buttons. */ private int getCheckBoxBaseline(AbstractButton button, int height) { FontMetrics fm = button.getFontMetrics(button.getFont()); resetRects(button, height); // NOTE: that we use "a" here to make sure we get a valid value, if // we were to pass in an empty string or null we would not get // back the right thing. SwingUtilities.layoutCompoundLabel( button, fm, "a", button.getIcon(), button.getVerticalAlignment(), button.getHorizontalAlignment(), button.getVerticalTextPosition(), button.getHorizontalTextPosition(), viewRect, iconRect, textRect, button.getText() == null ? 0 : button.getIconTextGap()); return textRect.y + fm.getAscent(); } /** * Returns the baseline for buttons. */ private int getButtonBaseline(AbstractButton button, int height) { FontMetrics fm = button.getFontMetrics(button.getFont()); resetRects(button, height); // NOTE: that we use "a" here to make sure we get a valid value, if // we were to pass in an empty string or null we would not get // back the right thing. SwingUtilities.layoutCompoundLabel( button, fm, "a", button.getIcon(), button.getVerticalAlignment(), button.getHorizontalAlignment(), button.getVerticalTextPosition(), button.getHorizontalTextPosition(), viewRect, iconRect, textRect, button.getText() == null ? 0 : button.getIconTextGap()); return textRect.y + fm.getAscent() + 1; } private void resetRects(JComponent c, int height) { Insets insets = c.getInsets(); viewRect.x = insets.left; viewRect.y = insets.top; viewRect.width = c.getWidth() - (insets.right + viewRect.x); viewRect.height = height - (insets.bottom + viewRect.y); textRect.x = textRect.y = textRect.width = textRect.height = 0; iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0; } private static boolean isMac() { return UIManager.getLookAndFeel().getID() == "Mac"; } private static boolean isAqua() { return UIManager.getLookAndFeel().getID() == "Aqua"; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy