- <?php
- /**
- * sptpl_clsPageMgr.php
- *
- * Class PageManeger definition.
- * This class manage all the output detail, such margins, page size (and
- * skip to the next page) and print (to the file) each row.
- *
- * @copyright sptpl_clsPageMgr.php is part of Sptpl project {@link http://www.andrioli.com/en/sptpl.html} and it is LGPL
- * @author Andrioli Darvin <darvin (inside) andrioli (dot) com>
- * @version $Header: d:\cvs/classistd/sptpl/sptpl_clsPageMgr.php,v 2.16 2005/03/17 12:46:48 Darvin Exp $
- */
- /*
- * +-------------------------------------------------------------------------+
- * | Sptpl |
- * +-------------------------------------------------------------------------+
- * | Copyright (c) 2003-2005 Andrioli Darvin |
- * | Email <darvin (inside) andrioli (dot) com> |
- * | Web http://www.andrioli.com/en/sptpl.html |
- * | Download http://www.phpclasses.org/browse.html/package/1326.html |
- * | |
- * +-------------------------------------------------------------------------+
- * | This library is free software; you can redistribute it and/or modify |
- * | it under the terms of the GNU Lesser General Public License as |
- * | published by the Free Software Foundation; either version 2 of the |
- * | License, or (at your option) any later version. |
- * | |
- * | This library is distributed in the hope that it will be useful, but |
- * | WITHOUT ANY WARRANTY; without even the implied warranty of |
- * | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
- * | Lesser General Public License for more details. |
- * | |
- * | You should have received a copy of the GNU Lesser General Public |
- * | License along with this library; if not, write to the Free Software |
- * | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
- * +-------------------------------------------------------------------------+
- */
-
-
-
- class CPageMgr {
-
- /**
- * Handler to the output file
- * @var integer
- */
- var $OutputFp;
- /**
- * Size of the page (width, length) as number
- * of characters and rows.
- * Index length = number of rows
- * Index width = number of characters for each row
- * @var array $PageSize
- */
- var $PageSize;
- /**
- * Table contains the size for the ISO code
- * Each index contains an array with two key length e width
- *
- * @var array
- */
- var $tblFormatIso;
- /**
- * Page format from the configuration file.
- * It is an ISO code
- * @see $tblFormatIso
- * @var string
- */
- var $PageFormat;
- /**
- * Margins setting.
- * Allowed index: top, bottom, left, right
- * @var array $Margins
- */
- var $Margins;
-
- /**
- * Index of the current item to be inserted into $PageData
- * @var integer $CurrentLine
- * @see WriteOut()
- */
- var $CurrentLine;
-
- /**
- * Index of the first line of the page
- * @var integer
- * @see WriteOut()
- */
- var $TopPageLine;
-
- var $CurrentPage;
- /**
- * Array holding the text to print at the begin and end page.
- * See ParseXml for detail about the text stored
- * @var array
- * @see ParseXml()
- */
- var $Report;
- /**
- * Reference to the DataStorage class
- * @var object CDataStorage
- */
- var $clsDataManager;
- /**
- * Memory image of the page, each item of this array
- * is one row of the page. Each row is made by many columns
- * The columns 0 contains the whole page, the index > 0
- * point to the column defined by column set.
- * Each element is a CUnit object
- * The array is load by WriteOut and
- * written to the file by _ClosePage
- * @var array $PageData
- * @see WriteOut()
- * @see _ClosePage()
- */
- var $PageData;
- /**
- * Current ColumnSet
- * Array of CColumn object.
- * Each block my set its own column set.
- * Columns 0 is the whole page
- * @var array
- * @see NewColumnSet()
- */
- var $ColumnSet;
- /**
- * Column set used to print out the page header
- * @var array
- */
- var $HeaderColSet;
- /**
- * Column set used to print out the page footer
- * @var array
- */
- var $FooterColSet;
- /**
- * array with all columnset defined. The first index is the columnsset
- * identifier
- * @var array
- */
- var $DefinedColumnSet;
- /**
- * Id of the current columnset selected. It is uesd to avoid
- * to reload the same columnset if it is selected again
- * @var string
- * @see NewColumnSet()
- */
- var $CurrentColumnSetId;
- /**
- * Max height for each row.
- * @var array
- */
- var $LineHeight;
- /**
- * Array containing all defined class CFont
- * @var array $Fonts
- */
- var $Fonts;
- /**
- * Class constructor. It initalize all configuration varaibale
- * @param object CDataStorage &$DataMgr Reference to the DataStorage istance
- * @access public
- */
- function CPageMgr(&$DataMgr)
- {
- // set the default margins and page size.
- $this->tblFormatIso=array();
- $this->PageSize=array( 'width' => 80,
- 'length' => 66 );
- $this->Margins=array('top' =>2,
- 'bottom' =>2,
- 'left' =>2,
- 'right' =>2);
- $this->Report=array();
- $this->clsDataManager=&$DataMgr;
- $this->PageData=array();
- $this->Fonts=array();
- $this->_CreateDefaultFont();
- $this->ColumnSet=array();
- $this->ColumnSet[0]=new CColumn();
- $this->HeaderColSet[0]=new CColumn();
- $this->FooterColSet[0]=new CColumn();
- $this->CurrentFont='STANDARD';
- $this->ColumnSet[0]->setDefaultFont($this->Fonts['STANDARD']);
- $this->HeaderColSet[0]->setDefaultFont($this->Fonts['STANDARD']);
- $this->FooterColSet[0]->setDefaultFont($this->Fonts['STANDARD']);
- $this->LastWrittenLine=0;
- $this->TopPageLine=1;
- $this->LineHeight=array();
- $this->CurrentColumnSet=-1; // No default columnset
- $this->DefinedColumnSet=array();
- }
- /**
- * Parse the configuration node for a new information about the layout
- * of the page
- * @param object CXml2Array Class containingg the configuration
- * @access public
- */
- function ParseXml($cfg)
- {
-
- switch(strtolower($cfg->GetNodeName())) {
- case 'columnset':
- $this->_SetColumnSet($cfg);
- break;
- case 'margin' :
- $this->_SetMargins($cfg);
- break;
- case 'pagesize' :
- $this->_SetPageSize($cfg);
- break;
- case 'beginreport' :
- $this->Report['beginreport']=new CRow($this->clsDataManager,$cfg);
- break;
- case 'closereport' :
- $this->Report['closereport']=new CRow($this->clsDataManager,$cfg);
- break;
- case 'openpage' :
- $this->Report['openpage']=new CRowHeader($this->clsDataManager,$cfg);
- break;
- case 'closepage' :
- $this->Report['closepage']=new CRowFooter($this->clsDataManager,$cfg);
- break;
-
- }
- }
-
- /**
- * Create one default font named STANDARD
- * @access private
- */
- function _CreateDefaultFont()
- {
- $q="?"; // It makes happy my editor!!
- $XmlStr="<".$q."xml version='1.0' ".$q.">
- <font id='STANDARD' size='1' />
- ";
- $tmpRoot=new CXml2Array();
- $tmpRoot->LoadFromString($XmlStr);
- $this->NewFont($tmpRoot);
-
- }
- /**
- * Create an istance of the CFont class based on configuration
- * file.
- * @param object CXml2Array Node with font configuration
- * @access public
- */
- function NewFont($node)
- {
- $tmpFont=new CFont($node);
- if(array_key_exists($tmpFont->GetId(),$this->Fonts))
- trigger_error('Font '.$tmpFont->GetId().' already exist',E_USER_ERROR);
- $this->Fonts[$tmpFont->GetId()]=$tmpFont;
- }
-
- /**
- * Load columnset settings from the configuration file
- * Default values are set by the class constructor.
- * @param object CXml2Array
- * @access private
- *
- */
- function _SetColumnSet($Cfg)
- {
- $ColumNo=0;
- // Check some attribute
- while(($ret=$Cfg->EachAttribute())!=FALSE)
- {
- list($AttribName,$value)=$ret;
- switch(strtolower($AttribName))
- {
- case 'id' :
- $Id=$value;
- break;
- }
- }
- if($Id=='')
- trigger_error('Configuration error: columnset without attribute id',E_USER_ERROR);
- while(($ret=$Cfg->EachChild())!=FALSE)
- {
- list($ChildName,$Child)=$ret;
- switch(strtolower($ChildName)) {
- case 'column' :
- $this->DefinedColumnSet[$Id][$ColumNo]=new CColumn();
- $this->DefinedColumnSet[$Id][$ColumNo]->setDefaultFont($this->Fonts['STANDARD']);
- $this->DefinedColumnSet[$Id][$ColumNo]->Parse($Child);
- $ColumNo++;
- break;
- default:
- trigger_error('Unknown tag '.$Child->GetNodeName(),E_USER_ERROR);
- break;
- }
- }
- }
-
- /**
- * Load margins setting from the configuration file
- * Default values are set by the class constructor.
- * @param object CXml2Array
- * @access private
- *
- */
- function _SetMargins($Cfg)
- {
-
- while(($ret=$Cfg->EachChild())!=FALSE)
- {
- list($ChildName,$Child)=$ret;
- switch(strtolower($ChildName)) {
- case 'top' :
- $value=trim($Child->GetText());
- if(!ctype_digit($value))
- trigger_error('Tag '.$Child->GetNodeName(). ', numeric value expected',E_USER_ERROR);
- $this->Margins['top']=$value;
- break;
- case 'bottom' :
- $value=trim($Child->GetText());
- if(!ctype_digit($value))
- trigger_error('Tag '.$Child->GetNodeName(). ', numeric value expected',E_USER_ERROR);
- $this->Margins['bottom']=$value;
- break;
- case 'left' :
- $value=trim($Child->GetText());
- if(!ctype_digit($value))
- trigger_error('Tag '.$Child->GetNodeName(). ', numeric value expected',E_USER_ERROR);
- $this->Margins['left']=$value;
- break;
- case 'right' :
- $value=trim($Child->GetText());
- if(!ctype_digit($value))
- trigger_error('Tag '.$Child->GetNodeName(). ', numeric value expected',E_USER_ERROR);
- $this->Margins['right']=$value;
- break;
- default:
- trigger_error('Unknown tag '.$Child->GetNodeName(),E_USER_ERROR);
- break;
- }
- }
- }
- /**
- * Load the size of the page from the configuration file.
- * Default values are set by the class constructor.
- * @param object CXml2Array $Cfg
- * @access private
- *
- */
- function _SetPageSize($Cfg)
- {
- while(($ret=$Cfg->EachChild())!=FALSE)
- {
- list($ChildName,$Child)=$ret;
- switch(strtolower($ChildName)) {
- case 'length' :
- $value=trim($Child->GetText());
- if(!ctype_digit($value))
- trigger_error('Tag '.$Child->GetNodeName(). ', numeric value expected',E_USER_ERROR);
- $this->PageSize['length']=$value;
- break;
- case 'width' :
- $value=trim($Child->GetText());
- if(!ctype_digit($value))
- trigger_error('Tag '.$Child->GetNodeName(). ', numeric value expected',E_USER_ERROR);
- $this->PageSize['width']=$value;
- break;
- case 'pageformat' :
- $value=trim($Child->GetText());
- if(!array_key_exists($value,$this->tblFormatIso))
- trigger_error('Tag '.$Child->GetNodeName(). ', format unknown',E_USER_ERROR);
- $this->PageFormat=$value;
- break;
- default:
- trigger_error('Unknown tag '.$Child->GetNodeName(),E_USER_ERROR);
- break;
- }
- }
- }
-
- /**
- * Check whether the margins are placed inside or outside the page
- * @access private
- */
- function CheckMargins()
- {
- if(($this->Margins['top']+$this->Margins['bottom'])>$this->PageSize['length'])
- trigger_error('The top or bottom margin are bigger then the size of the page',E_USER_ERROR);
- if(($this->Margins['left']+$this->Margins['right'])>$this->PageSize['width'])
- trigger_error('The left or right margin are bigger then the size of the page',E_USER_ERROR);
- }
-
- /**
- * Function executed at the end of the xml parsing. I run the final configuration
- * checks and complete the configration data
- * @access public
- */
- function EndParseXml()
- {
- $this->CheckMargins();
- $this->ColumnSet[0]->SetWidth($this->PageSize['width']-$this->Margins['left']-$this->Margins['right']); // page with
- $this->ColumnSet[0]->SetLeftPos($this->Margins['left']); // starting point of the column 0
- //$GLOBALS['dbg']->pray($this->DefinedColumnSet);
- // die();
- foreach($this->DefinedColumnSet as $colSet)
- {
- $nCol=count($colSet);
- for($i=0;$i<$nCol;$i++)
- $colSet[$i]->EndParseXml();
- }
- // As header/footer column set I use the default with only one column
- $this->HeaderColSet[0]->SetWidth($this->PageSize['width']-$this->Margins['left']-$this->Margins['right']); // page with
- $this->HeaderColSet[0]->SetLeftPos($this->Margins['left']); // starting point of the column 0
- $this->FooterColSet[0]->SetWidth($this->PageSize['width']-$this->Margins['left']-$this->Margins['right']); // page with
- $this->FooterColSet[0]->SetLeftPos($this->Margins['left']); // starting point of the column 0
-
- }
-
- /**
- * Set new columnset. Each block may hve its own columnset. Before write the text, the
- * block passes its configuration. This configuration override the previous one,
- * so I must write the previous text
- * @param string id of the new columnset to use
- * @access public
- */
- function NewColumnSet($NewSet)
- {
- // close the previous
- $this->_ComposeRow($this->ColumnSet);
- // if I already use this set I don't change anything
- if($NewSet==$this->CurrentColumnSetId)
- return(TRUE);
- if(!array_key_exists($NewSet,$this->DefinedColumnSet))
- trigger_error('The columnset id '.$NewSet.' doesn\'t exists',E_USER_ERROR); // '
- $size=count($this->DefinedColumnSet[$NewSet]);
- for($i=0;$i<$size;$i++)
- {
- $this->ColumnSet[$i+1]=$this->DefinedColumnSet[$NewSet][$i];
- }
- $this->CurrentColumnSetId=$NewSet;
- }
- /**
- * Start to printout the report. OPen the output file,
- * initialize some variable.
- * @parameter string $OutFile output file name
- * @access public
- */
- function BeginReport($OutFile)
- {
- $this->OutputFp=fopen($OutFile,'wb');
- $this->CurrentPage=0;
- $this->_OpenPage();
- $this->_StartReport();
- }
-
- /**
- * Perform the requested job for ending the report.
- * Print the end report text, close the current page and the output file
- * @access public
- */
- function CloseReport()
- {
- $this->_EndReport();
- $this->_ComposeRow($this->ColumnSet);
- $this->CurrentLine=$this->PageSize['length']-$this->Margins['bottom'];
- $this->_ClosePage();
- fclose($this->OutputFp);
- }
-
- /**
- * Print out the 'beginreport' text
- * @access public
- */
- function _StartReport()
- {
- if(array_key_exists('beginreport',$this->Report))
- $this->Report['beginreport']->WriteOut($this);
- }
-
- /**
- * Print out the 'closereport' text
- * @access public
- */
- function _EndReport()
- {
- if(array_key_exists('closereport',$this->Report))
- $this->Report['closereport']->WriteOut($this);
- }
-
- /**
- * Begin a new page. Close the previous, if any,
- * and printout the 'openpage' text if specified
- *
- * @access public
- */
- function NewPage($FromComposeRow=FALSE)
- {
- // If this function is not called from composerow, but as page skip
- // in the middle of the page, before change the page, I close the
- // current text
- if(!$FromComposeRow)
- $this->_ComposeRow($this->ColumnSet);
-
- if($this->CurrentPage)
- {
- $this->CurrentLine=$this->PageSize['length']-$this->Margins['bottom'];
- $this->_ClosePage();
- fputs($this->OutputFp,NEWPAGECHAR);
- }
- // print "<br>".$this->CurrentPage;
- $this->_OpenPage();
- }
-
- /**
- * Start the new page
- * @access private
- */
- function _OpenPage()
- {
- $this->PageData=array_fill(1,$this->PageSize['length'],"\r\n");
- $this->CurrentPage++;
- $this->clsDataManager->SetVar('PageNumber',$this->CurrentPage);
- // The open should printed on the first row
- $this->CurrentLine=1;
- if(array_key_exists('openpage',$this->Report))
- {
- $this->Report['openpage']->WriteOut($this);
- }
- $this->CurrentLine=$this->Margins['top']+1;
- }
-
- /**
- * Printout the closepage text (if any)
- * @access private
- */
- function _ClosePage()
- {
- if(array_key_exists('closepage',$this->Report))
- {
- $this->Report['closepage']->WriteOut($this);
- }
- // Now I may download the page to the file
- for($c=1;$c<($this->PageSize['length']+1);$c++)
- fputs($this->OutputFp,$this->PageData[$c]);
- }
-
- /**
- * Now each column has its own text for the current row. This function
- * merge all texts from the columns and fill the PageData array.
- * Note a column may span over one or more row
- * @param array column set to print
- * @param bool the row to print is the footer? If so don't skip to the new page
- * @return bool return true if the function writes almost 1 row
- * @access private
- */
- function _ComposeRow($ColSet,$PageFooter=FALSE)
- {
- $nColumn=count($ColSet);
- $RowWritten=FALSE;
- /*
- if($PageFooter) {
- $GLOBALS['dbg']->pray($this);
- $GLOBALS['dbg']->Backtrace();
- die('prova');
- }
- */
- // $GLOBALS['dbg']->pray($ColSet);
- do
- {
- $Text='';
- $OneColumnWithText=FALSE;
- for($i=0;$i<$nColumn;$i++)
- {
- // I've got one columns, check where it starts
- assert('is_object($ColSet[$i])');
- if($ColSet[$i]->HasAnotherText())
- {
- $LeftPos=$ColSet[$i]->GetLeftTextPos();
- $Diff=$LeftPos-strlen($Text);
- if($Diff>0)
- $Text.=str_repeat(' ',$Diff);
- // Text too long, cut it!
- if($Diff<0)
- $Text=substr($Text,0,$LeftPos-1);
-
- $Text.=$ColSet[$i]->GetText();
- $OneColumnWithText=TRUE;
- }
- }
- if($OneColumnWithText)
- {
- $RowWritten=TRUE;
- if($this->CurrentLine>($this->PageSize['length']-$this->Margins['bottom'])&&!$PageFooter)
- {
- // echo $this->PageSize['length']."-".$this->Margins['bottom']."-".$this->CurrentLine;
- $this->NewPage(TRUE);
- }
- $this->PageData[$this->CurrentLine]=$Text."\r\n";
- $this->CurrentLine++;
- }
- } while($OneColumnWithText);
- // Clear all used text
- for($i=0;$i<$nColumn;$i++)
- $ColSet[$i]->ClearText();
- return($RowWritten);
- }
-
- /**
- * Pass the text to the appropriate column. It returns a CUnit object containing
- * the text with format (alignment, font) according to the given parameters
- * @parameter string $txt Text to write
- * @parameter string $align Text alignment, left, center, right
- * @parameter integer $colPos
- * @parameter integer $Column column where place the text
- * @parameter string Id of the selected font. If not set, the font defined for the column will be used
- * @access public
- */
- function WriteOut($txt,$align='',$colPos=0,$Column=0,$idfont='')
- {
- if(!array_key_exists($Column,$this->ColumnSet))
- trigger_error('Error: the request column '.$Column.' does not exists. Text to print:'.$txt,E_USER_ERROR);
- if($this->ColumnSet[$Column]->AlreadyHaveText()||$Column==0)
- {
- // If I've already set the text for that column in the current line, skip to next
- // Before skip to the new row, I merge the texts from the columns into
- // many row (each column may span over one or more rows)
- $this->_ComposeRow($this->ColumnSet);
- }
- if(!array_key_exists($idfont,$this->Fonts)&&$idfont!='')
- trigger_error('Undefined font '.$idfont,E_USER_ERROR);
- $font=($idfont=='')?NULL:$this->Fonts[$idfont];
- $this->ColumnSet[$Column]->WriteOut($txt,$align,$colPos,$font);
- }
-
- /**
- * Print out the text row (used only for the closepage row)
- * @parameter string $txt Text to write
- * @parameter string $align Text alignment, left, center, right
- * @parameter integer $colPos
- * @access public
- */
- function WriteOutFooterRow($txt,$align='',$colPos=0,$idfont='')
- {
- $font=($idfont=='')?NULL:$this->Fonts[$idfont];
- $this->FooterColSet[0]->WriteOut($txt,$align,$colPos,$font);
- // $GLOBALS['dbg']->pray($this->ColumnSet);
- $this->_ComposeRow($this->FooterColSet,TRUE);
- }
-
- /**
- * Print out the text row (used only for the closepage row)
- * @parameter string $txt Text to write
- * @parameter string $align Text alignment, left, center, right
- * @parameter integer $colPos
- * @access public
- */
- function WriteOutHeaderRow($txt,$align='',$colPos=0,$idfont='')
- {
- $font=($idfont=='')?NULL:$this->Fonts[$idfont];
- $this->HeaderColSet[0]->WriteOut($txt,$align,$colPos,$font);
- // $GLOBALS['dbg']->pray($this->ColumnSet);
- // $GLOBALS['dbg']->pray($this->HeaderColSet);
- // print_r($this->CurrentLine);
- // $GLOBALS['dbg']->BackTrace();
- $this->_ComposeRow($this->HeaderColSet,TRUE);
- }
-
- /**
- * loop over all columns inside the current columnset and print
- * the column's header, if set
- *
- * @access public
- */
- function PrintColumnsHeader()
- {
-
- }
-
- /**
- * Move the currentline up or down of nRow rows. It return TRUE on success,
- * FALSE otherwise
- * @parameter integer $nRow Number of row to add (or subtract) from the
- * current line
- * @access public
- * @return boolean
- */
- function MvRelativePos($nRow)
- {
- if($nRow<0&&abs($nRow)>$this->CurrentLine)
- return(FALSE);
- elseif($nRow+$this->CurrentLine>$this->PageSize['length'])
- {
- $this->_ComposeRow($this->ColumnSet);
- $this->NewPage();
- return(TRUE);
- }
- $this->_ComposeRow($this->ColumnSet);
- $this->CurrentLine+=$nRow;
- return(TRUE);
- }
-
-
- /**
- * Move the currentline to nRow. It return TRUE on success,
- * FALSE otherwise
- * @parameter integer $nRow New current line number
- * @access public
- * @return boolean
- */
- function MvAbsolutePos($nRow)
- {
- if($nRow<1||$nRow>$this->PageSize['length'])
- return(FALSE);
- $this->_ComposeRow($this->ColumnSet);
- $this->CurrentLine=$nRow;
- return(TRUE);
- }
-
- /**
- * Move to the first row after the top margin It return TRUE on success,
- * FALSE otherwise
- * @access public
- * @return boolean
- */
- function MvTop()
- {
- $this->_ComposeRow($this->ColumnSet);
- $this->CurrentLine=$this->Margins['top']+1;
- return(TRUE);
- }
-
- /**
- * Move to the last row before the bottom margin It return TRUE on success,
- * FALSE otherwise
- * @access public
- * @return boolean
- */
- function MvBottom()
- {
- $this->_ComposeRow($this->Columnset);
- $this->CurrentLine=$this->PageSize['length']-$this->Margins['bottom'];
- return(TRUE);
- }
-
- /**
- * Return True if the current PHP version is 5
- * False if is PHP4
- * @return boolean
- * @access public
- */
- function __php5()
- {
- return((version_compare(phpversion(), "5.0.0", "<")==-1)?false:true);
- }
- }
- ?>