← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 10185: (GIS) Root level rendering bug fixed + (PT) Sharing (wip).

 

Merge authors:
  Jan Henrik Øverland (janhenrik-overland)
------------------------------------------------------------
revno: 10185 [merge]
committer: Jan Henrik Overland <janhenrik.overland@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2013-03-13 18:01:13 +0100
message:
  (GIS) Root level rendering bug fixed + (PT) Sharing (wip).
added:
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/images/grid-sharing_16.png
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml
  dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/GetGeoJsonAction.java
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm


--
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
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java	2013-03-11 14:11:16 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java	2013-03-12 13:44:27 +0000
@@ -141,6 +141,10 @@
     public static final String FONT_SIZE_LARGE = "large";
     public static final String FONT_SIZE_NORMAL = "normal";
     public static final String FONT_SIZE_SMALL = "small";
+
+    public static final String NUMBER_FORMATTING_COMMA = "comma";
+    public static final String NUMBER_FORMATTING_SPACE = "space";
+    public static final String NUMBER_FORMATTING_NONE = "none";
     
     public static final int ASC = -1;
     public static final int DESC = 1;
@@ -310,6 +314,11 @@
     private boolean hideEmptyRows;
     
     /**
+     * Indicates rendering of number formatting for the table.
+     */
+    private String numberFormatting;
+    
+    /**
      * The display density of the text in the table.
      */
     private String displayDensity;
@@ -1402,6 +1411,19 @@
     @JsonProperty
     @JsonView( {DetailedView.class, ExportView.class} )
     @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0)
+    public String getNumberFormatting()
+    {
+        return numberFormatting;
+    }
+
+    public void setNumberFormatting( String numberFormatting )
+    {
+        this.numberFormatting = numberFormatting;
+    }
+
+    @JsonProperty
+    @JsonView( {DetailedView.class, ExportView.class} )
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0)
     public String getDisplayDensity()
     {
         return displayDensity;
@@ -1630,6 +1652,7 @@
             topLimit = reportTable.getTopLimit() == null ? topLimit : reportTable.getTopLimit();
             subtotals = reportTable.isSubtotals();
             hideEmptyRows = reportTable.isHideEmptyRows();
+            numberFormatting = reportTable.getNumberFormatting();
             displayDensity = reportTable.getDisplayDensity();
             fontSize = reportTable.getFontSize();
             userOrganisationUnit = reportTable.isUserOrganisationUnit();

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2013-03-13 15:03:10 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2013-03-13 16:50:49 +0000
@@ -427,6 +427,7 @@
         executeSql( "update reporttable set displaydensity = 'normal' where displaydensity is null" );
         executeSql( "update reporttable set fontsize = 'normal' where fontsize is null" );
         executeSql( "update reporttable set hideemptyrows = false where hideemptyrows is null" );
+        executeSql( "update reporttable set numberformatting = 'space' where numberformatting is null" );
 
         executeSql( "update chart set reportingmonth = false where reportingmonth is null" );
         executeSql( "update chart set reportingbimonth = false where reportingbimonth is null" );

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml	2013-03-11 14:11:16 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml	2013-03-12 13:44:27 +0000
@@ -138,6 +138,8 @@
     
     <property name="hideEmptyRows" />
     
+    <property name="numberFormatting" />
+    
     <property name="displayDensity" />
     
     <property name="fontSize" />

=== modified file 'dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/GetGeoJsonAction.java'
--- dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/GetGeoJsonAction.java	2012-11-26 18:44:13 +0000
+++ dhis-2/dhis-web/dhis-web-mapping/src/main/java/org/hisp/dhis/mapping/action/GetGeoJsonAction.java	2013-03-13 16:50:19 +0000
@@ -131,7 +131,7 @@
         {
             orgUnitLevel = organisationUnitService.getOrganisationUnitLevel( parent.getOrganisationUnitLevel() );
         }
-
+        
         Collection<OrganisationUnit> organisationUnits = organisationUnitService.getOrganisationUnitsAtLevel(
             orgUnitLevel.getLevel(), parent );
 
@@ -160,11 +160,14 @@
             }
         }
         
-        Collection<OrganisationUnit> organisationUnitsUp = organisationUnitService.getOrganisationUnitsAtLevel( orgUnitLevel.getLevel() - 1 );
-        
-        FilterUtils.filter( organisationUnitsUp, new OrganisationUnitWithValidCoordinatesFilter() );
-        
-        hasCoordinatesUp = organisationUnitsUp.size() > 0;
+        if ( orgUnitLevel.getLevel() > 1 )
+        {
+            Collection<OrganisationUnit> organisationUnitsUp = organisationUnitService.getOrganisationUnitsAtLevel( orgUnitLevel.getLevel() - 1 );
+            
+            FilterUtils.filter( organisationUnitsUp, new OrganisationUnitWithValidCoordinatesFilter() );
+            
+            hasCoordinatesUp = organisationUnitsUp.size() > 0;
+        }
 
         return SUCCESS;
     }

=== added file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/images/grid-sharing_16.png'
Binary files dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/images/grid-sharing_16.png	1970-01-01 00:00:00 +0000 and dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/images/grid-sharing_16.png	2013-03-13 17:01:13 +0000 differ
=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js	2013-03-11 15:39:06 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js	2013-03-13 16:19:28 +0000
@@ -109,7 +109,7 @@
 				}
 			},
 			addBlurHandler: function(w) {
-				var el = Ext.get(document.getElementsByClassName('x-mask')[0]);
+				var el = Ext.get(Ext.query('.x-mask')[0]);
 
 				el.on('click', function() {
 					w.hide();
@@ -121,7 +121,7 @@
 
 		util.pivot.getSettingsConfig = function() {
 			var data = {},
-				setup = pt.viewport.settingsWindow.getSetup(),
+				setup = pt.viewport.settingsWindow ? pt.viewport.settingsWindow.getSetup() : {},
 				getData,
 				extendSettings,
 				config;
@@ -361,7 +361,7 @@
 				}
 			},
 			listeners: {
-				load: function() {
+				load: function(s) {
 					if (!this.isLoaded) {
 						this.isLoaded = true;
 					}
@@ -697,15 +697,23 @@
 				'->',
 				{
 					text: 'Hide',
-					handler: function() {
-						window.hide();
+					listeners: {
+						added: function(b) {
+							b.on('click', function() {
+								window.hide();
+							});
+						}
 					}
 				},
 				{
 					text: '<b>Update</b>',
-					handler: function() {
-						pt.viewport.updateViewport();
-						window.hide();
+					listeners: {
+						added: function(b) {
+							b.on('click', function() {
+								pt.viewport.updateViewport();
+								window.hide();
+							});
+						}
 					}
 				}
 			],
@@ -727,6 +735,7 @@
 	PT.app.OptionsWindow = function() {
 		var showSubTotals,
 			hideEmptyRows,
+			numberFormatting,
 			displayDensity,
 			fontSize,
 
@@ -745,8 +754,28 @@
 		});
 		pt.viewport.hideEmptyRows = hideEmptyRows;
 
+		numberFormatting = Ext.create('Ext.form.field.ComboBox', {
+			fieldLabel: 'Number formatting', //i18n
+			labelStyle: 'color:#333',
+			cls: 'pt-combo',
+			width: 230,
+			queryMode: 'local',
+			valueField: 'id',
+			editable: false,
+			value: 'space',
+			store: Ext.create('Ext.data.Store', {
+				fields: ['id', 'text'],
+				data: [
+					{id: 'comma', text: 'Comma'},
+					{id: 'space', text: 'Space'},
+					{id: 'none', text: 'None'}
+				]
+			})
+		});
+		pt.viewport.numberFormatting = numberFormatting;
+
 		displayDensity = Ext.create('Ext.form.field.ComboBox', {
-			fieldLabel: 'Display density',
+			fieldLabel: 'Display density', //i18n
 			labelStyle: 'color:#333',
 			cls: 'pt-combo',
 			width: 230,
@@ -767,7 +796,7 @@
 
 		fontSize = Ext.create('Ext.form.field.ComboBox', {
 			xtype: 'combobox',
-			fieldLabel: 'Font size',
+			fieldLabel: 'Font size', //i18n
 			labelStyle: 'color:#333',
 			cls: 'pt-combo',
 			width: 230,
@@ -799,6 +828,7 @@
 			bodyStyle: 'border:0 none',
 			style: 'margin-left:14px',
 			items: [
+				numberFormatting,
 				displayDensity,
 				fontSize
 			]
@@ -815,6 +845,7 @@
 				return {
 					showSubTotals: showSubTotals.getValue(),
 					hideEmptyRows: hideEmptyRows.getValue(),
+					numberFormatting: numberFormatting.getValue(),
 					displayDensity: displayDensity.getValue(),
 					fontSize: fontSize.getValue()
 				};
@@ -887,33 +918,42 @@
 			tbar,
 			bbar,
 			info,
-
 			nameTextfield,
-			systemCheckbox,
 			createButton,
 			updateButton,
 			cancelButton,
+			mapWindow,
 
-			mapWindow;
+		// Vars
+			windowWidth = 500,
+			windowCmpWidth = windowWidth - 22;
 
 		pt.store.tables.on('load', function(store, records) {
-			info.setText(records.length + ' favorite' + (records.length !== 1 ? 's' : '') + ' available');
+			var pager = store.proxy.reader.jsonData.pager;
+
+			info.setText('Page ' + pager.page + ' of ' + pager.pageCount);
+
+			prevButton.enable();
+			nextButton.enable();
+
+			if (pager.page === 1) {
+				prevButton.disable();
+			}
+
+			if (pager.page === pager.pageCount) {
+				nextButton.disable();
+			}
 		});
 
 		getBody = function() {
-			var name = nameTextfield.getValue(),
-				system = systemCheckbox.getValue(),
-				favorite;
+			var favorite;
 
 			if (pt.xSettings) {
 				favorite = Ext.clone(pt.xSettings.options);
 
-				// server
+				// Server sync
 				favorite.subtotals = favorite.showSubTotals;
 
-				favorite.name = name;
-				favorite.user = system ? null : {id: 'currentUser'};
-
 				// Dimensions
 				for (var i = 0, obj, key, items; i < pt.xSettings.objects.length; i++) {
 					obj = pt.xSettings.objects[i];
@@ -1029,25 +1069,23 @@
 				}
 			});
 
-			systemCheckbox = Ext.create('Ext.form.field.Checkbox', {
-				labelWidth: 70,
-				fieldLabel: 'System', //i18n
-				style: 'margin-bottom: 0',
-				disabled: !pt.init.user.isAdmin,
-				checked: !id ? false : (record.data.user ? false : true)
-			});
-
 			createButton = Ext.create('Ext.button.Button', {
 				text: 'Create', //i18n
 				handler: function() {
 					var favorite = getBody();
 
+					favorite.name = nameTextfield.getValue();
+
 					if (favorite) {
 						Ext.Ajax.request({
 							url: pt.baseUrl + '/api/reportTables/',
 							method: 'POST',
 							headers: {'Content-Type': 'application/json'},
 							params: Ext.encode(favorite),
+							failure: function(r) {
+								pt.viewport.mask.show();
+								alert(r.responseText);
+							},
 							success: function(r) {
 								var id = r.getAllResponseHeaders().location.split('/').pop();
 
@@ -1071,16 +1109,37 @@
 				text: 'Update', //i18n
 				handler: function() {
 					var name = nameTextfield.getValue(),
-						system = systemCheckbox.getValue();
-
-					Ext.Ajax.request({
-						url: pt.baseUrl + pt.conf.finals.ajax.path_pivot + 'renameMap.action?id=' + id + '&name=' + name + '&user=' + !system,
-						success: function() {
-							pt.store.tables.loadStore();
-
-							window.destroy();
-						}
-					});
+						reportTable;
+
+					if (id && name) {
+						Ext.Ajax.request({
+							url: pt.baseUrl + '/api/reportTables/' + id + '.json?links=false',
+							method: 'GET',
+							failure: function(r) {
+								pt.viewport.mask.show();
+								alert(r.responseText);
+							},
+							success: function(r) {
+								reportTable = Ext.decode(r.responseText);
+								reportTable.name = name;
+
+								Ext.Ajax.request({
+									url: pt.baseUrl + '/api/reportTables/' + reportTable.id,
+									method: 'PUT',
+									headers: {'Content-Type': 'application/json'},
+									params: Ext.encode(reportTable),
+									failure: function(r) {
+										pt.viewport.mask.show();
+										alert(r.responseText);
+									},
+									success: function(r) {
+										pt.store.tables.loadStore();
+										window.destroy();
+									}
+								});
+							}
+						});
+					}
 				}
 			});
 
@@ -1098,8 +1157,7 @@
 				resizable: false,
 				modal: true,
 				items: [
-					nameTextfield,
-					systemCheckbox
+					nameTextfield
 				],
 				bbar: [
 					cancelButton,
@@ -1129,7 +1187,7 @@
 		});
 
 		searchTextfield = Ext.create('Ext.form.field.Text', {
-			width: 350,
+			width: windowCmpWidth - addButton.width - 11,
 			height: 26,
 			fieldStyle: 'padding-right: 0; padding-left: 6px; border-radius: 1px; border-color: #bbb; font-size:11px',
 			emptyText: 'Search for favorites', //i18n
@@ -1191,7 +1249,7 @@
 				{
 					dataIndex: 'name',
 					sortable: false,
-					width: 340,
+					width: windowCmpWidth - 88,
 					renderer: function(value, metaData, record) {
 						var fn = function() {
 							var el = Ext.get(record.data.id);
@@ -1220,21 +1278,15 @@
 						{
 							iconCls: 'pt-grid-row-icon-edit',
 							getClass: function(value, metaData, record) {
-								var system = !record.data.user,
-									isAdmin = pt.init.user.isAdmin;
-
-								if (isAdmin || (!isAdmin && !system)) {
+								if (pt.init.user.isAdmin) {
 									return 'tooltip-favorite-edit';
 								}
 							},
 							handler: function(grid, rowIndex, colIndex, col, event) {
 								var record = this.up('grid').store.getAt(rowIndex),
-									id = record.data.id,
-									system = !record.data.user,
-									isAdmin = pt.init.user.isAdmin;
+									id = record.data.id;
 
-								if (isAdmin || (!isAdmin && !system)) {
-									var id = this.up('grid').store.getAt(rowIndex).data.id;
+								if (pt.init.user.isAdmin) {
 									nameWindow = new NameWindow(id);
 									nameWindow.show();
 								}
@@ -1243,10 +1295,7 @@
 						{
 							iconCls: 'pt-grid-row-icon-overwrite',
 							getClass: function(value, metaData, record) {
-								var system = !record.data.user,
-									isAdmin = pt.init.user.isAdmin;
-
-								if (isAdmin || (!isAdmin && !system)) {
+								if (pt.init.user.isAdmin) {
 									return 'tooltip-favorite-overwrite';
 								}
 							},
@@ -1258,6 +1307,8 @@
 									favorite = getBody();
 
 								if (favorite) {
+									favorite.name = name;
+
 									if (confirm(message)) {
 										Ext.Ajax.request({
 											url: pt.baseUrl + '/api/reportTables/' + id,
@@ -1280,24 +1331,30 @@
 							}
 						},
 						{
-							iconCls: 'pt-grid-row-icon-dashboard',
+							iconCls: 'pt-grid-row-icon-sharing',
 							getClass: function() {
-								return 'tooltip-favorite-dashboard';
+								return 'tooltip-favorite-sharing';
 							},
 							handler: function(grid, rowIndex) {
 								var record = this.up('grid').store.getAt(rowIndex),
 									id = record.data.id,
-									name = record.data.name,
-									message = 'Add to dashboard?\n\n' + name;
+									window;
+									//name = record.data.name,
+									//message = 'Add to dashboard?\n\n' + name;
 
-								if (confirm(message)) {
-									Ext.Ajax.request({
-										url: pt.baseUrl + pt.conf.finals.ajax.path_pivot + 'addMapViewToDashboard.action',
-										params: {
-											id: id
-										}
-									});
-								}
+								Ext.Ajax.request({
+									url: pt.baseUrl + '/api/sharing?type=reportTable&id=' + id,
+									method: 'GET',
+									failure: function(r) {
+										pt.viewport.mask.hide();
+										alert(r.responseText);
+									},
+									success: function(r) {
+										sharing = Ext.decode(r.responseText);
+										window = PT.app.SharingWindow(sharing);
+										window.show();
+									}
+								});
 							}
 						},
 						{
@@ -1367,6 +1424,7 @@
 						var editArray = document.getElementsByClassName('tooltip-favorite-edit'),
 							overwriteArray = document.getElementsByClassName('tooltip-favorite-overwrite'),
 							dashboardArray = document.getElementsByClassName('tooltip-favorite-dashboard'),
+							sharingArray = document.getElementsByClassName('tooltip-favorite-sharing'),
 							deleteArray = document.getElementsByClassName('tooltip-favorite-delete'),
 							el;
 
@@ -1409,6 +1467,17 @@
 								showDelay: 1000
 							});
 						}
+
+						for (var i = 0; i < sharingArray.length; i++) {
+							el = sharingArray[i];
+							Ext.create('Ext.tip.ToolTip', {
+								target: el,
+								html: 'Share with other people',
+								'anchor': 'bottom',
+								anchorOffset: -14,
+								showDelay: 1000
+							});
+						}
 					};
 
 					Ext.defer(fn, 100);
@@ -1432,7 +1501,7 @@
 			bodyStyle: 'padding: 5px; background-color:#fff',
 			resizable: false,
 			modal: true,
-			width: 450,
+			width: windowWidth,
 			items: [
 				{
 					xtype: 'panel',
@@ -1465,6 +1534,254 @@
 		return favoriteWindow;
 	};
 
+	PT.app.SharingWindow = function(sharing) {
+
+		// Objects
+		var UserGroupRow,
+
+		// Functions
+			getBody,
+
+		// Components
+			userGroupStore,
+			userGroupField,
+			userGroupButton,
+			userGroupRowContainer,
+			publicGroup,
+			window;
+
+		UserGroupRow = function(obj, isPublicAccess, disallowPublicAccess) {
+			var getData,
+				store,
+				getItems,
+				combo,
+				getAccess,
+				panel;
+
+			getData = function() {
+				var data = [
+					{id: 'r-------', name: 'Can view'}, //i18n
+					{id: 'rw------', name: 'Can edit and view'}
+				];
+
+				if (isPublicAccess) {
+					data.unshift({id: '-------', name: 'None'});
+				}
+
+				return data;
+			}
+
+			store = Ext.create('Ext.data.Store', {
+				fields: ['id', 'name'],
+				data: getData()
+			});
+
+			getItems = function() {
+				var items = [];
+
+				combo = Ext.create('Ext.form.field.ComboBox', {
+					fieldLabel: isPublicAccess ? 'Public access' : obj.name, //i18n
+					labelStyle: 'color:#333',
+					cls: 'pt-combo',
+					width: 380,
+					labelWidth: 250,
+					queryMode: 'local',
+					valueField: 'id',
+					displayField: 'name',
+					labelSeparator: null,
+					editable: false,
+					disabled: !!disallowPublicAccess,
+					value: obj.access,
+					store: store
+				});
+
+				items.push(combo);
+
+				if (!isPublicAccess) {
+					items.push(Ext.create('Ext.Img', {
+						src: 'images/grid-delete_16.png',
+						style: 'margin-top:2px; margin-left:7px',
+						overCls: 'pointer',
+						width: 16,
+						height: 16,
+						listeners: {
+							render: function(i) {
+								i.getEl().on('click', function(e) {
+									i.up('panel').destroy();
+									window.doLayout();
+								});
+							}
+						}
+					}));
+				}
+
+				return items;
+			};
+
+			getAccess = function() {
+				return {
+					id: obj.id,
+					name: obj.name,
+					access: combo.getValue()
+				};
+			};
+
+			panel = Ext.create('Ext.panel.Panel', {
+				layout: 'column',
+				bodyStyle: 'border:0 none',
+				getAccess: getAccess,
+				items: getItems()
+			});
+
+			return panel;
+		};
+
+		getBody = function() {
+			var body = {
+				object: {
+					id: sharing.object.id,
+					name: sharing.object.name,
+					publicAccess: publicGroup.down('combobox').getValue(),
+					user: {
+						id: pt.init.user.id,
+						name: pt.init.user.name
+					}
+				}
+			};
+
+			if (userGroupRowContainer.items.items.length > 1) {
+				body.object.userGroupAccesses = [];
+				for (var i = 1, item; i < userGroupRowContainer.items.items.length; i++) {
+					item = userGroupRowContainer.items.items[i];
+					body.object.userGroupAccesses.push(item.getAccess());
+				}
+			}
+
+			return body;
+		};
+
+		// Initialize
+		userGroupStore = Ext.create('Ext.data.Store', {
+			fields: ['id', 'name'],
+			proxy: {
+				type: 'ajax',
+				url: pt.baseUrl + '/api/sharing/search',
+				reader: {
+					type: 'json',
+					root: 'userGroups'
+				}
+			}
+		});
+
+		userGroupField = Ext.create('Ext.form.field.ComboBox', {
+			valueField: 'id',
+			displayField: 'name',
+			emptyText: 'Search for user groups', //i18n
+			queryParam: 'key',
+			queryDelay: 200,
+			minChars: 1,
+			hideTrigger: true,
+			fieldStyle: 'height:26px; padding-left:6px; border-radius:1px; font-size:11px',
+			style: 'margin-bottom:5px',
+			width: 380,
+			store: userGroupStore,
+			listeners: {
+				beforeselect: function(cb) { // beforeselect instead of select, fires regardless of currently selected item
+					userGroupButton.enable();
+				},
+				afterrender: function(cb) {
+					cb.inputEl.on('keyup', function() {
+						userGroupButton.disable();
+					});
+				}
+			}
+		});
+
+		userGroupButton = Ext.create('Ext.button.Button', {
+			text: '+',
+			style: 'margin-left:2px; padding-right:4px; padding-left:4px; border-radius:1px',
+			disabled: true,
+			height: 26,
+			handler: function(b) {
+				userGroupRowContainer.add(UserGroupRow({
+					id: userGroupField.getValue(),
+					name: userGroupField.getRawValue(),
+					access: 'r-------'
+				}));
+
+				userGroupField.clearValue();
+				b.disable();
+			}
+		});
+
+		userGroupRowContainer = Ext.create('Ext.container.Container', {
+			bodyStyle: 'border:0 none'
+		});
+
+		publicGroup = userGroupRowContainer.add(UserGroupRow({
+			id: sharing.object.id,
+			name: sharing.object.name,
+			access: sharing.object.publicAccess
+		}, true, !sharing.meta.allowPublicAccess));
+
+		if (Ext.isArray(sharing.object.userGroupAccesses)) {
+			for (var i = 0, userGroupRow; i < sharing.object.userGroupAccesses.length; i++) {
+				userGroupRow = UserGroupRow(sharing.object.userGroupAccesses[i]);
+				userGroupRowContainer.add(userGroupRow);
+			}
+		}
+
+		window = Ext.create('Ext.window.Window', {
+			title: 'Sharing settings',
+			bodyStyle: 'padding:8px 8px 3px; background-color:#fff',
+			width: 434,
+			resizable: false,
+			modal: true,
+			items: [
+				{
+					html: sharing.object.name,
+					bodyStyle: 'border:0 none; font-weight:bold; color:#333',
+					style: 'margin-bottom:8px'
+				},
+				{
+					xtype: 'container',
+					layout: 'column',
+					bodyStyle: 'border:0 none',
+					items: [
+						userGroupField,
+						userGroupButton
+					]
+				},
+				userGroupRowContainer
+			],
+			bbar: [
+				'->',
+				{
+					text: 'Save',
+					handler: function() {
+						Ext.Ajax.request({
+							url: pt.baseUrl + '/api/sharing?type=reportTable&id=' + sharing.object.id,
+							method: 'POST',
+							headers: {
+								'Content-Type': 'application/json'
+							},
+							params: Ext.encode(getBody())
+						});
+
+						window.destroy();
+					}
+				}
+			],
+			listeners: {
+				show: function(w) {
+					w.setPosition(w.getPosition()[0], 33);
+				}
+			}
+		});
+
+		return window;
+	};
+
 	PT.app.init.onInitialize = function(r) {
 		var createViewport;
 
@@ -3031,6 +3348,24 @@
 									window.location.href = pt.baseUrl + '/api/analytics.csv' + pt.paramString;
 								}
 							}
+						},
+						{
+							text: 'JSON',
+							iconCls: 'pt-menu-item-csv',
+							handler: function() {
+								if (pt.baseUrl && pt.paramString) {
+									window.open(pt.baseUrl + '/api/analytics.json' + pt.paramString);
+								}
+							}
+						},
+						{
+							text: 'XML',
+							iconCls: 'pt-menu-item-csv',
+							handler: function() {
+								if (pt.baseUrl && pt.paramString) {
+									window.open(pt.baseUrl + '/api/analytics.xml' + pt.paramString);
+								}
+							}
 						}
 					],
 					listeners: {
@@ -3223,6 +3558,7 @@
 				// Options
 				pt.viewport.showSubTotals.setValue(r.subtotals);
 				pt.viewport.hideEmptyRows.setValue(r.hideEmptyRows);
+				pt.viewport.numberFormatting.setValue(r.numberFormatting);
 				pt.viewport.displayDensity.setValue(r.displayDensity);
 				pt.viewport.fontSize.setValue(r.fontSize);
 

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js	2013-03-11 15:39:06 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js	2013-03-13 14:59:20 +0000
@@ -217,6 +217,10 @@
     };
 
 	conf.pivot = {
+		numberFormatting: {
+			'comma': ',',
+			'space': ' '
+		},
 		displayDensity: {
 			'compact': '3px',
 			'normal': '5px',
@@ -504,8 +508,14 @@
 			return x;
 		},
 
-		pp: function(x) {
-			return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, " ");
+		pp: function(x, nf) {
+			nf = nf || 'space';
+
+			if (nf === 'none') {
+				return x;
+			}
+
+			return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, pt.conf.pivot.numberFormatting[nf]);
 		}
 	};
 
@@ -1027,7 +1037,7 @@
 					colSpan = config.colSpan ? 'colspan="' + config.colSpan + '"' : '';
 					rowSpan = config.rowSpan ? 'rowspan="' + config.rowSpan + '"' : '';
 					htmlValue = config.collapsed ? '&nbsp;' : config.htmlValue || config.value || '&nbsp;';
-					htmlValue = config.type !== 'dimension' ? pt.util.number.pp(htmlValue) : htmlValue;
+					htmlValue = config.type !== 'dimension' ? pt.util.number.pp(htmlValue, options.numberFormatting) : htmlValue;
 					displayDensity = pt.conf.pivot.displayDensity[config.displayDensity] || pt.conf.pivot.displayDensity[options.displayDensity];
 					fontSize = pt.conf.pivot.fontSize[config.fontSize] || pt.conf.pivot.fontSize[options.fontSize];
 
@@ -1570,7 +1580,6 @@
 
 						if (!validateResponse(response)) {
 							pt.util.mask.hideMask();
-							console.log(response);
 							return;
 						}
 
@@ -1644,6 +1653,8 @@
 
 			defaultOptions = {
 				showSubTotals: true,
+				hideEmptyRows: false,
+				numberFormatting: 'space',
 				displayDensity: 'normal',
 				fontSize: 'normal'
 			};
@@ -1704,6 +1715,8 @@
 			}
 
 			options.showSubTotals = Ext.isDefined(options.showSubTotals) ? options.showSubTotals : defaultOptions.showSubTotals;
+			options.hideEmptyRows = Ext.isDefined(options.hideEmptyRows) ? options.hideEmptyRows : defaultOptions.hideEmptyRows;
+			options.numberFormatting = Ext.isDefined(options.numberFormatting) ? options.numberFormatting : defaultOptions.numberFormatting;
 			options.displayDensity = options.displayDensity || defaultOptions.displayDensity;
 			options.fontSize = options.fontSize || defaultOptions.fontSize;
 

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js	2013-03-11 13:53:25 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/plugin.js	2013-03-12 13:44:27 +0000
@@ -15,6 +15,7 @@
 	options: {
 		showSubTotals: true,
 		hideEmptyRows: false,
+		numberFormatting: 'space',
 		displayDensity: 'normal',
 		fontSize: 'normal',
 		userOrganisationUnit: true,

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css	2013-03-08 11:00:41 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css	2013-03-13 11:59:50 +0000
@@ -83,6 +83,10 @@
 	position: fixed;
 }
 
+.pointer {
+	cursor: pointer;
+}
+
 .td-nobreak {
 	white-space: nowrap;
 }
@@ -539,6 +543,7 @@
 .pt-grid-row-icon-edit,
 .pt-grid-row-icon-overwrite,
 .pt-grid-row-icon-dashboard,
+.pt-grid-row-icon-sharing,
 .pt-grid-row-icon-delete {
 	width: 16px;
 	height: 16px;
@@ -555,6 +560,10 @@
 	background: url('../images/grid-dashboard_16.png') no-repeat;
 	margin-left: 4px;
 }
+.pt-grid-row-icon-sharing {
+	background: url('../images/grid-sharing_16.png') no-repeat;
+	margin-left: 4px;
+}
 .pt-grid-row-icon-delete {
 	background: url('../images/grid-delete_16.png') no-repeat;
 	margin-left: 4px;
@@ -568,7 +577,8 @@
 .pt-grid-row-icon-disabled * {
 	cursor: default !important;
 }
-.pt-grid-row-icon-disabled img.pt-grid-row-icon-dashboard {
+.pt-grid-row-icon-disabled img.pt-grid-row-icon-dashboard,
+.pt-grid-row-icon-disabled img.pt-grid-row-icon-sharing {
 	cursor: pointer !important;
 }
 

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm	2013-02-25 15:39:41 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm	2013-03-13 12:34:10 +0000
@@ -1,6 +1,6 @@
 #set($oucSize = $currentUser.getOrganisationUnit().getSortedChildren().size()){
 "contextPath":"$!{contextPath}",
-"user":{"id":"$!currentUser.id","isAdmin":true,
+"user":{"id":"$!currentUser.id","name":"$currentUser.name","isAdmin":true,
 "ou":{"id":"$currentUser.getOrganisationUnit().uid","name":"$currentUser.getOrganisationUnit().name"},
 "ouc":[#foreach($ou in $currentUser.getOrganisationUnit().getSortedChildren()){"id":"$ou.uid","name":"$ou.name"}#if($velocityCount < $oucSize),#end#end]},
 "rootNodes":[#foreach($node in $rootNodes){"id": "$!{node.uid}","text": "$!encoder.jsonEncode( ${node.name} )","level": 1,"hasChildrenWithCoordinates": $!{node.hasChildrenWithCoordinates()},"expanded": true}#if($velocityCount<$rootNodes.size()),#end#end],