package esmska.gui;
import com.jgoodies.looks.plastic.PlasticLookAndFeel;
import com.jgoodies.looks.plastic.PlasticTheme;
import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;
import com.jgoodies.looks.plastic.theme.ExperienceBlue;
import javax.swing.JDialog;
import javax.swing.UIManager;
import esmska.data.Config;
import esmska.utils.RuntimeUtils;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.LookAndFeel;
import javax.swing.UIManager.LookAndFeelInfo;
import org.apache.commons.lang.ObjectUtils;
import org.pushingpixels.lafwidget.LafWidget;
import org.pushingpixels.substance.api.ColorSchemeAssociationKind;
import org.pushingpixels.substance.api.ComponentState;
import org.pushingpixels.substance.api.DecorationAreaType;
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.api.skin.BusinessBlackSteelSkin;
import org.pushingpixels.substance.api.skin.SkinInfo;
/** Manage and set look and feel
*
* @author ripper
*/
public class ThemeManager {
public enum LAF {
SYSTEM, CROSSPLATFORM, GTK, JGOODIES, SUBSTANCE
}
private static final Logger logger = Logger.getLogger(ThemeManager.class.getName());
private static LookAndFeelInfo[] installedLafs = UIManager.getInstalledLookAndFeels();
private static LAF activeLaf = LAF.CROSSPLATFORM;
//remember Mac UI for MenuBar from default l&f
private static final String macBarUI = UIManager.getString("MenuBarUI");
static {
//if Nimbus is available, let's replace Metal with it
setNimbusAsCrossplatformLAF();
}
/** Disabled constructor */
private ThemeManager() {
}
/** Set look and feel found in configuration. If it is not possible, use
* the next best one.
* Must be called on the EDT.
* @throws Throwable when chosen look and feel can't be set
*/
public static void setLaF() throws Throwable {
Config config = Config.getInstance();
ThemeManager.LAF laf = config.getLookAndFeel();
//if selected LaF is not supported, then use a suggested one
if (!isLaFSupported(laf)) {
LAF newLaf = suggestBestLAF();
logger.info("Look and feel '" + laf + "' is no longer supported on " +
"your system, selected a new one: " + newLaf);
laf = newLaf;
config.setLookAndFeel(laf);
}
//with most LaFs use system decorations
setLaFDecorated(false);
switch (laf) {
case SYSTEM:
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
activeLaf = LAF.SYSTEM;
break;
case CROSSPLATFORM:
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
activeLaf = LAF.CROSSPLATFORM;
break;
case GTK:
boolean found = false;
for (LookAndFeelInfo lafInfo : installedLafs) {
if ("GTK+".equals(lafInfo.getName())) {
UIManager.setLookAndFeel(lafInfo.getClassName());
found = true;
break;
}
}
if (!found) {
//GTK requested and supported, but now we can't find it among installed LAFs
throw new IllegalStateException("GTK LaF requested, but not found");
}
activeLaf = LAF.GTK;
break;
case JGOODIES:
String themeString = config.getLafJGoodiesTheme();
PlasticTheme theme = null;
for (Object o : PlasticLookAndFeel.getInstalledThemes()) {
PlasticTheme ptheme = (PlasticTheme) o;
if (ptheme.getName().equals(themeString)) {
theme = ptheme;
break;
}
}
PlasticLookAndFeel.setPlasticTheme(theme != null ? theme : new ExperienceBlue());
UIManager.setLookAndFeel(new PlasticXPLookAndFeel());
activeLaf = LAF.JGOODIES;
break;
case SUBSTANCE:
String skinString = config.getLafSubstanceSkin();
String skin = null;
for (SkinInfo skinInfo : SubstanceLookAndFeel.getAllSkins().values()) {
if (skinInfo.getDisplayName().equals(skinString)) {
skin = skinInfo.getClassName();
break;
}
}
SubstanceLookAndFeel.setSkin(skin != null ? skin : new BusinessBlackSteelSkin().getClass().getName());
//set Substance specific addons
UIManager.put(LafWidget.TEXT_EDIT_CONTEXT_MENU, Boolean.TRUE);
UIManager.put(SubstanceLookAndFeel.SHOW_EXTRA_WIDGETS, Boolean.TRUE);
//set LaF decorations
setLaFDecorated(true);
activeLaf = LAF.SUBSTANCE;
break;
default:
throw new IllegalArgumentException("Unknown LaF name");
}
//set MenuBar usage on Mac OS
if (RuntimeUtils.isMac() && macBarUI != null) {
logger.fine("Setting Mac OS MenuBar UI");
UIManager.put("MenuBarUI", macBarUI);
}
logger.fine("New LaF set: " + UIManager.getLookAndFeel());
}
/** Returns currently active look and feel */
public static LAF getActiveLaF() {
return activeLaf;
}
/** Returns whether GTK is current look and feel */
public static boolean isGTKCurrentLaF() {
LookAndFeel laf = UIManager.getLookAndFeel();
return ObjectUtils.equals(laf.getName(), "GTK look and feel");
}
/** Returns whether Aqua (Mac OS native) is current look and feel */
public static boolean isAquaCurrentLaF() {
LookAndFeel laf = UIManager.getLookAndFeel();
return ObjectUtils.equals(laf.getName(), "Mac OS X");
}
/** Returns whether Nimbus is current look and feel */
public static boolean isNimbusCurrentLaF() {
LookAndFeel laf = UIManager.getLookAndFeel();
return ObjectUtils.equals(laf.getName(), "Nimbus");
}
/** Returns whether Substance is current look and feel */
public static boolean isSubstanceCurrentLaF() {
LookAndFeel laf = UIManager.getLookAndFeel();
return laf.getName() != null && laf.getName().startsWith("Substance");
}
/** Returns whether current LaF skin is dark-toned,
* mainly in text-areas
*/
public static boolean isCurrentSkinDark() {
//currently only Substance skins are dark
return isSubstanceCurrentLaF() &&
SubstanceLookAndFeel.getCurrentSkin().getColorScheme(DecorationAreaType.GENERAL,
ColorSchemeAssociationKind.FILL, ComponentState.ENABLED).isDark();
}
/** Returns whether specified LaF is supported on current configuration
* (operating system, java version, etc).
*/
public static boolean isLaFSupported(LAF laf) {
switch (laf) {
case SYSTEM:
//if system and crossplatform classnames are equal, then
//there is no special "system" laf
return !UIManager.getSystemLookAndFeelClassName().equals(
UIManager.getCrossPlatformLookAndFeelClassName());
case CROSSPLATFORM:
//always supported
return true;
case GTK:
//only if installed
for (LookAndFeelInfo lafInfo : installedLafs) {
if ("GTK+".equals(lafInfo.getName())) {
//and if different from system laf, because in that
//case there is no reason to display it twice
return !lafInfo.getClassName().equals(
UIManager.getSystemLookAndFeelClassName());
}
}
return false;
case JGOODIES:
//always supported
return true;
case SUBSTANCE:
//always supported
return true;
default:
throw new IllegalArgumentException("Unknown LAF: " + laf);
}
}
/** Propose the best LaF for current system, based on java type and
* operating system. Useful for program first run.
* @return the best LaF for this platform
*/
public static LAF suggestBestLAF() {
LAF laf = LAF.SYSTEM;
//Windows users are used to fancy and inconsistent looks
//On other (Linux) systems Oracle Java is very bad in emulating system look
if (RuntimeUtils.isWindows() || RuntimeUtils.isOracleJava()) {
laf = LAF.SUBSTANCE;
}
//if the suggested LaF is not supported, suggest crossplatform LaF as a safe choice
if (!isLaFSupported(laf)) {
laf = LAF.CROSSPLATFORM;
}
logger.finer("Suggested LaF: " + laf);
return laf;
}
/** If Nimbus LaF is available (from Java 6 Update 10), set it as the
* default crossplatform LaF instead of Metal.
*/
private static void setNimbusAsCrossplatformLAF() {
for (LookAndFeelInfo lafInfo : installedLafs) {
if ("Nimbus".equals(lafInfo.getName())) {
System.setProperty("swing.crossplatformlaf", lafInfo.getClassName());
return;
}
}
}
/** Set if frame and dialogs should be decorated by current LaF or by system
*/
private static void setLaFDecorated(boolean decorated) {
JFrame.setDefaultLookAndFeelDecorated(decorated);
JDialog.setDefaultLookAndFeelDecorated(decorated);
}
}