[Commits] r1970 - in core/trunk/geoext: examples lib/GeoExt/widgets tests/lib/GeoExt/widgets

commits at geoext.org commits at geoext.org
Tue Mar 16 14:56:40 CET 2010


Author: elemoine
Date: 2010-03-16 14:56:39 +0100 (Tue, 16 Mar 2010)
New Revision: 1970

Modified:
   core/trunk/geoext/examples/mappanel-div.html
   core/trunk/geoext/examples/mappanel-div.js
   core/trunk/geoext/lib/GeoExt/widgets/MapPanel.js
   core/trunk/geoext/tests/lib/GeoExt/widgets/MapPanel.html
Log:
make the MapPanel stateful, so map position, layer visibility, and layer opacity can be stored and restored through an Ext.state.Provider, r=bartvde (closes #94)

Modified: core/trunk/geoext/examples/mappanel-div.html
===================================================================
--- core/trunk/geoext/examples/mappanel-div.html	2010-03-16 13:46:09 UTC (rev 1969)
+++ core/trunk/geoext/examples/mappanel-div.html	2010-03-16 13:56:39 UTC (rev 1970)
@@ -16,6 +16,11 @@
         <p>This example shows the how to create a MapPanel with a map that has
         already been created.  See <a href="mappanel-window.html">mappanel-window.html</a>
         for an example that creates the MapPanel without creating the map first.<p>
+        <p>This example makes use of a <code>CookieProvider</code>. The <code>MapPanel</code>
+        being a stateful component, if you reload the page the map should be
+        at the same location as previously. Also the <code>getState</code> and
+        <code>applyState</code> methods are overloaded so the size of the map
+        panel is also restored when refreshing the page.</p>
         <p>The js is not minified so it is readable. See <a href="mappanel-div.js">mappanel-div.js</a>.</p>
         <div id="mappanel"></div>
         <input type="button" onclick="mapSizeUp()" value="bigger"></input>

Modified: core/trunk/geoext/examples/mappanel-div.js
===================================================================
--- core/trunk/geoext/examples/mappanel-div.js	2010-03-16 13:46:09 UTC (rev 1969)
+++ core/trunk/geoext/examples/mappanel-div.js	2010-03-16 13:56:39 UTC (rev 1970)
@@ -15,6 +15,7 @@
 var mapPanel;
 
 Ext.onReady(function() {
+    Ext.state.Manager.setProvider(new Ext.state.CookieProvider());
     var map = new OpenLayers.Map();
     var layer = new OpenLayers.Layer.WMS(
         "Global Imagery",
@@ -26,11 +27,25 @@
     mapPanel = new GeoExt.MapPanel({
         title: "GeoExt MapPanel",
         renderTo: "mappanel",
+        stateId: "mappanel",
         height: 400,
         width: 600,
         map: map,
         center: new OpenLayers.LonLat(5, 45),
-        zoom: 4
+        zoom: 4,
+        // getState and applyState are overloaded so panel size
+        // can be stored and restored
+        getState: function() {
+            var state = GeoExt.MapPanel.prototype.getState.apply(this);
+            state.width = this.getSize().width;
+            state.height = this.getSize().height;
+            return state;
+        },
+        applyState: function(state) {
+            GeoExt.MapPanel.prototype.applyState.apply(this, arguments);
+            this.width = state.width;
+            this.height = state.height;
+        }
     });
 });
 

Modified: core/trunk/geoext/lib/GeoExt/widgets/MapPanel.js
===================================================================
--- core/trunk/geoext/lib/GeoExt/widgets/MapPanel.js	2010-03-16 13:46:09 UTC (rev 1969)
+++ core/trunk/geoext/lib/GeoExt/widgets/MapPanel.js	2010-03-16 13:56:39 UTC (rev 1970)
@@ -85,13 +85,29 @@
      */
     zoom: null,
 
+    /** api: config[prettyStateKeys]
+     *  ``Boolean`` Set this to true if you want pretty strings in the MapPanel's
+     *  state keys. More specifically, layer.name instead of layer.id will be used
+     *  in the state keys if this option is set to true. But in that case you have
+     *  to make sure you don't have two layers with the same name. Defaults to 
+     *  false.
+     */
+    prettyStateKeys: false,
+
     /** api: config[extent]
      *  ``OpenLayers.Bounds or Array(Number)``  An initial extent for the map (used
      *  if center and zoom are not provided.  If an array, the first four items
      *  should be minx, miny, maxx, maxy.
      */
     extent: null,
-    
+
+    /** private: property[stateEvents]
+     *  ``Array(String)`` Array of state events
+     */
+    stateEvents: ["aftermapmove",
+                  "afterlayervisibilitychange",
+                  "afterlayeropacitychange"],
+
     /** private: method[initComponent]
      *  Initializes the map panel. Creates an OpenLayers map if
      *  none was provided in the config options passed to the
@@ -122,9 +138,129 @@
             this.extent = OpenLayers.Bounds.fromArray(this.extent);
         }
         
-        GeoExt.MapPanel.superclass.initComponent.call(this);       
+        GeoExt.MapPanel.superclass.initComponent.call(this);
+
+        this.addEvents(
+            /** private: event[aftermapmove]
+             *  Fires after the map is moved.
+             */
+            "aftermapmove",
+
+            /** private: event[afterlayervisibilitychange]
+             *  Fires after a layer changed visibility.
+             */
+            "afterlayervisibilitychange",
+
+            /** private: event[afterlayeropacitychange]
+             *  Fires after a layer changed opacity.
+             */
+            "afterlayeropacitychange"
+        );
+        this.map.events.on({
+            "moveend": this.onMoveend,
+            "changelayer": this.onLayerchange,
+            scope: this
+        });
     },
-    
+
+    /** private: method[onMoveend]
+     *
+     *  The "moveend" listener.
+     */
+    onMoveend: function() {
+        this.fireEvent("aftermapmove");
+    },
+
+    /** private: method[onLayerchange]
+     *  :param e: ``Object``
+     *
+     * The "changelayer" listener.
+     */
+    onLayerchange: function(e) {
+        if(e.property) {
+            if(e.property === "visibility") {
+                this.fireEvent("afterlayervisibilitychange");
+            } else if(e.property === "opacity") {
+                this.fireEvent("afterlayeropacitychange");
+            }
+        }
+    },
+
+    /** private: method[applyState]
+     *  :param state: ``Object`` The state to apply.
+     *
+     *  Apply the state provided as an argument.
+     */
+    applyState: function(state) {
+
+        // if we get strings for state.x, state.y or state.zoom
+        // OpenLayers will take care of converting them to the
+        // appropriate types so we don't bother with that
+        this.center = new OpenLayers.LonLat(state.x, state.y);
+        this.zoom = state.zoom;
+
+        // set layer visibility and opacity
+        var i, l, layer, layerId, visibility, opacity;
+        var layers = this.map.layers;
+        for(i=0, l=layers.length; i<l; i++) {
+            layer = layers[i];
+            layerId = this.prettyStateKeys ? layer.name : layer.id;
+            visibility = state["visibility_" + layerId];
+            if(visibility !== undefined) {
+                // convert to boolean
+                visibility = (/^true$/i).test(visibility);
+                if(layer.isBaseLayer) {
+                    if(visibility) {
+                        this.map.setBaseLayer(layer);
+                    }
+                } else {
+                    layer.setVisibility(visibility);
+                }
+            }
+            opacity = state["opacity_" + layerId];
+            if(opacity !== undefined) {
+                layer.setOpacity(opacity);
+            }
+        }
+    },
+
+    /** private: method[getState]
+     *  :return:  ``Object`` The state.
+     *
+     *  Returns the current state for the map panel.
+     */
+    getState: function() {
+        var state;
+
+        // Ext delays the call to getState when a state event
+        // occurs, so the MapPanel may have been destroyed
+        // between the time the event occurred and the time
+        // getState is called
+        if(!this.map) {
+            return;
+        }
+
+        // record location and zoom level
+        var center = this.map.getCenter();
+        state = {
+            x: center.lon,
+            y: center.lat,
+            zoom: this.map.getZoom()
+        };
+
+        // record layer visibility and opacity
+        var i, l, layer, layerId, layers = this.map.layers;
+        for(i=0, l=layers.length; i<l; i++) {
+            layer = layers[i];
+            layerId = this.prettyStateKeys ? layer.name : layer.id;
+            state["visibility_" + layerId] = layer.getVisibility();
+            state["opacity_" + layerId] = layer.opacity == null ?
+                1 : layer.opacity;
+        }
+
+        return state;
+    },
+
     /** private: method[updateMapSize]
      *  Tell the map that it needs to recalculate its size and position.
      */
@@ -208,10 +344,15 @@
             this.ownerCt.un("move", this.updateMapSize, this);
         }
         GeoExt.MapPanel.superclass.beforeDestroy.apply(this, arguments);
-        /**
-         * If this container was passed a map instance, it is the
-         * responsibility of the creator to destroy it.
-         */
+        // if the map panel was passed a map instance, this map instance
+        // is under the user's responsibility
+        if(this.map && this.map.events) {
+            this.map.events.un({
+                "moveend": this.onMoveend,
+                "changelayer": this.onLayerchange,
+                scope: this
+            });
+        }
         if(!this.initialConfig.map ||
            !(this.initialConfig.map instanceof OpenLayers.Map)) {
             // we created the map, we destroy it

Modified: core/trunk/geoext/tests/lib/GeoExt/widgets/MapPanel.html
===================================================================
--- core/trunk/geoext/tests/lib/GeoExt/widgets/MapPanel.html	2010-03-16 13:46:09 UTC (rev 1969)
+++ core/trunk/geoext/tests/lib/GeoExt/widgets/MapPanel.html	2010-03-16 13:56:39 UTC (rev 1970)
@@ -291,7 +291,288 @@
             panel.destroy();
         }
 
+        function test_applyState_called(t) {
+            t.plan(1);
 
+            // set up
+
+            var provider, applyState, mapPanel, log;
+
+            provider = new Ext.state.Provider();
+            provider.state["map"] = {};
+            Ext.state.Manager.setProvider(provider);
+
+            applyState = GeoExt.MapPanel.prototype.applyState;
+            GeoExt.MapPanel.prototype.applyState = function(state) {
+                log = true;
+            };
+
+            // test
+
+            // test that applyState gets called when the MapPanel is created
+            // 1 test
+            log = false;
+            mapPanel = new GeoExt.MapPanel({
+                renderTo: "mappanel",
+                stateId: "map",
+                height: 400,
+                width: 600
+            });
+            t.eq(log, true, "applyState called when creating the MapPanel");
+
+            // tear down
+
+            GeoExt.MapPanel.prototype.applyState = applyState;
+            mapPanel.destroy();
+        }
+
+        function test_applyState(t) {
+            t.plan(21);
+
+            // set up
+
+            var state;
+
+            var layers = [
+                new OpenLayers.Layer("foo", {visibility: false}),
+                new OpenLayers.Layer("bar", {visibility: false})
+            ];
+            layers[0].id = "fooid";
+            layers[1].id = "barid";
+            var mapPanel = new GeoExt.MapPanel({
+                renderTo: "mappanel",
+                stateId: "map",
+                prettyStateKeys: true,
+                height: 400,
+                width: 600,
+                layers: layers
+            });
+
+            // test
+
+            // test with numeric and boolean state values
+            state = {
+                x: 5,
+                y: 45,
+                zoom: 10,
+                visibility_foo: true,
+                visibility_bar: true,
+                opacity_foo: 0.2,
+                opacity_bar: 0.5
+            };
+            mapPanel.applyState(state);
+            t.eq(mapPanel.center.lon, 5,
+                 "mapPanel.center.lon correctly set [0]");
+            t.eq(mapPanel.center.lat, 45,
+                 "mapPanel.center.lat correctly set [0]");
+            t.eq(mapPanel.zoom, 10,
+                 "mapPanel.zoom correctly set [0]");
+            t.eq(layers[0].getVisibility(), true,
+                 "layer foo visibility is correct [0]");
+            t.eq(layers[1].getVisibility(), true,
+                 "layer bar visibility is correct [0]");
+            t.eq(layers[0].opacity, 0.2,
+                 "layer foo opacity is correct [0]");
+            t.eq(layers[1].opacity, 0.5,
+                 "layer bar opacity is correct [0]");
+
+            layers[0].visibility = false;
+            layers[1].visibility = false;
+            layers[0].opacity = null;
+            layers[1].opacity = null;
+ 
+            // test with string state values
+            state = {
+                x: "5",
+                y: "45",
+                zoom: "10",
+                visibility_foo: "true",
+                visibility_bar: "true",
+                opacity_foo: "0.2",
+                opacity_bar: "0.5"
+            };
+            mapPanel.applyState(state);
+            t.eq(mapPanel.center.lon, 5,
+                 "mapPanel.center.lon correctly set [1]");
+            t.eq(mapPanel.center.lat, 45,
+                 "mapPanel.center.lat correctly set [1]");
+            t.eq(mapPanel.zoom, "10",
+                 "mapPanel.zoom correctly set [1]");
+            t.eq(layers[0].getVisibility(), true,
+                 "layer foo visibility is correct [1]");
+            t.eq(layers[1].getVisibility(), true,
+                 "layer bar visibility is correct [1]");
+            t.eq(layers[0].opacity, "0.2",
+                 "layer foo opacity is correct [1]");
+            t.eq(layers[1].opacity, "0.5",
+                 "layer bar opacity is correct [1]");
+
+            layers[0].visibility = false;
+            layers[1].visibility = false;
+            layers[0].opacity = null;
+            layers[1].opacity = null;
+
+            // test with prettyStateKeys set to false
+            mapPanel.prettyStateKeys = false;
+            state = {
+                x: "5",
+                y: "45",
+                zoom: "10",
+                visibility_fooid: "true",
+                visibility_barid: "true",
+                opacity_fooid: "0.2",
+                opacity_barid: "0.5"
+            };
+            mapPanel.applyState(state);
+            t.eq(mapPanel.center.lon, 5,
+                 "mapPanel.center.lon correctly set [1]");
+            t.eq(mapPanel.center.lat, 45,
+                 "mapPanel.center.lat correctly set [1]");
+            t.eq(mapPanel.zoom, "10",
+                 "mapPanel.zoom correctly set [1]");
+            t.eq(layers[0].getVisibility(), true,
+                 "layer foo visibility is correct [1]");
+            t.eq(layers[1].getVisibility(), true,
+                 "layer bar visibility is correct [1]");
+            t.eq(layers[0].opacity, "0.2",
+                 "layer foo opacity is correct [1]");
+            t.eq(layers[1].opacity, "0.5",
+                 "layer bar opacity is correct [1]");
+
+            // tear down
+
+            mapPanel.destroy();
+        }
+
+        function test_getState_called(t) {
+            t.plan(2);
+
+            // set up
+
+            var getState, mapPanel, log;
+
+            getState = GeoExt.MapPanel.prototype.getState;
+            GeoExt.MapPanel.prototype.getState = function(state) {
+                log = true;
+            };
+
+            mapPanel = new GeoExt.MapPanel({
+                renderTo: "mappanel",
+                layers: [
+                    new OpenLayers.Layer("foo")
+                ],
+                stateId: "map",
+                height: 400,
+                width: 600
+            });
+
+            // test
+
+            // test that getState gets called when the map is moved
+            // 1 test
+            log = false;
+            mapPanel.map.setCenter(new OpenLayers.LonLat(5, 45), 5);
+            t.delay_call(1, function() {
+                t.eq(log, true, "getState called when map is moved");
+            });
+
+            // test that getState gets called when layer visibility
+            // is changed
+            // 1 test
+            log = false;
+            mapPanel.map.layers[0].setVisibility(false);
+            t.delay_call(1, function() {
+                t.eq(log, true, "getState called when layer visibility is changed");
+
+                // tear down
+
+                GeoExt.MapPanel.prototype.getState = getState;
+                mapPanel.destroy();
+            });
+        }
+
+        function test_getState(t) {
+            t.plan(14);
+
+            // set up
+
+            var state;
+
+            // test
+
+            // test with prettyStateKeys set to true
+            var layers = [
+                new OpenLayers.Layer("foo", {visibility: true}),
+                new OpenLayers.Layer("bar", {visibility: false})
+            ];
+            layers[0].id = "fooid";
+            layers[1].id = "barid";
+            var mapPanel = new GeoExt.MapPanel({
+                renderTo: "mappanel",
+                prettyStateKeys: true,
+                stateId: "map",
+                height: 400,
+                width: 600,
+                layers: layers,
+                center: [5, 45],
+                zoom: 6
+            });
+            layers[0].setOpacity(0.5);
+
+            state = mapPanel.getState();
+            t.eq(state.x, 5,
+                 "state.x correctly set");
+            t.eq(state.y, 45,
+                 "state.y correctly set");
+            t.eq(state.zoom, 6,
+                 "state.zoom correctly set");
+            t.eq(state.visibility_foo, true,
+                 "state.visibility_foo correctly set");
+            t.eq(state.visibility_bar, false,
+                 "state.visibility_bar correctly set");
+            t.eq(state.opacity_foo, 0.5,
+                 "state.opacity_foo correctly set");
+            t.eq(state.opacity_bar, 1,
+                 "state.opacity_bar correctly set");
+            mapPanel.destroy();
+
+            // test with prettyStateKeys set to false
+            var layers = [
+                new OpenLayers.Layer("foo", {visibility: true}),
+                new OpenLayers.Layer("bar", {visibility: false})
+            ];
+            layers[0].id = "fooid";
+            layers[1].id = "barid";
+            var mapPanel = new GeoExt.MapPanel({
+                renderTo: "mappanel",
+                prettyStateKeys: false,
+                stateId: "map",
+                height: 400,
+                width: 600,
+                layers: layers,
+                center: [5, 45],
+                zoom: 6
+            });
+            layers[0].setOpacity(0.5);
+
+            mapPanel.prettyStateKeys = false;
+            state = mapPanel.getState();
+            t.eq(state.x, 5,
+                 "state.x correctly set");
+            t.eq(state.y, 45,
+                 "state.y correctly set");
+            t.eq(state.zoom, 6,
+                 "state.zoom correctly set");
+            t.eq(state.visibility_fooid, true,
+                 "state.visibility_fooid correctly set");
+            t.eq(state.visibility_barid, false,
+                 "state.visibility_barid correctly set");
+            t.eq(state.opacity_fooid, 0.5,
+                 "state.opacity_fooid correctly set");
+            t.eq(state.opacity_barid, 1,
+                 "state.opacity_barid correctly set");
+            mapPanel.destroy();
+        }
     </script>
   </head>
   <body>



More information about the Commits mailing list