Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TDataGridColumn class file
4
 *
5
 * @author Qiang Xue <qiang.xue@gmail.com>
6
 * @link http://www.pradosoft.com/
7
 * @copyright Copyright &copy; 2005-2008 PradoSoft
8
 * @license http://www.pradosoft.com/license/
9
 * @version $Id: TDataGridColumn.php 2541 2008-10-21 15:05:13Z qiang.xue $
10
 * @package System.Web.UI.WebControls
11
 */
12
 
13
Prado::using('System.Util.TDataFieldAccessor');
14
Prado::using('System.Web.UI.WebControls.TDataGrid');
15
 
16
/**
17
 * TDataGridColumn class
18
 *
19
 * TDataGridColumn serves as the base class for the different column types of
20
 * the {@link TDataGrid} control.
21
 * TDataGridColumn defines the properties and methods that are common among
22
 * all datagrid column types. In particular, it initializes header and footer
23
 * cells according to {@link setHeaderText HeaderText} and {@link getHeaderStyle HeaderStyle}
24
 * {@link setFooterText FooterText} and {@link getFooterStyle FooterStyle} properties.
25
 * If {@link setHeaderImageUrl HeaderImageUrl} is specified, the image
26
 * will be displayed instead in the header cell.
27
 * The {@link getItemStyle ItemStyle} is applied to cells that belong to
28
 * non-header and -footer datagrid items.
29
 *
30
 * When the datagrid enables sorting, if the {@link setSortExpression SortExpression}
31
 * is not empty, the header cell will display a button (linkbutton or imagebutton)
32
 * that will bubble the sort command event to the datagrid.
33
 *
34
 * Since v3.1.0, TDataGridColumn has introduced two new properties {@link setHeaderRenderer HeaderRenderer}
35
 * and {@link setFooterRenderer FooterRenderer} which can be used to specify
36
 * the layout of header and footer column cells.
37
 * A renderer refers to a control class that is to be instantiated as a control.
38
 * For more details, see {@link TRepeater} and {@link TDataList}.
39
 *
40
 * Since v3.1.1, TDataGridColumn has introduced {@link setEnableCellGrouping EnableCellGrouping}.
41
 * If a column has this property set true, consecutive cells having the same content in this
42
 * column will be grouped into one cell.
43
 * Note, there are some limitations to cell grouping. We determine the cell content according to
44
 * the cell's {@link TTableCell::getText Text} property. If the text is empty and the cell has
45
 * some child controls, we will pick up the first control who implements {@link IDataRenderer}
46
 * and obtain its {@link IDataRenderer::getData Data} property.
47
 *
48
 * The following datagrid column types are provided by the framework currently,
49
 * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
50
 * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
51
 * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
52
 * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
53
 * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
54
 * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
55
 * - {@link TTemplateColumn}, displaying content based on templates.
56
 *
57
 * To create your own column class, simply override {@link initializeCell()} method,
58
 * which is the major logic for managing the data and presentation of cells in the column.
59
 *
60
 * @author Qiang Xue <qiang.xue@gmail.com>
61
 * @version $Id: TDataGridColumn.php 2541 2008-10-21 15:05:13Z qiang.xue $
62
 * @package System.Web.UI.WebControls
63
 * @since 3.0
64
 */
65
abstract class TDataGridColumn extends TApplicationComponent
66
{
67
	private $_id='';
68
	private $_owner=null;
69
	private $_viewState=array();
70
 
71
	/**
72
	 * @return string the ID of the column.
73
	 */
74
	public function getID()
75
	{
76
		return $this->_id;
77
	}
78
 
79
	/**
80
	 * Sets the ID of the column.
81
	 * By explicitly specifying the column ID, one can access the column
82
	 * by $templateControl->ColumnID.
83
	 * @param string the ID of the column.
84
	 * @throws TInvalidDataValueException if the ID is of bad format
85
	 */
86
	public function setID($value)
87
	{
88
		if(!preg_match(TControl::ID_FORMAT,$value))
89
			throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
90
		$this->_id=$value;
91
	}
92
 
93
	/**
94
	 * @return string the text to be displayed in the header of this column
95
	 */
96
	public function getHeaderText()
97
	{
98
		return $this->getViewState('HeaderText','');
99
	}
100
 
101
	/**
102
	 * @param string text to be displayed in the header of this column
103
	 */
104
	public function setHeaderText($value)
105
	{
106
		$this->setViewState('HeaderText',$value,'');
107
	}
108
 
109
	/**
110
	 * @return string the url of the image to be displayed in header
111
	 */
112
	public function getHeaderImageUrl()
113
	{
114
		return $this->getViewState('HeaderImageUrl','');
115
	}
116
 
117
	/**
118
	 * @param string the url of the image to be displayed in header
119
	 */
120
	public function setHeaderImageUrl($value)
121
	{
122
		$this->setViewState('HeaderImageUrl',$value,'');
123
	}
124
 
125
	/**
126
	 * @return string the class name for the column header cell renderer. Defaults to empty, meaning not set.
127
	 * @since 3.1.0
128
	 */
129
	public function getHeaderRenderer()
130
	{
131
		return $this->getViewState('HeaderRenderer','');
132
	}
133
 
134
	/**
135
	 * Sets the column header cell renderer class.
136
	 *
137
	 * If not empty, the class will be used to instantiate as a child control in the column header cell.
138
	 * If the class implements {@link IDataRenderer}, the <b>Data</b> property
139
	 * will be set as the {@link getFooterText FooterText}.
140
	 *
141
	 * @param string the renderer class name in namespace format.
142
	 * @since 3.1.0
143
	 */
144
	public function setHeaderRenderer($value)
145
	{
146
		$this->setViewState('HeaderRenderer',$value,'');
147
	}
148
 
149
	/**
150
	 * @param boolean whether to create a style if previously not existing
151
	 * @return TTableItemStyle the style for header
152
	 */
153
	public function getHeaderStyle($createStyle=true)
154
	{
155
		if(($style=$this->getViewState('HeaderStyle',null))===null && $createStyle)
156
		{
157
			$style=new TTableItemStyle;
158
			$this->setViewState('HeaderStyle',$style,null);
159
		}
160
		return $style;
161
	}
162
 
163
	/**
164
	 * @return string the text to be displayed in the footer of this column
165
	 */
166
	public function getFooterText()
167
	{
168
		return $this->getViewState('FooterText','');
169
	}
170
 
171
	/**
172
	 * @param string text to be displayed in the footer of this column
173
	 */
174
	public function setFooterText($value)
175
	{
176
		$this->setViewState('FooterText',$value,'');
177
	}
178
 
179
	/**
180
	 * @return string the class name for the column footer cell renderer. Defaults to empty, meaning not set.
181
	 * @since 3.1.0
182
	 */
183
	public function getFooterRenderer()
184
	{
185
		return $this->getViewState('FooterRenderer','');
186
	}
187
 
188
	/**
189
	 * Sets the column footer cell renderer class.
190
	 *
191
	 * If not empty, the class will be used to instantiate as a child control in the column footer cell.
192
	 * If the class implements {@link IDataRenderer}, the <b>Data</b> property
193
	 * will be set as the {@link getFooterText FooterText}.
194
	 *
195
	 * @param string the renderer class name in namespace format.
196
	 * @since 3.1.0
197
	 */
198
	public function setFooterRenderer($value)
199
	{
200
		$this->setViewState('FooterRenderer',$value,'');
201
	}
202
 
203
	/**
204
	 * @param boolean whether to create a style if previously not existing
205
	 * @return TTableItemStyle the style for footer
206
	 */
207
	public function getFooterStyle($createStyle=true)
208
	{
209
		if(($style=$this->getViewState('FooterStyle',null))===null && $createStyle)
210
		{
211
			$style=new TTableItemStyle;
212
			$this->setViewState('FooterStyle',$style,null);
213
		}
214
		return $style;
215
	}
216
 
217
	/**
218
	 * @param boolean whether to create a style if previously not existing
219
	 * @return TTableItemStyle the style for item
220
	 */
221
	public function getItemStyle($createStyle=true)
222
	{
223
		if(($style=$this->getViewState('ItemStyle',null))===null && $createStyle)
224
		{
225
			$style=new TTableItemStyle;
226
			$this->setViewState('ItemStyle',$style,null);
227
		}
228
		return $style;
229
	}
230
 
231
	/**
232
	 * @return string the name of the field or expression for sorting
233
	 */
234
	public function getSortExpression()
235
	{
236
		return $this->getViewState('SortExpression','');
237
	}
238
 
239
	/**
240
	 * @param string the name of the field or expression for sorting
241
	 */
242
	public function setSortExpression($value)
243
	{
244
		$this->setViewState('SortExpression',$value,'');
245
	}
246
 
247
	/**
248
	 * @return boolean whether cells having the same content should be grouped together. Defaults to false.
249
	 * @since 3.1.1
250
	 */
251
	public function getEnableCellGrouping()
252
	{
253
		return $this->getViewState('EnableCellGrouping',false);
254
	}
255
 
256
	/**
257
	 * @param boolean whether cells having the same content should be grouped together.
258
	 * @since 3.1.1
259
	 */
260
	public function setEnableCellGrouping($value)
261
	{
262
		$this->setViewState('EnableCellGrouping',TPropertyValue::ensureBoolean($value),false);
263
	}
264
 
265
	/**
266
	 * @return boolean whether the column is visible. Defaults to true.
267
	 */
268
	public function getVisible($checkParents=true)
269
	{
270
		return $this->getViewState('Visible',true);
271
	}
272
 
273
	/**
274
	 * @param boolean whether the column is visible
275
	 */
276
	public function setVisible($value)
277
	{
278
		$this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true);
279
	}
280
 
281
	/**
282
	 * Returns a viewstate value.
283
	 *
284
	 * @param string the name of the viewstate value to be returned
285
	 * @param mixed the default value. If $key is not found in viewstate, $defaultValue will be returned
286
	 * @return mixed the viewstate value corresponding to $key
287
	 */
288
	protected function getViewState($key,$defaultValue=null)
289
	{
290
		return isset($this->_viewState[$key])?$this->_viewState[$key]:$defaultValue;
291
	}
292
 
293
	/**
294
	 * Sets a viewstate value.
295
	 *
296
	 * Make sure that the viewstate value must be serializable and unserializable.
297
	 * @param string the name of the viewstate value
298
	 * @param mixed the viewstate value to be set
299
	 * @param mixed default value. If $value===$defaultValue, the item will be cleared from the viewstate.
300
	 */
301
	protected function setViewState($key,$value,$defaultValue=null)
302
	{
303
		if($value===$defaultValue)
304
			unset($this->_viewState[$key]);
305
		else
306
			$this->_viewState[$key]=$value;
307
	}
308
 
309
	/**
310
	 * Loads persistent state values.
311
	 * @param mixed state values
312
	 */
313
	public function loadState($state)
314
	{
315
		$this->_viewState=$state;
316
	}
317
 
318
	/**
319
	 * Saves persistent state values.
320
	 * @return mixed values to be saved
321
	 */
322
	public function saveState()
323
	{
324
		return $this->_viewState;
325
	}
326
 
327
	/**
328
	 * @return TDataGrid datagrid that owns this column
329
	 */
330
	public function getOwner()
331
	{
332
		return $this->_owner;
333
	}
334
 
335
	/**
336
	 * @param TDataGrid datagrid object that owns this column
337
	 */
338
	public function setOwner(TDataGrid $value)
339
	{
340
		$this->_owner=$value;
341
	}
342
 
343
	/**
344
	 * Initializes the column.
345
	 * This method is invoked by {@link TDataGrid} when the column
346
	 * is about to be used to initialize datagrid items.
347
	 * Derived classes may override this method to do additional initialization.
348
	 */
349
	public function initialize()
350
	{
351
	}
352
 
353
	/**
354
	 * Fetches the value of the data at the specified field.
355
	 * If the data is an array, the field is used as an array key.
356
	 * If the data is an of {@link TMap}, {@link TList} or their derived class,
357
	 * the field is used as a key value.
358
	 * If the data is a component, the field is used as the name of a property.
359
	 * @param mixed data containing the field of value
360
	 * @param string the data field
361
	 * @return mixed data value at the specified field
362
	 * @throws TInvalidDataValueException if the data or the field is invalid.
363
	 */
364
	protected function getDataFieldValue($data,$field)
365
	{
366
		return TDataFieldAccessor::getDataFieldValue($data,$field);
367
	}
368
 
369
 
370
	/**
371
	 * Initializes the specified cell to its initial values.
372
	 * The default implementation sets the content of header and footer cells.
373
	 * If sorting is enabled by the grid and sort expression is specified in the column,
374
	 * the header cell will show a link/image button. Otherwise, the header/footer cell
375
	 * will only show static text/image.
376
	 * This method can be overriden to provide customized intialization to column cells.
377
	 * @param TTableCell the cell to be initialized.
378
	 * @param integer the index to the Columns property that the cell resides in.
379
	 * @param string the type of cell (Header,Footer,Item,AlternatingItem,EditItem,SelectedItem)
380
	 */
381
	public function initializeCell($cell,$columnIndex,$itemType)
382
	{
383
		if($itemType===TListItemType::Header)
384
			$this->initializeHeaderCell($cell,$columnIndex);
385
		else if($itemType===TListItemType::Footer)
386
			$this->initializeFooterCell($cell,$columnIndex);
387
	}
388
 
389
	/**
390
	 * Returns a value indicating whether this column allows sorting.
391
	 * The column allows sorting only when {@link getSortExpression SortExpression}
392
	 * is not empty and the datagrid allows sorting.
393
	 * @return boolean whether this column allows sorting
394
	 */
395
	public function getAllowSorting()
396
	{
397
		return $this->getSortExpression()!=='' && (!$this->_owner || $this->_owner->getAllowSorting());
398
	}
399
 
400
	/**
401
	 * Initializes the header cell.
402
	 *
403
	 * This method attempts to use {@link getHeaderRenderer HeaderRenderer} to
404
	 * instantiate the header cell. If that is not available, it will populate
405
	 * the cell with an image or a text string, depending on {@link getHeaderImageUrl HeaderImageUrl}
406
	 * and {@link getHeaderText HeaderText} property values.
407
	 *
408
	 * If the column allows sorting, image or text will be created as
409
	 * a button which issues <b>Sort</b> command upon user click.
410
	 *
411
	 * @param TTableCell the cell to be initialized
412
	 * @param integer the index to the Columns property that the cell resides in.
413
	 */
414
	protected function initializeHeaderCell($cell,$columnIndex)
415
	{
416
		$text=$this->getHeaderText();
417
 
418
		if(($classPath=$this->getHeaderRenderer())!=='')
419
		{
420
			$control=Prado::createComponent($classPath);
421
			if($control instanceof IDataRenderer)
422
			{
423
				if($control instanceof IItemDataRenderer)
424
				{
425
					$item=$cell->getParent();
426
					$control->setItemIndex($item->getItemIndex());
427
					$control->setItemType($item->getItemType());
428
				}
429
				$control->setData($text);
430
			}
431
			$cell->getControls()->add($control);
432
		}
433
		else if($this->getAllowSorting())
434
		{
435
			$sortExpression=$this->getSortExpression();
436
			if(($url=$this->getHeaderImageUrl())!=='')
437
			{
438
				$button=Prado::createComponent('System.Web.UI.WebControls.TImageButton');
439
				$button->setImageUrl($url);
440
				$button->setCommandName(TDataGrid::CMD_SORT);
441
				$button->setCommandParameter($sortExpression);
442
				if($text!=='')
443
					$button->setAlternateText($text);
444
				$button->setCausesValidation(false);
445
				$cell->getControls()->add($button);
446
			}
447
			else if($text!=='')
448
			{
449
				$button=Prado::createComponent('System.Web.UI.WebControls.TLinkButton');
450
				$button->setText($text);
451
				$button->setCommandName(TDataGrid::CMD_SORT);
452
				$button->setCommandParameter($sortExpression);
453
				$button->setCausesValidation(false);
454
				$cell->getControls()->add($button);
455
			}
456
			else
457
				$cell->setText('&nbsp;');
458
		}
459
		else
460
		{
461
			if(($url=$this->getHeaderImageUrl())!=='')
462
			{
463
				$image=Prado::createComponent('System.Web.UI.WebControls.TImage');
464
				$image->setImageUrl($url);
465
				if($text!=='')
466
					$image->setAlternateText($text);
467
				$cell->getControls()->add($image);
468
			}
469
			else if($text!=='')
470
				$cell->setText($text);
471
			else
472
				$cell->setText('&nbsp;');
473
		}
474
	}
475
 
476
	/**
477
	 * Initializes the footer cell.
478
	 *
479
	 * This method attempts to use {@link getFooterRenderer FooterRenderer} to
480
	 * instantiate the footer cell. If that is not available, it will populate
481
	 * the cell with a text string specified by {@link getFooterImageUrl FooterImageUrl}
482
	 *
483
	 * @param TTableCell the cell to be initialized
484
	 * @param integer the index to the Columns property that the cell resides in.
485
	 */
486
	protected function initializeFooterCell($cell,$columnIndex)
487
	{
488
		$text=$this->getFooterText();
489
		if(($classPath=$this->getFooterRenderer())!=='')
490
		{
491
			$control=Prado::createComponent($classPath);
492
			if($control instanceof IDataRenderer)
493
			{
494
				if($control instanceof IItemDataRenderer)
495
				{
496
					$item=$cell->getParent();
497
					$control->setItemIndex($item->getItemIndex());
498
					$control->setItemType($item->getItemType());
499
				}
500
				$control->setData($text);
501
			}
502
			$cell->getControls()->add($control);
503
		}
504
		else if($text!=='')
505
			$cell->setText($text);
506
		else
507
			$cell->setText('&nbsp;');
508
	}
509
 
510
	/**
511
	 * Formats the text value according to a format string.
512
	 * If the format string is empty, the original value is converted into
513
	 * a string and returned.
514
	 * If the format string starts with '#', the string is treated as a PHP expression
515
	 * within which the token '{0}' is translated with the data value to be formated.
516
	 * Otherwise, the format string and the data value are passed
517
	 * as the first and second parameters in {@link sprintf}.
518
	 * @param string format string
519
	 * @param mixed the data to be formatted
520
	 * @return string the formatted result
521
	 */
522
	protected function formatDataValue($formatString,$value)
523
	{
524
		if($formatString==='')
525
			return TPropertyValue::ensureString($value);
526
		else if($formatString[0]==='#')
527
		{
528
			$expression=strtr(substr($formatString,1),array('{0}'=>'$value'));
529
			try
530
			{
531
				if(eval("\$result=$expression;")===false)
532
					throw new Exception('');
533
				return $result;
534
			}
535
			catch(Exception $e)
536
			{
537
				throw new TInvalidDataValueException('datagridcolumn_expression_invalid',get_class($this),$expression,$e->getMessage());
538
			}
539
		}
540
		else
541
			return sprintf($formatString,$value);
542
	}
543
}
544
 
545
 
546
/**
547
 * TButtonColumnType class.
548
 * TButtonColumnType defines the enumerable type for the possible types of buttons
549
 * that can be used in a {@link TButtonColumn}.
550
 *
551
 * The following enumerable values are defined:
552
 * - LinkButton: link buttons
553
 * - PushButton: form buttons
554
 * - ImageButton: image buttons
555
 *
556
 * @author Qiang Xue <qiang.xue@gmail.com>
557
 * @version $Id: TDataGridColumn.php 2541 2008-10-21 15:05:13Z qiang.xue $
558
 * @package System.Web.UI.WebControls
559
 * @since 3.0.4
560
 */
561
class TButtonColumnType extends TEnumerable
562
{
563
	const LinkButton='LinkButton';
564
	const PushButton='PushButton';
565
	const ImageButton='ImageButton';
566
}
567