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

it.tidalwave.netbeans.lookandfeel.impl.LookAndFeelModule Maven / Gradle / Ivy

The newest version!
/***********************************************************************************************************************
 *
 * SolidBlue - open source safe data
 * Copyright (C) 2011-2011 by Tidalwave s.a.s. (http://www.tidalwave.it)
 *
 ***********************************************************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations under the License.
 *
 ***********************************************************************************************************************
 *
 * WWW: http://solidblue.java.net
 * SCM: https://bitbucket.org/tidalwave/solidblue-src
 *
 **********************************************************************************************************************/
package it.tidalwave.netbeans.lookandfeel.impl;

import java.awt.Component;
import java.awt.Container;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.SwingUtilities;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JPopupMenu;
import javax.swing.UIManager;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.html.HTMLEditorKit;
import javax.swing.text.html.StyleSheet;
import org.jdesktop.layout.LayoutStyle;
import org.jdesktop.swingx.JXDatePicker;
import org.openide.util.Utilities;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.openide.modules.ModuleInstall;
import it.tidalwave.netbeans.lookandfeel.DimmableColor;
import it.tidalwave.netbeans.lookandfeel.LookAndFeel;
import it.tidalwave.netbeans.lookandfeel.ui.BlueMarineScrollBarUI;
import it.tidalwave.netbeans.lookandfeel.ui.DarkViewPanelUI;
import it.tidalwave.netbeans.lookandfeel.ui.HeaderPanelUI;
import it.tidalwave.netbeans.lookandfeel.ui.openide.NoTabsTabDisplayerUI;
import it.tidalwave.util.logging.Logger;
import java.awt.GraphicsEnvironment;
import java.util.Arrays;
import java.util.List;
import javax.annotation.Nonnull;
import javax.swing.JPanel;
import javax.swing.plaf.basic.BasicListUI;
import org.openide.util.Lookup;

// This was originally for fixing BM407, but now also serves to apply the proper gap to header panels.
// TODO: I'm not sure it's still needed, even for header panels.
//class PachedLayoutStyle extends LayoutStyle
//  {
//    private final LayoutStyle style;
//    
//    public PachedLayoutStyle (final LayoutStyle style)
//      {
//        this.style = style;
//      }
//
//    @Override
//    public int getPreferredGap (final JComponent component1,
//                                final JComponent component2,
//                                final int type,
//                                final int position,
//                                final Container parent)
//      {
////        System.err.println("getPreferredGap(" + component1 + ", " + component2 + ", " + type + ", " + position + ", " + parent + ")");
//        if (isHeaderPanel(component1) || isHeaderPanel(component2))
//          {
//            return 0;  
//          }
//
//        return style.getPreferredGap(component1, component2, type, position, parent); 
//      }
//
//    @Override
//    public int getContainerGap (final JComponent component,
//                                final int position,
//                                final Container parent)
//      {
//        final int result = style.getContainerGap(component, position, parent);  
////        System.err.printf("getContainerGap(%s, %d, %s) -> %d\n", component.getName(), position, parent.getName(), result);
//        return result;
//      }
//    
//    private boolean isHeaderPanel (final JComponent component)
//      {
//        if (component instanceof JPanel)
//          {
//            return ((JPanel)component).getUI().getClass().equals(HeaderPanelUI.class);
//          }
//
//        return false;
//      }
//  }

/*******************************************************************************
 *
 * @author  Fabrizio Giudici
 * @version $Id$
 *
 ******************************************************************************/
public class LookAndFeelModule extends ModuleInstall  
  {
    private static final String CLASS = LookAndFeelModule.class.getName();    
    private static final Logger logger = Logger.getLogger(CLASS);
    private static final long serialVersionUID = 4833975975713639040L;
    
    private static final float FONT_HEADER_SCALE = 16.0F / 13.0F;
    
    private static final float FONT_HEADER_SMALL_SCALE = 14.0F / 13.0F;
    
    /***************************************************************************
     *
     * Installs the L&F settings at startup.
     *
     **************************************************************************/
    @Override
    public void restored() 
      {
        super.restored();
        
//        dumpDefaults();
        logger.info("Installing look and feel...");
        
        final boolean isSoyLatte = "Darwin".equals(System.getProperty("os.name")) &&
                    "Sun Microsystems Inc.".equals(System.getProperty("java.vm.vendor"));
        final boolean soyLatteDontUseQuaqua = Boolean.getBoolean("it.tidalwave.netbeans.soylatteDontUseQuaqua");
        
        if ((Utilities.getOperatingSystem() == Utilities.OS_MAC) && !(isSoyLatte && soyLatteDontUseQuaqua))
          {
            installQuaqua();
//            installNimrod(); // only for testing
            
            // Workaround for a bug in SwingX 2007_04_15, as there's a bad mapping for DatePickerUI on Mac OS X
            // See https://swingx.dev.java.net/issues/show_bug.cgi?id=488
            // TODO: should be fixed now, check
            UIManager.put(JXDatePicker.uiClassID, "org.jdesktop.swingx.plaf.basic.BasicDatePickerUI");
          }

        else
          {
            // This is because NASA World Wind 0.3.0 use a heavyweight component that hides lightweight popups
            JPopupMenu.setDefaultLightWeightPopupEnabled(false);
            installNimrod(); 
//            installNimbus(); 
          }
            
//        UIManager.put("ScrollBarUI", BlueMarineScrollBarUI.class.getName());
//        LayoutStyle.setSharedInstance(new PachedLayoutStyle(LayoutStyle.getSharedInstance()));
            
//        int borderSize = 2;
//        Border border = BorderFactory.createEmptyBorder(0, borderSize, 0, borderSize);
//        UIManager.put("ToolBar.rolloverBorder", border);
//        UIManager.put("ToolBar.nonrolloverBorder", border);
        
        if (Boolean.getBoolean("it.tidalwave.netbeans.disableTabs"))
          {
            installEmptyComponentTabs();
          }
        
        installFonts();
//        installBlueMarineTheme();   
//        installBlackTheme();
      }

    /***************************************************************************
     *
     * Installs the Quaqua L&F.
     *
     **************************************************************************/
    private void installQuaqua() 
      {
        if (!Boolean.getBoolean("it.tidalwave.netbeans.disableQuaua"))
          {
            final String lafClassName = "ch.randelshofer.quaqua.QuaquaLookAndFeel";
 //           final Object save = UIManager.get("LayoutStyle.instance");
                
    //            System.setProperty("Quaqua.opaque", "true");
    //            System.setProperty("Quaqua.Table.style", "striped");
    //            System.setProperty("Quaqua.Tree.style", "striped");
//                UIManager.put("OptionPaneUI", "it.tidalwave.bluemarine.lookandfeel.quaqua.BMQuaquaOptionPaneUI"); 
            installLookAndFeel(lafClassName);
            UIManager.put("Panel.opaque", Boolean.TRUE); // FIXME: workaround for reducing the gray border bug
            
            UIManager.put("Quaqua.ToolBar.style", "title"); // FIXME: requires setting apple.awt.brushMetalLook to the JRootPane

            final Object icon = javax.swing.LookAndFeel.makeIcon(getClass(), "Icon-64.png");
            UIManager.put("OptionPane.errorIcon", icon);
            UIManager.put("OptionPane.informationIcon", icon);
            UIManager.put("OptionPane.questionIcon", icon);
            UIManager.put("OptionPane.warningIcon", icon);
          }
      }

    /***************************************************************************
     *
     * Installs the Nimbus L&F.
     *
     **************************************************************************/
//    private void installNimbus()
//      {
//        installLookAndFeel("org.jdesktop.swingx.plaf.nimbus.NimbusLookAndFeel");
//        UIManager.put("Nb.Toolbar.ui", "javax.swing.plaf.basic.BasicToolBarUI");
//        UIManager.put("ScrollBarUI", BlueMarineScrollBarUI.class.getName());
//        installDefaultDarkUISettings();
//      }
    
    /***************************************************************************
     *
     * Installs the Nimrod L&F.
     *
     **************************************************************************/
    private void installNimrod() 
      {
        System.setProperty("nimrodlf.p1", "#808080");
        System.setProperty("nimrodlf.p2", "#a0a0a0");
        System.setProperty("nimrodlf.p3", "#c0c0c0");
        System.setProperty("nimrodlf.s1", "#525252");
        System.setProperty("nimrodlf.s2", "#5C5C5C");
        System.setProperty("nimrodlf.s3", "#666666");
        System.setProperty("nimrodlf.w", "#000000");
        System.setProperty("nimrodlf.b", "#FFFFFF");
        System.setProperty("nimrodlf.menuOpacity", "255");
        System.setProperty("nimrodlf.frameOpacity", "255");
        
        installLookAndFeel("com.nilo.plaf.nimrod.NimRODLookAndFeel");
        UIManager.put("Nb.Toolbar.ui", "javax.swing.plaf.basic.BasicToolBarUI"); 
        UIManager.put("ScrollBarUI", BlueMarineScrollBarUI.class.getName());
        UIManager.put("ListUI", BasicListUI.class.getName());
//        installDefaultDarkUISettings();
      }
    
    /***************************************************************************
     *
     * Installs a L&F specified by the given class name. Since it uses the
     * Platform classloader, the L&F provider needn't to be in dependencies.
     * 
     * @param  lafClassName  the L&F class name
     *
     **************************************************************************/
    private void installLookAndFeel (@Nonnull final String lafClassName)
      {        
        try 
          {
//            final Class lookAndFeelClass = Class.forName(lafClassName);
            final ClassLoader classLoader = Lookup.getDefault().lookup(ClassLoader.class);
            final Class lookAndFeelClass = classLoader.loadClass(lafClassName);
            final javax.swing.LookAndFeel lookAndFeel = (javax.swing.LookAndFeel)lookAndFeelClass.newInstance();
            UIManager.setLookAndFeel(lookAndFeel);
//            UIManager.setLookAndFeel(lafClassName);
          }    
        catch (Exception e) 
          {
            logger.throwing(CLASS, "installLookAndFeel()", e);
          }
      }

    /***************************************************************************
     *
     * Installs the UI components that remove the tabs from NetBeans.
     *
     **************************************************************************/
    private void installEmptyComponentTabs()
      {
        UIManager.put("EditorTabDisplayerUI", NoTabsTabDisplayerUI.class.getName());
        UIManager.put("ViewTabDisplayerUI", NoTabsTabDisplayerUI.class.getName());
        UIManager.put("TabbedContainer.editor.contentBorder", BorderFactory.createEmptyBorder());
        UIManager.put("TabbedContainer.view.contentBorder", BorderFactory.createEmptyBorder());
      }
    
    /***************************************************************************
     *
     * Installs the UIManager defaults for the blueMarine color theme.
     *
     **************************************************************************/
//    private void installBlueMarineTheme() 
//      {
//        UIManager.put(LookAndFeel.UI_HEADER_PANEL, new HeaderPanelUI());
//        UIManager.put(LookAndFeel.UI_DARK_VIEW_PANEL, new DarkViewPanelUI());       
//        
//        // Light theme - not used any longer, if you want to re-enable it, you have to complete the settings.
//        if (false)
//          {
//            UIManager.put(LookAndFeel.COLOR_DESKTOP_BACKGROUND, new DimmableColor(100, 100, 100));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_BACKGROUND, new DimmableColor(210, 210, 210));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_FOREGROUND, new DimmableColor(40, 40, 40));
//            UIManager.put(LookAndFeel.COLOR_HEADER_FOREGROUND, new DimmableColor(0, 0, 0));
//            UIManager.put(LookAndFeel.COLOR_HEADER_BACKGROUND, new DimmableColor(185, 185, 185));
//            UIManager.put(LookAndFeel.COLOR_HEADER_DARK_FOREGROUND, new DimmableColor(140, 140, 140));
//            UIManager.put(LookAndFeel.COLOR_HEADER_DARK_FOREGROUND2, new DimmableColor(200, 200, 200));
//            UIManager.put(LookAndFeel.COLOR_HEADER_DARK_BACKGROUND, new DimmableColor(25, 25, 25));
//          }
//        
//        // Dark theme
//        else
//          {
//            //
//            // The default renderer would drastically choose BLACK or WHITE if there's not enough contrast 
//            // between the background and the foreround. See a comment in http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5069799
//            // We disable it, so we take control of the colors.
//            //
//            System.setProperty("nb.useSwingHtmlRendering", "true");
//            UIManager.put(LookAndFeel.COLOR_FRAME_FOREGROUND, new DimmableColor(28, 28, 28));
//            UIManager.put(LookAndFeel.COLOR_DESKTOP_BACKGROUND, new DimmableColor(100, 100, 100));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_BACKGROUND, new DimmableColor(62, 62, 62));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_FOREGROUND, new DimmableColor(210, 210, 210));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_DARK_BACKGROUND, new DimmableColor(70, 70, 70));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_DARK_FOREGROUND, new DimmableColor(170, 170, 170));
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_SELECTION_FOREGROUND, new DimmableColor(15, 15, 15)); 
//            UIManager.put(LookAndFeel.COLOR_EXPLORER_SELECTION_BACKGROUND, new DimmableColor(208, 208, 208));
//            UIManager.put(LookAndFeel.COLOR_HEADER_FOREGROUND, new DimmableColor(178, 178, 178));
//            UIManager.put(LookAndFeel.COLOR_HEADER_BACKGROUND, new DimmableColor(65, 65, 65));
//            UIManager.put(LookAndFeel.COLOR_HEADER_DARK_FOREGROUND, new DimmableColor(140, 140, 140));
//            UIManager.put(LookAndFeel.COLOR_HEADER_DARK_FOREGROUND2, new DimmableColor(200, 200, 200));
//            UIManager.put(LookAndFeel.COLOR_HEADER_DARK_BACKGROUND, new DimmableColor(25, 25, 25));
//            UIManager.put(LookAndFeel.BORDER_EXPLORER, new ExplorerPanelBorder());            
////            UIManager.put("it.tidalwave.openide.explorer.scrollbar.darkenerColor", new Color(0, 0, 0, 128));
//            UIManager.put("ScrollBar.thumb", new DimmableColor(90, 90, 90));
//            UIManager.put("ScrollBar.track", new DimmableColor(64, 64, 64));
////            UIManager.put("nbProgressBar.Foreground", Color.RED); useless
//          }
//      }

    /***************************************************************************
     *
     *
     **************************************************************************/
//    private void installDefaultDarkUISettings() 
//      throws NumberFormatException 
//      {
//        UIManager.put("List.background", Color.decode("#777777"));
//        UIManager.put("Tree.background", Color.decode("#777777"));
//        UIManager.put("Tree.textBackground", Color.decode("#777777"));
//        UIManager.put("Table.background", Color.decode("#777777"));
//        UIManager.put("TextField.background", Color.decode("#777777"));
//        UIManager.put("EditorPane.background", Color.decode("#666666"));
//        UIManager.put("EditorPane.foreground", Color.decode("#ffffff"));
//        UIManager.put("TextPane.background", Color.decode("#666666"));
//        UIManager.put("TextPane.foreground", Color.decode("#ffffff"));
//
//        //
//        // This is for JTextPane and JEditorPane.
//        //
//        final HTMLEditorKit editorKit = new HTMLEditorKit();
//        // By default HTMLEditorKit comes with a shared StyleSheet.
//        // Changing it will affect all HTMLEditorKits.
//        final StyleSheet defaultStyleSheet = editorKit.getStyleSheet();
//        final Style bodyStyle = defaultStyleSheet.getStyle("body");
//        StyleConstants.setForeground(bodyStyle, Color.WHITE);
//        StyleConstants.setFontFamily(bodyStyle, "sansserif");
//        final Style aStyle = defaultStyleSheet.getStyle("a");
//        StyleConstants.setForeground(aStyle, Color.WHITE);
//        StyleConstants.setBold(aStyle, true);
//        StyleConstants.setUnderline(aStyle, false);
//        StyleConstants.setItalic(aStyle, true);
//      }

    /***************************************************************************
     *
     *
     **************************************************************************/
    private void installFonts() 
      {
        Font font = UIManager.getFont("Tree.font"); // reference font for getting the size
        logger.info("Default font: %s", font.getName());
        
        String fontNames = null;

        if (Utilities.getOperatingSystem() == Utilities.OS_MAC)
          {
            // to try: Geeza pro, Lucida grande, Tahoma, Trebuchet MS
            // These don't have bold: Geneva, Gulim, Open Symbol
            fontNames = "Lucida grande";
          }
        
        else if (Utilities.getOperatingSystem() == Utilities.OS_LINUX)
          {
            fontNames = "Bitstream Vera Sans, SansSerif, Arial";
          }

        if (fontNames != null)
          {
            font = new Font(findAvailableFont(fontNames.split(",")), Font.PLAIN, font.getSize());
          }

        if (font != null)
          {
            logger.info("Selected font: %s", font.getName());
            final float scale = 11.0f / 13.0f;
            final Font newFont = font.deriveFont(scale * font.getSize2D());
            UIManager.put(LookAndFeel.FONT_EXPLORER, newFont);
            UIManager.put(LookAndFeel.FONT_SMALL, newFont);
            UIManager.put(LookAndFeel.FONT_HEADER, font.deriveFont(FONT_HEADER_SCALE * font.getSize2D()));
            UIManager.put(LookAndFeel.FONT_HEADER_SMALL, font.deriveFont(FONT_HEADER_SMALL_SCALE * font.getSize2D()));
          }
      }

    /***************************************************************************
     *
     *
     **************************************************************************/
    @Nonnull
    private static String findAvailableFont (@Nonnull final String ... names)
      {
        final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        final List fontNames = Arrays.asList(ge.getAvailableFontFamilyNames());
        logger.info("Available fonts: %s", fontNames);

        for (String name : names)
          {
            name = name.trim();
            
            if (fontNames.contains(name))
              {
                return name;
              }
          }

        return "Arial";
      }
    
    /***************************************************************************
     *
     *
     **************************************************************************/
//    private void installBlackTheme()
//      {
//        SwingUtilities.invokeLater(new Runnable() 
//          {
//            public void run() 
//              {
//                final Color color = UIManager.getColor(LookAndFeel.COLOR_FRAME_FOREGROUND);
////                System.err.println("XXXCOL " + color);
//                final Frame mainWindow = WindowManager.getDefault().getMainWindow();
//
//                if (mainWindow.isVisible())
//                  {
//                    setBackgroundRecursively(mainWindow, color);
//                  }
//
//                else
//                  {
//                    mainWindow.addComponentListener(new ComponentAdapter() 
//                      {
//                        @Override
//                        public void componentShown (final ComponentEvent event) 
//                          {
//                            setBackgroundRecursively(mainWindow, color);
//                            mainWindow.removeComponentListener(this);
//                          }
//                      });
//                  } 
//              }
//          });
//      }
    
    /***************************************************************************
     *
     *
     **************************************************************************/
//    private void setBackgroundRecursively (final Component component, final Color color)
//      {
//        final String className = component.getClass().getName();
//       
//        if (className.startsWith("org.openide.awt.MenuBar"))
//          {
//            return;
//          }
//            
//        if (component instanceof TopComponent) // refactor using className, --but include subclasses!--, drop import and module dependency
//          {
//            return;
//          }
//
//        logger.fine("Setting background on: %s", component);
//        component.setBackground(color);
//        
//        if (component instanceof Container)
//          {
//            for (final Component child : ((Container)component).getComponents())
//              {
//                setBackgroundRecursively(child, color);
//              }
//          }
//      }

    /***************************************************************************
     *
     *
     **************************************************************************/
//    private void dumpDefaults()
//      {
//        logger.info("UIDefaults: ");
//
//        for (final Object propName : new ArrayList(UIManager.getDefaults().keySet()))
//          {
//            final Object value = UIManager.getDefaults().get(propName);
//            logger.info(">>>> %s: %s", propName, value);
//          }
//      }
  }