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

net.miginfocom.swing.SwingComponentWrapper Maven / Gradle / Ivy

The newest version!
package net.miginfocom.swing;
/*
 * License (BSD):
 * ==============
 *
 * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (miglayout (at) miginfocom (dot) com)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or other
 * materials provided with the distribution.
 * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
 * used to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * @version 1.0
 * @author Mikael Grev, MiG InfoCom AB
 *         Date: 2006-sep-08
 */

import net.miginfocom.layout.ComponentWrapper;
import net.miginfocom.layout.ContainerWrapper;
import net.miginfocom.layout.LayoutUtil;
import net.miginfocom.layout.PlatformDefaults;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.plaf.basic.BasicHTML;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.IdentityHashMap;
import java.util.StringTokenizer;

/**
 */
public class SwingComponentWrapper implements ComponentWrapper
{
	private static boolean maxSet = false;

	private static boolean vp = true;

	/** Debug color for component bounds outline.
	 */
	private static final Color DB_COMP_OUTLINE = new Color(0, 0, 200);

	/** Property to use in LAF settings and as JComponent client property
	 * to specify the visual padding.
	 * 

*/ private static final String VISUAL_PADDING_PROPERTY = net.miginfocom.layout.PlatformDefaults.VISUAL_PADDING_PROPERTY; private final Component c; private int compType = TYPE_UNSET; private Boolean bl = null; private boolean prefCalled = false; public SwingComponentWrapper(Component c) { this.c = c; } @Override public final int getBaseline(int width, int height) { int h = height; int[] visPad = getVisualPadding(); if (h < 0) { h = c.getHeight(); } else if (visPad != null) { h = height + visPad[0] + visPad[2]; } int baseLine = c.getBaseline(Math.max(0, width < 0 ? c.getWidth() : width), Math.max(0, h)); if (baseLine != -1 && visPad != null) baseLine -= visPad[0]; return baseLine; } @Override public final Object getComponent() { return c; } /** Cache. */ private final static IdentityHashMap FM_MAP = new IdentityHashMap(4); private final static Font SUBST_FONT = new Font("sansserif", Font.PLAIN, 11); @Override public final float getPixelUnitFactor(boolean isHor) { switch (PlatformDefaults.getLogicalPixelBase()) { case PlatformDefaults.BASE_FONT_SIZE: Font font = c.getFont(); FontMetrics fm = c.getFontMetrics(font != null ? font : SUBST_FONT); Point.Float p = FM_MAP.get(fm); if (p == null) { Rectangle2D r = fm.getStringBounds("X", c.getGraphics()); p = new Point.Float(((float) r.getWidth()) / 6f, ((float) r.getHeight()) / 13.27734375f); FM_MAP.put(fm, p); } return isHor ? p.x : p.y; case PlatformDefaults.BASE_SCALE_FACTOR: Float s = isHor ? PlatformDefaults.getHorizontalScaleFactor() : PlatformDefaults.getVerticalScaleFactor(); float scaleFactor = (s != null) ? s : 1f; // If the current look and feel is able to scale and provides // an scale factor, then use it. Object lafScaleFactorObj = UIManager.get( "laf.scaleFactor" ); if( lafScaleFactorObj instanceof Number ) { float lafScaleFactor = ((Number)lafScaleFactorObj).floatValue(); return scaleFactor * lafScaleFactor; } // Swing in Java 9 scales automatically using the system scale factor(s) that the // user can change in the system settings (Windows: Control Panel; Mac: System Preferences). // Each connected screen may use its own scale factor // (e.g. 1.5 for primary 4K 40inch screen and 1.0 for secondary HD screen). float screenScale = isJava9orLater ? 1f // use system scale factor(s) : (float) (isHor ? getHorizontalScreenDPI() : getVerticalScreenDPI()) / (float) PlatformDefaults.getDefaultDPI(); return scaleFactor * screenScale; default: return 1f; } } private static boolean isJava9orLater; static { try { // Java 9 version-String Scheme: http://openjdk.java.net/jeps/223 StringTokenizer st = new StringTokenizer(System.getProperty("java.version"), "._-+"); int majorVersion = Integer.parseInt(st.nextToken()); isJava9orLater = majorVersion >= 9; } catch (Exception e) { // Java 8 or older } } // /** Cache. // */ // private final static IdentityHashMap FM_MAP2 = new IdentityHashMap(4); // private final static Font SUBST_FONT2 = new Font("sansserif", Font.PLAIN, 11); // // public float getDialogUnit(boolean isHor) // { // Font font = c.getFont(); // FontMetrics fm = c.getFontMetrics(font != null ? font : SUBST_FONT2); // Point.Float dluP = FM_MAP2.get(fm); // if (dluP == null) { // float w = fm.charWidth('X') / 4f; // int ascent = fm.getAscent(); // float h = (ascent > 14 ? ascent : ascent + (15 - ascent) / 3) / 8f; // // dluP = new Point.Float(w, h); // FM_MAP2.put(fm, dluP); // } // return isHor ? dluP.x : dluP.y; // } @Override public final int getX() { return c.getX(); } @Override public final int getY() { return c.getY(); } @Override public final int getHeight() { return c.getHeight(); } @Override public final int getWidth() { return c.getWidth(); } @Override public final int getScreenLocationX() { Point p = new Point(); SwingUtilities.convertPointToScreen(p, c); return p.x; } @Override public final int getScreenLocationY() { Point p = new Point(); SwingUtilities.convertPointToScreen(p, c); return p.y; } @Override public final int getMinimumHeight(int sz) { if (prefCalled == false) { c.getPreferredSize(); // To defeat a bug where the minimum size is different before and after the first call to getPreferredSize(); prefCalled = true; } return c.getMinimumSize().height; } @Override public final int getMinimumWidth(int sz) { if (prefCalled == false) { c.getPreferredSize(); // To defeat a bug where the minimum size is different before and after the first call to getPreferredSize(); prefCalled = true; } return c.getMinimumSize().width; } @Override public final int getPreferredHeight(int sz) { // If the component has not gotten size yet and there is a size hint, trick Swing to return a better height. if (c.getWidth() == 0 && c.getHeight() == 0 && sz != -1) c.setBounds(c.getX(), c.getY(), sz, 1); return c.getPreferredSize().height; } @Override public final int getPreferredWidth(int sz) { // If the component has not gotten size yet and there is a size hint, trick Swing to return a better height. if (c.getWidth() == 0 && c.getHeight() == 0 && sz != -1) c.setBounds(c.getX(), c.getY(), 1, sz); return c.getPreferredSize().width; } @Override public final int getMaximumHeight(int sz) { if (!isMaxSet(c)) return Integer.MAX_VALUE; return c.getMaximumSize().height; } @Override public final int getMaximumWidth(int sz) { if (!isMaxSet(c)) return Integer.MAX_VALUE; return c.getMaximumSize().width; } private boolean isMaxSet(Component c) { return c.isMaximumSizeSet(); } @Override public final ContainerWrapper getParent() { Container p = c.getParent(); return p != null ? new SwingContainerWrapper(p) : null; } @Override public final int getHorizontalScreenDPI() { try { return c.getToolkit().getScreenResolution(); } catch (HeadlessException ex) { return PlatformDefaults.getDefaultDPI(); } } @Override public final int getVerticalScreenDPI() { try { return c.getToolkit().getScreenResolution(); } catch (HeadlessException ex) { return PlatformDefaults.getDefaultDPI(); } } @Override public final int getScreenWidth() { try { return c.getToolkit().getScreenSize().width; } catch (HeadlessException ex) { return 1024; } } @Override public final int getScreenHeight() { try { return c.getToolkit().getScreenSize().height; } catch (HeadlessException ex) { return 768; } } @Override public final boolean hasBaseline() { if (bl == null) { try { if(c instanceof JLabel && ((JComponent)c).getClientProperty(BasicHTML.propertyKey) != null) { bl = Boolean.FALSE; }else { bl = getBaseline(8192, 8192) > -1; // Use large number but don't risk overflow or exposing size bugs with Integer.MAX_VALUE } // Removed since OTHER is sometimes returned even though there is a valid baseline (e.g. an empty JComboBox) // if (c.getBaselineResizeBehavior() == Component.BaselineResizeBehavior.OTHER) { // bl = Boolean.FALSE; // } else { // Removed since it made some components layout themselves to the minimum size and that stuck after that. E.g. JLabel with HTML content and white spaces would be very tall. // Dimension d = c.getMinimumSize(); // bl = getBaseline(d.width, d.height) > -1; // } } catch (Throwable ex) { bl = Boolean.FALSE; } } return bl; } @Override public final String getLinkId() { return c.getName(); } @Override public final void setBounds(int x, int y, int width, int height) { c.setBounds(x, y, width, height); } @Override public boolean isVisible() { return c.isVisible(); } @Override public final int[] getVisualPadding() { int[] padding = null; if (isVisualPaddingEnabled()) { //First try "visualPadding" client property if (c instanceof JComponent) { JComponent component = (JComponent) c; Object padValue = component.getClientProperty(VISUAL_PADDING_PROPERTY); if (padValue instanceof int[] ) { //client property value could be an int[] padding = (int[]) padValue; } else if (padValue instanceof Insets) { //OR client property value could be an Insets Insets padInsets = (Insets) padValue; padding = new int[] { padInsets.top, padInsets.left, padInsets.bottom, padInsets.right }; } if (padding == null) { //No client property set on the individual JComponent, // so check for a LAF setting for the component type. String classID; switch (getComponentType(false)) { case TYPE_BUTTON: Border border = component.getBorder(); if (border != null && border.getClass().getName().startsWith("com.apple.laf.AquaButtonBorder")) { if (PlatformDefaults.getPlatform() == PlatformDefaults.MAC_OSX) { Object buttonType = component.getClientProperty("JButton.buttonType"); if (buttonType == null) { classID = component.getHeight() < 33 ? "Button" : "Button.bevel"; } else { classID = "Button." + buttonType; } if (((AbstractButton) component).getIcon() != null) classID += ".icon"; } else { classID = "Button"; } } else { classID = ""; } break; case TYPE_CHECK_BOX: border = component.getBorder(); if (border != null && border.getClass().getName().startsWith("com.apple.laf.AquaButtonBorder")) { Object size = component.getClientProperty("JComponent.sizeVariant"); if (size != null && size.toString().equals("regular") == false) { size = "." + size; } else { size = ""; } if (component instanceof JRadioButton) { classID = "RadioButton" + size; } else if (component instanceof JCheckBox) { classID = "CheckBox" + size; } else { classID = "ToggleButton" + size; } } else { classID = ""; } break; case TYPE_COMBO_BOX: if (PlatformDefaults.getPlatform() == PlatformDefaults.MAC_OSX) { if (((JComboBox) component).isEditable()) { Object isSquare = component.getClientProperty("JComboBox.isSquare"); if (isSquare != null && isSquare.toString().equals("true")) { classID = "ComboBox.editable.isSquare"; } else { classID = "ComboBox.editable"; } } else { Object isSquare = component.getClientProperty("JComboBox.isSquare"); Object isPopDown = component.getClientProperty("JComboBox.isPopDown"); if (isSquare != null && isSquare.toString().equals("true")) { classID = "ComboBox.isSquare"; } else if (isPopDown != null && isPopDown.toString().equals("true")) { classID = "ComboBox.isPopDown"; } else { classID = "ComboBox"; } } } else { classID = "ComboBox"; } break; case TYPE_CONTAINER: classID = "Container"; break; case TYPE_IMAGE: classID = "Image"; break; case TYPE_LABEL: classID = "Label"; break; case TYPE_LIST: classID = "List"; break; case TYPE_PANEL: classID = "Panel"; break; case TYPE_PROGRESS_BAR: classID = "ProgressBar"; break; case TYPE_SCROLL_BAR: classID = "ScrollBar"; break; case TYPE_SCROLL_PANE: classID = "ScrollPane"; break; case TYPE_SEPARATOR: classID = "Separator"; break; case TYPE_SLIDER: classID = "Slider"; break; case TYPE_SPINNER: classID = "Spinner"; break; case TYPE_TABLE: classID = "Table"; break; case TYPE_TABBED_PANE: classID = "TabbedPane"; break; case TYPE_TEXT_AREA: classID = "TextArea"; break; case TYPE_TEXT_FIELD: border = component.getBorder(); if (!component.isOpaque() && border != null && border.getClass().getSimpleName().equals("AquaTextFieldBorder")) { classID = "TextField"; } else { classID = ""; } break; case TYPE_TREE: classID = "Tree"; break; case TYPE_UNKNOWN: classID = "Other"; break; case TYPE_UNSET: default: classID = ""; break; } padValue = PlatformDefaults.getDefaultVisualPadding(classID + "." + VISUAL_PADDING_PROPERTY); if (padValue instanceof int[]) { //client property value could be an int[] padding = (int[]) padValue; } else if (padValue instanceof Insets) { //OR client property value could be an Insets Insets padInsets = (Insets) padValue; padding = new int[] { padInsets.top, padInsets.left, padInsets.bottom, padInsets.right }; } } } } return padding; } /** * @deprecated Java 1.4 is not supported anymore */ public static boolean isMaxSizeSetOn1_4() { return maxSet; } /** * @deprecated Java 1.4 is not supported anymore */ public static void setMaxSizeSetOn1_4(boolean b) { maxSet = b; } public static boolean isVisualPaddingEnabled() { return vp; } public static void setVisualPaddingEnabled(boolean b) { vp = b; } @Override public final void paintDebugOutline(boolean showVisualPadding) { if (c.isShowing() == false) return; Graphics2D g = (Graphics2D) c.getGraphics(); if (g == null) return; g.setPaint(DB_COMP_OUTLINE); g.setStroke(new BasicStroke(1f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] {2f, 4f}, 0)); g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); if (showVisualPadding && isVisualPaddingEnabled()) { int[] padding = getVisualPadding(); if (padding != null) { g.setColor(Color.GREEN); g.drawRect(padding[1], padding[0], (getWidth() - 1) - (padding[1] + padding[3]), (getHeight() - 1) - (padding[0] + padding[2])); } } } @Override public int getComponentType(boolean disregardScrollPane) { if (compType == TYPE_UNSET) compType = checkType(disregardScrollPane); return compType; } @Override public int getLayoutHashCode() { Dimension d = c.getMaximumSize(); int hash = d.width + (d.height << 5); d = c.getPreferredSize(); hash += (d.width << 10) + (d.height << 15); d = c.getMinimumSize(); hash += (d.width << 20) + (d.height << 25); if (c.isVisible()) hash += 1324511; String id = getLinkId(); if (id != null) hash += id.hashCode(); return hash; } private int checkType(boolean disregardScrollPane) { Component c = this.c; if (disregardScrollPane) { if (c instanceof JScrollPane) { c = ((JScrollPane) c).getViewport().getView(); } else if (c instanceof ScrollPane) { c = ((ScrollPane) c).getComponent(0); } } if (c instanceof JTextField || c instanceof TextField) { return TYPE_TEXT_FIELD; } else if (c instanceof JLabel || c instanceof Label) { return TYPE_LABEL; } else if (c instanceof JCheckBox || c instanceof JRadioButton || c instanceof Checkbox) { return TYPE_CHECK_BOX; } else if (c instanceof AbstractButton || c instanceof Button) { return TYPE_BUTTON; } else if (c instanceof JComboBox || c instanceof Choice) { return TYPE_COMBO_BOX; } else if (c instanceof JTextComponent || c instanceof TextComponent) { return TYPE_TEXT_AREA; } else if (c instanceof JPanel || c instanceof Canvas) { return TYPE_PANEL; } else if (c instanceof JList || c instanceof List) { return TYPE_LIST; } else if (c instanceof JTable) { return TYPE_TABLE; } else if (c instanceof JSeparator) { return TYPE_SEPARATOR; } else if (c instanceof JSpinner) { return TYPE_SPINNER; } else if (c instanceof JTabbedPane) { return TYPE_TABBED_PANE; } else if (c instanceof JProgressBar) { return TYPE_PROGRESS_BAR; } else if (c instanceof JSlider) { return TYPE_SLIDER; } else if (c instanceof JScrollPane) { return TYPE_SCROLL_PANE; } else if (c instanceof JScrollBar || c instanceof Scrollbar) { return TYPE_SCROLL_BAR; } else if (c instanceof Container) { // only AWT components is not containers. return TYPE_CONTAINER; } return TYPE_UNKNOWN; } @Override public final int hashCode() { return getComponent().hashCode(); } @Override public final boolean equals(Object o) { if (o instanceof ComponentWrapper == false) return false; return c.equals(((ComponentWrapper) o).getComponent()); } @Override public int getContentBias() { return c instanceof JTextArea || c instanceof JEditorPane || (c instanceof JComponent && Boolean.TRUE.equals(((JComponent)c).getClientProperty("migLayout.dynamicAspectRatio"))) ? LayoutUtil.HORIZONTAL : -1; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy