package com.limegroup.gnutella.gui.menu; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FilenameFilter; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import javax.swing.ButtonGroup; import javax.swing.JMenuItem; import javax.swing.JRadioButtonMenuItem; import javax.swing.UIManager; import com.limegroup.gnutella.gui.GUIMediator; import com.limegroup.gnutella.gui.themes.ThemeMediator; import com.limegroup.gnutella.gui.themes.ThemeSettings; import com.limegroup.gnutella.util.CommonUtils; /** * The menu to be used for themes. */ final class ThemeMenu extends AbstractMenu { /** * The client property to use for theme changing items. */ private static final String THEME_PROPERTY = "THEME_NAME"; /** * The client property to use for theme changing when using 'other' L&Fs. */ private static final String THEME_CLASSNAME = "THEME_CLASSNAME"; /** * The listener for changing the theme. */ private static final ActionListener THEME_CHANGER = new ThemeChangeListener(); /** * The ButtonGroup to store the theme options in. */ private static final ButtonGroup GROUP = new ButtonGroup(); /** * Constructs the menu. */ ThemeMenu(String key) { super(key); addMenuItem("VIEW_THEMES_GET_MORE", new GetThemesListener()); addMenuItem("VIEW_THEMES_REFRESH", new RefreshThemesListener()); JMenuItem def = addMenuItem("VIEW_THEMES_USE_DEFAULT", THEME_CHANGER); final Object defaultVal = ThemeSettings.THEME_DEFAULT.getAbsolutePath(); def.putClientProperty(THEME_PROPERTY, defaultVal); // Add a listener to set the new theme as selected. def.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent ae) { setSelection(defaultVal); } }); addSeparator(); addThemeItems(); } /** * Sets the default theme. */ private static void setSelection(Object value) { Enumeration items = GROUP.getElements(); while(items.hasMoreElements()) { JMenuItem item = (JMenuItem)items.nextElement(); if(value.equals(item.getClientProperty(THEME_PROPERTY))) { item.setSelected(true); break; } } } /** * Scans through the theme directory for .lwtp files & adds them * as menu items to the menu. */ private void addThemeItems() { File themeDir = ThemeSettings.THEME_DIR_FILE; if(!themeDir.exists()) return; List allThemes = new LinkedList(Arrays.asList(themeDir.list(new ThemeFileFilter()))); addInstalledLFs(allThemes); Collections.sort(allThemes, new ThemeComparator()); if(allThemes.isEmpty()) return; String otherClassName = ThemeSettings.getOtherLF(); for(Iterator i = allThemes.iterator(); i.hasNext(); ) { Object next = i.next(); File themeFile; JMenuItem theme; if(next instanceof String) { themeFile = new File(themeDir, (String)next); theme = new JRadioButtonMenuItem(ThemeSettings.formatName(themeFile.getName())); if( themeFile.equals(ThemeSettings.THEME_FILE.getValue()) ) theme.setSelected(true); } else { themeFile = new File(themeDir, ThemeSettings.OTHER_THEME_NAME); UIManager.LookAndFeelInfo lfi = (UIManager.LookAndFeelInfo)next; theme = new JRadioButtonMenuItem(lfi.getName()); if( themeFile.equals(ThemeSettings.THEME_FILE.getValue()) && otherClassName != null && lfi.getClassName().equals(otherClassName) ) theme.setSelected(true); theme.putClientProperty(THEME_CLASSNAME, lfi.getClassName()); } theme.setFont(AbstractMenu.FONT); GROUP.add(theme); theme.addActionListener(THEME_CHANGER); theme.putClientProperty(THEME_PROPERTY, themeFile.getAbsolutePath()); MENU.add(theme); } } /** * Removes all items in the group from the menu. Used for refreshing. */ private void removeThemeItems() { Enumeration items = GROUP.getElements(); List removed = new LinkedList(); while(items.hasMoreElements()) { JMenuItem item = (JMenuItem)items.nextElement(); MENU.remove(item); removed.add(item); } for(Iterator itr = removed.iterator(); itr.hasNext();) GROUP.remove((JMenuItem)itr.next()); } /** * Opens the themes page in the default browser, displaying * an error message if the browser could not be launched * successfully. */ private static class GetThemesListener implements ActionListener { public void actionPerformed(ActionEvent e) { String url = "http://www.limewire.com/skins2"; GUIMediator.openURL(url); } } /** * Refreshes the theme menu options to those on the disk. */ private class RefreshThemesListener implements ActionListener { public void actionPerformed(ActionEvent e) { removeThemeItems(); addThemeItems(); } } /** * ActionListener to change the theme based on the client property. */ protected static class ThemeChangeListener implements ActionListener { public void actionPerformed(ActionEvent e) { JMenuItem item = (JMenuItem)e.getSource(); String themePath = (String)item.getClientProperty(THEME_PROPERTY); String className = (String)item.getClientProperty(THEME_CLASSNAME); ThemeMediator.changeTheme(new File(themePath), className); } } /** * Simple class to sort the theme lists. */ private static class ThemeComparator implements Comparator { public int compare(Object a, Object b) { String name1, name2; if(a instanceof String) name1 = ThemeSettings.formatName((String)a); else name1 = ((UIManager.LookAndFeelInfo)a).getName(); if(b instanceof String) name2 = ThemeSettings.formatName((String)b); else name2 = ((UIManager.LookAndFeelInfo)b).getName(); return name1.compareTo(name2); } } /** * Adds installed LFs to the list. */ private static void addInstalledLFs(List themes) { UIManager.LookAndFeelInfo[] lfs = UIManager.getInstalledLookAndFeels(); if(lfs == null) return; for(int i = 0; i < lfs.length; i++) { UIManager.LookAndFeelInfo l = lfs[i]; if(l.getClassName().equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel")) continue; if(l.getClassName().startsWith("apple")) continue; if(l.getClassName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel") && CommonUtils.isLinux() && CommonUtils.isJava15OrLater()) continue; if(l.getClassName().equals("com.sun.java.swing.plaf.motif.MotifLookAndFeel")) continue; themes.add(l); } } /** * <tt>FileNameFilter</tt> class for only displaying theme file types. */ public static class ThemeFileFilter implements FilenameFilter { public boolean accept(File dir, String name) { // don't allow anything that isn't a theme file if(!name.endsWith(ThemeSettings.EXTENSION)) return false; // if this is one of the old 'default_X' themes // we used to ship with, ignore it. if(name.startsWith("default_")) return false; // don't allow the 'other' theme to show. if(name.equals(ThemeSettings.OTHER_THEME_NAME)) return false; // only allow the osx theme if we're on osx. if(!CommonUtils.isMacOSX() && name.equals(ThemeSettings.PINSTRIPES_OSX_THEME_NAME)) return false; // only allow the brushed metal theme if we're on // osx with 10.3 if(name.equals(ThemeSettings.BRUSHED_METAL_OSX_THEME_NAME) && CommonUtils.isJaguarOrAbove()) return false; // only allow the windows theme if we're on windows. if(!CommonUtils.isWindows() && name.equals(ThemeSettings.WINDOWS_LAF_THEME_NAME)) return false; // only show pro theme if we're on pro. if(!CommonUtils.isPro() && name.equals(ThemeSettings.PRO_THEME_NAME)) return false; // only show GTK theme on linux with 1.5 if(name.equals(ThemeSettings.GTK_LAF_THEME_NAME) && (!CommonUtils.isLinux() || !CommonUtils.isJava15OrLater())) return false; // everything's okay -- allow it. return true; } } }