← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 3976: (GIS) Point context menu + Relocation of points implemented.

 

Merge authors:
  Jan Henrik Øverland (janhenrik-overland)
------------------------------------------------------------
revno: 3976 [merge]
committer: Jan Henrik Overland <janhenrik.overland@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2011-06-22 09:38:13 +0300
message:
  (GIS) Point context menu + Relocation of points implemented.
added:
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/cancel2.png
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/relocate.png
  dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/UpdateOrganisationUnitCoordinatesAction.java
modified:
  dhis-2/dhis-web/dhis-web-mapping/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-mapping/src/main/resources/struts.xml
  dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/css/style.css
  dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/global.js
  dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/index.js
  dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Choropleth.js
  dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Point.js
  dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Symbol.js


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/cancel2.png'
Binary files dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/cancel2.png	1970-01-01 00:00:00 +0000 and dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/cancel2.png	2011-06-22 05:50:46 +0000 differ
=== added file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/relocate.png'
Binary files dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/relocate.png	1970-01-01 00:00:00 +0000 and dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/images/relocate.png	2011-06-22 05:50:46 +0000 differ
=== added file 'dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/UpdateOrganisationUnitCoordinatesAction.java'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/UpdateOrganisationUnitCoordinatesAction.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/UpdateOrganisationUnitCoordinatesAction.java	2011-06-22 05:50:46 +0000
@@ -0,0 +1,85 @@
+package org.hisp.dhis.mapping.action;
+
+/*
+ * Copyright (c) 2004-2010, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import org.hisp.dhis.organisationunit.OrganisationUnit;
+import org.hisp.dhis.organisationunit.OrganisationUnitService;
+
+import com.opensymphony.xwork2.Action;
+
+/**
+ * @author Jan Henrik Overland
+ * @version $Id$
+ */
+public class UpdateOrganisationUnitCoordinatesAction
+    implements Action
+{
+    // -------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------
+    
+    private OrganisationUnitService organisationUnitService;
+    
+    public void setOrganisationUnitService( OrganisationUnitService organisationUnitService )
+    {
+        this.organisationUnitService = organisationUnitService;
+    }
+
+    // -------------------------------------------------------------------------
+    // Input
+    // -------------------------------------------------------------------------
+
+    private Integer id;
+    
+    public void setId( Integer id )
+    {
+        this.id = id;
+    }
+
+    private String coordinates;
+
+    public void setCoordinates( String coordinates )
+    {
+        this.coordinates = coordinates;
+    }
+    
+    // -------------------------------------------------------------------------
+    // Action implementation
+    // -------------------------------------------------------------------------
+
+    public String execute()
+    {
+        OrganisationUnit organisationUnit = organisationUnitService.getOrganisationUnit( id );
+        
+        organisationUnit.setCoordinates( coordinates );
+        
+        organisationUnitService.updateOrganisationUnit( organisationUnit );
+
+        return SUCCESS;
+    }
+}
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/resources/META-INF/dhis/beans.xml	2011-06-08 13:52:49 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/resources/META-INF/dhis/beans.xml	2011-06-22 05:50:46 +0000
@@ -50,6 +50,13 @@
 			ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
 	</bean>
 
+    <bean id="org.hisp.dhis.mapping.action.UpdateOrganisationUnitCoordinatesAction"
+        class="org.hisp.dhis.mapping.action.UpdateOrganisationUnitCoordinatesAction"
+        scope="prototype">
+        <property name="organisationUnitService"
+            ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
+    </bean>
+
     <!-- UserSetting -->
 
     <bean id="org.hisp.dhis.mapping.action.GetMapUserSettingsAction"

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/resources/struts.xml	2011-06-11 20:37:08 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/resources/struts.xml	2011-06-22 05:50:46 +0000
@@ -84,6 +84,12 @@
 				/dhis-web-mapping/jsonOrganisationUnitChildren.vm</result>
 		</action>
 
+        <action name="updateOrganisationUnitCoordinates"
+            class="org.hisp.dhis.mapping.action.UpdateOrganisationUnitCoordinatesAction">
+            <result name="success" type="velocity-json">/dhis-web-mapping/void.vm
+            </result>
+        </action>
+
         <!-- OrganisationUnitLevel -->
 
         <action name="getOrganisationUnitLevels"

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/css/style.css'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/css/style.css	2011-06-09 13:05:20 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/css/style.css	2011-06-22 05:50:46 +0000
@@ -123,6 +123,12 @@
 .menu-layeroptions-labels {
     background-image:url('../../../images/labels.png');
 }
+.menu-featureoptions-info {
+    background-image:url('../../../images/information2.png');
+}
+.menu-featureoptions-relocate {
+    background-image:url('../../../images/relocate.png');
+}
 .no-icon-menu .x-menu-item-icon {
     display: none;
 }
@@ -235,6 +241,9 @@
 .x-btn .icon-assign {
 	background-image:url('../../../images/accept.png');
 }
+.x-btn .icon-cancel {
+	background-image:url('../../../images/cancel2.png');
+}
 .x-btn .icon-labels {
 	background-image:url('../../../images/labels.png');
 }
@@ -346,6 +355,12 @@
 	font:bold 11px arial;
 	color:#111;
 }
+.window-relocate-title {
+	padding:0 0 3px 21px;
+	background:url('../../../images/relocate.png') no-repeat 0 0 transparent;
+	font:bold 11px arial;
+	color:#111;
+}
 
 /* Ext Panel */
 .panel-title {

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/global.js'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/global.js	2011-06-08 12:11:42 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/global.js	2011-06-22 05:50:46 +0000
@@ -477,7 +477,11 @@
         isSymbol: function() {
             return this.value === G.conf.thematicMap3;
         }
-    }
+    },
+    
+    relocate: {},
+    
+    mouseMove: {}
 };
 
 G.user = {

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/index.js'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/index.js	2011-06-14 07:06:49 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/mapping/javascript/index.js	2011-06-22 06:24:33 +0000
@@ -1952,7 +1952,7 @@
                             }
                         }
                     });
-                    locateFeatureWindow.setPagePosition(Ext.getCmp('east').x - (G.conf.window_width + 15 + 5), Ext.getCmp('center').y + 41);
+                    locateFeatureWindow.setPagePosition(Ext.getCmp('east').x - (locateFeatureWindow.width + 15), Ext.getCmp('center').y + 41);
                     locateFeatureWindow.show();
                 }
                 else {
@@ -2076,8 +2076,7 @@
                                 }
                             ]
                         });
-                        
-                        item.labelWindow.setPagePosition(Ext.getCmp('east').x - (G.conf.window_width + 15 + 5), Ext.getCmp('center').y + 41);
+                        item.labelWindow.setPagePosition(Ext.getCmp('east').x - (item.labelWindow.width + 15), Ext.getCmp('center').y + 41);                        
                         item.labelWindow.show();
                     }
                 }
@@ -2153,7 +2152,7 @@
                 text: 'Overlays',
                 iconCls: 'icon-overlay',
                 handler: function() {
-                    Ext.getCmp('overlays_w').setPagePosition(Ext.getCmp('east').x - (G.conf.window_width + 15 + 5), Ext.getCmp('center').y + 41);
+                    Ext.getCmp('overlays_w').setPagePosition(Ext.getCmp('east').x - (Ext.getCmp('overlays_w').width + 15), Ext.getCmp('center').y + 41);
                     Ext.getCmp('overlays_w').show();
                 }
             }
@@ -2175,7 +2174,7 @@
                 qtip: 'Refresh layer',
                 handler: function() {
                     choropleth.updateValues = true;
-                    choropleth.classify();
+                    choropleth.loadGeoJson();
                 }
             },
             {
@@ -2210,7 +2209,7 @@
                 qtip: 'Refresh layer',
                 handler: function() {
                     point.updateValues = true;
-                    point.classify();
+                    point.loadGeoJson();
                 }
             },
             {
@@ -2244,7 +2243,7 @@
                 id: 'refresh',
                 qtip: 'Refresh layer',
                 handler: function() {
-                    symbol.classify();
+                    symbol.loadGeoJson();
                 }
             },
             {
@@ -2478,7 +2477,7 @@
                         }
                     });
                 }
-                control.window.setPagePosition(Ext.getCmp('east').x - (control.window.width + 15 + 5), Ext.getCmp('center').y + 41);
+                control.window.setPagePosition(Ext.getCmp('east').x - (control.window.width + 15), Ext.getCmp('center').y + 41);
                 control.window.show();
                 document.getElementById('measureDistanceDiv').innerHTML = '0 km';                
                 control.setImmediate(true);
@@ -2683,6 +2682,36 @@
                     e.layer.svgId = svg[svg.length-1].id;
                 });
                 
+                G.vars.map.events.register('mousemove', null, function(e) {
+                    G.vars.mouseMove.x = e.clientX;
+                    G.vars.mouseMove.y = e.clientY;
+                });
+                
+                G.vars.map.events.register('click', null, function(e) {
+                    if (G.vars.relocate.active) {
+                        var mp = document.getElementById('mouseposition');
+                        var coordinates = '[' + mp.childNodes[1].data + ',' + mp.childNodes[4].data + ']';
+                        var center = Ext.getCmp('center').x;
+	
+                        Ext.Ajax.request({
+                            url: G.conf.path_mapping + 'updateOrganisationUnitCoordinates' + G.conf.type,
+                            method: 'POST',
+                            params: {id: G.vars.relocate.feature.attributes.id, coordinates: coordinates},
+                            success: function(r) {
+                                G.vars.relocate.active = false;
+                                G.vars.relocate.widget.featureOptions.coordinate.destroy();
+                                                                
+                                G.vars.relocate.feature.move({x: parseFloat(e.clientX - center), y: parseFloat(e.clientY - 28)});
+                                document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
+                                Ext.message.msg(true, '<span class="x-msg-hl">' + G.vars.relocate.feature.attributes.name + 
+                                    ' </span>relocated to ' +
+                                    '[<span class="x-msg-hl">' + mp.childNodes[1].data + '</span>,' + 
+                                    '<span class="x-msg-hl">' + mp.childNodes[4].data + '</span>]');
+                            }
+                        });
+                    }
+                });
+                
                 document.getElementById('featuredatatext').innerHTML = '<div style="color:#666">' + G.i18n.no_feature_selected + '</div>';
             }
         }

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Choropleth.js'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Choropleth.js	2011-06-19 08:33:00 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Choropleth.js	2011-06-22 05:50:46 +0000
@@ -82,6 +82,8 @@
     
     infrastructuralPeriod: false,
     
+    featureOptions: {},
+    
     initComponent: function() {
     
         this.initProperties();
@@ -1059,7 +1061,7 @@
     createSelectFeatures: function() {
         var scope = this;
         
-        var onHoverSelect = function onHoverSelect(feature) {  
+        var onHoverSelect = function onHoverSelect(feature) {
             if (feature.attributes.name) {
                 document.getElementById('featuredatatext').innerHTML =
                     '<div style="' + G.conf.feature_data_style_name + '">' + feature.attributes.name + '</div>' +
@@ -1082,111 +1084,179 @@
         
         var onClickSelect = function onClickSelect(feature) {
             if (feature.geometry.CLASS_NAME == G.conf.map_feature_type_point_class_name) {
-                if (scope.featureInfoWindow) {
-                    scope.featureInfoWindow.destroy();
+                if (scope.featureOptions.menu) {
+                    scope.featureOptions.menu.destroy();
                 }
                 
-                function fn() {
-                    scope.featureInfoWindow = new Ext.Window({
-                        title: '<span class="window-information-title">' + feature.attributes.name + '</span>',
-                        layout: 'table',
-                        width: G.conf.window_width + 178,
-                        height: G.util.getMultiSelectHeight() + 100,
-                        bodyStyle: 'background-color:#fff',
-                        defaults: {
-                            bodyStyle: 'vertical-align:top',
-                            labelSeparator: G.conf.labelseparator,
-                            emptyText: G.conf.emptytext
-                        },
-                        layoutConfig: {
-                            columns: 2
-                        },
-                        items: [
-                            {
-                                xtype: 'panel',
-                                layout: 'anchor',
-                                bodyStyle: 'padding:8px 4px 8px 8px',
-                                width: 160,
-                                items: [
-                                    {html: '<div class="window-info">Type<p style="font-weight:normal">' + feature.attributes.type + '</p></div>'},
-                                    {html: '<div class="window-info">Code<p style="font-weight:normal">' + feature.attributes.code + '</p></div>'},
-                                    {html: '<div class="window-info">Address<p style="font-weight:normal">' + feature.attributes.ad + '</p></div>'},
-                                    {html: '<div class="window-info">Contact person<p style="font-weight:normal">' + feature.attributes.cp + '</p></div>'},
-                                    {html: '<div class="window-info">Email<p style="font-weight:normal">' + feature.attributes.em + '</p></div>'},
-                                    {html: '<div class="window-info">Phone number<p style="font-weight:normal">' + feature.attributes.pn + '</p></div>'}
-                                ]
-                            },
-                            {
-                                xtype: 'form',
-                                bodyStyle: 'padding:8px 8px 8px 4px',
-                                width: G.conf.window_width + 20,
-                                labelWidth: G.conf.label_width,
-                                items: [
-                                    {html: '<div class="window-info">Infrastructural data</div>'},
-                                    {
-                                        xtype: 'combo',
-                                        name: 'period',
-                                        fieldLabel: G.i18n.period,
-                                        typeAhead: true,
-                                        editable: false,
-                                        valueField: 'id',
-                                        displayField: 'name',
-                                        mode: 'remote',
-                                        forceSelection: true,
-                                        triggerAction: 'all',
-                                        selectOnFocus: true,
-                                        width: G.conf.combo_width,
-                                        store: G.stores.infrastructuralPeriodsByType,
-                                        keepPosition: false,
-                                        listeners: {
-                                            'select': function(cb) {
-                                                scope.infrastructuralPeriod = cb.getValue();
-                                                scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', cb.getValue());
-                                                scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
-                                                scope.stores.infrastructuralDataElementMapValue.load();
+                scope.featureOptions.menu = new Ext.menu.Menu({
+                    showInfo: function() {
+                        if (scope.featureOptions.info) {
+                            scope.featureOptions.info.destroy();
+                        }
+                        
+                        scope.featureOptions.info = new Ext.Window({
+                            title: '<span class="window-information-title">' + feature.attributes.name + '</span>',
+                            layout: 'table',
+                            width: G.conf.window_width + 178,
+                            height: G.util.getMultiSelectHeight() + 100,
+                            bodyStyle: 'background-color:#fff',
+                            defaults: {
+                                bodyStyle: 'vertical-align:top',
+                                labelSeparator: G.conf.labelseparator,
+                                emptyText: G.conf.emptytext
+                            },
+                            layoutConfig: {
+                                columns: 2
+                            },
+                            items: [
+                                {
+                                    xtype: 'panel',
+                                    layout: 'anchor',
+                                    bodyStyle: 'padding:8px 4px 8px 8px',
+                                    width: 160,
+                                    items: [
+                                        {html: '<div class="window-info">Type<p style="font-weight:normal">' + feature.attributes.type + '</p></div>'},
+                                        {html: '<div class="window-info">Code<p style="font-weight:normal">' + feature.attributes.code + '</p></div>'},
+                                        {html: '<div class="window-info">Address<p style="font-weight:normal">' + feature.attributes.ad + '</p></div>'},
+                                        {html: '<div class="window-info">Contact person<p style="font-weight:normal">' + feature.attributes.cp + '</p></div>'},
+                                        {html: '<div class="window-info">Email<p style="font-weight:normal">' + feature.attributes.em + '</p></div>'},
+                                        {html: '<div class="window-info">Phone number<p style="font-weight:normal">' + feature.attributes.pn + '</p></div>'}
+                                    ]
+                                },
+                                {
+                                    xtype: 'form',
+                                    bodyStyle: 'padding:8px 8px 8px 4px',
+                                    width: G.conf.window_width + 20,
+                                    labelWidth: G.conf.label_width,
+                                    items: [
+                                        {html: '<div class="window-info">Infrastructural data</div>'},
+                                        {
+                                            xtype: 'combo',
+                                            name: 'period',
+                                            fieldLabel: G.i18n.period,
+                                            typeAhead: true,
+                                            editable: false,
+                                            valueField: 'id',
+                                            displayField: 'name',
+                                            mode: 'remote',
+                                            forceSelection: true,
+                                            triggerAction: 'all',
+                                            selectOnFocus: true,
+                                            width: G.conf.combo_width,
+                                            store: G.stores.infrastructuralPeriodsByType,
+                                            keepPosition: false,
+                                            listeners: {
+                                                'select': function(cb) {
+                                                    scope.infrastructuralPeriod = cb.getValue();
+                                                    scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', cb.getValue());
+                                                    scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
+                                                    scope.stores.infrastructuralDataElementMapValue.load();
+                                                }
                                             }
+                                        },
+                                        {html: '<div style="padding:4px 0 0 0"></div>'},
+                                        {
+                                            xtype: 'grid',
+                                            height: G.util.getMultiSelectHeight(),
+                                            width: 242,
+                                            cm: new Ext.grid.ColumnModel({
+                                                columns: [
+                                                    {id: 'dataElementName', header: 'Data element', dataIndex: 'dataElementName', sortable: true, width: 150},
+                                                    {id: 'value', header: 'Value', dataIndex: 'value', sortable: true, width: 50}
+                                                ]
+                                            }),
+                                            disableSelection: true,
+                                            viewConfig: {forceFit: true},
+                                            store: scope.stores.infrastructuralDataElementMapValue
                                         }
-                                    },
-                                    {html: '<div style="padding:4px 0 0 0"></div>'},
-                                    {
-                                        xtype: 'grid',
-                                        height: G.util.getMultiSelectHeight(),
-                                        width: 242,
-                                        cm: new Ext.grid.ColumnModel({
-                                            columns: [
-                                                {id: 'dataElementName', header: 'Data element', dataIndex: 'dataElementName', sortable: true, width: 150},
-                                                {id: 'value', header: 'Value', dataIndex: 'value', sortable: true, width: 50}
-                                            ]
-                                        }),
-                                        disableSelection: true,
-                                        viewConfig: {forceFit: true},
-                                        store: scope.stores.infrastructuralDataElementMapValue
+                                    ]
+                                }
+                            ]
+                        });
+    
+                        if (scope.infrastructuralPeriod) {
+                            scope.featureOptions.info.find('name', 'period')[0].setValue(scope.infrastructuralPeriod);
+                            scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', scope.infrastructuralPeriod);
+                            scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
+                            scope.stores.infrastructuralDataElementMapValue.load();
+                        }
+                        scope.featureOptions.info.setPagePosition(Ext.getCmp('east').x - (scope.featureOptions.info.width + 15), Ext.getCmp('center').y + 41);
+                        scope.featureOptions.info.show();
+                        scope.featureOptions.menu.destroy();
+                    },
+                    showRelocate: function() {
+                        if (scope.featureOptions.coordinate) {
+                            scope.featureOptions.coordinate.destroy();
+                        }
+                        
+                        scope.featureOptions.coordinate = new Ext.Window({
+                            title: '<span class="window-relocate-title">' + feature.attributes.name + '</span>',
+                            layout: 'fit',
+                            width: G.conf.window_width,
+                            height: 95,
+                            items: [
+                                {
+                                    xtype: 'panel',
+                                    bodyStyle: 'padding:8px',
+                                    items: [
+                                        {html: 'Please select the new location on the map..'}
+                                    ]
+                                }
+                            ],
+                            bbar: [
+                                '->',
+                                {
+                                    xtype: 'button',
+                                    iconCls: 'icon-cancel',
+                                    hideLabel: true,
+                                    text: G.i18n.cancel,
+                                    handler: function() {
+                                        G.vars.relocate.active = false;
+                                        scope.featureOptions.coordinate.destroy();
+                                        document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
                                     }
-                                ]
-                            }
-                        ]
-                    });
-                    
-                    if (scope.infrastructuralPeriod) {
-                        scope.featureInfoWindow.find('name', 'period')[0].setValue(scope.infrastructuralPeriod);
-                        scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', scope.infrastructuralPeriod);
-                        scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
-                        scope.stores.infrastructuralDataElementMapValue.load();
-                    }
-                    
-                    scope.featureInfoWindow.setPagePosition(Ext.getCmp('east').x - (G.conf.window_width + 178 + 15 + 5), Ext.getCmp('center').y + 41);
-                    scope.featureInfoWindow.show();
-                }
-                
-                if (G.stores.infrastructuralPeriodsByType.isLoaded) {
-                    fn();
-                }
-                else {
-                    G.stores.infrastructuralPeriodsByType.setBaseParam('name', G.system.infrastructuralPeriodType);
-                    G.stores.infrastructuralPeriodsByType.load({callback: function() {
-                        fn();
-                    }});
-                }
+                                }
+                            ],
+                            listeners: {
+                                'close': function() {
+                                    G.vars.relocate.active = false;
+                                    document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
+                                }
+                            }
+                        });
+                        scope.featureOptions.coordinate.setPagePosition(Ext.getCmp('east').x - (scope.featureOptions.coordinate.width + 15), Ext.getCmp('center').y + 41);
+                        scope.featureOptions.coordinate.show();                        
+                    },
+                    items: [
+                        {
+                            text: 'Show information sheet',
+                            iconCls: 'menu-featureoptions-info',
+                            handler: function(item) {
+                                if (G.stores.infrastructuralPeriodsByType.isLoaded) {
+                                    item.parentMenu.showInfo();
+                                }
+                                else {
+                                    G.stores.infrastructuralPeriodsByType.setBaseParam('name', G.system.infrastructuralPeriodType);
+                                    G.stores.infrastructuralPeriodsByType.load({callback: function() {
+                                        item.parentMenu.showInfo();
+                                    }});
+                                }
+                            }
+                        },
+                        {
+                            text: 'Relocate',
+                            iconCls: 'menu-featureoptions-relocate',
+                            handler: function(item) {
+                                G.vars.relocate.active = true;
+                                G.vars.relocate.widget = scope;
+                                G.vars.relocate.feature = feature;
+                                document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'crosshair';
+                                item.parentMenu.showRelocate();
+                            }
+                        }
+                    ]
+                });
+                scope.featureOptions.menu.showAt([G.vars.mouseMove.x, G.vars.mouseMove.y]);
             }
             else {
                 if (feature.attributes.hasChildrenWithCoordinates) {

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Point.js'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Point.js	2011-06-19 08:33:00 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Point.js	2011-06-22 06:24:33 +0000
@@ -82,6 +82,8 @@
     
     infrastructuralPeriod: false,
     
+    featureOptions: {},
+    
     initComponent: function() {
     
         this.initProperties();
@@ -1030,7 +1032,7 @@
     createSelectFeatures: function() {
         var scope = this;
         
-        var onHoverSelect = function onHoverSelect(feature) {  
+        var onHoverSelect = function onHoverSelect(feature) {
             if (feature.attributes.name) {
                 document.getElementById('featuredatatext').innerHTML =
                     '<div style="' + G.conf.feature_data_style_name + '">' + feature.attributes.name + '</div>' +
@@ -1053,111 +1055,179 @@
         
         var onClickSelect = function onClickSelect(feature) {
             if (feature.geometry.CLASS_NAME == G.conf.map_feature_type_point_class_name) {
-                if (scope.featureInfoWindow) {
-                    scope.featureInfoWindow.destroy();
+                if (scope.featureOptions.menu) {
+                    scope.featureOptions.menu.destroy();
                 }
                 
-                function fn() {
-                    scope.featureInfoWindow = new Ext.Window({
-                        title: '<span class="window-information-title">' + feature.attributes.name + '</span>',
-                        layout: 'table',
-                        width: G.conf.window_width + 178,
-                        height: G.util.getMultiSelectHeight() + 100,
-                        bodyStyle: 'background-color:#fff',
-                        defaults: {
-                            bodyStyle: 'vertical-align:top',
-                            labelSeparator: G.conf.labelseparator,
-                            emptyText: G.conf.emptytext
-                        },
-                        layoutConfig: {
-                            columns: 2
-                        },
-                        items: [
-                            {
-                                xtype: 'panel',
-                                layout: 'anchor',
-                                bodyStyle: 'padding:8px 4px 8px 8px',
-                                width: 160,
-                                items: [
-                                    {html: '<div class="window-info">Type<p style="font-weight:normal">' + feature.attributes.type + '</p></div>'},
-                                    {html: '<div class="window-info">Code<p style="font-weight:normal">' + feature.attributes.code + '</p></div>'},
-                                    {html: '<div class="window-info">Address<p style="font-weight:normal">' + feature.attributes.ad + '</p></div>'},
-                                    {html: '<div class="window-info">Contact person<p style="font-weight:normal">' + feature.attributes.cp + '</p></div>'},
-                                    {html: '<div class="window-info">Email<p style="font-weight:normal">' + feature.attributes.em + '</p></div>'},
-                                    {html: '<div class="window-info">Phone number<p style="font-weight:normal">' + feature.attributes.pn + '</p></div>'}
-                                ]
-                            },
-                            {
-                                xtype: 'form',
-                                bodyStyle: 'padding:8px 8px 8px 4px',
-                                width: G.conf.window_width + 20,
-                                labelWidth: G.conf.label_width,
-                                items: [
-                                    {html: '<div class="window-info">Infrastructural data</div>'},
-                                    {
-                                        xtype: 'combo',
-                                        name: 'period',
-                                        fieldLabel: G.i18n.period,
-                                        typeAhead: true,
-                                        editable: false,
-                                        valueField: 'id',
-                                        displayField: 'name',
-                                        mode: 'remote',
-                                        forceSelection: true,
-                                        triggerAction: 'all',
-                                        selectOnFocus: true,
-                                        width: G.conf.combo_width,
-                                        store: G.stores.infrastructuralPeriodsByType,
-                                        keepPosition: false,
-                                        listeners: {
-                                            'select': function(cb) {
-                                                scope.infrastructuralPeriod = cb.getValue();
-                                                scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', cb.getValue());
-                                                scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
-                                                scope.stores.infrastructuralDataElementMapValue.load();
+                scope.featureOptions.menu = new Ext.menu.Menu({
+                    showInfo: function() {
+                        if (scope.featureOptions.info) {
+                            scope.featureOptions.info.destroy();
+                        }
+                        
+                        scope.featureOptions.info = new Ext.Window({
+                            title: '<span class="window-information-title">' + feature.attributes.name + '</span>',
+                            layout: 'table',
+                            width: G.conf.window_width + 178,
+                            height: G.util.getMultiSelectHeight() + 100,
+                            bodyStyle: 'background-color:#fff',
+                            defaults: {
+                                bodyStyle: 'vertical-align:top',
+                                labelSeparator: G.conf.labelseparator,
+                                emptyText: G.conf.emptytext
+                            },
+                            layoutConfig: {
+                                columns: 2
+                            },
+                            items: [
+                                {
+                                    xtype: 'panel',
+                                    layout: 'anchor',
+                                    bodyStyle: 'padding:8px 4px 8px 8px',
+                                    width: 160,
+                                    items: [
+                                        {html: '<div class="window-info">Type<p style="font-weight:normal">' + feature.attributes.type + '</p></div>'},
+                                        {html: '<div class="window-info">Code<p style="font-weight:normal">' + feature.attributes.code + '</p></div>'},
+                                        {html: '<div class="window-info">Address<p style="font-weight:normal">' + feature.attributes.ad + '</p></div>'},
+                                        {html: '<div class="window-info">Contact person<p style="font-weight:normal">' + feature.attributes.cp + '</p></div>'},
+                                        {html: '<div class="window-info">Email<p style="font-weight:normal">' + feature.attributes.em + '</p></div>'},
+                                        {html: '<div class="window-info">Phone number<p style="font-weight:normal">' + feature.attributes.pn + '</p></div>'}
+                                    ]
+                                },
+                                {
+                                    xtype: 'form',
+                                    bodyStyle: 'padding:8px 8px 8px 4px',
+                                    width: G.conf.window_width + 20,
+                                    labelWidth: G.conf.label_width,
+                                    items: [
+                                        {html: '<div class="window-info">Infrastructural data</div>'},
+                                        {
+                                            xtype: 'combo',
+                                            name: 'period',
+                                            fieldLabel: G.i18n.period,
+                                            typeAhead: true,
+                                            editable: false,
+                                            valueField: 'id',
+                                            displayField: 'name',
+                                            mode: 'remote',
+                                            forceSelection: true,
+                                            triggerAction: 'all',
+                                            selectOnFocus: true,
+                                            width: G.conf.combo_width,
+                                            store: G.stores.infrastructuralPeriodsByType,
+                                            keepPosition: false,
+                                            listeners: {
+                                                'select': function(cb) {
+                                                    scope.infrastructuralPeriod = cb.getValue();
+                                                    scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', cb.getValue());
+                                                    scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
+                                                    scope.stores.infrastructuralDataElementMapValue.load();
+                                                }
                                             }
+                                        },
+                                        {html: '<div style="padding:4px 0 0 0"></div>'},
+                                        {
+                                            xtype: 'grid',
+                                            height: G.util.getMultiSelectHeight(),
+                                            width: 242,
+                                            cm: new Ext.grid.ColumnModel({
+                                                columns: [
+                                                    {id: 'dataElementName', header: 'Data element', dataIndex: 'dataElementName', sortable: true, width: 150},
+                                                    {id: 'value', header: 'Value', dataIndex: 'value', sortable: true, width: 50}
+                                                ]
+                                            }),
+                                            disableSelection: true,
+                                            viewConfig: {forceFit: true},
+                                            store: scope.stores.infrastructuralDataElementMapValue
                                         }
-                                    },
-                                    {html: '<div style="padding:4px 0 0 0"></div>'},
-                                    {
-                                        xtype: 'grid',
-                                        height: G.util.getMultiSelectHeight(),
-                                        width: 242,
-                                        cm: new Ext.grid.ColumnModel({
-                                            columns: [
-                                                {id: 'dataElementName', header: 'Data element', dataIndex: 'dataElementName', sortable: true, width: 150},
-                                                {id: 'value', header: 'Value', dataIndex: 'value', sortable: true, width: 50}
-                                            ]
-                                        }),
-                                        disableSelection: true,
-                                        viewConfig: {forceFit: true},
-                                        store: scope.stores.infrastructuralDataElementMapValue
+                                    ]
+                                }
+                            ]
+                        });
+    
+                        if (scope.infrastructuralPeriod) {
+                            scope.featureOptions.info.find('name', 'period')[0].setValue(scope.infrastructuralPeriod);
+                            scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', scope.infrastructuralPeriod);
+                            scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
+                            scope.stores.infrastructuralDataElementMapValue.load();
+                        }
+                        scope.featureOptions.info.setPagePosition(Ext.getCmp('east').x - (scope.featureOptions.info.width + 15), Ext.getCmp('center').y + 41);
+                        scope.featureOptions.info.show();
+                        scope.featureOptions.menu.destroy();
+                    },
+                    showRelocate: function() {
+                        if (scope.featureOptions.coordinate) {
+                            scope.featureOptions.coordinate.destroy();
+                        }
+                        
+                        scope.featureOptions.coordinate = new Ext.Window({
+                            title: '<span class="window-relocate-title">' + feature.attributes.name + '</span>',
+                            layout: 'fit',
+                            width: G.conf.window_width,
+                            height: 95,
+                            items: [
+                                {
+                                    xtype: 'panel',
+                                    bodyStyle: 'padding:8px',
+                                    items: [
+                                        {html: 'Please select the new location on the map..'}
+                                    ]
+                                }
+                            ],
+                            bbar: [
+                                '->',
+                                {
+                                    xtype: 'button',
+                                    iconCls: 'icon-cancel',
+                                    hideLabel: true,
+                                    text: G.i18n.cancel,
+                                    handler: function() {
+                                        G.vars.relocate.active = false;
+                                        scope.featureOptions.coordinate.destroy();
+                                        document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
                                     }
-                                ]
-                            }
-                        ]
-                    });
-                    
-                    if (scope.infrastructuralPeriod) {
-                        scope.featureInfoWindow.find('name', 'period')[0].setValue(scope.infrastructuralPeriod);
-                        scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', scope.infrastructuralPeriod);
-                        scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
-                        scope.stores.infrastructuralDataElementMapValue.load();
-                    }
-                    
-                    scope.featureInfoWindow.setPagePosition(Ext.getCmp('east').x - (G.conf.window_width + 178 + 15 + 5), Ext.getCmp('center').y + 41);
-                    scope.featureInfoWindow.show();
-                }
-                
-                if (G.stores.infrastructuralPeriodsByType.isLoaded) {
-                    fn();
-                }
-                else {
-                    G.stores.infrastructuralPeriodsByType.setBaseParam('name', G.system.infrastructuralPeriodType);
-                    G.stores.infrastructuralPeriodsByType.load({callback: function() {
-                        fn();
-                    }});
-                }
+                                }
+                            ],
+                            listeners: {
+                                'close': function() {
+                                    G.vars.relocate.active = false;
+                                    document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
+                                }
+                            }
+                        });
+                        scope.featureOptions.coordinate.setPagePosition(Ext.getCmp('east').x - (scope.featureOptions.coordinate.width + 15), Ext.getCmp('center').y + 41);
+                        scope.featureOptions.coordinate.show();                        
+                    },
+                    items: [
+                        {
+                            text: 'Show information sheet',
+                            iconCls: 'menu-featureoptions-info',
+                            handler: function(item) {
+                                if (G.stores.infrastructuralPeriodsByType.isLoaded) {
+                                    item.parentMenu.showInfo();
+                                }
+                                else {
+                                    G.stores.infrastructuralPeriodsByType.setBaseParam('name', G.system.infrastructuralPeriodType);
+                                    G.stores.infrastructuralPeriodsByType.load({callback: function() {
+                                        item.parentMenu.showInfo();
+                                    }});
+                                }
+                            }
+                        },
+                        {
+                            text: 'Relocate',
+                            iconCls: 'menu-featureoptions-relocate',
+                            handler: function(item) {
+                                G.vars.relocate.active = true;
+                                G.vars.relocate.widget = scope;
+                                G.vars.relocate.feature = feature;
+                                document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'crosshair';
+                                item.parentMenu.showRelocate();
+                            }
+                        }
+                    ]
+                });
+                scope.featureOptions.menu.showAt([G.vars.mouseMove.x, G.vars.mouseMove.y]);
             }
             else {
                 if (feature.attributes.hasChildrenWithCoordinates) {

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Symbol.js'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Symbol.js	2011-06-19 08:33:00 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/webapp/dhis-web-mapping/resources/mapfish/widgets/geostat/Symbol.js	2011-06-22 06:24:33 +0000
@@ -80,6 +80,8 @@
     
     infrastructuralPeriod: false,
     
+    featureOptions: {},
+    
     initComponent: function() {
         
         this.initProperties();
@@ -523,112 +525,179 @@
         
         var onClickSelect = function onClickSelect(feature) {
             if (feature.geometry.CLASS_NAME == G.conf.map_feature_type_point_class_name) {
-                if (scope.featureInfoWindow) {
-                    scope.featureInfoWindow.destroy();
+                if (scope.featureOptions.menu) {
+                    scope.featureOptions.menu.destroy();
                 }
                 
-                function fn() {
-                    var cssCls = G.stores.groupsByGroupSet.img[G.stores.groupsByGroupSet.find('name', feature.attributes.type)] + '-title';            
-                    scope.featureInfoWindow = new Ext.Window({
-                        title: '<span class="' + cssCls + '">' + feature.attributes.name + '</span>',
-                        layout: 'table',
-                        width: G.conf.window_width + 178,
-                        height: G.util.getMultiSelectHeight() + 100,
-                        bodyStyle: 'background-color:#fff',
-                        defaults: {
-                            bodyStyle: 'vertical-align:top',
-                            labelSeparator: G.conf.labelseparator,
-                            emptyText: G.conf.emptytext
-                        },
-                        layoutConfig: {
-                            columns: 2
-                        },
-                        items: [
-                            {
-                                xtype: 'panel',
-                                layout: 'anchor',
-                                bodyStyle: 'padding:8px 4px 8px 8px',
-                                width: 160,
-                                items: [
-                                    {html: '<div class="window-info">Type<p style="font-weight:normal">' + feature.attributes.type + '</p></div>'},
-                                    {html: '<div class="window-info">Code<p style="font-weight:normal">' + feature.attributes.code + '</p></div>'},
-                                    {html: '<div class="window-info">Address<p style="font-weight:normal">' + feature.attributes.ad + '</p></div>'},
-                                    {html: '<div class="window-info">Contact person<p style="font-weight:normal">' + feature.attributes.cp + '</p></div>'},
-                                    {html: '<div class="window-info">Email<p style="font-weight:normal">' + feature.attributes.em + '</p></div>'},
-                                    {html: '<div class="window-info">Phone number<p style="font-weight:normal">' + feature.attributes.pn + '</p></div>'}
-                                ]
-                            },
-                            {
-                                xtype: 'form',
-                                bodyStyle: 'padding:8px 8px 8px 4px',
-                                width: G.conf.window_width + 20,
-                                labelWidth: G.conf.label_width,
-                                items: [
-                                    {html: '<div class="window-info">Infrastructural data</div>'},
-                                    {
-                                        xtype: 'combo',
-                                        name: 'period',
-                                        fieldLabel: G.i18n.period,
-                                        typeAhead: true,
-                                        editable: false,
-                                        valueField: 'id',
-                                        displayField: 'name',
-                                        mode: 'remote',
-                                        forceSelection: true,
-                                        triggerAction: 'all',
-                                        selectOnFocus: true,
-                                        width: G.conf.combo_width,
-                                        store: G.stores.infrastructuralPeriodsByType,
-                                        keepPosition: false,
-                                        listeners: {
-                                            'select': function(cb) {
-                                                scope.infrastructuralPeriod = cb.getValue();
-                                                scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', cb.getValue());
-                                                scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
-                                                scope.stores.infrastructuralDataElementMapValue.load();
+                scope.featureOptions.menu = new Ext.menu.Menu({
+                    showInfo: function() {
+                        if (scope.featureOptions.info) {
+                            scope.featureOptions.info.destroy();
+                        }
+                        
+                        scope.featureOptions.info = new Ext.Window({
+                            title: '<span class="window-information-title">' + feature.attributes.name + '</span>',
+                            layout: 'table',
+                            width: G.conf.window_width + 178,
+                            height: G.util.getMultiSelectHeight() + 100,
+                            bodyStyle: 'background-color:#fff',
+                            defaults: {
+                                bodyStyle: 'vertical-align:top',
+                                labelSeparator: G.conf.labelseparator,
+                                emptyText: G.conf.emptytext
+                            },
+                            layoutConfig: {
+                                columns: 2
+                            },
+                            items: [
+                                {
+                                    xtype: 'panel',
+                                    layout: 'anchor',
+                                    bodyStyle: 'padding:8px 4px 8px 8px',
+                                    width: 160,
+                                    items: [
+                                        {html: '<div class="window-info">Type<p style="font-weight:normal">' + feature.attributes.type + '</p></div>'},
+                                        {html: '<div class="window-info">Code<p style="font-weight:normal">' + feature.attributes.code + '</p></div>'},
+                                        {html: '<div class="window-info">Address<p style="font-weight:normal">' + feature.attributes.ad + '</p></div>'},
+                                        {html: '<div class="window-info">Contact person<p style="font-weight:normal">' + feature.attributes.cp + '</p></div>'},
+                                        {html: '<div class="window-info">Email<p style="font-weight:normal">' + feature.attributes.em + '</p></div>'},
+                                        {html: '<div class="window-info">Phone number<p style="font-weight:normal">' + feature.attributes.pn + '</p></div>'}
+                                    ]
+                                },
+                                {
+                                    xtype: 'form',
+                                    bodyStyle: 'padding:8px 8px 8px 4px',
+                                    width: G.conf.window_width + 20,
+                                    labelWidth: G.conf.label_width,
+                                    items: [
+                                        {html: '<div class="window-info">Infrastructural data</div>'},
+                                        {
+                                            xtype: 'combo',
+                                            name: 'period',
+                                            fieldLabel: G.i18n.period,
+                                            typeAhead: true,
+                                            editable: false,
+                                            valueField: 'id',
+                                            displayField: 'name',
+                                            mode: 'remote',
+                                            forceSelection: true,
+                                            triggerAction: 'all',
+                                            selectOnFocus: true,
+                                            width: G.conf.combo_width,
+                                            store: G.stores.infrastructuralPeriodsByType,
+                                            keepPosition: false,
+                                            listeners: {
+                                                'select': function(cb) {
+                                                    scope.infrastructuralPeriod = cb.getValue();
+                                                    scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', cb.getValue());
+                                                    scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
+                                                    scope.stores.infrastructuralDataElementMapValue.load();
+                                                }
                                             }
+                                        },
+                                        {html: '<div style="padding:4px 0 0 0"></div>'},
+                                        {
+                                            xtype: 'grid',
+                                            height: G.util.getMultiSelectHeight(),
+                                            width: 242,
+                                            cm: new Ext.grid.ColumnModel({
+                                                columns: [
+                                                    {id: 'dataElementName', header: 'Data element', dataIndex: 'dataElementName', sortable: true, width: 150},
+                                                    {id: 'value', header: 'Value', dataIndex: 'value', sortable: true, width: 50}
+                                                ]
+                                            }),
+                                            disableSelection: true,
+                                            viewConfig: {forceFit: true},
+                                            store: scope.stores.infrastructuralDataElementMapValue
                                         }
-                                    },
-                                    {html: '<div style="padding:4px 0 0 0"></div>'},
-                                    {
-                                        xtype: 'grid',
-                                        height: G.util.getMultiSelectHeight(),
-                                        width: 242,
-                                        cm: new Ext.grid.ColumnModel({
-                                            columns: [
-                                                {id: 'dataElementName', header: 'Data element', dataIndex: 'dataElementName', sortable: true, width: 150},
-                                                {id: 'value', header: 'Value', dataIndex: 'value', sortable: true, width: 50}
-                                            ]
-                                        }),
-                                        disableSelection: true,
-                                        viewConfig: {forceFit: true},
-                                        store: scope.stores.infrastructuralDataElementMapValue
+                                    ]
+                                }
+                            ]
+                        });
+    
+                        if (scope.infrastructuralPeriod) {
+                            scope.featureOptions.info.find('name', 'period')[0].setValue(scope.infrastructuralPeriod);
+                            scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', scope.infrastructuralPeriod);
+                            scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
+                            scope.stores.infrastructuralDataElementMapValue.load();
+                        }
+                        scope.featureOptions.info.setPagePosition(Ext.getCmp('east').x - (scope.featureOptions.info.width + 15), Ext.getCmp('center').y + 41);
+                        scope.featureOptions.info.show();
+                        scope.featureOptions.menu.destroy();
+                    },
+                    showRelocate: function() {
+                        if (scope.featureOptions.coordinate) {
+                            scope.featureOptions.coordinate.destroy();
+                        }
+                        
+                        scope.featureOptions.coordinate = new Ext.Window({
+                            title: '<span class="window-relocate-title">' + feature.attributes.name + '</span>',
+                            layout: 'fit',
+                            width: G.conf.window_width,
+                            height: 95,
+                            items: [
+                                {
+                                    xtype: 'panel',
+                                    bodyStyle: 'padding:8px',
+                                    items: [
+                                        {html: 'Please select the new location on the map..'}
+                                    ]
+                                }
+                            ],
+                            bbar: [
+                                '->',
+                                {
+                                    xtype: 'button',
+                                    iconCls: 'icon-cancel',
+                                    hideLabel: true,
+                                    text: G.i18n.cancel,
+                                    handler: function() {
+                                        G.vars.relocate.active = false;
+                                        scope.featureOptions.coordinate.destroy();
+                                        document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
                                     }
-                                ]
-                            }
-                        ]
-                    });
-                    
-                    if (scope.infrastructuralPeriod) {
-                        scope.featureInfoWindow.find('name', 'period')[0].setValue(scope.infrastructuralPeriod);
-                        scope.stores.infrastructuralDataElementMapValue.setBaseParam('periodId', scope.infrastructuralPeriod);
-                        scope.stores.infrastructuralDataElementMapValue.setBaseParam('organisationUnitId', feature.attributes.id);
-                        scope.stores.infrastructuralDataElementMapValue.load();
-                    }
-                    
-                    scope.featureInfoWindow.setPagePosition(Ext.getCmp('east').x - (G.conf.window_width + 178 + 15 + 5), Ext.getCmp('center').y + 41);
-                    scope.featureInfoWindow.show();
-                }
-                
-                if (G.stores.infrastructuralPeriodsByType.isLoaded) {
-                    fn();
-                }
-                else {
-                    G.stores.infrastructuralPeriodsByType.setBaseParam('name', G.system.infrastructuralPeriodType);
-                    G.stores.infrastructuralPeriodsByType.load({callback: function() {
-                        fn();
-                    }});
-                }
+                                }
+                            ],
+                            listeners: {
+                                'close': function() {
+                                    G.vars.relocate.active = false;
+                                    document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'auto';
+                                }
+                            }
+                        });
+                        scope.featureOptions.coordinate.setPagePosition(Ext.getCmp('east').x - (scope.featureOptions.coordinate.width + 15), Ext.getCmp('center').y + 41);
+                        scope.featureOptions.coordinate.show();                        
+                    },
+                    items: [
+                        {
+                            text: 'Show information sheet',
+                            iconCls: 'menu-featureoptions-info',
+                            handler: function(item) {
+                                if (G.stores.infrastructuralPeriodsByType.isLoaded) {
+                                    item.parentMenu.showInfo();
+                                }
+                                else {
+                                    G.stores.infrastructuralPeriodsByType.setBaseParam('name', G.system.infrastructuralPeriodType);
+                                    G.stores.infrastructuralPeriodsByType.load({callback: function() {
+                                        item.parentMenu.showInfo();
+                                    }});
+                                }
+                            }
+                        },
+                        {
+                            text: 'Relocate',
+                            iconCls: 'menu-featureoptions-relocate',
+                            handler: function(item) {
+                                G.vars.relocate.active = true;
+                                G.vars.relocate.widget = scope;
+                                G.vars.relocate.feature = feature;
+                                document.getElementById('OpenLayers.Map_3_OpenLayers_ViewPort').style.cursor = 'crosshair';
+                                item.parentMenu.showRelocate();
+                            }
+                        }
+                    ]
+                });
+                scope.featureOptions.menu.showAt([G.vars.mouseMove.x, G.vars.mouseMove.y]);
             }
             else {
                 if (feature.attributes.hasChildrenWithCoordinates) {