Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TDataGrid related class files.
4
 * This file contains the definition of the following classes:
5
 * TDataGrid, TDataGridItem, TDataGridItemCollection, TDataGridColumnCollection,
6
 * TDataGridPagerStyle, TDataGridItemEventParameter,
7
 * TDataGridCommandEventParameter, TDataGridSortCommandEventParameter,
8
 * TDataGridPageChangedEventParameter
9
 *
10
 * @author Qiang Xue <qiang.xue@gmail.com>
11
 * @link http://www.pradosoft.com/
12
 * @copyright Copyright &copy; 2005-2008 PradoSoft
13
 * @license http://www.pradosoft.com/license/
14
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
15
 * @package System.Web.UI.WebControls
16
 */
17
 
18
/**
19
 * Includes TBaseList, TPagedDataSource, TDummyDataSource and TTable classes
20
 */
21
Prado::using('System.Web.UI.WebControls.TBaseDataList');
22
Prado::using('System.Collections.TPagedDataSource');
23
Prado::using('System.Collections.TDummyDataSource');
24
Prado::using('System.Web.UI.WebControls.TTable');
25
Prado::using('System.Web.UI.WebControls.TPanel');
26
Prado::using('System.Web.UI.WebControls.TDataGridPagerStyle');
27
 
28
/**
29
 * TDataGrid class
30
 *
31
 * TDataGrid represents a data bound and updatable grid control.
32
 *
33
 * To populate data into the datagrid, sets its {@link setDataSource DataSource}
34
 * to a tabular data source and call {@link dataBind()}.
35
 * Each row of data will be represented by an item in the {@link getItems Items}
36
 * collection of the datagrid.
37
 *
38
 * An item can be at one of three states: browsing, selected and edit.
39
 * The state determines how the item will be displayed. For example, if an item
40
 * is in edit state, it may be displayed as a table row with input text boxes
41
 * if the columns are of type {@link TBoundColumn}; and if in browsing state,
42
 * they are displayed as static text.
43
 *
44
 * To change the state of an item, set {@link setEditItemIndex EditItemIndex}
45
 * or {@link setSelectedItemIndex SelectedItemIndex} property.
46
 *
47
 * Each datagrid item has a {@link TDataGridItem::getItemType type}
48
 * which tells the position and state of the item in the datalist. An item in the header
49
 * of the repeater is of type Header. A body item may be of either
50
 * Item, AlternatingItem, SelectedItem or EditItem, depending whether the item
51
 * index is odd or even, whether it is being selected or edited.
52
 *
53
 * A datagrid is specified with a list of columns. Each column specifies how the corresponding
54
 * table column will be displayed. For example, the header/footer text of that column,
55
 * the cells in that column, and so on. The following column types are currently
56
 * provided by the framework,
57
 * - {@link TBoundColumn}, associated with a specific field in datasource and displays the corresponding data.
58
 * - {@link TEditCommandColumn}, displaying edit/update/cancel command buttons
59
 * - {@link TButtonColumn}, displaying generic command buttons that may be bound to specific field in datasource.
60
 * - {@link TDropDownListColumn}, displaying a dropdown list when the item is in edit state
61
 * - {@link THyperLinkColumn}, displaying a hyperlink that may be bound to specific field in datasource.
62
 * - {@link TCheckBoxColumn}, displaying a checkbox that may be bound to specific field in datasource.
63
 * - {@link TTemplateColumn}, displaying content based on templates.
64
 *
65
 * There are three ways to specify columns for a datagrid.
66
 * <ul>
67
 *  <li>Automatically generated based on data source.
68
 *  By setting {@link setAutoGenerateColumns AutoGenerateColumns} to true,
69
 *  a list of columns will be automatically generated based on the schema of the data source.
70
 *  Each column corresponds to a column of the data.</li>
71
 *  <li>Specified in template. For example,
72
 *    <code>
73
 *     <com:TDataGrid ...>
74
 *        <com:TBoundColumn .../>
75
 *        <com:TEditCommandColumn .../>
76
 *     </com:TDataGrid>
77
 *    </code>
78
 *  </li>
79
 *  <li>Manually created in code. Columns can be manipulated via
80
 *  the {@link setColumns Columns} property of the datagrid. For example,
81
 *  <code>
82
 *    $column=new TBoundColumn;
83
 *    $datagrid->Columns[]=$column;
84
 *  </code>
85
 *  </li>
86
 * </ul>
87
 * Note, automatically generated columns cannot be accessed via
88
 * the {@link getColumns Columns} property.
89
 *
90
 * TDataGrid supports sorting. If the {@link setAllowSorting AllowSorting}
91
 * is set to true, a column with nonempty {@link setSortExpression SortExpression}
92
 * will have its header text displayed as a clickable link button.
93
 * Clicking on the link button will raise {@link onSortCommand OnSortCommand}
94
 * event. You can respond to this event, sort the data source according
95
 * to the event parameter, and then invoke {@link databind()} on the datagrid
96
 * to show to end users the sorted data.
97
 *
98
 * TDataGrid supports paging. If the {@link setAllowPaging AllowPaging}
99
 * is set to true, a pager will be displayed on top and/or bottom of the table.
100
 * How the pager will be displayed is determined by the {@link getPagerStyle PagerStyle}
101
 * property. Clicking on a pager button will raise an {@link onPageIndexChanged OnPageIndexChanged}
102
 * event. You can respond to this event, specify the page to be displayed by
103
 * setting {@link setCurrentPageIndex CurrentPageIndex}</b> property,
104
 * and then invoke {@link databind()} on the datagrid to show to end users
105
 * a new page of data.
106
 *
107
 * TDataGrid supports two kinds of paging. The first one is based on the number of data items in
108
 * datasource. The number of pages {@link getPageCount PageCount} is calculated based
109
 * the item number and the {@link setPageSize PageSize} property.
110
 * The datagrid will manage which section of the data source to be displayed
111
 * based on the {@link setCurrentPageIndex CurrentPageIndex} property.
112
 * The second approach calculates the page number based on the
113
 * {@link setVirtualItemCount VirtualItemCount} property and
114
 * the {@link setPageSize PageSize} property. The datagrid will always
115
 * display from the beginning of the datasource up to the number of
116
 * {@link setPageSize PageSize} data items. This approach is especially
117
 * useful when the datasource may contain too many data items to be managed by
118
 * the datagrid efficiently.
119
 *
120
 * When the datagrid contains a button control that raises an {@link onCommand OnCommand}
121
 * event, the event will be bubbled up to the datagrid control.
122
 * If the event's command name is recognizable by the datagrid control,
123
 * a corresponding item event will be raised. The following item events will be
124
 * raised upon a specific command:
125
 * - OnEditCommand, if CommandName=edit
126
 * - OnCancelCommand, if CommandName=cancel
127
 * - OnSelectCommand, if CommandName=select
128
 * - OnDeleteCommand, if CommandName=delete
129
 * - OnUpdateCommand, if CommandName=update
130
 * - onPageIndexChanged, if CommandName=page
131
 * - OnSortCommand, if CommandName=sort
132
 * Note, an {@link onItemCommand OnItemCommand} event is raised in addition to
133
 * the above specific command events.
134
 *
135
 * TDataGrid also raises an {@link onItemCreated OnItemCreated} event for
136
 * every newly created datagrid item. You can respond to this event to customize
137
 * the content or style of the newly created item.
138
 *
139
 * Note, the data bound to the datagrid are reset to null after databinding.
140
 * There are several ways to access the data associated with a datagrid row:
141
 * - Access the data in {@link onItemDataBound OnItemDataBound} event
142
 * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
143
 * the specified datagrid row and use the key to fetch the corresponding data
144
 * from some persistent storage such as DB.
145
 * - Save the data in viewstate and get it back during postbacks.
146
 *
147
 * @author Qiang Xue <qiang.xue@gmail.com>
148
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
149
 * @package System.Web.UI.WebControls
150
 * @since 3.0
151
 */
152
class TDataGrid extends TBaseDataList implements INamingContainer
153
{
154
	/**
155
	 * datagrid item types
156
	 * @deprecated deprecated since version 3.0.4. Use TListItemType constants instead.
157
	 */
158
	const IT_HEADER='Header';
159
	const IT_FOOTER='Footer';
160
	const IT_ITEM='Item';
161
	const IT_SEPARATOR='Separator';
162
	const IT_ALTERNATINGITEM='AlternatingItem';
163
	const IT_EDITITEM='EditItem';
164
	const IT_SELECTEDITEM='SelectedItem';
165
	const IT_PAGER='Pager';
166
 
167
	/**
168
	 * Command name that TDataGrid understands.
169
	 */
170
	const CMD_SELECT='Select';
171
	const CMD_EDIT='Edit';
172
	const CMD_UPDATE='Update';
173
	const CMD_DELETE='Delete';
174
	const CMD_CANCEL='Cancel';
175
	const CMD_SORT='Sort';
176
	const CMD_PAGE='Page';
177
	const CMD_PAGE_NEXT='Next';
178
	const CMD_PAGE_PREV='Previous';
179
 
180
	/**
181
	 * @var TDataGridColumnCollection manually created column collection
182
	 */
183
	private $_columns=null;
184
	/**
185
	 * @var TDataGridColumnCollection automatically created column collection
186
	 */
187
	private $_autoColumns=null;
188
	/**
189
	 * @var TList all columns including both manually and automatically created columns
190
	 */
191
	private $_allColumns=null;
192
	/**
193
	 * @var TDataGridItemCollection datagrid item collection
194
	 */
195
	private $_items=null;
196
	/**
197
	 * @var TDataGridItem header item
198
	 */
199
	private $_header=null;
200
	/**
201
	 * @var TDataGridItem footer item
202
	 */
203
	private $_footer=null;
204
	/**
205
	 * @var TPagedDataSource paged data source object
206
	 */
207
	private $_pagedDataSource=null;
208
	private $_topPager=null;
209
	private $_bottomPager=null;
210
	/**
211
	 * @var ITemplate template used when empty data is bounded
212
	 */
213
	private $_emptyTemplate=null;
214
	/**
215
	 * @var boolean whether empty template is effective
216
	 */
217
	private $_useEmptyTemplate=false;
218
 
219
	/**
220
	 * @return string tag name (table) of the datagrid
221
	 */
222
	protected function getTagName()
223
	{
224
		return 'table';
225
	}
226
 
227
	/**
228
	 * Adds objects parsed in template to datagrid.
229
	 * Datagrid columns are added into {@link getColumns Columns} collection.
230
	 * @param mixed object parsed in template
231
	 */
232
	public function addParsedObject($object)
233
	{
234
		if($object instanceof TDataGridColumn)
235
			$this->getColumns()->add($object);
236
		else
237
			parent::addParsedObject($object);  // this is needed by EmptyTemplate
238
	}
239
 
240
	/**
241
	 * @return TDataGridColumnCollection manually specified datagrid columns
242
	 */
243
	public function getColumns()
244
	{
245
		if(!$this->_columns)
246
			$this->_columns=new TDataGridColumnCollection($this);
247
		return $this->_columns;
248
	}
249
 
250
	/**
251
	 * @return TDataGridColumnCollection automatically generated datagrid columns
252
	 */
253
	public function getAutoColumns()
254
	{
255
		if(!$this->_autoColumns)
256
			$this->_autoColumns=new TDataGridColumnCollection($this);
257
		return $this->_autoColumns;
258
	}
259
 
260
	/**
261
	 * @return TDataGridItemCollection datagrid item collection
262
	 */
263
	public function getItems()
264
	{
265
		if(!$this->_items)
266
			$this->_items=new TDataGridItemCollection;
267
		return $this->_items;
268
	}
269
 
270
	/**
271
	 * @return integer number of items
272
	 */
273
	public function getItemCount()
274
	{
275
		return $this->_items?$this->_items->getCount():0;
276
	}
277
 
278
	/**
279
	 * Creates a style object for the control.
280
	 * This method creates a {@link TTableStyle} to be used by datagrid.
281
	 * @return TTableStyle control style to be used
282
	 */
283
	protected function createStyle()
284
	{
285
		return new TTableStyle;
286
	}
287
 
288
	/**
289
	 * @return string the URL of the background image for the datagrid
290
	 */
291
	public function getBackImageUrl()
292
	{
293
		return $this->getStyle()->getBackImageUrl();
294
	}
295
 
296
	/**
297
	 * @param string the URL of the background image for the datagrid
298
	 */
299
	public function setBackImageUrl($value)
300
	{
301
		$this->getStyle()->setBackImageUrl($value);
302
	}
303
 
304
	/**
305
	 * @return TTableItemStyle the style for every item
306
	 */
307
	public function getItemStyle()
308
	{
309
		if(($style=$this->getViewState('ItemStyle',null))===null)
310
		{
311
			$style=new TTableItemStyle;
312
			$this->setViewState('ItemStyle',$style,null);
313
		}
314
		return $style;
315
	}
316
 
317
	/**
318
	 * @return TTableItemStyle the style for each alternating item
319
	 */
320
	public function getAlternatingItemStyle()
321
	{
322
		if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
323
		{
324
			$style=new TTableItemStyle;
325
			$this->setViewState('AlternatingItemStyle',$style,null);
326
		}
327
		return $style;
328
	}
329
 
330
	/**
331
	 * @return TTableItemStyle the style for selected item
332
	 */
333
	public function getSelectedItemStyle()
334
	{
335
		if(($style=$this->getViewState('SelectedItemStyle',null))===null)
336
		{
337
			$style=new TTableItemStyle;
338
			$this->setViewState('SelectedItemStyle',$style,null);
339
		}
340
		return $style;
341
	}
342
 
343
	/**
344
	 * @return TTableItemStyle the style for edit item
345
	 */
346
	public function getEditItemStyle()
347
	{
348
		if(($style=$this->getViewState('EditItemStyle',null))===null)
349
		{
350
			$style=new TTableItemStyle;
351
			$this->setViewState('EditItemStyle',$style,null);
352
		}
353
		return $style;
354
	}
355
 
356
	/**
357
	 * @return TTableItemStyle the style for header
358
	 */
359
	public function getHeaderStyle()
360
	{
361
		if(($style=$this->getViewState('HeaderStyle',null))===null)
362
		{
363
			$style=new TTableItemStyle;
364
			$this->setViewState('HeaderStyle',$style,null);
365
		}
366
		return $style;
367
	}
368
 
369
	/**
370
	 * @return TTableItemStyle the style for footer
371
	 */
372
	public function getFooterStyle()
373
	{
374
		if(($style=$this->getViewState('FooterStyle',null))===null)
375
		{
376
			$style=new TTableItemStyle;
377
			$this->setViewState('FooterStyle',$style,null);
378
		}
379
		return $style;
380
	}
381
 
382
	/**
383
	 * @return TDataGridPagerStyle the style for pager
384
	 */
385
	public function getPagerStyle()
386
	{
387
		if(($style=$this->getViewState('PagerStyle',null))===null)
388
		{
389
			$style=new TDataGridPagerStyle;
390
			$this->setViewState('PagerStyle',$style,null);
391
		}
392
		return $style;
393
	}
394
 
395
	/**
396
	 * @return TStyle the style for thead element, if any
397
	 * @since 3.1.1
398
	 */
399
	public function getTableHeadStyle()
400
	{
401
		if(($style=$this->getViewState('TableHeadStyle',null))===null)
402
		{
403
			$style=new TStyle;
404
			$this->setViewState('TableHeadStyle',$style,null);
405
		}
406
		return $style;
407
	}
408
 
409
	/**
410
	 * @return TStyle the style for tbody element, if any
411
	 * @since 3.1.1
412
	 */
413
	public function getTableBodyStyle()
414
	{
415
		if(($style=$this->getViewState('TableBodyStyle',null))===null)
416
		{
417
			$style=new TStyle;
418
			$this->setViewState('TableBodyStyle',$style,null);
419
		}
420
		return $style;
421
	}
422
 
423
	/**
424
	 * @return TStyle the style for tfoot element, if any
425
	 * @since 3.1.1
426
	 */
427
	public function getTableFootStyle()
428
	{
429
		if(($style=$this->getViewState('TableFootStyle',null))===null)
430
		{
431
			$style=new TStyle;
432
			$this->setViewState('TableFootStyle',$style,null);
433
		}
434
		return $style;
435
	}
436
 
437
	/**
438
	 * @return string caption for the datagrid
439
	 */
440
	public function getCaption()
441
	{
442
		return $this->getViewState('Caption','');
443
	}
444
 
445
	/**
446
	 * @param string caption for the datagrid
447
	 */
448
	public function setCaption($value)
449
	{
450
		$this->setViewState('Caption',$value,'');
451
	}
452
 
453
	/**
454
	 * @return TTableCaptionAlign datagrid caption alignment. Defaults to TTableCaptionAlign::NotSet.
455
	 */
456
	public function getCaptionAlign()
457
	{
458
		return $this->getViewState('CaptionAlign',TTableCaptionAlign::NotSet);
459
	}
460
 
461
	/**
462
	 * @param TTableCaptionAlign datagrid caption alignment. Valid values include
463
	 */
464
	public function setCaptionAlign($value)
465
	{
466
		$this->setViewState('CaptionAlign',TPropertyValue::ensureEnum($value,'TTableCaptionAlign'),TTableCaptionAlign::NotSet);
467
	}
468
 
469
	/**
470
	 * @return TDataGridItem the header item
471
	 */
472
	public function getHeader()
473
	{
474
		return $this->_header;
475
	}
476
 
477
	/**
478
	 * @return TDataGridItem the footer item
479
	 */
480
	public function getFooter()
481
	{
482
		return $this->_footer;
483
	}
484
 
485
	/**
486
	 * @return TDataGridPager the pager displayed at the top of datagrid. It could be null if paging is disabled.
487
	 */
488
	public function getTopPager()
489
	{
490
		return $this->_topPager;
491
	}
492
 
493
	/**
494
	 * @return TDataGridPager the pager displayed at the bottom of datagrid. It could be null if paging is disabled.
495
	 */
496
	public function getBottomPager()
497
	{
498
		return $this->_bottomPager;
499
	}
500
 
501
	/**
502
	 * @return TDataGridItem the selected item, null if no item is selected.
503
	 */
504
	public function getSelectedItem()
505
	{
506
		$index=$this->getSelectedItemIndex();
507
		$items=$this->getItems();
508
		if($index>=0 && $index<$items->getCount())
509
			return $items->itemAt($index);
510
		else
511
			return null;
512
	}
513
 
514
	/**
515
	 * @return integer the zero-based index of the selected item in {@link getItems Items}.
516
	 * A value -1 means no item selected.
517
	 */
518
	public function getSelectedItemIndex()
519
	{
520
		return $this->getViewState('SelectedItemIndex',-1);
521
	}
522
 
523
	/**
524
	 * Selects an item by its index in {@link getItems Items}.
525
	 * Previously selected item will be un-selected.
526
	 * If the item to be selected is already in edit mode, it will remain in edit mode.
527
	 * If the index is less than 0, any existing selection will be cleared up.
528
	 * @param integer the selected item index
529
	 */
530
	public function setSelectedItemIndex($value)
531
	{
532
		if(($value=TPropertyValue::ensureInteger($value))<0)
533
			$value=-1;
534
		if(($current=$this->getSelectedItemIndex())!==$value)
535
		{
536
			$this->setViewState('SelectedItemIndex',$value,-1);
537
			$items=$this->getItems();
538
			$itemCount=$items->getCount();
539
			if($current>=0 && $current<$itemCount)
540
			{
541
				$item=$items->itemAt($current);
542
				if($item->getItemType()!==TListItemType::EditItem)
543
					$item->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
544
			}
545
			if($value>=0 && $value<$itemCount)
546
			{
547
				$item=$items->itemAt($value);
548
				if($item->getItemType()!==TListItemType::EditItem)
549
					$item->setItemType(TListItemType::SelectedItem);
550
			}
551
		}
552
	}
553
 
554
	/**
555
	 * @return TDataGridItem the edit item
556
	 */
557
	public function getEditItem()
558
	{
559
		$index=$this->getEditItemIndex();
560
		$items=$this->getItems();
561
		if($index>=0 && $index<$items->getCount())
562
			return $items->itemAt($index);
563
		else
564
			return null;
565
	}
566
 
567
	/**
568
	 * @return integer the zero-based index of the edit item in {@link getItems Items}.
569
	 * A value -1 means no item is in edit mode.
570
	 */
571
	public function getEditItemIndex()
572
	{
573
		return $this->getViewState('EditItemIndex',-1);
574
	}
575
 
576
	/**
577
	 * Edits an item by its index in {@link getItems Items}.
578
	 * Previously editting item will change to normal item state.
579
	 * If the index is less than 0, any existing edit item will be cleared up.
580
	 * @param integer the edit item index
581
	 */
582
	public function setEditItemIndex($value)
583
	{
584
		if(($value=TPropertyValue::ensureInteger($value))<0)
585
			$value=-1;
586
		if(($current=$this->getEditItemIndex())!==$value)
587
		{
588
			$this->setViewState('EditItemIndex',$value,-1);
589
			$items=$this->getItems();
590
			$itemCount=$items->getCount();
591
			if($current>=0 && $current<$itemCount)
592
				$items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem:TListItemType::Item);
593
			if($value>=0 && $value<$itemCount)
594
				$items->itemAt($value)->setItemType(TListItemType::EditItem);
595
		}
596
	}
597
 
598
	/**
599
	 * @return boolean whether sorting is enabled. Defaults to false.
600
	 */
601
	public function getAllowSorting()
602
	{
603
		return $this->getViewState('AllowSorting',false);
604
	}
605
 
606
	/**
607
	 * @param boolean whether sorting is enabled
608
	 */
609
	public function setAllowSorting($value)
610
	{
611
		$this->setViewState('AllowSorting',TPropertyValue::ensureBoolean($value),false);
612
	}
613
 
614
	/**
615
	 * @return boolean whether datagrid columns should be automatically generated. Defaults to true.
616
	 */
617
	public function getAutoGenerateColumns()
618
	{
619
		return $this->getViewState('AutoGenerateColumns',true);
620
	}
621
 
622
	/**
623
	 * @param boolean whether datagrid columns should be automatically generated
624
	 */
625
	public function setAutoGenerateColumns($value)
626
	{
627
		$this->setViewState('AutoGenerateColumns',TPropertyValue::ensureBoolean($value),true);
628
	}
629
 
630
	/**
631
	 * @return boolean whether the header should be displayed. Defaults to true.
632
	 */
633
	public function getShowHeader()
634
	{
635
		return $this->getViewState('ShowHeader',true);
636
	}
637
 
638
	/**
639
	 * @param boolean whether the header should be displayed
640
	 */
641
	public function setShowHeader($value)
642
	{
643
		$this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
644
	}
645
 
646
	/**
647
	 * @return boolean whether the footer should be displayed. Defaults to false.
648
	 */
649
	public function getShowFooter()
650
	{
651
		return $this->getViewState('ShowFooter',false);
652
	}
653
 
654
	/**
655
	 * @param boolean whether the footer should be displayed
656
	 */
657
	public function setShowFooter($value)
658
	{
659
		$this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),false);
660
	}
661
 
662
	/**
663
	 * @return ITemplate the template applied when no data is bound to the datagrid
664
	 */
665
	public function getEmptyTemplate()
666
	{
667
		return $this->_emptyTemplate;
668
	}
669
 
670
	/**
671
	 * @param ITemplate the template applied when no data is bound to the datagrid
672
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
673
	 */
674
	public function setEmptyTemplate($value)
675
	{
676
		if($value instanceof ITemplate || $value===null)
677
			$this->_emptyTemplate=$value;
678
		else
679
			throw new TInvalidDataTypeException('datagrid_template_required','EmptyTemplate');
680
	}
681
 
682
	/**
683
	 * This method overrides parent's implementation to handle
684
	 * {@link onItemCommand OnItemCommand} event which is bubbled from
685
	 * {@link TDataGridItem} child controls.
686
	 * If the event parameter is {@link TDataGridCommandEventParameter} and
687
	 * the command name is a recognized one, which includes 'select', 'edit',
688
	 * 'delete', 'update', and 'cancel' (case-insensitive), then a
689
	 * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
690
	 * This method should only be used by control developers.
691
	 * @param TControl the sender of the event
692
	 * @param TEventParameter event parameter
693
	 * @return boolean whether the event bubbling should stop here.
694
	 */
695
	public function bubbleEvent($sender,$param)
696
	{
697
		if($param instanceof TDataGridCommandEventParameter)
698
		{
699
			$this->onItemCommand($param);
700
			$command=$param->getCommandName();
701
			if(strcasecmp($command,self::CMD_SELECT)===0)
702
			{
703
				$this->setSelectedItemIndex($param->getItem()->getItemIndex());
704
				$this->onSelectedIndexChanged($param);
705
				return true;
706
			}
707
			else if(strcasecmp($command,self::CMD_EDIT)===0)
708
			{
709
				$this->onEditCommand($param);
710
				return true;
711
			}
712
			else if(strcasecmp($command,self::CMD_DELETE)===0)
713
			{
714
				$this->onDeleteCommand($param);
715
				return true;
716
			}
717
			else if(strcasecmp($command,self::CMD_UPDATE)===0)
718
			{
719
				$this->onUpdateCommand($param);
720
				return true;
721
			}
722
			else if(strcasecmp($command,self::CMD_CANCEL)===0)
723
			{
724
				$this->onCancelCommand($param);
725
				return true;
726
			}
727
			else if(strcasecmp($command,self::CMD_SORT)===0)
728
			{
729
				$this->onSortCommand(new TDataGridSortCommandEventParameter($sender,$param));
730
				return true;
731
			}
732
			else if(strcasecmp($command,self::CMD_PAGE)===0)
733
			{
734
				$p=$param->getCommandParameter();
735
				if(strcasecmp($p,self::CMD_PAGE_NEXT)===0)
736
					$pageIndex=$this->getCurrentPageIndex()+1;
737
				else if(strcasecmp($p,self::CMD_PAGE_PREV)===0)
738
					$pageIndex=$this->getCurrentPageIndex()-1;
739
				else
740
					$pageIndex=TPropertyValue::ensureInteger($p)-1;
741
				$this->onPageIndexChanged(new TDataGridPageChangedEventParameter($sender,$pageIndex));
742
				return true;
743
			}
744
		}
745
		return false;
746
	}
747
 
748
	/**
749
	 * Raises <b>OnCancelCommand</b> event.
750
	 * This method is invoked when a button control raises <b>OnCommand</b> event
751
	 * with <b>cancel</b> command name.
752
	 * @param TDataGridCommandEventParameter event parameter
753
	 */
754
	public function onCancelCommand($param)
755
	{
756
		$this->raiseEvent('OnCancelCommand',$this,$param);
757
	}
758
 
759
	/**
760
	 * Raises <b>OnDeleteCommand</b> event.
761
	 * This method is invoked when a button control raises <b>OnCommand</b> event
762
	 * with <b>delete</b> command name.
763
	 * @param TDataGridCommandEventParameter event parameter
764
	 */
765
	public function onDeleteCommand($param)
766
	{
767
		$this->raiseEvent('OnDeleteCommand',$this,$param);
768
	}
769
 
770
	/**
771
	 * Raises <b>OnEditCommand</b> event.
772
	 * This method is invoked when a button control raises <b>OnCommand</b> event
773
	 * with <b>edit</b> command name.
774
	 * @param TDataGridCommandEventParameter event parameter
775
	 */
776
	public function onEditCommand($param)
777
	{
778
		$this->raiseEvent('OnEditCommand',$this,$param);
779
	}
780
 
781
	/**
782
	 * Raises <b>OnItemCommand</b> event.
783
	 * This method is invoked when a button control raises <b>OnCommand</b> event.
784
	 * @param TDataGridCommandEventParameter event parameter
785
	 */
786
	public function onItemCommand($param)
787
	{
788
		$this->raiseEvent('OnItemCommand',$this,$param);
789
	}
790
 
791
	/**
792
	 * Raises <b>OnSortCommand</b> event.
793
	 * This method is invoked when a button control raises <b>OnCommand</b> event
794
	 * with <b>sort</b> command name.
795
	 * @param TDataGridSortCommandEventParameter event parameter
796
	 */
797
	public function onSortCommand($param)
798
	{
799
		$this->raiseEvent('OnSortCommand',$this,$param);
800
	}
801
 
802
	/**
803
	 * Raises <b>OnUpdateCommand</b> event.
804
	 * This method is invoked when a button control raises <b>OnCommand</b> event
805
	 * with <b>update</b> command name.
806
	 * @param TDataGridCommandEventParameter event parameter
807
	 */
808
	public function onUpdateCommand($param)
809
	{
810
		$this->raiseEvent('OnUpdateCommand',$this,$param);
811
	}
812
 
813
	/**
814
	 * Raises <b>OnItemCreated</b> event.
815
	 * This method is invoked right after a datagrid item is created and before
816
	 * added to page hierarchy.
817
	 * @param TDataGridItemEventParameter event parameter
818
	 */
819
	public function onItemCreated($param)
820
	{
821
		$this->raiseEvent('OnItemCreated',$this,$param);
822
	}
823
 
824
	/**
825
	 * Raises <b>OnPagerCreated</b> event.
826
	 * This method is invoked right after a datagrid pager is created and before
827
	 * added to page hierarchy.
828
	 * @param TDataGridPagerEventParameter event parameter
829
	 */
830
	public function onPagerCreated($param)
831
	{
832
		$this->raiseEvent('OnPagerCreated',$this,$param);
833
	}
834
 
835
	/**
836
	 * Raises <b>OnItemDataBound</b> event.
837
	 * This method is invoked for each datagrid item after it performs
838
	 * databinding.
839
	 * @param TDataGridItemEventParameter event parameter
840
	 */
841
	public function onItemDataBound($param)
842
	{
843
		$this->raiseEvent('OnItemDataBound',$this,$param);
844
	}
845
 
846
	/**
847
	 * Raises <b>OnPageIndexChanged</b> event.
848
	 * This method is invoked when current page is changed.
849
	 * @param TDataGridPageChangedEventParameter event parameter
850
	 */
851
	public function onPageIndexChanged($param)
852
	{
853
		$this->raiseEvent('OnPageIndexChanged',$this,$param);
854
	}
855
 
856
	/**
857
	 * Saves item count in viewstate.
858
	 * This method is invoked right before control state is to be saved.
859
	 */
860
	public function saveState()
861
	{
862
		parent::saveState();
863
		if(!$this->getEnableViewState(true))
864
			return;
865
		if($this->_items)
866
			$this->setViewState('ItemCount',$this->_items->getCount(),0);
867
		else
868
			$this->clearViewState('ItemCount');
869
		if($this->_autoColumns)
870
		{
871
			$state=array();
872
			foreach($this->_autoColumns as $column)
873
				$state[]=$column->saveState();
874
			$this->setViewState('AutoColumns',$state,array());
875
		}
876
		else
877
			$this->clearViewState('AutoColumns');
878
		if($this->_columns)
879
		{
880
			$state=array();
881
			foreach($this->_columns as $column)
882
				$state[]=$column->saveState();
883
			$this->setViewState('Columns',$state,array());
884
		}
885
		else
886
			$this->clearViewState('Columns');
887
	}
888
 
889
	/**
890
	 * Loads item count information from viewstate.
891
	 * This method is invoked right after control state is loaded.
892
	 */
893
	public function loadState()
894
	{
895
		parent::loadState();
896
		if(!$this->getEnableViewState(true))
897
			return;
898
		if(!$this->getIsDataBound())
899
		{
900
			$state=$this->getViewState('AutoColumns',array());
901
			if(!empty($state))
902
			{
903
				$this->_autoColumns=new TDataGridColumnCollection($this);
904
				foreach($state as $st)
905
				{
906
					$column=new TBoundColumn;
907
					$column->loadState($st);
908
					$this->_autoColumns->add($column);
909
				}
910
			}
911
			else
912
				$this->_autoColumns=null;
913
			$state=$this->getViewState('Columns',array());
914
			if($this->_columns && $this->_columns->getCount()===count($state))
915
			{
916
				$i=0;
917
				foreach($this->_columns as $column)
918
				{
919
					$column->loadState($state[$i]);
920
					$i++;
921
				}
922
			}
923
			$this->restoreGridFromViewState();
924
		}
925
	}
926
 
927
	/**
928
	 * Clears up all items in the datagrid.
929
	 */
930
	public function reset()
931
	{
932
		$this->getControls()->clear();
933
		$this->getItems()->clear();
934
		$this->_header=null;
935
		$this->_footer=null;
936
		$this->_topPager=null;
937
		$this->_bottomPager=null;
938
		$this->_useEmptyTemplate=false;
939
	}
940
 
941
	/**
942
	 * Restores datagrid content from viewstate.
943
	 */
944
	protected function restoreGridFromViewState()
945
	{
946
		$this->reset();
947
 
948
		$allowPaging=$this->getAllowPaging();
949
 
950
		$itemCount=$this->getViewState('ItemCount',0);
951
		$dsIndex=$this->getViewState('DataSourceIndex',0);
952
 
953
		$columns=new TList($this->getColumns());
954
		$columns->mergeWith($this->_autoColumns);
955
		$this->_allColumns=$columns;
956
 
957
		$items=$this->getItems();
958
 
959
		if($columns->getCount())
960
		{
961
			foreach($columns as $column)
962
				$column->initialize();
963
			$selectedIndex=$this->getSelectedItemIndex();
964
			$editIndex=$this->getEditItemIndex();
965
			for($index=0;$index<$itemCount;++$index)
966
			{
967
				if($index===0)
968
				{
969
					if($allowPaging)
970
						$this->_topPager=$this->createPager();
971
					$this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,false,null,$columns);
972
				}
973
				if($index===$editIndex)
974
					$itemType=TListItemType::EditItem;
975
				else if($index===$selectedIndex)
976
					$itemType=TListItemType::SelectedItem;
977
				else if($index % 2)
978
					$itemType=TListItemType::AlternatingItem;
979
				else
980
					$itemType=TListItemType::Item;
981
				$items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
982
				$dsIndex++;
983
			}
984
			if($index>0)
985
			{
986
				$this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,false,null,$columns);
987
				if($allowPaging)
988
					$this->_bottomPager=$this->createPager();
989
			}
990
		}
991
		if(!$dsIndex && $this->_emptyTemplate!==null)
992
		{
993
			$this->_useEmptyTemplate=true;
994
			$this->_emptyTemplate->instantiateIn($this);
995
		}
996
	}
997
 
998
	/**
999
	 * Performs databinding to populate datagrid items from data source.
1000
	 * This method is invoked by {@link dataBind()}.
1001
	 * You may override this function to provide your own way of data population.
1002
	 * @param Traversable the bound data
1003
	 */
1004
	protected function performDataBinding($data)
1005
	{
1006
		$this->reset();
1007
		$keys=$this->getDataKeys();
1008
		$keys->clear();
1009
		$keyField=$this->getDataKeyField();
1010
 
1011
		// get all columns
1012
		if($this->getAutoGenerateColumns())
1013
		{
1014
			$columns=new TList($this->getColumns());
1015
			$autoColumns=$this->createAutoColumns($data);
1016
			$columns->mergeWith($autoColumns);
1017
		}
1018
		else
1019
			$columns=$this->getColumns();
1020
		$this->_allColumns=$columns;
1021
 
1022
		$items=$this->getItems();
1023
 
1024
		$index=0;
1025
		$allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
1026
		$dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
1027
		$this->setViewState('DataSourceIndex',$dsIndex,0);
1028
		if($columns->getCount())
1029
		{
1030
			foreach($columns as $column)
1031
				$column->initialize();
1032
 
1033
			$selectedIndex=$this->getSelectedItemIndex();
1034
			$editIndex=$this->getEditItemIndex();
1035
			foreach($data as $key=>$row)
1036
			{
1037
				if($keyField!=='')
1038
					$keys->add($this->getDataFieldValue($row,$keyField));
1039
				else
1040
					$keys->add($key);
1041
				if($index===0)
1042
				{
1043
					if($allowPaging)
1044
						$this->_topPager=$this->createPager();
1045
					$this->_header=$this->createItemInternal(-1,-1,TListItemType::Header,true,null,$columns);
1046
				}
1047
				if($index===$editIndex)
1048
					$itemType=TListItemType::EditItem;
1049
				else if($index===$selectedIndex)
1050
					$itemType=TListItemType::SelectedItem;
1051
				else if($index % 2)
1052
					$itemType=TListItemType::AlternatingItem;
1053
				else
1054
					$itemType=TListItemType::Item;
1055
				$items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
1056
				$index++;
1057
				$dsIndex++;
1058
			}
1059
			if($index>0)
1060
			{
1061
				$this->_footer=$this->createItemInternal(-1,-1,TListItemType::Footer,true,null,$columns);
1062
				if($allowPaging)
1063
					$this->_bottomPager=$this->createPager();
1064
			}
1065
		}
1066
		$this->setViewState('ItemCount',$index,0);
1067
		if(!$dsIndex && $this->_emptyTemplate!==null)
1068
		{
1069
			$this->_useEmptyTemplate=true;
1070
			$this->_emptyTemplate->instantiateIn($this);
1071
			$this->dataBindChildren();
1072
		}
1073
	}
1074
 
1075
	/**
1076
	 * Merges consecutive cells who have the same text.
1077
	 * @since 3.1.1
1078
	 */
1079
	private function groupCells()
1080
	{
1081
		if(($columns=$this->_allColumns)===null)
1082
			return;
1083
		$items=$this->getItems();
1084
		foreach($columns as $id=>$column)
1085
		{
1086
			if(!$column->getEnableCellGrouping())
1087
				continue;
1088
			$prevCell=null;
1089
			$prevCellText=null;
1090
			foreach($items as $item)
1091
			{
1092
				$itemType=$item->getItemType();
1093
				$cell=$item->getCells()->itemAt($id);
1094
				if(!$cell->getVisible())
1095
					continue;
1096
				if($itemType===TListItemType::Item || $itemType===TListItemType::AlternatingItem || $itemType===TListItemType::SelectedItem)
1097
				{
1098
					if(($cellText=$this->getCellText($cell))==='')
1099
					{
1100
						$prevCell=null;
1101
						$prevCellText=null;
1102
						continue;
1103
					}
1104
					if($prevCell===null || $prevCellText!==$cellText)
1105
					{
1106
						$prevCell=$cell;
1107
						$prevCellText=$cellText;
1108
					}
1109
					else
1110
					{
1111
						if(($rowSpan=$prevCell->getRowSpan())===0)
1112
							$rowSpan=1;
1113
						$prevCell->setRowSpan($rowSpan+1);
1114
						$cell->setVisible(false);
1115
					}
1116
				}
1117
			}
1118
		}
1119
	}
1120
 
1121
	private function getCellText($cell)
1122
	{
1123
		if(($data=$cell->getText())==='' && $cell->getHasControls())
1124
		{
1125
			$controls=$cell->getControls();
1126
			foreach($controls as $control)
1127
			{
1128
				if($control instanceof IDataRenderer)
1129
					return $control->getData();
1130
			}
1131
		}
1132
		return $data;
1133
	}
1134
 
1135
	/**
1136
	 * Creates a datagrid item instance based on the item type and index.
1137
	 * @param integer zero-based item index
1138
	 * @param TListItemType item type
1139
	 * @return TDataGridItem created data list item
1140
	 */
1141
	protected function createItem($itemIndex,$dataSourceIndex,$itemType)
1142
	{
1143
		return new TDataGridItem($itemIndex,$dataSourceIndex,$itemType);
1144
	}
1145
 
1146
	private function createItemInternal($itemIndex,$dataSourceIndex,$itemType,$dataBind,$dataItem,$columns)
1147
	{
1148
		$item=$this->createItem($itemIndex,$dataSourceIndex,$itemType);
1149
		$this->initializeItem($item,$columns);
1150
		$param=new TDataGridItemEventParameter($item);
1151
		if($dataBind)
1152
		{
1153
			$item->setDataItem($dataItem);
1154
			$this->onItemCreated($param);
1155
			$this->getControls()->add($item);
1156
			$item->dataBind();
1157
			$this->onItemDataBound($param);
1158
		}
1159
		else
1160
		{
1161
			$this->onItemCreated($param);
1162
			$this->getControls()->add($item);
1163
		}
1164
		return $item;
1165
	}
1166
 
1167
	/**
1168
	 * Initializes a datagrid item and cells inside it
1169
	 * @param TDataGrid datagrid item to be initialized
1170
	 * @param TDataGridColumnCollection datagrid columns to be used to initialize the cells in the item
1171
	 */
1172
	protected function initializeItem($item,$columns)
1173
	{
1174
		$cells=$item->getCells();
1175
		$itemType=$item->getItemType();
1176
		$index=0;
1177
		foreach($columns as $column)
1178
		{
1179
			if($itemType===TListItemType::Header)
1180
				$cell=new TTableHeaderCell;
1181
			else
1182
				$cell=new TTableCell;
1183
			if(($id=$column->getID())!=='')
1184
				$item->registerObject($id,$cell);
1185
			$cells->add($cell);
1186
			$column->initializeCell($cell,$index,$itemType);
1187
			$index++;
1188
		}
1189
	}
1190
 
1191
	private function createPager()
1192
	{
1193
		$pager=new TDataGridPager($this);
1194
		$this->buildPager($pager);
1195
		$this->onPagerCreated(new TDataGridPagerEventParameter($pager));
1196
		$this->getControls()->add($pager);
1197
		return $pager;
1198
	}
1199
 
1200
	/**
1201
	 * Builds the pager content based on pager style.
1202
	 * @param TDataGridPager the container for the pager
1203
	 */
1204
	protected function buildPager($pager)
1205
	{
1206
		switch($this->getPagerStyle()->getMode())
1207
		{
1208
			case TDataGridPagerMode::NextPrev:
1209
				$this->buildNextPrevPager($pager);
1210
				break;
1211
			case TDataGridPagerMode::Numeric:
1212
				$this->buildNumericPager($pager);
1213
				break;
1214
		}
1215
	}
1216
 
1217
	/**
1218
	 * Creates a pager button.
1219
	 * Depending on the button type, a TLinkButton or a TButton may be created.
1220
	 * If it is enabled (clickable), its command name and parameter will also be set.
1221
	 * Derived classes may override this method to create additional types of buttons, such as TImageButton.
1222
	 * @param string button type, either LinkButton or PushButton
1223
	 * @param boolean whether the button should be enabled
1224
	 * @param string caption of the button
1225
	 * @param string CommandName corresponding to the OnCommand event of the button
1226
	 * @param string CommandParameter corresponding to the OnCommand event of the button
1227
	 * @return mixed the button instance
1228
	 */
1229
	protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
1230
	{
1231
		if($buttonType===TDataGridPagerButtonType::LinkButton)
1232
		{
1233
			if($enabled)
1234
				$button=new TLinkButton;
1235
			else
1236
			{
1237
				$button=new TLabel;
1238
				$button->setText($text);
1239
				return $button;
1240
			}
1241
		}
1242
		else
1243
		{
1244
			$button=new TButton;
1245
			if(!$enabled)
1246
				$button->setEnabled(false);
1247
		}
1248
		$button->setText($text);
1249
		$button->setCommandName($commandName);
1250
		$button->setCommandParameter($commandParameter);
1251
		$button->setCausesValidation(false);
1252
		return $button;
1253
	}
1254
 
1255
	/**
1256
	 * Builds a next-prev pager
1257
	 * @param TDataGridPager the container for the pager
1258
	 */
1259
	protected function buildNextPrevPager($pager)
1260
	{
1261
		$style=$this->getPagerStyle();
1262
		$buttonType=$style->getButtonType();
1263
		$controls=$pager->getControls();
1264
		$currentPageIndex=$this->getCurrentPageIndex();
1265
		if($currentPageIndex===0)
1266
		{
1267
			$label=$this->createPagerButton($buttonType,false,$style->getPrevPageText(),'','');
1268
			$controls->add($label);
1269
		}
1270
		else
1271
		{
1272
			$button=$this->createPagerButton($buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
1273
			$controls->add($button);
1274
		}
1275
		$controls->add("\n");
1276
		if($currentPageIndex===$this->getPageCount()-1)
1277
		{
1278
			$label=$this->createPagerButton($buttonType,false,$style->getNextPageText(),'','');
1279
			$controls->add($label);
1280
		}
1281
		else
1282
		{
1283
			$button=$this->createPagerButton($buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
1284
			$controls->add($button);
1285
		}
1286
	}
1287
 
1288
	/**
1289
	 * Builds a numeric pager
1290
	 * @param TDataGridPager the container for the pager
1291
	 */
1292
	protected function buildNumericPager($pager)
1293
	{
1294
		$style=$this->getPagerStyle();
1295
		$buttonType=$style->getButtonType();
1296
		$controls=$pager->getControls();
1297
		$pageCount=$this->getPageCount();
1298
		$pageIndex=$this->getCurrentPageIndex()+1;
1299
		$maxButtonCount=$style->getPageButtonCount();
1300
		$buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
1301
		$startPageIndex=1;
1302
		$endPageIndex=$buttonCount;
1303
		if($pageIndex>$endPageIndex)
1304
		{
1305
			$startPageIndex=((int)(($pageIndex-1)/$maxButtonCount))*$maxButtonCount+1;
1306
			if(($endPageIndex=$startPageIndex+$maxButtonCount-1)>$pageCount)
1307
				$endPageIndex=$pageCount;
1308
			if($endPageIndex-$startPageIndex+1<$maxButtonCount)
1309
			{
1310
				if(($startPageIndex=$endPageIndex-$maxButtonCount+1)<1)
1311
					$startPageIndex=1;
1312
			}
1313
		}
1314
 
1315
		if($startPageIndex>1)
1316
		{
1317
			$prevPageIndex=$startPageIndex-1;
1318
			$button=$this->createPagerButton($buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
1319
			$controls->add($button);
1320
			$controls->add("\n");
1321
		}
1322
 
1323
		for($i=$startPageIndex;$i<=$endPageIndex;++$i)
1324
		{
1325
			if($i===$pageIndex)
1326
			{
1327
				$label=$this->createPagerButton($buttonType,false,"$i",'','');
1328
				$controls->add($label);
1329
			}
1330
			else
1331
			{
1332
				$button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i");
1333
				$controls->add($button);
1334
			}
1335
			if($i<$endPageIndex)
1336
				$controls->add("\n");
1337
		}
1338
 
1339
		if($pageCount>$endPageIndex)
1340
		{
1341
			$controls->add("\n");
1342
			$nextPageIndex=$endPageIndex+1;
1343
			$button=$this->createPagerButton($buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
1344
			$controls->add($button);
1345
		}
1346
	}
1347
 
1348
	/**
1349
	 * Automatically generates datagrid columns based on datasource schema
1350
	 * @param Traversable data source bound to the datagrid
1351
	 * @return TDataGridColumnCollection
1352
	 */
1353
	protected function createAutoColumns($dataSource)
1354
	{
1355
		if(!$dataSource)
1356
			return null;
1357
		$autoColumns=$this->getAutoColumns();
1358
		$autoColumns->clear();
1359
		foreach($dataSource as $row)
1360
		{
1361
			foreach($row as $key=>$value)
1362
			{
1363
				$column=new TBoundColumn;
1364
				if(is_string($key))
1365
				{
1366
					$column->setHeaderText($key);
1367
					$column->setDataField($key);
1368
					$column->setSortExpression($key);
1369
					$autoColumns->add($column);
1370
				}
1371
				else
1372
				{
1373
					$column->setHeaderText(TListItemType::Item);
1374
					$column->setDataField($key);
1375
					$column->setSortExpression(TListItemType::Item);
1376
					$autoColumns->add($column);
1377
				}
1378
			}
1379
			break;
1380
		}
1381
		return $autoColumns;
1382
	}
1383
 
1384
	/**
1385
	 * Applies styles to items, header, footer and separators.
1386
	 * Item styles are applied in a hierarchical way. Style in higher hierarchy
1387
	 * will inherit from styles in lower hierarchy.
1388
	 * Starting from the lowest hierarchy, the item styles include
1389
	 * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
1390
	 * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
1391
	 * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
1392
	 * {@link getEditItemStyle EditItemStyle} will also have red background color
1393
	 * unless it is set to a different value explicitly.
1394
	 */
1395
	protected function applyItemStyles()
1396
	{
1397
		$itemStyle=$this->getViewState('ItemStyle',null);
1398
 
1399
		$alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
1400
		if($itemStyle!==null)
1401
		{
1402
			if($alternatingItemStyle===null)
1403
				$alternatingItemStyle=$itemStyle;
1404
			else
1405
				$alternatingItemStyle->mergeWith($itemStyle);
1406
		}
1407
 
1408
		$selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
1409
 
1410
		$editItemStyle=$this->getViewState('EditItemStyle',null);
1411
		if($selectedItemStyle!==null)
1412
		{
1413
			if($editItemStyle===null)
1414
				$editItemStyle=$selectedItemStyle;
1415
			else
1416
				$editItemStyle->mergeWith($selectedItemStyle);
1417
		}
1418
 
1419
		$headerStyle=$this->getViewState('HeaderStyle',null);
1420
		$footerStyle=$this->getViewState('FooterStyle',null);
1421
		$pagerStyle=$this->getViewState('PagerStyle',null);
1422
		$separatorStyle=$this->getViewState('SeparatorStyle',null);
1423
 
1424
		foreach($this->getControls() as $index=>$item)
1425
		{
1426
			if(!($item instanceof TDataGridItem) && !($item instanceof TDataGridPager))
1427
				continue;
1428
			$itemType=$item->getItemType();
1429
			switch($itemType)
1430
			{
1431
				case TListItemType::Header:
1432
					if($headerStyle)
1433
						$item->getStyle()->mergeWith($headerStyle);
1434
					if(!$this->getShowHeader())
1435
						$item->setVisible(false);
1436
					break;
1437
				case TListItemType::Footer:
1438
					if($footerStyle)
1439
						$item->getStyle()->mergeWith($footerStyle);
1440
					if(!$this->getShowFooter())
1441
						$item->setVisible(false);
1442
					break;
1443
				case TListItemType::Separator:
1444
					if($separatorStyle)
1445
						$item->getStyle()->mergeWith($separatorStyle);
1446
					break;
1447
				case TListItemType::Item:
1448
					if($itemStyle)
1449
						$item->getStyle()->mergeWith($itemStyle);
1450
					break;
1451
				case TListItemType::AlternatingItem:
1452
					if($alternatingItemStyle)
1453
						$item->getStyle()->mergeWith($alternatingItemStyle);
1454
					break;
1455
				case TListItemType::SelectedItem:
1456
					if($selectedItemStyle)
1457
						$item->getStyle()->mergeWith($selectedItemStyle);
1458
					if($index % 2==1)
1459
					{
1460
						if($itemStyle)
1461
							$item->getStyle()->mergeWith($itemStyle);
1462
					}
1463
					else
1464
					{
1465
						if($alternatingItemStyle)
1466
							$item->getStyle()->mergeWith($alternatingItemStyle);
1467
					}
1468
					break;
1469
				case TListItemType::EditItem:
1470
					if($editItemStyle)
1471
						$item->getStyle()->mergeWith($editItemStyle);
1472
					if($index % 2==1)
1473
					{
1474
						if($itemStyle)
1475
							$item->getStyle()->mergeWith($itemStyle);
1476
					}
1477
					else
1478
					{
1479
						if($alternatingItemStyle)
1480
							$item->getStyle()->mergeWith($alternatingItemStyle);
1481
					}
1482
					break;
1483
				case TListItemType::Pager:
1484
					if($pagerStyle)
1485
					{
1486
						$item->getStyle()->mergeWith($pagerStyle);
1487
						if($index===0)
1488
						{
1489
							if($pagerStyle->getPosition()===TDataGridPagerPosition::Bottom || !$pagerStyle->getVisible())
1490
								$item->setVisible(false);
1491
						}
1492
						else
1493
						{
1494
							if($pagerStyle->getPosition()===TDataGridPagerPosition::Top || !$pagerStyle->getVisible())
1495
								$item->setVisible(false);
1496
						}
1497
					}
1498
					break;
1499
				default:
1500
					break;
1501
			}
1502
			if($this->_columns && $itemType!==TListItemType::Pager)
1503
			{
1504
				$n=$this->_columns->getCount();
1505
				$cells=$item->getCells();
1506
				for($i=0;$i<$n;++$i)
1507
				{
1508
					$cell=$cells->itemAt($i);
1509
					$column=$this->_columns->itemAt($i);
1510
					if(!$column->getVisible())
1511
						$cell->setVisible(false);
1512
					else
1513
					{
1514
						if($itemType===TListItemType::Header)
1515
							$style=$column->getHeaderStyle(false);
1516
						else if($itemType===TListItemType::Footer)
1517
							$style=$column->getFooterStyle(false);
1518
						else
1519
							$style=$column->getItemStyle(false);
1520
						if($style!==null)
1521
							$cell->getStyle()->mergeWith($style);
1522
					}
1523
				}
1524
			}
1525
		}
1526
	}
1527
 
1528
	/**
1529
	 * Renders the openning tag for the datagrid control which will render table caption if present.
1530
	 * @param THtmlWriter the writer used for the rendering purpose
1531
	 */
1532
	public function renderBeginTag($writer)
1533
	{
1534
		parent::renderBeginTag($writer);
1535
		if(($caption=$this->getCaption())!=='')
1536
		{
1537
			if(($align=$this->getCaptionAlign())!==TTableCaptionAlign::NotSet)
1538
				$writer->addAttribute('align',strtolower($align));
1539
			$writer->renderBeginTag('caption');
1540
			$writer->write($caption);
1541
			$writer->renderEndTag();
1542
		}
1543
	}
1544
 
1545
	/**
1546
	 * Renders the datagrid.
1547
	 * @param THtmlWriter writer for the rendering purpose
1548
	 */
1549
	public function render($writer)
1550
	{
1551
		if($this->getHasControls())
1552
		{
1553
			$this->groupCells();
1554
			if($this->_useEmptyTemplate)
1555
			{
1556
				$control=new TWebControl;
1557
				$control->setID($this->getClientID());
1558
				$control->copyBaseAttributes($this);
1559
				if($this->getHasStyle())
1560
					$control->getStyle()->copyFrom($this->getStyle());
1561
				$control->renderBeginTag($writer);
1562
				$this->renderContents($writer);
1563
				$control->renderEndTag($writer);
1564
			}
1565
			else if($this->getViewState('ItemCount',0)>0)
1566
			{
1567
				$this->applyItemStyles();
1568
				if($this->_topPager)
1569
				{
1570
					$this->_topPager->renderControl($writer);
1571
					$writer->writeLine();
1572
				}
1573
				$this->renderTable($writer);
1574
				if($this->_bottomPager)
1575
				{
1576
					$writer->writeLine();
1577
					$this->_bottomPager->renderControl($writer);
1578
				}
1579
			}
1580
		}
1581
	}
1582
 
1583
	/**
1584
	 * Renders the tabular data.
1585
	 * @param THtmlWriter writer
1586
	 */
1587
	protected function renderTable($writer)
1588
	{
1589
		$this->renderBeginTag($writer);
1590
		if($this->_header && $this->_header->getVisible())
1591
		{
1592
			$writer->writeLine();
1593
			if($style=$this->getViewState('TableHeadStyle',null))
1594
				$style->addAttributesToRender($writer);
1595
			$writer->renderBeginTag('thead');
1596
			$this->_header->render($writer);
1597
			$writer->renderEndTag();
1598
		}
1599
		$writer->writeLine();
1600
		if($style=$this->getViewState('TableBodyStyle',null))
1601
			$style->addAttributesToRender($writer);
1602
		$writer->renderBeginTag('tbody');
1603
		foreach($this->getItems() as $item)
1604
			$item->renderControl($writer);
1605
		$writer->renderEndTag();
1606
 
1607
		if($this->_footer && $this->_footer->getVisible())
1608
		{
1609
			$writer->writeLine();
1610
			if($style=$this->getViewState('TableFootStyle',null))
1611
				$style->addAttributesToRender($writer);
1612
			$writer->renderBeginTag('tfoot');
1613
			$this->_footer->render($writer);
1614
			$writer->renderEndTag();
1615
		}
1616
 
1617
		$writer->writeLine();
1618
		$this->renderEndTag($writer);
1619
	}
1620
}
1621
 
1622
/**
1623
 * TDataGridItemEventParameter class
1624
 *
1625
 * TDataGridItemEventParameter encapsulates the parameter data for
1626
 * {@link TDataGrid::onItemCreated OnItemCreated} event of {@link TDataGrid} controls.
1627
 * The {@link getItem Item} property indicates the datagrid item related with the event.
1628
 *
1629
 * @author Qiang Xue <qiang.xue@gmail.com>
1630
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
1631
 * @package System.Web.UI.WebControls
1632
 * @since 3.0
1633
 */
1634
class TDataGridItemEventParameter extends TEventParameter
1635
{
1636
	/**
1637
	 * The TDataGridItem control responsible for the event.
1638
	 * @var TDataGridItem
1639
	 */
1640
	private $_item=null;
1641
 
1642
	/**
1643
	 * Constructor.
1644
	 * @param TDataGridItem datagrid item related with the corresponding event
1645
	 */
1646
	public function __construct(TDataGridItem $item)
1647
	{
1648
		$this->_item=$item;
1649
	}
1650
 
1651
	/**
1652
	 * @return TDataGridItem datagrid item related with the corresponding event
1653
	 */
1654
	public function getItem()
1655
	{
1656
		return $this->_item;
1657
	}
1658
}
1659
 
1660
/**
1661
 * TDataGridPagerEventParameter class
1662
 *
1663
 * TDataGridPagerEventParameter encapsulates the parameter data for
1664
 * {@link TDataGrid::onPagerCreated OnPagerCreated} event of {@link TDataGrid} controls.
1665
 * The {@link getPager Pager} property indicates the datagrid pager related with the event.
1666
 *
1667
 * @author Qiang Xue <qiang.xue@gmail.com>
1668
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
1669
 * @package System.Web.UI.WebControls
1670
 * @since 3.0
1671
 */
1672
class TDataGridPagerEventParameter extends TEventParameter
1673
{
1674
	/**
1675
	 * The TDataGridPager control responsible for the event.
1676
	 * @var TDataGridPager
1677
	 */
1678
	private $_pager=null;
1679
 
1680
	/**
1681
	 * Constructor.
1682
	 * @param TDataGridPager datagrid pager related with the corresponding event
1683
	 */
1684
	public function __construct(TDataGridPager $pager)
1685
	{
1686
		$this->_pager=$pager;
1687
	}
1688
 
1689
	/**
1690
	 * @return TDataGridPager datagrid pager related with the corresponding event
1691
	 */
1692
	public function getPager()
1693
	{
1694
		return $this->_pager;
1695
	}
1696
}
1697
 
1698
/**
1699
 * TDataGridCommandEventParameter class
1700
 *
1701
 * TDataGridCommandEventParameter encapsulates the parameter data for
1702
 * {@link TDataGrid::onItemCommand ItemCommand} event of {@link TDataGrid} controls.
1703
 *
1704
 * The {@link getItem Item} property indicates the datagrid item related with the event.
1705
 * The {@link getCommandSource CommandSource} refers to the control that originally
1706
 * raises the Command event.
1707
 *
1708
 * @author Qiang Xue <qiang.xue@gmail.com>
1709
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
1710
 * @package System.Web.UI.WebControls
1711
 * @since 3.0
1712
 */
1713
class TDataGridCommandEventParameter extends TCommandEventParameter
1714
{
1715
	/**
1716
	 * @var TDataGridItem the TDataGridItem control responsible for the event.
1717
	 */
1718
	private $_item=null;
1719
	/**
1720
	 * @var TControl the control originally raises the <b>Command</b> event.
1721
	 */
1722
	private $_source=null;
1723
 
1724
	/**
1725
	 * Constructor.
1726
	 * @param TDataGridItem datagrid item responsible for the event
1727
	 * @param TControl original event sender
1728
	 * @param TCommandEventParameter original event parameter
1729
	 */
1730
	public function __construct($item,$source,TCommandEventParameter $param)
1731
	{
1732
		$this->_item=$item;
1733
		$this->_source=$source;
1734
		parent::__construct($param->getCommandName(),$param->getCommandParameter());
1735
	}
1736
 
1737
	/**
1738
	 * @return TDataGridItem the TDataGridItem control responsible for the event.
1739
	 */
1740
	public function getItem()
1741
	{
1742
		return $this->_item;
1743
	}
1744
 
1745
	/**
1746
	 * @return TControl the control originally raises the <b>Command</b> event.
1747
	 */
1748
	public function getCommandSource()
1749
	{
1750
		return $this->_source;
1751
	}
1752
}
1753
 
1754
/**
1755
 * TDataGridSortCommandEventParameter class
1756
 *
1757
 * TDataGridSortCommandEventParameter encapsulates the parameter data for
1758
 * {@link TDataGrid::onSortCommand SortCommand} event of {@link TDataGrid} controls.
1759
 *
1760
 * The {@link getCommandSource CommandSource} property refers to the control
1761
 * that originally raises the OnCommand event, while {@link getSortExpression SortExpression}
1762
 * gives the sort expression carried with the sort command.
1763
 *
1764
 * @author Qiang Xue <qiang.xue@gmail.com>
1765
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
1766
 * @package System.Web.UI.WebControls
1767
 * @since 3.0
1768
 */
1769
class TDataGridSortCommandEventParameter extends TEventParameter
1770
{
1771
	/**
1772
	 * @var string sort expression
1773
	 */
1774
	private $_sortExpression='';
1775
	/**
1776
	 * @var TControl original event sender
1777
	 */
1778
	private $_source=null;
1779
 
1780
	/**
1781
	 * Constructor.
1782
	 * @param TControl the control originally raises the <b>OnCommand</b> event.
1783
	 * @param TDataGridCommandEventParameter command event parameter
1784
	 */
1785
	public function __construct($source,TDataGridCommandEventParameter $param)
1786
	{
1787
		$this->_source=$source;
1788
		$this->_sortExpression=$param->getCommandParameter();
1789
	}
1790
 
1791
	/**
1792
	 * @return TControl the control originally raises the <b>OnCommand</b> event.
1793
	 */
1794
	public function getCommandSource()
1795
	{
1796
		return $this->_source;
1797
	}
1798
 
1799
	/**
1800
	 * @return string sort expression
1801
	 */
1802
	public function getSortExpression()
1803
	{
1804
		return $this->_sortExpression;
1805
	}
1806
}
1807
 
1808
/**
1809
 * TDataGridPageChangedEventParameter class
1810
 *
1811
 * TDataGridPageChangedEventParameter encapsulates the parameter data for
1812
 * {@link TDataGrid::onPageIndexChanged PageIndexChanged} event of {@link TDataGrid} controls.
1813
 *
1814
 * The {@link getCommandSource CommandSource} property refers to the control
1815
 * that originally raises the OnCommand event, while {@link getNewPageIndex NewPageIndex}
1816
 * returns the new page index carried with the page command.
1817
 *
1818
 * @author Qiang Xue <qiang.xue@gmail.com>
1819
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
1820
 * @package System.Web.UI.WebControls
1821
 * @since 3.0
1822
 */
1823
class TDataGridPageChangedEventParameter extends TEventParameter
1824
{
1825
	/**
1826
	 * @var integer new page index
1827
	 */
1828
	private $_newIndex;
1829
	/**
1830
	 * @var TControl original event sender
1831
	 */
1832
	private $_source=null;
1833
 
1834
	/**
1835
	 * Constructor.
1836
	 * @param TControl the control originally raises the <b>OnCommand</b> event.
1837
	 * @param integer new page index
1838
	 */
1839
	public function __construct($source,$newPageIndex)
1840
	{
1841
		$this->_source=$source;
1842
		$this->_newIndex=$newPageIndex;
1843
	}
1844
 
1845
	/**
1846
	 * @return TControl the control originally raises the <b>OnCommand</b> event.
1847
	 */
1848
	public function getCommandSource()
1849
	{
1850
		return $this->_source;
1851
	}
1852
 
1853
	/**
1854
	 * @return integer new page index
1855
	 */
1856
	public function getNewPageIndex()
1857
	{
1858
		return $this->_newIndex;
1859
	}
1860
}
1861
 
1862
/**
1863
 * TDataGridItem class
1864
 *
1865
 * A TDataGridItem control represents an item in the {@link TDataGrid} control,
1866
 * such as heading section, footer section, or a data item.
1867
 * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
1868
 * and {@link getDataItem DataItem} properties, respectively. The type of the item
1869
 * is given by {@link getItemType ItemType} property. Property {@link getDataSourceIndex DataSourceIndex}
1870
 * gives the index of the item from the bound data source.
1871
 *
1872
 * @author Qiang Xue <qiang.xue@gmail.com>
1873
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
1874
 * @package System.Web.UI.WebControls
1875
 * @since 3.0
1876
 */
1877
class TDataGridItem extends TTableRow implements INamingContainer
1878
{
1879
	/**
1880
	 * @var integer index of the data item in the Items collection of datagrid
1881
	 */
1882
	private $_itemIndex='';
1883
	/**
1884
	 * @var integer index of the item from the bound data source
1885
	 */
1886
	private $_dataSourceIndex=0;
1887
	/**
1888
	 * type of the TDataGridItem
1889
	 * @var string
1890
	 */
1891
	private $_itemType='';
1892
	/**
1893
	 * value of the data item
1894
	 * @var mixed
1895
	 */
1896
	private $_data=null;
1897
 
1898
	/**
1899
	 * Constructor.
1900
	 * @param integer zero-based index of the item in the item collection of datagrid
1901
	 * @param TListItemType item type
1902
	 */
1903
	public function __construct($itemIndex,$dataSourceIndex,$itemType)
1904
	{
1905
		$this->_itemIndex=$itemIndex;
1906
		$this->_dataSourceIndex=$dataSourceIndex;
1907
		$this->setItemType($itemType);
1908
		if($itemType===TListItemType::Header)
1909
			$this->setTableSection(TTableRowSection::Header);
1910
		else if($itemType===TListItemType::Footer)
1911
			$this->setTableSection(TTableRowSection::Footer);
1912
	}
1913
 
1914
	/**
1915
	 * @return TListItemType item type.
1916
	 */
1917
	public function getItemType()
1918
	{
1919
		return $this->_itemType;
1920
	}
1921
 
1922
	/**
1923
	 * @param TListItemType item type
1924
	 */
1925
	public function setItemType($value)
1926
	{
1927
		$this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
1928
	}
1929
 
1930
	/**
1931
	 * @return integer zero-based index of the item in the item collection of datagrid
1932
	 */
1933
	public function getItemIndex()
1934
	{
1935
		return $this->_itemIndex;
1936
	}
1937
 
1938
	/**
1939
	 * @return integer the index of the datagrid item from the bound data source
1940
	 */
1941
	public function getDataSourceIndex()
1942
	{
1943
		return $this->_dataSourceIndex;
1944
	}
1945
 
1946
	/**
1947
	 * @return mixed data associated with the item
1948
	 * @since 3.1.0
1949
	 */
1950
	public function getData()
1951
	{
1952
		return $this->_data;
1953
	}
1954
 
1955
	/**
1956
	 * @param mixed data to be associated with the item
1957
	 * @since 3.1.0
1958
	 */
1959
	public function setData($value)
1960
	{
1961
		$this->_data=$value;
1962
	}
1963
 
1964
	/**
1965
	 * This property is deprecated since v3.1.0.
1966
	 * @return mixed data associated with the item
1967
	 * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
1968
	 */
1969
	public function getDataItem()
1970
	{
1971
		return $this->getData();
1972
	}
1973
 
1974
	/**
1975
	 * This property is deprecated since v3.1.0.
1976
	 * @param mixed data to be associated with the item
1977
	 * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
1978
	 */
1979
	public function setDataItem($value)
1980
	{
1981
		return $this->setData($value);
1982
	}
1983
 
1984
	/**
1985
	 * This method overrides parent's implementation by wrapping event parameter
1986
	 * for <b>OnCommand</b> event with item information.
1987
	 * @param TControl the sender of the event
1988
	 * @param TEventParameter event parameter
1989
	 * @return boolean whether the event bubbling should stop here.
1990
	 */
1991
	public function bubbleEvent($sender,$param)
1992
	{
1993
		if($param instanceof TCommandEventParameter)
1994
		{
1995
			$this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
1996
			return true;
1997
		}
1998
		else
1999
			return false;
2000
	}
2001
}
2002
 
2003
 
2004
/**
2005
 * TDataGridPager class.
2006
 *
2007
 * TDataGridPager represents a datagrid pager.
2008
 *
2009
 * @author Qiang Xue <qiang.xue@gmail.com>
2010
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
2011
 * @package System.Web.UI.WebControls
2012
 * @since 3.0
2013
 */
2014
class TDataGridPager extends TPanel implements INamingContainer
2015
{
2016
	private $_dataGrid;
2017
 
2018
	/**
2019
	 * Constructor.
2020
	 * @param TDataGrid datagrid object
2021
	 */
2022
	public function __construct($dataGrid)
2023
	{
2024
		$this->_dataGrid=$dataGrid;
2025
	}
2026
 
2027
	/**
2028
	 * This method overrides parent's implementation by wrapping event parameter
2029
	 * for <b>OnCommand</b> event with item information.
2030
	 * @param TControl the sender of the event
2031
	 * @param TEventParameter event parameter
2032
	 * @return boolean whether the event bubbling should stop here.
2033
	 */
2034
	public function bubbleEvent($sender,$param)
2035
	{
2036
		if($param instanceof TCommandEventParameter)
2037
		{
2038
			$this->raiseBubbleEvent($this,new TDataGridCommandEventParameter($this,$sender,$param));
2039
			return true;
2040
		}
2041
		else
2042
			return false;
2043
	}
2044
 
2045
	/**
2046
	 * @return TDataGrid the datagrid owning this pager
2047
	 */
2048
	public function getDataGrid()
2049
	{
2050
		return $this->_dataGrid;
2051
	}
2052
 
2053
	/**
2054
	 * @return string item type.
2055
	 */
2056
	public function getItemType()
2057
	{
2058
		return TListItemType::Pager;
2059
	}
2060
}
2061
 
2062
 
2063
/**
2064
 * TDataGridItemCollection class.
2065
 *
2066
 * TDataGridItemCollection represents a collection of data grid items.
2067
 *
2068
 * @author Qiang Xue <qiang.xue@gmail.com>
2069
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
2070
 * @package System.Web.UI.WebControls
2071
 * @since 3.0
2072
 */
2073
class TDataGridItemCollection extends TList
2074
{
2075
	/**
2076
	 * Inserts an item at the specified position.
2077
	 * This overrides the parent implementation by inserting only TDataGridItem.
2078
	 * @param integer the speicified position.
2079
	 * @param mixed new item
2080
	 * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridItem.
2081
	 */
2082
	public function insertAt($index,$item)
2083
	{
2084
		if($item instanceof TDataGridItem)
2085
			parent::insertAt($index,$item);
2086
		else
2087
			throw new TInvalidDataTypeException('datagriditemcollection_datagriditem_required');
2088
	}
2089
}
2090
 
2091
/**
2092
 * TDataGridColumnCollection class.
2093
 *
2094
 * TDataGridColumnCollection represents a collection of data grid columns.
2095
 *
2096
 * @author Qiang Xue <qiang.xue@gmail.com>
2097
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
2098
 * @package System.Web.UI.WebControls
2099
 * @since 3.0
2100
 */
2101
class TDataGridColumnCollection extends TList
2102
{
2103
	/**
2104
	 * the control that owns this collection.
2105
	 * @var TControl
2106
	 */
2107
	private $_o;
2108
 
2109
	/**
2110
	 * Constructor.
2111
	 * @param TDataGrid the control that owns this collection.
2112
	 */
2113
	public function __construct(TDataGrid $owner)
2114
	{
2115
		$this->_o=$owner;
2116
	}
2117
 
2118
	/**
2119
	 * @return TDataGrid the control that owns this collection.
2120
	 */
2121
	protected function getOwner()
2122
	{
2123
		return $this->_o;
2124
	}
2125
 
2126
	/**
2127
	 * Inserts an item at the specified position.
2128
	 * This overrides the parent implementation by inserting only TDataGridColumn.
2129
	 * @param integer the speicified position.
2130
	 * @param mixed new item
2131
	 * @throws TInvalidDataTypeException if the item to be inserted is not a TDataGridColumn.
2132
	 */
2133
	public function insertAt($index,$item)
2134
	{
2135
		if($item instanceof TDataGridColumn)
2136
		{
2137
			$item->setOwner($this->_o);
2138
			parent::insertAt($index,$item);
2139
		}
2140
		else
2141
			throw new TInvalidDataTypeException('datagridcolumncollection_datagridcolumn_required');
2142
	}
2143
}
2144
 
2145
/**
2146
 * TDataGridPagerMode class.
2147
 * TDataGridPagerMode defines the enumerable type for the possible modes that a datagrid pager can take.
2148
 *
2149
 * The following enumerable values are defined:
2150
 * - NextPrev: pager buttons are displayed as next and previous pages
2151
 * - Numeric: pager buttons are displayed as numeric page numbers
2152
 *
2153
 * @author Qiang Xue <qiang.xue@gmail.com>
2154
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
2155
 * @package System.Web.UI.WebControls
2156
 * @since 3.0.4
2157
 */
2158
class TDataGridPagerMode extends TEnumerable
2159
{
2160
	const NextPrev='NextPrev';
2161
	const Numeric='Numeric';
2162
}
2163
 
2164
 
2165
/**
2166
 * TDataGridPagerButtonType class.
2167
 * TDataGridPagerButtonType defines the enumerable type for the possible types of datagrid pager buttons.
2168
 *
2169
 * The following enumerable values are defined:
2170
 * - LinkButton: link buttons
2171
 * - PushButton: form submit buttons
2172
 *
2173
 * @author Qiang Xue <qiang.xue@gmail.com>
2174
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
2175
 * @package System.Web.UI.WebControls
2176
 * @since 3.0.4
2177
 */
2178
class TDataGridPagerButtonType extends TEnumerable
2179
{
2180
	const LinkButton='LinkButton';
2181
	const PushButton='PushButton';
2182
}
2183
 
2184
 
2185
/**
2186
 * TDataGridPagerPosition class.
2187
 * TDataGridPagerPosition defines the enumerable type for the possible positions that a datagrid pager can be located at.
2188
 *
2189
 * The following enumerable values are defined:
2190
 * - Bottom: pager appears only at the bottom of the data grid.
2191
 * - Top: pager appears only at the top of the data grid.
2192
 * - TopAndBottom: pager appears on both top and bottom of the data grid.
2193
 *
2194
 * @author Qiang Xue <qiang.xue@gmail.com>
2195
 * @version $Id: TDataGrid.php 2541 2008-10-21 15:05:13Z qiang.xue $
2196
 * @package System.Web.UI.WebControls
2197
 * @since 3.0.4
2198
 */
2199
class TDataGridPagerPosition extends TEnumerable
2200
{
2201
	const Bottom='Bottom';
2202
	const Top='Top';
2203
	const TopAndBottom='TopAndBottom';
2204
}
2205