[Commits] r1710 - in sandbox/ahocevar/playground/trunk: . docsrc docsrc/_theme/geoext docsrc/_theme/geoext/static docsrc/_theme/geoext/static/img docsrc/lib docsrc/lib/GeoExt docsrc/primers docsrc/tutorials geoext/build geoext/examples geoext/lib geoext/lib/GeoExt/widgets geoext/lib/GeoExt/widgets/form geoext/lib/GeoExt/widgets/tree geoext/tests geoext/tests/lib/GeoExt/widgets geoext/tests/lib/GeoExt/widgets/tree

commits at geoext.org commits at geoext.org
Mon Jan 11 13:47:52 CET 2010


Author: ahocevar
Date: 2010-01-11 13:47:52 +0100 (Mon, 11 Jan 2010)
New Revision: 1710

Added:
   sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/examples.js
   sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/favicon.ico
   sandbox/ahocevar/playground/trunk/docsrc/examples.jst
   sandbox/ahocevar/playground/trunk/docsrc/lib/overrides.rst
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/UrlLegend.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/WMSLegend.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/RadioButtonMixin.js
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/UrlLegend.html
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/WMSLegend.html
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/RadioButtonMixin.html
Removed:
   sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/img/favicon.ico
   sandbox/ahocevar/playground/trunk/docsrc/examples/
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendWMS.js
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendWMS.html
Modified:
   sandbox/ahocevar/playground/trunk/
   sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/layout.html
   sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/front-page.js
   sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/geoext.css
   sandbox/ahocevar/playground/trunk/docsrc/conf.py
   sandbox/ahocevar/playground/trunk/docsrc/docs.rst
   sandbox/ahocevar/playground/trunk/docsrc/downloads.rst
   sandbox/ahocevar/playground/trunk/docsrc/index.rst
   sandbox/ahocevar/playground/trunk/docsrc/lib/GeoExt/widgets.rst
   sandbox/ahocevar/playground/trunk/docsrc/lib/index.rst
   sandbox/ahocevar/playground/trunk/docsrc/lib/template.jst
   sandbox/ahocevar/playground/trunk/docsrc/primers/ext-primer.rst
   sandbox/ahocevar/playground/trunk/docsrc/primers/openlayers-primer.rst
   sandbox/ahocevar/playground/trunk/docsrc/tutorials/control-button-tutorial.rst
   sandbox/ahocevar/playground/trunk/docsrc/tutorials/layertree-tutorial.rst
   sandbox/ahocevar/playground/trunk/docsrc/tutorials/mappanel-tutorial.rst
   sandbox/ahocevar/playground/trunk/docsrc/tutorials/quickstart.rst
   sandbox/ahocevar/playground/trunk/docsrc/tutorials/remote-features-tutorial.rst
   sandbox/ahocevar/playground/trunk/geoext/build/full.cfg
   sandbox/ahocevar/playground/trunk/geoext/examples/legendpanel.js
   sandbox/ahocevar/playground/trunk/geoext/examples/tree.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/Action.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/FeatureRenderer.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendImage.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendPanel.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/FormPanel.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js
   sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/OverlayLayerContainer.js
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html
   sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html
   sandbox/ahocevar/playground/trunk/geoext/tests/list-tests.html
Log:
merging r1709 from trunk


Property changes on: sandbox/ahocevar/playground/trunk
___________________________________________________________________
Name: svn:externals
   - openlayers http://svn.openlayers.org/branches/openlayers/2.8
ext http://www.geoext.org/svn/geoext/ext/2.2.1

   + openlayers http://svn.openlayers.org/trunk/openlayers
ext http://www.geoext.org/svn/geoext/ext/2.2.1


Modified: sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/layout.html
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/layout.html	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/layout.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -25,9 +25,9 @@
     <div class="sphinxsidebar">
         <div class="sphinxsidebarwrapper">
             <h1>Download</h1>
-            <p>Current release: <a href="{{ pathto('downloads') }}">{{ version }}</a></p>
+            <p>Current release: <a href="{{ pathto('downloads') }}">{{ release }}</a></p>
             <h1>GeoExt News</h1>
-            <script src="http://landmark-project.com/feed2js/feed2js.php?src=http%3A%2F%2Fgeoext.blogspot.com%2Ffeeds%2Fposts%2Fdefault%3Falt%3Drss&num=3&desc=75"></script>
+            <script charset="ISO-8859-1" src="http://landmark-project.com/feed2js/feed2js.php?src=http%3A%2F%2Fgeoext.blogspot.com%2Ffeeds%2Fposts%2Fdefault%3Falt%3Drss&num=3&desc=75"></script>
             <span><a href="http://geoext.blogspot.com" title="GeoExt Blog">more ...</a></span>
         </div>
     </div>
@@ -36,15 +36,14 @@
 {% block extrahead %}
     {% if pagename == "index" %}
     <script type="text/javascript" src="http://extjs.cachefly.net/builds/ext-cdn-771.js"></script>
-    <script type="text/javascript" src="http://openlayers.org/api/2.8-rc2/OpenLayers.js"></script>
-    <script type="text/javascript">
-        // In IE, OpenLayers clobbers the $ from jQuery.
-        // Remove this when http://trac.openlayers.org/ticket/1391 is closed.
-        $ = jQuery;
-    </script>
+    <script type="text/javascript" src="http://openlayers.org/api/2.8/OpenLayers.js"></script>
     <script src="{{ pathto('_static/GeoExt.js', 1) }}"></script>
     <script src="{{ pathto('_static/front-page.js', 1) }}"></script>
     {% endif %}
+    {% if pagename == "examples" %}
+    <script type="text/javascript" src="http://extjs.cachefly.net/builds/ext-cdn-771.js"></script>
+    <script src="{{ pathto('_static/examples.js', 1) }}"></script>
+    {% endif %}
 {% endblock %}
 
 {% block header %}
@@ -53,9 +52,9 @@
             <h1 id="logo"><a href="{{ pathto('index') }}">GeoExt</a></h1>
             <ul id="top-nav">
                 <li class="first"><a href="{{ pathto('docs') }}">Documentation</a></li>
-                <li><a href="{{ pathto('examples/index') }}">Demos</a></li>
+                <li><a href="{{ pathto('examples') }}">Examples</a></li>
                 <li><a href="{{ pathto('downloads') }}">Download</a></li>
-                <li><a href="http://www.geoext.org/trac/geoext/">Development</a></li>
+                <li><a href="http://trac.geoext.org/">Development</a></li>
             </ul>
             {%- if pagename != "search" %}
             <div id="searchbox">

Copied: sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/examples.js (from rev 1709, core/trunk/docsrc/_theme/geoext/static/examples.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/examples.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/examples.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,15 @@
+Ext.onReady(function() {
+    var blocks = Ext.select("div.exampleblock");
+    var exbase = "http://dev.geoext.org/trunk/geoext/examples/";
+    blocks.each(function(el) {
+        el.wrap({
+            tag: "a", 
+            href: el.first().id.replace(
+                /^example-(.*)/, 
+                exbase + "$1.html"
+            ),
+            cls: "examplelink",
+            target: "_blank"
+        });
+    });
+});
\ No newline at end of file

Copied: sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/favicon.ico (from rev 1709, core/trunk/docsrc/_theme/geoext/static/favicon.ico)
===================================================================
(Binary files differ)

Modified: sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/front-page.js
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/front-page.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/front-page.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -13,8 +13,8 @@
                     items: [{
                         xtype: "gx_mappanel",
                         layers: [new OpenLayers.Layer.WMS(
-                            "bluemarble", "http://demo.opengeo.org/geoserver/wms",
-                            {layers: 'bluemarble'}
+                            "Global Imagery", "http://maps.opengeo.org/geowebcache/service/wms",
+                            {layers: "bluemarble"}
                         )],
                         zoom: 1
                     }]

Modified: sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/geoext.css
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/geoext.css	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/geoext.css	2010-01-11 12:47:52 UTC (rev 1710)
@@ -3,11 +3,19 @@
 @import url("sphinxdoc.css");
 
 /* override some of ext-all.css */
-ul {
+ul, ol {
     margin: 14px 0;
     padding-left: 40px;
+}
+ul {
     list-style: disc;
 }
+ol {
+    list-style-type:decimal;
+}
+strong {
+    font-weight: bolder;
+}
 
 /* override some of sphinxdoc.css */
 html {
@@ -49,6 +57,9 @@
 div.document {
     margin: 0 80px;
 }
+div.documentwrapper {
+    width: auto;
+}
 div.footer {
     background: #4E7AB2 url(img/footer-bg.png) repeat-x;
     color: #d9d9d9;
@@ -156,6 +167,9 @@
 .method .descclassname {
     display: none;
 }
+.classmethod .descclassname, .classmethod .property {
+    display: none;
+}
 
 /* headers with bottom border get some padding */
 h2, h3, h4 {
@@ -175,4 +189,26 @@
 /* execute button style */
 .x-btn.execute {
     margin: 1em;
-}
\ No newline at end of file
+}
+
+.exampleblock {
+    width: 225px;
+    margin: 5px;
+    height: 110px;
+    overflow: auto;
+}
+.exampleblock h2 {
+    margin-top: 0px;
+    font-size: 1em;
+}
+a.examplelink {
+    margin: 5px;
+    text-decoration: none !important;
+    float: left;
+    display: block;
+    border: 1px solid #FFFFFF;
+}
+a.examplelink:hover {
+    border: 1px solid #E5EDD3;
+    background-color: #F5FDE3
+}

Deleted: sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/img/favicon.ico
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/img/favicon.ico	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/_theme/geoext/static/img/favicon.ico	2010-01-11 12:47:52 UTC (rev 1710)
@@ -1,5 +0,0 @@
-         h     (                                    ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ýüüؼ¤­«€QøÇ«‘úÛ¯¹üûúÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ýýüͪŠÅ£zGÿ›ƒSÿ®¤ƒÿØÏÃÿ¿¤ƒÕüûúÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ýýüàųɩ}KÿžNÿ”€Oÿ½¶ÿ²·žÿˆZÿ¸¡~×ýûúÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ýýüÊ¢ÉÒ³›ÿÛÎÁÿ¶¢ÿ¼²—ÿÜÛÒÿ ¥…ÿ‚”lÿzeÿ¶£×ýûúÿÿÿ ÿÿÿ ÿÿÿ ýýüͦ„É«s;ÿµ‘hÿ·Ÿ|ÿÕ̽ÿËǵÿÊʹÿ»À¬ÿÚÞÖÿ‰©ˆÿk’hÿ³¤‚×ýûúÿÿÿ ýýüÕ±—Å°t<ÿ­~Kÿ¥~MÿQÿ™ˆ[ÿ±«ŽÿÏÒÅÿžªŒÿŸ²—ÿÉ×Ìÿ¨É·ÿ`šqÿ²¨ˆÕýûúÞ𭼁Xÿ´‚Vÿ«Qÿ§‡Zÿ–~Mÿ« }ÿßßÙÿ—qÿ|eÿq’hÿ™¶ÿ®Í½ÿT£}ÿYŸyÿŹŸ½¾„\ÿ¾Šeÿ¾—vÿÖñÿÛÑÄÿ¶¨‰ÿ«¥„ÿÅƵÿ‡”lÿ~–nÿr˜pÿ‚«ŒÿÎáÙÿa«‰ÿH­Šÿ{”kÿ»ZýÉ ƒÿëâÜÿȳÿ·¥ˆÿÒ̽ÿË˼ÿÔÕÊÿ®º¡ÿw•lÿvŸzÿ°Ëºÿ¡Ê·ÿWªˆÿC¯Œÿ{•kÿâʺŸÍ§ÿÍ·¢ÿ¨‰cÿ¥‘nÿ –sÿÒÒÅÿ²º£ÿ¼Ç´ÿÎÚÑÿ¿ÓÅÿÆÜÒÿT¢}ÿI¬ˆÿR£~ÿÎï®ýýýòäÞ³¾ž€ÿ§kÿ¥—uÿš•rÿÑÒÆÿ­¹¢ÿ¤ƒÿ »¥ÿx§†ÿt®ÿ^®ÿb©ˆÿ»¥Çýüüÿÿÿ þþþçÕɶ«‘nÿž•rÿ·µžÿØÜÓÿŽ €ÿ‡¤„ÿ~¦†ÿz¬Žÿn±•ÿoª‹ÿú¤Éýýüÿÿÿ ÿÿÿ ÿÿÿ þþþ
-éÚжÓǹÿÍÐÃÿ¹Á®ÿ£„ÿ†¦‡ÿªŒÿt¯“ÿr¨ˆÿù£Éýýüÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ þýý
-çÓȶ˜”pÿ‰ž|ÿŠ¥…ÿƒ¨Šÿy­ÿw¥†ÿĹ¢Éýýüÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ýýý
-Ö𳓘uÿ…§ˆÿ~«Œÿ~¢‚ÿȼ¦Âýýüÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ýýý
-ßοŸ¥˜w÷ ™xø×ǵ­ýüüÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ÿÿÿ ü?  ø  ð  à  À  €                  €  À  à  ð  ø  ü?  
\ No newline at end of file

Modified: sandbox/ahocevar/playground/trunk/docsrc/conf.py
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/conf.py	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/conf.py	2010-01-11 12:47:52 UTC (rev 1710)
@@ -45,9 +45,9 @@
 # built documents.
 #
 # The short X.Y version.
-version = '0.1'
+version = '0.6'
 # The full version, including alpha/beta/rc tags.
-release = '0.1 beta'
+release = '0.6'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -103,7 +103,7 @@
 
 # The name for this set of Sphinx documents.  If None, it defaults to
 # "<project> v<release> documentation".
-#html_title = None
+html_title = 'GeoExt v%s' % (version,) 
 
 # A shorter title for the navigation bar.  Default is the same as html_title.
 html_short_title = 'GeoExt'

Modified: sandbox/ahocevar/playground/trunk/docsrc/docs.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/docs.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/docs.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -12,17 +12,11 @@
 Examples
 --------
 
-* Using a `Feature Grid <http://dev.geoext.org/trunk/geoext/examples/feature-grid.html>`_ to display geospatial data in a tabular format
+Learn by :ref:`example <examples>`! Most of the GeoExt widgets and data components
+have simple examples that demonstrate their use. By looking through the sources
+for the examples, you can learn how to use GeoExt components in your
+application.
 
-* Using a `Map Panel <http://dev.geoext.org/trunk/geoext/examples/mappanel-window.html>`_ to embed an interactive map in a web page
-
-* Using `Popups <http://dev.geoext.org/trunk/geoext/examples/popup.html>`_ to provide more detailed information about features on a map
-
-* Using `WMS Capabilities <http://dev.geoext.org/trunk/geoext/examples/wms-capabilities.html>`_ to find the available layers from a web mapping service.
-
-* Using a `Zoom Chooser <http://dev.geoext.org/trunk/geoext/examples/zoom-chooser.html>`_ to help users navigate the map.
-
-
 Library Reference
 -----------------
 

Modified: sandbox/ahocevar/playground/trunk/docsrc/downloads.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/downloads.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/downloads.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -2,7 +2,12 @@
  Download GeoExt
 =================
 
-Since GeoExt is still in a pre-release state, no minified build is available.  You can still get the development version using svn::
+Current Release
+---------------
 
-    svn export http://svn.geoext.org/core/trunk/geoext/ GeoExt/
+ * GeoExt 0.6 (`Source <http://trac.geoext.org/attachment/wiki/Download/GeoExt-release-0.6.zip?format=raw>`__ | `Release Notes <http://trac.geoext.org/wiki/Release/0.6/Notes>`__)
 
+Previous Releases
+-----------------
+
+ * GeoExt 0.5 (`Source <http://trac.geoext.org/attachment/wiki/Download/GeoExt-release-0.5.zip?format=raw>`__ | `Release Notes <http://trac.geoext.org/wiki/Release/0.5/Notes>`__)

Copied: sandbox/ahocevar/playground/trunk/docsrc/examples.jst (from rev 1709, core/trunk/docsrc/examples.jst)
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/examples.jst	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/docsrc/examples.jst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,14 @@
+{# This template is used to produce the examples.html page for the website. #}
+.. _examples:
+
+Examples
+========
+
+{% for (name, desc) in example|dictsort %}
+.. _example.{{ name }}:
+
+.. cssclass:: exampleblock example-{{ name }}
+
+{{ desc }}
+
+{% endfor %}

Modified: sandbox/ahocevar/playground/trunk/docsrc/index.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/index.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/index.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -1,3 +1,7 @@
+.. Sphinx 0.6.2 will support the 'title' directive.  See
+    http://bitbucket.org/birkenfeld/sphinx/changeset/036f2d008240/
+
+
 JavaScript Toolkit for Rich Web Mapping Applications
 ====================================================
 
@@ -7,9 +11,9 @@
 the web with JavaScript.
 
 `Documentation <./docs.html>`_ | 
-`Demos <./examples/index.html>`_ | 
+:ref:`Examples <examples>` | 
 `Download <./downloads.html>`_ | 
-`Development <http://www.geoext.org/trac/geoext/>`_
+`Development <http://trac.geoext.org/>`_
 
 Using GeoExt
 ------------
@@ -26,8 +30,8 @@
         items: [{
             xtype: "gx_mappanel",
             layers: [new OpenLayers.Layer.WMS(
-                "bluemarble", "http://demo.opengeo.org/geoserver/wms",
-                {layers: 'bluemarble'}
+                "Global Imagery", "http://maps.opengeo.org/geowebcache/service/wms",
+                {layers: "bluemarble"}
             )],
             zoom: 1
         }]
@@ -50,7 +54,7 @@
     docs
     tutorials/index
     primers/index
+    examples
     developer/index
     lib/index
-    examples/index
     downloads

Modified: sandbox/ahocevar/playground/trunk/docsrc/lib/GeoExt/widgets.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/lib/GeoExt/widgets.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/lib/GeoExt/widgets.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -8,6 +8,7 @@
     :glob:
     
     widgets/*
+    widgets/tips/*
 
 
 .. module:: GeoExt.form
@@ -26,7 +27,22 @@
     widgets/form/*
 
 
+.. module:: GeoExt.grid
+    :synopsis: A collection of grid related classes.
 
+:mod:`GeoExt.grid`
+==================
+
+The :mod:`GeoExt.grid` module contains classes that extend map related
+functionality to ``Ext.grid`` classes.
+
+.. toctree::
+    :maxdepth: 1
+    :glob:
+    
+    widgets/grid/*
+
+
 .. module:: GeoExt.tree
     :synopsis: A collection of tree related classes.
 

Modified: sandbox/ahocevar/playground/trunk/docsrc/lib/index.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/lib/index.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/lib/index.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -32,6 +32,12 @@
     :maxdepth: 2
 
     GeoExt/data
-    
 
+Overrides
+---------
 
+.. toctree::
+    :maxdepth: 2
+
+    overrides
+

Copied: sandbox/ahocevar/playground/trunk/docsrc/lib/overrides.rst (from rev 1709, core/trunk/docsrc/lib/overrides.rst)
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/lib/overrides.rst	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/docsrc/lib/overrides.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,14 @@
+.. _overrides:
+
+Ext Overrides
+=============
+
+The GeoExt library provides some specific overrides for Ext objects and methods.
+These can be optionally included in your GeoExt build.
+
+See below for a list of available overrides.
+
+.. toctree::
+   :maxdepth: 1
+   
+   overrides/override-ext-ajax

Modified: sandbox/ahocevar/playground/trunk/docsrc/lib/template.jst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/lib/template.jst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/lib/template.jst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -12,6 +12,7 @@
         * Public Properties (optional)
         * Public Methods (optional)
         * Events (optional)
+        * Class Methods (optional)
 
 #}
 .. currentmodule:: {{ module }}
@@ -98,3 +99,17 @@
     {{ desc|indent(4) }}
 {% endfor %}
 {% endif %}
+
+{% if classmethod is defined %}
+Class Methods
+-------------
+
+Class methods{% if base_link is defined %} in addition to static methods
+listed for {{ base_link }}{% endif %}.
+
+{% for (name, desc) in classmethod|dictsort %}
+.. classmethod:: {{ class }}.{{ name }}
+
+    {{ desc|indent(4) }}
+{% endfor %}
+{% endif %}

Modified: sandbox/ahocevar/playground/trunk/docsrc/primers/ext-primer.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/primers/ext-primer.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/primers/ext-primer.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -18,19 +18,20 @@
 For more complete instructions about how configure a web page to use
 Ext, you can check the :doc:`../tutorials/quickstart` tutorial.
 
-When you download Ext, you also get their excellent `Examples <http://www.extjs.com/deploy/dev/examples/>'_ and 'API
-Documentation <http://www.extjs.com/deploy/dev/docs/>`_, which you can also look at on-line for education and reference.
+When you download Ext, you also get their excellent
+`Examples <http://www.extjs.com/deploy/dev/examples/>`_ and
+`API Documentation <http://www.extjs.com/deploy/dev/docs/>`_, which you can also
+look at on-line for education and reference.
 
 In order to get Ext running on a page you will need to have something
 like the following in the ``<head>`` of an HTML page in a directory
 that is published by your web server.
 
-    .. code-block::
-       xml
+.. code-block:: html
 
-       <script src="ext-2.2/adapter/ext/ext-base.js" type="text/javascript"></script>
-       <script src="ext-2.2/ext-all.js"  type="text/javascript"></script>
-       <link rel="stylesheet" type="text/css" href="ext-2.2/resources/css/ext-all.css"></link>
+    <script src="ext-2.2/adapter/ext/ext-base.js" type="text/javascript"></script>
+    <script src="ext-2.2/ext-all.js"  type="text/javascript"></script>
+    <link rel="stylesheet" type="text/css" href="ext-2.2/resources/css/ext-all.css"></link>
 
 This will load the code and styles for Ext.  Change the paths
 according to where you have put the Ext files.
@@ -40,25 +41,24 @@
 configuration object--as an argument.  This snippet demonstrates this
 coding pattern:
 
-    .. code-block::
-       html
+.. code-block:: javascript
 
-       Ext.onReady(function(){
-            var myPanel = new Ext.Panel({
-                title: 'Hello World!',
-                html: '<i>Hello World!</i> Please enjoy this primer on Ext!',
-                collapsible: true,
-                width:300,
-                renderTo: 'panelDiv'
-            });        
-       });
+    Ext.onReady(function(){
+        var myPanel = new Ext.Panel({
+            title: 'Hello World!',
+            html: '<i>Hello World!</i> Please enjoy this primer on Ext!',
+            collapsible: true,
+            width:300,
+            renderTo: 'panelDiv'
+        });        
+    });
 
 There are a few things to note about this example:
 
 * This code uses Ext's ``onReady`` method to trigger the method when the
-  document's body is ready.  (This is cleaner than using body's
-  ``onready`` event, and with ``Ext.onReady`` several functions can be
-  queued for execution before the page loads.)
+  document's body is ready. (This is cleaner than using body's ``onready``
+  event, and with ``Ext.onReady`` several functions can be queued for execution
+  before the page loads.)
 
 * When the page is ready, the ``Ext.Panel`` constructor is called with a
   single configuration object as argument.  The Panel's structure should
@@ -75,7 +75,8 @@
 * Lastly, this code assumes that somewhere in the DOM of the page is a
   ``div`` with the id ``panelDiv``.  When the Panel is constructed, it
   will be automatically rendered in this div because of the ``renderTo``
-  option.  (This option can be left out and panels rendered manually, if desired.)
+  option. (This option can be left out and panels rendered manually, if
+  desired.)
 
 .. _ext-basic-layout:
 
@@ -87,29 +88,28 @@
 ``Ext.Panel`` built above is the most common kind of container.  You
 can nest panels using the ``items`` property.  For example:
 
-    .. code-block::
-       html
+.. code-block:: javascript
 
-       Ext.onReady(function(){
-            var myPanel = new Ext.Panel({
-                title: 'Top level',
-                layout: 'border',
-                items: [{
-                        xtype:'panel',
-                        title:'Sub1',
-                        html:'Contents of sub panel 1',
-                        region: 'east'
-                    },{
-                        xtype:'panel',
-                        title: 'Sub2',
-                        html:'Contents of sub panel 2',
-                        region: 'center'
-                }],
-                width:300,
-                height:200,
-                renderTo:'panelDiv'
-            });        
-       });
+    Ext.onReady(function(){
+        var myPanel = new Ext.Panel({
+            title: 'Top level',
+            layout: 'border',
+            items: [{
+                xtype:'panel',
+                title:'Sub1',
+                html:'Contents of sub panel 1',
+                region: 'east'
+            },{
+                xtype:'panel',
+                title: 'Sub2',
+                html:'Contents of sub panel 2',
+                region: 'center'
+            }],
+            width:300,
+            height:200,
+            renderTo:'panelDiv'
+        });        
+    });
 
 This code introduces some new concepts:
 
@@ -131,26 +131,4 @@
 Layout Browser
 <http://extjs.com/deploy/dev/examples/layout-browser/layout-browser.html>`_
 , which demonstrates each layout and provides sample code.
-  
 
-.. _ext-trees:
-
-Trees, Nodes, and Childnodes
-============================
-
-[tba]
-
-.. _ext-grid-store:
-
-Grid and Store
-==============
-
-[working with records from a reader]
-
-
-.. _ext-events:
-
-Events
-======
-
-[from a geoxt perspective]

Modified: sandbox/ahocevar/playground/trunk/docsrc/primers/openlayers-primer.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/primers/openlayers-primer.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/primers/openlayers-primer.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -4,50 +4,80 @@
  Primer: OpenLayers
 ====================
 
-The OpenLayers mapping library is the key component of GeoExt, performing the core map-related functions of every GeoExt-based application. To get up to speed with GeoExt, let's discover some OpenLayers basics.
+The OpenLayers mapping library is the key component of GeoExt, performing the
+core map-related functions of every GeoExt-based application. To get up to speed
+with GeoExt, let's discover some OpenLayers basics.
 
 Layers
 ======
 
-As its name suggests, OpenLayers manages a list of layers that together form a web-based mapping client. Each layer represents a different set of data. For instance, one layer might be responsible for displaying the boundary of a country.  Another layer responsible for that country's roads.
+As its name suggests, OpenLayers manages a list of layers that together form a
+web-based mapping client. Each layer represents a different set of data. For
+instance, one layer might be responsible for displaying the boundary of a
+country. Another layer responsible for that country's roads.
 
-OpenLayers contains many types of layers (you can see them all at the `OpenLayers website <http://trac.openlayers.org/browser/trunk/openlayers/lib/OpenLayers/Layer>`_). For this primer, we'll focus on two different layer types: ``WMS`` and ``Vector``.
+OpenLayers contains many types of layers (you can see them all at the
+`OpenLayers website
+<http://trac.openlayers.org/browser/trunk/openlayers/lib/OpenLayers/Layer>`_).
+For this primer, we'll focus on two different layer types: ``WMS`` and
+``Vector``.
 
 The WMS Layer
-~~~~~~~~~~~~~
+-------------
 
-This is the canonical layer type found in almost all GeoExt applications, where one or more images are used to display map-related information to the user. This type is named 'WMS' because it implements the `Web Map Service <http://www.opengeospatial.org/standards/wms>`_ standard set by the `Open Geospatial Consortium. <http://www.opengeospatial.org/>`_
+This is the canonical layer type found in almost all GeoExt applications, where
+one or more images are used to display map-related information to the user. This
+type is named 'WMS' because it implements the `Web Map Service
+<http://www.opengeospatial.org/standards/wms>`_ standard set by the `Open
+Geospatial Consortium. <http://www.opengeospatial.org/>`_
 
-If you followed the :doc:`/tutorials/quickstart` guide, you will have already encountered a ``MapPanel`` and created your very own WMS layer. Let's dissect what you did:
+If you followed the :doc:`/tutorials/quickstart` guide, you will have already
+encountered a ``MapPanel`` and created your very own WMS layer. Let's dissect
+what you did:
 
-    .. code-block::
-       javascript
-       :linenos:
-
-       var layer = new OpenLayers.Layer.WMS(
-           "Blue Marble",
-           "http://sigma.openplans.org/geoserver/wms?",
-           {layers: "bluemarble"}
-       );
-       map.addLayer(layer);
+    .. code-block:: javascript
+        :linenos:
     
-This tells OpenLayers that you'd like to create a new WMS layer referenced by the ``layer`` variable, and that you'd like to add that layer
-to the map. In this case, we're adding the `Blue Marble data set <http://earthobservatory.nasa.gov/Features/BlueMarble/>`_ provided by NASA.
+        var layer = new OpenLayers.Layer.WMS(
+            "Global Imagery",
+            "http://maps.opengeo.org/geowebcache/service/wms",
+            {layers: "bluemarble"}
+        );
+        map.addLayer(layer);
+    
+This tells OpenLayers that you'd like to create a new WMS layer referenced by
+the ``layer`` variable, and that you'd like to add that layer to the map. In
+this case, we're adding the `Blue Marble data set
+<http://earthobservatory.nasa.gov/Features/BlueMarble/>`_ provided by NASA.
 
-In **line 2** we provide "Blue Marble" as the name of the layer. This can be anything, and is only used to reference the layer on screen.
+In **line 2** we provide "Global Imagery" as the name of the layer. This can be
+anything, and is only used to reference the layer on screen.
 
-In **line 3** we provide the location of the WMS server tasked with providing the images. Here, we use a GeoServer instance located at ``sigma.openplans.org``\ .
+In **line 3** we provide the location of the WMS server tasked with providing
+the images. Here, we use a GeoWebCache instance located at
+``maps.opengeo.org``\ .
 
-In **line 4** we provide extra parameters for the WMS server. Since many servers host different data sets, we need to specify which set we'd like. We do this by creating a new object and setting the ``layers`` property to ``"bluemarble"``\ , the identifier for the Blue Marble data set.
+In **line 4** we provide extra parameters for the WMS server. Since many servers
+host different data sets, we need to specify which set we'd like. We do this by
+creating a new object and setting the ``layers`` property to ``"bluemarble"``\ ,
+the identifier for the Blue Marble data set.
 
-Note that ``layers`` isn't the only WMS parameter we can provide. You can find out more in the `OpenLayers API Documentation`_, by selecting 'Layer' and then 'WMS' in the navigation.
+Note that ``layers`` isn't the only WMS parameter we can provide. You can find
+out more in the `OpenLayers API Documentation`_, by selecting 'Layer' and then
+'WMS' in the navigation.
 
 And that's it! Now let's move on to the vector layer.
 
 The Vector Layer
-~~~~~~~~~~~~~~~~
+----------------
 
-The WMS Layer, and many of the layer types provided by OpenLayers, use raster files (images like JPG, GIF, and PNG) to display maps.  However, OpenLayers can also render map features directly in the browser, simply by adding an ``OpenLayers.Layer.Vector`` to the map.  This is useful when displaying data from an OGC `Web Feature Service <http://www.opengeospatial.org/standards/wfs>`, a KML document, or even sketched in by the user.  Here's an example that generates some random data and displays it in a vector layer::
+The WMS Layer, and many of the layer types provided by OpenLayers, use raster
+files (images like JPG, GIF, and PNG) to display maps. However, OpenLayers can
+also render map features directly in the browser, simply by adding an
+``OpenLayers.Layer.Vector`` to the map. This is useful when displaying data from
+an OGC `Web Feature Service <http://www.opengeospatial.org/standards/wfs>`, a
+KML document, or even sketched in by the user. Here's an example that generates
+some random data and displays it in a vector layer::
 
     var vectorLayer = new OpenLayers.Layer.Vector();
     for (var i = 0; i < 10; i++){
@@ -64,261 +94,289 @@
     var map = new OpenLayers.Map();
     map.addLayer(vectorLayer);
 
-While OpenLayers provides customized vector layers for loading data from existing sources, the GeoExt team recommends that you use the generic vector layer and populate it using :class:`GeoExt.data.FeatureStore`\ .  For more information on doing this, see :doc:`/tutorials/remote-features-tutorial`\ .
+While OpenLayers provides customized vector layers for loading data from
+existing sources, the GeoExt team recommends that you use the generic vector
+layer and populate it using :class:`GeoExt.data.FeatureStore`\ . For more
+information on doing this, see :doc:`/tutorials/remote-features-tutorial`\ .
 
 Other Layers
 ------------
 
-WMS and Vector are not the only layer types in OpenLayers.  There are plenty more available, including Google Maps, Virtual Earth, and many more.  Browse the `OpenLayers API documentation <http://dev.openlayers.org/apidocs>`_ for more information. 
+WMS and Vector are not the only layer types in OpenLayers. There are plenty more
+available, including Google Maps, Virtual Earth, and many more. Browse the
+`OpenLayers API documentation <http://dev.openlayers.org/apidocs>`_ for more
+information. 
 
 Controls
 ========
 
-Although OpenLayers is great at managing layers, it also provides a way to interact with those layers, primarily through the use of controls.
+Although OpenLayers is great at managing layers, it also provides a way to
+interact with those layers, primarily through the use of controls.
 
-Controls are primary user interface elements and/or API hooks that control and manage interaction with an OpenLayers map. For instance, panning and navigating a map is handled by the ``OpenLayers.Control.Navigation`` control. If you want a zoom bar in addition to zoom buttons, you'd add a ``PanZoomBar``
-control. If you then want to see where you've navigated, you'd use the ``NavigationHistory`` control.
+Controls are primary user interface elements and/or API hooks that control and
+manage interaction with an OpenLayers map. For instance, panning and navigating
+a map is handled by the ``OpenLayers.Control.Navigation`` control. If you want a
+zoom bar in addition to zoom buttons, you'd add a ``PanZoomBar`` control. If you
+then want to see where you've navigated, you'd use the ``NavigationHistory``
+control.
 
-Each control provides different and unique functionality. For this primer, we'll focus only on the ``NavigationHistory`` control.
+Each control provides different and unique functionality. For this primer, we'll
+focus only on the ``NavigationHistory`` control.
 
 
 NavigationHistory Control
-~~~~~~~~~~~~~~~~~~~~~~~~~
+-------------------------
 
-Take a look at the OpenLayers `NavigationHistory control example <http://openlayers.org/dev/examples/navigation-history.html>`_. 
-If you view the source, you'll come across code like this:
+Take a look at the OpenLayers `NavigationHistory control example
+<http://openlayers.org/dev/examples/navigation-history.html>`_. If you view the
+source, you'll come across code like this:
 
-    .. code-block::
-       html
+    .. code-block:: javascript
        
-       var map, nav, panel;
-
-       //...
-            
-       map = new OpenLayers.Map('map');
-
-       nav = new OpenLayers.Control.NavigationHistory();
-       map.addControl(nav);
+        var map = new OpenLayers.Map('map');
+        var nav = new OpenLayers.Control.NavigationHistory();
+        map.addControl(nav);
        
-The above code is fairly straightforward. First create a map, then a ``NavigationHistory`` control, and then finally add that control to the map.
-If you were to then look at your map in a web browser, you would only see the layers that you had added -- no special user interface elements
-for exploring the navigation history.
+The above code is fairly straightforward. First create a map, then a
+``NavigationHistory`` control, and then finally add that control to the map. If
+you were to then look at your map in a web browser, you would only see the
+layers that you had added -- no special user interface elements for exploring
+the navigation history.
 
-This is because without more intervention, the NavigationHistory control only provides an API allowing you to scroll through
-the history using a programmable interface.
+This is because without more intervention, the NavigationHistory control only
+provides an API allowing you to scroll through the history using a programmable
+interface.
 
-But the ``NavigationHistory`` control also provides a user interface. Let's continue on through the example:
+But the ``NavigationHistory`` control also provides a user interface. Let's
+continue on through the example:
 
-    .. code-block::
-       html
+    .. code-block:: javascript
        
-       panel = new OpenLayers.Control.Panel(
-           {div: document.getElementById("panel")}
-       );
-       panel.addControls([nav.next, nav.previous]);
-       map.addControl(panel);
+        panel = new OpenLayers.Control.Panel({
+            div: document.getElementById("panel")
+        });
+        panel.addControls([nav.next, nav.previous]);
+        map.addControl(panel);
        
-To expose this interface, we first create a ``Panel`` control, and then add the ``next`` and ``previous`` buttons to the panel giving the user 
-something to click on. We finally add the panel to the map.
+To expose this interface, we first create a ``Panel`` control, and then add the
+``next`` and ``previous`` buttons to the panel giving the user something to
+click on. We finally add the panel to the map.
 
 Now try the example again in your browser. *Beautiful ain't it?*
 
 Initialization w/ Controls
-~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------
 
-In the above examples, we only added controls to the map using the ``map.addControl()`` method. Often, controls are added when the map
-is initialized bypassing the ``map.addControl()`` method. This is done simply by using the ``controls`` key and passing an array 
-of controls, as seen below.
+In the above examples, we only added controls to the map using the
+``map.addControl()`` method. Often, controls are added when the map is
+initialized bypassing the ``map.addControl()`` method. This is done simply by
+using the ``controls`` key and passing an array of controls, as seen below.
 
-    .. code-block::
-       html
+    .. code-block:: javascript
        
-       var map = new OpenLayers.Map({
+        var map = new OpenLayers.Map({
             controls: [
                 new OpenLayers.Control.Navigation(),
                 new OpenLayers.Control.Measure()
             ]
-       });
+        });
        
-.. note:: If you use the ``controls`` key, **you will not be given the default controls**  when initializing the map.
-   You will have to add those controls yourself instead. `Find out more. <http://docs.openlayers.org/library/controls.html>`_
+.. note:: If you use the ``controls`` key, **you will not be given the default
+    controls** when initializing the map. You will have to add those controls
+    yourself instead. `Find out more.
+    <http://docs.openlayers.org/library/controls.html>`_
 
 More Controls
-~~~~~~~~~~~~~
+--------------
 
 You can find more controls by 
-`browsing the OpenLayers source code <http://trac.openlayers.org/browser/trunk/openlayers/lib/OpenLayers/Control>`_ or by reading
-`OpenLayers' Control documentation <http://docs.openlayers.org/library/controls.html>`_.
+`browsing the OpenLayers source code
+<http://trac.openlayers.org/browser/trunk/openlayers/lib/OpenLayers/Control>`_
+or by reading `OpenLayers' Control documentation
+<http://docs.openlayers.org/library/controls.html>`_.
 
 
 
 Events
 ======
 
-Events are the main mechanism for notifying multiple objects that something has happened. For instance, the ``NavigationHistory``
-control listens to the map's ``zoomend`` event to save the user's zoom history for a later date; similarly, other objects may
-listen to the same event without interfering or knowing about the ``NavigationHistory`` control. This makes events very powerful, 
-allowing objects to perform their desired function while decreasing coupling within OpenLayers and Ext applications.
+Events are the main mechanism for notifying multiple objects that something has
+happened. For instance, the ``NavigationHistory`` control listens to the map's
+``zoomend`` event to save the user's zoom history for a later date; similarly,
+other objects may listen to the same event without interfering or knowing about
+the ``NavigationHistory`` control. This makes events very powerful, allowing
+objects to perform their desired function while decreasing coupling within
+OpenLayers and Ext applications.
 
-Both GeoExt and OpenLayers make extensive use of events. However, the OpenLayers events are slightly different from those in
-GeoExt, though they provide the same functionality. Let's explore those differences.
+Both GeoExt and OpenLayers make extensive use of events. However, the OpenLayers
+events are slightly different from those in GeoExt, though they provide the same
+functionality. Let's explore those differences.
 
 GeoExt Events
-~~~~~~~~~~~~~
+-------------
 
-GeoExt uses the event library that comes standard with Ext. GeoExt events are synonymous with Ext events.
+GeoExt uses the event library that comes standard with Ext. GeoExt events are
+synonymous with Ext events.
 
-Ext events can be used in any Ext or GeoExt components that extend the ``Ext.util.Observable`` class.
-`More here. <http://www.slideshare.net/sdhjl2000/ext-j-s-observable>`_
+Ext events can be used in any Ext or GeoExt components that extend the
+``Ext.util.Observable`` class. `More here.
+<http://www.slideshare.net/sdhjl2000/ext-j-s-observable>`_
 
-To throw an event in any component that extends ``Ext.util.Observable``, you must first tell the component that the event may be thrown.
-For instance, in a custom ``Ext.Panel`` class, this is done using the ``addEvents()`` method below.
+To throw an event in any component that extends ``Ext.util.Observable``, you
+must first tell the component that the event may be thrown. For instance, in a
+custom ``Ext.Panel`` class, this is done using the ``addEvents()`` method below.
 
-    .. code-block::
-       html
-       
-       var MyPanel = Ext.Extend(Ext.Panel, {
-            initComponent: function() {
-                // ...
-                this.addEvents("event1" /*, "event2", ... etc.*/ ); 
-                
-                MyPanel.superclass.initComponent.call(this);
-            }
-       });
+.. code-block:: javascript
+   
+    var MyPanel = Ext.Extend(Ext.Panel, {
+        initComponent: function() {
+            // ...
+            this.addEvents("event1" /*, "event2", ... etc.*/ ); 
+            
+            MyPanel.superclass.initComponent.call(this);
+        }
+    });
 
 Finally triggering the event is easy: 
 
-    .. code-block::
-       html
-       
-       var MyPanel = Ext.Extend(Ext.Panel, {
-            
-            // ...
-            
-            myFunction: function() {
-                var arg1 = "somevalue"
-                
-                this.fireEvent("event1", arg1 /*, arg2, ... etc. */);
-            }
-       });
+.. code-block:: javascript
+   
+    var MyPanel = Ext.Extend(Ext.Panel, {
+         
+        // ...
+         
+        myFunction: function() {
+            var arg1 = "somevalue";
+            this.fireEvent("event1", arg1 /*, arg2, ... etc. */);
+        }
+    });
 
-Great! Now in order for the event to be useful, we have to listen to it. Below is an example of adding two listeners to an instance
-of ``MyPanel`` using the ``on()`` function, and then finally triggering the event by calling ``myFunction()``. 
+Great! Now in order for the event to be useful, we have to listen to it. Below
+is an example of adding two listeners to an instance of ``MyPanel`` using the
+``on()`` function, and then finally triggering the event by calling
+``myFunction()``. 
 
-    .. code-block::
-       html
-       
-       var panel = new MyPanel(/* ... */);
-       
-       // First listener.
-       panel.on("event1", function(arg1) {
-            alert("First listener responded. Got " + arg1 + "!");
-       });
-       
-       // Second listener.
-       panel.on("event1", function(arg1) {
-            alert("Second listener responded. Got " + arg1 + "!");
-       });
+.. code-block:: javascript
+   
+    var panel = new MyPanel(/* ... */);
+    
+    // First listener.
+    panel.on("event1", function(arg1) {
+        alert("First listener responded. Got " + arg1 + "!");
+    });
+    
+    // Second listener.
+    panel.on("event1", function(arg1) {
+        alert("Second listener responded. Got " + arg1 + "!");
+    });
 
-       panel.myFunction();
+    panel.myFunction();
        
-.. note:: The ``on()`` function takes an optional third parameter that specifies the scope of the listening function. If given, the ``this``
-   identifier within the listening function will refer to the object passed.
+.. note:: The ``on()`` function takes an optional third parameter that specifies
+    the scope of the listening function. If given, the ``this`` identifier
+    within the listening function will refer to the object passed.
    
 And that's it! Now let's see how to do the same thing in OpenLayers.
 
 OpenLayers Events
-~~~~~~~~~~~~~~~~~
+-----------------
 
-OpenLayers provides similar functionality as the ``Ext.util.Observable`` class, but it does so using the ``OpenLayers.Events`` class.
-Unlike ``Ext.util.Observable``, OpenLayers classes do not extend ``OpenLayers.Events``.
+OpenLayers provides similar functionality as the ``Ext.util.Observable`` class,
+but it does so using the ``OpenLayers.Events`` class. Unlike
+``Ext.util.Observable``, OpenLayers classes do not extend ``OpenLayers.Events``.
 
-Instead, it is customary for OpenLayers classes to create an attribute called ``events`` that is an instance of ``OpenLayers.Events``, 
-as per the code below.
+Instead, it is customary for OpenLayers classes to create an attribute called
+``events`` that is an instance of ``OpenLayers.Events``, as per the code below.
 
-    .. code-block::
-       html
-       
-       var MyControl = new OpenLayers.Class(OpenLayers.Control, {
+.. code-block:: javascript
+   
+    var MyControl = new OpenLayers.Class(OpenLayers.Control, {
 
-            events: null,
+        events: null,
+        
+        initialize: function() {
+            this.events = new OpenLayers.Events(
+                this,
+                null,
+                ["event1" /*, "event2", ... etc. */]
+                false
+            );
             
-            initialize: function() {
-                this.events = new OpenLayers.Events(
-                    this,
-                    null,
-                    ["event1" /*, "event2", ... etc. */]
-                    false
-                );
-                
-                OpenLayers.Control.prototype.initialize.call(this);
-            }
-       });
+            OpenLayers.Control.prototype.initialize.call(this);
+        }
+    });
        
-The first parameter to the ``OpenLayers.Events`` constructor is the object that will 'own' these events -- in other words, the caller
-that triggers the event. In situations like the example above, it is usually ``this``.
+The first parameter to the ``OpenLayers.Events`` constructor is the object that
+will 'own' these events -- in other words, the caller that triggers the event.
+In situations like the example above, it is usually ``this``.
 
-The second parameter specifies a ``div`` that will listen to events thrown by the browser. Here, this functionality is ignored; see the note
-below.
+The second parameter specifies a ``div`` that will listen to events thrown by
+the browser. Here, this functionality is ignored; see the note below.
 
-The third parameter is an array specifying the events that this ``OpenLayers.Events`` object can throw. This is analogous to 
-``Ext.util.Observable``'s ``addEvents()`` method, and can accept any number of events.
+The third parameter is an array specifying the events that this
+``OpenLayers.Events`` object can throw. This is analogous to
+``Ext.util.Observable``'s ``addEvents()`` method, and can accept any number of
+events.
 
-The fourth parameter is the ``fallthrough``, a boolean that is related to the second parameter above. For our purposes, we'll leave
-it as ``false``.
+The fourth parameter is the ``fallthrough``, a boolean that is related to the
+second parameter above. For our purposes, we'll leave it as ``false``.
 
-.. note:: The ``OpenLayers.Events`` class handles both browser events like when the window resizes, as well
-   as handling developer-created events like ``event1`` above. This makes initializing an ``OpenLayers.Events`` object fairly mucky,
-   though using it like we did above is nearly the same. See more below. 
+.. note:: The ``OpenLayers.Events`` class handles both browser events like when
+    the window resizes, as well as handling developer-created events like
+    ``event1`` above. This makes initializing an ``OpenLayers.Events`` object
+    fairly mucky, though using it like we did above is nearly the same. See more
+    below. 
 
-Triggering an event is just as easy as Ext's ``fireEvent()``, except here we use ``triggerEvent()``:
+Triggering an event is just as easy as Ext's ``fireEvent()``, except here we use
+``triggerEvent()``:
 
-    .. code-block::
-       html
-       
-       var MyControl = new OpenLayers.Class(OpenLayers.Control, {
+.. code-block:: javascript
+   
+    var MyControl = new OpenLayers.Class(OpenLayers.Control, {
 
-            // ...
-            
-            myFunction: function() {
-                var evt = {
-                    arg1: "somevalue" /*, arg2: ..., ... etc.*/
-                }
-                this.events.triggerEvent("event1", evt);
+        // ...
+        
+        myFunction: function() {
+            var evt = {
+                arg1: "somevalue" /*, arg2: ..., ... etc.*/
             }
-       });
+            this.events.triggerEvent("event1", evt);
+        }
+    });
        
-.. note:: ``OpenLayers.Events`` passes data to listeners using a single object with parameters -- otherwise called
-   'the event object' -- instead of passing function arguments like Ext. All listener functions, then, should only expect 
-   one named argument. See example below.
+.. note:: ``OpenLayers.Events`` passes data to listeners using a single object
+    with properties -- otherwise called 'the event object' -- instead of passing
+    function arguments like Ext. All listener functions, then, should only
+    expect one named argument. See example below.
 
 Finally, let's add two listeners and call ``myFunction()``:
 
-    .. code-block::
-       html
-       
-       var control = new MyControl(/* ... */);
-       
-       // First listener.
-       control.events.register("event1", null, function(evt) {
-            alert("First listener responded. Got " + evt.arg1 + "!");
-       });
-       
-       // Second listener.
-       control.events.register("event1", null, function(evt) {
-            alert("Second listener responded. Got " + evt.arg1 + "!");
-       });
+.. code-block:: javascript
+   
+    var control = new MyControl(/* ... */);
+    
+    // First listener.
+    control.events.register("event1", null, function(evt) {
+        alert("First listener responded. Got " + evt.arg1 + "!");
+    });
+   
+    // Second listener.
+    control.events.register("event1", null, function(evt) {
+        alert("Second listener responded. Got " + evt.arg1 + "!");
+    });
 
-       control.myFunction();
+    control.myFunction();
        
-.. note:: Like Ext's ``on()`` function, OpenLayer's ``register()`` function also takes an optional ``scope`` value in order to specify
-   the scope of the listening function, but it expects this value as the second parameter passed to the function. 
-   We don't have a scope for our listeners in this example, hence the ``null`` parameters.
+.. note:: Like Ext's ``on()`` function, OpenLayer's ``register()`` function also
+    takes an optional ``scope`` value in order to specify the scope of the
+    listening function, but it expects this value as the second parameter passed
+    to the function. We don't have a scope for our listeners in this example,
+    hence the ``null`` parameters.
    
 And that's it! Events in GeoExt should now be old hat. Fire away!
 
 More Information
-~~~~~~~~~~~~~~~~
+----------------
 
 More information about both event types can be found at the links below:
 

Modified: sandbox/ahocevar/playground/trunk/docsrc/tutorials/control-button-tutorial.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/tutorials/control-button-tutorial.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/tutorials/control-button-tutorial.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -4,21 +4,38 @@
 Map Tool Tutorial
 ============================
 
-Okay, so now you know how to :doc:`add a map to a web page <mappanel-tutorial>` and load some data into it. Your users can drag and zoom to their hearts' content.  You even followed the :doc:`layertree-tutorial` so they could switch between different datasets. (You did follow that tutorial, right?)  But now you want to do more than just view some pretty pictures.  You want to let your users analyze data, or get more info about particular features on your map, or just draw things.  Basically, you want to give them some **tools**\ .
+Okay, so now you know how to :doc:`add a map to a web page <mappanel-tutorial>`
+and load some data into it. Your users can drag and zoom to their hearts'
+content. You even followed the :doc:`layertree-tutorial` so they could switch
+between different datasets. (You did follow that tutorial, right?) But now you
+want to do more than just view some pretty pictures. You want to let your users
+analyze data, or get more info about particular features on your map, or just
+draw things. Basically, you want to give them some **tools**\ .
 
-.. note:: This tutorial makes heavy use of the OpenLayers mapping library.  If you're not familiar with it, you might want to take a look at the :doc:`/primers/openlayers-primer` before moving forward.
+.. note:: This tutorial makes heavy use of the OpenLayers mapping library.  If
+    you're not familiar with it, you might want to take a look at the
+    :doc:`/primers/openlayers-primer` before moving forward.
 
 OpenLayers Controls
 ===================
 
-In `OpenLayers <http://openlayers.org/>`_\ , these tools for interacting with a map are called ``Controls``\ .  For the purposes of this tutorial, we'll just stick to the ``Measure`` control, a handy little tool that lets you draw a line on the map and tells you its length in real-world units.
+In `OpenLayers <http://openlayers.org/>`_\ , these tools for interacting with a
+map are called ``Controls``\ . For the purposes of this tutorial, we'll just
+stick to the ``Measure`` control, a handy little tool that lets you draw a line
+on the map and tells you its length in real-world units.
 
 .. seealso:: The OpenLayer API documentation for a comprehensive listing of standard controls.
 
 ExtJS Buttons
 =============
 
-While OpenLayers ``Control``\ s provide a number of excellent ways of interacting with maps, they have only limited support for actually manipulating the controls; ie, choosing which tool to use and providing user feedback about which tool is active.  ExtJS provides a richer array of options for managing tools.  Here is the idiomatic way to create an ``Ext.Button`` which activates and deactivates an OpenLayers ``Control``\ , and stays depressed while the control is active::
+While OpenLayers ``Control``\ s provide a number of excellent ways of
+interacting with maps, they have only limited support for actually manipulating
+the controls; ie, choosing which tool to use and providing user feedback about
+which tool is active. ExtJS provides a richer array of options for managing
+tools. Here is the idiomatic way to create an ``Ext.Button`` which activates and
+deactivates an OpenLayers ``Control``\ , and stays depressed while the control
+is active::
     
     var control = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, {
         eventListeners: {
@@ -41,7 +58,9 @@
         }
     });
 
-The ``Button`` can be added to an ExtJS toolbar or to a panel, in whatever layout we choose.  For example, you could add the button to a ``MapPanel``\ 's top toolbar::
+The ``Button`` can be added to an ExtJS toolbar or to a panel, in whatever
+layout we choose. For example, you could add the button to a ``MapPanel``\ 's
+top toolbar::
 
     mapPanel.getTopToolbar().addButton(button);
    
@@ -49,7 +68,15 @@
 There Can Be Only One
 =====================
 
-In general, when you have multiple tools associated with a map, you want to avoid having more than one tool active at the same time.  It would be somewhat confusing if the user starts deleting data while he or she is trying to find the distance from one end of town to the other!  Fortunately, ExtJS makes it very simple to ensure that only one toggle button from a group is toggled at a time, through the ``toggleGroup`` property of the ``Button`` object.  This is a string identifying a group of buttons, only one of which can be pressed at a time.  Let's extend our example from before, this time adding the option to measure area instead of length::
+In general, when you have multiple tools associated with a map, you want to
+avoid having more than one tool active at the same time. It would be somewhat
+confusing if the user starts deleting data while he or she is trying to find the
+distance from one end of town to the other! Fortunately, ExtJS makes it very
+simple to ensure that only one toggle button from a group is toggled at a time,
+through the ``toggleGroup`` property of the ``Button`` object. This is a string
+identifying a group of buttons, only one of which can be pressed at a time.
+Let's extend our example from before, this time adding the option to measure
+area instead of length::
     
     var length = new OpenLayers.Control.Measure(OpenLayers.Handler.Path, {
         eventListeners: {
@@ -98,4 +125,5 @@
         }
     });
 
-All right, you've got all you need to add and activate tools to help users get the most out of your maps.
+All right, you've got all you need to add and activate tools to help users get
+the most out of your maps.

Modified: sandbox/ahocevar/playground/trunk/docsrc/tutorials/layertree-tutorial.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/tutorials/layertree-tutorial.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/tutorials/layertree-tutorial.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -2,14 +2,28 @@
 Layer Tree Tutorial
 ============================
 
-Often when presenting users with an interactive map, it is useful to allow them to control the visible layers.  In this tutorial, we examine the use of :class:`GeoExt.tree.LayerContainer` with the stock ``Ext.tree.TreePanel`` class to accommodate toggling visibility of layers and rearranging their drawing order.
+Often when presenting users with an interactive map, it is useful to allow them
+to control the visible layers. In this tutorial, we examine the use of
+:class:`GeoExt.tree.LayerContainer` with the stock ``Ext.tree.TreePanel`` class
+to accommodate toggling visibility of layers and rearranging their drawing
+order.
 
-.. note:: Before starting this tutorial, you should have a working :class:`GeoExt.MapPanel` in your page.   The :doc:`mappanel-tutorial` will help you set one up if you don't already have one.
+.. note:: Before starting this tutorial, you should have a working
+    :class:`GeoExt.MapPanel` in your page. The :doc:`mappanel-tutorial` will
+    help you set one up if you don't already have one.
 
 Start With a Map
 ================
 
-Let's assume you already have a :class:`GeoExt.MapPanel` on your page with some layers.  In the :doc:`mappanel-tutorial`\ , we discussed how you can use the ``layers`` property of the ``MapPanel`` to add, remove, and modify the layers of the map as well as monitor the layer list for changes.  This is more than sufficient to display a 'live' list of layers in an ``Ext.grid.GridPanel``\ .  The :class:`GeoExt.tree.LayerContainer` is another component that can listen to changes to the map's layer list.  However, rather than an independent panel, the ``LayerContainer`` is a node that must be contained in an ``Ext.tree.TreePanel`` to be displayed.  Here's an example rendering a layer tree to a ``div``:
+Let's assume you already have a :class:`GeoExt.MapPanel` on your page with some
+layers. In the :doc:`mappanel-tutorial`\ , we discussed how you can use the
+``layers`` property of the ``MapPanel`` to add, remove, and modify the layers of
+the map as well as monitor the layer list for changes. This is more than
+sufficient to display a 'live' list of layers in an ``Ext.grid.GridPanel``\ .
+The :class:`GeoExt.tree.LayerContainer` is another component that can listen to
+changes to the map's layer list. However, rather than an independent panel, the
+``LayerContainer`` is a node that must be contained in an ``Ext.tree.TreePanel``
+to be displayed. Here's an example rendering a layer tree to a ``div``:
 
 .. code-block:: javascript
        
@@ -30,10 +44,155 @@
         root: layerList
     });
 
-``LayerContainer``\ s automatically add checkboxes that can be used to toggle the visibility of layers.  You can also enable drag-n-drop layer reordering by simply setting the ``enableDD`` property of the ``TreePanel``. 
+``LayerContainer``\ s automatically add checkboxes (radio buttons for base
+layers) that can be used to toggle the visibility of layers. You can also enable
+drag-n-drop layer reordering by simply setting the ``enableDD`` property of the
+``TreePanel``.
 
 Filtering
 =========
-Currently, the ``LayerContainer`` automatically pulls in all layers from the store and displays those with the ``displayInLayerSwitcher`` property set to true.  In the future (but before the robots take over) you will be able to filter out some layers by providing a filter function.  By adding multiple named and filtered ``LayerContainer``\ s to a ``TreePanel`` you will be able to provide logical organization to your layer trees.  In the meantime, you can directly instantiate :class:`GeoExt.LayerNode` to create tree nodes that can be added anywhere in a tree.  Keep in mind, however, that this approach does not allow for automatic drag-n-drop support.
+By default, the ``LayerContainer``'s ``LayerLoader`` automatically pulls in all layers from the store and displays those with the ``displayInLayerSwitcher``
+property set to true. You can provide your own filter function to the loader:
 
-.. seealso:: The ExtJS TreePanel `documentation <http://extjs.com/deploy/dev/docs/?class=Ext.tree.TreePanel>`_ and `examples <http://extjs.com/deploy/dev/examples/samples.html#sample-4>`_ for more information about customizing tree panels.
+.. code-block:: javascript
+
+    var layerList = new GeoExt.tree.LayerContainer({
+        text: 'Tasmania Layers',
+        layerStore: mapPanel.layers,
+        leaf: false, 
+        expanded: true,
+        loader: {
+            filter: function(record) {
+                return record.get("layer").name.indexOf("Tasmania") !== -1
+            }
+        }
+    });
+
+The above will only load layers with "Tasmania" in their name. By adding
+multiple named and filtered ``LayerContainer``\ s to a ``TreePanel`` you are
+able to provide logical organization to your layer trees. When ``enableDD`` is
+set to true on the tree, drag-n-drop will also work between filtered layer
+containers, as long as they have the same parent node. You can also directly
+instantiate :class:`GeoExt.tree.LayerNode` to create tree nodes that can be
+added anywhere in a tree. Keep in mind, however, that this approach does not
+allow for automatic drag-n-drop support.
+
+.. note::
+
+    There are two LayerContainer types with a preconfigured filter:
+    
+    * :class:`GeoExt.tree.BaseLayerContainer` will be populated only with layers
+      that have isBaseLayer set to true,
+    * :class:`GeoExt.tree.OverlayLayerContainer` will be populated only with
+      layers that have  isBaseLayer set to false.
+
+Visibility Grouping
+===================
+
+The concept of a base layer in OpenLayers is just a gruop of layers that are on
+the bottom of the layer stack, and only one can be visible at a time. In maps
+without base layers (when ``allOverlays`` is set to true, the latter can be
+enforced by configuring a ``checkedGroup`` on a LayerNode. Such a layer node
+will be rendered with a radio button instead of a check box. Of all layers
+configured with the same ``checkedGroup``, only one will be visible at a time:
+
+.. code-block:: javascript
+
+    var layerList = new GeoExt.tree.LayerContainer({
+        text: 'Tasmania Layers',
+        layerStore: mapPanel.layers,
+        leaf: false, 
+        expanded: true,
+        loader: {
+            filter: function(record) {
+                return record.get("layer").name.indexOf("Tasmania") !== -1
+            },
+            baseAttrs: {
+                checkedGroup: "tasmania"
+            }
+        }
+    });
+
+Layer Nodes with Additional Radio Buttons
+=========================================
+
+It is possible to render layer nodes with an additional radio button. This can
+be useful if an application uses the concept of an "active layer". The active
+layer can then be set by clicking its radio button:
+
+.. code-block:: javascript
+
+    var layerList = new GeoExt.tree.LayerContainer({
+        text: 'All Layers',
+        layerStore: mapPanel.layers,
+        leaf: false, 
+        expanded: true,
+        loader: {
+            baseAttrs: {
+                radioGroup: "active"
+            }
+        }
+    });
+    var registerRadio = function(node)
+        if(!node.hasListener("radiochange")) {
+            node.on("radiochange", function(node){
+                /* set your active layer here */
+            });
+        }
+    }
+    var layerTree = new Ext.tree.TreePanel({
+        title: 'Map Layers',
+        renderTo: 'layerTree',
+        root: layerList,
+        listeners: {
+            append: registerRadio,
+            insert: registerRadio
+        }
+    });
+
+The layer node fires the "radiochange" event when the radio button is clicked.
+The above snippet configures a listener for this event when a node is added to
+or inserted in the tree.
+
+Sub-Layers
+==========
+
+Layers that have a ``params`` property (like ``OpenLayers.Layer.WMS``) can be
+used to create sub-layers based on one of the ``params`` properties. This is
+useful to e.g. create sub-nodes from the layer object's "LAYERS" or "CQL_FILTER"
+param:
+
+.. code-block:: javascript
+
+    var groupLayer = new OpenLayers.Layer.WMS("Tasmania (Group Layer)",
+        "http://demo.opengeo.org/geoserver/wms", {
+            layers: [
+                "topp:tasmania_state_boundaries",
+                "topp:tasmania_water_bodies",
+                "topp:tasmania_cities",
+                "topp:tasmania_roads"
+            ],
+            transparent: true,
+            format: "image/gif"
+        }
+    );
+    var groupLayerNode = new GeoExt.tree.LayerNode({
+        layer: groupLayer,
+        leaf: false, 
+        expanded: true,
+        loader: {
+            param: "LAYERS"
+        }
+    });
+    
+.. note::
+    The :class:`GeoExt.tree.LayerParamLoader` does not add drag-n-drop support
+    to the sub-nodes it creates, so ``allowDrag`` and ``allowDrag`` should be
+    set to false for a :class:`GeoExt.tree.LayerNode` configured with a
+    :class:`GeoExt.class.LayerParamLoader`, unless you provide custom "move"
+    handlers.
+
+.. seealso:: The ExtJS TreePanel `documentation
+    <http://extjs.com/deploy/dev/docs/?class=Ext.tree.TreePanel>`_ and `examples
+    <http://extjs.com/deploy/dev/examples/samples.html#sample-4>`_ for more
+    information about customizing tree panels.

Modified: sandbox/ahocevar/playground/trunk/docsrc/tutorials/mappanel-tutorial.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/tutorials/mappanel-tutorial.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/tutorials/mappanel-tutorial.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -4,56 +4,82 @@
 ``MapPanel`` Tutorial
 ============================
 
-The :class:`GeoExt.MapPanel` is the heart of most GeoExt applications, displaying rendered data.  Leveraging the OpenLayers JavaScript mapping library, it can display rendered tiles from OWS services, perform client-side rendering in the browser, and use tiles from popular mapping services such as Google Maps or Virtual Earth.  In this tutorial, we explore ways that developers can customize the MapPanel.
+The :class:`GeoExt.MapPanel` is the heart of most GeoExt applications,
+displaying rendered data. Leveraging the OpenLayers JavaScript mapping library,
+it can display rendered tiles from OWS services, perform client-side rendering
+in the browser, and use tiles from popular mapping services such as Google Maps
+or Virtual Earth. In this tutorial, we explore ways that developers can
+customize the MapPanel.
 
-.. note:: It is recommended that you follow the :doc:`quickstart` tutorial before moving on to this one.  It really is quick; we'll wait for you.
+.. note:: 
+  It is recommended that you follow the :doc:`quickstart` tutorial
+  before moving on to this one. It really is quick; we'll wait for you.
 
 A Basic MapPanel
 ================
 
-Taking a look at the example code from the quickstart tutorial, we can see a very basic map configuration::
+Taking a look at the example code from the quickstart tutorial, we can see a
+very basic map configuration:
        
-       var map = new OpenLayers.Map();
-       var layer = new OpenLayers.Layer.WMS(
-           "Blue Marble",
-           "http://sigma.openplans.org/geoserver/wms?",
-           {layers: "bluemarble"}
-       );
-       map.addLayer(layer);
-        
-       var mapPanel = new GeoExt.MapPanel({
-           renderTo: 'gxmap',
-           height: 400,
-           width: 600,
-           map: map,
-           title: 'A Simple GeoExt Map'
-       });
+.. code-block:: javascript
+    :linenos:
 
+    var map = new OpenLayers.Map();
+    var layer = new OpenLayers.Layer.WMS(
+        "Global Imagery",
+        "http://maps.opengeo.org/geowebcache/service/wms",
+        {layers: "bluemarble"}
+    );
+    map.addLayer(layer);
+     
+    var mapPanel = new GeoExt.MapPanel({
+        renderTo: 'gxmap',
+        height: 400,
+        width: 600,
+        map: map,
+        title: 'A Simple GeoExt Map'
+    });
+
 Looking at this code we can see a few things going on:
 
-In **line 1** we instantiate an :class:`OpenLayers.Map`.  This isn't required by the MapPanel (it will create a Map for you if none is provided) but we want to customize our map a bit.
+In **line 1** we instantiate an :class:`OpenLayers.Map`. This isn't required by
+the MapPanel (it will create a Map for you if none is provided) but we want to
+customize our map a bit.
 
-In **lines 2-6** we create a new :class:`OpenLayers.Layer`.  This particular layer is a WMS layer, which uses tiles from the Blue Marble layer at http://sigma.openplans.org/. 
+In **lines 2-6** we create a new :class:`OpenLayers.Layer`. This particular
+layer is a WMS layer, which uses tiles from the Blue Marble layer at
+http://maps.opengeo.org/. 
 
 In **line 7** we add our new layer to the map.
 
 In **lines 9-15** we create a new map panel with several options:
 
-    renderTo
-       This works the same as ``renderTo`` in a normal :class:`Ext.Panel`; it can be an id string, DOM node, or :class:`Ext.Element` telling the MapPanel where on the page it should insert itself.
+    ``renderTo``
+       This works the same as ``renderTo`` in a normal :class:`Ext.Panel`; it
+       can be an id string, DOM node, or :class:`Ext.Element` telling the
+       MapPanel where on the page it should insert itself.
 
-    height, width
+    ``height``, ``width``
        These tell the map panel how much large it should draw itself.
 
-    map
-       This is an :class:`OpenLayers.Map` which will be used as the actual map inside the panel. 
+    ``map``
+       This is an :class:`OpenLayers.Map` which will be used as the actual map
+       inside the panel. 
 
-    title
-       This is the normal ``title`` property for ExtJS components.  It will be rendered nicely across the top of the panel.
+    ``title``
+       This is the normal ``title`` property for ExtJS components. It will be
+       rendered nicely across the top of the panel.
 
 Working with the MapPanel
 =========================
-While using ``OpenLayers.Map.addLayer()`` to add layers is a convenient way to customize the map, a hand-coded, static list of map layers is not always what we want.  In order to make manipulating the layer list more accessible to ExtJS widgets, the MapPanel exposes a `layers` property which is an :class:`Ext.data.Store` that will automatically be updated when layers are added, removed, changed, or reordered, with all of the Ext events that go with it.  We can use this to, for example, populate an :class:`Ext.grid.GridPanel` with a live list of layers in the map::
+While using ``OpenLayers.Map.addLayer()`` to add layers is a convenient way to
+customize the map, a hand-coded, static list of map layers is not always what we
+want. In order to make manipulating the layer list more accessible to ExtJS
+widgets, the MapPanel exposes a `layers` property which is an
+:class:`Ext.data.Store` that will automatically be updated when layers are
+added, removed, changed, or reordered, with all of the Ext events that go with
+it. We can use this to, for example, populate an :class:`Ext.grid.GridPanel`
+with a live list of layers in the map::
     
     new Ext.grid.GridPanel({
         renderTo: 'layerlist',
@@ -63,13 +89,20 @@
         columns: [{name: 'name', heading: 'Name'}]
     });
 
-.. highlight:: html
 
+In the HTML, you'll need to add a ``div`` for the grid panel to render itself in:
 
-In the HTML, you'll need to add a ``div`` for the grid panel to render itself in::
+.. code-block:: html
 
     <div id='layerlist'></div>
 
-More information on the :class:`Ext.grid.GridPanel` is available from the `ExtJS API documentation <http://extjs.com/deploy/dev/docs/?class=Ext.grid.GridPanel>`_.
+More information on the :class:`Ext.grid.GridPanel` is available from the `ExtJS
+API documentation
+<http://extjs.com/deploy/dev/docs/?class=Ext.grid.GridPanel>`_.
 
-.. note:: This code is only meant as an example to demonstrate the map panel's integration with Ext.  An :class:`Ext.tree.TreePanel` with :class:`GeoExt.tree.LayerNode`\ s is a a much nicer way to display the layers in a map, with optional support for hiding/showing layers and reordering.  The TreePanel approach is discussed in the :doc:`layertree-tutorial`.
+.. note:: 
+  This code is only meant as an example to demonstrate the map panel's
+  integration with Ext. An :class:`Ext.tree.TreePanel` with
+  :class:`GeoExt.tree.LayerNode`\ s is a a much nicer way to display the layers in
+  a map, with optional support for hiding/showing layers and reordering. The
+  TreePanel approach is discussed in the :doc:`layertree-tutorial`.

Modified: sandbox/ahocevar/playground/trunk/docsrc/tutorials/quickstart.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/tutorials/quickstart.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/tutorials/quickstart.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -15,127 +15,126 @@
 reasons, ExtJS cannot be included in the GeoExt download, so preparing
 GeoExt for use on your own web pages is a multi-step process:
 
-#. Download GeoExt from the :doc:`downloads page </downloads>`.  For the purposes of this
-   quickstart, the development version will be fine.
+#.  Download GeoExt from the :doc:`downloads page </downloads>`. For the purposes
+    of this quickstart, the development version will be fine.
 
-#. Download OpenLayers from http://openlayers.org/. 
+#.  Download OpenLayers 2.8 or later from http://openlayers.org/. 
 
-   .. note:: GeoExt 0.1 relies on features from OpenLayers 2.8.  Until OpenLayers 2.8 is released, you can use the latest release candidate (link directly to http://openlayers.org/api/2.8-rc2/OpenLayers.js)
+#.  Download ExtJS 2.2 from `the ExtJS website <http://extjs.com/products/extjs/download.php>`_.
 
-#. Download ExtJS 2.2 from `the ExtJS website <http://extjs.com/products/extjs/download.php>`_.
+#.  Place both unpacked libraries in a directory that is published by your web
+    server. For this tutorial, I will assume that this is the root of your web
+    server, so that GeoExt.js is at http://localhost/GeoExt/lib/GeoExt.js and
+    ext-all.js is at http://localhost/ext-2.2/ext-all.js
 
-#. Place both unpacked libraries in a directory that is published by your web server.  For this tutorial, I will assume that this is the root of your web server, so that GeoExt.js is at http://localhost/GeoExt/lib/GeoExt.js and ext-all.js is at http://localhost/ext-2.2/ext-all.js
+#.  Now you're ready to use GeoExt in your application!
 
-#. Now you're ready to use GeoExt in your application!
-
 .. note:: For production environments, the GeoExt team recommends that
-   you use compressed and minified builds of GeoExt and ExtJS to
-   optimize the download size of your page.  A generic minified build
-   containing all of GeoExt is available from the
-   :doc:`downloads page </downloads>`, but advanced users can build their
-   own.
+    you use compressed and minified builds of GeoExt and ExtJS to
+    optimize the download size of your page.  A generic minified build
+    containing all of GeoExt is available from the
+    :doc:`downloads page </downloads>`, but advanced users can build their
+    own.
 
 
 
 Basic Example
 =============
 
-let's build a simple web page that just embeds a map with interactive
+Let's build a simple web page that just embeds a map with interactive
 navigation.
 
-#. Include the ExtJS libraries in your web page.
+#.  Include the ExtJS libraries in your web page.
 
-    .. code-block::
-       xml
+    .. code-block:: html
+    
+        <script src="ext-2.2/adapter/ext/ext-base.js" type="text/javascript"></script>
+        <script src="ext-2.2/ext-all.js"  type="text/javascript"></script>
+        <link rel="stylesheet" type="text/css" href="ext-2.2/resources/ext-all.css"></link>
+        <script src="OpenLayers/OpenLayers.js" type="text/javascript"></script>
+        <script src="GeoExt/lib/GeoExt.js" type="text/javascript"></script>
+        <link rel="stylesheet" type="text/css" href="GeoExt/resources/geoext-all-debug.css"></link>
 
-       <script src="ext-2.2/adapter/ext/ext-base.js" type="text/javascript"></script>
-       <script src="ext-2.2/ext-all.js"  type="text/javascript"></script>
-       <link rel="stylesheet" type="text/css" href="ext-2.2/resources/ext-all.css"></link>
-       <script src="OpenLayers/OpenLayers.js" type="text/javascript"></script>
-       <script src="GeoExt/lib/GeoExt.js" type="text/javascript"></script>
-       <link rel="stylesheet" type="text/css" href="GeoExt/resources/geoext-all-debug.css"></link>
+#.  Create a ``<div>`` element in your web page with its ``id``
+    attribute set to ``gxmap``.  We will use the ``id`` to attach a
+    GeoExt component to the ``div``.
 
-#. Create a ``<div>`` element in your web page with its ``id``
-   attribute set to ``gxmap``.  We will use the ``id`` to attach a
-   GeoExt component to the ``div``.
+#.  Attach a ``MapPanel`` object to the ``div`` with some JavaScript code:
 
-#. Attach a ``MapPanel`` object to the ``div`` with some JavaScript code:
+    .. code-block:: html 
+    
+        <script type="text/javascript">
+            Ext.onReady(function() {
+                var map = new OpenLayers.Map();
+                var layer = new OpenLayers.Layer.WMS(
+                    "Global Imagery",
+                    "http://maps.opengeo.org/geowebcache/service/wms",
+                    {layers: "bluemarble"}
+                );
+                map.addLayer(layer);
+    
+                new GeoExt.MapPanel({
+                    renderTo: 'gxmap',
+                    height: 400,
+                    width: 600,
+                    map: map,
+                    title: 'A Simple GeoExt Map'
+                });
+            });
+        </script>
 
-    .. code-block::
-       html 
-
-       <script type="text/javascript">
-           Ext.onReady(function() {
-               var map = new OpenLayers.Map();
-               var layer = new OpenLayers.Layer.WMS(
-                   "Blue Marble",
-                   "http://sigma.openplans.org/geoserver/wms?",
-                   {layers: "bluemarble"}
-               );
-               map.addLayer(layer);
-
-               new GeoExt.MapPanel({
-                   renderTo: 'gxmap',
-                   height: 400,
-                   width: 600,
-                   map: map,
-                   title: 'A Simple GeoExt Map'
-               });
-           });
-       </script>
-
 The entire source of your page should look something like:
 
-    .. code-block::
-       html
+.. code-block:: html
 
-       <html>
-       <head>
+    <html>
+    <head>
 
-       <title> A Basic GeoExt Page </title>
-       <script src="ext-2.2/adapter/ext/ext-base.js" type="text/javascript"></script>
-       <script src="ext-2.2/ext-all.js"  type="text/javascript"></script>
-       <link rel="stylesheet" type="text/css" href="ext-2.2/resources/ext-all.css"></link>
-       <script src="OpenLayers/OpenLayers.js" type="text/javascript"></script>
-       <script src="GeoExt/lib/GeoExt.js" type="text/javascript"></script>
-       <link rel="stylesheet" type="text/css" href="GeoExt/resources/geoext-all-debug.css"></link>
+    <title> A Basic GeoExt Page </title>
+    <script src="ext-2.2/adapter/ext/ext-base.js" type="text/javascript"></script>
+    <script src="ext-2.2/ext-all.js"  type="text/javascript"></script>
+    <link rel="stylesheet" type="text/css" href="ext-2.2/resources/ext-all.css"></link>
+    <script src="OpenLayers/OpenLayers.js" type="text/javascript"></script>
+    <script src="GeoExt/lib/GeoExt.js" type="text/javascript"></script>
+    <link rel="stylesheet" type="text/css" href="GeoExt/resources/geoext-all-debug.css"></link>
 
-       <script type="text/javascript">
-           Ext.onReady(function() {
-               var map = new OpenLayers.Map();
-               var layer = new OpenLayers.Layer.WMS(
-                   "Blue Marble",
-                   "http://sigma.openplans.org/geoserver/wms?",
-                   {layers: "bluemarble"}
-               );
-               map.addLayer(layer);
+    <script type="text/javascript">
+        Ext.onReady(function() {
+            var map = new OpenLayers.Map();
+            var layer = new OpenLayers.Layer.WMS(
+                "Global Imagery",
+                "http://maps.opengeo.org/geowebcache/service/wms",
+                {layers: "bluemarble"}
+            );
+            map.addLayer(layer);
 
-               new GeoExt.MapPanel({
-                   renderTo: 'gxmap',
-                   height: 400,
-                   width: 600,
-                   map: map,
-                   title: 'A Simple GeoExt Map'
-               });
-           });
-       </script>
-       </head>
-       <body>
-       <div id="gxmap"></div>
-       </body>
-       </html>
+            new GeoExt.MapPanel({
+                renderTo: 'gxmap',
+                height: 400,
+                width: 600,
+                map: map,
+                title: 'A Simple GeoExt Map'
+            });
+        });
+    </script>
+    </head>
+    <body>
+    <div id="gxmap"></div>
+    </body>
+    </html>
 
-And that's it! You now have all of GeoExt, ready to bring your geospatial data to life.  Go forth and prosper!
+And that's it! You now have all of GeoExt, ready to bring your geospatial data
+to life. Go forth and prosper!
 
 Going Further
 =============
 
 From here, there are a wide variety of options available for making
 customized, highly interactive mapping applications with GeoExt.  To
-learn more take a look at :doc:`index`, :doc:`/examples/index` and
-:doc:`/lib/index`.  
+learn more take a look at :doc:`index`, :ref:`examples <examples>` and
+:doc:`/lib/index`.
 
-We also recommend reading :doc:`../primers/ext-primer` and :doc:`../primers/openlayers-primer` to
-become acquainted with the libraries that form the foundation of
-GeoExt.
+We also recommend reading :doc:`../primers/ext-primer` and
+:doc:`../primers/openlayers-primer` to become acquainted with the libraries that
+form the foundation of GeoExt.
 

Modified: sandbox/ahocevar/playground/trunk/docsrc/tutorials/remote-features-tutorial.rst
===================================================================
--- sandbox/ahocevar/playground/trunk/docsrc/tutorials/remote-features-tutorial.rst	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/docsrc/tutorials/remote-features-tutorial.rst	2010-01-11 12:47:52 UTC (rev 1710)
@@ -5,19 +5,33 @@
 Vector Data Tutorial
 ====================
 
-Base layers such as OpenStreetMap and Google Maps are generally distributed in pre-rendered tiles using file formats such as PNG or JPG.  While these are great for **displaying** maps, they are not very useful for getting at the data behind a map.  They don't allow you to provide functionality such as informational popups, selection and highlighting of individual features, and editing of data.  For these, you need to use **vector data**, provided through file formats such as KML, GeoJSON, or GML which provide information about each feature on the map, rather than just the pixels to put on the screen.
+Base layers such as OpenStreetMap and Google Maps are generally distributed in
+pre-rendered tiles using file formats such as PNG or JPG. While these are great
+for **displaying** maps, they are not very useful for getting at the data behind
+a map. They don't allow you to provide functionality such as informational
+popups, selection and highlighting of individual features, and editing of data.
+For these, you need to use **vector data**, provided through file formats such
+as KML, GeoJSON, or GML which provide information about each feature on the map,
+rather than just the pixels to put on the screen.
 
-.. note:: Modern web browsers impose a single-site restriction on JavaScript code to protect users from cross-site scripting attacks.  This means that if your GeoExt application is hosted on a different host or port from your vector data, you will need to configure a proxy service.
+.. note:: Web browsers impose a same origin policy on JavaScript code to protect
+    users from cross-site scripting attacks. This means that if your GeoExt
+    application is hosted on a different host or port from your vector data, you
+    will need to configure a proxy service.
 
 Reading KML
 ===========
 
-As an introduction to using vector data in GeoExt, let's create a simple map that displays data from a KML.  Copy :download:`this sample KML file <sundials.kml>` to the same directory with your GeoExt and Ext libraries.  Then we can load it with some JavaScript::
+As an introduction to using vector data in GeoExt, let's create a simple map
+that displays data from a KML. Copy :download:`this sample KML file
+<sundials.kml>` to the same directory with your GeoExt and Ext libraries. Then
+we can load it with some JavaScript::
 
     var map = new Openlayers.Map();
-    var bluemarble = new OpenLayers.Layer.WMS("Blue Marble",
-        'http://sigma.openplans.org/geoserver/wms',
-        { layers: 'bluemarble' }
+    var bluemarble = new OpenLayers.Layer.WMS(
+        "Global Imagery",
+        "http://maps.opengeo.org/geowebcache/service/wms",
+        {layers: "bluemarble"}
     );
     var sundials = new OpenLayers.Layer.Vector("Sundials");
     map.addLayer(bluemarble);
@@ -46,25 +60,46 @@
         width: 600
     });
 
-Here, we set up a map with two layers.  ``bluemarble`` is a WMS layer, which you should have seen before in other tutorials.  ``sundials`` is a vector layer, which handles client-side rendering of vector data.
+Here, we set up a map with two layers. ``bluemarble`` is a WMS layer, which you
+should have seen before in other tutorials. ``sundials`` is a vector layer,
+which handles client-side rendering of vector data.
 
-In **line 10** we initialize a :class:`GeoExt.data.FeatureStore`\ .  This class functions as a normal ``Ext.data.Store`` to interoperate with ExtJS classes, as well as providing the ability to **bind** to an ``OpenLayers.Layer.Vector`` in order to display features on a map.  In this example, we set up the store completely through constructor parameters:
+In **line 10** we initialize a :class:`GeoExt.data.FeatureStore`\ . This class
+functions as a normal ``Ext.data.Store`` to interoperate with ExtJS classes, as
+well as providing the ability to **bind** to an ``OpenLayers.Layer.Vector`` in
+order to display features on a map. In this example, we set up the store
+completely through constructor parameters:
     
     ``layer: sundials``
-        tells the store to render features using the ``sundials`` layer.  This is equivalent to calling ``store.bind(sundials)`` after initializing the store.
+        tells the store to render features using the ``sundials`` layer. This is
+        equivalent to calling ``store.bind(sundials)`` after initializing the
+        store.
 
     ``proxy: new GeoExt.data.ProtocolProxy(``
-        tells the store to use a ``ProtocolProxy`` for fetching features.  ``ProtocolProxy`` wraps OpenLayers Protocol objects.  Here we use an ``OpenLayers.Protocol.HTTP`` to fetch data over the web.  The ``HTTP`` protocol works with a variety of ``OpenLayers.Format`` types; here we use ``KML`` to match our dataset.  You can see all the available ``Protocol``\ s and ``Format``\ s in the `OpenLayers API documentation <http://openlayers.org>`_.
+        tells the store to use a ``ProtocolProxy`` for fetching features.
+        ``ProtocolProxy`` wraps OpenLayers Protocol objects. Here we use an
+        ``OpenLayers.Protocol.HTTP`` to fetch data over the web. The ``HTTP``
+        protocol works with a variety of ``OpenLayers.Format`` types; here we
+        use ``KML`` to match our dataset. You can see all the available
+        ``Protocol``\ s and ``Format``\ s in the `OpenLayers API documentation
+        <http://openlayers.org>`_.
 
     ``fields: [...]``
-        tells the store which extra properties (aside from just the geometry) to look for.  Here, we know that KML includes a ``title`` and a ``description`` for each point, and that both are string values.
+        tells the store which extra properties (aside from just the geometry) to
+        look for. Here, we know that KML includes a ``title`` and a
+        ``description`` for each point, and that both are string values.
 
     ``autoLoad: true``
-        tells the store to go ahead and fetch the feature data as soon as the constructor finishes.  This is equivalent to calling ``store.load()`` after the store is initialized.
+        tells the store to go ahead and fetch the feature data as soon as the
+        constructor finishes. This is equivalent to calling ``store.load()``
+        after the store is initialized.
 
-Now we have a map with a background and some data hosted on our server.  It looks like any other map; we can pan and zoom normally to navigate around.
+Now we have a map with a background and some data hosted on our server. It looks
+like any other map; we can pan and zoom normally to navigate around.
 
-However, since GeoExt has access to the data *behind* the map, we now have some options that weren't available to us before.  For example, we can add a control that allows us to view the features in a tabular format::
+However, since GeoExt has access to the data *behind* the map, we now have some
+options that weren't available to us before. For example, we can add a control
+that allows us to view the features in a tabular format::
     
     new Ext.grid.GridPanel({
         title: 'Sundials',

Modified: sandbox/ahocevar/playground/trunk/geoext/build/full.cfg
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/build/full.cfg	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/build/full.cfg	2010-01-11 12:47:52 UTC (rev 1710)
@@ -4,6 +4,7 @@
 exclude =
     GeoExt.js
     GeoExt/SingleFile.js
+    overrides/override-ext-ajax.js
     
 
 [ext.js]

Modified: sandbox/ahocevar/playground/trunk/geoext/examples/legendpanel.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/examples/legendpanel.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/examples/legendpanel.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -38,32 +38,34 @@
     ]);
     map.addControl(new OpenLayers.Control.LayerSwitcher());
 
-    var addLayer = function() {
-        var wmslayer = new OpenLayers.Layer.WMS("Bodies of Water",
-            "http://demo.opengeo.org/geoserver/wms?",
-            {layers: 'topp:tasmania_water_bodies', format: 'image/png', transparent: true},
-            {singleTile: true});
-        mapPanel.map.addLayer(wmslayer);
+    var addRemoveLayer = function() {
+        if(mapPanel.map.layers.indexOf(water) == -1) {
+            mapPanel.map.addLayer(water);
+        } else {
+            mapPanel.map.removeLayer(water);
+        }
     };
 
-    var removeLayer = function() {
-        mapPanel.map.removeLayer(mapPanel.map.layers[1]);
-    };
-
     var moveLayer = function(idx) {
-        mapPanel.map.setLayerIndex(mapPanel.map.layers[0], idx);
+        var layer = layerRec0.get("layer");
+        var idx = mapPanel.map.layers.indexOf(layer) == 0 ?
+            mapPanel.map.layers.length : 0;
+        mapPanel.map.setLayerIndex(layerRec0.get("layer"), idx);
     };
 
     var toggleVisibility = function() {
-        mapPanel.map.layers[1].setVisibility(!mapPanel.map.layers[1].getVisibility());
+        var layer = layerRec0.get("layer");
+        layer.setVisibility(!layer.getVisibility());
     };
 
     var updateHideInLegend = function() {
-        mapPanel.layers.getAt(1).set("hideInLegend", true);
+        layerRec0.set("hideInLegend", !layerRec0.get("hideInLegend"));
     };
 
     var updateLegendUrl = function() {
-        mapPanel.layers.getAt(0).set("legendURL", "http://www.geoext.org/trac/geoext/chrome/site/img/GeoExt.png");
+        var url = layerRec0.get("legendURL");
+        layerRec0.set("legendURL", otherUrl);
+        otherUrl = url;
     };
 
     var mapPanel = new GeoExt.MapPanel({
@@ -74,9 +76,26 @@
         center: new OpenLayers.LonLat(146.4, -41.6),
         zoom: 7
     });
+    
+    // give the record of the 1st layer a legendURL, which will cause
+    // UrlLegend instead of WMSLegend to be used
+    var layerRec0 = mapPanel.layers.getAt(0);
+    layerRec0.set("legendURL", "http://demo.opengeo.org/geoserver/wms?FORMAT=image%2Fgif&TRANSPARENT=true&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&LAYER=topp%3Atasmania_state_boundaries");
 
+    // stores another legendURL for the legendurl button action
+    var otherUrl = "http://www.geoext.org/trac/geoext/chrome/site/img/GeoExt.png";
+
+    // create another layer for the add/remove button action
+    var water = new OpenLayers.Layer.WMS("Bodies of Water",
+        "http://demo.opengeo.org/geoserver/wms?",
+        {layers: 'topp:tasmania_water_bodies', format: 'image/png', transparent: true},
+        {singleTile: true});
+
     legendPanel = new GeoExt.LegendPanel({
-        labelCls: 'mylabel',
+        defaults: {
+            labelCls: 'mylabel',
+            style: 'padding:5px'            
+        },
         bodyStyle: 'padding:5px',
         width: 350,
         autoScroll: true,
@@ -91,12 +110,10 @@
         width: 800,
         tbar: new Ext.Toolbar({
             items: [
-                {text: 'add', handler: addLayer},
-                {text: 'remove', handler: removeLayer},
-                {text: 'movetotop', handler: function() { moveLayer(10); } },
-                {text: 'moveup', handler: function() { moveLayer(1); } },
+                {text: 'add/remove', handler: addRemoveLayer},
+                {text: 'movetop/bottom', handler: moveLayer },
                 {text: 'togglevis', handler: toggleVisibility},
-                {text: 'hide', handler: updateHideInLegend},
+                {text: 'hide/show', handler: updateHideInLegend},
                 {text: 'legendurl', handler: updateLegendUrl}
             ]
         }),

Modified: sandbox/ahocevar/playground/trunk/geoext/examples/tree.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/examples/tree.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/examples/tree.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -91,6 +91,11 @@
             )
         ]
     });
+
+    // create our own layer node UI class, using the RadioButtonMixin
+    var LayerNodeUI = Ext.extend(
+        GeoExt.tree.LayerNodeUI, new GeoExt.tree.RadioButtonMixin()
+    );
         
     // using OpenLayers.Format.JSON to create a nice formatted string of the
     // configuration for editing it in the UI
@@ -100,11 +105,12 @@
         nodeType: "gx_overlaylayercontainer",
         expanded: true,
         // render the nodes inside this container with a radio button,
-        // and assign them the group "foo". See the registerRadio function
-        // in the code that we use as handlers for the tree's insert and
-        // append events to make these radio buttons change the active layer.
+        // and assign them the group "foo".
         loader: {
-            baseAttrs: {radioGroup: "foo"}
+            baseAttrs: {
+                radioGroup: "foo",
+                uiProvider: "use_radio"
+            }
         }
     }, {
         nodeType: "gx_layer",
@@ -118,16 +124,6 @@
         }
     }], true);
 
-    // the layer node's radio button with its radiochange event can be used
-    // to set an active layer.
-    var registerRadio = function(node){
-        if(!node.hasListener("radiochange")) {
-            node.on("radiochange", function(node){
-                alert(node.layer.name + " is now the the active layer.");
-            });
-        }
-    }
-    
     // create the tree with the configuration from above
     var tree = new Ext.tree.TreePanel({
         border: true,
@@ -141,7 +137,10 @@
         loader: new Ext.tree.TreeLoader({
             // applyLoader has to be set to false to not interfer with loaders
             // of nodes further down the tree hierarchy
-            applyLoader: false
+            applyLoader: false,
+            uiProviders: {
+                "use_radio": LayerNodeUI
+            }
         }),
         root: {
             nodeType: "async",
@@ -151,8 +150,9 @@
             children: Ext.decode(treeConfig)
         },
         listeners: {
-            "insert": registerRadio,
-            "append": registerRadio
+            "radiochange": function(node){
+                alert(node.layer.name + " is now the the active layer.");
+            }
         },
         rootVisible: false,
         lines: false,

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/Action.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/Action.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/Action.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -215,7 +215,12 @@
         var cs = this.items;
         for(var i = 0, len = cs.length; i < len; i++){
             if(cs[i][fnName]) {
-                cs[i][fnName].apply(cs[i], args);
+                cs[i].rendered ?
+                    cs[i][fnName].apply(cs[i], args) :
+                    cs[i].on({
+                        "render": cs[i][fnName].createDelegate(cs[i], args),
+                        single: true
+                    });
             }
         }
     }

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/FeatureRenderer.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/FeatureRenderer.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/FeatureRenderer.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -13,6 +13,11 @@
  */
 Ext.namespace('GeoExt');
 
+/** api: constructor
+ *  .. class:: FeatureRenderer(config)
+ *   
+ *      Create a box component for rendering a vector feature.
+ */
 GeoExt.FeatureRenderer = Ext.extend(Ext.BoxComponent, {
 
     /** api: config[feature]
@@ -32,8 +37,8 @@
 
     /** api: config[symbolType]
      *  ``String``
-     *   One of ``"Point"``, ``"Line"``, or ``"Polygon"``.  If ``feature``
-     *   is provided, it will be preferred.  Default is ``"Point"``.
+     *  One of ``"Point"``, ``"Line"``, or ``"Polygon"``.  If ``feature``
+     *  is provided, it will be preferred.  Default is ``"Point"``.
      */
     symbolType: "Point",
 
@@ -131,7 +136,8 @@
              *  Fires when the feature is clicked on.
              *
              *  Listener arguments:
-             *  * renderer - ``GeoExt.FeatureRenderer`` This feature renderer.
+             *  
+             *  * renderer - :class:`GeoExt.FeatureRenderer` This feature renderer.
              */
             "click"
         );
@@ -248,6 +254,7 @@
      *  Update the symbolizers used to render the feature.
      *
      *  Valid options:
+     *  
      *  * draw - ``Boolean`` Draw the feature after setting it.  Default is ``true``.
      */
     setSymbolizers: function(symbolizers, options) {
@@ -264,6 +271,7 @@
      *  Create a new feature based on the geometry type and render it.
      *
      *  Valid options:
+     *  
      *  * draw - ``Boolean`` Draw the feature after setting it.  Default is ``true``.
      */
     setSymbolType: function(type, options) {
@@ -279,6 +287,7 @@
      *  Update the feature and redraw.
      *
      *  Valid options:
+     *  
      *  * draw - ``Boolean`` Draw the feature after setting it.  Default is ``true``.
      */
     setFeature: function(feature, options) {
@@ -309,6 +318,7 @@
      *  the feature.
      *
      *  Valid options:
+     *  
      *  * feature - ``OpenLayers.Feature.Vector`` The new or updated feature.  
      *      If provided, the feature gets precedence over ``symbolType``.
      *  * symbolType - ``String`` One of the allowed ``symbolType`` values.
@@ -339,4 +349,5 @@
     
 });
 
+/** api: xtype = gx_renderer */
 Ext.reg('gx_renderer', GeoExt.FeatureRenderer);

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js (from rev 1709, core/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LayerLegend.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,124 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/** api: (define)
+ *  module = GeoExt
+ *  class = LayerLegend
+ *  base_link = `Ext.Container <http://extjs.com/deploy/dev/docs/?class=Ext.Container>`_
+ */
+
+Ext.namespace('GeoExt');
+
+/** api: constructor
+ *  .. class:: LayerLegend(config)
+ *
+ *      Base class for components of :class:`GeoExt.LegendPanel`.
+ */
+GeoExt.LayerLegend = Ext.extend(Ext.Container, {
+
+    /** api: config[layerRecord]
+     *  :class:`GeoExt.data.LayerRecord`  The layer record for the legend
+     */
+    layerRecord: null,
+
+    /** api: config[showTitle]
+     *  ``Boolean``
+     *  Whether or not to show the title of a layer. This can be overridden
+     *  on the LayerStore record using the hideTitle property.
+     */
+    showTitle: true,
+
+    /** api: config[labelCls]
+     *  ``String``
+     *  Optional css class to use for the layer title labels.
+     */
+    labelCls: null,
+
+    /** private: method[initComponent]
+     */
+    initComponent: function() {
+        GeoExt.LayerLegend.superclass.initComponent.call(this);
+        this.autoEl = {};
+        var rec = this.layerRecord;
+        this.add({
+            xtype: "label",
+            text: (this.showTitle && !rec.get('hideTitle')) ? 
+                rec.get("layer").name : '',
+            cls: 'x-form-item x-form-item-label' +
+                (this.labelCls ? ' ' + this.labelCls : '')
+        });
+    },
+
+    /** private: method[update]
+     *  Updates the legend.
+     */
+    update: function() {
+        var rec = this.layerRecord;
+        if ((this.showTitle && !rec.get('hideTitle')) && 
+            (this.items.get(0).text !== rec.get('title'))) {
+                // we need to update the title
+                this.items.get(0).setText(rec.get('title'));
+        }
+    }
+
+});
+
+/** class: method[getTypes]
+ *  :param layerRecord: class:`GeoExt.data.LayerRecord` A layer record to get
+ *      legend types for. If not provided, all registered types will be
+ *      returned.
+ *  :param preferredTypes: ``Array(String)`` Types that should be considered.
+ *      first. If not provided, all legend types will be returned in the order
+ *      they were registered.
+ *  :return: ``Array(String)`` xtypes of legend types that can be used with
+ *      the provided ``layerRecord``.
+ *  
+ *  Gets an array of legend xtypes that support the provided layer record,
+ *  with optionally provided preferred types listed first.
+ */
+GeoExt.LayerLegend.getTypes = function(layerRecord, preferredTypes) {
+    var types = (preferredTypes || []).concat();
+    var goodTypes = [];
+    for(var type in GeoExt.LayerLegend.types) {
+        if(GeoExt.LayerLegend.types[type].supports(layerRecord)) {
+            // add to goodTypes if not preferred
+            types.indexOf(type) == -1 && goodTypes.push(type);
+        } else {
+            // preferred, but not supported
+            types.remove(type);
+        }
+    }
+    // take the remaining preferred types, and add other good types 
+    return types.concat(goodTypes);
+};
+    
+/** private: method[supports]
+ *  :param layerRecord: :class:`GeoExt.data.LayerRecord` The layer record
+ *      to check support for.
+ *  :return: ``Boolean`` true if this legend type supports the layer
+ *      record.
+ *  
+ *  Checks whether this legend type supports the provided layerRecord.
+ */
+GeoExt.LayerLegend.supports = function(layerRecord) {
+    // to be implemented by subclasses
+};
+
+/** class: constant[GeoExt.LayerLegend.types]
+ *  An object containing a name-class mapping of LayerLegend subclasses.
+ *  To register as LayerLegend, a subclass should add itself to this object:
+ *  
+ *  .. code-block:: javascript
+ *  
+ *      GeoExt.GetLegendGraphicLegend = Ext.extend(GeoExt.LayerLegend, {
+ *      });
+ *      
+ *      GeoExt.LayerLegend.types["getlegendgraphic"] =
+ *          GeoExt.GetLegendGraphicLegend;
+ */
+GeoExt.LayerLegend.types = {};

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendImage.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendImage.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendImage.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -53,12 +53,12 @@
         };
     },
 
-    /** api: method[updateLegend]
+    /** api: method[setUrl]
      *  :param url: ``String`` The new URL.
      *  
-     *  Sets the url of the image.
+     *  Sets the url of the legend image.
      */
-    updateLegend: function(url) {
+    setUrl: function(url) {
         this.url = url;
         var el = this.getEl();
         if (el) {
@@ -75,7 +75,7 @@
     onRender: function(ct, position) {
         GeoExt.LegendImage.superclass.onRender.call(this, ct, position);
         if(this.url) {
-            this.updateLegend(this.url);
+            this.setUrl(this.url);
         }
     },
 

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendPanel.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendPanel.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendPanel.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -30,26 +30,6 @@
      */
     dynamic: true,
     
-    /** api: config[showTitle]
-     *  ``Boolean``
-     *  Whether or not to show the title of a layer. This can be a global
-     *  setting for the whole panel, or it can be overridden on the LayerStore 
-     *  record using the hideInLegend property.
-     */
-    showTitle: true,
-
-    /** api: config[labelCls]
-     *  ``String``
-     *  Optional css class to use for the layer title labels.
-     */
-    labelCls: null,
-
-    /** api: config[bodyStyle]
-     *  ``String``
-     *  Optional style to apply to the body of the legend panels.
-     */
-    bodyStyle: '',
-
     /** api: config[layerStore]
      *  ``GeoExt.data.LayerStore``
      *  The layer store containing layers to be displayed in the legend 
@@ -57,11 +37,13 @@
      */
     layerStore: null,
     
-    /** api: config[legendOptions]
-     *  ``Object``
-     *  Config options for the legend generator, i.e. the panel that provides
-     *  the legend image.
+    /** api: config[preferredTypes]
+     *  ``Array(String)`` An array of preferred legend types.
      */
+    
+    /** private: property[preferredTypes]
+     */
+    preferredTypes: null,
 
     /** api: config[filter]
      *  ``Function``
@@ -106,7 +88,6 @@
                 scope: this
             });
         }
-        this.doLayout();
     },
 
     /** private: method[recordIndexToPanelIndex]
@@ -122,12 +103,12 @@
         var count = store.getCount();
         var panelIndex = -1;
         var legendCount = this.items ? this.items.length : 0;
+        var record, layer;
         for(var i=count-1; i>=0; --i) {
-            var layer = store.getAt(i).get("layer");
-            var legendGenerator = GeoExt[
-                "Legend" + layer.CLASS_NAME.split(".").pop()
-            ];
-            if(layer.displayInLayerSwitcher && legendGenerator &&
+            record = store.getAt(i);
+            layer = record.get("layer");
+            var types = GeoExt.LayerLegend.getTypes(record);
+            if(layer.displayInLayerSwitcher && types.length > 0 &&
                 (store.getAt(i).get("hideInLegend") !== true)) {
                     ++panelIndex;
                     if(index === i || panelIndex > legendCount-1) {
@@ -137,6 +118,16 @@
         }
         return panelIndex;
     },
+    
+    /** private: method[getIdForLayer]
+     *  :arg layer: ``OpenLayers.Layer``
+     *  :returns: ``String``
+     *
+     *  Generate an element id that is unique to this panel/layer combo.
+     */
+    getIdForLayer: function(layer) {
+        return this.id + "-" + layer.id;
+    },
 
     /** private: method[onStoreUpdate]
      *  Update a layer within the legend panel. Gets called when the store
@@ -151,20 +142,11 @@
      */
     onStoreUpdate: function(store, record, operation) {
         var layer = record.get('layer');
-        var legend = this.items ? this.getComponent(layer.id) : null;
-        if ((this.showTitle && !record.get('hideTitle')) && 
-            (legend && legend.items.get(0).text !== record.get('title'))) {
-                // we need to update the title
-                legend.items.get(0).setText(record.get('title'));
-        }
+        var legend = this.items ? this.getComponent(this.getIdForLayer(layer)) : null;
         if (legend) {
             legend.setVisible(layer.getVisibility() && layer.inRange &&
                 layer.displayInLayerSwitcher && !record.get('hideInLegend'));
-            var url = record.get("legendURL") != null ?
-                      record.get("legendURL") : undefined;
-            // the actual legend panel is the second item in
-            // the main panel
-            legend.items.get(1).updateLegend(url);
+            legend.update();
         }
     },
 
@@ -204,7 +186,7 @@
      *      store to remove.
      */
     removeLegend: function(record) {
-        var legend = this.getComponent(record.get('layer').id);
+        var legend = this.getComponent(this.getIdForLayer(record.get('layer')));
         if (legend) {
             this.remove(legend, true);
             this.doLayout();
@@ -228,40 +210,6 @@
         this.doLayout();
     },
 
-    /** private: method[createLegendSubpanel]
-     *  Create a legend sub panel for the layer.
-     *
-     *  :param record: ``Ext.data.Record`` The record object from the layer
-     *      store.
-     *
-     *  :return: ``Ext.Panel`` The created panel per layer
-     */
-    createLegendSubpanel: function(record) {
-        var layer = record.get('layer');
-        var mainPanel = this.createMainPanel(record);
-        if (mainPanel !== null) {
-            // the default legend can be overridden by specifying a
-            // legendURL property
-            var legend;
-            if (record.get('legendURL')) {
-                legend = new GeoExt.LegendImage({url: record.get('legendURL')});
-                mainPanel.add(legend);
-            } else {
-                var legendGenerator = GeoExt[
-                    "Legend" + layer.CLASS_NAME.split(".").pop()
-                ];
-                if (legendGenerator) {
-                    legend = new legendGenerator(Ext.applyIf({
-                        layer: layer,
-                        record: record
-                    }, this.legendOptions));
-                    mainPanel.add(legend);
-                }
-            }
-        }
-        return mainPanel;
-    },
-
     /** private: method[addLegend]
      *  Add a legend for the layer.
      *
@@ -271,52 +219,23 @@
      */
     addLegend: function(record, index) {
         if (this.filter(record) === true) {
+            var layer = record.get("layer");
             index = index || 0;
-            var layer = record.get('layer');
-            var legendSubpanel = this.createLegendSubpanel(record);
-            if (legendSubpanel !== null) {
-                legendSubpanel.setVisible(layer.getVisibility() && layer.inRange);
-                this.insert(index, legendSubpanel);
+            var legend;
+            var types = GeoExt.LayerLegend.getTypes(record,
+                this.preferredTypes);
+            if(layer.displayInLayerSwitcher && !record.get('hideInLegend') &&
+                types.length > 0) {
+                this.insert(index, {
+                    xtype: types[0],
+                    id: this.getIdForLayer(layer),
+                    layerRecord: record,
+                    hidden: !(layer.getVisibility() && layer.inRange)
+                });
             }
         }
     },
 
-    /** private: method[createMainPanel]
-     *  Creates the main panel with a title for the layer.
-     *
-     *  :param record: ``Ext.data.Record`` The record object from the layer
-     *      store.
-     *
-     *  :return: ``Ext.Panel`` The created main panel with a label.
-     */
-    createMainPanel: function(record) {
-        var layer = record.get('layer');
-        var panel = null;
-        var legendGenerator = GeoExt[
-            "Legend" + layer.CLASS_NAME.split(".").pop()
-        ];
-        if (layer.displayInLayerSwitcher && !record.get('hideInLegend') &&
-            legendGenerator) {
-            var panelConfig = {
-                id: layer.id,
-                border: false,
-                bodyBorder: false,
-                hideMode: 'offsets',
-                bodyStyle: this.bodyStyle,
-                items: [
-                    new Ext.form.Label({
-                        text: (this.showTitle && !record.get('hideTitle')) ? 
-                            layer.name : '',
-                        cls: 'x-form-item x-form-item-label' +
-                            (this.labelCls ? ' ' + this.labelCls : '')
-                    })
-                ]
-            };
-            panel = new Ext.Panel(panelConfig);
-        }
-        return panel;
-    },
-
     /** private: method[onDestroy]
      *  Private method called during the destroy sequence.
      */

Deleted: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendWMS.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendWMS.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/LegendWMS.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -1,185 +0,0 @@
-/**
- * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
- * 
- * Published under the BSD license.
- * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
- * of the license.
- */
-
-/**
- * @include GeoExt/widgets/LegendImage.js
- */
-
-/** api: (define)
- *  module = GeoExt
- *  class = LegendWMS
- *  base_link = `Ext.Panel <http://extjs.com/deploy/dev/docs/?class=Ext.Panel>`_
- */
-Ext.namespace('GeoExt');
-
-/** api: constructor
- *  .. class:: LegendWMS(config)
- *
- *  Show a legend image for a WMS layer. The image can be read from the styles
- *  field of a layer record (if the record comes e.g. from a
- *  :class:`GeoExt.data.WMSCapabilitiesReader`). If not provided, a
- *  GetLegendGraphic request will be issued to retrieve the image.
- */
-GeoExt.LegendWMS = Ext.extend(Ext.Panel, {
-
-    /** api: config[imageFormat]
-     *  ``String``  
-     *  The image format to request the legend image in if the url cannot be
-     *  determined from the styles field of the layer record. Defaults to
-     *  image/gif.
-     */
-    imageFormat: "image/gif",
-    
-    /** api: config[defaultStyleIsFirst]
-     *  ``String``
-     *  The WMS spec does not say if the first style advertised for a layer in
-     *  a Capabilities document is the default style that the layer is
-     *  rendered with. We make this assumption by default. To be strictly WMS
-     *  compliant, set this to false, but make sure to configure a STYLES
-     *  param with your WMS layers, otherwise LegendURLs advertised in the
-     *  GetCapabilities document cannot be used.
-     */
-    defaultStyleIsFirst: true,
-
-    /** api: config[layer]
-     *  ``OpenLayers.Layer.WMS``
-     *  The WMS layer to request the legend for. Not required if record is
-     *  provided.
-     */
-    layer: null,
-    
-    /** api: config[record]
-     *  ``Ext.data.Record``
-     *  Optional record containing the layer. If provided, and if the record
-     *  has a styles property, the legend image associated with the layer's
-     *  style will be used.
-     */
-    record: null,
-
-    /** api: config[bodyBorder]
-     *  ``Boolean``
-     *  Show a border around the legend image or not. Default is false.
-     */
-    bodyBorder: false,
-
-    /** private: method[initComponent]
-     *  Initializes the WMS legend. For group layers it will create multiple
-     *  image box components.
-     */
-    initComponent: function() {
-        GeoExt.LegendWMS.superclass.initComponent.call(this);
-        if(!this.layer) {
-            this.layer = this.record.get("layer");
-        }
-        this.updateLegend();
-    },
-
-    /** private: method[getLegendUrl]
-     *  :param layerName: ``String`` A sublayer.
-     *  :param layerNames: ``Array(String)`` The array of sublayers,
-     *      read from this.layer if not provided.
-     *  :return: ``String`` The legend URL.
-     *
-     *  Get the legend URL of a sublayer.
-     */
-    getLegendUrl: function(layerName, layerNames) {
-        var url;
-        var styles = this.record && this.record.get("styles");
-        layerNames = layerNames ||
-                             (this.layer.params.LAYERS instanceof Array) ?
-                             this.layer.params.LAYERS :
-                             this.layer.params.LAYERS.split(",");
-
-        var styleNames = this.layer.params.STYLES &&
-                             this.layer.params.STYLES.split(",");
-        var idx = layerNames.indexOf(layerName);
-        var styleName = styleNames && styleNames[idx];
-        // check if we have a legend URL in the record's
-        // "styles" data field
-        if(styles && styles.length > 0) {
-            if(styleName) {
-                Ext.each(styles, function(s) {
-                    url = (s.name == styleName && s.legend) && s.legend.href;
-                    return !url;
-                });
-            } else if(this.defaultStyleIsFirst === true && !styleNames &&
-                      !this.layer.params.SLD && !this.layer.params.SLD_BODY) {
-                url = styles[0].legend && styles[0].legend.href;
-            }
-        }
-        return url ||
-               this.layer.getFullRequestString({
-                   REQUEST: "GetLegendGraphic",
-                   WIDTH: null,
-                   HEIGHT: null,
-                   EXCEPTIONS: "application/vnd.ogc.se_xml",
-                   LAYER: layerName,
-                   LAYERS: null,
-                   STYLE: (styleName !== '') ? styleName: null,
-                   STYLES: null,
-                   SRS: null,
-                   FORMAT: this.imageFormat
-        });
-    },
-
-    /** private: method[updateLegend]
-     *  :param url: ``String`` The legend URL, derived from the
-     *      layer record or layer params (WMS GetLegendGraphic)
-     *      if not provided.
-     *
-     *  Update the legend panel, adding, removing or updating
-     *  the per-sublayer box component.
-     */
-    updateLegend: function(url) {
-        var layerNames, layerName, i, len;
-        
-        layerNames = (this.layer.params.LAYERS instanceof Array) ? 
-            this.layer.params.LAYERS :
-            this.layer.params.LAYERS.split(",");
-
-        if(this.items) {
-            var destroyList = [];
-            this.items.each(function(cmp) {
-                i = layerNames.indexOf(cmp.itemId);
-                if(i < 0) {
-                    destroyList.push(cmp);
-                } else {
-                    layerName = layerNames[i];
-                    var newUrl = url ||
-                                 this.getLegendUrl(layerName, layerNames);
-                    if(!OpenLayers.Util.isEquivalentUrl(newUrl, cmp.url)) {
-                        cmp.updateLegend(newUrl);
-                    }
-                }
-            }, this);
-            for(i = 0, len = destroyList.length; i<len; i++) {
-                var cmp = destroyList[i];
-                // cmp.destroy() does not remove the cmp from
-                // its parent container!
-                this.remove(cmp);
-                cmp.destroy();
-            }
-        }
-
-        var doLayout = false;
-        for(i = 0, len = layerNames.length; i<len; i++) {
-            layerName = layerNames[i];
-            if(!this.items || !this.getComponent(layerName)) {
-                this.add({
-                    xtype: "gx_legendimage",
-                    url: url || this.getLegendUrl(layerName, layerNames),
-                    itemId: layerName
-                });
-                doLayout = true;
-            }
-        }
-        if(doLayout) {
-            this.doLayout();
-        }
-    }
-});

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/UrlLegend.js (from rev 1709, core/trunk/geoext/lib/GeoExt/widgets/UrlLegend.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/UrlLegend.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/UrlLegend.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/**
+ * @include GeoExt/widgets/LegendImage.js
+ * @requires GeoExt/widgets/LayerLegend.js
+ */
+
+/** api: (define)
+ *  module = GeoExt
+ *  class = UrlLegend
+ */
+
+/** api: (extends)
+ * GeoExt/widgets/LayerLegend.js
+ */
+
+Ext.namespace('GeoExt');
+
+/** api: constructor
+ *  .. class:: UrlLegend(config)
+ *
+ *      Show a legend image in a BoxComponent and make sure load errors are 
+ *      dealt with.
+ */
+GeoExt.UrlLegend = Ext.extend(GeoExt.LayerLegend, {
+
+    /** private: method[initComponent]
+     *  Initializes the legend image component. 
+     */
+    initComponent: function() {
+        GeoExt.UrlLegend.superclass.initComponent.call(this);
+    },
+    
+    /** private: method[onRender]
+     *  Private method called when the legend image component is being
+     *  rendered.
+     */
+    onRender: function(ct, position) {
+        GeoExt.UrlLegend.superclass.onRender.call(this, ct, position);
+        this.add(new GeoExt.LegendImage({
+            url: this.layerRecord.get("legendURL")
+        }));
+    },
+
+    /** private: method[update]
+     *  Private override
+     */
+    update: function() {
+        GeoExt.WMSLegend.superclass.update.apply(this, arguments);
+        this.items.get(1).setUrl(this.layerRecord.get("legendURL"));
+    }
+
+});
+
+/** private: method[supports]
+ *  Private override
+ */
+GeoExt.UrlLegend.supports = function(layerRecord) {
+    return layerRecord.get("legendURL") != null;
+};
+
+/** api: legendtype = gx_urllegend */
+GeoExt.LayerLegend.types["gx_urllegend"] = GeoExt.UrlLegend;
+
+/** api: xtype = gx_urllegend */
+Ext.reg('gx_urllegend', GeoExt.UrlLegend);
\ No newline at end of file

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/WMSLegend.js (from rev 1709, core/trunk/geoext/lib/GeoExt/widgets/WMSLegend.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/WMSLegend.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/WMSLegend.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+/**
+ * @include GeoExt/widgets/LegendImage.js
+ * @requires GeoExt/widgets/LayerLegend.js
+ */
+
+/** api: (define)
+ *  module = GeoExt
+ *  class = WMSLegend
+ *  base_link = `Ext.Panel <http://extjs.com/deploy/dev/docs/?class=Ext.Panel>`_
+ */
+Ext.namespace('GeoExt');
+
+/** api: constructor
+ *  .. class:: WMSLegend(config)
+ *
+ *  Show a legend image for a WMS layer. The image can be read from the styles
+ *  field of a layer record (if the record comes e.g. from a
+ *  :class:`GeoExt.data.WMSCapabilitiesReader`). If not provided, a
+ *  GetLegendGraphic request will be issued to retrieve the image.
+ */
+GeoExt.WMSLegend = Ext.extend(GeoExt.LayerLegend, {
+
+    /** api: config[imageFormat]
+     *  ``String``  
+     *  The image format to request the legend image in if the url cannot be
+     *  determined from the styles field of the layer record. Defaults to
+     *  image/gif.
+     */
+    imageFormat: "image/gif",
+    
+    /** api: config[defaultStyleIsFirst]
+     *  ``String``
+     *  The WMS spec does not say if the first style advertised for a layer in
+     *  a Capabilities document is the default style that the layer is
+     *  rendered with. We make this assumption by default. To be strictly WMS
+     *  compliant, set this to false, but make sure to configure a STYLES
+     *  param with your WMS layers, otherwise LegendURLs advertised in the
+     *  GetCapabilities document cannot be used.
+     */
+    defaultStyleIsFirst: true,
+
+    /** private: method[initComponent]
+     *  Initializes the WMS legend. For group layers it will create multiple
+     *  image box components.
+     */
+    initComponent: function() {
+        GeoExt.WMSLegend.superclass.initComponent.call(this);
+    },
+
+    /** private: method[onRender]
+     *  Private method called when the legend image component is being
+     *  rendered.
+     */
+    onRender: function(ct, position) {
+        GeoExt.WMSLegend.superclass.onRender.call(this, ct, position);
+        this.update();
+    },
+    
+    /** private: method[getLegendUrl]
+     *  :param layerName: ``String`` A sublayer.
+     *  :param layerNames: ``Array(String)`` The array of sublayers,
+     *      read from this.layerRecord if not provided.
+     *  :return: ``String`` The legend URL.
+     *
+     *  Get the legend URL of a sublayer.
+     */
+    getLegendUrl: function(layerName, layerNames) {
+        var rec = this.layerRecord;
+        var url;
+        var styles = rec && rec.get("styles");
+        var layer = rec.get("layer");
+        layerNames = layerNames ||
+                             (layer.params.LAYERS instanceof Array) ?
+                             layer.params.LAYERS :
+                             layer.params.LAYERS.split(",");
+
+        var styleNames = layer.params.STYLES &&
+                             layer.params.STYLES.split(",");
+        var idx = layerNames.indexOf(layerName);
+        var styleName = styleNames && styleNames[idx];
+        // check if we have a legend URL in the record's
+        // "styles" data field
+        if(styles && styles.length > 0) {
+            if(styleName) {
+                Ext.each(styles, function(s) {
+                    url = (s.name == styleName && s.legend) && s.legend.href;
+                    return !url;
+                });
+            } else if(this.defaultStyleIsFirst === true && !styleNames &&
+                      !layer.params.SLD && !layer.params.SLD_BODY) {
+                url = styles[0].legend && styles[0].legend.href;
+            }
+        }
+        return url ||
+               layer.getFullRequestString({
+                   REQUEST: "GetLegendGraphic",
+                   WIDTH: null,
+                   HEIGHT: null,
+                   EXCEPTIONS: "application/vnd.ogc.se_xml",
+                   LAYER: layerName,
+                   LAYERS: null,
+                   STYLE: (styleName !== '') ? styleName: null,
+                   STYLES: null,
+                   SRS: null,
+                   FORMAT: this.imageFormat
+        });
+    },
+
+    /** private: method[update]
+     *  Update the legend, adding, removing or updating
+     *  the per-sublayer box component.
+     */
+    update: function() {
+        GeoExt.WMSLegend.superclass.update.apply(this, arguments);
+        
+        var layerNames, layerName, i, len;
+        
+        var layer = this.layerRecord.get("layer");
+        layerNames = (layer.params.LAYERS instanceof Array) ? 
+            layer.params.LAYERS :
+            layer.params.LAYERS.split(",");
+
+        var destroyList = [];
+        var textCmp = this.items.get(0);
+        this.items.each(function(cmp) {
+            i = layerNames.indexOf(cmp.itemId);
+            if(i < 0 && cmp != textCmp) {
+                destroyList.push(cmp);
+            } else if(cmp !== textCmp){
+                layerName = layerNames[i];
+                var newUrl = this.getLegendUrl(layerName, layerNames);
+                if(!OpenLayers.Util.isEquivalentUrl(newUrl, cmp.url)) {
+                    cmp.setUrl(newUrl);
+                }
+            }
+        }, this);
+        for(i = 0, len = destroyList.length; i<len; i++) {
+            var cmp = destroyList[i];
+            // cmp.destroy() does not remove the cmp from
+            // its parent container!
+            this.remove(cmp);
+            cmp.destroy();
+        }
+
+        for(i = 0, len = layerNames.length; i<len; i++) {
+            layerName = layerNames[i];
+            if(!this.items || !this.getComponent(layerName)) {
+                this.add({
+                    xtype: "gx_legendimage",
+                    url: this.getLegendUrl(layerName, layerNames),
+                    itemId: layerName
+                });
+            }
+        }
+        this.doLayout();
+    }
+});
+
+/** private: method[supports]
+ *  Private override
+ */
+GeoExt.WMSLegend.supports = function(layerRecord) {
+    return layerRecord.get("layer") instanceof OpenLayers.Layer.WMS;
+};
+
+/** api: legendtype = gx_wmslegend */
+GeoExt.LayerLegend.types["gx_wmslegend"] = GeoExt.WMSLegend;
+
+/** api: xtype = gx_wmslegend */
+Ext.reg('gx_wmslegend', GeoExt.WMSLegend);

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/FormPanel.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/FormPanel.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/form/FormPanel.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -23,13 +23,13 @@
  *
  *  .. code-block:: javascript
  *
- *      var formPanel = new GeoExt.form.Panel({
+ *      var formPanel = new GeoExt.form.FormPanel({
  *          renderTo: "formpanel",
  *          protocol: new OpenLayers.Protocol.WFS({
  *              url: "http://publicus.opengeo.org/geoserver/wfs",
  *              featureType: "tasmania_roads",
  *              featureNS: "http://www.openplans.org/topp"
- *          })
+ *          }),
  *          items: [{
  *              xtype: "textfield",
  *              name: "name__ilike",

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/LayerNode.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -15,11 +15,6 @@
  */
 GeoExt.tree.LayerNodeUI = Ext.extend(Ext.tree.TreeNodeUI, {
     
-    /** private: property[radio]
-     *  ``Ext.Element``
-     */
-    radio: null,
-    
     /** private: method[constructor]
      */
     constructor: function(config) {
@@ -36,11 +31,6 @@
         }
         GeoExt.tree.LayerNodeUI.superclass.render.apply(this, arguments);
         var cb = this.checkbox;
-        if (a.radioGroup && this.radio === null) {
-            this.radio = Ext.DomHelper.insertAfter(cb,
-                ['<input type="radio" class="gx-tree-layer-radio" name="',
-                a.radioGroup, '_radio"></input>'].join(""));
-        }
         if(a.checkedGroup) {
             // replace the checkbox with a radio button
             var radio = Ext.DomHelper.insertAfter(cb,
@@ -59,10 +49,7 @@
      *  :param e: ``Object``
      */
     onClick: function(e) {
-        if (e.getTarget('.gx-tree-layer-radio', 1)) {
-            this.radio.defaultChecked = this.radio.checked;
-            this.fireEvent("radiochange", this.node);
-        } else if(e.getTarget('.x-tree-node-cb', 1)) {
+        if(e.getTarget('.x-tree-node-cb', 1)) {
             this.toggleCheck(this.isChecked());
         } else {
             GeoExt.tree.LayerNodeUI.superclass.onClick.apply(this, arguments);
@@ -122,13 +109,6 @@
             r.name = r.name + "_clone";
         });
         ghostNode.appendChild(n);
-    },
-
-    /** private: method[destroy]
-     */
-    destroy: function() {
-        delete this.radio;
-        GeoExt.tree.LayerNodeUI.superclass.destroy.apply(this, arguments);
     }
 });
 
@@ -159,12 +139,6 @@
  *      the checkedGroup attribute is a string, identifying the options group
  *      for the node.
  * 
- *      If the node has a radioGroup attribute configured, the node will be
- *      rendered with a radio button next to the checkbox. This works like the
- *      checkbox with the checked attribute, but radioGroup is a string that
- *      identifies the options group. Clicking the radio button will fire a
- *      radioChange event.
- * 
  *      To use this node type in a ``TreePanel`` config, set ``nodeType`` to
  *      "gx_layer".
  */
@@ -218,13 +192,6 @@
         }
         
         this.defaultUI = this.defaultUI || GeoExt.tree.LayerNodeUI;
-        this.addEvents(
-            /** api: event[radiochange]
-             *  Notifies listener when a differnt radio button was selected.
-             *  Will be called with the currently selected node as argument.
-             */
-            "radiochange"
-        );
         
         Ext.apply(this, {
             layer: config.layer,

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/OverlayLayerContainer.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/OverlayLayerContainer.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/OverlayLayerContainer.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -28,7 +28,7 @@
  *     included.
  * 
  *     To use this node type in ``TreePanel`` config, set nodeType to
- *     "gx_overlaylayerontainer".
+ *     "gx_overlaylayercontainer".
  */
 GeoExt.tree.OverlayLayerContainer = Ext.extend(GeoExt.tree.LayerContainer, {
 

Copied: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/RadioButtonMixin.js (from rev 1709, core/trunk/geoext/lib/GeoExt/widgets/tree/RadioButtonMixin.js)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/RadioButtonMixin.js	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt/widgets/tree/RadioButtonMixin.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,103 @@
+/**
+ * Copyright (c) 2008-2009 The Open Source Geospatial Foundation
+ * 
+ * Published under the BSD license.
+ * See http://svn.geoext.org/core/trunk/geoext/license.txt for the full text
+ * of the license.
+ */
+
+Ext.namespace("GeoExt.tree");
+
+/** api: (define)
+ *  module = GeoExt.tree
+ *  class = RadioButtonMixin
+ */
+
+/** api: constructor
+ *  A mixin to create tree node UIs with radio buttons. Can be mixed in
+ *  any ``Ext.tree.TreeNodeUI`` class, and in particular in
+ *  :class:`GeoExt.data.LayerNodeUI`.
+ *
+ *  A tree node using an ``Ext.tree.TreeNodeUI`` with a
+ *  ``GeoExt.tree.RadioButtonMixin`` mixed into it generates a ``radiochange``
+ *  event when the radio button is clicked. A ``radiochange`` listener
+ *  receives the tree node whose radio button was clicked as its first
+ *  argument.
+ *
+ *  If the node has a radioGroup attribute configured, the node will be
+ *  rendered with a radio button next to the checkbox. This works like the
+ *  checkbox with the checked attribute, but radioGroup is a string that
+ *  identifies the options group.
+ * 
+ */
+
+/** api: example
+ *  Sample code to create a layer node UI with a radio button:
+ *
+ *  .. code-block:: javascript
+ *
+ *      var uiClass = Ext.extend(
+ *          GeoExt.tree.LayerNodeUI,
+ *          GeoExt.tree.RadioButtonMixin
+ *      );
+ *
+ *  Sample code to create a tree node UI with a radio button:
+ *
+ *  .. code-block:: javascript
+ *
+ *      var uiClass = Ext.extend(
+ *          Ext.tree.TreeNodeUI,
+ *          new GeoExt.tree.RadioButtonMixin
+ *      );
+ */
+
+GeoExt.tree.RadioButtonMixin = function() {
+    return (function() {
+        /** private: property[superclass]
+         *  ``Ext.tree.TreeNodeUI`` A reference to the superclass that is
+         *  extended with this mixin object.
+         */
+        var superclass;
+
+        return {
+            /** private: method[constructor]
+             *  :param node: ``Ext.tree.TreeNode`` The tree node.
+             */
+            constructor: function(node) {
+                node.addEvents(
+                    "radiochange"
+                );
+                superclass = arguments.callee.superclass;
+                superclass.constructor.apply(this, arguments);
+            },
+
+            /** private: method[render]
+             *  :param bulkRender: ``Boolean``
+             */
+            render: function(bulkRender) {
+                if(!this.rendered) {
+                    superclass.render.apply(this, arguments);
+                    var a = this.node.attributes;
+                    if(a.radioGroup) {
+                        Ext.DomHelper.insertBefore(this.anchor,
+                            ['<input type="radio" class="gx-tree-radio" name="',
+                            a.radioGroup, '_radio"></input>'].join(""));
+                    }
+                }
+            },
+
+            /** private: method[onClick]
+             *  :param e: ``Object``
+             */
+            onClick: function(e) {
+                var el = e.getTarget('.gx-tree-radio', 1); 
+                if(el) {
+                    el.defaultChecked = el.checked;
+                    this.fireEvent("radiochange", this.node);
+                } else {
+                    superclass.onClick.apply(this, arguments);
+                }
+            }
+        };
+    })();
+};

Modified: sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/lib/GeoExt.js	2010-01-11 12:47:52 UTC (rev 1710)
@@ -93,6 +93,7 @@
             "GeoExt/widgets/tips/LayerOpacitySliderTip.js",
             "GeoExt/widgets/tips/ZoomSliderTip.js",
             "GeoExt/widgets/tree/LayerNode.js",
+            "GeoExt/widgets/tree/RadioButtonMixin.js",
             "GeoExt/widgets/tree/LayerLoader.js",
             "GeoExt/widgets/tree/LayerContainer.js",
             "GeoExt/widgets/tree/BaseLayerContainer.js",
@@ -100,8 +101,10 @@
             "GeoExt/widgets/tree/LayerParamNode.js",
             "GeoExt/widgets/tree/LayerParamLoader.js",
             "GeoExt/widgets/LayerOpacitySlider.js",
+            "GeoExt/widgets/LayerLegend.js",
             "GeoExt/widgets/LegendImage.js",
-            "GeoExt/widgets/LegendWMS.js",
+            "GeoExt/widgets/UrlLegend.js",
+            "GeoExt/widgets/WMSLegend.js",
             "GeoExt/widgets/LegendPanel.js",
             "GeoExt/widgets/ZoomSlider.js",
             "GeoExt/widgets/grid/FeatureSelectionModel.js"

Copied: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html (from rev 1709, core/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LayerLegend.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html debug="true">
+  <head>
+    <script type="text/javascript" src="../../../../../openlayers/lib/OpenLayers.js"></script>
+    <script type="text/javascript" src="../../../../../ext/adapter/ext/ext-base.js"></script>
+    <script type="text/javascript" src="../../../../../ext/ext-all.js"></script>
+    <script type="text/javascript" src="../../../../lib/GeoExt.js"></script>
+
+    <script type="text/javascript">
+
+        function test_initialize(t) {
+            t.plan(3);
+
+            var Rec = GeoExt.data.LayerRecord.create();
+            var rec = new Rec({
+                layer: new OpenLayers.Layer("foo")
+            });
+            var legend = new GeoExt.LayerLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            t.ok(legend instanceof GeoExt.LayerLegend, "Instance created correctly");
+            t.eq(legend.items.get(0).text, "foo", "Layer text set correctly");
+            legend.destroy();
+            
+            rec = new Rec({
+                layer: new OpenLayers.Layer("foo"),
+                hideTitle: true
+            });
+            legend = new GeoExt.LayerLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            t.eq(legend.items.get(0).text, "", "Layer text for records with hideTitle set to true is empty.");
+            legend.destroy();
+        }
+        
+        function test_update(t) {
+            t.plan(2);
+            
+            var Rec = GeoExt.data.LayerRecord.create([{
+                name: "hideTitle", type: "boolean"
+            }]);
+            var rec = new Rec({
+                layer: new OpenLayers.Layer("foo")
+            });
+            var legend = new GeoExt.LayerLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            rec.set("title", "bar");
+            legend.update();
+            t.eq(legend.items.get(0).text, "bar", "Layer text updated correctly");
+            legend.destroy();
+
+            rec = new Rec({
+                layer: new OpenLayers.Layer("foo"),
+                hideTitle: true
+            });
+            legend = new GeoExt.LayerLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            rec.set("title", "bar");
+            legend.update();
+            t.eq(legend.items.get(0).text, "", "Layer text for record with hideTitle set to true still empty after update.")
+            legend.destroy();
+
+        }
+
+        function test_getTypes(t) {
+            t.plan(4);
+            var Rec = GeoExt.data.LayerRecord.create([{
+                name: "legendURL"
+            }]);
+            var rec = new Rec({
+                layer: new OpenLayers.Layer(),
+                legendURL: "foo"
+            });
+            t.eq(GeoExt.LayerLegend.getTypes(rec), ["gx_urllegend"], "a layer record with plain layer and legendURL is supported by gx_urllegend only.");
+            rec = new Rec({
+                layer: new OpenLayers.Layer.WMS(),
+                legendURL: "foo"
+            });
+            t.eq(GeoExt.LayerLegend.getTypes(rec), ["gx_urllegend","gx_wmslegend"], "a layer record with WMS layer and legendURL is supported by gx_urllegend and gx_wmslegend.");
+            t.eq(GeoExt.LayerLegend.getTypes(rec, ["gx_wmslegend"]), ["gx_wmslegend","gx_urllegend"], "a layer record with WMS layer and legendURL and gx_wmslegend as preferred type lists  gx_wmslegend first, then gx_urllegend.");
+            rec = new Rec({
+                layer: new OpenLayers.Layer.WMS()
+            });
+            t.eq(GeoExt.LayerLegend.getTypes(rec), ["gx_wmslegend"], "a layer record with wms layer is supported by gx_wmslegend only.");
+        }
+
+    </script>
+  <body>
+    <div id="legend"></div>
+  </body>
+</html>
\ No newline at end of file

Modified: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendPanel.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -28,8 +28,9 @@
         }
 
         function test_legendurl(t) {
-            t.plan(3);
+            t.plan(4);
             var mapPanel = loadMapPanel();
+            mapPanel.layers.getAt(0).set("legendURL", "foo");
             var lp  = new GeoExt.LegendPanel({
                 renderTo: 'legendpanel'});
             lp.render();
@@ -38,7 +39,8 @@
             mapPanel.layers.getAt(0).set("legendURL", newUrl);
 
             var item = lp.getComponent(mapPanel.map.layers[0].id);
-            var url = item.items.get(1).items.get(0).getEl().dom.src;
+            t.ok(item instanceof GeoExt.UrlLegend, "If legendURL is found in layerRecord, UrlLegend is chosen.")
+            var url = item.items.get(1).getEl().dom.src;
             t.eq(url, newUrl, "Update the image with the provided legendURL");
 
             var vectorLayer = new OpenLayers.Layer.Vector("vector layer");
@@ -108,27 +110,6 @@
             mapPanel.destroy();
         }
 
-        function test_wms(t) {
-            t.plan(3);
-            var mapPanel = loadMapPanel();
-            var LegendWMS = GeoExt.LegendWMS;
-            GeoExt.LegendWMS = function(config) {
-                t.ok(config.record == mapPanel.layers.getAt(0), "layer record passed correctly");
-                t.ok(config.layer == mapPanel.map.layers[0], "layer passed correctly");
-                t.eq(config.foo, "bar", "legendOptions passed correctly");
-                return new Ext.Panel();
-            }
-            var lp  = new GeoExt.LegendPanel({
-                renderTo: 'legendpanel',
-                legendOptions: {foo: "bar"}
-            });
-            lp.render();
-
-            lp.destroy();
-            mapPanel.destroy();
-            GeoExt.LegendWMS = LegendWMS;
-        }
-
         function test_addremove(t) {
             t.plan(4);
             var mapPanel = loadMapPanel();
@@ -143,15 +124,15 @@
             layer = new OpenLayers.Layer.WMS("test2", '/ows', {layers: 'b', format: 'image/png', transparent: 'TRUE'});
             mapPanel.map.addLayer(layer);
 
-            t.eq(lp.items.length, 2, "New WMS layer has been added");
+            t.eq(lp.items.length, 2, "New layer has been added");
 
             layer = new OpenLayers.Layer.WMS("test3", '/ows', {layers: 'c'}, {visibility: false});
             mapPanel.map.addLayer(layer);
 
-            t.eq(lp.items.length, 3, "A non visible WMS layer will be added but will be invisible");
+            t.eq(lp.items.length, 3, "A non visible layer will be added but will be invisible");
 
             mapPanel.map.removeLayer(mapPanel.map.layers[0]);
-            t.eq(lp.items.length, 2, "Removing the WMS layer really removes the legend from the panel");
+            t.eq(lp.items.length, 2, "Removing the layer really removes the legend from the panel");
 
             lp.destroy();
             mapPanel.destroy();
@@ -190,7 +171,9 @@
             lp.destroy();
 
             var lp  = new GeoExt.LegendPanel({
-                showTitle: false,
+                defaults: {
+                    showTitle: false
+                },
                 renderTo: 'legendpanel'});
             lp.render();
 
@@ -255,13 +238,13 @@
             layer.mergeNewParams({
                 layers: "a,b"
             });
-            t.eq(cmp.items.get(1).items.getCount(), 2,
+            t.eq(cmp.items.getCount(), 3,
                  "mergeNewParams caused addition of a legend image");
 
             layer.mergeNewParams({
                 layers: "b"
             });
-            t.eq(cmp.items.get(1).items.getCount(), 1,
+            t.eq(cmp.items.getCount(), 2,
                  "mergeNewParams caused removal of a legend image");
         }
 

Deleted: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendWMS.html
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendWMS.html	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/LegendWMS.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -1,187 +0,0 @@
-<!DOCTYPE html>
-<html debug="true">
-  <head>
-    <script type="text/javascript" src="../../../../../openlayers/lib/OpenLayers.js"></script>
-    <script type="text/javascript" src="../../../../../ext/adapter/ext/ext-base.js"></script>
-    <script type="text/javascript" src="../../../../../ext/ext-all.js"></script>
-    <script type="text/javascript" src="../../../../lib/GeoExt.js"></script>
-
-    <script type="text/javascript">
-
-        function loadMapPanel() {
-            var mapPanel = new GeoExt.MapPanel({
-                // panel options
-                id: "map-panel",
-                title: "GeoExt MapPanel",
-                renderTo: "mappanel",
-                height: 400,
-                width: 600,
-                // map panel-specific options
-                layers: [
-                    new OpenLayers.Layer.WMS("test", '/ows', {layers: 'a'})
-                ],
-                center: new OpenLayers.LonLat(5, 45),
-                zoom: 4
-            });
-
-            return mapPanel;
-        }
-
-        function test_legendurl(t) {
-            t.plan(5);
-
-            var l, url, expectedUrl;
-            var mapPanel = loadMapPanel();
-            l = new GeoExt.LegendWMS({
-                renderTo: 'legendwms',
-                record: mapPanel.layers.getAt(0)
-            });
-            l.render();
-
-            url = l.items.get(0).url;
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&LAYER=a";
-            t.eq(url, expectedUrl, "GetLegendGraphic url is generated correctly");
-            l.destroy()
-            
-            mapPanel.map.layers[0].params.STYLES = "bar";
-            mapPanel.layers.getAt(0).set("styles", [{
-                name: "bar",
-                legend: {href: "foo"}
-            }]);
-            l = new GeoExt.LegendWMS({
-                renderTo: 'legendwms',
-                record: mapPanel.layers.getAt(0)
-            });
-            l.render();
-            url = l.items.get(0).url;
-            t.eq(url, "foo", "legend url from styles field of layer record used correctly.");
-            l.destroy();
-            mapPanel.map.layers[0].params.STYLES = "";
-            
-            l = new GeoExt.LegendWMS({
-                renderTo: 'legendwms',
-                record: mapPanel.layers.getAt(0),
-                defaultStyleIsFirst: true
-            });
-            l.render();
-            url = l.items.get(0).url;
-            t.eq(url, "foo", "legend url from styles field of layer record used correctly when defaultStyleIsFirst set to true and layer has no STYLES param.");
-            l.destroy();
-
-            mapPanel.map.layers[0].params.SLD = "sld";
-            l = new GeoExt.LegendWMS({
-                renderTo: 'legendwms',
-                record: mapPanel.layers.getAt(0),
-                defaultStyleIsFirst: true
-            });
-            l.render();
-            url = l.items.get(0).url;
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&SLD=sld&LAYER=a";
-            t.eq(url, expectedUrl, "GetLegendGraphic url is generated when layer has SLD set");
-            l.destroy();
-            delete mapPanel.map.layers[0].params.SLD;
-
-            mapPanel.map.layers[0].params.SLD_BODY = "sld_body";
-            l = new GeoExt.LegendWMS({
-                renderTo: 'legendwms',
-                record: mapPanel.layers.getAt(0),
-                defaultStyleIsFirst: true
-            });
-            l.render();
-            url = l.items.get(0).url;
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&SLD_BODY=sld_body&LAYER=a";
-            t.eq(url, expectedUrl, "GetLegendGraphic url is generated when layer has SLD_BODY set");
-            l.destroy();
-            delete mapPanel.map.layers[0].params.SLD_BODY;
-
-            mapPanel.destroy();
-        }
-
-        function test_updateLegend(t) {
-            t.plan(8);
-
-            // set up
-
-            var mapPanel = loadMapPanel();
-            var layerRecord = mapPanel.layers.getAt(0);
-
-            var url, expectedUrl, cmp;
-
-            var l = new GeoExt.LegendWMS({
-                renderTo: 'legendwms',
-                record: layerRecord
-            });
-
-            // test
-
-            // #1
-            layerRecord.get("layer").mergeNewParams({
-                layers: "b"
-            });
-            l.updateLegend();
-            t.ok(!l.getComponent("a"),
-                 "updateLegend removes old components");
-            t.ok(l.getComponent("b"),
-                 "updateLegend adds new components");
-
-            // #2
-            layerRecord.get("layer").mergeNewParams({
-                layers: "b,c",
-                foo: "bar"
-            });
-            l.updateLegend();
-            t.ok(l.getComponent("b"),
-                 "updateLegend does not remove components to be updated");
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&LAYER=b";
-            t.eq(l.getComponent("b").url, expectedUrl,
-                 "updateLegend updates component URL");
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&LAYER=c";
-            t.eq(l.getComponent("c").url, expectedUrl,
-                 "updateLegend sets correct URL in new component");
-
-            // #3
-            layerRecord.get("layer").mergeNewParams({
-                layers: "c",
-                styles: "style1"
-            });
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&LAYER=c&STYLE=style1";
-            l.updateLegend();
-            t.eq(l.getComponent("c").url, expectedUrl,
-                 "updateLegend sets correct STYLE params in URL");
-
-            // #4
-            layerRecord.set("styles", [{
-                name: "style1",
-                legend: {
-                    href: "http://url-to-legend.org/"
-                }
-            }]);
-            l.updateLegend();
-            expectedUrl = "http://url-to-legend.org/";
-            t.eq(l.getComponent("c").url, expectedUrl,
-                 "updateLegend uses the legend href from the styles field");
-
-            // #5
-            layerRecord.get("layer").mergeNewParams({
-                layers: "c",
-                styles: null,
-                sld: "http://url-to-sld.org/"
-            });
-            l.updateLegend();
-            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&SLD=http%3A%2F%2Furl-to-sld.org%2F&LAYER=c";
-            t.eq(l.getComponent("c").url, expectedUrl,
-                 "updateLegend does not use the legend href from the " +
-                 "styles field if SLD is set in the layer params");
-
-            // tear down
-
-            l.destroy()
-        }
-
-
-    </script>
-  <body>
-    <div id="legendwms"></div>
-    <div id="mappanel"></div>
-  </body>
-</html>

Copied: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/UrlLegend.html (from rev 1709, core/trunk/geoext/tests/lib/GeoExt/widgets/UrlLegend.html)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/UrlLegend.html	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/UrlLegend.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<html debug="true">
+  <head>
+    <script type="text/javascript" src="../../../../../openlayers/lib/OpenLayers.js"></script>
+    <script type="text/javascript" src="../../../../../ext/adapter/ext/ext-base.js"></script>
+    <script type="text/javascript" src="../../../../../ext/ext-all.js"></script>
+    <script type="text/javascript" src="../../../../lib/GeoExt.js"></script>
+
+    <script type="text/javascript">
+
+        function test_initialize(t) {
+            t.plan(1);
+
+            var Rec = GeoExt.data.LayerRecord.create();
+            var rec = new Rec({
+                layer: new OpenLayers.Layer("foo")
+            });
+            var legend = new GeoExt.UrlLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            t.ok(legend instanceof GeoExt.LayerLegend, "Instance created correctly.");
+            legend.destroy();
+        }
+        
+        function test_render(t) {
+            t.plan(2);
+
+            var Rec = GeoExt.data.LayerRecord.create([{
+                name: "legendURL"
+            }]);
+            var rec = new Rec({
+                layer: new OpenLayers.Layer("foo"),
+                legendURL: Ext.BLANK_IMAGE_URL+"?foo"
+            });
+            var legend = new GeoExt.UrlLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            t.ok(legend.items.get(1) instanceof GeoExt.LegendImage, "Legend has a LegendImage.");
+            t.eq(legend.items.get(1).url, Ext.BLANK_IMAGE_URL+"?foo", "Legend image rendered correctly.");
+            legend.destroy();
+        }
+
+        function test_update(t) {
+            t.plan(1);
+            
+            var Rec = GeoExt.data.LayerRecord.create([{
+                name: "legendURL"
+            }]);
+            var rec = new Rec({
+                layer: new OpenLayers.Layer("foo"),
+                legendURL: "http://path/to/foo"
+            });
+            var legend = new GeoExt.UrlLegend({
+                layerRecord: rec,
+                renderTo: "legend"
+            });
+            rec.set("legendURL", Ext.BLANK_IMAGE_URL+"?foo");
+            legend.update();
+            t.eq(legend.items.get(1).url, Ext.BLANK_IMAGE_URL+"?foo", "Legend content updated correctly");
+
+        }
+
+        function test_supports(t) {
+            t.plan(2);
+            var Rec = GeoExt.data.LayerRecord.create([{
+                name: "legendURL"
+            }]);
+            var rec = new Rec({
+                layer: new OpenLayers.Layer(),
+                legendURL: "foo"
+            });
+            t.eq(GeoExt.UrlLegend.supports(rec), true, "layer record with a legendURL property is supported.");
+
+            var rec = new Rec({
+                layer: new OpenLayers.Layer()
+            });
+            t.eq(GeoExt.UrlLegend.supports(rec), false, "layer record without a legendURL property is not supported.");
+        }
+
+    </script>
+  <body>
+    <div id="legend"></div>
+  </body>
+</html>
\ No newline at end of file

Copied: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/WMSLegend.html (from rev 1709, core/trunk/geoext/tests/lib/GeoExt/widgets/WMSLegend.html)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/WMSLegend.html	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/WMSLegend.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,187 @@
+<!DOCTYPE html>
+<html debug="true">
+  <head>
+    <script type="text/javascript" src="../../../../../openlayers/lib/OpenLayers.js"></script>
+    <script type="text/javascript" src="../../../../../ext/adapter/ext/ext-base.js"></script>
+    <script type="text/javascript" src="../../../../../ext/ext-all.js"></script>
+    <script type="text/javascript" src="../../../../lib/GeoExt.js"></script>
+
+    <script type="text/javascript">
+
+        function loadMapPanel() {
+            var mapPanel = new GeoExt.MapPanel({
+                // panel options
+                id: "map-panel",
+                title: "GeoExt MapPanel",
+                renderTo: "mappanel",
+                height: 400,
+                width: 600,
+                // map panel-specific options
+                layers: [
+                    new OpenLayers.Layer.WMS("test", '/ows', {layers: 'a'})
+                ],
+                center: new OpenLayers.LonLat(5, 45),
+                zoom: 4
+            });
+
+            return mapPanel;
+        }
+
+        function test_legendurl(t) {
+            t.plan(5);
+
+            var l, url, expectedUrl;
+            var mapPanel = loadMapPanel();
+            l = new GeoExt.WMSLegend({
+                renderTo: 'legendwms',
+                layerRecord: mapPanel.layers.getAt(0)
+            });
+            l.render();
+
+            url = l.items.get(1).url;
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&LAYER=a";
+            t.eq(url, expectedUrl, "GetLegendGraphic url is generated correctly");
+            l.destroy()
+            
+            mapPanel.map.layers[0].params.STYLES = "bar";
+            mapPanel.layers.getAt(0).set("styles", [{
+                name: "bar",
+                legend: {href: "foo"}
+            }]);
+            l = new GeoExt.WMSLegend({
+                renderTo: 'legendwms',
+                layerRecord: mapPanel.layers.getAt(0)
+            });
+            l.render();
+            url = l.items.get(1).url;
+            t.eq(url, "foo", "legend url from styles field of layer record used correctly.");
+            l.destroy();
+            mapPanel.map.layers[0].params.STYLES = "";
+            
+            l = new GeoExt.WMSLegend({
+                renderTo: 'legendwms',
+                layerRecord: mapPanel.layers.getAt(0),
+                defaultStyleIsFirst: true
+            });
+            l.render();
+            url = l.items.get(1).url;
+            t.eq(url, "foo", "legend url from styles field of layer record used correctly when defaultStyleIsFirst set to true and layer has no STYLES param.");
+            l.destroy();
+
+            mapPanel.map.layers[0].params.SLD = "sld";
+            l = new GeoExt.WMSLegend({
+                renderTo: 'legendwms',
+                layerRecord: mapPanel.layers.getAt(0),
+                defaultStyleIsFirst: true
+            });
+            l.render();
+            url = l.items.get(1).url;
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&SLD=sld&LAYER=a";
+            t.eq(url, expectedUrl, "GetLegendGraphic url is generated when layer has SLD set");
+            l.destroy();
+            delete mapPanel.map.layers[0].params.SLD;
+
+            mapPanel.map.layers[0].params.SLD_BODY = "sld_body";
+            l = new GeoExt.WMSLegend({
+                renderTo: 'legendwms',
+                layerRecord: mapPanel.layers.getAt(0),
+                defaultStyleIsFirst: true
+            });
+            l.render();
+            url = l.items.get(1).url;
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&SLD_BODY=sld_body&LAYER=a";
+            t.eq(url, expectedUrl, "GetLegendGraphic url is generated when layer has SLD_BODY set");
+            l.destroy();
+            delete mapPanel.map.layers[0].params.SLD_BODY;
+
+            mapPanel.destroy();
+        }
+
+        function test_update(t) {
+            t.plan(8);
+
+            // set up
+
+            var mapPanel = loadMapPanel();
+            var layerRecord = mapPanel.layers.getAt(0);
+
+            var url, expectedUrl, cmp;
+
+            var l = new GeoExt.WMSLegend({
+                renderTo: 'legendwms',
+                layerRecord: layerRecord
+            });
+
+            // test
+
+            // #1
+            layerRecord.get("layer").mergeNewParams({
+                layers: "b"
+            });
+            l.update();
+            t.ok(!l.getComponent("a"),
+                 "update removes old components");
+            t.ok(l.getComponent("b"),
+                 "update adds new components");
+
+            // #2
+            layerRecord.get("layer").mergeNewParams({
+                layers: "b,c",
+                foo: "bar"
+            });
+            l.update();
+            t.ok(l.getComponent("b"),
+                 "update does not remove components to be updated");
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&LAYER=b";
+            t.eq(l.getComponent("b").url, expectedUrl,
+                 "update updates component URL");
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&LAYER=c";
+            t.eq(l.getComponent("c").url, expectedUrl,
+                 "update sets correct URL in new component");
+
+            // #3
+            layerRecord.get("layer").mergeNewParams({
+                layers: "c",
+                styles: "style1"
+            });
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&LAYER=c&STYLE=style1";
+            l.update();
+            t.eq(l.getComponent("c").url, expectedUrl,
+                 "update sets correct STYLE params in URL");
+
+            // #4
+            layerRecord.set("styles", [{
+                name: "style1",
+                legend: {
+                    href: "http://url-to-legend.org/"
+                }
+            }]);
+            l.update();
+            expectedUrl = "http://url-to-legend.org/";
+            t.eq(l.getComponent("c").url, expectedUrl,
+                 "update uses the legend href from the styles field");
+
+            // #5
+            layerRecord.get("layer").mergeNewParams({
+                layers: "c",
+                styles: null,
+                sld: "http://url-to-sld.org/"
+            });
+            l.update();
+            expectedUrl = "/ows?SERVICE=WMS&VERSION=1.1.1&REQUEST=GetLegendGraphic&EXCEPTIONS=application%2Fvnd.ogc.se_xml&FORMAT=image%2Fgif&FOO=bar&SLD=http%3A%2F%2Furl-to-sld.org%2F&LAYER=c";
+            t.eq(l.getComponent("c").url, expectedUrl,
+                 "update does not use the legend href from the " +
+                 "styles field if SLD is set in the layer params");
+
+            // tear down
+
+            l.destroy()
+        }
+
+
+    </script>
+  <body>
+    <div id="legendwms"></div>
+    <div id="mappanel"></div>
+  </body>
+</html>

Modified: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/LayerNode.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -30,7 +30,7 @@
         
         function test_render(t) {
             
-            t.plan(8);
+            t.plan(6);
             
             var layer = new OpenLayers.Layer("foo");
             
@@ -41,15 +41,10 @@
             
             var node = new GeoExt.tree.LayerNode({
                 layer: "foo",
-                radioGroup: "group",
                 checkedGroup: "check"
             });
-            
-            node.on("radiochange", function() {
-                t.ok(arguments[0] === node, "radiochange event triggered with the selected node as first argument");
-            });
-                        
-            var panel = new Ext.tree.TreePanel({
+
+           var panel = new Ext.tree.TreePanel({
                 renderTo: "tree",
                 root: node
             });
@@ -58,10 +53,7 @@
                 t.ok(node.layer === layer, "layer found on detected map panel");
 
                 t.ok(node.ui.checkbox, "node has a checkbox");
-                t.ok(node.ui.radio, "node has a radio button");
-                // simulate a click event for testing the radiochange event
-                node.ui.onClick({getTarget: function() {return true}});
-                
+
                 t.eq(node.ui.checkbox.type, "radio", "checkbox rendered as radio button when checkedGroup is configured");
                 t.eq(node.ui.checkbox.name, "check_checkbox", "option group name set correctly according to checkedGroup");
                 

Copied: sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/RadioButtonMixin.html (from rev 1709, core/trunk/geoext/tests/lib/GeoExt/widgets/tree/RadioButtonMixin.html)
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/RadioButtonMixin.html	                        (rev 0)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/lib/GeoExt/widgets/tree/RadioButtonMixin.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -0,0 +1,57 @@
+<html>
+    <head>
+        <script src="../../../../../../openlayers/lib/OpenLayers.js"></script>
+        <script src="../../../../../../ext/adapter/ext/ext-base.js"></script>
+        <script src="../../../../../../ext/ext-all-debug.js"></script>
+        <script src="../../../../../lib/GeoExt.js"></script>
+    
+        <script>
+       
+        function test_render(t) {
+            
+            t.plan(2);
+            
+            var layer = new OpenLayers.Layer("foo");
+            
+            var mapPanel = new GeoExt.MapPanel({
+                layers: [layer],
+                allOverlays: true
+            });
+
+            var ui = Ext.extend(
+                GeoExt.tree.LayerNodeUI,
+                new GeoExt.tree.RadioButtonMixin()
+            );
+            
+            var node = new GeoExt.tree.LayerNode({
+                layer: "foo",
+                radioGroup: "group",
+                uiProvider: ui
+            });
+            
+            node.on("radiochange", function() {
+                t.ok(arguments[0] === node, "radiochange event triggered with the selected node as first argument");
+            });
+                        
+            var panel = new Ext.tree.TreePanel({
+                renderTo: "tree",
+                root: node
+            });
+            
+            mapPanel.on("render", function() {
+                t.ok(Ext.Element.get(node.ui.anchor.previousSibling).hasClass("gx-tree-radio"), "node has a radio button");
+                // simulate a click event for testing the radiochange event
+                node.ui.onClick({getTarget: function() {return true}});
+            });
+
+            mapPanel.render("map");
+            
+            mapPanel.destroy();
+        }
+        </script>
+    </head>
+    <body>
+        <div id="map" style="width: 100px; height: 100px;"></div>
+        <div id="tree" style="width: 100px; height: 100px;"></div>
+    </body>
+</html>

Modified: sandbox/ahocevar/playground/trunk/geoext/tests/list-tests.html
===================================================================
--- sandbox/ahocevar/playground/trunk/geoext/tests/list-tests.html	2010-01-11 10:32:33 UTC (rev 1709)
+++ sandbox/ahocevar/playground/trunk/geoext/tests/list-tests.html	2010-01-11 12:47:52 UTC (rev 1710)
@@ -26,11 +26,14 @@
   <li>lib/GeoExt/widgets/tree/LayerContainer.html</li>
   <li>lib/GeoExt/widgets/tree/LayerLoader.html</li>
   <li>lib/GeoExt/widgets/tree/LayerNode.html</li>
+  <li>lib/GeoExt/widgets/tree/RadioButtonMixin.html</li>
   <li>lib/GeoExt/widgets/tree/LayerParamLoader.html</li>
   <li>lib/GeoExt/widgets/tree/LayerParamNode.html</li>
   <li>lib/GeoExt/widgets/LegendImage.html</li>
   <li>lib/GeoExt/widgets/LegendPanel.html</li>
-  <li>lib/GeoExt/widgets/LegendWMS.html</li>
+  <li>lib/GeoExt/widgets/LayerLegend.html</li>
+  <li>lib/GeoExt/widgets/UrlLegend.html</li>
+  <li>lib/GeoExt/widgets/WMSLegend.html</li>
   <li>lib/GeoExt/widgets/ZoomSlider.html</li>
   <li>lib/GeoExt/widgets/grid/FeatureSelectionModel.html</li>
 </ul>



More information about the Commits mailing list