1 /* 2 * aTunes 3 * Copyright (C) Alex Aranda, Sylvain Gaudard and contributors 4 * 5 * See http://www.atunes.org/wiki/index.php?title=Contributing for information about contributors 6 * 7 * http://www.atunes.org 8 * http://sourceforge.net/projects/atunes 9 * 10 * This program is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU General Public License 12 * as published by the Free Software Foundation; either version 2 13 * of the License, or (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 */ 20 21 package net.sourceforge.atunes.gui.lookandfeel; 22 23 import java.awt.Color; 24 import java.awt.Font; 25 import java.awt.Window; 26 import java.util.ArrayList; 27 import java.util.List; 28 import java.util.Map; 29 30 import javax.swing.BorderFactory; 31 import javax.swing.SwingUtilities; 32 import javax.swing.UIManager; 33 import javax.swing.plaf.ColorUIResource; 34 35 import net.sourceforge.atunes.gui.GuiUtils; 36 import net.sourceforge.atunes.model.FontSettings; 37 import net.sourceforge.atunes.model.IApplicationArguments; 38 import net.sourceforge.atunes.model.IBeanFactory; 39 import net.sourceforge.atunes.model.IFontBeanFactory; 40 import net.sourceforge.atunes.model.ILookAndFeel; 41 import net.sourceforge.atunes.model.ILookAndFeelChangeListener; 42 import net.sourceforge.atunes.model.ILookAndFeelManager; 43 import net.sourceforge.atunes.model.IOSManager; 44 import net.sourceforge.atunes.model.IStateCore; 45 import net.sourceforge.atunes.model.IStateUI; 46 import net.sourceforge.atunes.model.LookAndFeelBean; 47 import net.sourceforge.atunes.utils.Logger; 48 49 /** 50 * Responsible of change and manage look and feel 51 * 52 * @author alex 53 * 54 */ 55 public final class LookAndFeelManager implements 56 ILookAndFeelManager { 57 58 private static final boolean USE_FONT_SMOOTHING_SETTINGS_FROM_OS_DEFAULT_VALUE = false; 59 private static final boolean USE_FONT_SMOOTHING_DEFAULT_VALUE = true; 60 61 /** 62 * Current look and feel 63 */ 64 private ILookAndFeel currentLookAndFeel; 65 66 /** 67 * Map containing look and feels 68 */ 69 private Map<String, Class<? extends ILookAndFeel>> lookAndFeels; 70 71 /** 72 * Default look and feel 73 */ 74 private Class<? extends ILookAndFeel> defaultLookAndFeelClass; 75 76 /** 77 * Look and Feel change listeners 78 */ 79 private List<ILookAndFeelChangeListener> changeListeners; 80 81 private IApplicationArguments applicationArguments; 82 83 private IBeanFactory beanFactory; 84 85 private IOSManager osManager; 86 87 /** 88 * @param osManager 89 */ setOsManager(final IOSManager osManager)90 public void setOsManager(final IOSManager osManager) { 91 this.osManager = osManager; 92 } 93 94 /** 95 * @param beanFactory 96 */ setBeanFactory(final IBeanFactory beanFactory)97 public void setBeanFactory(final IBeanFactory beanFactory) { 98 this.beanFactory = beanFactory; 99 } 100 101 /** 102 * Initialize manager 103 */ initialize()104 public void initialize() { 105 this.lookAndFeels = this.osManager.getLookAndFeels(); 106 this.defaultLookAndFeelClass = this.osManager.getDefaultLookAndFeel(); 107 } 108 109 /** 110 * @param applicationArguments 111 */ setApplicationArguments( final IApplicationArguments applicationArguments)112 public void setApplicationArguments( 113 final IApplicationArguments applicationArguments) { 114 this.applicationArguments = applicationArguments; 115 } 116 117 @Override setLookAndFeel(final LookAndFeelBean bean, final IStateCore stateCore, final IStateUI stateUI, final IOSManager osManager)118 public void setLookAndFeel(final LookAndFeelBean bean, 119 final IStateCore stateCore, final IStateUI stateUI, 120 final IOSManager osManager) { 121 if (this.applicationArguments.isIgnoreLookAndFeel()) { 122 return; 123 } 124 125 LookAndFeelBean lookAndFeelBean = bean; 126 if (lookAndFeelBean == null || lookAndFeelBean.getName() == null) { 127 lookAndFeelBean = new LookAndFeelBean(); 128 ILookAndFeel defaultLookAndFeel = null; 129 try { 130 defaultLookAndFeel = this.defaultLookAndFeelClass.newInstance(); 131 } catch (InstantiationException e) { 132 Logger.error(e); 133 } catch (IllegalAccessException e) { 134 Logger.error(e); 135 } 136 lookAndFeelBean.setName(defaultLookAndFeel.getName()); 137 lookAndFeelBean.setSkin(defaultLookAndFeel.getDefaultSkin()); 138 if (stateUI.getLookAndFeel() == null) { 139 stateUI.setLookAndFeel(lookAndFeelBean); 140 } 141 } 142 143 Class<? extends ILookAndFeel> currentLookAndFeelClass = this.lookAndFeels 144 .get(lookAndFeelBean.getName()); 145 if (currentLookAndFeelClass == null) { 146 currentLookAndFeelClass = this.defaultLookAndFeelClass; 147 } 148 149 try { 150 this.currentLookAndFeel = currentLookAndFeelClass.newInstance(); 151 this.currentLookAndFeel.setOsManager(osManager); 152 this.currentLookAndFeel.setBeanFactory(this.beanFactory); 153 } catch (InstantiationException e) { 154 Logger.error(e); 155 } catch (IllegalAccessException e) { 156 Logger.error(e); 157 } 158 159 this.currentLookAndFeel.initializeLookAndFeel(this.beanFactory); 160 this.currentLookAndFeel.setLookAndFeel(lookAndFeelBean.getSkin()); 161 initializeFonts(this.currentLookAndFeel, stateCore, stateUI); 162 initializeColors(); 163 } 164 165 /** 166 * Color initialization for some ui components 167 */ initializeColors()168 private void initializeColors() { 169 UIManager.put("ToolTip.border", 170 BorderFactory.createLineBorder(GuiUtils.getBorderColor())); 171 UIManager.put("ToolTip.background", new ColorUIResource(Color.WHITE)); 172 UIManager.put("ToolTip.foreground", new ColorUIResource(Color.BLACK)); 173 } 174 175 /** 176 * Initializes fonts for look and feel 177 * 178 * @param lookAndFeel 179 * @param state 180 * @param stateUI 181 */ initializeFonts(final ILookAndFeel lookAndFeel, final IStateCore stateCore, final IStateUI stateUI)182 private void initializeFonts(final ILookAndFeel lookAndFeel, 183 final IStateCore stateCore, final IStateUI stateUI) { 184 FontSettings fontSettings = stateUI.getFontSettings(); 185 186 setAntialiasingProperties(lookAndFeel, fontSettings); 187 188 Font font = UIManager.getFont("Label.font"); 189 if (lookAndFeel.supportsCustomFontSettings()) { 190 if (fontSettings != null) { 191 font = fontSettings.getFont().toFont(); 192 } else { 193 font = getFontToUse(lookAndFeel, stateCore.getLocale() 194 .getLanguage()); 195 stateUI.setFontSettings(new FontSettings(this.beanFactory 196 .getBean(IFontBeanFactory.class).getFontBean(font), 197 USE_FONT_SMOOTHING_DEFAULT_VALUE, 198 USE_FONT_SMOOTHING_SETTINGS_FROM_OS_DEFAULT_VALUE)); 199 } 200 } 201 lookAndFeel.setBaseFont(font); 202 lookAndFeel.initializeFonts(font); 203 } 204 getFontToUse(final ILookAndFeel lookAndFeel, String language)205 private Font getFontToUse(final ILookAndFeel lookAndFeel, String language) { 206 /* 207 * Get appropriate font for the currently selected language. For Chinese 208 * or Japanese we should use default font. 209 */ 210 if ("zh".equals(language) || "ja".equals(language)) { 211 return new Font(Font.SANS_SERIF, Font.PLAIN, 12); 212 } else { 213 return lookAndFeel.getSuggestedFont(); 214 } 215 } 216 setAntialiasingProperties(final ILookAndFeel lookAndFeel, FontSettings fontSettings)217 private void setAntialiasingProperties(final ILookAndFeel lookAndFeel, 218 FontSettings fontSettings) { 219 if (lookAndFeel.supportsCustomFontSettings() && fontSettings != null 220 && !fontSettings.isUseFontSmoothingSettingsFromOs()) { 221 if (fontSettings.isUseFontSmoothing()) { 222 System.setProperty("awt.useSystemAAFontSettings", "lcd"); 223 } else { 224 System.setProperty("awt.useSystemAAFontSettings", "false"); 225 } 226 } else { 227 System.setProperty("awt.useSystemAAFontSettings", "lcd"); 228 } 229 } 230 231 @Override getAvailableLookAndFeels()232 public List<String> getAvailableLookAndFeels() { 233 return new ArrayList<String>(this.lookAndFeels.keySet()); 234 } 235 236 @Override getAvailableSkins(final String lookAndFeelName)237 public List<String> getAvailableSkins(final String lookAndFeelName) { 238 Class<? extends ILookAndFeel> clazz = this.lookAndFeels 239 .get(lookAndFeelName); 240 if (clazz != null) { 241 ILookAndFeel lookAndFeel = null; 242 try { 243 lookAndFeel = clazz.newInstance(); 244 } catch (InstantiationException e) { 245 Logger.error(e); 246 } catch (IllegalAccessException e) { 247 Logger.error(e); 248 } 249 if (lookAndFeel != null) { 250 return lookAndFeel.getSkins() != null ? lookAndFeel.getSkins() 251 : new ArrayList<String>(); 252 } 253 } 254 return new ArrayList<String>(); 255 } 256 257 @Override getCurrentLookAndFeelName()258 public String getCurrentLookAndFeelName() { 259 return this.currentLookAndFeel.getName(); 260 } 261 262 @Override applySkin(final String selectedSkin, final IStateCore stateCore, final IStateUI stateUI, final IOSManager osManager)263 public void applySkin(final String selectedSkin, 264 final IStateCore stateCore, final IStateUI stateUI, 265 final IOSManager osManager) { 266 LookAndFeelBean bean = new LookAndFeelBean(); 267 bean.setName(this.currentLookAndFeel.getName()); 268 bean.setSkin(selectedSkin); 269 setLookAndFeel(bean, stateCore, stateUI, osManager); 270 for (Window window : Window.getWindows()) { 271 // Only update displayable windows 272 // References to disposed windows (not displayable) are kept so 273 // calling to update those windows can throw exceptions or errors 274 if (window.isDisplayable()) { 275 SwingUtilities.updateComponentTreeUI(window); 276 } 277 } 278 // Notify listeners 279 for (ILookAndFeelChangeListener listener : getChangeListeners()) { 280 listener.lookAndFeelChanged(); 281 } 282 } 283 284 @Override getCurrentLookAndFeel()285 public ILookAndFeel getCurrentLookAndFeel() { 286 return this.currentLookAndFeel; 287 } 288 289 @Override getDefaultSkin(final String lookAndFeelName)290 public String getDefaultSkin(final String lookAndFeelName) { 291 Class<? extends ILookAndFeel> clazz = this.lookAndFeels 292 .get(lookAndFeelName); 293 if (clazz != null) { 294 ILookAndFeel lookAndFeel = null; 295 try { 296 lookAndFeel = clazz.newInstance(); 297 } catch (InstantiationException e) { 298 Logger.error(e); 299 } catch (IllegalAccessException e) { 300 Logger.error(e); 301 } 302 if (lookAndFeel != null) { 303 return lookAndFeel.getDefaultSkin(); 304 } 305 } 306 return null; 307 } 308 309 @Override getDefaultLookAndFeel()310 public ILookAndFeel getDefaultLookAndFeel() { 311 try { 312 return this.defaultLookAndFeelClass.newInstance(); 313 } catch (InstantiationException e) { 314 Logger.error(e); 315 } catch (IllegalAccessException e) { 316 Logger.error(e); 317 } 318 return null; 319 } 320 321 /** 322 * @return the changeListeners 323 */ getChangeListeners()324 protected List<ILookAndFeelChangeListener> getChangeListeners() { 325 if (this.changeListeners == null) { 326 this.changeListeners = new ArrayList<ILookAndFeelChangeListener>(); 327 } 328 return this.changeListeners; 329 } 330 331 @Override addLookAndFeelChangeListener( final ILookAndFeelChangeListener listener)332 public void addLookAndFeelChangeListener( 333 final ILookAndFeelChangeListener listener) { 334 getChangeListeners().add(listener); 335 } 336 337 @Override removeLookAndFeelChangeListener( final ILookAndFeelChangeListener listener)338 public void removeLookAndFeelChangeListener( 339 final ILookAndFeelChangeListener listener) { 340 getChangeListeners().remove(listener); 341 } 342 } 343