<?php /** * TMultiView and TView class file. * * @author Qiang Xue <qiang.xue@gmail.com> * @link http://www.pradosoft.com/ * @copyright Copyright © 2005-2011 PradoSoft * @license http://www.pradosoft.com/license/ * @version $Id$ * @package System.Web.UI.WebControls */ /** * TMultiView class * * TMultiView serves as a container for a group of {@link TView} controls. * The view collection can be retrieved by {@link getViews Views}. * Each view contains child controls. TMultiView determines which view and its * child controls are visible. At any time, at most one view is visible (called * active). To make a view active, set {@link setActiveView ActiveView} or * {@link setActiveViewIndex ActiveViewIndex}. * * TMultiView also responds to specific command events raised from button controls * contained in current active view. A command event with name 'NextView' * will cause TMultiView to make the next available view active. * Other command names recognized by TMultiView include * - PreviousView : switch to previous view * - SwitchViewID : switch to a view by its ID path * - SwitchViewIndex : switch to a view by its index in the {@link getViews Views} collection. * * TMultiView raises {@link OnActiveViewChanged OnActiveViewChanged} event * when its active view is changed during a postback. * * @author Qiang Xue <qiang.xue@gmail.com> * @version $Id$ * @package System.Web.UI.WebControls * @since 3.0 */ class TMultiView extends TControl { const CMD_NEXTVIEW='NextView'; const CMD_PREVIOUSVIEW='PreviousView'; const CMD_SWITCHVIEWID='SwitchViewID'; const CMD_SWITCHVIEWINDEX='SwitchViewIndex'; private $_cachedActiveViewIndex=-1; private $_ignoreBubbleEvents=false; /** * Processes an object that is created during parsing template. * This method overrides the parent implementation by adding only {@link TView} * controls as children. * @param string|TComponent text string or component parsed and instantiated in template * @see createdOnTemplate * @throws TConfigurationException if controls other than {@link TView} is being added */ public function addParsedObject($object) { if($object instanceof TView) $this->getControls()->add($object); else if(!is_string($object)) throw new TConfigurationException('multiview_view_required'); } /** * Creates a control collection object that is to be used to hold child controls * @return TViewCollection control collection */ protected function createControlCollection() { return new TViewCollection($this); } /** * @return integer the zero-based index of the current view in the view collection. -1 if no active view. Default is -1. */ public function getActiveViewIndex() { if($this->_cachedActiveViewIndex>-1) return $this->_cachedActiveViewIndex; else return $this->getControlState('ActiveViewIndex',-1); } /** * @param integer the zero-based index of the current view in the view collection. -1 if no active view. * @throws TInvalidDataValueException if the view index is invalid */ public function setActiveViewIndex($value) { if(($index=TPropertyValue::ensureInteger($value))<0) $index=-1; $views=$this->getViews(); $count=$views->getCount(); if($count===0 && $this->getControlStage()<TControl::CS_CHILD_INITIALIZED) $this->_cachedActiveViewIndex=$index; else if($index<$count) { $this->setControlState('ActiveViewIndex',$index,-1); $this->_cachedActiveViewIndex=-1; if($index>=0) $this->activateView($views->itemAt($index),true); } else throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index); } /** * @return TView the currently active view, null if no active view * @throws TInvalidDataValueException if the current active view index is invalid */ public function getActiveView() { $index=$this->getActiveViewIndex(); $views=$this->getViews(); if($index>=$views->getCount()) throw new TInvalidDataValueException('multiview_activeviewindex_invalid',$index); if($index<0) return null; $view=$views->itemAt($index); if(!$view->getActive()) $this->activateView($view,false); return $view; } /** * @param TView the view to be activated * @throws TInvalidOperationException if the view is not in the view collection */ public function setActiveView($view) { if(($index=$this->getViews()->indexOf($view))>=0) $this->setActiveViewIndex($index); else throw new TInvalidOperationException('multiview_view_inexistent'); } /** * Activates the specified view. * If there is any view currently active, it will be deactivated. * @param TView the view to be activated * @param boolean whether to trigger OnActiveViewChanged event. */ protected function activateView($view,$triggerViewChangedEvent=true) { if($view->getActive()) return; $triggerEvent=$triggerViewChangedEvent && ($this->getControlStage()>=TControl::CS_STATE_LOADED || ($this->getPage() && !$this->getPage()->getIsPostBack())); foreach($this->getViews() as $v) { if($v===$view) { $view->setActive(true); if($triggerEvent) { $view->onActivate(null); $this->onActiveViewChanged(null); } } else if($v->getActive()) { $v->setActive(false); if($triggerEvent) $v->onDeactivate(null); } } } /** * @return TViewCollection the view collection */ public function getViews() { return $this->getControls(); } /** * Makes the multiview ignore all bubbled events. * This is method is used internally by framework and control * developers. */ public function ignoreBubbleEvents() { $this->_ignoreBubbleEvents=true; } /** * Initializes the active view if any. * This method overrides the parent implementation. * @param TEventParameter event parameter */ public function onInit($param) { parent::onInit($param); if($this->_cachedActiveViewIndex>=0) $this->setActiveViewIndex($this->_cachedActiveViewIndex); } /** * Raises <b>OnActiveViewChanged</b> event. * The event is raised when the currently active view is changed to a new one * @param TEventParameter event parameter */ public function onActiveViewChanged($param) { $this->raiseEvent('OnActiveViewChanged',$this,$param); } /** * Processes the events bubbled from child controls. * The method handles view-related command events. * @param TControl sender of the event * @param mixed event parameter * @return boolean whether this event is handled */ public function bubbleEvent($sender,$param) { if(!$this->_ignoreBubbleEvents && ($param instanceof TCommandEventParameter)) { switch($param->getCommandName()) { case self::CMD_NEXTVIEW: if(($index=$this->getActiveViewIndex())<$this->getViews()->getCount()-1) $this->setActiveViewIndex($index+1); else $this->setActiveViewIndex(-1); return true; case self::CMD_PREVIOUSVIEW: if(($index=$this->getActiveViewIndex())>=0) $this->setActiveViewIndex($index-1); return true; case self::CMD_SWITCHVIEWID: $view=$this->findControl($viewID=$param->getCommandParameter()); if($view!==null && $view->getParent()===$this) { $this->setActiveView($view); return true; } else throw new TInvalidDataValueException('multiview_viewid_invalid', $viewID); case self::CMD_SWITCHVIEWINDEX: $index=TPropertyValue::ensureInteger($param->getCommandParameter()); $this->setActiveViewIndex($index); return true; } } return false; } /** * Loads state into the wizard. * This method is invoked by the framework when the control state is being saved. */ public function loadState() { // a dummy call to ensure the view is activated $this->getActiveView(); } /** * Renders the currently active view. * @param THtmlWriter the writer for the rendering purpose. */ public function render($writer) { if(($view=$this->getActiveView())!==null) $view->renderControl($writer); } } /** * TViewCollection class. * TViewCollection represents a collection that only takes {@link TView} instances * as collection elements. * @author Qiang Xue <qiang.xue@gmail.com> * @version $Id$ * @package System.Web.UI.WebControls * @since 3.0 */ class TViewCollection extends TControlCollection { /** * Inserts an item at the specified position. * This overrides the parent implementation by ensuring only {@link TView} * controls be added into the collection. * @param integer the speicified position. * @param mixed new item * @throws TInvalidDataTypeException if the item to be inserted is neither a string nor a TControl. */ public function insertAt($index,$item) { if($item instanceof TView) parent::insertAt($index,$item); else throw new TInvalidDataTypeException('viewcollection_view_required'); } } /** * TView class * * TView is a container for a group of controls. TView must be contained * within a {@link TMultiView} control in which only one view can be active * at one time. * * To activate a view, set {@link setActive Active} to true. * When a view is activated, it raises {@link onActivate OnActivate} event; * and when a view is deactivated, it raises {@link onDeactivate OnDeactivate}. * * @author Qiang Xue <qiang.xue@gmail.com> * @version $Id$ * @package System.Web.UI.WebControls * @since 3.0 */ class TView extends TControl { private $_active=false; /** * Raises <b>OnActivate</b> event. * @param TEventParameter event parameter */ public function onActivate($param) { $this->raiseEvent('OnActivate',$this,$param); } /** * Raises <b>OnDeactivate</b> event. * @param TEventParameter event parameter */ public function onDeactivate($param) { $this->raiseEvent('OnDeactivate',$this,$param); } /** * @return boolean whether this view is active. Defaults to false. */ public function getActive() { return $this->_active; } /** * @param boolean whether this view is active. */ public function setActive($value) { $value=TPropertyValue::ensureBoolean($value); $this->_active=$value; parent::setVisible($value); } /** * @param boolean whether the parents should also be checked if visible * @return boolean whether this view is visible. * The view is visible if it is active and its parent is visible. */ public function getVisible($checkParents=true) { if(($parent=$this->getParent())===null) return $this->getActive(); else if($this->getActive()) return $parent->getVisible($checkParents); else return false; } /** * @param boolean * @throws TInvalidOperationException whenever this method is invoked. */ public function setVisible($value) { throw new TInvalidOperationException('view_visible_readonly'); } }