[Commits] r2247 - in sandbox/foss4g2010/src/doc: . basics layout wfs

commits at geoext.org commits at geoext.org
Fri Jul 30 14:32:45 CEST 2010


Author: pgiraud
Date: 2010-07-30 14:32:45 +0200 (Fri, 30 Jul 2010)
New Revision: 2247

Added:
   sandbox/foss4g2010/src/doc/wfs/
   sandbox/foss4g2010/src/doc/wfs/editing.png
   sandbox/foss4g2010/src/doc/wfs/editing.rst
   sandbox/foss4g2010/src/doc/wfs/grid.png
   sandbox/foss4g2010/src/doc/wfs/grid.rst
   sandbox/foss4g2010/src/doc/wfs/index.rst
   sandbox/foss4g2010/src/doc/wfs/layer.png
   sandbox/foss4g2010/src/doc/wfs/layer.rst
   sandbox/foss4g2010/src/doc/wfs/wfst.png
   sandbox/foss4g2010/src/doc/wfs/wfst.rst
Removed:
   sandbox/foss4g2010/src/doc/layout/toolbar.rst
Modified:
   sandbox/foss4g2010/src/doc/basics/dissect.rst
   sandbox/foss4g2010/src/doc/basics/map.rst
   sandbox/foss4g2010/src/doc/basics/map1.png
   sandbox/foss4g2010/src/doc/index.rst
   sandbox/foss4g2010/src/doc/layout/index.rst
   sandbox/foss4g2010/src/doc/layout/layout.rst
   sandbox/foss4g2010/src/doc/layout/legend.rst
   sandbox/foss4g2010/src/doc/layout/tree.rst
   sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst
Log:
OpenGeo workshop update, more work to come

Modified: sandbox/foss4g2010/src/doc/basics/dissect.rst
===================================================================
--- sandbox/foss4g2010/src/doc/basics/dissect.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/basics/dissect.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -113,11 +113,18 @@
         layout: "fit",
         items: [{
             xtype: "gx_mappanel",
-            layers: [new OpenLayers.Layer.WMS(
-                "Imagery",
-                "/geoserver/ows?",
-                {layers: "bluemarble"}
-            )]
+            layers: [new OpenLayers.Layer.WMS("Global Imagery",
+                "http://maps.opengeo.org/geowebcache/service/wms", {
+                    layers: "bluemarble"
+                }, {
+                    buffer: 0,
+                    visibility: false
+                }
+            )],
+            extent: new OpenLayers.Bounds(
+                143.83482400000003, -43.648056,
+                148.47914100000003, -39.573891
+            )
         }
     }
 
@@ -140,6 +147,9 @@
 If we want our MapPanel to zoom to the first layer's maximum extent, there is
 nothing else we need to configure.
 
+The last property ``extent`` is here to tell the OpenLayers map to zoom to the
+given extent when initialized.
+
 .. note::
 
     The following two notations are equivalent:

Modified: sandbox/foss4g2010/src/doc/basics/map.rst
===================================================================
--- sandbox/foss4g2010/src/doc/basics/map.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/basics/map.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -32,17 +32,17 @@
     <html>
         <head>
             <title>GeoExt Map Window</title>
-    
+
             <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
             <script type="text/javascript" src="ext/ext-all.js"></script>
             <link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css" />
             <script src="openlayers/lib/OpenLayers.js"></script>
-    
+
             <script type="text/javascript" src="geoext/lib/GeoExt.js"></script>
-            
+
             <script type="text/javascript">
             Ext.BLANK_IMAGE_URL = "ext/resources/images/default/s.gif";
-            
+
             Ext.onReady(function() {
                 new Ext.Window({
                     title: "My Map Window",
@@ -52,10 +52,14 @@
                     items: [{
                         xtype: "gx_mappanel",
                         layers: [new OpenLayers.Layer.WMS(
-                            "Imagery",
-                            "/geoserver/ows?",
-                            {layers: "bluemarble"}
-                        )]
+                            "Tasmania",
+                            "/geoserver/wms?",
+                            {layers: "tasmania"}
+                        )],
+                        extent: new OpenLayers.Bounds(
+                            143.83482400000003, -43.648056,
+                            148.47914100000003, -39.573891
+                        )
                     }]
                 }).show();
             });

Modified: sandbox/foss4g2010/src/doc/basics/map1.png
===================================================================
(Binary files differ)

Modified: sandbox/foss4g2010/src/doc/index.rst
===================================================================
--- sandbox/foss4g2010/src/doc/index.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/index.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -21,11 +21,10 @@
     Add some standard GeoExt widgets such as Layer Tree, LegendPanel, as well
     as User Extension such as WMSBrowser.
     Put them all in a well organized interface using a ViewPort.
+
+:ref:`geoext.wfs`
+    Create a WFS-T editor with a synchronized map and table view.
     
-:ref:`geoext.features`
-    Learn how to load features from a WFS service, display them in a grid and
-    in the map, then synchronize feature selection between grid and map.
-    
 :ref:`geoext.editing`
     Enable feature editing.
 
@@ -34,5 +33,5 @@
 
     basics/index
     layout/index
-    features/index
+    wfs/index
     editing/index

Modified: sandbox/foss4g2010/src/doc/layout/index.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/index.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/index.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -18,6 +18,5 @@
    
     Add a Tree to Manage the Map Layers <tree>
     Create a LegendPanel <legend>
-    Plug a WMSBrowser <wmsbrowser>
     Organize the Application Interface Using a ViewPort <layout>
-    Add a Toolbar to the MapPanel <toolbar>
+    Plug a WMSBrowser <wmsbrowser>

Modified: sandbox/foss4g2010/src/doc/layout/layout.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/layout.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/layout.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -3,3 +3,113 @@
 Organize the Application Interface Using a ViewPort
 ===================================================
 
+.. code-block:: javascript
+
+        Ext.onReady(function() {
+            var layers = [
+                new OpenLayers.Layer.WMS("Global Imagery",
+                    "http://maps.opengeo.org/geowebcache/service/wms", {
+                        layers: "bluemarble"
+                    }, {
+                        buffer: 0,
+                        visibility: false
+                    }
+                ),
+                new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+                    "/geoserver/wms", {
+                        layers: "topp:tasmania_state_boundaries"
+                    }, {
+                        buffer: 0
+                    }
+                ),
+                new OpenLayers.Layer.WMS("Water",
+                    "/geoserver/wms", {
+                        layers: "topp:tasmania_water_bodies",
+                        transparent: true,
+                        format: "image/gif"
+                    }, {
+                        isBaseLayer: false,
+                        buffer: 0
+                    }
+                ),
+                new OpenLayers.Layer.WMS("Cities",
+                    "/geoserver/wms", {
+                        layers: "topp:tasmania_cities",
+                        transparent: true,
+                        format: "image/gif"
+                    }, {
+                        isBaseLayer: false,
+                        buffer: 0
+                    }
+                ),
+                new OpenLayers.Layer.WMS("Tasmania Roads",
+                    "/geoserver/wms", {
+                        layers: "topp:tasmania_roads",
+                        transparent: true,
+                        format: "image/gif"
+                    }, {
+                        isBaseLayer: false,
+                        buffer: 0
+                    }
+                ),
+                // create a group layer (with several layers in the "layers" param)
+                // to show how the LayerParamLoader works
+                new OpenLayers.Layer.WMS("Tasmania (Group Layer)",
+                    "/geoserver/wms", {
+                        layers: [
+                            "topp:tasmania_state_boundaries",
+                            "topp:tasmania_water_bodies",
+                            "topp:tasmania_cities",
+                            "topp:tasmania_roads"
+                        ],
+                        transparent: true,
+                        format: "image/gif"
+                    }, {
+                        isBaseLayer: false,
+                        buffer: 0,
+                        // exclude this layer from layer container nodes
+                        displayInLayerSwitcher: false,
+                        visibility: false
+                    }
+                )
+            ];
+
+            var mappanel = new GeoExt.MapPanel({
+                extent: new OpenLayers.Bounds(
+                    143.83482400000003, -43.648056,
+                    148.47914100000003, -39.573891
+                ),
+                map: new OpenLayers.Map({allOverlays: false}),
+                layers: layers,
+                region: 'center'
+            });
+
+            new Ext.Viewport({
+                layout: 'border',
+                items: [mappanel]
+            });
+        });
+
+.. code-block:: javascript
+
+    {
+        xtype: 'tabpanel',
+        region: 'west',
+        width: 250
+    }
+
+
+.. code-block:: javascript
+
+    activeTab: 0,
+    items: [tree]
+
+.. note::
+
+    Don't forget to add a title to the tree panel.
+    Also no need to render the panel, the rendering will be done by Ext while doing the layout.
+
+Repeat the same operation for legendPanel. You should now have a column on the left with two tabs.
+
+.. code-block:: javascript
+

Modified: sandbox/foss4g2010/src/doc/layout/legend.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/legend.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/legend.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -2,3 +2,14 @@
 
 Create a LegendPanel
 ====================
+
+.. code-block:: javascript
+
+    var legendPanel = new GeoExt.LegendPanel({
+        defaults: {
+            labelCls: 'mylabel',
+            style: 'padding:5px'
+        },
+        bodyStyle: 'padding:5px'
+    });
+    legendPanel.render(document.body);

Deleted: sandbox/foss4g2010/src/doc/layout/toolbar.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/toolbar.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/toolbar.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -1,5 +0,0 @@
-.. _geoext.layout.toolbar:
-
-Add a Toolbar to the MapPanel
-=============================
-

Modified: sandbox/foss4g2010/src/doc/layout/tree.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/tree.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/tree.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -2,3 +2,120 @@
 
 Add a Tree to Manage the Map Layers
 ===================================
+
+We want several layers: base and overlay layers.
+Modify the ``layers`` array to match the following.
+
+.. code-block:: javascript
+
+    var layers = [
+        new OpenLayers.Layer.WMS("Global Imagery",
+            "http://maps.opengeo.org/geowebcache/service/wms", {
+                layers: "bluemarble"
+            }, {
+                buffer: 0,
+                visibility: false
+            }
+        ),
+        new OpenLayers.Layer.WMS("Tasmania State Boundaries",
+            "/geoserver/wms", {
+                layers: "topp:tasmania_state_boundaries"
+            }, {
+                buffer: 0
+            }
+        ),
+        new OpenLayers.Layer.WMS("Water",
+            "/geoserver/wms", {
+                layers: "topp:tasmania_water_bodies",
+                transparent: true,
+                format: "image/gif"
+            }, {
+                isBaseLayer: false,
+                buffer: 0
+            }
+        ),
+        new OpenLayers.Layer.WMS("Cities",
+            "/geoserver/wms", {
+                layers: "topp:tasmania_cities",
+                transparent: true,
+                format: "image/gif"
+            }, {
+                isBaseLayer: false,
+                buffer: 0
+            }
+        ),
+        new OpenLayers.Layer.WMS("Tasmania Roads",
+            "/geoserver/wms", {
+                layers: "topp:tasmania_roads",
+                transparent: true,
+                format: "image/gif"
+            }, {
+                isBaseLayer: false,
+                buffer: 0
+            }
+        ),
+        // create a group layer (with several layers in the "layers" param)
+        // to show how the LayerParamLoader works
+        new OpenLayers.Layer.WMS("Tasmania (Group Layer)",
+            "/geoserver/wms", {
+                layers: [
+                    "topp:tasmania_state_boundaries",
+                    "topp:tasmania_water_bodies",
+                    "topp:tasmania_cities",
+                    "topp:tasmania_roads"
+                ],
+                transparent: true,
+                format: "image/gif"
+            }, {
+                isBaseLayer: false,
+                buffer: 0,
+                // exclude this layer from layer container nodes
+                displayInLayerSwitcher: false,
+                visibility: false
+            }
+        )
+    ];
+
+Also, since we don't want all layers to be considered as overlays we need to set
+options for our map.
+Add the following to your `GeoExt.MapPanel` configuration object:
+
+.. code-block:: javascript
+
+    map: new OpenLayers.Map({allOverlays: false})
+
+.. code-block:: javascript
+
+    var treeConfig = [{
+        nodeType: "gx_baselayercontainer"
+    }, {
+        nodeType: "gx_overlaylayercontainer",
+        expanded: true
+    }, {
+        nodeType: "gx_layer",
+        layer: "Tasmania (Group Layer)",
+        isLeaf: false,
+        // create subnodes for the layers in the LAYERS param. If we assign
+        // a loader to a LayerNode and do not provide a loader class, a
+        // LayerParamLoader will be assumed.
+        loader: {
+            param: "LAYERS"
+        }
+    }];
+    var tree = new Ext.tree.TreePanel({
+        border: false,
+        loader: new Ext.tree.TreeLoader({
+            applyLoader: false
+        }),
+        root: {
+            nodeType: "async",
+            children: treeConfig
+        },
+        rootVisible: false
+    });
+    tree.render(document.body);
+
+Don't forget to add a title to the tree panel
+
+
+

Modified: sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst
===================================================================
--- sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst	2010-07-28 19:38:54 UTC (rev 2246)
+++ sandbox/foss4g2010/src/doc/layout/wmsbrowser.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -3,3 +3,9 @@
 Plug a WMSBrowser
 =================
 
+
+
+.. code-block:: javascript
+
+
+

Added: sandbox/foss4g2010/src/doc/wfs/editing.png
===================================================================
(Binary files differ)


Property changes on: sandbox/foss4g2010/src/doc/wfs/editing.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/foss4g2010/src/doc/wfs/editing.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/editing.rst	                        (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/editing.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,186 @@
+.. _geoext.wfs.editing:
+
+Editing Featuers and Their Attributes
+=====================================
+
+We will now enhance our application by making the layer and its attributes
+editable, and using WFS-T to commit changes.
+
+Making Layer and Grid Editable
+------------------------------
+
+Let's modify our application to allow for editing feature geometries and
+attributes. On the layer side this requires replacing the SelectFeature
+control that the FeatureSelectionModel automatically creates with a
+ModifyFeature control. On the grid side, we have to replace the GridPanel with
+an EditorGridPanel, provide editors for the columns, and reconfigure the
+FeatureSelectionModel a bit.
+
+.. rubric:: Tasks
+
+#.  Open :file:`wfs-editor.html` in your text editor. Add a ModifyFeature
+    control to the map and activate it. To do so, find the mapPanel
+    definition, and add the following code just below:
+    
+    .. code-block:: javascript
+
+        var modifyControl = new OpenLayers.Control.ModifyFeature(layer);
+        mapPanel.map.addControl(modifyControl);
+        modifyControl.activate();
+
+#.  Reconfigure the FeatureSelectionModel to use the internal SelectFeature
+    control of the modifyControl, and enable ``singleSelect`` (meaning that
+    only one feature can be selected at a time, which makes sense for
+    editing). The FeatureSelectionModel instantiation should now look like
+    this:
+    
+    .. code-block:: javascript
+
+        sm: new GeoExt.grid.FeatureSelectionModel({
+            selectControl: modifyControl.selectControl,
+            singleSelect: true
+        }),
+
+#.  Replace the GridPanel with an EditorGridPanel and configure editors for
+    the columns: TextField by default, and NumberField for the
+    "# of Facilities" column. This is how the whole gridPanel definition
+    should look now:
+    
+    .. code-block:: javascript
+
+        var gridPanel = new Ext.grid.EditorGridPanel({
+            title: "Feature Table - Manhattan (NY) landmarks",
+            region: "center",
+            viewConfig: {forceFit: true},
+            store: store,
+            sm: new GeoExt.grid.FeatureSelectionModel({
+                selectControl: modifyControl.selectControl,
+                singleSelect: true
+            }),
+            cm: new Ext.grid.ColumnModel({
+                defaults: {
+                    sortable: true,
+                    editor: {xtype: "textfield"}
+                },
+                columns: [
+                    {header: "Name", dataIndex: "LANAME"},
+                    {header: "CFCC", dataIndex: "CFCC"},
+                    {header: "Land", dataIndex: "LAND"}
+                ]
+            })
+        });
+
+Adding "Create" and "Delete" Buttons
+------------------------------------
+
+We are already able to modify existing features, but we also want to be able
+to add and remove features. To add features, we will use an
+`OpenLayers.Control.DrawFeature
+<http://dev.openlayers.org/releases/OpenLayers-2.9/doc/apidocs/files/OpenLayers/Control/DrawFeature-js.html>`_.
+Thanks to our FeatureStore, a feature added to the layer will automatically
+also show up in the grid. For deleting features, we add a button with a custom
+handler.
+
+.. rubric:: Tasks
+
+#.  Create a DrawFeature control. To do so, add the following right above the
+    mapPanel definition:
+    
+    .. code-block:: javascript
+    
+        var drawControl = new OpenLayers.Control.DrawFeature(
+            layer,
+            OpenLayers.Handler.Polygon,
+            {handlerOptions: {multi: true}}
+        );
+        
+    Add the following below the mapPanel definition:
+    
+    .. code-block:: javascript
+    
+        mapPanel.map.addControl(drawControl);
+
+#.  Add a bottom toolbar (``bbar``) property to the mapPanel definition. Now
+    the mapPanel definition should look like this:
+    
+    .. code-block:: javascript
+
+        var mapPanel = new GeoExt.MapPanel({
+            title: "Map",
+            region: "west",
+            width: 400,
+            layers: [layer],
+            extent: new OpenLayers.Bounds(-74.047, 40.68, -73.908, 40.882),
+            bbar: [
+                new GeoExt.Action({
+                    control: drawControl,
+                    text: "Create",
+                    enableToggle: true
+                }), {
+                    text: "Delete",
+                    handler: function() {
+                        gridPanel.getSelectionModel().each(function(rec) {
+                            var feature = rec.get("feature");
+                            modifyControl.unselectFeature(feature);
+                            store.remove(rec);
+                        })
+                    }
+                }
+            ]
+        });
+
+#.  Save your file. Open or refresh @workshop_url@/wfs-editor.html in your
+    browser. Double-click in a grid cell to modify it. Click on a feature in
+    the map and modify it by playing with the vertices. Remove a feature by
+    hitting "Delete". Hit "Create" and draw a new feature. Scroll down to the
+    bottom of the Feature Table and edit its attributes. Hit the "Create"
+    button again to turn back to selection mode.
+
+.. figure:: editing.png
+
+    Modified layer after heavy feature editing.
+
+A Closer Look
+`````````````
+The "Create" button uses a `GeoExt.Action
+<http://geoext.org/lib/GeoExt/widgets/Action.html>`_ to turn an OpenLayers
+control into a button. It is important to understand that any OpenLayers
+control can be added to a toolbar or menu by wrapping it into such an Action.
+
+.. code-block:: javascript
+
+    new GeoExt.Action({
+        control: drawControl,
+        text: "Create",
+        enableToggle: true
+    }),
+
+The "Delete" button is just a plain Ext.Button. When clicked, it performs the
+action defined in its handler.
+
+.. code-block:: javascript
+
+    {
+        text: "Delete",
+        handler: function() {
+            gridPanel.getSelectionModel().each(function(rec) {
+                var feature = rec.get("feature");
+                modifyControl.unselectFeature(feature);
+                store.remove(rec);
+            })
+        }
+    }
+
+The handler function uses the selection model's ``each`` method to walk
+through the selected records (which will either be none ore one in our case,
+with ``singleSelect`` set to true). Before removing the record, we use the
+modifyControl's ``unselectFeature`` method to remove the feature's editing
+vertices and unselect the feature, bringing the layer in a clean state.
+
+Next Steps
+----------
+
+It is nice to be able to create, modify and delete features, but finally we
+will need to save our changes. The :ref:`final section <geoext.wfs.wfst>` of
+this module will teach you how to use the WFS-T functionality of OpenLayers
+to commit changes to the server.

Added: sandbox/foss4g2010/src/doc/wfs/grid.png
===================================================================
(Binary files differ)


Property changes on: sandbox/foss4g2010/src/doc/wfs/grid.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/foss4g2010/src/doc/wfs/grid.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/grid.rst	                        (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/grid.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,190 @@
+.. _geoext.wfs.grid:
+
+Creating a Grid View of WFS Features
+====================================
+
+GeoExt borrows most of its WFS support from OpenLayers. What it does provide
+though is the `GeoExt.data.FeatureStore
+<http://geoext.org/lib/GeoExt/data/FeatureStore.html>`_, so showing feature
+attributes in a grid is a very easy task. If we just want to display features
+in a grid, we can use a `GeoExt.data.ProtocolProxy
+<http://geoext.org/lib/GeoExt/data/ProtocolProxy.html>`_, so we don't even
+need an OpenLayers layer.
+
+Vector Features in a Table
+--------------------------
+
+Let's start with some code that reads a WFS layer and displays the feature
+attributes in a table:
+
+.. _geoext.wfs.grid.grid:
+
+.. code-block:: html
+
+    <html>
+        <head>
+            <title>GeoExt WFS Editor</title>
+    
+            <script type="text/javascript" src="ext/adapter/ext/ext-base.js"></script>
+            <script type="text/javascript" src="ext/ext-all.js"></script>
+            <link rel="stylesheet" type="text/css" href="ext/resources/css/ext-all.css" />
+            <script src="openlayers/lib/OpenLayers.js"></script>
+    
+            <script type="text/javascript" src="geoext/lib/GeoExt.js"></script>
+            
+            <script type="text/javascript">
+            Ext.BLANK_IMAGE_URL = "ext/resources/images/default/s.gif";
+    
+            Ext.onReady(function() {
+                var store = new GeoExt.data.FeatureStore({
+                    fields: [
+                        {name: "LANAME", type: "string"},
+                        {name: "CFCC", type: "string"},
+                        {name: "LAND", type: "float"}
+                    ],
+                    proxy: new GeoExt.data.ProtocolProxy({
+                        protocol: new OpenLayers.Protocol.WFS({
+                            url: "/geoserver/ows",
+                            version: "1.1.0",
+                            featureType: "poly_landmarks",
+                            featureNS: "http://www.census.gov",
+                            srsName: "EPSG:4326"
+                        })
+                    }),
+                    autoLoad: true
+                });
+    
+                var gridPanel = new Ext.grid.GridPanel({
+                    title: "Feature Table - Manhattan (NY) landmarks",
+                    region: "center",
+                    viewConfig: {forceFit: true},
+                    store: store,
+                    cm: new Ext.grid.ColumnModel({
+                        defaults: {
+                            sortable: true
+                        },
+                        columns: [
+                            {header: "Name", dataIndex: "LANAME"},
+                            {header: "CFCC", dataIndex: "CFCC"},
+                            {header: "Land", dataIndex: "LAND"}
+                        ]
+                    })
+                });
+    
+                var mainPanel = new Ext.Panel({
+                    renderTo: document.body,
+                    layout: "border",
+                    height: 450,
+                    width: 800,
+                    items: [gridPanel]
+                });
+            });
+            </script>
+        </head>
+        <body>
+        </body>
+    </html>
+
+.. rubric:: Tasks
+
+#.  Open a text editor, paste the code from above into a new file and save it
+    as :file:`wfs-editor.html` in the root of your workshop directory.
+
+#.  After saving your changes, point your browser to
+    @workshop_url@/wfs-editor.html. You should see a grid, populated with
+    data.
+
+.. figure:: grid.png
+
+    A table view of WFS features.
+
+Understanding the FeatureStore
+``````````````````````````````
+Let's have a look at the FeatureStore definition:
+
+.. _geoext.wfs.grid.store:
+
+.. code-block:: javascript
+
+    var store = new GeoExt.data.FeatureStore({
+        fields: [
+            {name: "name", type: "string"},
+            {name: "owner", type: "string"},
+            {name: "usage", type: "string"},
+            {name: "number_fac", type: "int", defaultValue: 0}
+        ],
+        proxy: new GeoExt.data.ProtocolProxy({
+            protocol: new OpenLayers.Protocol.WFS({
+                url: "/geoserver/ows",
+                version: "1.1.0",
+                featureType: "parks",
+                featureNS: "http://medford.opengeo.org",
+                srsName: "EPSG:4326"
+            })
+        }),
+        autoLoad: true
+    });
+
+Two things are important: the field definition, and some way to tell the store
+where to get its data from.
+
+The field definition is straight forward -- we just need to make sure that we
+use the corect name of the attributes, and assign an appropriate type. Not all
+fields of the layer need to be mapped here -- only those we want to use. For
+the "number_fac" field we also set a default value, to make sure that we
+always display a number.
+
+There are many ways to tell a feature store where to find its data. When
+working with a map and a vector layer, it is enough to point it to that layer
+and it will synchronize itself with the layer. We will see how that works in
+the :ref:`next section <geoext.wfs.layer>`. For now, since we don't use a
+layer here, we use a ProtocolProxy. This is a wrapper for an
+`OpenLayers.Protocol
+<http://dev.openlayers.org/releases/OpenLayers-2.9/doc/apidocs/files/OpenLayers/Protocol-js.html>`_
+instance.
+
+A Closer Look at the Grid
+`````````````````````````
+A grid needs at least a store and a column definition to work properly. Let's
+see how we have done this for our feature grid:
+
+.. code-block:: javascript
+
+    var gridPanel = new Ext.grid.GridPanel({
+        title: "Feature Table - Medford Parks",
+        region: "center"
+        viewConfig: {forceFit: true},
+        store: store,
+        cm: new Ext.grid.ColumnModel({
+            defaults: {
+                sortable: true
+            },
+            columns: [
+                {header: "Name", dataIndex: "name"},
+                {header: "Owner", dataIndex: "owner"},
+                {header: "Usage", dataIndex: "usage", width: 35},
+                {
+                    xtype: "numbercolumn",
+                    header: "# of Facilities",
+                    dataIndex: "number_fac",
+                    format: "1,000",
+                    align: "right",
+                    width: 55
+                }
+            ]
+        })
+    });
+
+We have discussed the :ref:`store <geoext.wfs.grid.store>` already, so let's
+have a look at the definition of the ColumnModel: the columns are connected to
+fields of FeatureRecords using the ``dataIndex`` property. The numeric
+column ("# of Facilities") needs some extra attention: we want to ``align`` it
+to the right, and we can provide a number ``format`` property. This works
+exactly as the number formats in your favorite spreadsheet application.
+
+Next Steps
+----------
+
+Features in a grid are somewhat boring. We want to add a geospatial component
+to our application and give it a map. The :ref:`next section
+<geoext.wfs.layer>` explains how to do that.

Added: sandbox/foss4g2010/src/doc/wfs/index.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/index.rst	                        (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/index.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,37 @@
+.. module:: geoext.wfs
+    :synopsis: Learn how to use WFS with GeoExt.
+
+.. _geoext.wfs:
+
+WFS Made Easy with GeoExt
+=========================
+
+GeoExt provides access to remote WFS data vie Stores and Readers, using the
+same mechanisms that Ext JS provides for any remote data access. Because the
+`GeoExt.data.FeatureStore
+<http://geoext.org/lib/GeoExt/data/FeatureStore.html>`_ can synchronize its
+records with an OpenLayers vector layer, working with vector features from
+WFS is extremely effortless.
+
+Users familiar with desktop based GIS
+applications expect to have a combined map and table (grid) view of geospatial
+data. GeoExt brings this feature to the web. At the end of this module, you
+will have built a simple WFS feature editor. The grid view comes for free
+because Ext JS can display data from any store in a grid, and the synchronized
+selection between map and table is also handled by GeoExt. Rendering
+the data on the map, editing and committing changes over WFS-T is provided by
+OpenLayers.
+
+GeoExt's FeatureReader is not limited to WFS protocol and GML -- other
+protocols (e.g. plain HTTP) with formats like KML, GeoRSS or GeoJSON work as
+well.
+
+In this module, you will:
+
+.. toctree::
+    :maxdepth: 1
+    
+    Create a grid view of WFS features, <grid>
+    Add a map view of the same features with synchronized highlighting, <layer>
+    Make features editable, <editing>
+    Save modifications over WFS-T. <wfst>

Added: sandbox/foss4g2010/src/doc/wfs/layer.png
===================================================================
(Binary files differ)


Property changes on: sandbox/foss4g2010/src/doc/wfs/layer.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/foss4g2010/src/doc/wfs/layer.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/layer.rst	                        (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/layer.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,133 @@
+.. _geoext.wfs.layer:
+
+A Synchronized Map and Table View of Vector Features
+====================================================
+
+In Ext JS, grids can not only have a store and a column model, but also a
+selection model. The FeatureStore provides everything to synchronize itself
+with the features of an OpenLayers vector layer, and the
+`GeoExt.grid.FeatureSelectionModel
+<http://geoext.org/lib/GeoExt/widgets/grid/FeatureSelectionModel.html>`_ can
+be used to synchronize highlighting (feature selection) between layer and
+grid.
+
+Let the Layer Fetch the Features, not the Store
+-----------------------------------------------
+
+We will now configure a vector layer with the WFS protocol and get rid of the
+ProtocolProxy.
+
+.. rubric:: Tasks
+
+#.  Open :file:`wfs-editor.html` again in your text editor. Find the store
+    definition, and add the following code above it to create a layer:
+    
+    .. code-block:: javascript
+
+        var layer = new OpenLayers.Layer.Vector("vector", {
+            strategies: [new OpenLayers.Strategy.Fixed()],
+            protocol: new OpenLayers.Protocol.WFS({
+                url: "/geoserver/wms",
+                version: "1.1.0",
+                featureType: "poly_landmarks",
+                featureNS: "http://www.census.gov",
+                srsName: "EPSG:4326"
+            })
+        });
+
+#.  Now remove the ``proxy`` and ``autoLoad`` properties from the store
+    definition, and add a ``layer`` property pointing to the layer that we
+    created above.
+    
+    .. code-block:: javascript
+    
+        var store = new GeoExt.data.FeatureStore({
+            fields: [
+                {name: "LANAME", type: "string"},
+                {name: "CFCC", type: "string"},
+                {name: "LAND", type: "float"}
+            ],
+            layer: layer
+        });
+     
+The ``protocol`` property we added to the layer definition is exactly the same
+that we had in the ProtocolProxy configuration in the :ref:`previous version
+<geoext.wfs.grid.grid>`.
+
+Adding a MapPanel to Display The Layer
+--------------------------------------
+
+Configured like above, our application does the same as before. The only
+difference is that OpenLayers takes care of loading features now. This means
+that unless we add the layer to a map, features won't be loaded, and we won't
+see anything in the grid. So let's add a map to our application.
+
+.. rubric:: Tasks
+
+#.  Create a map panel. To do so, add the following code above the gridPanel
+    definition:
+    
+    .. code-block:: javascript
+
+        var mapPanel = new GeoExt.MapPanel({
+            title: "Map",
+            region: "west",
+            width: 400,
+            layers: [layer],
+            extent: new OpenLayers.Bounds(-74.047, 40.68, -73.908, 40.882)
+        });
+
+#.  Add the mapPanel to the application's main panel, by modifying the main
+    panel definition to look like this:
+    
+    .. code-block:: javascript
+
+        var mainPanel = new Ext.Panel({
+            renderTo: document.body,
+            layout: "border",
+            height: 450,
+            width: 800,
+            items: [gridPanel, mapPanel]
+        });
+
+Now the application has a map window with a vector layer sharing its content
+with the grid.
+
+Synchronizing Feature Selection between Map and Grid
+----------------------------------------------------
+
+We are almost there. We just have to add some code to enable feature
+selection on the layer and synchronize it with the grid. Surprisingly, this
+requires just one line of code.
+
+.. rubric:: Tasks
+
+#.  Configure the grid with a FeatureSelectionModel to get feature selection
+    (highlighting) synchronized between map and grid. Your gridPanel
+    definition should now start like this:
+    
+    .. code-block:: javascript
+
+        var gridPanel = new Ext.grid.GridPanel({
+            title: "Feature Table - Manhattan (NY) landmarks",
+            region: "center",
+            viewConfig: {forceFit: true},
+            store: store,
+            sm: new GeoExt.grid.FeatureSelectionModel(),
+            cm: new Ext.grid.ColumnModel({
+
+#.  Save your changes. Open or reload @workshop_url@/wfs-editor.html in your
+    browser. Select some features in the map and/or in the feature table and
+    see how they synchronize.
+
+.. figure:: layer.png
+
+    Map and table view of vector features with synchronized highlighting.
+
+What's Next?
+------------
+
+Having a map viewer like this is really close to a Desktop GIS. But for the
+ultimate user experience, we have to add editing capabilities. This is
+explained in the :ref:`next section <geoext.wfs.editing>`.
+    

Added: sandbox/foss4g2010/src/doc/wfs/wfst.png
===================================================================
(Binary files differ)


Property changes on: sandbox/foss4g2010/src/doc/wfs/wfst.png
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: sandbox/foss4g2010/src/doc/wfs/wfst.rst
===================================================================
--- sandbox/foss4g2010/src/doc/wfs/wfst.rst	                        (rev 0)
+++ sandbox/foss4g2010/src/doc/wfs/wfst.rst	2010-07-30 12:32:45 UTC (rev 2247)
@@ -0,0 +1,216 @@
+.. _geoext.wfs.wfst:
+
+Committing Feature Modifications Over WFS-T
+===========================================
+
+Until GeoExt also provides writers, we have to rely on OpenLayers for writing
+modifications back to the WFS. This is not a big problem though, because WFS-T
+support in OpenLayers is solid. But it requires us to take some extra care of
+feature states.
+
+Managing Feature States
+-----------------------
+
+For keeping track of "create", "update" and "delete" operations, OpenLayers
+vector features have a ``state`` property. The WFS protocol relies on this
+property to determine which features to commit using an "Insert", "Update" or
+"Delete" transaction. So we need to make sure that the ``state`` property gets
+set properly:
+
+* ``OpenLayers.State.INSERT`` for features that were just created. We do not
+  need to do anything here, because the DrawFeature control handles this for
+  us.
+* ``OpenLayers.State.UPDATE`` for features with modified attributes, except
+  for features that have ``OpenLayers.State.INSERT`` set already. For modified
+  geometries, the ModifyFeature control handles this.
+* ``OpenLayers.State.DELETE`` for features that the user wants to delete,
+  except for features that have ``OpenLayers.State.INSERT`` set, which can be
+  removed.
+
+.. rubric:: Tasks
+
+#.  Open :file:`wfs-editor.html`` in your text editor. Add an "afteredit"
+    listener to the gridPanel definition, setting the state to
+    ``OpenLayers.State.UPDATE``, unless it is ``OpenLayers.State.INSERT``.
+    The first few lines of yourgridPanel definition should now look like this:
+    
+    .. code-block:: javascript
+
+        var gridPanel = new Ext.grid.EditorGridPanel({
+            title: "Feature Table - Manhattan (NY) landmarks",
+            region: "center",
+            viewConfig: {forceFit: true},
+            store: store,
+            listeners: {
+                afteredit: function(e) {
+                    var feature = e.record.get("feature");
+                    if(feature.state !== OpenLayers.State.INSERT) {
+                        feature.state = OpenLayers.State.UPDATE;
+                    }
+                }
+            },
+            sm: new GeoExt.grid.FeatureSelectionModel({
+                selectControl: modifyControl.selectControl,
+                singleSelect: true
+            }),
+
+#.  Modify the handler for the "Delete" button so it re-adds deleted features
+    with a state other than ``OpenLayers.State.INSERT``, after setting
+    their state to ``OpenLayers.State.DELETE`` (which also makes them
+    invisible on the layer:
+    
+    .. code-block:: javascript
+
+        {
+            text: "Delete",
+            handler: function() {
+                gridPanel.getSelectionModel().each(function(rec) {
+                    var feature = rec.get("feature");
+                    modifyControl.unselectFeature(feature);
+                    store.remove(rec);
+                    if(feature.state !== OpenLayers.State.INSERT) {
+                        feature.state = OpenLayers.State.DELETE;
+                        layer.addFeatures([feature]);
+                    }
+                });
+            }
+        }
+    
+    To avoid that features marked ``OpenLayers.State.DELETE`` show up in the
+    grid, we have to configure a filter for the store, using its
+    ``addFeatureFilter`` config property. Make the store definition look like
+    this:
+    
+    .. code-block:: javascript
+
+        var store = new GeoExt.data.FeatureStore({
+            fields: [
+                {name: "name", type: "string"},
+                {name: "owner", type: "string"},
+                {name: "usage", type: "string"},
+                {name: "number_fac", type: "int", defaultValue: 0}
+            ],
+            layer: layer,
+            addFeatureFilter: function(feature) {
+                return feature.state !== OpenLayers.State.DELETE;
+            }
+        });
+
+Adding a Save Strategy and a Save Button
+----------------------------------------
+
+Saving feature modifications the OpenLayers way requires the vector layer to
+be configured with an `OpenLayers.Strategy.Save
+<http://dev.openlayers.org/releases/OpenLayers-2.9/doc/apidocs/files/OpenLayers/Strategy/Save-js.html>`_.
+We will now add such a strategy, along with a "Save" button.
+
+.. rubric:: Tasks
+
+#.  Find the layer definition in your :file:`wfs-browser.html` file.
+    Instantiate a Save strategy above, and make the layer uses it by adding it
+    to the layer's ``strategies`` array. The whole code block should now look
+    like this:
+    
+    .. code-block:: javascript
+
+        var saveStrategy = new OpenLayers.Strategy.Save();
+        var layer = new OpenLayers.Layer.Vector("vector", {
+            strategies: [new OpenLayers.Strategy.Fixed(), saveStrategy],
+            protocol: new OpenLayers.Protocol.WFS({
+                url: "/geoserver/ows",
+                version: "1.1.0",
+                featureType: "parks",
+                featureNS: "http://medford.opengeo.org",
+                srsName: "EPSG:4326"
+            })
+        });
+    
+    .. warning:: If you are modifying this example to work with a layer that
+        is stored in a shapefile or a MySQL database, modify your saveStrategy
+        to look like this:
+        
+        .. code-block:: javascript
+            
+            var saveStrategy = new OpenLayers.Strategy.Save({
+                onCommit: function() {
+                    saveStrategy.layer.refresh();
+                }
+            });
+        
+        This is required because the mentioned data backends do not report
+        back the ids of inserted features. What it does is that it refreshes
+        the whole layer rather than just assigning the appropriate feature
+        ids to the features that are already on the layer.
+
+#.  Add a button on the right side of the map panel's bottom toolbar, with a
+    handler that calls the ``save`` method of the saveStrategy. The mapPanel's
+    bbar definition has to look like this now:
+    
+    .. code-block:: javascript
+
+        bbar: [
+            new GeoExt.Action({
+                control: drawControl,
+                text: "Create",
+                enableToggle: true
+            }), {
+                text: "Delete",
+                handler: function() {
+                    gridPanel.getSelectionModel().each(function(rec) {
+                        var feature = rec.get("feature");
+                        modifyControl.unselectFeature(feature);
+                        gridPanel.store.remove(rec);
+                        if(feature.state !== OpenLayers.State.INSERT) {
+                            feature.state = OpenLayers.State.DELETE;
+                            layer.addFeatures([feature]);
+                        }
+                    })
+                }
+            }, "->", {
+                text: "Save",
+                handler: function() {
+                    store.commitChanges();
+                    saveStrategy.save();
+                }
+            }
+        ]
+ 
+#.  Save your file and reload @workshop_url@/wfs-editor.html. Make some
+    changes and hit "Save". Reload the page to see that your changes were
+    persisted.
+
+.. figure:: wfst.png
+
+    Application with "Save" button and a persisted feature after reloading.
+
+One More Look at the "Save" Button
+``````````````````````````````````
+For the "Save" button, we have added a line of code reading
+``store.commitChanges()``.
+
+.. code-block:: javascript
+
+    {
+        text: "Save",
+        handler: function() {
+            store.commitChanges();
+            saveStrategy.save();
+        }
+    }
+
+In Ext JS, the ``commitChanges`` method of a store is used to save changes.
+We use OpenLayers to perform the WFS transaction, so we would not necessarily
+have to call ``commitChanges``. But doing so will make sure that the records are no
+longer marked "dirty", which resets the store into the same clean state that the
+layer will be in when the commit operation is finished. The pleasant side effect
+of calling ``commitChanges`` is that the tiny read triangles in the top left
+corner of edited grid cells disappear.
+
+Conclusion
+----------
+
+You have successfully created a WFS based feature editor. GeoExt makes working
+with features easy, thanks to its FeatureStore. Although there is no write
+support yet for the FeatureStore in GeoExt, saving changes via WFS-T is easy
+because of the solid WFS-T support in OpenLayers and the interoperability of
+GeoExt and OpenLayers.



More information about the Commits mailing list