diff options
author | xue <> | 2006-06-27 00:31:33 +0000 |
---|---|---|
committer | xue <> | 2006-06-27 00:31:33 +0000 |
commit | b03d276f8a70675907ec8746c77c780f77f5d11a (patch) | |
tree | 5b0be511ccc58d096eeed9078dc842e5f2985ff9 | |
parent | f6d121552ca54980473d4f1c38a2ee4b0233de04 (diff) |
Added paging support to all data-bound controls.
Updated TPager accordingly.
-rw-r--r-- | HISTORY | 1 | ||||
-rw-r--r-- | framework/Exceptions/messages.txt | 15 | ||||
-rw-r--r-- | framework/Web/UI/WebControls/TDataBoundControl.php | 154 | ||||
-rw-r--r-- | framework/Web/UI/WebControls/TDataGrid.php | 302 | ||||
-rw-r--r-- | framework/Web/UI/WebControls/TPager.php | 314 |
5 files changed, 320 insertions, 466 deletions
@@ -16,6 +16,7 @@ ENH: Ticket#232 - Allow <%# %> and <%= %> embedded within property values (Qiang ENH: TRepeater, TDataList and TDataGrid will store data indices in DataKeys if DataKeyField is not set. (Qiang)
ENH: Added TPageService.BasePageClass property (Qiang)
ENH: Added TDataGrid.EmptyTemplate property (Qiang)
+ENH: Added paging feature to all TDataBoundControl-derived controls (Qiang)
NEW: Added TPager (Qiang)
Version 3.0.1 June 4, 2006
diff --git a/framework/Exceptions/messages.txt b/framework/Exceptions/messages.txt index b5db3613..8bc1cd6f 100644 --- a/framework/Exceptions/messages.txt +++ b/framework/Exceptions/messages.txt @@ -300,4 +300,17 @@ stack_data_not_iterable = TStack can only fetch data from an array or a trav stack_empty = TStack is empty.
queue_data_not_iterable = TQueue can only fetch data from an array or a traversable object.
-queue_empty = TQueue is empty.
\ No newline at end of file +queue_empty = TQueue is empty.
+
+pager_pagebuttoncount_invalid = TPager.PageButtonCount must be an integer no less than 1.
+pager_currentpageindex_invalid = TPager.CurrentPageIndex is out of range.
+pager_pagecount_invalid = TPager.PageCount cannot be smaller than 0.
+pager_controltopaginate_invalid = TPager.ControlToPaginate {0} must be a valid ID path pointing to a TDataBoundControl-derived control.
+
+databoundcontrol_pagesize_invalid = {0}.PageSize must be an integer no smaller than 1.
+databoundcontrol_virtualitemcount_invalid = {0}.VirtualItemCount must be an integer no smaller than 0.
+databoundcontrol_currentpageindex_invalid = {0}.CurrentPageIndex is out of range.
+databoundcontrol_datasource_invalid = {0}.DataSource is not valid.
+databoundcontrol_datasourceid_inexistent = databoundcontrol_datasourceid_inexistent.
+databoundcontrol_datasourceid_invalid = databoundcontrol_datasourceid_invalid
+databoundcontrol_datamember_invalid = databoundcontrol_datamember_invalid
\ No newline at end of file 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..342a39ac 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()
@@ -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(' ');
- 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(' ');
+ $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(' ');
+ $controls->add("\n");
}
if($pageCount>$endPageIndex)
{
- $controls->add(' ');
- $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/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'));
}
|