You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by jw...@apache.org on 2008/03/11 17:42:42 UTC

svn commit: r636000 - in /myfaces/trinidad/trunk: src/site/xdoc/ src/site/xdoc/devguide/ trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/ trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/ trinidad-impl/src/main/java/org/...

Author: jwaldman
Date: Tue Mar 11 09:42:25 2008
New Revision: 636000

URL: http://svn.apache.org/viewvc?rev=636000&view=rev
Log:
TRINIDAD-472 @agent support for icons
on trunk

Added:
    myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/collapsed.gif   (with props)
    myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/expanded.gif   (with props)
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/DocumentProviderSkin.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/RequestSkinWrapper.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/IconNode.java
Removed:
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/parse/IconNode.java
Modified:
    myfaces/trinidad/trunk/src/site/xdoc/devguide/skinning.xml
    myfaces/trinidad/trunk/src/site/xdoc/release-notes.xml
    myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/purpleSkin.css
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinFactoryImpl.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinImpl.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleProvider.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleSheetParserUtils.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/StyleSheetEntry.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/icon/NullIcon.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleProvider.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetDocument.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNode.java
    myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeParser.java
    myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeEqualsTest.java

Modified: myfaces/trinidad/trunk/src/site/xdoc/devguide/skinning.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/src/site/xdoc/devguide/skinning.xml?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/src/site/xdoc/devguide/skinning.xml (original)
+++ myfaces/trinidad/trunk/src/site/xdoc/devguide/skinning.xml Tue Mar 11 09:42:25 2008
@@ -152,7 +152,7 @@
             <li>By default you'll need to restart your server to see your skin changes. To see your changes
             without restarting your server, set the web.xml parameter 
             'org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION' to true. However, you always need to restart the
-            server to see icon and skin property changes.</li>
+            server to see skin property changes.</li>
             <li>Run your component to see the changes. NOTE: A frequently asked question is why
                 don't I see my skin? The most frequently correct answer is that you forgot to add
                 &lt;tr:document&gt; to your page. This kicks off the skin framework to create the
@@ -358,7 +358,7 @@
 You can run the panelBox demo with your skin-family set to see the change. 
 If you have 'org.apache.myfaces.trinidad.CHECK_FILE_MODIFICATION' set to true, there is no need to restart the server to see
 css property changes .You can just refresh your page and the skinning framework will detect the skin has changed 
-and will regenerate it. To see icon or skin property changes, you always have to restart the server.
+and will regenerate it. To see skin property changes, you always have to restart the server.
 
 
 Now you have this:
@@ -717,13 +717,13 @@
         <ul>
         <li>
         <strong>@platform</strong> {/skin definitions go here/} - > 
-        Possible values are: windows, macos, linux, solaris, ppc (DOES NOT WORK FOR ICONS). 
+        Possible values are: windows, macos, linux, solaris, ppc. 
         This is to define styles only for a particular platform.
         </li>
         <li>
         <strong>@agent</strong> {/skin definitions go here/} - > 
-        Possible values are: netscape, ie, mozilla, gecko, webkit (maps to safari), ice 
-        (DOES NOT WORK FOR ICONS). This is to define styles only for a particular agent.          
+        Possible values are: netscape, ie, mozilla, gecko, webkit (maps to safari), ice. 
+        This is to define styles only for a particular agent.          
         </li>
         <li>
         <strong>:rtl</strong> - >  pseudo-class to create a style or icon definition when the browser 

Modified: myfaces/trinidad/trunk/src/site/xdoc/release-notes.xml
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/src/site/xdoc/release-notes.xml?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/src/site/xdoc/release-notes.xml (original)
+++ myfaces/trinidad/trunk/src/site/xdoc/release-notes.xml Tue Mar 11 09:42:25 2008
@@ -60,6 +60,8 @@
 
 <subsection name="Changes from previous release">
 <ul>
+<li>In previous releases, @agent/@platform constrains in skin definitions were not applied to icons.  That is, icons which appeared within @agent/@platform objects were registered globally and were not constrained to any particular agent/platform.  This is no longer the case.  @agent/@platform constraints are now honored for both styles and icons, making it possible to define agent/platform-specific icons.
+</li>
 <li>In previous releases, when you change a skinning css file, the change is reflected 
 in the running application on refresh. To aid in performance, this is now a configuration
 option that defaults to false -- do not check for css file modifications.

Added: myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/collapsed.gif
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/collapsed.gif?rev=636000&view=auto
==============================================================================
Binary file - no diff available.

Propchange: myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/collapsed.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/expanded.gif
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/expanded.gif?rev=636000&view=auto
==============================================================================
Binary file - no diff available.

Propchange: myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/images/expanded.gif
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/purpleSkin.css
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/purpleSkin.css?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/purpleSkin.css (original)
+++ myfaces/trinidad/trunk/trinidad-examples/trinidad-demo/src/main/webapp/skins/purple/purpleSkin.css Tue Mar 11 09:42:25 2008
@@ -616,13 +616,23 @@
 @agent gecko {
 af|column::sortable-header-text {
     border-style: solid;
-}  
+}
+
+  af|tree::collapsed-icon {
+    content:url(/skins/purple/images/collapsed.gif);
+    width:18px;
+    height:19px    
+  }
+
+  af|tree::expanded-icon {
+    content:url(/skins/purple/images/expanded.gif);
+    width:18px;
+    height:19px    
+  }
 }
 
 
 /* test @agent and @platform styles */
-/* right now @agent/@platform work with style selectors, but they have no
-   effect on icon selectors. */
 /* possible values for @agent are: 
 netscape, ie, mozilla, gecko, webkit, ice */
 /* possible values for @platform are: 
@@ -879,4 +889,4 @@
 
 af|tree {
   -tr-show-lines:false;
-}
\ No newline at end of file
+}

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/StyleContextImpl.java Tue Mar 11 09:42:25 2008
@@ -20,6 +20,8 @@
 
 import java.util.Map;
 
+import java.util.concurrent.ConcurrentMap;
+
 import javax.faces.context.FacesContext;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
@@ -28,6 +30,7 @@
 import org.apache.myfaces.trinidad.context.RenderingContext;
 import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.HtmlRenderer;
 import org.apache.myfaces.trinidad.context.LocaleContext;
+import org.apache.myfaces.trinidad.skin.Icon;
 import org.apache.myfaces.trinidad.skin.Skin;
 import org.apache.myfaces.trinidadinternal.share.config.Configuration;
 import org.apache.myfaces.trinidadinternal.skin.SkinStyleProvider;
@@ -145,6 +148,11 @@
     }
 
     public StyleMap getStyleMap(StyleContext context)
+    {
+      return null;
+    }
+
+    public ConcurrentMap<String, Icon> getIcons(StyleContext context)
     {
       return null;
     }

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/DocumentProviderSkin.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/DocumentProviderSkin.java?rev=636000&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/DocumentProviderSkin.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/DocumentProviderSkin.java Tue Mar 11 09:42:25 2008
@@ -0,0 +1,40 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ */
+package org.apache.myfaces.trinidadinternal.skin;
+
+import org.apache.myfaces.trinidadinternal.style.StyleContext;
+
+import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetDocument;
+
+/**
+ * Some Skin consumers need access to the StyleSheetDocument.  However,
+ * the public Skin API cannot provide access to the StyleSheetDocument,
+ * since this is not part of the public API.  This little interface is
+ * provided so that internal Skin consumers (such as SkinStyleProvider)
+ * can get access to the StyleSheetDocument without casting to a particular
+ * Skin implementation.
+ * 
+ */
+public interface DocumentProviderSkin
+{
+  /**
+   * Returns the StyleSheetDocument for the specified context.
+   */
+  public StyleSheetDocument getStyleSheetDocument(StyleContext styleContext);
+}

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/RequestSkinWrapper.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/RequestSkinWrapper.java?rev=636000&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/RequestSkinWrapper.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/RequestSkinWrapper.java Tue Mar 11 09:42:25 2008
@@ -0,0 +1,328 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ */
+
+package org.apache.myfaces.trinidadinternal.skin;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.MissingResourceException;
+
+import org.apache.myfaces.trinidad.context.LocaleContext;
+import org.apache.myfaces.trinidad.context.RenderingContext;
+import org.apache.myfaces.trinidad.skin.Icon;
+import org.apache.myfaces.trinidad.skin.Skin;
+import org.apache.myfaces.trinidad.skin.SkinAddition;
+import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderingContext;
+import org.apache.myfaces.trinidadinternal.skin.icon.NullIcon;
+import org.apache.myfaces.trinidadinternal.style.StyleContext;
+import org.apache.myfaces.trinidadinternal.style.StyleProvider;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetDocument;
+
+/**
+ * This is a Skin decorator which is used to store request-specific
+ * skin state.  In particular, the set of icons to use varies from
+ * request to request, eg. based on the browser/platform.  We cannot
+ * store such request-specific state on our shared Skin instances.
+ * Instead, SkinFactoryImpl wraps shared Skin instances in RequestSkinWrappers
+ * so that request-specific state can be stored locally in the wrapper.
+ * 
+ * At the moment, the only piece of request-specific state is that 
+ * icon map, which is retrieved from the StyleProvider one time per
+ * request and stored here.
+ */
+public class RequestSkinWrapper extends Skin implements DocumentProviderSkin
+{
+  // An alternate implementation strategy would be to enhance SkinImpl.getIcon()
+  // to serve up the request/context-specific Icons directly, rather than do so
+  // via a wrapper Skin class.  There are two issues with the SkinImpl-based
+  // solution:
+  // 
+  // 1. SkinImpl.getIcon() needs access to the StyleContext in order to retrieve
+  // the request/context-specific Icon map.  However, Skin.getIcon() does not 
+  // get take a StyleContext.  We could change the Skin.getIcon() API to take
+  // a StyleContext, but since this is a public API we would prefer a solution
+  // which does not involve an API change.  Alternatively, SkinImpl.getIcon()
+  // could get at the StyleContext by retrieving the RenderingContext, casting 
+  // to CoreRenderingContext, and calling CoreRenderingContext.getStyleContext().
+  // However, that adds overhead to the SkinImpl.getIcon() implementation
+  // (mainly just a ThreadLocal look up, which isn't the end of the world, 
+  // but nonetheless would prefer to avoid if possible).
+  // 
+  // 2. Calls to registerIcon() need to behave differently depending on whether
+  // the Icon is being registered at Skin initialization time, or at 
+  // request-time.
+  //
+  // At Skin initialization time, we simply want to register the Icon on the
+  // Skin instance itself, since such Icons are global to the Skin.  However,
+  // we also use registerIcon() to register request-specific icon - for example,
+  // see CoreRenderingContext.getIcon()'s handling of rtl icons.  We cannot 
+  // register these request-specific Icons on the Skin as the Skin is reused
+  // across requests.  Instead we want to register request-specific Icons on
+  // the request-specific Icon map.
+  // 
+  // In order to deal with #2, we could have SkinImpl behave differently 
+  // depending on whether it is at initialization time or request time.  However,
+  // this is awkward and more cleanly solved via the request-specific wrapper 
+  // approach.
+
+  public RequestSkinWrapper(Skin wrappedSkin)
+  {
+    _skin = wrappedSkin;
+  }
+
+  /**
+   * Returns the Skin that is wrapped by this request-specific
+   * wrapper skin.
+   */
+  public Skin getWrappedSkin()
+  {
+    return _skin;
+  }
+
+  @Override
+  public String getId()
+  {
+    return _skin.getId();
+  }
+
+  @Override
+  public String getFamily()
+  {
+    return _skin.getFamily();
+  }
+
+  @Override
+  public String getRenderKitId()
+  {
+    return _skin.getRenderKitId();
+  }
+
+  @Override  
+  public String getStyleSheetDocumentId(RenderingContext arc)
+  {
+    return _skin.getStyleSheetDocumentId(arc);
+  }
+
+  @Override  
+  public Map<String, String> getStyleClassMap(RenderingContext arc)
+  {
+    return _skin.getStyleClassMap(arc);
+  }
+
+  @Override  
+  public String getStyleSheetName()
+  {
+    return _skin.getStyleSheetName();
+  }
+
+  @Override  
+  public String getTranslatedString(
+    LocaleContext lContext,
+    String        key
+    ) throws MissingResourceException
+  {
+    return _skin.getTranslatedString(lContext, key);
+  }
+
+  @Override  
+  public Object getTranslatedValue(
+    LocaleContext lContext,
+    String        key
+    ) throws MissingResourceException
+  {
+    return _skin.getTranslatedValue(lContext, key);
+  }
+
+  @Override  
+  public Icon getIcon(String  iconName)
+  {
+    return this.getIcon(iconName, true);
+  }
+
+  @Override  
+  public Icon getIcon(
+    String  iconName,
+    boolean resolveIcon)
+  {
+    // We look for the icon in two places:
+    //
+    // 1. In the the icon map provided by the StyleProvider.
+    //    The StyleProvider serves up icons that are 
+    //    specific to this particular request, including
+    //    agent-specific icons.
+    // 2. In the wrapped Skin instance.  Any Icons that are
+    //    manually registered via a call to registerIcon()
+    //    will be stored in the wrapped skin.
+  
+    // Note: no synchronization needed since we are in a
+    // a request-specific object.
+    Map<String, Icon> icons = _getRequestIcons();
+    assert(icons != null);
+
+    Icon icon = icons.get(iconName);
+    
+    if (icon == null)
+    {  
+      icon = _skin.getIcon(iconName, resolveIcon);
+      
+      // We ended up having to do two lookups for icons
+      // which are not available in the StyleProvider
+      // icon map.  To avoid having to do two lookups
+      // the next time this icon is requested, we promote
+      // the icon up from the wrapped skin into the
+      // StyleProvider icon map.
+      //
+      // resolveIcon should always be true here, but just
+      // to be totally safe, avoid caching unresolved icons
+      if (resolveIcon)
+        registerIcon(iconName, icon);
+    }
+
+    return (icon == _NULL_ICON) ? null : icon;
+  }
+
+  @Override  
+  public Object getProperty(Object key)
+  {
+    return _skin.getProperty(key);
+  }
+
+  @Override  
+  public void setProperty(
+    Object key,
+    Object value)
+  {
+    _skin.setProperty(key, value);
+  }
+
+  @Override  
+  public void registerIcon(
+    String  iconName,
+    Icon    icon)
+  {
+    // registerIcon() is called on a RequestSkinWrapper
+    // in two cases:
+    //
+    // 1. CoreRenderingContext.getIcon() contains special handling
+    // for icons when the reading direction is right-to-left.  If a
+    // rtl variant of the icon is not available, CoreRenderingContext
+    // will look up the non-directional version of the icon and register
+    // that under the rtl name to avoid repeated lookups.
+    //
+    // 2. RequestSkingWrapper.getIcon() calls registerIcon() to register
+    // icons which were not found in the StyleProvider's icon map.  This
+    // also is done as a performance optimization - to repeatedly looking
+    // up icons first in the StyleProvider icon map and then in the 
+    // wrapped skin.
+    //
+    // In both of these cases storing the missing icon in the StyleProvider
+    // icon map is safe/appropriate, since lookups with the same set of
+    // StyleContext properties would return the same results.  By storing
+    // the result in the StyleProvider icon map, we short-circuit, avoiding
+    // redundant work.
+    
+    Map<String, Icon> icons = _getRequestIcons();
+    if (icons != _NULL_ICONS)
+      icons.put(iconName, (icon == null) ? _NULL_ICON : icon);
+  }
+
+  @Override  
+  public void registerStyleSheet(
+    String styleSheetName
+    )
+  {
+    _skin.registerStyleSheet(styleSheetName);
+  }
+    
+  @Override  
+  public void addSkinAddition (
+    SkinAddition skinAddition
+    )
+  {
+    _skin.addSkinAddition(skinAddition);
+  }
+    
+  @Override  
+  public List<SkinAddition> getSkinAdditions ()
+  {
+    return _skin.getSkinAdditions();
+  }
+
+  /**
+   * Implementation of DocumentProviderSkin.getStyleSheetDocument().
+   */
+  public StyleSheetDocument getStyleSheetDocument(StyleContext styleContext)
+  {
+    // If getStyleSheetDocument() is being called on us, this implies
+    // that the wrapped Skin must also be a DocumentProviderSkin.
+    assert(_skin instanceof DocumentProviderSkin);
+    
+    return ((DocumentProviderSkin)_skin).getStyleSheetDocument(styleContext);
+  }
+
+  // Returns request-specific map of icon names to Icons
+  private Map<String, Icon> _getRequestIcons()
+  {
+    if (_icons == null)
+    {
+      // We get to the request-specific icons via the
+      // StyleProvider.  We need a CoreRenderingContext
+      // instance to get at the StyleProvider.  This
+      // implementation assumes that the RenderingContext
+      // is going to be an instanceof CoreRenderingContext.
+      // This is a pretty good bet, since the only
+      // RenderingContext provided by Trinidad is
+      // CoreRenderingContext, and given the complexity of
+      // the CoreRenderingContext implementation, it seems
+      // unlikely that anyone would attempt to replace the
+     // implementation.
+      RenderingContext rc = RenderingContext.getCurrentInstance();
+      assert(rc instanceof CoreRenderingContext);
+      
+      CoreRenderingContext crc = (CoreRenderingContext)rc;
+      StyleContext styleContext = crc.getStyleContext();
+      StyleProvider styleProvider = styleContext.getStyleProvider();
+      _icons = styleProvider.getIcons(styleContext);
+      
+      // Under normal circumstances, the StyleProvider will return
+      // a non-null, modifiable map.  If the skin/style subsystem
+      // has failed to initialize, however, the map may be null.
+      // Substitute an empty map so we don't need to check for null
+      // later.
+      if (_icons == null)
+        _icons = _NULL_ICONS;
+    }
+
+    return _icons;
+  }
+
+  // The wrapped skin 
+  private final Skin _skin;
+
+  // The icon map specific to this request as served
+  // up by the StyleProvider.
+  private Map<String, Icon> _icons;
+  
+  // Marker used to cache nulls.
+  private static final Icon _NULL_ICON = new NullIcon();
+  
+  // Empty map used when StyleProvider.getIcons() fails;
+  private static final Map<String, Icon> _NULL_ICONS = Collections.emptyMap();
+}

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinFactoryImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinFactoryImpl.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinFactoryImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinFactoryImpl.java Tue Mar 11 09:42:25 2008
@@ -124,6 +124,7 @@
 
     // loop through each skin in the SkinFactory
     // and see if the family and the renderKitId match
+    Skin matchingSkin = null;
 
     for(Skin skin : _skins.values())
     {
@@ -131,28 +132,36 @@
           renderKitId.equalsIgnoreCase(skin.getRenderKitId()))
       {
         // exact family+renderKitId match!
-        return skin;
+        matchingSkin = skin;
+        break;
       }
     }
 
-    // if we get here, that means we couldn't find an exact
-    // family/renderKitId match, so return the simple skin
-    // that matches the renderkitid.
-     if (_LOG.isWarning())
-     {
-       _LOG.warning("CANNOT_FIND_MATCHING_SKIN", new Object[]{family, renderKitId});
-     }
+    if (matchingSkin == null)
+    {
+      // if we get here, that means we couldn't find an exact
+      // family/renderKitId match, so return the simple skin
+      // that matches the renderkitid.
+       if (_LOG.isWarning())
+       {
+         _LOG.warning("CANNOT_FIND_MATCHING_SKIN", new Object[]{family, renderKitId});
+       }
+
+      // if we get here, that means we couldn't find an exact
+      // family/renderKitId match, so return the simple skin
+      // that matches the renderkitid.
 
-    // if we get here, that means we couldn't find an exact
-    // family/renderKitId match, so return the simple skin
-    // that matches the renderkitid.
-    if (renderKitId.equals(XhtmlConstants.APACHE_TRINIDAD_PORTLET))
-      return getSkin(context, _SIMPLE_PORTLET);
-    else if (renderKitId.equals(XhtmlConstants.APACHE_TRINIDAD_PDA))
-      return getSkin(context, _SIMPLE_PDA);
-    else
-      return getSkin(context, _SIMPLE_DESKTOP);
+      if (renderKitId.equals(XhtmlConstants.APACHE_TRINIDAD_PORTLET))
+        matchingSkin = getSkin(context, _SIMPLE_PORTLET);
+      else if (renderKitId.equals(XhtmlConstants.APACHE_TRINIDAD_PDA))
+        matchingSkin = getSkin(context, _SIMPLE_PDA);
+      else
+        matchingSkin = getSkin(context, _SIMPLE_DESKTOP);
+    }
 
+    // If we've got a matching skin, wrap it in a RequestSkinWrapper 
+    // to provide access to request-specific state.
+    return (matchingSkin == null) ? null : new RequestSkinWrapper(matchingSkin);
   }
 
   @Override

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinImpl.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinImpl.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinImpl.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinImpl.java Tue Mar 11 09:42:25 2008
@@ -52,7 +52,6 @@
 import org.apache.myfaces.trinidadinternal.share.config.Configuration;
 import org.apache.myfaces.trinidadinternal.share.expl.Coercions;
 import org.apache.myfaces.trinidadinternal.skin.icon.ReferenceIcon;
-import org.apache.myfaces.trinidadinternal.skin.parse.IconNode;
 import org.apache.myfaces.trinidadinternal.skin.parse.SkinPropertyNode;
 import org.apache.myfaces.trinidadinternal.style.StyleContext;
 import org.apache.myfaces.trinidadinternal.style.StyleProvider;
@@ -71,7 +70,7 @@
  *
  * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/skin/Skin.java#0 $) $Date: 10-nov-2005.18:58:54 $
  */
-abstract public class SkinImpl extends Skin
+abstract public class SkinImpl extends Skin implements DocumentProviderSkin
 {
 
   /**
@@ -569,23 +568,13 @@
     return modified;
   }
 
-  private void _registerIconsAndPropertiesFromStyleSheetEntry(
+  private void _registerPropertiesFromStyleSheetEntry(
     StyleSheetEntry entry)
   {
-    // register the icons and properties if there are any.
+    // register the properties if there are any.
     // get a List of IconNodes, and register them.
     if (entry != null)
     {
-      // register icons
-      List<IconNode> icons = entry.getIcons();
-      if (icons != null)
-      {
-        for(IconNode iconNode : icons)
-        {
-          registerIcon(iconNode.getIconName(), iconNode.getIcon());
-        }
-      }
-
       // register properties
       List<SkinPropertyNode> skinProperties = entry.getSkinProperties();
 
@@ -641,7 +630,7 @@
       if (styleSheetName != null)
       {
         _skinStyleSheet = StyleSheetEntry.createEntry(context, styleSheetName);
-        _registerIconsAndPropertiesFromStyleSheetEntry(_skinStyleSheet);
+        _registerPropertiesFromStyleSheetEntry(_skinStyleSheet);
       }
 
       // Now create entries for skin-addition-specific style sheets.
@@ -666,7 +655,7 @@
         {
           // add the icons and properties that are in the
           // skin-addition's StyleSheetEntry
-           _registerIconsAndPropertiesFromStyleSheetEntry(entry);
+           _registerPropertiesFromStyleSheetEntry(entry);
 
           // now merge the css properties
           StyleSheetDocument additionDocument = entry.getDocument();

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleProvider.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleProvider.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleProvider.java Tue Mar 11 09:42:25 2008
@@ -69,6 +69,13 @@
       throw new IllegalArgumentException(_LOG.getMessage(
         "NO_SKIN_SPECIFIED"));
 
+    // If the skin is actually one of our request-specific wrapper
+    // skins, rip off the wrapper and look up the StyleProvider
+    // for the wrapped skin.  If we don't do this, we end up creating
+    // a new StyleProvider for every request.
+    if (skin instanceof RequestSkinWrapper)
+      skin = ((RequestSkinWrapper)skin).getWrappedSkin();
+
     // Create the key object that we use to look up our
     // shared SkinStyleProvider instance
     ProviderKey key = new ProviderKey(skin, 
@@ -149,7 +156,8 @@
     synchronized (this)
     {
       // gets the skin's StyleSheetDocument (it creates it if needed)
-      skinDocument = _skinDocument = ((SkinImpl) _skin).getStyleSheetDocument(context);
+      skinDocument = _skinDocument = 
+        ((DocumentProviderSkin) _skin).getStyleSheetDocument(context);
     }
 
 
@@ -174,7 +182,8 @@
     // Synchronize access to _skinDocument
     synchronized (this)
     {
-      return (_skinDocument != ((SkinImpl) _skin).getStyleSheetDocument(context));
+      return (_skinDocument != 
+              ((DocumentProviderSkin) _skin).getStyleSheetDocument(context));
     }
   }
 

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleSheetParserUtils.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleSheetParserUtils.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleSheetParserUtils.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/SkinStyleSheetParserUtils.java Tue Mar 11 09:42:25 2008
@@ -45,6 +45,7 @@
 import org.apache.myfaces.trinidadinternal.share.xml.XMLUtils;
 
 import org.apache.myfaces.trinidadinternal.style.CSSStyle;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.IconNode;
 import org.apache.myfaces.trinidadinternal.style.xml.parse.IncludeStyleNode;
 import org.apache.myfaces.trinidadinternal.style.xml.parse.PropertyNode;
 import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleNode;
@@ -54,7 +55,6 @@
 import org.apache.myfaces.trinidadinternal.skin.icon.NullIcon;
 import org.apache.myfaces.trinidadinternal.skin.icon.TextIcon;
 import org.apache.myfaces.trinidadinternal.skin.icon.URIImageIcon;
-import org.apache.myfaces.trinidadinternal.skin.parse.IconNode;
 import org.apache.myfaces.trinidadinternal.skin.parse.SkinPropertyNode;
 import org.apache.myfaces.trinidadinternal.style.util.CSSUtils;
 import org.apache.myfaces.trinidadinternal.style.util.StyleUtils;
@@ -186,7 +186,6 @@
     // styleNodeList. Also, build one iconNodeList and one skinPropertyNodeList.
     
     // initialize
-    List<IconNode> iconNodeList = new ArrayList<IconNode>();
     List<SkinPropertyNode> skinPropertyNodeList = new ArrayList<SkinPropertyNode>();
     List<StyleSheetNode> ssNodeList = new ArrayList<StyleSheetNode>();
     String baseSourceURI = CSSUtils.getBaseSkinStyleSheetURI(sourceName);
@@ -201,6 +200,7 @@
      
       // initialize
       List <StyleNode> styleNodeList = new ArrayList<StyleNode>();
+      List<IconNode> iconNodeList = new ArrayList<IconNode>();
   
       for (SkinSelectorPropertiesNode cssSelector : selectorNodeList) 
       {
@@ -244,25 +244,6 @@
                           resolvedProperties.isTrTextAntialias(),
                           styleNodeList);           
           }
-          
-          
-          // log warning if the icon is defined within an @agent or @platform
-          // block that tells the user that this icon will be used 
-          // for all agents and platforms.
-          // TODO add agent and platform support for icons.
-          // This means that if an icon is defined within the @agent and/or
-          // the @platform keys, then that icon should be rendered when
-          // the rendering context matches the agent/platform.
-          if (skinSSNode.getAgents() != null ||
-              skinSSNode.getPlatforms() != null)
-          {
-            _LOG.warning("Icon '" +
-                         selectorName +
-                         "' is defined for agents and/or platforms in the skinning file." +
-                         " However that feature is not implemented yet for icons, only styles. "+ " " +
-                         "Therefore, this icon will be used " +
-                         "regardless of the request's agent or platform.");
-          }
         }
         else
         {
@@ -277,7 +258,7 @@
         }
       }
       
-      if (styleNodeList.size() > 0)
+      if ((styleNodeList.size() > 0) || (iconNodeList.size() > 0))
       {
         // we need to deal with the styleNodeList by building a StyleSheetNode
         // with this information.
@@ -285,6 +266,7 @@
         StyleNode[] styleNodeArray = styleNodeList.toArray(new StyleNode[0]);
         StyleSheetNode ssNode = 
           new StyleSheetNode(styleNodeArray,
+                             iconNodeList,
                              null,/*locales, not yet supported*/
                              skinSSNode.getDirection(),
                              skinSSNode.getAgents(),
@@ -303,7 +285,6 @@
 
     return new StyleSheetEntry(sourceName,
                                ssDocument,
-                               iconNodeList,
                                skinPropertyNodeList);
 
 

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/StyleSheetEntry.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/StyleSheetEntry.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/StyleSheetEntry.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/StyleSheetEntry.java Tue Mar 11 09:42:25 2008
@@ -30,7 +30,6 @@
 import org.apache.myfaces.trinidadinternal.share.xml.ParseContextImpl;
 import org.apache.myfaces.trinidadinternal.share.xml.XMLProvider;
 
-import org.apache.myfaces.trinidadinternal.skin.parse.IconNode;
 import org.apache.myfaces.trinidadinternal.skin.parse.SkinPropertyNode;
 
 import org.apache.myfaces.trinidadinternal.style.StyleContext;
@@ -83,7 +82,6 @@
       if (context.checkStylesModified())
         return new CheckModifiedEntry(styleSheetName,
                                       skinStyleSheet.getDocument(),
-                                      skinStyleSheet.getIcons(),
                                       skinStyleSheet.getSkinProperties(),
                                       resolver);
 
@@ -101,21 +99,19 @@
   StyleSheetEntry(
     String                 styleSheetName,
     StyleSheetDocument     document,
-    List<IconNode>         icons,
     List<SkinPropertyNode> skinProperties
 
     )
   {
     _name       = styleSheetName;
     _document   = document;
-    _icons      = icons;
     _skinProperties = skinProperties;
 
   }
 
   StyleSheetEntry(String styleSheetName)
   {
-    this(styleSheetName, null, null, null);
+    this(styleSheetName, null, null);
   }
 
   // Use full constructor
@@ -142,15 +138,6 @@
   }
 
   /**
-   * Returns the icons List for this
-   * StyleSheetEntry. (this is a list of IconNodes )
-   */
-  public List <IconNode> getIcons()
-  {
-    return _icons;
-  }
-
-  /**
    * Returns the SkinProperties List for this
    * StyleSheetEntry. This is a list of SkinProperyNodes
    * a node contains the selector, the -tr- property, and the value.
@@ -180,12 +167,6 @@
   }
 
   // Called by CheckModifiedEntry when the style sheet has changed
-  void __setIcons(List <IconNode> icons)
-  {
-    _icons = icons;
-  }
-
-  // Called by CheckModifiedEntry when the style sheet has changed
   void __setSkinProperties(List <SkinPropertyNode> skinProperties)
   {
     _skinProperties = skinProperties;
@@ -193,7 +174,7 @@
 
   // Creates the SkinStyleSheet (a private static inner class that
   // contains StyleSheetDocument plus a list
-  // of icons and properties) from a CSS file
+  // of properties) from a CSS file
   //
   private static StyleSheetEntry _createSkinStyleSheet(
     NameResolver     resolver,
@@ -215,7 +196,6 @@
       {
         skinStyleSheet = new StyleSheetEntry(styleSheetName,
                                              document,
-                                             null,
                                              null);
       }
 
@@ -317,12 +297,11 @@
     public CheckModifiedEntry(
       String                 styleSheetName,
       StyleSheetDocument     document,
-      List<IconNode>         icons,
       List<SkinPropertyNode> properties,
       NameResolver           resolver
       )
     {
-      super(styleSheetName, document, icons, properties);
+      super(styleSheetName, document, properties);
 
       // We need the InputStreamProvider in order to check
       // for modifications.  Get it from the NameResolver.
@@ -342,7 +321,6 @@
         // Throw away the old InputStreamProvider and StyleSheetDocument
         _provider = null;
         __setDocument(null);
-        __setIcons(null);
         __setSkinProperties(null);
 
         // Get a new NameResolver
@@ -364,7 +342,6 @@
           {
             _provider = _getInputStreamProvider(resolver);
             __setDocument(skinStyleSheet.getDocument());
-            __setIcons(skinStyleSheet.getIcons());
             __setSkinProperties(skinStyleSheet.getSkinProperties());
           }
 
@@ -408,8 +385,7 @@
 
   private String              _name;
   private StyleSheetDocument  _document;
-  // List of IconNodes
-  private List <IconNode> _icons;
+
   // List of -tr- properties that the skin can be set on the skin.
   // This is a List of SkinPropertyNodes
   private List <SkinPropertyNode> _skinProperties;

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/icon/NullIcon.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/icon/NullIcon.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/icon/NullIcon.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/skin/icon/NullIcon.java Tue Mar 11 09:42:25 2008
@@ -34,6 +34,14 @@
     return _ICON;
   }
 
+  // Most NullIcon clients should use NullIcon.sharedInstance() to
+  // retrieve a NullIcon instance.  This constructor is provided
+  // specifically for clients that are using a NullIcon instance
+  // as a marker object, eg. see RequestSkinWrapper.
+  public NullIcon()
+  {
+  }
+
   @Override
   public void renderIcon(
     FacesContext context,
@@ -50,10 +58,7 @@
     return true;
   }
 
-  private NullIcon()
-  {
-  }
-
   static private final NullIcon _ICON = new NullIcon();
 }
+
 

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleProvider.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleProvider.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleProvider.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/StyleProvider.java Tue Mar 11 09:42:25 2008
@@ -20,12 +20,20 @@
 
 import java.util.Map;
 
+import java.util.concurrent.ConcurrentMap;
+
+import org.apache.myfaces.trinidad.skin.Icon;
+
 /**
  * The StyleProvider API is used to access context-dependent style
  * information.  Style information is exposed in two ways - as
  * CSS style sheet URIs (via getStyleSheetURI()), or as Style objects
  * (via getStyleMap()).  Both methods take a StyleContext object,
  * which describes the target end user environment.
+ * 
+ * In addition to providing access to style-related information, the
+ * StyleProvider also provides access to Icons which are defined within
+ * style sheets via the getIcons() API.
  *
  * @see StyleContext
  * @see StyleMap
@@ -71,4 +79,16 @@
    */
   public StyleMap getStyleMap(StyleContext context);
 
+  /**
+   * Returns a map of icon names to Icon instances.
+   * 
+   * The returned map is both mutable and threadsafe.  This allows
+   * request/context-specific icons to be cached on the icon map.
+   * 
+   * @param context The context which describes the target end user 
+   *   environment
+   * @return A ConcurrentMap which exposes the Icons for the
+   *  specified context.
+   */
+  public ConcurrentMap<String, Icon> getIcons(StyleContext context);
 }

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/cache/FileSystemStyleCache.java Tue Mar 11 09:42:25 2008
@@ -6,9 +6,9 @@
  *  to you 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
@@ -27,6 +27,7 @@
 import java.io.UnsupportedEncodingException;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -38,6 +39,10 @@
 import java.util.Set;
 import java.util.Vector;
 
+import java.util.concurrent.ConcurrentHashMap;
+
+import java.util.concurrent.ConcurrentMap;
+
 import javax.faces.context.FacesContext;
 
 import org.apache.myfaces.trinidad.logging.TrinidadLogger;
@@ -50,6 +55,7 @@
 import org.apache.myfaces.trinidadinternal.share.io.NameResolver;
 import org.apache.myfaces.trinidad.context.LocaleContext;
 import org.apache.myfaces.trinidad.context.RenderingContext;
+import org.apache.myfaces.trinidad.skin.Icon;
 import org.apache.myfaces.trinidad.skin.Skin;
 import org.apache.myfaces.trinidadinternal.renderkit.core.CoreRenderKit;
 import org.apache.myfaces.trinidadinternal.renderkit.core.xhtml.StyleSheetRenderer;
@@ -63,6 +69,7 @@
 import org.apache.myfaces.trinidadinternal.style.util.CSSGenerationUtils;
 import org.apache.myfaces.trinidadinternal.style.util.NameUtils;
 import org.apache.myfaces.trinidadinternal.style.xml.StyleSheetDocumentUtils;
+import org.apache.myfaces.trinidadinternal.style.xml.parse.IconNode;
 import org.apache.myfaces.trinidadinternal.style.xml.parse.PropertyNode;
 import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleNode;
 import org.apache.myfaces.trinidadinternal.style.xml.parse.StyleSheetDocument;
@@ -73,6 +80,10 @@
 /**
  * The FileSystemStyleCache is a StyleProvider implementation which
  * caches generated CSS style sheets on the file system.
+ * 
+ * Note that StyleProviders are responsible for providing access 
+ * both to style information (eg. getStyleSheetURI(), getStyleMap()) as
+ * well as to icons registered via style sheets (see getIcons()).
  *
  * @see org.apache.myfaces.trinidadinternal.style.StyleProvider
  * @see org.apache.myfaces.trinidadinternal.skin.SkinStyleProvider
@@ -170,6 +181,20 @@
   }
 
   /**
+   * Implementation of StyleProvider.getIcons()
+   */
+  public ConcurrentMap<String, Icon> getIcons(StyleContext context)
+  {
+
+    Entry entry = _getEntry(context);
+
+    if (entry == null)
+      return null;
+
+    return entry.icons;    
+  }
+
+  /**
    * Returns a Map which maps style class names to
    * equivalent shorter names.
    * <p>
@@ -462,10 +487,12 @@
 
     _LOG.fine("Finished processing stylesheet {0}", uri);
 
+    ConcurrentMap<String, Icon> icons = _getStyleContextResolvedIcons(context, document);
+
     // Create a new entry and cache it in the "normal" cache. The "normal" cache is one
     // where the key is the Key object which is built based on information from the StyleContext,
     // like browser, agent, locale, direction.
-    Entry entry = new Entry(uri, new StyleMapImpl());
+    Entry entry = new Entry(uri, new StyleMapImpl(), icons);
     cache.put(key, entry);
 
     // Also, cache the new entry in the entry cache
@@ -594,6 +621,32 @@
     return v.toArray(new StyleNode[v.size()]);
   }
 
+  // Returns a Map of icon names to Icons for the specified
+  // StyleContext and StyleSheetDocument.
+  private ConcurrentMap<String, Icon> _getStyleContextResolvedIcons(
+    StyleContext       context,
+    StyleSheetDocument document
+    )
+  {
+    ConcurrentMap<String, Icon> icons = new ConcurrentHashMap<String, Icon>();
+    Iterator<StyleSheetNode> styleSheetNodes = document.getStyleSheets(context);
+    while (styleSheetNodes.hasNext())
+    {
+      StyleSheetNode styleSheetNode = styleSheetNodes.next();
+      Collection<IconNode> iconNodes = styleSheetNode.getIcons();
+      
+      if (iconNodes != null)
+      {
+        for (IconNode iconNode : iconNodes)
+        {
+          icons.put(iconNode.getIconName(), iconNode.getIcon());
+        }
+      }
+    }
+
+    return icons;
+  }
+
   // Generates the CSS file for the specified context and styles.
   // Returns the name of the generated CSS file.
   private String        _createStyleSheetFile(
@@ -907,7 +960,7 @@
             if (styleClass != null && !styleClass.startsWith(SkinSelectors.STATE_PREFIX))
               if (!map.containsKey(styleClass))
                 map.put(styleClass, _getShortStyleClass(map.size()));
-            
+
             if (style.isEmpty())
               emptySelectors.add(styleClass);
             else
@@ -924,15 +977,14 @@
               {
                 String styleClass = styleClasses.next();
                 _putStyleClassInShortMap(styleClass, map);
-                
                 // Don't remove any styleclass that is referred to
                 nonEmptySelectors.add(styleClass);
               }
             }
-            
+
             // now search for the selectors that have namespaces and add those to the map
             int length = namespacePrefixes.length;
-            
+
             for (int i=0; i < length; i++)
             {
               String nsPrefix = namespacePrefixes[i];
@@ -947,7 +999,6 @@
                 {
                   String styleClass = afSelectors.next();
                   _putStyleClassInShortMap(styleClass, map);
-
                   if (isFirst && !afSelectors.hasNext() && style.isEmpty())
                   {
                     emptySelectors.add(styleClass);
@@ -956,7 +1007,7 @@
                   {
                     nonEmptySelectors.add(styleClass);
                   }
-                  
+
                   isFirst = false;
                 }
               }
@@ -1098,11 +1149,13 @@
   {
     public final String uri;
     public final StyleMap map;
+    public final ConcurrentMap<String, Icon> icons;
 
-    public Entry(String uri, StyleMap map)
+    public Entry(String uri, StyleMap map, ConcurrentMap<String, Icon> icons)
     {
       this.uri = uri;
       this.map = map;
+      this.icons = icons;
     }
   }
 

Added: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/IconNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/IconNode.java?rev=636000&view=auto
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/IconNode.java (added)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/IconNode.java Tue Mar 11 09:42:25 2008
@@ -0,0 +1,74 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ */
+package org.apache.myfaces.trinidadinternal.style.xml.parse;
+
+import org.apache.myfaces.trinidad.skin.Icon;
+import org.apache.myfaces.trinidad.logging.TrinidadLogger;
+
+/**
+ * Object which represents a single <icon> element.
+ *
+ * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/ui/laf/xml/parse/IconNode.java#0 $) $Date: 10-nov-2005.18:50:36 $
+ */
+public class IconNode
+{
+  /**
+   * Creates a IconNode
+   * @param namespace The namespace of the icon
+   * @param name The name of the icon
+   * @param icon The Icon instance
+   */
+  public IconNode(
+    String name,
+    Icon   icon
+    )
+  {
+    if (name == null)
+    {
+      throw new NullPointerException(_LOG.getMessage(
+        "NULL_NAME"));
+    }
+
+    _name = name;
+    _icon = icon;
+  }
+
+
+  /**
+   * Returns the name of the icon that is defined
+   * by this IconNode.
+   */
+  public String getIconName()
+  {
+    return _name;
+  }
+
+  /**
+   * Returns the Icon instance for this IconNode.
+   */
+  public Icon getIcon()
+  {
+    return _icon;
+  }
+
+  private String      _name;
+  private Icon        _icon;
+  private static final TrinidadLogger _LOG = TrinidadLogger.createTrinidadLogger(
+    IconNode.class);
+}

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetDocument.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetDocument.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetDocument.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetDocument.java Tue Mar 11 09:42:25 2008
@@ -48,7 +48,10 @@
 
 
 /**
- * Private implementation of StyleSheetDocument.
+ * Parsed representation of a Trinidad style sheet document.
+ * 
+ * The StyleSheetDocument provides access to both style as well as icons
+ * information, but not to skin properties.
  *
  * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/style/xml/parse/StyleSheetDocument.java#0 $) $Date: 10-nov-2005.18:58:12 $
  */
@@ -122,7 +125,7 @@
     Iterator<StyleSheetNode> styleSheetNodes = getStyleSheets(sContext);
     while (styleSheetNodes.hasNext())
     {
-      hashCode = hashCode*37 +  styleSheetNodes.next().hashCode();      
+      hashCode = hashCode*37 +  styleSheetNodes.next().getStyleSheetId();      
     }
     return Integer.toString(Math.abs(hashCode), 36);
   }

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNode.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNode.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNode.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNode.java Tue Mar 11 09:42:25 2008
@@ -18,6 +18,7 @@
  */
 package org.apache.myfaces.trinidadinternal.style.xml.parse;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -38,7 +39,9 @@
 
 /**
  * Private implementation of StyleSheetNode. A StyleSheetNode has StyleNodes for particular
- * browsers, direction, versions, platforms and mode.
+ * browsers, direction, versions, platforms and mode.  In addition, the StyleSheetNode
+ * provides access to IconNodes representing the icons which were defined within
+ * the context of this style sheet.
  *
  * @version $Name:  $ ($Revision: adfrt/faces/adf-faces-impl/src/main/java/oracle/adfinternal/view/faces/style/xml/parse/StyleSheetNode.java#0 $) $Date: 10-nov-2005.18:58:46 $
  */
@@ -50,6 +53,7 @@
    */
   public StyleSheetNode(
     StyleNode[] styles,
+    Collection<IconNode> icons,
     Locale[] locales,
     int direction,
     int[] browsers,
@@ -64,6 +68,11 @@
     else
       _styles = Collections.emptyList();
 
+    if (icons != null)
+      _icons = Collections.unmodifiableList(new ArrayList<IconNode>(icons));
+    else
+      _icons = Collections.emptyList();
+
     // locales, browsers, versions, platforms order does not matter, so these are Sets.
     if (locales != null)
     {
@@ -100,7 +109,7 @@
       
     _mode = mode;
     _direction = direction;
-    _hashCode = _getHashCode();
+    _id = _computeStyleSheetId();
   }
 
   /**
@@ -112,6 +121,14 @@
   }
 
   /**
+   * Returns icons contained by this StyleSheetNode.
+   */
+  public Collection<IconNode> getIcons()
+  {
+    return _icons;
+  }
+
+  /**
    * Implementation of StyleSheetNode.getReadingDirection();
    */
   public int getReadingDirection()
@@ -207,33 +224,38 @@
   }
 
   @Override  
-  public boolean equals(Object obj)
+  public final boolean equals(Object obj)
   {
-    if (this == obj)
-      return true;
-    if (!(obj instanceof StyleSheetNode))
-      return false;
-      
-    // obj at this point must be a StyleSheetNode
-    StyleSheetNode test = (StyleSheetNode)obj;
-    // look for equality in the order of what is most likely to be different and what
-    // is easiest to check for.  
-    return
-      (_mode == test._mode) &&
-      (_direction == test._direction) &&
-      (_locales.equals(test._locales)) &&
-      (_browsers.equals(test._browsers)) &&
-      (_platforms.equals(test._platforms)) &&
-      (_versions.equals(test._versions)) &&
-      (_styles.equals(test._styles));
+    // A single StyleSheetNode is created for each "style sheet"
+    // section in a StyleSheetDocument.  As such, we have no need
+    // for a logical equality test.  We always want to perform 
+    // identity comparisons when determining the equality of 
+    // two StyleSheetNodes.  We use the default Object.equals()
+    // implementation to achieve this.
+    
+    // Note that technically speaking this override is not needed.
+    // However, to avoid confusion about whether we should be performing
+    // logical equality vs. identity comparisons, we explicitly define
+    // this final override, if only to serve as documentation of our
+    // intentions.
 
-  }
   
+    return super.equals(obj);
+  }
+
   @Override
-  public int hashCode()
+  public final int hashCode()
   {
-    // return the cached hashCode that is computed in the constructor
-    return _hashCode;
+    // Since unique StyleSheetNode instance is created for each "style sheet"
+    // section in a StyleSheetDocument, and since we have no need for 
+    // logical equality comparisions, the default hashCode() implementation
+    // is sufficient for our needs.
+    
+    // Like the override of equals(), this override is not strictly
+    // necessary, but is here to make it clear that we always want to
+    // use the default Object.hashCode() implementation.
+
+    return super.hashCode();
   }
   
   @Override
@@ -244,13 +266,37 @@
       "direction=" + _getDirectionString() + ", " +
       "browsers="  + _browsers.toString()  + ", " +
       "versions="  + _versions.toString()  + ", " +
-      "platforms=" + _platforms.toString()  + ", " +
-      "styles="    + _styles.toString() + "]";
+      "platforms=" + _platforms.toString() + ", " +
+      "styles="    + _styles.toString()    + ", " +
+      "icons="     + _icons.toString()     + "]";
   }
-  
-  // Compute the hashCode and return it.  
-  private int _getHashCode()
+
+  /**
+   * Returns an int-based id which can be used by StyleSheetDocument.getDocumentId()
+   * to (semi-)uniquely identify this StyleSheetNode.  This id is very similar
+   * to a hash code, though is not exactly the same, as some StyleSheetNode
+   * properties (such as icons) are intentionally excluded from the style sheet 
+   * id.
+   * 
+   * @return An integer value suitable for use by StyleSheetDocument.getDocumentId().
+   */
+  public int getStyleSheetId()
   {
+    return _id;    
+  }
+
+  // Compute the style sheet id and return it.  
+  private int _computeStyleSheetId()
+  {
+    // This is very similar to computing a hash code.  However, we
+    // explicitly exclude properties which have no impact on the
+    // generated style sheet, such as icons.  The reason for this
+    // is that the generated style sheet version produced by 
+    // StyleSheetDocument.getDocumentId() should not change unless
+    // the generated style sheet itself changes.  Since icons do not
+    // impact the generated style sheet, these are excluded form the
+    // style sheet id.
+
     int hash = 17;
     hash = 37*hash + _mode;
     hash = 37*hash + _direction;
@@ -432,6 +478,7 @@
   }
 
   private final List<StyleNode> _styles;     // The styles contained within this node
+  private final List<IconNode>  _icons;      // The icons contained within this node
   // Order does not matter for locales, browsers, versions, platforms
   private final Set<Locale>     _locales;    // The locale variants
   private final int             _direction;  // The reading direction
@@ -439,7 +486,7 @@
   private final Set<Integer>    _versions;   // The version variants
   private final Set<Integer>    _platforms;  // The platform variants
   private final int             _mode;       // The mode  
-  private final int             _hashCode;   // The cached hashCode
+  private final int             _id;         // The cached style sheet id
 
   // Constants for locale matches - 0x000f0000 bits
   private static final int _LOCALE_EXACT_MATCH      = 0x00040000;

Modified: myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeParser.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeParser.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeParser.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeParser.java Tue Mar 11 09:42:25 2008
@@ -77,9 +77,9 @@
       _styles.copyInto(styles);
     }
 
-    return new
-      StyleSheetNode(
+    return new StyleSheetNode(
         styles,
+        null,      // icons only supported in skin CSS - not XSS
         _locales,
         _direction,
         _browsers,

Modified: myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeEqualsTest.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeEqualsTest.java?rev=636000&r1=635999&r2=636000&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeEqualsTest.java (original)
+++ myfaces/trinidad/trunk/trinidad-impl/src/test/java/org/apache/myfaces/trinidadinternal/style/xml/parse/StyleSheetNodeEqualsTest.java Tue Mar 11 09:42:25 2008
@@ -18,6 +18,8 @@
  */
 package org.apache.myfaces.trinidadinternal.style.xml.parse;
 
+import java.util.ArrayList;
+
 import junit.framework.TestCase;
 
 import java.util.Arrays;
@@ -29,10 +31,14 @@
 import java.util.Set;
 import java.util.Vector;
 
+import org.apache.myfaces.trinidad.skin.Icon;
+import org.apache.myfaces.trinidadinternal.skin.icon.ContextImageIcon;
+import org.apache.myfaces.trinidadinternal.skin.icon.TextIcon;
+
 /**
- * Test the hashCode and equals methods on the StyleSheetNode object and the objects
- * that make up the StyleSheetNode. The hashcode of the StyleSheetNode object is used
- * to create a StyleSheetDocument id.
+ * Test the getStyleSheetId() method on the StyleSheetNode object. 
+ * The id of the StyleSheetNode object is used to create a StyleSheetDocument 
+ * id.
  */
 public class StyleSheetNodeEqualsTest extends TestCase
 {
@@ -119,6 +125,9 @@
                                       getOutputLabelStyleNode(),
                                       getAnotherOutputLabelStyleNode()};
 
+    List<IconNode> iconNodes = _getIconNodes();
+    List<IconNode> anotherIconNodes = _getIconNodes();
+
     // create locales arrays
     Locale[] localesArray = getLocalesArray();
     Locale[] anotherLocalesArray = getAnotherLocalesArray();
@@ -147,7 +156,8 @@
     // int mode
     
     StyleSheetNode styleSheetNode = 
-      new StyleSheetNode(styleSheetOneNodes, 
+      new StyleSheetNode(styleSheetOneNodes,
+                         iconNodes,
                          localesArray, 
                          0, 
                          browsers, 
@@ -155,7 +165,8 @@
                          platforms, 
                          0);
     StyleSheetNode anotherStyleSheetNode = 
-      new StyleSheetNode(anotherStyleSheetOneNodes, 
+      new StyleSheetNode(anotherStyleSheetOneNodes,
+                         anotherIconNodes,
                          anotherLocalesArray,
                          0, 
                          anotherBrowsersDiffOrder, 
@@ -163,7 +174,8 @@
                          anotherPlatforms, 
                          0);
     StyleSheetNode sameDiffOrderStyleSheetNode = 
-      new StyleSheetNode(anotherStyleSheetOneNodes, 
+      new StyleSheetNode(anotherStyleSheetOneNodes,
+                         anotherIconNodes,
                          diffOrderLocalesArray,
                          0, 
                          anotherBrowsersDiffOrder, 
@@ -172,12 +184,20 @@
                          0);                         
       
     // these should be equal
-    assertEquals(styleSheetNode.hashCode() == anotherStyleSheetNode.hashCode(), true);   
-    assertEquals(anotherStyleSheetNode.equals(styleSheetNode), true);
-    assertEquals(styleSheetNode.equals(anotherStyleSheetNode), true); 
-    assertEquals(sameDiffOrderStyleSheetNode.equals(anotherStyleSheetNode), true); 
-    assertEquals(styleSheetNode.equals(sameDiffOrderStyleSheetNode), true);
-    
+    assertEquals(styleSheetNode.getStyleSheetId() == anotherStyleSheetNode.getStyleSheetId(), true);   
+    assertEquals(styleSheetNode.getStyleSheetId() == sameDiffOrderStyleSheetNode.getStyleSheetId(), true);   
+        
+    // Note that StyleSheetNode.equals() explicitly uses the default
+    // identity comparison since we never care about logical equivalence
+    // of two StyleSheetNode instances.  The StyleSheetNode equality
+    // tests below enforce that StyleSheetNode.equals() implements identity 
+    // rather that logical equality.
+    assertEquals(styleSheetNode.equals(styleSheetNode), true);  
+    assertEquals(anotherStyleSheetNode.equals(styleSheetNode), false);
+    assertEquals(styleSheetNode.equals(anotherStyleSheetNode), false); 
+    assertEquals(sameDiffOrderStyleSheetNode.equals(anotherStyleSheetNode), false); 
+    assertEquals(styleSheetNode.equals(sameDiffOrderStyleSheetNode), false);
+
     // these should be false
     assertEquals(styleSheetNode.equals(null), false);
     assertEquals(styleSheetNode.equals(localesArray), false);
@@ -292,6 +312,19 @@
   {
     return new Locale[] {new Locale("zh", "CN"), new Locale("tw", "TW")};  
   }
-  
+
+  private List<IconNode> _getIconNodes()
+  {
+    List<IconNode> iconNodes = new ArrayList<IconNode>(2);
+    
+    Icon icon1 = new TextIcon("Hello, world!");
+    Icon icon2 = new ContextImageIcon("/foo/bar/baz.png", 10, 10);
+    
+    iconNodes.add(new IconNode("hello", icon1));
+    iconNodes.add(new IconNode("foo", icon1));
+    
+    return iconNodes;
+  }
 }
+