summaryrefslogtreecommitdiff
path: root/framework/Web
diff options
context:
space:
mode:
Diffstat (limited to 'framework/Web')
-rw-r--r--framework/Web/UI/WebControls/TDataBoundControl.php154
-rw-r--r--framework/Web/UI/WebControls/TDataGrid.php304
-rw-r--r--framework/Web/UI/WebControls/TDataGridColumn.php23
-rw-r--r--framework/Web/UI/WebControls/TDataList.php2
-rw-r--r--framework/Web/UI/WebControls/TMultiView.php5
-rw-r--r--framework/Web/UI/WebControls/TPager.php314
6 files changed, 332 insertions, 470 deletions
diff --git a/framework/Web/UI/WebControls/TDataBoundControl.php b/framework/Web/UI/WebControls/TDataBoundControl.php
index 09023b66..798f9155 100644
--- a/framework/Web/UI/WebControls/TDataBoundControl.php
+++ b/framework/Web/UI/WebControls/TDataBoundControl.php
@@ -12,6 +12,7 @@
Prado::using('System.Web.UI.WebControls.TDataSourceControl');
Prado::using('System.Web.UI.WebControls.TDataSourceView');
+Prado::using('System.Collections.TPagedDataSource');
/**
* TDataBoundControl class.
@@ -20,7 +21,22 @@ Prado::using('System.Web.UI.WebControls.TDataSourceView');
* data from data sources. It provides basic properties and methods that allow
* the derived controls to associate with data sources and retrieve data from them.
*
- * TBC...
+ * TBC....
+ *
+ * TDataBoundControl is equipped with paging capabilities. By setting
+ * {@link setAllowPaging AllowPaging} to true, the input data will be paged
+ * and only one page of data is actually populated into the data-bound control.
+ * This saves a lot of memory when dealing with larget datasets.
+ *
+ * To specify the number of data items displayed on each page, set
+ * the {@link setPageSize PageSize} property, and to specify which
+ * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
+ *
+ * When the size of the original data is too big to be loaded all in the memory,
+ * one can enable custom paging. In custom paging, the total number of data items
+ * is specified manually via {@link setVirtualItemCount VirtualItemCount},
+ * and the data source only needs to contain the current page of data. To enable
+ * custom paging, set {@link setAllowCustomPaging AllowCustomPaging} to true.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Revision: $ $Date: $
@@ -152,6 +168,109 @@ abstract class TDataBoundControl extends TWebControl
}
/**
+ * @return boolean whether paging is enabled. Defaults to false.
+ */
+ public function getAllowPaging()
+ {
+ return $this->getViewState('AllowPaging',false);
+ }
+
+ /**
+ * @param boolean whether paging is enabled
+ */
+ public function setAllowPaging($value)
+ {
+ $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return boolean whether the custom paging is enabled. Defaults to false.
+ */
+ public function getAllowCustomPaging()
+ {
+ return $this->getViewState('AllowCustomPaging',false);
+ }
+
+ /**
+ * Sets a value indicating whether the custom paging should be enabled.
+ * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
+ * property is used to determine the paging, and the data items in the
+ * {@link setDataSource DataSource} are considered to be in the current page.
+ * @param boolean whether the custom paging is enabled
+ */
+ public function setAllowCustomPaging($value)
+ {
+ $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
+ }
+
+ /**
+ * @return integer the zero-based index of the current page. Defaults to 0.
+ */
+ public function getCurrentPageIndex()
+ {
+ return $this->getViewState('CurrentPageIndex',0);
+ }
+
+ /**
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ public function setCurrentPageIndex($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('databoundcontrol_currentpageindex_invalid',get_class($this));
+ $this->setViewState('CurrentPageIndex',$value,0);
+ }
+
+ /**
+ * @return integer the number of data items on each page. Defaults to 10.
+ */
+ public function getPageSize()
+ {
+ return $this->getViewState('PageSize',10);
+ }
+
+ /**
+ * @param integer the number of data items on each page.
+ * @throws TInvalidDataValueException if the value is less than 1
+ */
+ public function setPageSize($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<1)
+ throw new TInvalidDataValueException('databoundcontrol_pagesize_invalid',get_class($this));
+ $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
+ }
+
+ /**
+ * @return integer number of pages of data items available
+ */
+ public function getPageCount()
+ {
+ return $this->getViewState('PageCount',1);
+ }
+
+ /**
+ * @return integer virtual number of data items in the data source. Defaults to 0.
+ * @see setAllowCustomPaging
+ */
+ public function getVirtualItemCount()
+ {
+ return $this->getViewState('VirtualItemCount',0);
+ }
+
+ /**
+ * @param integer virtual number of data items in the data source.
+ * @throws TInvalidDataValueException if the value is less than 0
+ * @see setAllowCustomPaging
+ */
+ public function setVirtualItemCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('databoundcontrol_virtualitemcount_invalid',get_class($this));
+ $this->setViewState('VirtualItemCount',$value,0);
+ }
+
+ /**
* Sets a value indicating whether a databind call is required by the data bound control.
* If true and the control has been prerendered while it uses the data source
* specified by {@link setDataSourceID}, a databind call will be called by this method.
@@ -185,6 +304,20 @@ abstract class TDataBoundControl extends TWebControl
}
/**
+ * @return TPagedDataSource creates a paged data source
+ */
+ protected function createPagedDataSource()
+ {
+ $ds=new TPagedDataSource;
+ $ds->setCurrentPageIndex($this->getCurrentPageIndex());
+ $ds->setPageSize($this->getPageSize());
+ $ds->setAllowPaging($this->getAllowPaging());
+ $ds->setAllowCustomPaging($this->getAllowCustomPaging());
+ $ds->setVirtualItemCount($this->getVirtualItemCount());
+ return $ds;
+ }
+
+ /**
* Performs databinding.
* This method overrides the parent implementation by calling
* {@link performSelect} which fetches data from data source and does
@@ -197,7 +330,22 @@ abstract class TDataBoundControl extends TWebControl
$this->onDataBinding(null);
$data=$this->getData();
if($data instanceof Traversable)
- $this->performDataBinding($data);
+ {
+ if($this->getAllowPaging())
+ {
+ $ds=$this->createPagedDataSource();
+ $ds->setDataSource($data);
+ $this->setViewState('PageCount',$ds->getPageCount());
+ if($ds->getCurrentPageIndex()>=$ds->getPageCount())
+ throw new TInvalidDataValueException('databoundcontrol_currentpageindex_invalid',get_class($this));
+ $this->performDataBinding($ds);
+ }
+ else
+ {
+ $this->clearViewState('PageCount');
+ $this->performDataBinding($data);
+ }
+ }
$this->setIsDataBound(true);
$this->onDataBound(null);
}
@@ -336,7 +484,7 @@ abstract class TDataBoundControl extends TWebControl
else if(($value instanceof Traversable) || $value===null)
return $value;
else
- throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid');
+ throw new TInvalidDataTypeException('databoundcontrol_datasource_invalid',get_class($this));
}
public function getDataMember()
diff --git a/framework/Web/UI/WebControls/TDataGrid.php b/framework/Web/UI/WebControls/TDataGrid.php
index 4fe63f52..f811edaf 100644
--- a/framework/Web/UI/WebControls/TDataGrid.php
+++ b/framework/Web/UI/WebControls/TDataGrid.php
@@ -529,30 +529,6 @@ class TDataGrid extends TBaseDataList implements INamingContainer
}
/**
- * @return boolean whether the custom paging is enabled. Defaults to false.
- */
- public function getAllowCustomPaging()
- {
- return $this->getViewState('AllowCustomPaging',false);
- }
-
- /**
- * @param boolean whether the custom paging is enabled
- */
- public function setAllowCustomPaging($value)
- {
- $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return boolean whether paging is enabled. Defaults to false.
- */
- public function getAllowPaging()
- {
- return $this->getViewState('AllowPaging',false);
- }
-
- /**
* @return boolean whether sorting is enabled. Defaults to false.
*/
public function getAllowSorting()
@@ -561,14 +537,6 @@ class TDataGrid extends TBaseDataList implements INamingContainer
}
/**
- * @param boolean whether paging is enabled
- */
- public function setAllowPaging($value)
- {
- $this->setViewState('AllowPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
* @param boolean whether sorting is enabled
*/
public function setAllowSorting($value)
@@ -593,74 +561,6 @@ class TDataGrid extends TBaseDataList implements INamingContainer
}
/**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- public function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('datagrid_currentpageindex_invalid');
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer the number of rows displayed each page. Defaults to 10.
- */
- public function getPageSize()
- {
- return $this->getViewState('PageSize',10);
- }
-
- /**
- * @param integer the number of rows displayed within a page
- * @throws TInvalidDataValueException if the value is less than 1
- */
- public function setPageSize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('datagrid_pagesize_invalid');
- $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
- }
-
- /**
- * @return integer number of pages of items available
- */
- public function getPageCount()
- {
- if($this->_pagedDataSource)
- return $this->_pagedDataSource->getPageCount();
- else
- return $this->getViewState('PageCount',0);
- }
-
- /**
- * @return integer virtual number of items in the grid. Defaults to 0, meaning not set.
- */
- public function getVirtualItemCount()
- {
- return $this->getViewState('VirtualItemCount',0);
- }
-
- /**
- * @param integer virtual number of items in the grid
- * @throws TInvalidDataValueException if the value is less than 0
- */
- public function setVirtualItemCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('datagrid_virtualitemcount_invalid');
- $this->setViewState('VirtualItemCount',$value,0);
- }
-
- /**
* @return boolean whether the header should be displayed. Defaults to true.
*/
public function getShowHeader()
@@ -734,7 +634,7 @@ class TDataGrid extends TBaseDataList implements INamingContainer
if(strcasecmp($command,self::CMD_SELECT)===0)
{
$this->setSelectedItemIndex($param->getItem()->getItemIndex());
- $this->onSelectedIndexChanged(null);
+ $this->onSelectedIndexChanged($param);
return true;
}
else if(strcasecmp($command,self::CMD_EDIT)===0)
@@ -955,21 +855,6 @@ class TDataGrid extends TBaseDataList implements INamingContainer
}
$this->restoreGridFromViewState();
}
- $this->clearViewState('ItemCount');
- }
-
- /**
- * @return TPagedDataSource creates a paged data source
- */
- private function createPagedDataSource()
- {
- $ds=new TPagedDataSource;
- $ds->setCurrentPageIndex($this->getCurrentPageIndex());
- $ds->setPageSize($this->getPageSize());
- $ds->setAllowPaging($this->getAllowPaging());
- $ds->setAllowCustomPaging($this->getAllowCustomPaging());
- $ds->setVirtualItemCount($this->getVirtualItemCount());
- return $ds;
}
/**
@@ -992,42 +877,27 @@ class TDataGrid extends TBaseDataList implements INamingContainer
protected function restoreGridFromViewState()
{
$this->reset();
- $itemCount=$this->getViewState('ItemCount',0);
- $this->_pagedDataSource=$ds=$this->createPagedDataSource();
- $allowPaging=$ds->getAllowPaging();
- if($allowPaging && $ds->getAllowCustomPaging())
- $ds->setDataSource(new TDummyDataSource($itemCount));
- else
- $ds->setDataSource(new TDummyDataSource($this->getViewState('DataSourceCount',0)));
- if($ds->getCount()===0 && $ds->getCurrentPageIndex()===0 && $this->_emptyTemplate!==null)
- {
- $this->_emptyTemplate->instantiateIn($this);
- $this->_useEmptyTemplate=true;
- $this->clearViewState('ItemCount');
- $this->clearViewState('PageCount');
- $this->clearViewState('DataSourceCount');
- return;
- }
+ $allowPaging=$this->getAllowPaging();
+
+ $itemCount=$this->getViewState('ItemCount',0);
+ $dsIndex=$this->getViewState('DataSourceIndex',0);
$columns=new TList($this->getColumns());
$columns->mergeWith($this->_autoColumns);
$items=$this->getItems();
- $items->clear();
if($columns->getCount())
{
foreach($columns as $column)
$column->initialize();
if($allowPaging)
- $this->_topPager=$this->createPager($ds);
+ $this->_topPager=$this->createPager();
$this->_header=$this->createItemInternal(-1,-1,self::IT_HEADER,false,null,$columns);
$selectedIndex=$this->getSelectedItemIndex();
$editIndex=$this->getEditItemIndex();
- $index=0;
- $dsIndex=$ds->getAllowPaging()?$ds->getFirstIndexInPage():0;
- foreach($ds as $data)
+ for($index=0;$index<$itemCount;++$index)
{
if($index===$editIndex)
$itemType=self::IT_EDITITEM;
@@ -1038,14 +908,17 @@ class TDataGrid extends TBaseDataList implements INamingContainer
else
$itemType=self::IT_ITEM;
$items->add($this->createItemInternal($index,$dsIndex,$itemType,false,null,$columns));
- $index++;
$dsIndex++;
}
$this->_footer=$this->createItemInternal(-1,-1,self::IT_FOOTER,false,null,$columns);
if($allowPaging)
- $this->_bottomPager=$this->createPager($ds);
+ $this->_bottomPager=$this->createPager();
+ }
+ if(!$dsIndex && $this->_emptyTemplate!==null)
+ {
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
}
- $this->_pagedDataSource=null;
}
/**
@@ -1060,29 +933,12 @@ class TDataGrid extends TBaseDataList implements INamingContainer
$keys=$this->getDataKeys();
$keys->clear();
$keyField=$this->getDataKeyField();
- $this->_pagedDataSource=$ds=$this->createPagedDataSource();
- $ds->setDataSource($data);
-
- $allowPaging=$ds->getAllowPaging();
- if($allowPaging && $ds->getCurrentPageIndex()>=$ds->getPageCount())
- throw new TInvalidDataValueException('datagrid_currentpageindex_invalid');
-
- if($ds->getCount()===0 && $ds->getCurrentPageIndex()===0 && $this->_emptyTemplate!==null)
- {
- $this->_useEmptyTemplate=true;
- $this->_emptyTemplate->instantiateIn($this);
- $this->dataBindChildren();
- $this->clearViewState('ItemCount');
- $this->clearViewState('PageCount');
- $this->clearViewState('DataSourceCount');
- return;
- }
// get all columns
if($this->getAutoGenerateColumns())
{
$columns=new TList($this->getColumns());
- $autoColumns=$this->createAutoColumns($ds);
+ $autoColumns=$this->createAutoColumns($data);
$columns->mergeWith($autoColumns);
}
else
@@ -1090,22 +946,23 @@ class TDataGrid extends TBaseDataList implements INamingContainer
$items=$this->getItems();
+ $index=0;
+ $allowPaging=$this->getAllowPaging() && ($data instanceof TPagedDataSource);
+ $dsIndex=$allowPaging?$data->getFirstIndexInPage():0;
+ $this->setViewState('DataSourceIndex',$dsIndex,0);
if($columns->getCount())
{
foreach($columns as $column)
$column->initialize();
- $allowPaging=$ds->getAllowPaging();
if($allowPaging)
- $this->_topPager=$this->createPager($ds);
+ $this->_topPager=$this->createPager();
$this->_header=$this->createItemInternal(-1,-1,self::IT_HEADER,true,null,$columns);
$selectedIndex=$this->getSelectedItemIndex();
$editIndex=$this->getEditItemIndex();
- $index=0;
- $dsIndex=$allowPaging?$ds->getFirstIndexInPage():0;
- foreach($ds as $key=>$data)
+ foreach($data as $key=>$row)
{
if($keyField!=='')
- $keys->add($this->getDataFieldValue($data,$keyField));
+ $keys->add($this->getDataFieldValue($row,$keyField));
else
$keys->add($key);
if($index===$editIndex)
@@ -1116,24 +973,21 @@ class TDataGrid extends TBaseDataList implements INamingContainer
$itemType=self::IT_ALTERNATINGITEM;
else
$itemType=self::IT_ITEM;
- $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$data,$columns));
+ $items->add($this->createItemInternal($index,$dsIndex,$itemType,true,$row,$columns));
$index++;
$dsIndex++;
}
$this->_footer=$this->createItemInternal(-1,-1,self::IT_FOOTER,true,null,$columns);
if($allowPaging)
- $this->_bottomPager=$this->createPager($ds);
- $this->setViewState('ItemCount',$index,0);
- $this->setViewState('PageCount',$ds->getPageCount(),0);
- $this->setViewState('DataSourceCount',$ds->getDataSourceCount(),0);
+ $this->_bottomPager=$this->createPager();
}
- else
+ $this->setViewState('ItemCount',$index,0);
+ if(!$dsIndex && $this->_emptyTemplate!==null)
{
- $this->clearViewState('ItemCount');
- $this->clearViewState('PageCount');
- $this->clearViewState('DataSourceCount');
+ $this->_useEmptyTemplate=true;
+ $this->_emptyTemplate->instantiateIn($this);
+ $this->dataBindChildren();
}
- $this->_pagedDataSource=null;
}
/**
@@ -1191,10 +1045,10 @@ class TDataGrid extends TBaseDataList implements INamingContainer
}
}
- private function createPager($pagedDataSource)
+ private function createPager()
{
$pager=new TDataGridPager($this);
- $this->buildPager($pager,$pagedDataSource);
+ $this->buildPager($pager);
$this->onPagerCreated(new TDataGridPagerEventParameter($pager));
$this->getControls()->add($pager);
return $pager;
@@ -1203,81 +1057,87 @@ class TDataGrid extends TBaseDataList implements INamingContainer
/**
* Builds the pager content based on pager style.
* @param TDataGridPager the container for the pager
- * @param TPagedDataSource data source bound to the datagrid
*/
- protected function buildPager($pager,$dataSource)
+ protected function buildPager($pager)
{
switch($this->getPagerStyle()->getMode())
{
case 'NextPrev':
- $this->buildNextPrevPager($pager,$dataSource);
+ $this->buildNextPrevPager($pager);
break;
case 'Numeric':
- $this->buildNumericPager($pager,$dataSource);
+ $this->buildNumericPager($pager);
break;
}
}
/**
* Creates a pager button.
- * @param string button type, LinkButton or PushButton
+ * Depending on the button type, a TLinkButton or a TButton may be created.
+ * If it is enabled (clickable), its command name and parameter will also be set.
+ * Derived classes may override this method to create additional types of buttons, such as TImageButton.
+ * @param string button type, either LinkButton or PushButton
* @param boolean whether the button should be enabled
+ * @param string caption of the button
+ * @param string CommandName corresponding to the OnCommand event of the button
+ * @param string CommandParameter corresponding to the OnCommand event of the button
* @return mixed the button instance
*/
- protected function createPagerButton($buttonType,$enabled)
+ protected function createPagerButton($buttonType,$enabled,$text,$commandName,$commandParameter)
{
if($buttonType==='LinkButton')
{
- return $enabled?new TLinkButton:new TLabel;
+ if($enabled)
+ $button=new TLinkButton;
+ else
+ {
+ $button=new TLabel;
+ $button->setText($text);
+ return $button;
+ }
}
else
{
$button=new TButton;
if(!$enabled)
$button->setEnabled(false);
- return $button;
}
+ $button->setText($text);
+ $button->setCommandName($commandName);
+ $button->setCommandParameter($commandParameter);
+ $button->setCausesValidation(false);
+ return $button;
}
/**
* Builds a next-prev pager
* @param TDataGridPager the container for the pager
- * @param TPagedDataSource data source bound to the datagrid
*/
- protected function buildNextPrevPager($pager,$dataSource)
+ protected function buildNextPrevPager($pager)
{
$style=$this->getPagerStyle();
$buttonType=$style->getButtonType();
$controls=$pager->getControls();
- if($dataSource->getIsFirstPage())
+ $currentPageIndex=$this->getCurrentPageIndex();
+ if($currentPageIndex===0)
{
- $label=$this->createPagerButton($buttonType,false);
- $label->setText($style->getPrevPageText());
+ $label=$this->createPagerButton($buttonType,false,$style->getPrevPageText(),'','');
$controls->add($label);
}
else
{
- $button=$this->createPagerButton($buttonType,true);
- $button->setText($style->getPrevPageText());
- $button->setCommandName(self::CMD_PAGE);
- $button->setCommandParameter(self::CMD_PAGE_PREV);
- $button->setCausesValidation(false);
+ $button=$this->createPagerButton($buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,self::CMD_PAGE_PREV);
$controls->add($button);
}
- $controls->add('&nbsp;');
- if($dataSource->getIsLastPage())
+ $controls->add("\n");
+ if($currentPageIndex===$this->getPageCount()-1)
{
- $label=$this->createPagerButton($buttonType,false);
- $label->setText($style->getNextPageText());
+ $label=$this->createPagerButton($buttonType,false,$style->getNextPageText(),'','');
$controls->add($label);
}
else
{
- $button=$this->createPagerButton($buttonType,true);
- $button->setText($style->getNextPageText());
- $button->setCommandName(self::CMD_PAGE);
- $button->setCommandParameter(self::CMD_PAGE_NEXT);
- $button->setCausesValidation(false);
+ $button=$this->createPagerButton($buttonType,true,$style->getNextPageText(),self::CMD_PAGE,self::CMD_PAGE_NEXT);
$controls->add($button);
}
}
@@ -1285,15 +1145,14 @@ class TDataGrid extends TBaseDataList implements INamingContainer
/**
* Builds a numeric pager
* @param TDataGridPager the container for the pager
- * @param TPagedDataSource data source bound to the datagrid
*/
- protected function buildNumericPager($pager,$dataSource)
+ protected function buildNumericPager($pager)
{
$style=$this->getPagerStyle();
$buttonType=$style->getButtonType();
$controls=$pager->getControls();
- $pageCount=$dataSource->getPageCount();
- $pageIndex=$dataSource->getCurrentPageIndex()+1;
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
$maxButtonCount=$style->getPageButtonCount();
$buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
$startPageIndex=1;
@@ -1312,51 +1171,40 @@ class TDataGrid extends TBaseDataList implements INamingContainer
if($startPageIndex>1)
{
- $button=$this->createPagerButton($buttonType,true);
- $button->setText($style->getPrevPageText());
- $button->setCommandName(self::CMD_PAGE);
- $button->setCommandParameter($startPageIndex-1);
- $button->setCausesValidation(false);
+ $prevPageIndex=$startPageIndex-1;
+ $button=$this->createPagerButton($buttonType,true,$style->getPrevPageText(),self::CMD_PAGE,"$prevPageIndex");
$controls->add($button);
- $controls->add('&nbsp;');
+ $controls->add("\n");
}
for($i=$startPageIndex;$i<=$endPageIndex;++$i)
{
if($i===$pageIndex)
{
- $label=$this->createPagerButton($buttonType,false);
- $label->setText("$i");
+ $label=$this->createPagerButton($buttonType,false,"$i",'','');
$controls->add($label);
}
else
{
- $button=$this->createPagerButton($buttonType,true);
- $button->setText("$i");
- $button->setCommandName(self::CMD_PAGE);
- $button->setCommandParameter($i);
- $button->setCausesValidation(false);
+ $button=$this->createPagerButton($buttonType,true,"$i",self::CMD_PAGE,"$i");
$controls->add($button);
}
if($i<$endPageIndex)
- $controls->add('&nbsp;');
+ $controls->add("\n");
}
if($pageCount>$endPageIndex)
{
- $controls->add('&nbsp;');
- $button=$this->createPagerButton($buttonType,true);
- $button->setText($style->getNextPageText());
- $button->setCommandName(self::CMD_PAGE);
- $button->setCommandParameter($endPageIndex+1);
- $button->setCausesValidation(false);
+ $controls->add("\n");
+ $nextPageIndex=$endPageIndex+1;
+ $button=$this->createPagerButton($buttonType,true,$style->getNextPageText(),self::CMD_PAGE,"$nextPageIndex");
$controls->add($button);
}
}
/**
* Automatically generates datagrid columns based on datasource schema
- * @param TPagedDataSource data source bound to the datagrid
+ * @param Traversable data source bound to the datagrid
* @return TDataGridColumnCollection
*/
protected function createAutoColumns($dataSource)
diff --git a/framework/Web/UI/WebControls/TDataGridColumn.php b/framework/Web/UI/WebControls/TDataGridColumn.php
index e43b4895..8c34b85f 100644
--- a/framework/Web/UI/WebControls/TDataGridColumn.php
+++ b/framework/Web/UI/WebControls/TDataGridColumn.php
@@ -51,10 +51,33 @@ Prado::using('System.Util.TDataFieldAccessor');
*/
abstract class TDataGridColumn extends TApplicationComponent
{
+ private $_id='';
private $_owner=null;
private $_viewState=array();
/**
+ * @return string the ID of the column.
+ */
+ public function getID()
+ {
+ return $this->_id;
+ }
+
+ /**
+ * Sets the ID of the column.
+ * By explicitly specifying the column ID, one can access the column
+ * by $templateControl->ColumnID.
+ * @param string the ID of the column.
+ * @throws TInvalidDataValueException if the ID is of bad format
+ */
+ public function setID($value)
+ {
+ if(!preg_match(TControl::ID_FORMAT,$value))
+ throw new TInvalidDataValueException('datagridcolumn_id_invalid',get_class($this),$value);
+ $this->_id=$value;
+ }
+
+ /**
* @return string the text to be displayed in the header of this column
*/
public function getHeaderText()
diff --git a/framework/Web/UI/WebControls/TDataList.php b/framework/Web/UI/WebControls/TDataList.php
index b6888225..48392b1d 100644
--- a/framework/Web/UI/WebControls/TDataList.php
+++ b/framework/Web/UI/WebControls/TDataList.php
@@ -677,7 +677,7 @@ class TDataList extends TBaseDataList implements INamingContainer, IRepeatInfoUs
if(strcasecmp($command,self::CMD_SELECT)===0)
{
$this->setSelectedItemIndex($param->getItem()->getItemIndex());
- $this->onSelectedIndexChanged(null);
+ $this->onSelectedIndexChanged($param);
return true;
}
else if(strcasecmp($command,self::CMD_EDIT)===0)
diff --git a/framework/Web/UI/WebControls/TMultiView.php b/framework/Web/UI/WebControls/TMultiView.php
index b6001f90..00c0ce93 100644
--- a/framework/Web/UI/WebControls/TMultiView.php
+++ b/framework/Web/UI/WebControls/TMultiView.php
@@ -144,7 +144,7 @@ class TMultiView extends TControl
{
if($view->getActive())
return;
- $triggerEvent=($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack()));
+ $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack()));
foreach($this->getViews() as $v)
{
if($v===$view)
@@ -153,8 +153,7 @@ class TMultiView extends TControl
if($triggerEvent)
{
$view->onActivate(null);
- if($triggerViewChangedEvent)
- $this->onActiveViewChanged(null);
+ $this->onActiveViewChanged(null);
}
}
else if($v->getActive())
diff --git a/framework/Web/UI/WebControls/TPager.php b/framework/Web/UI/WebControls/TPager.php
index f802e8d7..0401c4f2 100644
--- a/framework/Web/UI/WebControls/TPager.php
+++ b/framework/Web/UI/WebControls/TPager.php
@@ -10,27 +10,18 @@
* @package System.Web.UI.WebControls
*/
-Prado::using('System.Web.UI.WebControls.TDataBoundControl');
-Prado::using('System.Web.UI.WebControls.TPanelStyle');
-Prado::using('System.Collections.TPagedDataSource');
-Prado::using('System.Collections.TDummyDataSource');
-
/**
* TPager class.
*
- * TPager creates a pager that controls the paging of the data populated
- * to a data-bound control specified by {@link setControlToPaginate ControlToPaginate}.
- * To specify the number of data items displayed on each page, set
- * the {@link setPageSize PageSize} property, and to specify which
- * page of data to be displayed, set {@link setCurrentPageIndex CurrentPageIndex}.
- *
- * When the size of the original data is too big to be loaded all in the memory,
- * one can enable custom paging. In custom paging, the total number of data items
- * is specified manually via {@link setVirtualItemCount VirtualItemCount}, and the data source
- * only needs to contain the current page of data. To enable custom paging,
- * set {@link setAllowCustomPaging AllowCustomPaging} to true.
+ * TPager creates a pager that provides UI for end-users to interactively
+ * specify which page of data to be rendered in a {@link TDataBoundControl}-derived control,
+ * such as {@link TDataList}, {@link TRepeater}, {@link TCheckBoxList}, etc.
+ * The target data-bound control is specified by {@link setControlToPaginate ControlToPaginate},
+ * which must be the ID path of the target control reaching from the pager's
+ * naming container. Note, the target control must have its {@link TDataBoundControl::setAllowPaging AllowPaging}
+ * set to true.
*
- * TPager can be in one of three {@link setMode Mode}:
+ * TPager can display three different UIs, specified via {@link setMode Mode}:
* - NextPrev: a next page and a previous page button are rendered.
* - Numeric: a list of page index buttons are rendered.
* - List: a dropdown list of page indices are rendered.
@@ -39,27 +30,17 @@ Prado::using('System.Collections.TDummyDataSource');
* the end-user interacts with it and specifies a new page (e.g. clicking
* on a page button that leads to a new page.) The new page index may be obtained
* from the event parameter's property {@link TPagerPageChangedEventParameter::getNewPageIndex NewPageIndex}.
+ * Normally, in the event handler, one can set the {@link TDataBoundControl::getCurrentPageIndex CurrentPageIndex}
+ * to this new page index so that the new page of data is rendered.
*
- * When multiple pagers are associated with the same data-bound control,
- * these pagers will do synchronization among each other so that the interaction
- * with one pager will automatically update the UI of the other relevant pagers.
- *
- * The following example shows a typical usage of TPager:
- * <code>
- * $pager->ControlToPaginate="Path.To.Control";
- * $pager->DataSource=$data;
- * $pager->dataBind();
- * </code>
- * Note, the data is assigned to the pager and dataBind() is invoked against the pager.
- * Without the pager, one has to set datasource for the target control and call
- * its dataBind() directly.
+ * Multiple pagers can be associated with the same data-bound control.
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @version $Revision: $ $Date: $
* @package System.Web.UI.WebControls
* @since 3.0.2
*/
-class TPager extends TDataBoundControl implements INamingContainer
+class TPager extends TWebControl implements INamingContainer
{
/**
* Command name that TPager understands.
@@ -71,36 +52,6 @@ class TPager extends TDataBoundControl implements INamingContainer
const CMD_PAGE_LAST='Last';
/**
- * @var array list of all pagers, used to synchronize their appearance
- */
- static private $_pagers=array();
-
- /**
- * Registers the pager itself to a global list.
- * This method overrides the parent implementation and is invoked during
- * OnInit control lifecycle.
- * @param mixed event parameter
- */
- public function onInit($param)
- {
- parent::onInit($param);
- self::$_pagers[]=$this;
- }
-
- /**
- * Unregisters the pager from a global list.
- * This method overrides the parent implementation and is invoked during
- * OnUnload control lifecycle.
- * @param mixed event parameter
- */
- public function onUnload($param)
- {
- parent::onUnload($param);
- if(($index=array_search($this,self::$_pagers,true))!==false)
- unset(self::$_pagers[$index]);
- }
-
- /**
* Restores the pager state.
* This method overrides the parent implementation and is invoked when
* the control is loading persistent state.
@@ -108,10 +59,11 @@ class TPager extends TDataBoundControl implements INamingContainer
public function loadState()
{
parent::loadState();
- if(!$this->getEnableViewState(true))
- return;
- if(!$this->getIsDataBound())
- $this->restoreFromViewState();
+ if($this->getEnableViewState(true))
+ {
+ $this->getControls()->clear();
+ $this->buildPager();
+ }
}
/**
@@ -134,107 +86,6 @@ class TPager extends TDataBoundControl implements INamingContainer
}
/**
- * @return integer the zero-based index of the current page. Defaults to 0.
- */
- public function getCurrentPageIndex()
- {
- return $this->getViewState('CurrentPageIndex',0);
- }
-
- /**
- * @param integer the zero-based index of the current page
- * @throws TInvalidDataValueException if the value is less than 0
- */
- public function setCurrentPageIndex($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('pager_currentpageindex_invalid');
- $this->setViewState('CurrentPageIndex',$value,0);
- }
-
- /**
- * @return integer the number of data items on each page. Defaults to 10.
- */
- public function getPageSize()
- {
- return $this->getViewState('PageSize',10);
- }
-
- /**
- * @param integer the number of data items on each page.
- * @throws TInvalidDataValueException if the value is less than 1
- */
- public function setPageSize($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<1)
- throw new TInvalidDataValueException('pager_pagesize_invalid');
- $this->setViewState('PageSize',TPropertyValue::ensureInteger($value),10);
- }
-
- /**
- * @return integer number of pages
- */
- public function getPageCount()
- {
- if(($count=$this->getItemCount())<1)
- return 1;
- else
- {
- $pageSize=$this->getPageSize();
- return (int)(($count+$pageSize-1)/$pageSize);
- }
- }
-
- /**
- * @return boolean whether the custom paging is enabled. Defaults to false.
- */
- public function getAllowCustomPaging()
- {
- return $this->getViewState('AllowCustomPaging',false);
- }
-
- /**
- * Sets a value indicating whether the custom paging should be enabled.
- * When the pager is in custom paging mode, the {@link setVirtualItemCount VirtualItemCount}
- * property is used to determine the paging, and the data items in the
- * {@link setDataSource DataSource} are considered to be in the current page.
- * @param boolean whether the custom paging is enabled
- */
- public function setAllowCustomPaging($value)
- {
- $this->setViewState('AllowCustomPaging',TPropertyValue::ensureBoolean($value),false);
- }
-
- /**
- * @return integer virtual number of data items in the data source. Defaults to 0.
- * @see setAllowCustomPaging
- */
- public function getVirtualItemCount()
- {
- return $this->getViewState('VirtualItemCount',0);
- }
-
- /**
- * @param integer virtual number of data items in the data source.
- * @throws TInvalidDataValueException if the value is less than 0
- * @see setAllowCustomPaging
- */
- public function setVirtualItemCount($value)
- {
- if(($value=TPropertyValue::ensureInteger($value))<0)
- throw new TInvalidDataValueException('pager_virtualitemcount_invalid');
- $this->setViewState('VirtualItemCount',$value,0);
- }
-
- /**
- * @return integer total number of items in the datasource.
- */
- public function getItemCount()
- {
- return $this->getViewState('ItemCount',0);
- }
-
- /**
* @return string pager mode. Defaults to 'NextPrev'.
*/
public function getMode()
@@ -350,38 +201,57 @@ class TPager extends TDataBoundControl implements INamingContainer
}
/**
- * @return TPagedDataSource creates a paged data source
+ * @return integer the zero-based index of the current page. Defaults to 0.
*/
- private function createPagedDataSource()
+ public function getCurrentPageIndex()
{
- $ds=new TPagedDataSource;
- $ds->setAllowPaging(true);
- $customPaging=$this->getAllowCustomPaging();
- $ds->setAllowCustomPaging($customPaging);
- $ds->setCurrentPageIndex($this->getCurrentPageIndex());
- $ds->setPageSize($this->getPageSize());
- if($customPaging)
- $ds->setVirtualItemCount($this->getVirtualItemCount());
- return $ds;
+ return $this->getViewState('CurrentPageIndex',0);
}
/**
- * Removes the existing child controls.
+ * @param integer the zero-based index of the current page
+ * @throws TInvalidDataValueException if the value is less than 0
*/
- protected function reset()
+ protected function setCurrentPageIndex($value)
{
- $this->getControls()->clear();
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('pager_currentpageindex_invalid');
+ $this->setViewState('CurrentPageIndex',$value,0);
}
/**
- * Restores the pager from viewstate.
+ * @return integer number of pages of data items available
*/
- protected function restoreFromViewState()
+ public function getPageCount()
{
- $this->reset();
- $ds=$this->createPagedDataSource();
- $ds->setDataSource(new TDummyDataSource($this->getItemCount()));
- $this->buildPager($ds);
+ return $this->getViewState('PageCount',0);
+ }
+
+ /**
+ * @param integer number of pages of data items available
+ * @throws TInvalidDataValueException if the value is less than 0
+ */
+ protected function setPageCount($value)
+ {
+ if(($value=TPropertyValue::ensureInteger($value))<0)
+ throw new TInvalidDataValueException('pager_pagecount_invalid');
+ $this->setViewState('PageCount',$value,0);
+ }
+
+ /**
+ * @return boolean whether the current page is the first page Defaults to false.
+ */
+ public function getIsFirstPage()
+ {
+ return $this->getCurrentPageIndex()===0;
+ }
+
+ /**
+ * @return boolean whether the current page is the last page
+ */
+ public function getIsLastPage()
+ {
+ return $this->getCurrentPageIndex()===$this->getPageCount()-1;
}
/**
@@ -390,66 +260,43 @@ class TPager extends TDataBoundControl implements INamingContainer
* You may override this function to provide your own way of data population.
* @param Traversable the bound data
*/
- protected function performDataBinding($data)
+ public function onPreRender($param)
{
- $this->reset();
+ parent::onPreRender($param);
$controlID=$this->getControlToPaginate();
if(($targetControl=$this->getNamingContainer()->findControl($controlID))===null || !($targetControl instanceof TDataBoundControl))
throw new TConfigurationException('pager_controltopaginate_invalid',$controlID);
- $ds=$this->createPagedDataSource();
- $ds->setDataSource($this->getDataSource());
- $this->setViewState('ItemCount',$ds->getDataSourceCount());
-
- $this->buildPager($ds);
- $this->synchronizePagers($targetControl,$ds);
-
- $targetControl->setDataSource($ds);
- $targetControl->dataBind();
- }
-
- /**
- * Synchronizes the state of all pagers who have the same {@link getControlToPaginate ControlToPaginate}.
- * @param TDataBoundControl the control whose content is to be paginated
- * @param TPagedDataSource the paged data source associated with the pager
- */
- protected function synchronizePagers($targetControl,$dataSource)
- {
- foreach(self::$_pagers as $pager)
+ if($targetControl->getAllowPaging() && $targetControl->getPageCount()>1)
{
- if($pager!==$this && $pager->getNamingContainer()->findControl($pager->getControlToPaginate())===$targetControl)
- {
- $pager->reset();
- $pager->setCurrentPageIndex($dataSource->getCurrentPageIndex());
- $customPaging=$dataSource->getAllowCustomPaging();
- $pager->setAllowCustomPaging($customPaging);
- $pager->setViewState('ItemCount',$dataSource->getDataSourceCount());
- if($customPaging)
- $pager->setVirtualItemCount($dataSource->getVirtualItemCount());
- $pager->buildPager($dataSource);
- }
+ $this->setVisible(true);
+ $this->getControls()->clear();
+ $this->setPageCount($targetControl->getPageCount());
+ $this->setCurrentPageIndex($targetControl->getCurrentPageIndex());
+ $this->buildPager();
}
+ else
+ $this->setVisible(false);
}
/**
* Builds the pager content based on the pager mode.
* Current implementation includes building 'NextPrev', 'Numeric' and 'List' pagers.
* Derived classes may override this method to provide additional pagers.
- * @param TPagedDataSource data source bound to the target control
*/
- protected function buildPager($dataSource)
+ protected function buildPager()
{
switch($this->getMode())
{
case 'NextPrev':
- $this->buildNextPrevPager($dataSource);
+ $this->buildNextPrevPager();
break;
case 'Numeric':
- $this->buildNumericPager($dataSource);
+ $this->buildNumericPager();
break;
case 'List':
- $this->buildListPager($dataSource);
+ $this->buildListPager();
break;
}
}
@@ -494,13 +341,12 @@ class TPager extends TDataBoundControl implements INamingContainer
/**
* Builds a next-prev pager
- * @param TPagedDataSource data source bound to the pager
*/
- protected function buildNextPrevPager($dataSource)
+ protected function buildNextPrevPager()
{
$buttonType=$this->getButtonType();
$controls=$this->getControls();
- if($dataSource->getIsFirstPage())
+ if($this->getIsFirstPage())
{
if(($text=$this->getFirstPageText())!=='')
{
@@ -523,7 +369,7 @@ class TPager extends TDataBoundControl implements INamingContainer
$controls->add($button);
}
$controls->add("\n");
- if($dataSource->getIsLastPage())
+ if($this->getIsLastPage())
{
$label=$this->createPagerButton($buttonType,false,$this->getNextPageText(),'','');
$controls->add($label);
@@ -549,14 +395,13 @@ class TPager extends TDataBoundControl implements INamingContainer
/**
* Builds a numeric pager
- * @param TPagedDataSource data source bound to the pager
*/
- protected function buildNumericPager($dataSource)
+ protected function buildNumericPager()
{
$buttonType=$this->getButtonType();
$controls=$this->getControls();
- $pageCount=$dataSource->getPageCount();
- $pageIndex=$dataSource->getCurrentPageIndex()+1;
+ $pageCount=$this->getPageCount();
+ $pageIndex=$this->getCurrentPageIndex()+1;
$maxButtonCount=$this->getPageButtonCount();
$buttonCount=$maxButtonCount>$pageCount?$pageCount:$maxButtonCount;
$startPageIndex=1;
@@ -620,15 +465,14 @@ class TPager extends TDataBoundControl implements INamingContainer
/**
* Builds a dropdown list pager
- * @param TPagedDataSource data source bound to the pager
*/
- protected function buildListPager($dataSource)
+ protected function buildListPager()
{
$list=new TDropDownList;
$this->getControls()->add($list);
- $list->setDataSource(range(1,$dataSource->getPageCount()));
+ $list->setDataSource(range(1,$this->getPageCount()));
$list->dataBind();
- $list->setSelectedIndex($dataSource->getCurrentPageIndex());
+ $list->setSelectedIndex($this->getCurrentPageIndex());
$list->setAutoPostBack(true);
$list->attachEventHandler('OnSelectedIndexChanged',array($this,'listIndexChanged'));
}