From b03d276f8a70675907ec8746c77c780f77f5d11a Mon Sep 17 00:00:00 2001 From: xue <> Date: Tue, 27 Jun 2006 00:31:33 +0000 Subject: Added paging support to all data-bound controls. Updated TPager accordingly. --- framework/Web/UI/WebControls/TPager.php | 314 ++++++++------------------------ 1 file changed, 79 insertions(+), 235 deletions(-) (limited to 'framework/Web/UI/WebControls/TPager.php') 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: - * - * $pager->ControlToPaginate="Path.To.Control"; - * $pager->DataSource=$data; - * $pager->dataBind(); - * - * 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 * @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. @@ -70,36 +51,6 @@ class TPager extends TDataBoundControl implements INamingContainer const CMD_PAGE_FIRST='First'; 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 @@ -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(); + } } /** @@ -133,107 +85,6 @@ class TPager extends TDataBoundControl implements INamingContainer $this->setViewState('ControlToPaginate',$value,''); } - /** - * @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'. */ @@ -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')); } -- cgit v1.2.3