package org.jboss.seam.theme; import static org.jboss.seam.annotations.Install.BUILT_IN; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.MissingResourceException; import java.util.ResourceBundle; import javax.faces.component.UIViewRoot; import javax.faces.context.FacesContext; import javax.faces.event.ValueChangeEvent; import javax.faces.model.SelectItem; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Create; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.contexts.Contexts; import org.jboss.seam.core.Events; import org.jboss.seam.faces.Selector; import org.jboss.seam.core.Locale; import org.jboss.seam.international.Messages; import org.jboss.seam.log.LogProvider; import org.jboss.seam.log.Logging; import org.jboss.seam.navigation.Pages; import org.jboss.seam.util.IteratorEnumeration; /** * Selects the current user's theme * * @author Gavin King */ @Scope(ScopeType.SESSION) @Name("org.jboss.seam.theme.themeSelector") @BypassInterceptors @Install(precedence=BUILT_IN, classDependencies="javax.faces.context.FacesContext") public class ThemeSelector extends Selector { private static final long serialVersionUID = 3920407140011388341L; private static final LogProvider log = Logging.getLogProvider(ThemeSelector.class); private String theme; private String[] availableThemes; @Create public void initDefaultTheme() { String themeName = getCookieValueIfEnabled(); if ( themeName!=null && Arrays.asList(availableThemes).contains(themeName) ) { setTheme(themeName); } if (theme==null) { if (availableThemes==null || availableThemes.length==0) { throw new IllegalStateException("no themes defined"); } theme = availableThemes[0]; } } @Override protected String getCookieName() { return "org.jboss.seam.core.Theme"; } /** * Recreate the JSF view, using the new theme, and raise the * org.jboss.seam.themeSelected event * */ public void select() { Contexts.removeFromAllContexts("org.jboss.seam.theme.theme"); FacesContext facesContext = FacesContext.getCurrentInstance(); String viewId = Pages.getViewId(facesContext); UIViewRoot viewRoot = facesContext.getApplication().getViewHandler().createView(facesContext, viewId); facesContext.setViewRoot(viewRoot); setCookieValueIfEnabled( getTheme() ); if ( Events.exists() ) { Events.instance().raiseEvent( "org.jboss.seam.themeSelected", getTheme() ); } } public void select(ValueChangeEvent event) { selectTheme( (String) event.getNewValue() ); } public void selectTheme(String themeName) { setTheme(themeName); select(); } /** * Get a selectable list of available themes for display in the UI */ public List<SelectItem> getThemes() { List<SelectItem> selectItems = new ArrayList<SelectItem>(availableThemes.length); for ( String name: availableThemes ) { selectItems.add( new SelectItem( name, getLocalizedThemeName(name) ) ); } return selectItems; } /** * Get the name of the current theme */ public String getTheme() { return theme; } public void setTheme(String themeName) { setDirty(this.theme, themeName); this.theme = themeName; } public void setAvailableThemes(String[] themeNames) { setDirty(this.availableThemes, themeNames); this.availableThemes = themeNames; } /** * Get the resource bundle for the theme */ public ResourceBundle getThemeResourceBundle() { try { java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle( theme, Locale.instance(), Thread.currentThread().getContextClassLoader() ); log.trace("loaded resource bundle: " + theme); return bundle; } catch (MissingResourceException mre) { log.debug("resource bundle missing: " + theme); return new ResourceBundle() { @Override public Enumeration<String> getKeys() { return new IteratorEnumeration( Collections.EMPTY_LIST.iterator() ); } @Override protected Object handleGetObject(String key) { return null; } }; } } /** * Get the localized name of the named theme, by looking for * org.jboss.seam.theme.<name> in the Seam resource * bundle */ public String getLocalizedThemeName(String name) { String key = "org.jboss.seam.theme." + name; String localizedName = Messages.instance().get(key); return key.equals(localizedName) ? name : localizedName; } public static ThemeSelector instance() { if ( !Contexts.isSessionContextActive() ) { throw new IllegalStateException("No active session context"); } return (ThemeSelector) Component.getInstance(ThemeSelector.class, ScopeType.SESSION); } public String[] getAvailableThemes() { return availableThemes; } }