/* Copyright 2008-2010 Gephi Authors : Mathieu Bastian <mathieu.bastian@gephi.org> Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi 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 Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.ui.utils; // Copied from org.netbeans.lib.profiler.ui import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Image; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.Window; import java.awt.image.BufferedImage; import java.awt.image.PixelGrabber; import java.lang.reflect.InvocationTargetException; import javax.swing.AbstractButton; import javax.swing.JLabel; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JViewport; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.basic.BasicButtonListener; import javax.swing.table.JTableHeader; //Copied from org.netbeans.lib.profiler.ui public final class UIUtils { public static final float ALTERNATE_ROW_DARKER_FACTOR = 0.96f; private static Color unfocusedSelBg; private static Color unfocusedSelFg; //~ Methods ------------------------------------------------------------------------------------------------------------------ /** Determines if current L&F is AquaLookAndFeel */ public static boolean isAquaLookAndFeel() { // is current L&F some kind of AquaLookAndFeel? return UIManager.getLookAndFeel().getID().equals("Aqua"); //NOI18N } public static Color getDarker(Color c) { if (c.equals(Color.WHITE)) { return new Color(244, 244, 244); } return getSafeColor((int) (c.getRed() * ALTERNATE_ROW_DARKER_FACTOR), (int) (c.getGreen() * ALTERNATE_ROW_DARKER_FACTOR), (int) (c.getBlue() * ALTERNATE_ROW_DARKER_FACTOR)); } public static Color getForegroundColorForBackground(Color background) { return (background.getRed() < 100 || background.getGreen() < 100 || background.getRed() < 100) ? Color.white : Color.black; } public static Color getDarkerLine(Color c, float alternateRowDarkerFactor) { return getSafeColor((int) (c.getRed() * alternateRowDarkerFactor), (int) (c.getGreen() * alternateRowDarkerFactor), (int) (c.getBlue() * alternateRowDarkerFactor)); } public static int getDefaultRowHeight() { return new JLabel("X").getPreferredSize().height + 2; //NOI18N } /** Determines if current L&F is GTKLookAndFeel */ public static boolean isGTKLookAndFeel() { // is current L&F some kind of GTKLookAndFeel? return UIManager.getLookAndFeel().getID().equals("GTK"); //NOI18N } /** Determines if current L&F is Nimbus */ public static boolean isNimbusLookAndFeel() { // is current L&F Nimbus? return UIManager.getLookAndFeel().getID().equals("Nimbus"); //NOI18N } /** Determines if current L&F is GTK using Nimbus theme */ public static boolean isNimbusGTKTheme() { // is current L&F GTK using Nimbus theme? return isGTKLookAndFeel() && "nimbus".equals(Toolkit.getDefaultToolkit().getDesktopProperty("gnome.Net/ThemeName")); //NOI18N } /** Determines if current L&F is Nimbus or GTK with Nimbus theme*/ public static boolean isNimbus() { // is current L&F Nimbus or GTK with Nimbus theme? return isNimbusLookAndFeel() || isNimbusGTKTheme(); } /** Determines if current L&F is MetalLookAndFeel */ public static boolean isMetalLookAndFeel() { // is current L&F some kind of MetalLookAndFeel? return UIManager.getLookAndFeel().getID().equals("Metal"); //NOI18N } // Returns next enabled tab of JTabbedPane public static int getNextSubTabIndex(JTabbedPane tabs, int tabIndex) { int nextTabIndex = tabIndex; for (int i = 0; i < tabs.getComponentCount(); i++) { nextTabIndex++; if (nextTabIndex == tabs.getComponentCount()) { nextTabIndex = 0; } if (tabs.isEnabledAt(nextTabIndex)) { break; } } return nextTabIndex; } public static Window getParentWindow(Component comp) { while ((comp != null) && !(comp instanceof Window)) { comp = comp.getParent(); } return (Window) comp; } // Returns previous enabled tab of JTabbedPane public static int getPreviousSubTabIndex(JTabbedPane tabs, int tabIndex) { int previousTabIndex = tabIndex; for (int i = 0; i < tabs.getComponentCount(); i++) { previousTabIndex--; if (previousTabIndex < 0) { previousTabIndex = tabs.getComponentCount() - 1; } if (tabs.isEnabledAt(previousTabIndex)) { break; } } return previousTabIndex; } public static Color getSafeColor(int red, int green, int blue) { red = Math.max(red, 0); red = Math.min(red, 255); green = Math.max(green, 0); green = Math.min(green, 255); blue = Math.max(blue, 0); blue = Math.min(blue, 255); return new Color(red, green, blue); } // Copied from org.openide.awt.HtmlLabelUI /** Get the system-wide unfocused selection background color */ public static Color getUnfocusedSelectionBackground() { if (unfocusedSelBg == null) { //allow theme/ui custom definition unfocusedSelBg = UIManager.getColor("nb.explorer.unfocusedSelBg"); //NOI18N if (unfocusedSelBg == null) { //try to get standard shadow color unfocusedSelBg = UIManager.getColor("controlShadow"); //NOI18N if (unfocusedSelBg == null) { //Okay, the look and feel doesn't suport it, punt unfocusedSelBg = Color.lightGray; } //Lighten it a bit because disabled text will use controlShadow/ //gray if (!Color.WHITE.equals(unfocusedSelBg.brighter())) { unfocusedSelBg = unfocusedSelBg.brighter(); } } } return unfocusedSelBg; } // Copied from org.openide.awt.HtmlLabelUI /** Get the system-wide unfocused selection foreground color */ public static Color getUnfocusedSelectionForeground() { if (unfocusedSelFg == null) { //allow theme/ui custom definition unfocusedSelFg = UIManager.getColor("nb.explorer.unfocusedSelFg"); //NOI18N if (unfocusedSelFg == null) { //try to get standard shadow color unfocusedSelFg = UIManager.getColor("textText"); //NOI18N if (unfocusedSelFg == null) { //Okay, the look and feel doesn't suport it, punt unfocusedSelFg = Color.BLACK; } } } return unfocusedSelFg; } private static Color profilerResultsBackground; private static Color getGTKProfilerResultsBackground() { int[] pixels = new int[1]; pixels[0] = -1; // Prepare textarea to grab the color from JTextArea textArea = new JTextArea(); textArea.setSize(new Dimension(10, 10)); textArea.doLayout(); // Print the textarea to an image Image image = new BufferedImage(textArea.getSize().width, textArea.getSize().height, BufferedImage.TYPE_INT_RGB); textArea.printAll(image.getGraphics()); // Grab appropriate pixels to get the color PixelGrabber pixelGrabber = new PixelGrabber(image, 5, 5, 1, 1, pixels, 0, 1); try { pixelGrabber.grabPixels(); if (pixels[0] == -1) { return Color.WHITE; // System background not customized } } catch (InterruptedException e) { return getNonGTKProfilerResultsBackground(); } return pixels[0] != -1 ? new Color(pixels[0]) : getNonGTKProfilerResultsBackground(); } private static Color getNonGTKProfilerResultsBackground() { return UIManager.getColor("Table.background"); // NOI18N } public static Color getProfilerResultsBackground() { if (profilerResultsBackground == null) { if (isGTKLookAndFeel() || isNimbusLookAndFeel()) { profilerResultsBackground = getGTKProfilerResultsBackground(); } else { profilerResultsBackground = getNonGTKProfilerResultsBackground(); } if (profilerResultsBackground == null) { profilerResultsBackground = Color.WHITE; } } return profilerResultsBackground; } /** Determines if current L&F is Windows Classic LookAndFeel */ public static boolean isWindowsClassicLookAndFeel() { if (!isWindowsLookAndFeel()) { return false; } return (!isWindowsXPLookAndFeel() && !isWindowsVistaLookAndFeel()); } /** Determines if current L&F is WindowsLookAndFeel */ public static boolean isWindowsLookAndFeel() { // is current L&F some kind of WindowsLookAndFeel? return UIManager.getLookAndFeel().getID().equals("Windows"); //NOI18N } /** Determines if current L&F is Windows XP LookAndFeel */ public static boolean isWindowsXPLookAndFeel() { if (!isWindowsLookAndFeel()) { return false; } // is XP theme active in the underlying OS? boolean xpThemeActiveOS = Boolean.TRUE.equals(Toolkit.getDefaultToolkit().getDesktopProperty("win.xpstyle.themeActive")); //NOI18N // is XP theme disabled by the application? boolean xpThemeDisabled = (System.getProperty("swing.noxp") != null); // NOI18N boolean vistaOs = System.getProperty("os.version").startsWith("6.0"); return ((xpThemeActiveOS) && (!xpThemeDisabled) && !vistaOs); } public static boolean isWindowsVistaLookAndFeel() { if (!isWindowsLookAndFeel()) { return false; } // is XP theme active in the underlying OS? boolean xpThemeActiveOS = Boolean.TRUE.equals(Toolkit.getDefaultToolkit().getDesktopProperty("win.xpstyle.themeActive")); //NOI18N // is XP theme disabled by the application? boolean xpThemeDisabled = (System.getProperty("swing.noxp") != null); // NOI18N boolean vistaOs = System.getProperty("os.version").startsWith("6.0"); return ((xpThemeActiveOS) && (!xpThemeDisabled) && vistaOs); } // Classic Windows LaF doesn't draw dotted focus rectangle inside JButton if parent is JToolBar, // XP Windows LaF doesn't draw dotted focus rectangle inside JButton at all // This method installs customized Windows LaF that draws dotted focus rectangle inside JButton always // On JDK 1.5 the XP Windows LaF enforces special border to all buttons, overriding any custom border // set by setBorder(). Class responsible for this is WindowsButtonListener. See Issue 71546. // Also fixes buttons size in JToolbar. /** Ensures that focus will be really painted if button is focused * and fixes using custom border for JDK 1.5 & XP LaF */ public static void fixButtonUI(AbstractButton button) { // JButton if (button.getUI() instanceof com.sun.java.swing.plaf.windows.WindowsButtonUI) { button.setUI(new com.sun.java.swing.plaf.windows.WindowsButtonUI() { protected BasicButtonListener createButtonListener(AbstractButton b) { return new BasicButtonListener(b); // Fix for Issue 71546 } protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { int width = b.getWidth(); int height = b.getHeight(); g.setColor(getFocusColor()); javax.swing.plaf.basic.BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, width - dashedRectGapWidth, height - dashedRectGapHeight); } }); } // JToggleButton else if (button.getUI() instanceof com.sun.java.swing.plaf.windows.WindowsToggleButtonUI) { button.setUI(new com.sun.java.swing.plaf.windows.WindowsToggleButtonUI() { protected BasicButtonListener createButtonListener(AbstractButton b) { return new BasicButtonListener(b); // Fix for Issue 71546 } protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) { int width = b.getWidth(); int height = b.getHeight(); g.setColor(getFocusColor()); javax.swing.plaf.basic.BasicGraphicsUtils.drawDashedRect(g, dashedRectGapX, dashedRectGapY, width - dashedRectGapWidth, height - dashedRectGapHeight); } }); } } private static BufferedImage createTableScreenshot(Component component) { Component source; Dimension sourceSize; JTable table; if (component instanceof JTable) { table = (JTable) component; if ((table.getTableHeader() == null) || !table.getTableHeader().isVisible()) { return createGeneralComponentScreenshot(component); } source = table; sourceSize = table.getSize(); } else if (component instanceof JViewport && ((JViewport) component).getView() instanceof JTable) { JViewport viewport = (JViewport) component; table = (JTable) viewport.getView(); if ((table.getTableHeader() == null) || !table.getTableHeader().isVisible()) { return createGeneralComponentScreenshot(component); } if (table.getSize().height > viewport.getSize().height) { source = viewport; sourceSize = viewport.getSize(); } else { source = table; sourceSize = table.getSize(); } } else { throw new IllegalArgumentException("Component can only be JTable or JViewport holding JTable"); // NOI18N } final JTableHeader tableHeader = table.getTableHeader(); Dimension tableHeaderSize = tableHeader.getSize(); BufferedImage tableScreenshot = new BufferedImage(sourceSize.width, tableHeaderSize.height + sourceSize.height, BufferedImage.TYPE_INT_RGB); final Graphics tableScreenshotGraphics = tableScreenshot.getGraphics(); // Component.printAll has to run in AWT Thread to print component contents correctly if (SwingUtilities.isEventDispatchThread()) { tableHeader.printAll(tableScreenshotGraphics); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { tableHeader.printAll(tableScreenshotGraphics); } }); } catch (Exception e) { } } tableScreenshotGraphics.translate(0, tableHeaderSize.height); final Component printSrc = source; // Component.printAll has to run in AWT Thread to print component contents correctly if (SwingUtilities.isEventDispatchThread()) { printSrc.printAll(tableScreenshotGraphics); } else { try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { printSrc.printAll(tableScreenshotGraphics); } }); } catch (Exception e) { } } return tableScreenshot; } private static BufferedImage createGeneralComponentScreenshot(Component component) { Component source; Dimension sourceSize; if (component instanceof JViewport) { JViewport viewport = (JViewport) component; Component contents = viewport.getView(); if (contents.getSize().height > viewport.getSize().height) { source = component; sourceSize = component.getSize(); } else { source = contents; sourceSize = contents.getSize(); } } else { source = component; sourceSize = component.getSize(); } BufferedImage componentScreenshot = new BufferedImage(sourceSize.width, sourceSize.height, BufferedImage.TYPE_INT_RGB); Graphics componentScreenshotGraphics = componentScreenshot.getGraphics(); source.printAll(componentScreenshotGraphics); return componentScreenshot; } public static void runInEventDispatchThread(final Runnable r) { if (SwingUtilities.isEventDispatchThread()) { r.run(); } else { SwingUtilities.invokeLater(r); } } public static void runInEventDispatchThreadAndWait(final Runnable r) { if (SwingUtilities.isEventDispatchThread()) { r.run(); } else { try { SwingUtilities.invokeAndWait(r); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static BufferedImage createComponentScreenshot(final Component component) { final BufferedImage[] result = new BufferedImage[1]; final Runnable screenshotPerformer = new Runnable() { public void run() { if (component instanceof JTable || (component instanceof JViewport && ((JViewport) component).getView() instanceof JTable)) { result[0] = createTableScreenshot(component); } else { result[0] = createGeneralComponentScreenshot(component); } } }; try { if (SwingUtilities.isEventDispatchThread()) { screenshotPerformer.run(); } else { SwingUtilities.invokeAndWait(screenshotPerformer); } } catch (Exception e) { return null; } return result[0]; } }