1 /**
  2  * @author Gillis Haasnoot <gillis.haasnoot@gmail.com>
  3  * @package Banana.Controls
  4  * @summary Datagrid  
  5  */
  6 
  7 goog.provide('Banana.Controls.DataGrid');
  8 
  9 goog.require('Banana.Controls.DataGridTableListRender');
 10 goog.require('Banana.Controls.DataGridTileListRender');
 11 goog.require('Banana.Controls.DataGridTreeListRender');
 12 goog.require('Banana.Controls.DataGridDataTreeListRender');
 13 goog.require('Banana.Controls.DataGridControlPanel');
 14 
 15 goog.require('Banana.Controls.DataGridCheckboxFilter');
 16 goog.require('Banana.Controls.DataGridDropDownFilter');
 17 goog.require('Banana.Controls.DataGridSearchFilter');
 18 goog.require('Banana.Controls.DataGridPagerFilter');
 19 goog.require('Banana.Controls.DataGridDateFilter');
 20 
 21 /** @namespace Banana.Controls.DataGrid */
 22 namespace('Banana.Controls').DataGrid = Banana.Controls.ListControl.extend(
 23 /** @lends Banana.Controls.DataGrid.prototype */
 24 {
 25 	/**
 26 	 * Creates a datagrid 
 27 	 * A datagrid is a more advanced list control with functionality to have its own listrender. 
 28 	 * A listrender is responsible for rendering the list and is completely independent from the datagrid itself.
 29 	 * By default a datagrid is having a table list render .
 30 	 * A different listrender can replace the current listrender if desired at anytime.
 31 	 * Empty template can be assigned to a datagrid which is shown when there is no data inside the
 32 	 * datagrid.
 33 	 *  
 34 	 Example:
 35 	 
 36 	var datagrid = new Banana.Controls.DataGrid();
 37 
 38 	var columns = [
 39 		          	new Banana.Controls.DataGridColumn().setHeaderText('name').setDataField('name'),
 40 		          	new Banana.Controls.DataGridColumn().setHeaderText('description').setDataField('description')
 41 		          ];
 42 		          
 43 	datagrid.getListRender().setColumns(colums);
 44 	
 45 	var datasource = [
 46 	                 	{'name':'a name1','description':'a description1'},
 47 	                 	{'name':'a name2','description':'a description2'},
 48 	                 	{'name':'a name3','description':'a description3'}
 49 	                 ];
 50 	                 
 51 	datagrid.setDataSource(datasource);   
 52 	
 53 	this.addControl(datagrid);
 54 	 
 55 	 * 
 56 	 * @constructs
 57 	 * @extends Banana.Controls.ListControl
 58 	 */
 59 	init : function()
 60 	{
 61 		this._super();
 62 	
 63 		this.addCssClass('BDataGrid');
 64 		
 65 		this.datasource = [];
 66 		
 67 		this.listRender = null;
 68 		this.listRenderCreated = false;
 69 		
 70 		this.createBasicControls();
 71 	},
 72 	
 73 	/**
 74 	 * Internaly used
 75 	 * @ignore
 76 	 */
 77 	createComponents : function()
 78 	{
 79 		this.triggerEvent('datagridReady');
 80 	},
 81 	
 82 	/**
 83 	 * @ignore
 84 	 */
 85 	updateDisplay : function()
 86 	{
 87 		if (!this.listRenderCreated)
 88 		{
 89 			this.createEmptyTemplate();
 90 		}
 91 	},
 92 	
 93 	/**
 94 	 * @param {mixed} datasource to fill the datagrid with
 95 	 * @return {this}
 96 	 */
 97 	setDataSource : function(datasource)
 98 	{
 99 		this.datasource = datasource;
100 
101 		this.triggerEvent('onSetDataSource',datasource);
102 		return this;
103 	},
104 	
105 	/**
106 	 * setData method is equal to the setDataSource method. This method is used
107 	 * when datagrid is binded to data in a dataset.
108 	 * @param {mixed} data
109 	 * @return {this}
110 	 */
111 	setData : function(data)
112 	{
113 		this.setDataSource(data);
114 		return this;
115 	},
116 	
117 	/**
118 	 * equal to getDataSource
119 	 * @return {mixed}
120 	 */
121 	getData : function()
122 	{
123 		return this.datasource;
124 	},
125 	
126 	/**
127 	 * add a control panal above the datagrid.
128 	 * A control panel is used as a container for filters and other controls interacting
129 	 * with the datagrid.
130 	 * 
131 	 * @param {Banana.Controls.DataGridControlPanel} c 
132 	 * @return {this}
133 	 */
134 	setControlPanel : function(c)
135 	{
136 		if (!(c instanceof(Banana.Controls.DataGridControlPanel)))
137 		{
138 			return this;
139 		}
140 		
141 		this.controlPanelHolder.addControl(c);
142 		return this;
143 	},
144 	
145 	/**
146 	 * @return {Banana.Controls.DataGridControlPanel}
147 	 */
148 	getControlPanel : function()
149 	{
150 		return this.controlPanelHolder.controls[0];
151 	},
152 	
153 	/**
154 	 * An empty template is shown when no datasource or empty datasource is inside the datagrid.
155 	 * @param {Banana.Controls.UiControl} c
156 	 * @return {this} 
157 	 */
158 	setEmptyTemplate : function(c)
159 	{
160 		this.emptyTemplate = c;
161 		
162 		this.clearEmptyTemplate(); 
163 		this.createEmptyTemplate();
164 				
165 		return this;
166 	},
167 	
168 	/**
169 	 * Create building blocks which are needed to visualize our datagrid.
170 	 * From top to bottom we create a control panel holder, the list holder, info holder for the empty template
171 	 * and loader holder to show a loader.
172 	 * 
173 	 * @ignore
174 	 */
175 	createBasicControls : function()
176 	{
177 		this.controlPanelHolder = new Banana.Control();
178 		this.listHolder = new Banana.Controls.Panel();
179 		this.infoHolder = new Banana.Controls.Panel().addCssClass('BDataGridInfoHolder');
180 		this.loaderHolder = new Banana.Controls.Panel();
181 		
182 		this.addControl(this.loaderHolder);
183 		this.addControl(this.controlPanelHolder);
184 		this.addControl(this.listHolder);
185 		this.addControl(this.infoHolder);
186 	},
187 	
188 	/**
189 	 * Sets the list render responsible for rendering content.
190 	 * If changed during runtime we rerender the complete datagrid.
191 	 * 
192 	 * @param {Banana.Controls.Banana.Controls.DataGridBaseListRender} lr
193 	 * @return {this}
194 	 */
195 	setListRender : function(lr)
196 	{
197 		this.clearListRender();
198 				
199 		this.listRender = lr;
200 		this.listRender.datagrid = this;
201 		//force rerender if datasource is available
202 		if (this.datasource && this.datasource.length)
203 		{
204 			this.setDataSource(this.datasource);
205 		}
206 		
207 		return this;
208 	},
209 	
210 	/**
211 	 * returns current active list render. If none is active we return a default table list render
212 	 * @return {Banana.Controls.DataGridBaseListRender} listRender
213 	 */
214 	getListRender : function()
215 	{
216 		if (!this.listRender)
217 		{
218 			this.listRender = new Banana.Controls.DataGridTableListRender();
219 		}
220 		
221 		return this.listRender;
222 	},
223 	
224 	/**
225 	 * Clears the list render.
226 	 * @return {this} 
227 	 */
228 	clearListRender : function()
229 	{
230 		this.listHolder.clear();
231 		return this;
232 	},
233 	
234 	/**
235 	 * Create the listRender
236 	 * @ignore
237 	 */
238 	createListRender : function()
239 	{
240 		if (!this.listRender || !this.listRender.id)
241 		{
242 			this.listRender = this.getListRender();
243 		}
244 		
245 		//if list holder is not already added to its placeholder 
246 		if (this.listHolder.controls.indexOf(this.listRender) === -1)
247 		{
248 			this.listHolder.addControl(this.listRender);
249 			this.listRender.datagrid = this;
250 			this.listRenderCreated = true;
251 					
252 			//bind event. if source is 0 we create empty template, otherwise remove it
253 			this.listRender.bind('dataSourceChanged',this.getProxy(function(e,f){
254 
255 				this.datasource = this.listRender.datasource; //synchronize datasources
256 
257 				///if already cleared and datasource is bigger than zero
258 				if (this.emptyTemplateCleared && this.datasource.length)
259 				{
260 					return;
261 				}
262 				
263 				this.emptyTemplateCleared = false;
264 				
265 				if (this.datasource.length)
266 				{
267 					this.clearEmptyTemplate();
268 					this.emptyTemplateCleared = true;
269 				}
270 				else
271 				{
272 					this.createEmptyTemplate();
273 				}
274 			}));
275 		}
276 	},
277 	
278 	/**
279 	 * Invoked when datasource is set
280 	 * we start the creation of controls here
281 	 * @ignore
282 	 */
283 	onSetDataSource : function()
284 	{
285 		if (!this.datasource)
286 		{
287 			this.datasource = [];
288 		}
289 		//datasource needs to be a indexed array
290 		if (!this.datasource.length)
291 		{	
292 			this.createEmptyTemplate();
293 		}
294 		else
295 		{
296 			this.infoHolder.setVisible(false);
297 		}
298 
299 		if (this.listRender)
300 		{
301 			this.listRender.clear();	
302 		}
303 
304 		this.createListRender();
305 		
306 		this.listRender.setDataSource(this.datasource);
307 		
308 		if (this.isRendered) 
309 		{
310 			this.listHolder.invalidateDisplay();
311 		}
312 	},
313 
314 	/**
315 	 * @abstract
316 	 * @ignore
317 	 */
318 	showInitLoader : function(){},
319 	
320 	/**
321 	 * @abstract
322 	 * @ignore
323 	 */
324 	renderList : function(){},
325 	
326 	/**
327 	 * @abstract
328 	 * @ignore
329 	 */
330 	showLoader : function(){},
331 	
332 	/**
333 	 * creates an empty template. 
334 	 * 
335 	 * @ignore
336 	 */
337 	createEmptyTemplate : function()
338 	{
339 		this.infoHolder.clear();
340 		
341 		if (this.emptyTemplate)
342 		{
343 			this.infoHolder.addControl(this.emptyTemplate(),true).setVisible(true);
344 		}
345 		else
346 		{
347 			this.infoHolder.addControl('No data found',true).setVisible(true);
348 		}
349 	},
350 	
351 	/**
352 	 * clears the empty template.
353 	 * @return {this}
354 	 */
355 	clearEmptyTemplate : function()
356 	{
357 		this.infoHolder.clear();
358 		return this;
359 	}
360 });