Subversion-Projekte lars-tiefland.prado

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
1 lars 1
<?php
2
/**
3
 * TDataList 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: TDataList.php 2541 2008-10-21 15:05:13Z qiang.xue $
10
 * @package System.Web.UI.WebControls
11
 */
12
 
13
/**
14
 * Includes TBaseDataList class
15
 */
16
Prado::using('System.Web.UI.WebControls.TBaseDataList');
17
/**
18
 * Includes TRepeatInfo class
19
 */
20
Prado::using('System.Web.UI.WebControls.TRepeatInfo');
21
 
22
/**
23
 * TDataList class
24
 *
25
 * TDataList represents a data bound and updatable list control.
26
 *
27
 * Like {@link TRepeater}, TDataList displays its content repeatedly based on
28
 * the data fetched from {@link setDataSource DataSource}.
29
 * The repeated contents in TDataList are called items, which are controls and
30
 * can be accessed through {@link getItems Items}. When {@link dataBind()} is
31
 * invoked, TDataList creates an item for each row of data and binds the data
32
 * row to the item. Optionally, a TDataList can have a header, a footer and/or
33
 * separators between items.
34
 *
35
 * TDataList differs from {@link TRepeater} in that it supports tiling the items
36
 * in different manners and it maintains status of items to handle data update.
37
 *
38
 * The layout of the repeated contents are specified by inline templates.
39
 * TDataList items, header, footer, etc. are being instantiated with the corresponding
40
 * templates when data is being bound to the repeater.
41
 *
42
 * Since v3.1.0, the layout can also be by renderers. A renderer is a control class
43
 * that can be instantiated as datalist items, header, etc. A renderer can thus be viewed
44
 * as an external template (in fact, it can also be non-templated controls).
45
 *
46
 * A renderer can be any control class.
47
 * - If the class implements {@link IDataRenderer}, the <b>Data</b>
48
 * property will be set as the data row during databinding. Many PRADO controls
49
 * implement this interface, such as {@link TLabel}, {@link TTextBox}, etc.
50
 * - If the class implements {@link IItemDataRenderer}, the <b>ItemIndex</b> property will be set
51
 * as the zero-based index of the item in the datalist item collection, and
52
 * the <b>ItemType</b> property as the item's type (such as TListItemType::Item).
53
 * {@link TDataListItemRenderer} may be used as the convenient base class which
54
 * already implements {@link IDataItemRenderer}.
55
 *
56
 * The following properties are used to specify different types of template and renderer
57
 * for a datalist:
58
 * - {@link setItemTemplate ItemTemplate}, {@link setItemRenderer ItemRenderer}:
59
 * for each repeated row of data
60
 * - {@link setAlternatingItemTemplate AlternatingItemTemplate}, {@link setAlternatingItemRenderer AlternatingItemRenderer}:
61
 * for each alternating row of data. If not set, {@link setItemTemplate ItemTemplate} or {@link setItemRenderer ItemRenderer}
62
 * will be used instead.
63
 * - {@link setHeaderTemplate HeaderTemplate}, {@link setHeaderRenderer HeaderRenderer}:
64
 * for the datalist header.
65
 * - {@link setFooterTemplate FooterTemplate}, {@link setFooterRenderer FooterRenderer}:
66
 * for the datalist footer.
67
 * - {@link setSeparatorTemplate SeparatorTemplate}, {@link setSeparatorRenderer SeparatorRenderer}:
68
 * for content to be displayed between items.
69
 * - {@link setEmptyTemplate EmptyTemplate}, {@link setEmptyRenderer EmptyRenderer}:
70
 * used when data bound to the datalist is empty.
71
 * - {@link setEditItemTemplate EditItemTemplate}, {@link setEditItemRenderer EditItemRenderer}:
72
 * for the row being editted.
73
 * - {@link setSelectedItemTemplate SelectedItemTemplate}, {@link setSelectedItemRenderer SelectedItemRenderer}:
74
 * for the row being selected.
75
 *
76
 * If a content type is defined with both a template and a renderer, the latter takes precedence.
77
 *
78
 * When {@link dataBind()} is being called, TDataList undergoes the following lifecycles for each row of data:
79
 * - create item based on templates or renderers
80
 * - set the row of data to the item
81
 * - raise {@link onItemCreated OnItemCreated}:
82
 * - add the item as a child control
83
 * - call dataBind() of the item
84
 * - raise {@link onItemDataBound OnItemDataBound}:
85
 *
86
 * TDataList raises an {@link onItemCommand OnItemCommand} whenever a button control
87
 * within some datalist item raises a <b>OnCommand</b> event. Therefore,
88
 * you can handle all sorts of <b>OnCommand</b> event in a central place by
89
 * writing an event handler for {@link onItemCommand OnItemCommand}.
90
 *
91
 * An additional event is raised if the <b>OnCommand</b> event has one of the following
92
 * command names:
93
 * - edit: user wants to edit an item. <b>OnEditCommand</b> event will be raised.
94
 * - update: user wants to save the change to an item. <b>OnUpdateCommand</b> event will be raised.
95
 * - select: user selects an item. <b>OnSelectedIndexChanged</b> event will be raised.
96
 * - delete: user deletes an item. <b>OnDeleteCommand</b> event will be raised.
97
 * - cancel: user cancels previously editting action. <b>OnCancelCommand</b> event will be raised.
98
 *
99
 * TDataList provides a few properties to support tiling the items.
100
 * The number of columns used to display the data items is specified via
101
 * {@link setRepeatColumns RepeatColumns} property, while the {@link setRepeatDirection RepeatDirection}
102
 * governs the order of the items being rendered.
103
 * The layout of the data items in the list is specified via {@link setRepeatLayout RepeatLayout},
104
 * which can take one of the following values:
105
 * - Table (default): items are organized using HTML table and cells.
106
 * When using this layout, one can set {@link setCellPadding CellPadding} and
107
 * {@link setCellSpacing CellSpacing} to adjust the cellpadding and cellpadding
108
 * of the table, and {@link setCaption Caption} and {@link setCaptionAlign CaptionAlign}
109
 * to add a table caption with the specified alignment.
110
 * - Flow: items are organized using HTML spans and breaks.
111
 * - Raw: TDataList does not generate any HTML tags to do the tiling.
112
 *
113
 * Items in TDataList can be in one of the three status: normal browsing,
114
 * being editted and being selected. To change the status of a particular
115
 * item, set {@link setSelectedItemIndex SelectedItemIndex} or
116
 * {@link setEditItemIndex EditItemIndex}. The former will change
117
 * the indicated item to selected mode, which will cause the item to
118
 * use {@link setSelectedItemTemplate SelectedItemTemplate} or
119
 * {@link setSelectedItemRenderer SelectedItemRenderer} for presentation.
120
 * The latter will change the indicated item to edit mode and to use corresponding
121
 * template or renderer.
122
 * Note, if an item is in edit mode, then selecting this item will have no effect.
123
 *
124
 * Different styles may be applied to items in different status. The style
125
 * application is performed in a hierarchical way: Style in higher hierarchy
126
 * will inherit from styles in lower hierarchy.
127
 * Starting from the lowest hierarchy, the item styles include
128
 * - item's own style
129
 * - {@link getItemStyle ItemStyle}
130
 * - {@link getAlternatingItemStyle AlternatingItemStyle}
131
 * - {@link getSelectedItemStyle SelectedItemStyle}
132
 * - {@link getEditItemStyle EditItemStyle}.
133
 * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
134
 * {@link getEditItemStyle EditItemStyle} will also have red background color
135
 * unless it is set to a different value explicitly.
136
 *
137
 * When a page containing a datalist is post back, the datalist will restore automatically
138
 * all its contents, including items, header, footer and separators.
139
 * However, the data row associated with each item will not be recovered and become null.
140
 * To access the data, use one of the following ways:
141
 * - Use {@link getDataKeys DataKeys} to obtain the data key associated with
142
 * the specified datalist item and use the key to fetch the corresponding data
143
 * from some persistent storage such as DB.
144
 * - Save the whole dataset in viewstate, which will restore the dataset automatically upon postback.
145
 * Be aware though, if the size of your dataset is big, your page size will become big. Some
146
 * complex data may also have serializing problem if saved in viewstate.
147
 *
148
 * @author Qiang Xue <qiang.xue@gmail.com>
149
 * @version $Id: TDataList.php 2541 2008-10-21 15:05:13Z qiang.xue $
150
 * @package System.Web.UI.WebControls
151
 * @since 3.0
152
 */
153
class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUser
154
{
155
	/**
156
	 * Command name that TDataList understands. They are case-insensitive.
157
	 */
158
	const CMD_SELECT='Select';
159
	const CMD_EDIT='Edit';
160
	const CMD_UPDATE='Update';
161
	const CMD_DELETE='Delete';
162
	const CMD_CANCEL='Cancel';
163
 
164
	/**
165
	 * @var TDataListItemCollection item list
166
	 */
167
	private $_items=null;
168
	/**
169
	 * @var Itemplate various item templates
170
	 */
171
	private $_itemTemplate=null;
172
	private $_emptyTemplate=null;
173
	private $_alternatingItemTemplate=null;
174
	private $_selectedItemTemplate=null;
175
	private $_editItemTemplate=null;
176
	private $_headerTemplate=null;
177
	private $_footerTemplate=null;
178
	private $_separatorTemplate=null;
179
	/**
180
	 * @var TControl header item
181
	 */
182
	private $_header=null;
183
	/**
184
	 * @var TControl footer item
185
	 */
186
	private $_footer=null;
187
 
188
	/**
189
	 * @return TDataListItemCollection item list
190
	 */
191
	public function getItems()
192
	{
193
		if(!$this->_items)
194
			$this->_items=new TDataListItemCollection;
195
		return $this->_items;
196
	}
197
 
198
	/**
199
	 * @return integer number of items
200
	 */
201
	public function getItemCount()
202
	{
203
		return $this->_items?$this->_items->getCount():0;
204
	}
205
 
206
	/**
207
	 * @return string the class name for datalist items. Defaults to empty, meaning not set.
208
	 * @since 3.1.0
209
	 */
210
	public function getItemRenderer()
211
	{
212
		return $this->getViewState('ItemRenderer','');
213
	}
214
 
215
	/**
216
	 * Sets the item renderer class.
217
	 *
218
	 * If not empty, the class will be used to instantiate as datalist items.
219
	 * This property takes precedence over {@link getItemTemplate ItemTemplate}.
220
	 *
221
	 * @param string the renderer class name in namespace format.
222
	 * @see setItemTemplate
223
	 * @since 3.1.0
224
	 */
225
	public function setItemRenderer($value)
226
	{
227
		$this->setViewState('ItemRenderer',$value,'');
228
	}
229
 
230
	/**
231
	 * @return string the class name for alternative datalist items. Defaults to empty, meaning not set.
232
	 * @since 3.1.0
233
	 */
234
	public function getAlternatingItemRenderer()
235
	{
236
		return $this->getViewState('AlternatingItemRenderer','');
237
	}
238
 
239
	/**
240
	 * Sets the alternative item renderer class.
241
	 *
242
	 * If not empty, the class will be used to instantiate as alternative datalist items.
243
	 * This property takes precedence over {@link getAlternatingItemTemplate AlternatingItemTemplate}.
244
	 *
245
	 * @param string the renderer class name in namespace format.
246
	 * @see setAlternatingItemTemplate
247
	 * @since 3.1.0
248
	 */
249
	public function setAlternatingItemRenderer($value)
250
	{
251
		$this->setViewState('AlternatingItemRenderer',$value,'');
252
	}
253
 
254
	/**
255
	 * @return string the class name for the datalist item being editted. Defaults to empty, meaning not set.
256
	 * @since 3.1.0
257
	 */
258
	public function getEditItemRenderer()
259
	{
260
		return $this->getViewState('EditItemRenderer','');
261
	}
262
 
263
	/**
264
	 * Sets the renderer class for the datalist item being editted.
265
	 *
266
	 * If not empty, the class will be used to instantiate as the datalist item.
267
	 * This property takes precedence over {@link getEditItemTemplate EditItemTemplate}.
268
	 *
269
	 * @param string the renderer class name in namespace format.
270
	 * @see setEditItemTemplate
271
	 * @since 3.1.0
272
	 */
273
	public function setEditItemRenderer($value)
274
	{
275
		$this->setViewState('EditItemRenderer',$value,'');
276
	}
277
 
278
	/**
279
	 * @return string the class name for the datalist item being selected. Defaults to empty, meaning not set.
280
	 * @since 3.1.0
281
	 */
282
	public function getSelectedItemRenderer()
283
	{
284
		return $this->getViewState('SelectedItemRenderer','');
285
	}
286
 
287
	/**
288
	 * Sets the renderer class for the datalist item being selected.
289
	 *
290
	 * If not empty, the class will be used to instantiate as the datalist item.
291
	 * This property takes precedence over {@link getSelectedItemTemplate SelectedItemTemplate}.
292
	 *
293
	 * @param string the renderer class name in namespace format.
294
	 * @see setSelectedItemTemplate
295
	 * @since 3.1.0
296
	 */
297
	public function setSelectedItemRenderer($value)
298
	{
299
		$this->setViewState('SelectedItemRenderer',$value,'');
300
	}
301
 
302
	/**
303
	 * @return string the class name for datalist item separators. Defaults to empty, meaning not set.
304
	 * @since 3.1.0
305
	 */
306
	public function getSeparatorRenderer()
307
	{
308
		return $this->getViewState('SeparatorRenderer','');
309
	}
310
 
311
	/**
312
	 * Sets the datalist item separator renderer class.
313
	 *
314
	 * If not empty, the class will be used to instantiate as datalist item separators.
315
	 * This property takes precedence over {@link getSeparatorTemplate SeparatorTemplate}.
316
	 *
317
	 * @param string the renderer class name in namespace format.
318
	 * @see setSeparatorTemplate
319
	 * @since 3.1.0
320
	 */
321
	public function setSeparatorRenderer($value)
322
	{
323
		$this->setViewState('SeparatorRenderer',$value,'');
324
	}
325
 
326
	/**
327
	 * @return string the class name for datalist header item. Defaults to empty, meaning not set.
328
	 * @since 3.1.0
329
	 */
330
	public function getHeaderRenderer()
331
	{
332
		return $this->getViewState('HeaderRenderer','');
333
	}
334
 
335
	/**
336
	 * Sets the datalist header renderer class.
337
	 *
338
	 * If not empty, the class will be used to instantiate as datalist header item.
339
	 * This property takes precedence over {@link getHeaderTemplate HeaderTemplate}.
340
	 *
341
	 * @param string the renderer class name in namespace format.
342
	 * @see setHeaderTemplate
343
	 * @since 3.1.0
344
	 */
345
	public function setHeaderRenderer($value)
346
	{
347
		$this->setViewState('HeaderRenderer',$value,'');
348
	}
349
 
350
	/**
351
	 * @return string the class name for datalist footer item. Defaults to empty, meaning not set.
352
	 * @since 3.1.0
353
	 */
354
	public function getFooterRenderer()
355
	{
356
		return $this->getViewState('FooterRenderer','');
357
	}
358
 
359
	/**
360
	 * Sets the datalist footer renderer class.
361
	 *
362
	 * If not empty, the class will be used to instantiate as datalist footer item.
363
	 * This property takes precedence over {@link getFooterTemplate FooterTemplate}.
364
	 *
365
	 * @param string the renderer class name in namespace format.
366
	 * @see setFooterTemplate
367
	 * @since 3.1.0
368
	 */
369
	public function setFooterRenderer($value)
370
	{
371
		$this->setViewState('FooterRenderer',$value,'');
372
	}
373
 
374
	/**
375
	 * @return string the class name for empty datalist item. Defaults to empty, meaning not set.
376
	 * @since 3.1.0
377
	 */
378
	public function getEmptyRenderer()
379
	{
380
		return $this->getViewState('EmptyRenderer','');
381
	}
382
 
383
	/**
384
	 * Sets the datalist empty renderer class.
385
	 *
386
	 * The empty renderer is created as the child of the datalist
387
	 * if data bound to the datalist is empty.
388
	 * This property takes precedence over {@link getEmptyTemplate EmptyTemplate}.
389
	 *
390
	 * @param string the renderer class name in namespace format.
391
	 * @see setEmptyTemplate
392
	 * @since 3.1.0
393
	 */
394
	public function setEmptyRenderer($value)
395
	{
396
		$this->setViewState('EmptyRenderer',$value,'');
397
	}
398
 
399
	/**
400
	 * @return ITemplate the template for item
401
	 */
402
	public function getItemTemplate()
403
	{
404
		return $this->_itemTemplate;
405
	}
406
 
407
	/**
408
	 * @param ITemplate the template for item
409
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
410
	 */
411
	public function setItemTemplate($value)
412
	{
413
		if($value instanceof ITemplate || $value===null)
414
			$this->_itemTemplate=$value;
415
		else
416
			throw new TInvalidDataTypeException('datalist_template_required','ItemTemplate');
417
	}
418
 
419
	/**
420
	 * @return TTableItemStyle the style for item
421
	 */
422
	public function getItemStyle()
423
	{
424
		if(($style=$this->getViewState('ItemStyle',null))===null)
425
		{
426
			$style=new TTableItemStyle;
427
			$this->setViewState('ItemStyle',$style,null);
428
		}
429
		return $style;
430
	}
431
 
432
	/**
433
	 * @return ITemplate the template for each alternating item
434
	 */
435
	public function getAlternatingItemTemplate()
436
	{
437
		return $this->_alternatingItemTemplate;
438
	}
439
 
440
	/**
441
	 * @param ITemplate the template for each alternating item
442
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
443
	 */
444
	public function setAlternatingItemTemplate($value)
445
	{
446
		if($value instanceof ITemplate || $value===null)
447
			$this->_alternatingItemTemplate=$value;
448
		else
449
			throw new TInvalidDataTypeException('datalist_template_required','AlternatingItemType');
450
	}
451
 
452
	/**
453
	 * @return TTableItemStyle the style for each alternating item
454
	 */
455
	public function getAlternatingItemStyle()
456
	{
457
		if(($style=$this->getViewState('AlternatingItemStyle',null))===null)
458
		{
459
			$style=new TTableItemStyle;
460
			$this->setViewState('AlternatingItemStyle',$style,null);
461
		}
462
		return $style;
463
	}
464
 
465
	/**
466
	 * @return ITemplate the selected item template
467
	 */
468
	public function getSelectedItemTemplate()
469
	{
470
		return $this->_selectedItemTemplate;
471
	}
472
 
473
	/**
474
	 * @param ITemplate the selected item template
475
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
476
	 */
477
	public function setSelectedItemTemplate($value)
478
	{
479
		if($value instanceof ITemplate || $value===null)
480
			$this->_selectedItemTemplate=$value;
481
		else
482
			throw new TInvalidDataTypeException('datalist_template_required','SelectedItemTemplate');
483
	}
484
 
485
	/**
486
	 * @return TTableItemStyle the style for selected item
487
	 */
488
	public function getSelectedItemStyle()
489
	{
490
		if(($style=$this->getViewState('SelectedItemStyle',null))===null)
491
		{
492
			$style=new TTableItemStyle;
493
			$this->setViewState('SelectedItemStyle',$style,null);
494
		}
495
		return $style;
496
	}
497
 
498
	/**
499
	 * @return ITemplate the edit item template
500
	 */
501
	public function getEditItemTemplate()
502
	{
503
		return $this->_editItemTemplate;
504
	}
505
 
506
	/**
507
	 * @param ITemplate the edit item template
508
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
509
	 */
510
	public function setEditItemTemplate($value)
511
	{
512
		if($value instanceof ITemplate || $value===null)
513
			$this->_editItemTemplate=$value;
514
		else
515
			throw new TInvalidDataTypeException('datalist_template_required','EditItemTemplate');
516
	}
517
 
518
	/**
519
	 * @return TTableItemStyle the style for edit item
520
	 */
521
	public function getEditItemStyle()
522
	{
523
		if(($style=$this->getViewState('EditItemStyle',null))===null)
524
		{
525
			$style=new TTableItemStyle;
526
			$this->setViewState('EditItemStyle',$style,null);
527
		}
528
		return $style;
529
	}
530
 
531
	/**
532
	 * @return ITemplate the header template
533
	 */
534
	public function getHeaderTemplate()
535
	{
536
		return $this->_headerTemplate;
537
	}
538
 
539
	/**
540
	 * @param ITemplate the header template
541
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
542
	 */
543
	public function setHeaderTemplate($value)
544
	{
545
		if($value instanceof ITemplate || $value===null)
546
			$this->_headerTemplate=$value;
547
		else
548
			throw new TInvalidDataTypeException('datalist_template_required','HeaderTemplate');
549
	}
550
 
551
	/**
552
	 * @return TTableItemStyle the style for header
553
	 */
554
	public function getHeaderStyle()
555
	{
556
		if(($style=$this->getViewState('HeaderStyle',null))===null)
557
		{
558
			$style=new TTableItemStyle;
559
			$this->setViewState('HeaderStyle',$style,null);
560
		}
561
		return $style;
562
	}
563
 
564
	/**
565
	 * @return TControl the header item
566
	 */
567
	public function getHeader()
568
	{
569
		return $this->_header;
570
	}
571
 
572
	/**
573
	 * @return ITemplate the footer template
574
	 */
575
	public function getFooterTemplate()
576
	{
577
		return $this->_footerTemplate;
578
	}
579
 
580
	/**
581
	 * @param ITemplate the footer template
582
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
583
	 */
584
	public function setFooterTemplate($value)
585
	{
586
		if($value instanceof ITemplate || $value===null)
587
			$this->_footerTemplate=$value;
588
		else
589
			throw new TInvalidDataTypeException('datalist_template_required','FooterTemplate');
590
	}
591
 
592
	/**
593
	 * @return TTableItemStyle the style for footer
594
	 */
595
	public function getFooterStyle()
596
	{
597
		if(($style=$this->getViewState('FooterStyle',null))===null)
598
		{
599
			$style=new TTableItemStyle;
600
			$this->setViewState('FooterStyle',$style,null);
601
		}
602
		return $style;
603
	}
604
 
605
	/**
606
	 * @return TControl the footer item
607
	 */
608
	public function getFooter()
609
	{
610
		return $this->_footer;
611
	}
612
 
613
	/**
614
	 * @return ITemplate the template applied when no data is bound to the datalist
615
	 */
616
	public function getEmptyTemplate()
617
	{
618
		return $this->_emptyTemplate;
619
	}
620
 
621
	/**
622
	 * @param ITemplate the template applied when no data is bound to the datalist
623
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
624
	 */
625
	public function setEmptyTemplate($value)
626
	{
627
		if($value instanceof ITemplate || $value===null)
628
			$this->_emptyTemplate=$value;
629
		else
630
			throw new TInvalidDataTypeException('datalist_template_required','EmptyTemplate');
631
	}
632
 
633
	/**
634
	 * @return ITemplate the separator template
635
	 */
636
	public function getSeparatorTemplate()
637
	{
638
		return $this->_separatorTemplate;
639
	}
640
 
641
	/**
642
	 * @param ITemplate the separator template
643
	 * @throws TInvalidDataTypeException if the input is not an {@link ITemplate} or not null.
644
	 */
645
	public function setSeparatorTemplate($value)
646
	{
647
		if($value instanceof ITemplate || $value===null)
648
			$this->_separatorTemplate=$value;
649
		else
650
			throw new TInvalidDataTypeException('datalist_template_required','SeparatorTemplate');
651
	}
652
 
653
	/**
654
	 * @return TTableItemStyle the style for separator
655
	 */
656
	public function getSeparatorStyle()
657
	{
658
		if(($style=$this->getViewState('SeparatorStyle',null))===null)
659
		{
660
			$style=new TTableItemStyle;
661
			$this->setViewState('SeparatorStyle',$style,null);
662
		}
663
		return $style;
664
	}
665
 
666
	/**
667
	 * @return integer the zero-based index of the selected item in {@link getItems Items}.
668
	 * A value -1 means no item selected.
669
	 */
670
	public function getSelectedItemIndex()
671
	{
672
		return $this->getViewState('SelectedItemIndex',-1);
673
	}
674
 
675
	/**
676
	 * Selects an item by its index in {@link getItems Items}.
677
	 * Previously selected item will be un-selected.
678
	 * If the item to be selected is already in edit mode, it will remain in edit mode.
679
	 * If the index is less than 0, any existing selection will be cleared up.
680
	 * @param integer the selected item index
681
	 */
682
	public function setSelectedItemIndex($value)
683
	{
684
		if(($value=TPropertyValue::ensureInteger($value))<0)
685
			$value=-1;
686
		if(($current=$this->getSelectedItemIndex())!==$value)
687
		{
688
			$this->setViewState('SelectedItemIndex',$value,-1);
689
			$items=$this->getItems();
690
			$itemCount=$items->getCount();
691
			if($current>=0 && $current<$itemCount)
692
			{
693
				$item=$items->itemAt($current);
694
				if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
695
					$item->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
696
			}
697
			if($value>=0 && $value<$itemCount)
698
			{
699
				$item=$items->itemAt($value);
700
				if(($item instanceof IItemDataRenderer) && $item->getItemType()!==TListItemType::EditItem)
701
					$item->setItemType(TListItemType::SelectedItem);
702
			}
703
		}
704
	}
705
 
706
	/**
707
	 * @return TControl the selected item, null if no item is selected.
708
	 */
709
	public function getSelectedItem()
710
	{
711
		$index=$this->getSelectedItemIndex();
712
		$items=$this->getItems();
713
		if($index>=0 && $index<$items->getCount())
714
			return $items->itemAt($index);
715
		else
716
			return null;
717
	}
718
 
719
	/**
720
	 * @return mixed the key value of the currently selected item
721
	 * @throws TInvalidOperationException if {@link getDataKeyField DataKeyField} is empty.
722
	 */
723
	public function getSelectedDataKey()
724
	{
725
		if($this->getDataKeyField()==='')
726
			throw new TInvalidOperationException('datalist_datakeyfield_required');
727
		$index=$this->getSelectedItemIndex();
728
		$dataKeys=$this->getDataKeys();
729
		if($index>=0 && $index<$dataKeys->getCount())
730
			return $dataKeys->itemAt($index);
731
		else
732
			return null;
733
	}
734
 
735
	/**
736
	 * @return integer the zero-based index of the edit item in {@link getItems Items}.
737
	 * A value -1 means no item is in edit mode.
738
	 */
739
	public function getEditItemIndex()
740
	{
741
		return $this->getViewState('EditItemIndex',-1);
742
	}
743
 
744
	/**
745
	 * Edits an item by its index in {@link getItems Items}.
746
	 * Previously editting item will change to normal item state.
747
	 * If the index is less than 0, any existing edit item will be cleared up.
748
	 * @param integer the edit item index
749
	 */
750
	public function setEditItemIndex($value)
751
	{
752
		if(($value=TPropertyValue::ensureInteger($value))<0)
753
			$value=-1;
754
		if(($current=$this->getEditItemIndex())!==$value)
755
		{
756
			$this->setViewState('EditItemIndex',$value,-1);
757
			$items=$this->getItems();
758
			$itemCount=$items->getCount();
759
			if($current>=0 && $current<$itemCount)
760
				$items->itemAt($current)->setItemType($current%2?TListItemType::AlternatingItem : TListItemType::Item);
761
			if($value>=0 && $value<$itemCount)
762
				$items->itemAt($value)->setItemType(TListItemType::EditItem);
763
		}
764
	}
765
 
766
	/**
767
	 * @return TControl the edit item
768
	 */
769
	public function getEditItem()
770
	{
771
		$index=$this->getEditItemIndex();
772
		$items=$this->getItems();
773
		if($index>=0 && $index<$items->getCount())
774
			return $items->itemAt($index);
775
		else
776
			return null;
777
	}
778
 
779
	/**
780
	 * @return boolean whether the header should be shown. Defaults to true.
781
	 */
782
	public function getShowHeader()
783
	{
784
		return $this->getViewState('ShowHeader',true);
785
	}
786
 
787
	/**
788
	 * @param boolean whether to show header
789
	 */
790
	public function setShowHeader($value)
791
	{
792
		$this->setViewState('ShowHeader',TPropertyValue::ensureBoolean($value),true);
793
	}
794
 
795
	/**
796
	 * @return boolean whether the footer should be shown. Defaults to true.
797
	 */
798
	public function getShowFooter()
799
	{
800
		return $this->getViewState('ShowFooter',true);
801
	}
802
 
803
	/**
804
	 * @param boolean whether to show footer
805
	 */
806
	public function setShowFooter($value)
807
	{
808
		$this->setViewState('ShowFooter',TPropertyValue::ensureBoolean($value),true);
809
	}
810
 
811
	/**
812
	 * @return TRepeatInfo repeat information (primarily used by control developers)
813
	 */
814
	protected function getRepeatInfo()
815
	{
816
		if(($repeatInfo=$this->getViewState('RepeatInfo',null))===null)
817
		{
818
			$repeatInfo=new TRepeatInfo;
819
			$this->setViewState('RepeatInfo',$repeatInfo,null);
820
		}
821
		return $repeatInfo;
822
	}
823
 
824
	/**
825
	 * @return string caption of the table layout
826
	 */
827
	public function getCaption()
828
	{
829
		return $this->getRepeatInfo()->getCaption();
830
	}
831
 
832
	/**
833
	 * @param string caption of the table layout
834
	 */
835
	public function setCaption($value)
836
	{
837
		$this->getRepeatInfo()->setCaption($value);
838
	}
839
 
840
	/**
841
	 * @return TTableCaptionAlign alignment of the caption of the table layout. Defaults to TTableCaptionAlign::NotSet.
842
	 */
843
	public function getCaptionAlign()
844
	{
845
		return $this->getRepeatInfo()->getCaptionAlign();
846
	}
847
 
848
	/**
849
	 * @return TTableCaptionAlign alignment of the caption of the table layout.
850
	 */
851
	public function setCaptionAlign($value)
852
	{
853
		$this->getRepeatInfo()->setCaptionAlign($value);
854
	}
855
 
856
	/**
857
	 * @return integer the number of columns that the list should be displayed with. Defaults to 0 meaning not set.
858
	 */
859
	public function getRepeatColumns()
860
	{
861
		return $this->getRepeatInfo()->getRepeatColumns();
862
	}
863
 
864
	/**
865
	 * @param integer the number of columns that the list should be displayed with.
866
	 */
867
	public function setRepeatColumns($value)
868
	{
869
		$this->getRepeatInfo()->setRepeatColumns($value);
870
	}
871
 
872
	/**
873
	 * @return TRepeatDirection the direction of traversing the list, defaults to TRepeatDirection::Vertical
874
	 */
875
	public function getRepeatDirection()
876
	{
877
		return $this->getRepeatInfo()->getRepeatDirection();
878
	}
879
 
880
	/**
881
	 * @param TRepeatDirection the direction of traversing the list
882
	 */
883
	public function setRepeatDirection($value)
884
	{
885
		$this->getRepeatInfo()->setRepeatDirection($value);
886
	}
887
 
888
	/**
889
	 * @return TRepeatLayout how the list should be displayed, using table or using line breaks. Defaults to TRepeatLayout::Table.
890
	 */
891
	public function getRepeatLayout()
892
	{
893
		return $this->getRepeatInfo()->getRepeatLayout();
894
	}
895
 
896
	/**
897
	 * @param TRepeatLayout how the list should be displayed, using table or using line breaks
898
	 */
899
	public function setRepeatLayout($value)
900
	{
901
		$this->getRepeatInfo()->setRepeatLayout($value);
902
	}
903
 
904
	/**
905
	 * This method overrides parent's implementation to handle
906
	 * {@link onItemCommand OnItemCommand} event which is bubbled from
907
	 * datalist items and their child controls.
908
	 * If the event parameter is {@link TDataListCommandEventParameter} and
909
	 * the command name is a recognized one, which includes 'select', 'edit',
910
	 * 'delete', 'update', and 'cancel' (case-insensitive), then a
911
	 * corresponding command event is also raised (such as {@link onEditCommand OnEditCommand}).
912
	 * This method should only be used by control developers.
913
	 * @param TControl the sender of the event
914
	 * @param TEventParameter event parameter
915
	 * @return boolean whether the event bubbling should stop here.
916
	 */
917
	public function bubbleEvent($sender,$param)
918
	{
919
		if($param instanceof TDataListCommandEventParameter)
920
		{
921
			$this->onItemCommand($param);
922
			$command=$param->getCommandName();
923
			if(strcasecmp($command,self::CMD_SELECT)===0)
924
			{
925
				if(($item=$param->getItem()) instanceof IItemDataRenderer)
926
					$this->setSelectedItemIndex($item->getItemIndex());
927
				$this->onSelectedIndexChanged($param);
928
				return true;
929
			}
930
			else if(strcasecmp($command,self::CMD_EDIT)===0)
931
			{
932
				$this->onEditCommand($param);
933
				return true;
934
			}
935
			else if(strcasecmp($command,self::CMD_DELETE)===0)
936
			{
937
				$this->onDeleteCommand($param);
938
				return true;
939
			}
940
			else if(strcasecmp($command,self::CMD_UPDATE)===0)
941
			{
942
				$this->onUpdateCommand($param);
943
				return true;
944
			}
945
			else if(strcasecmp($command,self::CMD_CANCEL)===0)
946
			{
947
				$this->onCancelCommand($param);
948
				return true;
949
			}
950
		}
951
		return false;
952
	}
953
 
954
 
955
	/**
956
	 * Raises <b>OnItemCreated</b> event.
957
	 * This method is invoked after a data list item is created and instantiated with
958
	 * template, but before added to the page hierarchy.
959
	 * The datalist item control responsible for the event
960
	 * can be determined from the event parameter.
961
	 * If you override this method, be sure to call parent's implementation
962
	 * so that event handlers have chance to respond to the event.
963
	 * @param TDataListItemEventParameter event parameter
964
	 */
965
	public function onItemCreated($param)
966
	{
967
		$this->raiseEvent('OnItemCreated',$this,$param);
968
	}
969
 
970
	/**
971
	 * Raises <b>OnItemDataBound</b> event.
972
	 * This method is invoked right after an item is data bound.
973
	 * The datalist item control responsible for the event
974
	 * can be determined from the event parameter.
975
	 * If you override this method, be sure to call parent's implementation
976
	 * so that event handlers have chance to respond to the event.
977
	 * @param TDataListItemEventParameter event parameter
978
	 */
979
	public function onItemDataBound($param)
980
	{
981
		$this->raiseEvent('OnItemDataBound',$this,$param);
982
	}
983
 
984
	/**
985
	 * Raises <b>OnItemCommand</b> event.
986
	 * This method is invoked when a child control of the data list
987
	 * raises an <b>OnCommand</b> event.
988
	 * @param TDataListCommandEventParameter event parameter
989
	 */
990
	public function onItemCommand($param)
991
	{
992
		$this->raiseEvent('OnItemCommand',$this,$param);
993
	}
994
 
995
	/**
996
	 * Raises <b>OnEditCommand</b> event.
997
	 * This method is invoked when a child control of the data list
998
	 * raises an <b>OnCommand</b> event and the command name is 'edit' (case-insensitive).
999
	 * @param TDataListCommandEventParameter event parameter
1000
	 */
1001
	public function onEditCommand($param)
1002
	{
1003
		$this->raiseEvent('OnEditCommand',$this,$param);
1004
	}
1005
 
1006
	/**
1007
	 * Raises <b>OnDeleteCommand</b> event.
1008
	 * This method is invoked when a child control of the data list
1009
	 * raises an <b>OnCommand</b> event and the command name is 'delete' (case-insensitive).
1010
	 * @param TDataListCommandEventParameter event parameter
1011
	 */
1012
	public function onDeleteCommand($param)
1013
	{
1014
		$this->raiseEvent('OnDeleteCommand',$this,$param);
1015
	}
1016
 
1017
	/**
1018
	 * Raises <b>OnUpdateCommand</b> event.
1019
	 * This method is invoked when a child control of the data list
1020
	 * raises an <b>OnCommand</b> event and the command name is 'update' (case-insensitive).
1021
	 * @param TDataListCommandEventParameter event parameter
1022
	 */
1023
	public function onUpdateCommand($param)
1024
	{
1025
		$this->raiseEvent('OnUpdateCommand',$this,$param);
1026
	}
1027
 
1028
	/**
1029
	 * Raises <b>OnCancelCommand</b> event.
1030
	 * This method is invoked when a child control of the data list
1031
	 * raises an <b>OnCommand</b> event and the command name is 'cancel' (case-insensitive).
1032
	 * @param TDataListCommandEventParameter event parameter
1033
	 */
1034
	public function onCancelCommand($param)
1035
	{
1036
		$this->raiseEvent('OnCancelCommand',$this,$param);
1037
	}
1038
 
1039
	/**
1040
	 * Returns a value indicating whether this control contains header item.
1041
	 * This method is required by {@link IRepeatInfoUser} interface.
1042
	 * @return boolean whether the datalist has header
1043
	 */
1044
	public function getHasHeader()
1045
	{
1046
		return ($this->getShowHeader() && ($this->_headerTemplate!==null || $this->getHeaderRenderer()!==''));
1047
	}
1048
 
1049
	/**
1050
	 * Returns a value indicating whether this control contains footer item.
1051
	 * This method is required by {@link IRepeatInfoUser} interface.
1052
	 * @return boolean whether the datalist has footer
1053
	 */
1054
	public function getHasFooter()
1055
	{
1056
		return ($this->getShowFooter() && ($this->_footerTemplate!==null || $this->getFooterRenderer()!==''));
1057
	}
1058
 
1059
	/**
1060
	 * Returns a value indicating whether this control contains separator items.
1061
	 * This method is required by {@link IRepeatInfoUser} interface.
1062
	 * @return boolean always false.
1063
	 */
1064
	public function getHasSeparators()
1065
	{
1066
		return $this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
1067
	}
1068
 
1069
	/**
1070
	 * Returns a style used for rendering items.
1071
	 * This method is required by {@link IRepeatInfoUser} interface.
1072
	 * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
1073
	 * @param integer index of the item being rendered
1074
	 * @return TStyle item style
1075
	 */
1076
	public function generateItemStyle($itemType,$index)
1077
	{
1078
		if(($item=$this->getItem($itemType,$index))!==null && ($item instanceof IStyleable) && $item->getHasStyle())
1079
		{
1080
			$style=$item->getStyle();
1081
			$item->clearStyle();
1082
			return $style;
1083
		}
1084
		else
1085
			return null;
1086
	}
1087
 
1088
	/**
1089
	 * Renders an item in the list.
1090
	 * This method is required by {@link IRepeatInfoUser} interface.
1091
	 * @param THtmlWriter writer for rendering purpose
1092
	 * @param TRepeatInfo repeat information
1093
	 * @param string item type (Header,Footer,Item,AlternatingItem,SelectedItem,EditItem,Separator,Pager)
1094
	 * @param integer zero-based index of the item in the item list
1095
	 */
1096
	public function renderItem($writer,$repeatInfo,$itemType,$index)
1097
	{
1098
		$item=$this->getItem($itemType,$index);
1099
		if($repeatInfo->getRepeatLayout()===TRepeatLayout::Raw && get_class($item)==='TDataListItem')
1100
			$item->setTagName('div');
1101
		$item->renderControl($writer);
1102
	}
1103
 
1104
	/**
1105
	 * @param TListItemType item type
1106
	 * @param integer item index
1107
	 * @return TControl data list item with the specified item type and index
1108
	 */
1109
	private function getItem($itemType,$index)
1110
	{
1111
		switch($itemType)
1112
		{
1113
			case TListItemType::Item:
1114
			case TListItemType::AlternatingItem:
1115
			case TListItemType::SelectedItem:
1116
			case TListItemType::EditItem:
1117
				return $this->getItems()->itemAt($index);
1118
			case TListItemType::Header:
1119
				return $this->getControls()->itemAt(0);
1120
			case TListItemType::Footer:
1121
				return $this->getControls()->itemAt($this->getControls()->getCount()-1);
1122
			case TListItemType::Separator:
1123
				$i=$index+$index+1;
1124
				if($this->_headerTemplate!==null || $this->getHeaderRenderer()!=='')
1125
					$i++;
1126
				return $this->getControls()->itemAt($i);
1127
		}
1128
		return null;
1129
	}
1130
 
1131
	/**
1132
	 * Creates a datalist item.
1133
	 * This method invokes {@link createItem} to create a new datalist item.
1134
	 * @param integer zero-based item index.
1135
	 * @param TListItemType item type
1136
	 * @return TControl the created item, null if item is not created
1137
	 */
1138
	private function createItemInternal($itemIndex,$itemType)
1139
	{
1140
		if(($item=$this->createItem($itemIndex,$itemType))!==null)
1141
		{
1142
			$param=new TDataListItemEventParameter($item);
1143
			$this->onItemCreated($param);
1144
			$this->getControls()->add($item);
1145
			return $item;
1146
		}
1147
		else
1148
			return null;
1149
	}
1150
 
1151
	/**
1152
	 * Creates a datalist item and performs databinding.
1153
	 * This method invokes {@link createItem} to create a new datalist item.
1154
	 * @param integer zero-based item index.
1155
	 * @param TListItemType item type
1156
	 * @param mixed data to be associated with the item
1157
	 * @return TControl the created item, null if item is not created
1158
	 */
1159
	private function createItemWithDataInternal($itemIndex,$itemType,$dataItem)
1160
	{
1161
		if(($item=$this->createItem($itemIndex,$itemType))!==null)
1162
		{
1163
			$param=new TDataListItemEventParameter($item);
1164
			if($item instanceof IDataRenderer)
1165
				$item->setData($dataItem);
1166
			$this->onItemCreated($param);
1167
			$this->getControls()->add($item);
1168
			$item->dataBind();
1169
			$this->onItemDataBound($param);
1170
			return $item;
1171
		}
1172
		else
1173
			return null;
1174
	}
1175
 
1176
	private function getAlternatingItemDisplay()
1177
	{
1178
		if(($classPath=$this->getAlternatingItemRenderer())==='' && $this->_alternatingItemTemplate===null)
1179
			return array($this->getItemRenderer(),$this->_itemTemplate);
1180
		else
1181
			return array($classPath,$this->_alternatingItemTemplate);
1182
	}
1183
 
1184
	private function getSelectedItemDisplay($itemIndex)
1185
	{
1186
		if(($classPath=$this->getSelectedItemRenderer())==='' && $this->_selectedItemTemplate===null)
1187
		{
1188
			if($itemIndex%2===0)
1189
				return array($this->getItemRenderer(),$this->_itemTemplate);
1190
			else
1191
				return $this->getAlternatingItemDisplay();
1192
		}
1193
		else
1194
			return array($classPath,$this->_selectedItemTemplate);
1195
	}
1196
 
1197
	private function getEditItemDisplay($itemIndex)
1198
	{
1199
		if(($classPath=$this->getEditItemRenderer())==='' && $this->_editItemTemplate===null)
1200
			return $this->getSelectedItemDisplay($itemIndex);
1201
		else
1202
			return array($classPath,$this->_editItemTemplate);
1203
	}
1204
 
1205
	/**
1206
	 * Creates a datalist item instance based on the item type and index.
1207
	 * @param integer zero-based item index
1208
	 * @param TListItemType item type
1209
	 * @return TControl created datalist item
1210
	 */
1211
	protected function createItem($itemIndex,$itemType)
1212
	{
1213
		$template=null;
1214
		$classPath=null;
1215
		switch($itemType)
1216
		{
1217
			case TListItemType::Item :
1218
				$classPath=$this->getItemRenderer();
1219
				$template=$this->_itemTemplate;
1220
				break;
1221
			case TListItemType::AlternatingItem :
1222
				list($classPath,$template)=$this->getAlternatingItemDisplay();
1223
				break;
1224
			case TListItemType::SelectedItem:
1225
				list($classPath,$template)=$this->getSelectedItemDisplay($itemIndex);
1226
				break;
1227
			case TListItemType::EditItem:
1228
				list($classPath,$template)=$this->getEditItemDisplay($itemIndex);
1229
				break;
1230
			case TListItemType::Header :
1231
				$classPath=$this->getHeaderRenderer();
1232
				$template=$this->_headerTemplate;
1233
				break;
1234
			case TListItemType::Footer :
1235
				$classPath=$this->getFooterRenderer();
1236
				$template=$this->_footerTemplate;
1237
				break;
1238
			case TListItemType::Separator :
1239
				$classPath=$this->getSeparatorRenderer();
1240
				$template=$this->_separatorTemplate;
1241
				break;
1242
			default:
1243
				throw new TInvalidDataValueException('datalist_itemtype_unknown',$itemType);
1244
		}
1245
		if($classPath!=='')
1246
		{
1247
			$item=Prado::createComponent($classPath);
1248
			if($item instanceof IItemDataRenderer)
1249
			{
1250
				$item->setItemIndex($itemIndex);
1251
				$item->setItemType($itemType);
1252
			}
1253
		}
1254
		else if($template!==null)
1255
		{
1256
			$item=new TDataListItem;
1257
			$item->setItemIndex($itemIndex);
1258
			$item->setItemType($itemType);
1259
			$template->instantiateIn($item);
1260
		}
1261
		else
1262
			$item=null;
1263
 
1264
		return $item;
1265
	}
1266
 
1267
	/**
1268
	 * Creates empty datalist content.
1269
	 */
1270
	protected function createEmptyContent()
1271
	{
1272
		if(($classPath=$this->getEmptyRenderer())!=='')
1273
			$this->getControls()->add(Prado::createComponent($classPath));
1274
		else if($this->_emptyTemplate!==null)
1275
			$this->_emptyTemplate->instantiateIn($this);
1276
	}
1277
 
1278
	/**
1279
	 * Applies styles to items, header, footer and separators.
1280
	 * Item styles are applied in a hierarchical way. Style in higher hierarchy
1281
	 * will inherit from styles in lower hierarchy.
1282
	 * Starting from the lowest hierarchy, the item styles include
1283
	 * item's own style, {@link getItemStyle ItemStyle}, {@link getAlternatingItemStyle AlternatingItemStyle},
1284
	 * {@link getSelectedItemStyle SelectedItemStyle}, and {@link getEditItemStyle EditItemStyle}.
1285
	 * Therefore, if background color is set as red in {@link getItemStyle ItemStyle},
1286
	 * {@link getEditItemStyle EditItemStyle} will also have red background color
1287
	 * unless it is set to a different value explicitly.
1288
	 */
1289
	protected function applyItemStyles()
1290
	{
1291
		$itemStyle=$this->getViewState('ItemStyle',null);
1292
 
1293
		$alternatingItemStyle=$this->getViewState('AlternatingItemStyle',null);
1294
		if($itemStyle!==null)
1295
		{
1296
			if($alternatingItemStyle===null)
1297
				$alternatingItemStyle=$itemStyle;
1298
			else
1299
				$alternatingItemStyle->mergeWith($itemStyle);
1300
		}
1301
 
1302
		$selectedItemStyle=$this->getViewState('SelectedItemStyle',null);
1303
 
1304
		$editItemStyle=$this->getViewState('EditItemStyle',null);
1305
		if($selectedItemStyle!==null)
1306
		{
1307
			if($editItemStyle===null)
1308
				$editItemStyle=$selectedItemStyle;
1309
			else
1310
				$editItemStyle->mergeWith($selectedItemStyle);
1311
		}
1312
 
1313
		// apply header style if any
1314
		if($this->_header!==null && $this->_header instanceof IStyleable)
1315
		{
1316
			if($headerStyle=$this->getViewState('HeaderStyle',null))
1317
				$this->_header->getStyle()->mergeWith($headerStyle);
1318
		}
1319
 
1320
		// apply footer style if any
1321
		if($this->_footer!==null && $this->_footer instanceof IStyleable)
1322
		{
1323
			if($footerStyle=$this->getViewState('FooterStyle',null))
1324
				$this->_footer->getStyle()->mergeWith($headerStyle);
1325
		}
1326
 
1327
		$selectedIndex=$this->getSelectedItemIndex();
1328
		$editIndex=$this->getEditItemIndex();
1329
 
1330
		// apply item styles if any
1331
		foreach($this->getItems() as $index=>$item)
1332
		{
1333
			if($index===$editIndex)
1334
				$style=$editItemStyle;
1335
			else if($index===$selectedIndex)
1336
				$style=$selectedItemStyle;
1337
			else if($index%2===0)
1338
				$style=$itemStyle;
1339
			else
1340
				$style=$alternatingItemStyle;
1341
			if($style && $item instanceof IStyleable)
1342
				$item->getStyle()->mergeWith($style);
1343
		}
1344
 
1345
		// apply separator style if any
1346
		if(($separatorStyle=$this->getViewState('SeparatorStyle',null))!==null && $this->getHasSeparators())
1347
		{
1348
			$controls=$this->getControls();
1349
			$count=$controls->getCount();
1350
			for($i=$this->_header?2:1;$i<$count;$i+=2)
1351
			{
1352
				if(($separator=$controls->itemAt($i)) instanceof IStyleable)
1353
					$separator->getStyle()->mergeWith($separatorStyle);
1354
			}
1355
		}
1356
	}
1357
 
1358
	/**
1359
	 * Saves item count in viewstate.
1360
	 * This method is invoked right before control state is to be saved.
1361
	 */
1362
	public function saveState()
1363
	{
1364
		parent::saveState();
1365
		if($this->_items)
1366
			$this->setViewState('ItemCount',$this->_items->getCount(),0);
1367
		else
1368
			$this->clearViewState('ItemCount');
1369
	}
1370
 
1371
	/**
1372
	 * Loads item count information from viewstate.
1373
	 * This method is invoked right after control state is loaded.
1374
	 */
1375
	public function loadState()
1376
	{
1377
		parent::loadState();
1378
		if(!$this->getIsDataBound())
1379
			$this->restoreItemsFromViewState();
1380
		$this->clearViewState('ItemCount');
1381
	}
1382
 
1383
	/**
1384
	 * Clears up all items in the data list.
1385
	 */
1386
	public function reset()
1387
	{
1388
		$this->getControls()->clear();
1389
		$this->getItems()->clear();
1390
		$this->_header=null;
1391
		$this->_footer=null;
1392
	}
1393
 
1394
	/**
1395
	 * Creates data list items based on viewstate information.
1396
	 */
1397
	protected function restoreItemsFromViewState()
1398
	{
1399
		$this->reset();
1400
		if(($itemCount=$this->getViewState('ItemCount',0))>0)
1401
		{
1402
			$items=$this->getItems();
1403
			$selectedIndex=$this->getSelectedItemIndex();
1404
			$editIndex=$this->getEditItemIndex();
1405
			$hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
1406
			$this->_header=$this->createItemInternal(-1,TListItemType::Header);
1407
			for($i=0;$i<$itemCount;++$i)
1408
			{
1409
				if($hasSeparator && $i>0)
1410
					$this->createItemInternal($i-1,TListItemType::Separator);
1411
				if($i===$editIndex)
1412
					$itemType=TListItemType::EditItem;
1413
				else if($i===$selectedIndex)
1414
					$itemType=TListItemType::SelectedItem;
1415
				else
1416
					$itemType=$i%2?TListItemType::AlternatingItem : TListItemType::Item;
1417
				$items->add($this->createItemInternal($i,$itemType));
1418
			}
1419
			$this->_footer=$this->createItemInternal(-1,TListItemType::Footer);
1420
		}
1421
		else
1422
			$this->createEmptyContent();
1423
		$this->clearChildState();
1424
	}
1425
 
1426
	/**
1427
	 * Performs databinding to populate data list items from data source.
1428
	 * This method is invoked by dataBind().
1429
	 * You may override this function to provide your own way of data population.
1430
	 * @param Traversable the data
1431
	 */
1432
	protected function performDataBinding($data)
1433
	{
1434
		$this->reset();
1435
		$keys=$this->getDataKeys();
1436
		$keys->clear();
1437
		$keyField=$this->getDataKeyField();
1438
		$itemIndex=0;
1439
		$items=$this->getItems();
1440
		$hasSeparator=$this->_separatorTemplate!==null || $this->getSeparatorRenderer()!=='';
1441
		$selectedIndex=$this->getSelectedItemIndex();
1442
		$editIndex=$this->getEditItemIndex();
1443
		foreach($data as $key=>$dataItem)
1444
		{
1445
			if($keyField!=='')
1446
				$keys->add($this->getDataFieldValue($dataItem,$keyField));
1447
			else
1448
				$keys->add($key);
1449
			if($itemIndex===0)
1450
				$this->_header=$this->createItemWithDataInternal(-1,TListItemType::Header,null);
1451
			if($hasSeparator && $itemIndex>0)
1452
				$this->createItemWithDataInternal($itemIndex-1,TListItemType::Separator,null);
1453
			if($itemIndex===$editIndex)
1454
				$itemType=TListItemType::EditItem;
1455
			else if($itemIndex===$selectedIndex)
1456
				$itemType=TListItemType::SelectedItem;
1457
			else
1458
				$itemType=$itemIndex%2?TListItemType::AlternatingItem : TListItemType::Item;
1459
			$items->add($this->createItemWithDataInternal($itemIndex,$itemType,$dataItem));
1460
			$itemIndex++;
1461
		}
1462
		if($itemIndex>0)
1463
			$this->_footer=$this->createItemWithDataInternal(-1,TListItemType::Footer,null);
1464
		else
1465
		{
1466
			$this->createEmptyContent();
1467
			$this->dataBindChildren();
1468
		}
1469
		$this->setViewState('ItemCount',$itemIndex,0);
1470
	}
1471
 
1472
	/**
1473
	 * Renders the data list control.
1474
	 * This method overrides the parent implementation.
1475
	 * @param THtmlWriter writer for rendering purpose.
1476
	 */
1477
	public function render($writer)
1478
	{
1479
		if($this->getHasControls())
1480
		{
1481
			if($this->getItemCount()>0)
1482
			{
1483
				$this->applyItemStyles();
1484
				$repeatInfo=$this->getRepeatInfo();
1485
				$repeatInfo->renderRepeater($writer,$this);
1486
			}
1487
			else if($this->_emptyTemplate!==null || $this->getEmptyRenderer()!=='')
1488
				parent::render($writer);
1489
		}
1490
	}
1491
}
1492
 
1493
 
1494
/**
1495
 * TDataListItemEventParameter class
1496
 *
1497
 * TDataListItemEventParameter encapsulates the parameter data for
1498
 * {@link TDataList::onItemCreated ItemCreated} event of {@link TDataList} controls.
1499
 * The {@link getItem Item} property indicates the DataList item related with the event.
1500
 *
1501
 * @author Qiang Xue <qiang.xue@gmail.com>
1502
 * @version $Id: TDataList.php 2541 2008-10-21 15:05:13Z qiang.xue $
1503
 * @package System.Web.UI.WebControls
1504
 * @since 3.0
1505
 */
1506
class TDataListItemEventParameter extends TEventParameter
1507
{
1508
	/**
1509
	 * The datalist item control responsible for the event.
1510
	 * @var TControl
1511
	 */
1512
	private $_item=null;
1513
 
1514
	/**
1515
	 * Constructor.
1516
	 * @param TControl DataList item related with the corresponding event
1517
	 */
1518
	public function __construct($item)
1519
	{
1520
		$this->_item=$item;
1521
	}
1522
 
1523
	/**
1524
	 * @return TControl datalist item related with the corresponding event
1525
	 */
1526
	public function getItem()
1527
	{
1528
		return $this->_item;
1529
	}
1530
}
1531
 
1532
/**
1533
 * TDataListCommandEventParameter class
1534
 *
1535
 * TDataListCommandEventParameter encapsulates the parameter data for
1536
 * {@link TDataList::onItemCommand ItemCommand} event of {@link TDataList} controls.
1537
 *
1538
 * The {@link getItem Item} property indicates the DataList item related with the event.
1539
 * The {@link getCommandSource CommandSource} refers to the control that originally
1540
 * raises the Command event.
1541
 *
1542
 * @author Qiang Xue <qiang.xue@gmail.com>
1543
 * @version $Id: TDataList.php 2541 2008-10-21 15:05:13Z qiang.xue $
1544
 * @package System.Web.UI.WebControls
1545
 * @since 3.0
1546
 */
1547
class TDataListCommandEventParameter extends TCommandEventParameter
1548
{
1549
	/**
1550
	 * @var TControl the datalist item control responsible for the event.
1551
	 */
1552
	private $_item=null;
1553
	/**
1554
	 * @var TControl the control originally raises the <b>OnCommand</b> event.
1555
	 */
1556
	private $_source=null;
1557
 
1558
	/**
1559
	 * Constructor.
1560
	 * @param TControl datalist item responsible for the event
1561
	 * @param TControl original event sender
1562
	 * @param TCommandEventParameter original event parameter
1563
	 */
1564
	public function __construct($item,$source,TCommandEventParameter $param)
1565
	{
1566
		$this->_item=$item;
1567
		$this->_source=$source;
1568
		parent::__construct($param->getCommandName(),$param->getCommandParameter());
1569
	}
1570
 
1571
	/**
1572
	 * @return TControl the datalist item control responsible for the event.
1573
	 */
1574
	public function getItem()
1575
	{
1576
		return $this->_item;
1577
	}
1578
 
1579
	/**
1580
	 * @return TControl the control originally raises the <b>OnCommand</b> event.
1581
	 */
1582
	public function getCommandSource()
1583
	{
1584
		return $this->_source;
1585
	}
1586
}
1587
 
1588
/**
1589
 * TDataListItem class
1590
 *
1591
 * A TDataListItem control represents an item in the {@link TDataList} control,
1592
 * such as heading section, footer section, or a data item.
1593
 * The index and data value of the item can be accessed via {@link getItemIndex ItemIndex}>
1594
 * and {@link getDataItem DataItem} properties, respectively. The type of the item
1595
 * is given by {@link getItemType ItemType} property.
1596
 *
1597
 * @author Qiang Xue <qiang.xue@gmail.com>
1598
 * @version $Id: TDataList.php 2541 2008-10-21 15:05:13Z qiang.xue $
1599
 * @package System.Web.UI.WebControls
1600
 * @since 3.0
1601
 */
1602
class TDataListItem extends TWebControl implements INamingContainer, IItemDataRenderer
1603
{
1604
	/**
1605
	 * index of the data item in the Items collection of DataList
1606
	 */
1607
	private $_itemIndex;
1608
	/**
1609
	 * type of the TDataListItem
1610
	 * @var TListItemType
1611
	 */
1612
	private $_itemType;
1613
	/**
1614
	 * value of the data associated with this item
1615
	 * @var mixed
1616
	 */
1617
	private $_data;
1618
 
1619
	private $_tagName='span';
1620
 
1621
	/**
1622
	 * Returns the tag name used for this control.
1623
	 * @return string tag name of the control to be rendered
1624
	 */
1625
	protected function getTagName()
1626
	{
1627
		return $this->_tagName;
1628
	}
1629
 
1630
	/**
1631
	 * @param string tag name of the control to be rendered
1632
	 */
1633
	public function setTagName($value)
1634
	{
1635
		$this->_tagName=$value;
1636
	}
1637
 
1638
	/**
1639
	 * Creates a style object for the control.
1640
	 * This method creates a {@link TTableItemStyle} to be used by a datalist item.
1641
	 * @return TStyle control style to be used
1642
	 */
1643
	protected function createStyle()
1644
	{
1645
		return new TTableItemStyle;
1646
	}
1647
 
1648
	/**
1649
	 * @return TListItemType item type
1650
	 */
1651
	public function getItemType()
1652
	{
1653
		return $this->_itemType;
1654
	}
1655
 
1656
	/**
1657
	 * @param TListItemType item type.
1658
	 */
1659
	public function setItemType($value)
1660
	{
1661
		$this->_itemType=TPropertyValue::ensureEnum($value,'TListItemType');
1662
	}
1663
 
1664
	/**
1665
	 * @return integer zero-based index of the item in the item collection of datalist
1666
	 */
1667
	public function getItemIndex()
1668
	{
1669
		return $this->_itemIndex;
1670
	}
1671
 
1672
	/**
1673
	 * Sets the zero-based index for the item.
1674
	 * If the item is not in the item collection (e.g. it is a header item), -1 should be used.
1675
	 * @param integer zero-based index of the item.
1676
	 */
1677
	public function setItemIndex($value)
1678
	{
1679
		$this->_itemIndex=TPropertyValue::ensureInteger($value);
1680
	}
1681
 
1682
	/**
1683
	 * @return mixed data associated with the item
1684
	 * @since 3.1.0
1685
	 */
1686
	public function getData()
1687
	{
1688
		return $this->_data;
1689
	}
1690
 
1691
	/**
1692
	 * @param mixed data to be associated with the item
1693
	 * @since 3.1.0
1694
	 */
1695
	public function setData($value)
1696
	{
1697
		$this->_data=$value;
1698
	}
1699
 
1700
	/**
1701
	 * This property is deprecated since v3.1.0.
1702
	 * @return mixed data associated with the item
1703
	 * @deprecated deprecated since v3.1.0. Use {@link getData} instead.
1704
	 */
1705
	public function getDataItem()
1706
	{
1707
		return $this->getData();
1708
	}
1709
 
1710
	/**
1711
	 * This property is deprecated since v3.1.0.
1712
	 * @param mixed data to be associated with the item
1713
	 * @deprecated deprecated since version 3.1.0. Use {@link setData} instead.
1714
	 */
1715
	public function setDataItem($value)
1716
	{
1717
		return $this->setData($value);
1718
	}
1719
 
1720
	/**
1721
	 * This method overrides parent's implementation by wrapping event parameter
1722
	 * for <b>OnCommand</b> event with item information.
1723
	 * @param TControl the sender of the event
1724
	 * @param TEventParameter event parameter
1725
	 * @return boolean whether the event bubbling should stop here.
1726
	 */
1727
	public function bubbleEvent($sender,$param)
1728
	{
1729
		if($param instanceof TCommandEventParameter)
1730
		{
1731
			$this->raiseBubbleEvent($this,new TDataListCommandEventParameter($this,$sender,$param));
1732
			return true;
1733
		}
1734
		else
1735
			return false;
1736
	}
1737
}
1738
 
1739
/**
1740
 * TDataListItemCollection class.
1741
 *
1742
 * TDataListItemCollection represents a collection of data list items.
1743
 *
1744
 * @author Qiang Xue <qiang.xue@gmail.com>
1745
 * @version $Id: TDataList.php 2541 2008-10-21 15:05:13Z qiang.xue $
1746
 * @package System.Web.UI.WebControls
1747
 * @since 3.0
1748
 */
1749
class TDataListItemCollection extends TList
1750
{
1751
	/**
1752
	 * Inserts an item at the specified position.
1753
	 * This overrides the parent implementation by inserting only TControl descendants.
1754
	 * @param integer the speicified position.
1755
	 * @param mixed new item
1756
	 * @throws TInvalidDataTypeException if the item to be inserted is not a TControl descendant.
1757
	 */
1758
	public function insertAt($index,$item)
1759
	{
1760
		if($item instanceof TControl)
1761
			parent::insertAt($index,$item);
1762
		else
1763
			throw new TInvalidDataTypeException('datalistitemcollection_datalistitem_required');
1764
	}
1765
}
1766