Changeset 240


Ignore:
Timestamp:
03/22/09 14:39:39 (9 years ago)
Author:
elemoine
Message:

r239 was supposed to include changes from "merge -r189:HEAD" only, it includes more than that, reverting

Location:
sandbox/elemoine/playground
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • sandbox/elemoine/playground/examples/mappanel-div.html

    r239 r240  
    1 <html>
    2   <head>
    3     <script type="text/javascript" src="../../../openlayers/lib/OpenLayers.js"></script>
    4     <script type="text/javascript" src="../../../ext/2.2.1/adapter/ext/ext-base.js"></script>
    5     <script type="text/javascript" src="../../../ext/2.2.1/ext-all-debug.js"></script>
    6     <script type="text/javascript" src="../lib/GeoExt.js"></script>
    7 
    8     <link rel="stylesheet" type="text/css" href="../../../ext/2.2.1/resources/css/ext-all.css"></link>
    9 
    10     <script type="text/javascript">
    11 
    12     // this example shows the OpenLayerish way to create a map panel. See
    13     // mappanel-window.html for the ExtJSish way to do the same.
    14 
    15     var mapPanel;
    16    
    17     Ext.onReady(function() {
    18         var map = new OpenLayers.Map();
    19         var layer = new OpenLayers.Layer.WMS(
    20             "bluemarble",
    21             "http://sigma.openplans.org/geoserver/wms?",
    22             {layers: 'bluemarble'}
    23         );
    24         map.addLayer(layer);
    25 
    26         mapPanel = new GeoExt.MapPanel({
    27             title: "GeoExt MapPanel",
    28             renderTo: "mappanel",
    29             height: 400,
    30             width: 600,
    31             map: map,
    32             center: new OpenLayers.LonLat(5, 45),
    33             zoom: 4
    34         });
    35     });
    36 
    37     // functions for resizing the map panel
    38     function mapSizeUp() {
    39         var size = mapPanel.getSize();
    40         size.width += 40;
    41         size.height += 40;
    42         mapPanel.setSize(size);
    43     }
    44     function mapSizeDown() {
    45         var size = mapPanel.getSize();
    46         size.width -= 40;
    47         size.height -= 40;
    48         mapPanel.setSize(size);
    49     }
    50 
    51     </script>
    52        
    53   </head>
    54   <body>
    55     <div id="mappanel"></div>
    56     <input type="button" onclick="mapSizeUp()" value="bigger"></input>
    57     <input type="button" onclick="mapSizeDown()" value="smaller"></input>
    58   </body>
    59 </html>
  • sandbox/elemoine/playground/examples/mappanel-window.html

    r239 r240  
    1 <html>
    2   <head>
    3     <link rel="stylesheet" type="text/css" href="../../../ext/2.2.1/resources/css/ext-all.css"></link>
    4     <script type="text/javascript" src="../../../openlayers/lib/OpenLayers.js"></script>
    5     <script type="text/javascript" src="../../../ext/2.2.1/adapter/ext/ext-base.js"></script>
    6     <script type="text/javascript" src="../../../ext/2.2.1/ext-all-debug.js"></script>
    7     <script type="text/javascript" src="../lib/GeoExt.js"></script>
    8 
    9     <script type="text/javascript">
    10 
    11     // this example shows the Extish way to create a map panel. See
    12     // mappanel-div.html for the OpenLayerish way to do the same.
    13    
    14     var mapPanel;
    15    
    16     Ext.onReady(function() {
    17         new Ext.Window({
    18             title: "GeoExt MapPanel Window",
    19             height: 400,
    20             width: 600,
    21             layout: "fit",
    22             items: [{
    23                 xtype: "gx_mappanel",
    24                 id: "mappanel",
    25                 layers: [new OpenLayers.Layer.WMS(
    26                     "bluemarble",
    27                     "http://sigma.openplans.org/geoserver/wms?",
    28                     {layers: 'bluemarble'}
    29                 )],
    30                 extent: "-5,35,15,55"
    31             }]
    32         }).show();
    33        
    34         mapPanel = Ext.getCmp("mappanel");
    35     });
    36 
    37     </script>
    38   </head>
    39   <body>
    40   </body>
    41 </html>
  • sandbox/elemoine/playground/lib/GeoExt.js

    r239 r240  
    1 /* Copyright (C) 2008-2009 The Open Source Geospatial Foundation ¹
    2  * Published under the BSD license.
    3  * See http://geoext.org/svn/geoext/core/trunk/license.txt for the full text
    4  * of the license.
    5  *
    6  * ¹ pending approval */
     1/*
     2 * Copyright (C) 2008 Eric Lemoine, Camptocamp France SAS
     3 *
     4 * This file is part of GeoExt
     5 *
     6 * GeoExt is free software: you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation, either version 3 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * GeoExt is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with GeoExt.  If not, see <http://www.gnu.org/licenses/>.
     18 */
    719
    820/*
     
    1325 * full text of the license.
    1426 */
    15  
     27
     28/*
     29 */
     30
    1631(function() {
    1732
     
    6176            "GeoExt/data/FeatureReader.js",
    6277            "GeoExt/data/FeatureStore.js",
    63             "GeoExt/data/LayerStore.js",
    64             "GeoExt/data/LayerRecord.js",
    6578            "GeoExt/data/FeatureStoreMediator.js",
    6679            "GeoExt/data/RecordLayerMediator.js",
    6780            "GeoExt/data/LayerStoreMediator.js",
    68             "GeoExt/data/ProtocolProxy.js",
    69             "GeoExt/widgets/MapPanel.js"
     81            "GeoExt/data/ProtocolProxy.js"
    7082        );
    7183
  • sandbox/elemoine/playground/lib/GeoExt/data/LayerReader.js

    r239 r240  
    1 /* Copyright (C) 2008-2009 The Open Source Geospatial Foundation
    2  * Published under the BSD license.
    3  * See http://geoext.org/svn/geoext/core/trunk/license.txt for the full text
    4  * of the license.
    5  *
    6  * ¹ pending approval */
    7 
    8 Ext.namespace("GeoExt", "GeoExt.data");
    9 
    10 /**
    11  * Class: GeoExt.data.LayerReader
    12  *      LayerReader is a specific Ext.data.DataReader for converting
    13  *      layers into layer records, i.e. {OpenLayers.Layer} objects
    14  *      into {GeoExt.data.LayerRecor} objects.
    15  *
    16  * Usage example:
    17  * (start code)
    18  *         var reader = new GeoExt.data.LayerReader();
    19  *         var layerData = reader.readRecords(map.layers);
    20  *         var numRecords = layerData.totalRecords;
    21  *         var layerRecords = layerData.records;
    22  * (end)
    23  *
    24  * Inherits from:
    25  *  - {Ext.data.DataReader}
    26  */
    27 
    28 /**
    29  * Constructor: GeoExt.data.LayerReader
    30  *      Create a layer reader. The arguments passed are similar to those
    31  *      passed to {Ext.data.DataReader} constructor.
    32  */
    33 GeoExt.data.LayerReader = function(meta, recordType) {
    34     meta = meta || {};
    35     if(!(recordType instanceof GeoExt.data.LayerRecord)) {
    36         recordType = GeoExt.data.LayerRecord.create(
    37             recordType || meta.fields || {});
    38     }
    39     GeoExt.data.LayerReader.superclass.constructor.call(
    40         this, meta, recordType);
    41 };
    42 
    43 Ext.extend(GeoExt.data.LayerReader, Ext.data.DataReader, {
    44 
    45     /**
    46      * APIProperty: totalRecords
    47      * {Integer}
    48      */
    49     totalRecords: null,
    50 
    51     /**
    52      * APIMethod: readRecords
    53      *      From an array of {OpenLayers.Layer} objects create a data block
    54      *      containing {<GeoExt.data.LayerRecord>} objects.
    55      *
    56      * Parameters:
    57      * layers - {Array({OpenLayers.Layer})}
    58      *
    59      * Returns:
    60      * {Object} An object with two properties. The value of the property "records"
    61      *      is the array of layer records. The value of the property "totalRecords"
    62      *      is the number of records in the array.
    63      */
    64     readRecords : function(layers) {
    65         var records = [];
    66 
    67         if (layers) {
    68             var recordType = this.recordType, fields = recordType.prototype.fields;
    69             var i, lenI, j, lenJ, layer, values, field, v;
    70             for (i = 0, lenI = layers.length; i < lenI; i++) {
    71                 layer = layers[i];
    72                 values = {};
    73                 for (j = 0, lenJ = fields.length; j < lenJ; j++){
    74                     field = fields.items[j];
    75                     v = layer[field.mapping || field.name] ||
    76                         field.defaultValue;
    77                     v = field.convert(v);
    78                     values[field.name] = v;
    79                 }
    80                 values.layer = layer;
    81                 records[records.length] = new recordType(values, layer.id);
    82             }
    83         }
    84 
    85         return {
    86             records: records,
    87             totalRecords: this.totalRecords != null ? this.totalRecords : records.length
    88         };
    89     }
    90 });
  • sandbox/elemoine/playground/lib/GeoExt/data/LayerRecord.js

    r239 r240  
    1 /* Copyright (C) 2008-2009 The Open Source Geospatial Foundation
    2  * Published under the BSD license.
    3  * See http://geoext.org/svn/geoext/core/trunk/license.txt for the full text
    4  * of the license.
    5  *
    6  * pending approval */
    7 
    8 Ext.namespace("GeoExt.data");
    9 
    10 /**
    11  * Class: GeoExt.data.LayerRecord
    12  * A subclass of {Ext.data.Record} which provides a special record that
    13  * represents an {OpenLayers.Layer}. This record will always have at least a
    14  * layer and a title field in its data. The id of this record will be the same
    15  * as the id of the layer it represents.
    16  *
    17  * Inherits from
    18  * - {Ext.data.Record}
    19  */
    20 GeoExt.data.LayerRecord = Ext.data.Record.create([
    21     {name: "layer"},
    22     {name: "title", type: "string", mapping: "name"}
    23 ]);
    24 
    25 /**
    26  * APIFunction: GeoExt.data.LayerRecord.create
    27  * Creates a constructor for a LayerRecord, optionally with additional
    28  * fields.
    29  *
    30  * Parameters:
    31  * o - {Array} Field definition as in {Ext.data.Record.create}. Can be omitted
    32  *     if no additional fields are required (records will always have a
    33  *     {OpenLayers.Layer} layer and a {String} title field).
    34  *
    35  * Returns:
    36  * {Function} A specialized {<GeoExt.data.LayerRecord>} constructor.
    37  */
    38 GeoExt.data.LayerRecord.create = function(o) {
    39     var f = Ext.extend(GeoExt.data.LayerRecord, {});
    40     var p = f.prototype;
    41     if(o) {
    42         for(var i = 0, len = o.length; i < len; i++){
    43             p.fields.add(new Ext.data.Field(o[i]));
    44         }
    45     }
    46     return f;
    47 }
  • sandbox/elemoine/playground/lib/GeoExt/data/LayerStore.js

    r239 r240  
    1 /* Copyright (C) 2008-2009 The Open Source Geospatial Foundation ¹
    2  * Published under the BSD license.
    3  * See http://geoext.org/svn/geoext/core/trunk/license.txt for the full text
    4  * of the license.
    5  *
    6  * ¹ pending approval */
    7 
    8 Ext.namespace("GeoExt.data");
    9 
    10 /**
    11  * Class: LayerStoreMixin
    12  * A store that synchronizes a layers array of an {OpenLayers.Map} with a
    13  * layer store holding {<GeoExt.data.LayerRecord>} entries.
    14  *
    15  * This class can not be instantiated directly. Instead, it is meant to extend
    16  * {Ext.data.Store} or a subclass of it:
    17  * (start code)
    18  * var store = new (Ext.extend(Ext.data.Store, GeoExt.data.LayerStoreMixin))({
    19  *     map: myMap,
    20  *     layers: myLayers
    21  * });
    22  * (end)
    23  *
    24  * For convenience, a {GeoExt.data.LayerStore} class is available as a
    25  * shortcut to the Ext.extend sequence in the above code snippet. The above
    26  * is equivalent to:
    27  * (start code)
    28  * var store = new GeoExt.data.LayerStore({
    29  *     map: myMap,
    30  *     layers: myLayers
    31  * })
    32  * (end)
    33  */
    34 GeoExt.data.LayerStoreMixin = {
    35     /**
    36      * APIProperty: map
    37      * {OpenLayers.Map} Map that this store will be in sync with.
    38      */
    39     map: null,
    40 
    41     /**
    42      * Property: reader
    43      * {<GeoExt.data.LayerReader>} The reader used to get
    44      *     <GeoExt.data.LayerRecord> objects from {OpenLayers.Layer}
    45      *     objects.
    46      */
    47     reader: null,
    48 
    49     /**
    50      * Constructor: GeoExt.LayerStore
    51      *
    52      * Parameters:
    53      * config - {Object}
    54      *
    55      * Valid config options:
    56      * map - {OpenLayers.Map|<GeoExt.MapPanel>} map to sync the layer store
    57      *     with.
    58      * layers - {Array(OpenLayers.Layer)} Layers that will be added to the
    59      *     layer store (and the map, because we are already syncing).
    60      * recordType - {<GeoExt.data.LayerRecord>} If provided, a custom layer
    61      *     record type with additional fields will be used. Default fields for
    62      *     every layer record are {OpenLayers.Layer} layer and {String} title.
    63      */
    64     constructor: function(config) {
    65         arguments.callee.superclass.constructor.apply(this, arguments);
    66         config = config || {};
    67         this.reader = new GeoExt.data.LayerReader({}, config.recordType);
    68         var map = config.map instanceof GeoExt.MapPanel ?
    69             config.map.map : config.map;
    70         if(map) {
    71             // create a snapshop of the map's layers
    72             var layers = map.layers;
    73             var layer;
    74             // walk through the layers snapshot and add layers to the store
    75             for(var i=0; i<layers.length; ++i) {
    76                 layer = layers[i];
    77                 this.add((this.reader.readRecords([layer])).records);
    78             }
    79 
    80             this.setMap(map);
    81             config.layers && map.addLayers(config.layers);
    82         }
    83     },
    84    
    85     /**
    86      * APIMethod: setMap
    87      *
    88      * Parameters:
    89      * map - {OpenLayers.Map}
    90      */
    91     setMap: function(map) {
    92         this.map = map;
    93         map.events.on({
    94             "addlayer": this.onAddLayer,
    95             "removelayer": this.onRemoveLayer,
    96             scope: this
    97         });
    98         this.on({
    99             "add": this.onAdd,
    100             "remove": this.onRemove,
    101             scope: this
    102         });
    103     },
    104    
    105     /**
    106      * Method: onAddLayer
    107      * Handler for a map's addlayer event
    108      *
    109      * Parameters:
    110      * evt - {Object}
    111      */
    112     onAddLayer: function(evt) {
    113         var layer = evt.layer;
    114         this._adding = true;
    115         this.add((this.reader.readRecords([layer])).records);
    116         delete this._adding;
    117     },
    118    
    119     /**
    120      * Method: onRemoveLayer
    121      * Handler for a map's removelayer event
    122      *
    123      * Parameters:
    124      * evt - {Object}
    125      */
    126     onRemoveLayer: function(evt){
    127         var layer = evt.layer;
    128         this._removing = true;
    129         this.remove(this.getById(layer.id));
    130         delete this._removing;
    131     },
    132    
    133     /**
    134      * Method: onAdd
    135      * Handler for a store's add event
    136      *
    137      * Parameters:
    138      * store - {<Ext.data.Store>}
    139      * records - {Array(Ext.data.Record)}
    140      * index - {Number}
    141      */
    142     onAdd: function(store, records, index) {
    143         if(!this._adding) {
    144             for(var i=0; i<records.length; ++i) {
    145                 this.map.addLayer(records[i].get("layer"));
    146             }
    147         }
    148     },
    149    
    150     /**
    151      * Method: onRemove
    152      * Handler for a store's remove event
    153      *
    154      * Parameters:
    155      * store - {<Ext.data.Store>}
    156      * records - {Array(Ext.data.Record)}
    157      * index - {Number}
    158      */
    159     onRemove: function(store, record, index){
    160         if(!this._removing) {
    161             this.map.removeLayer(record.get("layer"));
    162         }
    163     }
    164 };
    165 
    166 /**
    167  * Class: GeoExt.data.LayerStore
    168  * Default implementation of an {Ext.data.Store} enhanced with
    169  * {<GeoExt.data.LayerStoreMixin>}
    170  */
    171 GeoExt.data.LayerStore = Ext.extend(
    172     Ext.data.Store,
    173     GeoExt.data.LayerStoreMixin
    174 );
  • sandbox/elemoine/playground/license.txt

    r239 r240  
    1 Copyright (c) 2008-2009, The Open Source Geospatial Foundation ¹
    2 All rights reserved.
    3 
    4 Redistribution and use in source and binary forms, with or without
    5 modification, are permitted provided that the following conditions are met:
    6 
    7     * Redistributions of source code must retain the above copyright notice,
    8       this list of conditions and the following disclaimer.
    9     * Redistributions in binary form must reproduce the above copyright
    10       notice, this list of conditions and the following disclaimer in the
    11       documentation and/or other materials provided with the distribution.
    12     * Neither the name of the Open Source Geospatial Foundation nor the names
    13       of its contributors may be used to endorse or promote products derived
    14       from this software without specific prior written permission.
    15 
    16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
    20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    26 POSSIBILITY OF SUCH DAMAGE.
    27 
    28 Â¹ pending approval
  • sandbox/elemoine/playground/tests/data/LayerRecord.html

    r239 r240  
    1 <!DOCTYPE html>
    2 <html debug="true">
    3   <head>
    4     <script type="text/javascript" src="../../../../openlayers/lib/OpenLayers.js"></script>
    5     <script type="text/javascript" src="../../../../ext/2.2.1/adapter/ext/ext-base.js"></script>
    6     <script type="text/javascript" src="../../../../ext/2.2.1/ext-all-debug.js"></script>
    7     <script type="text/javascript" src="../../lib/GeoExt.js"></script>
    8 
    9     <script type="text/javascript">
    10        
    11         function test_layerrecord(t) {
    12             t.plan(12);
    13 
    14             var c, layer, record;
    15            
    16             c = GeoExt.data.LayerRecord.create();
    17             t.ok(c instanceof Function, "create returns a func");
    18             t.eq(c.prototype.fields.items[0].name, "layer",
    19                  "\"create\" returns a func with a \"layer\" field in its prototype");
    20             t.eq(c.prototype.fields.items[1].name, "title",
    21                  "\"create\" returns a func with a \"title\" field in its prototype");
    22 
    23             c = GeoExt.data.LayerRecord.create([
    24                 {name: "extra1"}, {name: "extra2"}
    25             ]);
    26             t.eq(c.prototype.fields.items[0].name, "layer",
    27                  "\"create(o)\" returns a func with a \"layer\" field in its prototype");
    28             t.eq(c.prototype.fields.items[1].name, "title",
    29                  "\"create(o)\" returns a func with a \"title\" field in its prototype");
    30             t.eq(c.prototype.fields.items[2].name, "extra1",
    31                  "\"create(o)\" returns a func with a \"extra1\" field in its prototype");
    32             t.eq(c.prototype.fields.items[3].name, "extra2",
    33                  "\"create(o)\" returns a func with a \"extra2\" field in its prototype");
    34 
    35             layer = new OpenLayers.Layer();
    36             record = new c({layer: layer, title: layer.name}, layer.id);
    37             t.ok(record instanceof GeoExt.data.LayerRecord, "create returns a constructor (LayerRecord)");
    38             t.ok(record instanceof c, "create returns a constructor (c)");
    39             t.eq(record.get("layer").id, layer.id, "layer stored correctly");
    40             t.eq(record.id, layer.id, "id set correctly");
    41             record = new c({layer: layer, title: layer.name, foo: "bar"}, layer.id);
    42             t.eq(record.get("foo"), "bar", "foo data row set correctly");
    43         }
    44     </script>
    45   <body>
    46     <div id="mappanel"></div>
    47   </body>
    48 </html>
  • sandbox/elemoine/playground/tests/data/LayerStore.html

    r239 r240  
    1 <!DOCTYPE html>
    2 <html debug="true">
    3   <head>
    4     <script type="text/javascript" src="../../../../openlayers/lib/OpenLayers.js"></script>
    5     <script type="text/javascript" src="../../../../ext/2.2.1/adapter/ext/ext-base.js"></script>
    6     <script type="text/javascript" src="../../../../ext/2.2.1/ext-all-debug.js"></script>
    7     <script type="text/javascript" src="../../lib/GeoExt.js"></script>
    8 
    9     <script type="text/javascript">
    10        
    11         function createMap() {
    12             var map = new OpenLayers.Map();
    13             return map;
    14         }
    15 
    16         function loadMapPanel() {
    17             var map = createMap();
    18 
    19             var mapPanel = new GeoExt.MapPanel({
    20                 // panel options
    21                 id: "map-panel",
    22                 title: "GeoExt MapPanel",
    23                 renderTo: "mappanel",
    24                 height: 400,
    25                 width: 600,
    26                 // map panel-specific options
    27                 map: map,
    28                 center: new OpenLayers.LonLat(5, 45),
    29                 zoom: 4
    30             });
    31 
    32             return mapPanel;
    33         }
    34 
    35         function test_layerstore(t) {
    36             t.plan(6);
    37 
    38             var mapPanel = loadMapPanel();
    39             var map = mapPanel.map;
    40 
    41             var layer = new OpenLayers.Layer.Vector("Foo Layer");
    42 
    43             map.addLayer(layer);
    44             t.eq(map.layers.length, 1, "Adding layer to map does not create duplicate layers on map");
    45             t.eq(mapPanel.layers.getCount(), 1, "Adding layer to map does not create duplicate records in LayerStore");
    46 
    47             mapPanel.layers.remove(mapPanel.layers.getById(layer.id));
    48             t.eq(map.layers.length,0,"removeLayer on MapPanel's LayerStore removes layer from map");
    49             t.eq(mapPanel.layers.getCount(),0,"removeLayer on MapPanel's LayerStore removes layer from map");
    50 
    51             var reader = new GeoExt.data.LayerReader();
    52             mapPanel.layers.add((reader.readRecords([layer])).records);
    53             t.eq(map.layers.length,1,"Adding layer to MapPanel's LayerStore adds only one layer to map");
    54             t.eq(mapPanel.layers.getCount(),1,"Adding layers to MapPanel's LayerStore does not create duplicate layers");
    55         }
    56     </script>
    57   <body>
    58     <div id="mappanel"></div>
    59   </body>
    60 </html>
  • sandbox/elemoine/playground/tests/list-tests.html

    r239 r240  
    33  <li>data/FeatureStore.html</li>
    44  <li>data/FeatureStoreMediator.html</li>
    5   <li>data/LayerRecord.html</li>
    6   <li>data/LayerStore.html</li>
    75  <li>data/LayerStoreMediator.html</li>
    86  <li>data/ProtocolProxy.html</li>
    9   <li>widgets/MapPanel.html</li>
    107</ul>
Note: See TracChangeset for help on using the changeset viewer.