X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=srcjar%2Fnet%2Fmiginfocom%2Fswing%2FSwingComponentWrapper.java;fp=srcjar%2Fnet%2Fmiginfocom%2Fswing%2FSwingComponentWrapper.java;h=2b6f1aaf145c731c6ea57af0cb7e0a6c4b80afec;hb=4f30214e8098748469c6a4269ac2ed6c5750e4b0;hp=0000000000000000000000000000000000000000;hpb=9dabc02511e3a334a5749a504f57f69d6c9017bd;p=jalview.git diff --git a/srcjar/net/miginfocom/swing/SwingComponentWrapper.java b/srcjar/net/miginfocom/swing/SwingComponentWrapper.java new file mode 100644 index 0000000..2b6f1aa --- /dev/null +++ b/srcjar/net/miginfocom/swing/SwingComponentWrapper.java @@ -0,0 +1,680 @@ +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.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(width < 0 ? c.getWidth() : width, 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; + + // 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 = true; +// 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 { + // 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.getPreferredSize(); +// bl = getBaseline(d.width, d.height) > -1; + bl = getBaseline(8192, 8192) > -1; // Use large number but don't risk overflow or exposing size bugs with Integer.MAX_VALUE +// } + } 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; + } +}