Advanced TabBox

A control class contributed by
Francesco Danti, demonstrating a
XULTabBox extended to add several new features including automated
adding and removing of tabs, auto-close, adding tabs in background and
scrolling tabs horizontally.
Updated: several new features. See also the
documentation and the
forum thread.
Updated 2: minor bugfixes and separation of component and sample code.
The
XULAdvancedTabBox component:
<?php
define('_ADV_TABBOX_MENU_CLOSE_ALL','Close all tabs');
define('_ADV_TABBOX_MENU_CLOSE_ALL_EXCEPT_ACTIVE','Close all tabs except active tab');
define('_ADV_TABBOX_MENU_CLOSE_ONLY_ACTIVE','Close only active tab');
/**
* XULAdvancedTabBox
*
* @package XULDataComponents
* @subpackage XULContainers
* @author Francesco Danti
* @author Cesare Bevacqua
* @copyright Oracol Tech s.r.l.
* @link http://www.oracoltech.com
* @version 2010
*/
class XULAdvancedTabBox extends XULTabBox {
public $tabs = array();
public $panels = array();
public $tabMenu;
public $ifEmptyFlexZero = FALSE;
public $restoreFlex = 20;
public $hideComponentIfEmpty= array();
/**
* XULAdvancedTabBox::__construct()
*
* @return void
*/
public function __construct() {
parent::__construct();
$this->tabs = new XULTabs();
$this->panels = new XULTabPanels();
$this->tabMenu = new tabMenu($this);
$this->addChild(new XULPopupSet($this->tabMenu));
$this->dropMarker = new XULDropmarker();
$this->dropMarker->popup($this->tabMenu);
$this->addChild(new XULHBox(new XULAdvancedTabBoxArrowScrollBox($this, $this->tabs) , new XULSpacer(1) , $this->dropMarker) , $this->panels);
$this->dropMarker->hidden(TRUE);
$this->setEventHandler('onAfterAttach', $this, 'setEventsAndDoFirstLoad');
}
/**
* XULAdvancedTabBox::setEventsAndDoFirstLoad()
* @internal
* @return void
*/
public function setEventsAndDoFirstLoad($e) {
$this->panels->margin(0)->padding(0);
$this->dropMarker->className('dropmarkerButtons');
}
/**
* XULAdvancedTabBox::addTabbedPanel()
* @param string name label of the tab
* @param node panel content panel to be attached
* @param bool background open in background
* @return void
*/
public function addTabbedPanel($name, $panel, $background = false) {
$tab = new XULAdvancedTab($name);
$this->tabs->addChild($tab);
$this->panels->addChild(new XULAdvancedTabPanel($this, $tab, $panel));
$tab->build($this);
$this->tabMenu->addMenu($tab);
if (!$background) $this->selectedTab($tab);
$this->checkIfEmptyFlexZero();
}
/**
* XULAdvancedTabBox::removeTabbedPanel()
*
* @param node panel content panel to be removed
* @return void
*/
public function removeTabbedPanel($panel) {
$panel->parent->selfClose();
return;
}
/**
* XULAdvancedTabBox::removeTabbedTab()
*
* @param node tab tab to be removed
* @return int the posintion index of the item
*/
public function removeTabbedTab($tab) {
$pos = $this->tabs->findChild($tab);
$focused = ($tab === $this->tabs->selectedItem());
$this->tabs->children[$pos]->removeNode();
$this->panels->children[$pos]->removeNode();
$pos = ($pos > 0) ? $pos - 1 : 0;
if ($focused && !$this->isEmpty()) $this->tabs->selectedItem($this->tabs->children[$pos]);
$this->checkIfEmptyFlexZero();
return $pos;
}
/**
* XULAdvancedTabBox::closeAll()
*
* @return void
*/
public function closeAll($e = NULL, $leaveActive = FALSE, $posActive = - 1) {
if($this->isEmpty()) return;
if ($leaveActive) {
$pos = $this->tabs->findChild($this->tabs->selectedItem());
$selectedTab = $this->tabs->children[$pos]->extractNode();
$selectedPan = $this->panels->children[$pos]->extractNode();
}
$this->tabs->removeChildren();
$this->panels->removeChildren();
if ($leaveActive) $this->addTabbedPanel($selectedTab->label, $selectedPan);
$this->checkIfEmptyFlexZero();
}
/**
* XULAdvancedTabBox::closeAllNoActive()
*
* @return void
*/
public function closeAllNoActive($e = NULL) {
$this->closeAll(NULL, TRUE);
}
/**
* XULAdvancedTabBox::closeActiveTab()
*
* @return void
*/
public function closeActiveTab($e = NULL) {
$pos = $this->removeTabbedTab($this->tabs->selectedItem());
$this->checkIfEmptyFlexZero();
if ($this->isEmpty()) return;
$selectNext = $pos - 1;
$this->selectedTab($this->tabs->children[($selectNext < 0) ? 0 : $selectNext]);
}
/**
* XULAdvancedTabBox::isEmpty()
*
* @return bool
*/
public function isEmpty() {
if (count($this->tabs->children) > 0) return false;
return true;
}
/**
* XULAdvancedTabBox::setIfEmptyFlexZero()
*
* @return void
*/
public function setIfEmptyFlexZero($bool) {
$this->ifEmptyFlexZero = $bool;
$this->restoreFlex = $this->flex;
$this->checkIfEmptyFlexZero();
}
/**
* XULAdvancedTabBox::addHideComponentIfEmpty()
*
* @return void
*/
public function addHideComponentIfEmpty($component) {
$this->hideComponentIfEmpty[] = $component;
}
/**
* XULAdvancedTabBox::checkIfEmptyFlexZero()
*
* @return void
*/
private function checkIfEmptyFlexZero() {
if ($this->ifEmptyFlexZero) {
if ($this->isEmpty()) {
$this->flex(0);
$this->hidden(TRUE);
foreach($this->hideComponentIfEmpty as $cmp)
$cmp->hidden(TRUE);
} else {
$this->flex($this->restoreFlex);
$this->hidden(FALSE);
foreach($this->hideComponentIfEmpty as $cmp)
$cmp->hidden(FALSE);
}
}
$this->dropMarker->hidden($this->isEmpty());
}
}
/**
* tabMenu
*
* @package XULDataComponents
* @subpackage XULDataComponents
* @author Francesco Danti
* @author Cesare Bevacqua
* @copyright Oracol Tech s.r.l.
* @link http://www.oracoltech.com
* @version 2010
*/
class tabMenu extends XULMenuPopup {
private $linkedXULAdvancedTabBox;
private $stardardMenu = TRUE;
/**
* tabMenu::__construct()
*
* @return void
*/
function __construct($linkedXULAdvancedTabBox, $stardardMenu = true) {
parent::__construct();
$this->stardardMenu = $stardardMenu;
$this->linkedXULAdvancedTabBox = $linkedXULAdvancedTabBox;
$this->setEventHandler('onAfterAttach', $this, 'setEventsAndDoFirstLoad');
}
/**
* tabMenu::setEventsAndDoFirstLoad()
*
* @return void
*/
public function setEventsAndDoFirstLoad($e) {
$this->addStandardMenus();
$this->setEvent('popupshowing',MSG_SEND,$this,'onBeforeOpen',$this);
}
/**
* tabMenu::addMenu()
*
* @return void
*/
function addMenu($tab) {
$menu = new XULMenuItemTabs($tab, $this->linkedXULAdvancedTabBox);
$this->addChild($menu);
}
/**
* tabMenu::delMenu()
*
* @return void
*/
function delMenu() {
}
/**
* tabMenu::addStandardMenus()
*
* @return void
*/
function addStandardMenus() {
if (!$this->stardardMenu) return;
$mnuCloseAll = new XULMenuItem(_ADV_TABBOX_MENU_CLOSE_ALL);
$mnuCloseAllNoActive = new XULMenuItem(_ADV_TABBOX_MENU_CLOSE_ALL_EXCEPT_ACTIVE);
$mnuCloseActive = new XULMenuItem(_ADV_TABBOX_MENU_CLOSE_ONLY_ACTIVE);
if(count($this->children) > 0 )
$this->addChildFirst($mnuCloseAll, $mnuCloseAllNoActive, $mnuCloseActive, new XULMenuSeparator());
else
$this->addChild($mnuCloseAll, $mnuCloseAllNoActive, $mnuCloseActive, new XULMenuSeparator());
$mnuCloseAll->setEvent('command', MSG_SEND, $this->linkedXULAdvancedTabBox, 'closeAll', $this->linkedXULAdvancedTabBox);
$mnuCloseAllNoActive->setEvent('command', MSG_SEND, $this->linkedXULAdvancedTabBox, 'closeAllNoActive', $this->linkedXULAdvancedTabBox);
$mnuCloseActive->setEvent('command', MSG_SEND, $this->linkedXULAdvancedTabBox, 'closeActiveTab', $this->linkedXULAdvancedTabBox);
}
public function onBeforeOpen($e) {
$this->removeChildren();
$this->addStandardMenus();
foreach($this->linkedXULAdvancedTabBox->tabs->children as $tab)
$this->addMenu($tab);
}
}
/**
* XULMenuItemTabs
*
* @package XULDataComponents
* @subpackage XULDataComponents
* @author Francesco Danti
* @author Cesare Bevacqua
* @copyright Oracol Tech s.r.l.
* @link http://www.oracoltech.com
* @version 2010
*/
class XULMenuItemTabs extends XULMenuItem {
private $linkedXULAdvancedTabBox;
private $tab;
/**
* XULMenuItemTabs::__construct()
*
* @return void
*/
function __construct($tab, $linkedXULAdvancedTabBox) {
parent::__construct($tab->label);
$this->linkedXULAdvancedTabBox = $linkedXULAdvancedTabBox;
$this->tab = $tab;
$this->setEventHandler('onAfterAttach', $this, 'setEventsAndDoFirstLoad');
}
/**
* XULMenuItemTabs::setEventsAndDoFirstLoad()
*
* @return void
*/
public function setEventsAndDoFirstLoad($e) {
$this->setEvent('command', MSG_SEND, $this, 'selectTab');
}
/**
* XULMenuItemTabs::selectTab()
*
* @return void
*/
function selectTab() {
$this->linkedXULAdvancedTabBox->selectedTab($this->tab);
}
}
/**
* XULAdvancedTab
*
* @package XULDataComponents
* @subpackage XULDataComponents
* @author Francesco Danti
* @author Cesare Bevacqua
* @copyright Oracol Tech s.r.l.
* @link http://www.oracoltech.com
* @version 2010
*/
class XULAdvancedTab extends XULTab {
public $tabbox;
public $contextMenu;
/**
* XULAdvancedTab::__construct()
*
* @return void
*/
public function __construct($label, $image = NULL) {
parent::__construct();
$this->label($label);
$this->removeChildren();
if ($image) $this->addChild(new XULImage($this->image));
$this->addChild(new XULLabel($this->label));
$this->mnuClose = new XULMenuItem('Close');
$this->addChild(new XULPopupSet($this->contextMenu = new XULMenuPopup($this->mnuClose)));
$this->setEventHandler('onAfterAttach', $this, 'setEventsAndDoFirstLoad');
}
/**
* XULAdvancedTab::setEventsAndDoFirstLoad()
*
* @return void
*/
public function setEventsAndDoFirstLoad($e) {
$this->mnuClose->setEvent('command', MSG_SEND, $this, 'selfClosetab');
}
/**
* XULAdvancedTab::build()
*
* @return void
*/
public function build($tabbox) {
$this->tabbox = $tabbox;
$this->context($this->contextMenu);
}
/**
* XULAdvancedTab::selfClosetab()
*
* @return void
*/
public function selfClosetab($e) {
$this->tabbox->removeTabbedTab($this);
}
}
/**
* XULAdvancedTabBoxArrowScrollBox
*
* @package XULDataComponents
* @subpackage XULDataComponents
* @author Francesco Danti
* @author Cesare Bevacqua
* @copyright Oracol Tech s.r.l.
* @link http://www.oracoltech.com
* @version 2010
*/
class XULAdvancedTabBoxArrowScrollBox extends XULArrowScrollBox {
public $flex = 1;
public $containerTabBox;
public $orient = 'horizontal';
public $closeButton;
/**
* XULAdvancedTabBoxArrowScrollBox::__construct()
*
* @return void
*/
public function __construct($cont, $child) {
$this->containerTabBox = $cont;
$this->addChild($child);
}
/**
* XULAdvancedTabBoxArrowScrollBox::selectedTab()
*
* @return void
*/
public function selectedTab($tab = NULL) {
$this->containerTabBox->selectedTab($tab);
}
/**
* XULAdvancedTabBoxArrowScrollBox::selectedPanel()
*
* @return void
*/
public function selectedPanel($tab = NULL) {
$this->containerTabBox->selectedPanel($tab);
}
}
/**
* XULAdvancedTabPanel
*
* @package XULDataComponents
* @subpackage XULDataComponents
* @author Francesco Danti
* @author Cesare Bevacqua
* @copyright Oracol Tech s.r.l.
* @link http://www.oracoltech.com
* @version 2010
*/
class XULAdvancedTabPanel extends XULTabPanel {
public $flex = 1;
private $tab;
private $linkedXULAdvancedTabBox;
/**
* XULAdvancedTabPanel::__construct()
*
* @return void
*/
function __construct($linkedXULAdvancedTabBox, $tab, $panel) {
parent::__construct();
$this->linkedXULAdvancedTabBox = $linkedXULAdvancedTabBox;
$this->tab = $tab;
$this->addChild($panel);
}
/**
* XULAdvancedTabPanel::selfClose()
*
* @return void
*/
public function selfClose() {
$this->linkedXULAdvancedTabBox->removeTabbedTab($this->tab);
}
}
A
sample application demonstrating the use of this component:
<?php
//============================================================+
// Author: Francesco "Abbadon1334" Danti
//
// (c) Copyright:
// Francesco Danti
// S.C. Oracol Tech s.r.l.
// www.oracoltech.com
// info@oracoltech.com
//============================================================+
function authorizeLogin( $args, $user, $pass ) {
// We'll just hardcode these credentials here, normally you'd want to do something
// more sophisticated here...
return ($user == 'user' && $pass == 'password');
}
function getApplication( $args ) {
// Return the name of the application class that should be started.
return 'testAdvTabBox';
}
class testAdvTabBox extends Application {
public $centerscreen = true;
public function init( $event ) {
// Set the window title and size
$this->window->title( 'Advanced TabBox Demo' );
$this->window->size( 1024, 740 );
$tBar = new XULToolBox(
new XULToolBar(
$this->mnuLeftAdd = new XULToolBarButton('Add panel left')
,$this->mnuLeftAddBack = new XULToolBarButton('Add panel left in background')
,$this->mnuLeftCloseAll = new XULToolBarButton('Close all left')
,$this->mnuLeftCloseAllExcActive = new XULToolBarButton('Close all except active left')
,new XULSpacer(1)
,$this->mnuRightAdd = new XULToolBarButton('Add panel right')
,$this->mnuRightAddBack = new XULToolBarButton('Add panel right in background')
,$this->mnuRightCloseAll = new XULToolBarButton('Close all right')
,$this->mnuRightCloseAllExcActive = new XULToolBarButton('Close all except active right')
)
);
$this->advTabBoxLeft = new XULAdvancedTabBox(1);
$this->advTabBoxRight = new XULAdvancedTabBox(3);
$mainSplitter = new XULSplitter();
$mainSplitter->addChild( new XULGrippy() );
$this->window->addChild(
$tBar
,new XULHBox(
1,
$this->advTabBoxLeft
,$mainSplitter
,$this->advTabBoxRight
)
);
$this->mnuLeftAdd->setEvent( 'command', MSG_SEND, $this, 'leftAdd');
$this->mnuLeftAddBack->setEvent( 'command', MSG_SEND, $this, 'leftAddBack');
$this->mnuLeftCloseAll->setEvent( 'command', MSG_SEND, $this, 'leftCloseAll');
$this->mnuLeftCloseAllExcActive->setEvent( 'command', MSG_SEND, $this, 'leftCloseAllExcActive');
$this->mnuRightAdd->setEvent( 'command', MSG_SEND, $this, 'rightAdd');
$this->mnuRightAddBack->setEvent( 'command', MSG_SEND, $this, 'rightAddBack');
$this->mnuRightCloseAll->setEvent( 'command', MSG_SEND, $this, 'rightCloseAll');
$this->mnuRightCloseAllExcActive->setEvent( 'command', MSG_SEND, $this, 'rightCloseAllExcActive');
}
public function leftAdd($e){
$this->advTabBoxLeft->addTabbedPanel( date("H:i:s",time()), new dummyPanel());
}
public function leftAddBack($e){
$this->advTabBoxLeft->addTabbedPanel( date("H:i:s",time()),new dummyPanel(),TRUE);
}
public function leftCloseAll($e){
$this->advTabBoxLeft->closeAll();
}
public function leftCloseAllExcActive($e){
$this->advTabBoxLeft->closeAll(NULL,TRUE);
}
public function rightAdd($e){
$this->advTabBoxRight->addTabbedPanel( date("H:i:s",time()),new dummyPanel());
}
public function rightAddBack($e){
$this->advTabBoxRight->addTabbedPanel( date("H:i:s",time()),new dummyPanel(),TRUE);
}
public function rightCloseAll($e){
$this->advTabBoxRight->closeAll();
}
public function rightCloseAllExcActive($e){
$this->advTabBoxRight->closeAll(NULL,TRUE);
}
}
class dummyPanel extends XULVBox {
public function __construct() {
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
$this->addChild( new XULLabel( "dummy Text "));
}
}