diff options
| author | Veit Olschinski <veit@olschinski.de> | 2010-04-05 10:29:41 +0000 |
|---|---|---|
| committer | Veit Olschinski <veit@olschinski.de> | 2010-04-05 10:29:41 +0000 |
| commit | 5bc7b36708d272081ffd2df5658ddf12275447dd (patch) | |
| tree | 7884d88bd634f62d94e0239c911305ac4349dba8 /includes/classes/class_reportbase.php | |
| parent | 5dbb23df7f03aeb32c6c5a3fa6139dd479f9c0b4 (diff) | |
| download | webtrees-5bc7b36708d272081ffd2df5658ddf12275447dd.tar.gz webtrees-5bc7b36708d272081ffd2df5658ddf12275447dd.tar.bz2 webtrees-5bc7b36708d272081ffd2df5658ddf12275447dd.zip | |
Diffstat (limited to 'includes/classes/class_reportbase.php')
| -rw-r--r-- | includes/classes/class_reportbase.php | 3940 |
1 files changed, 3940 insertions, 0 deletions
diff --git a/includes/classes/class_reportbase.php b/includes/classes/class_reportbase.php new file mode 100644 index 0000000000..e4d6bf3931 --- /dev/null +++ b/includes/classes/class_reportbase.php @@ -0,0 +1,3940 @@ +<?php +/** + * Base Report Generator + * + * used by the SAX parser to generate reports from the XML report file. + * + * webtrees: Web based Family History software + * Copyright (C) 2010 webtrees development team. + * + * Derived from PhpGedView + * Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. + * + * Modifications Copyright (c) 2010 Greg Roach + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @package webtrees + * @subpackage Reports + * @version $Id$ + */ + +if (!defined('WT_WEBTREES')) { + header('HTTP/1.0 403 Forbidden'); + exit; +} + +/** + * Enable HTML code to pass for testing + * false = use the old style, HTML disabled + * true = use the new style, HTML enabled + */ +define("WT_RNEW", false); + +define("WT_CLASS_REPORTBASE_PHP", ""); + +$ascii_langs = array("en", "da", "nl", "fr", "he", "hu", "de", "nn", "es"); + +//-- setup special characters array to force embedded fonts +$SpecialOrds = $RTLOrd; +for($i=195; $i<215; $i++) $SpecialOrds[] = $i; + +if (!isset($embed_fonts)) { + if (in_array(WT_LOCALE, $ascii_langs)) { + $embed_fonts = false; + } else { + $embed_fonts = true; + } +} + +/** + * Main PGV Report Class + * + * Document wide functions and variable defaults that will be inherited of the report modules + * @package webtrees + * @subpackage Reports + */ +class PGVReportBase { + /** + * Left Margin (expressed in points) Default: 17.99 mm, 0.7083 inch + * @see PGVRDocSHandler() + * @var float + */ + public $leftmargin = 51; + /** + * Right Margin (expressed in points) Default: 9.87 mm, 0.389 inch + * @see PGVRDocSHandler() + * @var float + */ + public $rightmargin = 28; + /** + * Top Margin (expressed in points) Default: 26.81 mm + * @see PGVRDocSHandler() + * @var float + */ + public $topmargin = 76; + /** + * Bottom Margin (expressed in points) Default: 21.6 mm + * @see PGVRDocSHandler() + * @var float + */ + public $bottommargin = 60; + /** + * Header Margin (expressed in points) Default: 4.93 mm + * @see PGVRDocSHandler() + * @var float + */ + public $headermargin = 14; + /** + * Footer Margin (expressed in points) Default: 9.88 mm, 0.389 inch + * @see PGVRDocSHandler() + * @var float + */ + public $footermargin = 28; + + /** + * Page orientation (portrait, landscape) + * @see PGVRDocSHandler() + * @var string + */ + public $orientation = "portrait"; + /** + * Page format name + * @see PGVRDocSHandler() + * @see PGVReportBase::setup() + * @var string + */ + public $pageFormat = "A4"; + + /** + * Height of page format in points + * @see PGVRDocSHandler() + * @see PGVReportBase::setup() + * @var float + */ + public $pageh = 0.0; + /** + * Width of page format in points + * @see PGVRDocSHandler() + * @see PGVReportBase::setup() + * @var float + */ + public $pagew = 0.0; + + /** + * An array of the PGVRStyles elements found in the document + * @see PGVRStyleSHandler() + * @var array + */ + public $PGVRStyles = array(); + /** + * The default Report font name + * @see PGVRStyleSHandler() + * @var string + */ + public $defaultFont = "dejavusans"; + /** + * The default Report font size + * @see PGVRStyleSHandler() + * @var int + */ + public $defaultFontSize = 12; + + /** + * Header (H), Page header (PH), Body (B) or Footer (F) + * @var string + */ + public $processing = "H"; + + /** + * RTL Language (false=LTR, true=RTL) + * @see PGVReportBase::setup() + * @var boolean + */ + public $rtl = false; + + /** + * User measure unit. + * @var string const + */ + const unit = "pt"; + + /** + * Character set + * @see PGVReportBase::setup() + * @var string + */ + public $charset = "UTF-8"; + + /** + * Show the Generated by... (true=show the text) + * @see PGVRDocSHandler() + * @var boolean + */ + public $showGenText = true; + /** + * Generated By... text + * @see PGVReportBase::setup() + * @var string + */ + public $generatedby = ""; + + /** + * webtrees URL + * @var string const + */ + const pgv_url = WT_WEBTREES_URL; + + /** + * The report title + * @see PGVReportBase::addTitle() + * @var string + */ + public $title = ""; + /** + * Author of the report, the users full name + * @var string + * @todo add the author support + */ +// var $rauthor = ""; + /** + * Keywords + * @see PGVReportBase::setup() + * @var string + */ + public $rkeywords = ""; + /** + * Report Description / Subject + * @see PGVReportBase::addDescription() + * @var string + */ + public $rsubject = ""; + + /** + * Initial Setup - PGVReportBase + * + * Setting up document wide defaults that will be inherited of the report modules + * As DEFAULT A4 and Portrait will be used if not set + * + * @see PGVRDocSHandler() + * @todo add page sizes to wiki + */ + function setup() { + global $TEXT_DIRECTION, $META_KEYWORDS; + + // Set RTL direction + if ($TEXT_DIRECTION == "rtl") { + $this->rtl = true; + } + // Set the character setting + $this->charset = 'UTF-8'; + // Set the Keywords + $this->rkeywords = $META_KEYWORDS; + // Generated By...text + // I18N This is a report footer. %s is the name of the application. + $this->generatedby = i18n::translate('Generated by %s', WT_WEBTREES); + // Only admin should see the version number + if (WT_USER_IS_ADMIN) { + $this->generatedby .= " ".WT_VERSION_TEXT; + } + + // For known size pages + if (($this->pagew == 0) AND ($this->pageh == 0)) { + /** + * The current ISO 216 standard was introduced in 1975 and is a direct follow up to the german DIN 476 standard from 1922. ISO 216 is also called EN 20216 in Europe. + * The ISO paper sizes are based on the metric system so everything else is aproxiamte + * + * The Series A is used for Standard Printing and Stationary. + * The Series B is used for Posters, Wall-Charts etc. + * The C series is used for folders, post cards and envelopes. C series envelope is suitable to insert A series sizes. + * ISO also define format series RA and SRA for untrimmed raw paper, where SRA stands for 'supplementary raw format A'. + * Japan has adopted the ISO series A sizes, but its series B sizes are slightly different. These sizes are sometimes called JIS B or JB sizes. + * sun was a unit of length used in Japan and is equal to about 3.03 cm or 1.193 inches + * The United States, Canada, and in part Mexico, are today the only industrialized nations in which the ISO standard paper sizes are not yet widely used. + * + * A0 & A1 Technical drawings, posters + * A1 & A2 Flip charts + * A2 & A3 Drawings, diagrams, large tables + * A4 Letters, magazines, forms, catalogs, laser printer and copying machine output + * A5 Note pads + * A6 Postcards + * B5, A5, B6 A6 Books + * C4, C5, C6 Envelopes for A4 letters: unfolded (C4), folded once (C5), folded twice (C6) + * B4 & A3 Newspapers, supported by most copying machines in addition to A4 + * B8 & A8 Playing cards + * + * 1 inch = 72 points + * 1 mm = 2.8346457 points + * 1 inch = 25.4 mm + * 1 point = 0,35278 mm + */ + switch ($this->pageFormat) { + // ISO A series + case "4A0": {$sizes = array(4767.86,6740.79);break;} // ISO 216, 1682 mm x 2378 mm + case "2A0": {$sizes = array(3370.39,4767.86);break;} // ISO 216, 1189 mm x 1682 mm + case "A0": {$sizes = array(2383.94,3370.39);break;} // ISO 216, 841 mm x 1189mm + case "A1": {$sizes = array(1683.78,2383.94);break;} // ISO 216, 594 mm x 841 mm + case "A2": {$sizes = array(1190.55,1683.78);break;} // ISO 216, 420 mm x 594 mm + case "A3": {$sizes = array(841.89,1190.55);break;} // ISO 216, 297 mm x 420 mm + case "A4": default:{ // For unknown Page Size Name + $sizes = array(595.28,841.89); // ISO 216, 210 mm 297 mm + $this->pageFormat = "A4"; + break;} + case "A5": {$sizes = array(419.53,595.28);break;} // ISO 216, 148 mm x 210 mm + case "A6": {$sizes = array(297.64,419.53);break;} // ISO 216, 105 mm x 148 mm + case "A7": {$sizes = array(209.76,297.64);break;} // ISO 216, 74 mm x 105 mm + case "A8": {$sizes = array(147.40,209.76);break;} // ISO 216, 52 mm x 74 mm + case "A9": {$sizes = array(104.88,147.40);break;} // ISO 216, 37 mm x 52 mm + case "A10": {$sizes = array(73.70,104.88);break;} // ISO 216, 26 mm x 37 mm + // ISO B series + case "B0": {$sizes = array(2834.65,4008.19);break;} // ISO 216, 1000 mm x 1414 mm + case "B1": {$sizes = array(2004.09,2834.65);break;} // ISO 216, 707 mm x 1000 mm + case "B2": {$sizes = array(1417.32,2004.09);break;} // ISO 216, 500 mm x 707 mm + case "B3": {$sizes = array(1000.63,1417.32);break;} // ISO 216, 353 mm x 500 mm + case "B4": {$sizes = array(708.66,1000.63);break;} // ISO 216, 250 mm x 353 mm + case "B5": {$sizes = array(498.90,708.66);break;} // ISO 216, 176 mm x 250 mm + case "B6": {$sizes = array(354.33,498.90);break;} // ISO 216, 125 mm x 176 mm + case "B7": {$sizes = array(249.45,354.33);break;} // ISO 216, 88 mm x 125 mm + case "B8": {$sizes = array(175.75,249.45);break;} // ISO 216, 62 mm x 88 mm + case "B9": {$sizes = array(124.72,175.75);break;} // ISO 216, 44 mm x 62 mm + case "B10": {$sizes = array(87.87,124.72);break;} // ISO 216, 31 mm x 44 mm + // ISO C series, Envelope + case "C0": {$sizes = array(2599.37,3676.54);break;} // ISO 269, 917 mm x 1297 mm, For flat A0 sheet + case "C1": {$sizes = array(1836.85,2599.37);break;} // ISO 269, 648 mm x 917 mm, For flat A1 sheet + case "C2": {$sizes = array(1298.27,1836.85);break;} // ISO 269, 458 mm x 648 mm, For flat A2 sheet, A1 folded in half + case "C3": {$sizes = array(918.43,1298.27);break;} // ISO 269, 324 mm x 458 mm, For flat A3 sheet, A2 folded in half + case "C4": {$sizes = array(649.13,918.43);break;} // ISO 269, 229 mm x 324 mm, For flat A4 sheet, A3 folded in half + case "C5": {$sizes = array(459.21,649.13);break;} // ISO 269, 162 mm x 229 mm, For flat A5 sheet, A4 folded in half + case "C6/5":{$sizes = array(323.15,649.13);break;} // ISO 269, 114 mm x 229 mm. A5 folded twice = 1/3 A4. Alternative for the DL envelope + case "C6": {$sizes = array(323.15,459.21);break;} // ISO 269, 114 mm x 162 mm, For A5 folded in half + case "C7/6":{$sizes = array(229.61,459.21);break;} // ISO 269, 81 mm x 162 mm, For A5 sheet folded in thirds + case "C7": {$sizes = array(229.61,323.15);break;} // ISO 269, 81 mm x 114 mm, For A5 folded in quarters + case "C8": {$sizes = array(161.57,229.61);break;} // ISO 269, 57 mm x 81 mm + case "C9": {$sizes = array(113.39,161.57);break;} // ISO 269, 40 mm x 57 mm + case "C10": {$sizes = array(79.37,113.39);break;} // ISO 269, 28 mm x 40 mm + case "DL": {$sizes = array(311.81,623.62);break;} // Original DIN 678 but ISO 269 now has this C6/5 , 110 mm x 220 mm, For A4 sheet folded in thirds, A5 in half + // Untrimmed stock sizes for the ISO-A Series - ISO primary range + case "RA0": {$sizes = array(2437.80,3458.27);break;} // ISO 478, 860 mm x 1220 mm + case "RA1": {$sizes = array(1729.13,2437.80);break;} // ISO 478, 610 mm x 860 mm + case "RA2": {$sizes = array(1218.90,1729.13);break;} // ISO 478, 430 mm x 610 mm + case "RA3": {$sizes = array(864.57,1218.90);break;} // ISO 478, 305 mm x 430 mm + case "RA4": {$sizes = array(609.45,864.57);break;} // ISO 478, 215 mm x 305 mm + // Untrimmed stock sizes for the ISO-A Series - ISO supplementary range + case "SRA0": {$sizes = array(2551.18,3628.35);break;} // ISO 593, 900 mm x 1280 mm + case "SRA1": {$sizes = array(1814.17,2551.18);break;} // ISO 593, 640 mm x 900 mm + case "SRA2": {$sizes = array(1275.59,1814.17);break;} // ISO 593, 450 mm x 640 mm + case "SRA3": {$sizes = array(907.09,1275.59);break;} // ISO 593, 320 mm x 450 mm + case "SRA4": {$sizes = array(637.80,907.09);break;} // ISO 593, 225 mm x 320 mm + // ISO size variations + case "A2EXTRA": {$sizes = array(1261.42,1754.65);break;} // ISO 216, 445 mm x 619 mm + case "A2SUPER": {$sizes = array(864.57,1440.00);break;} // ISO 216, 305 mm x 508 mm + case "A3EXTRA": {$sizes = array(912.76,1261.42);break;} // ISO 216, 322 mm x 445 mm + case "SUPERA3": {$sizes = array(864.57,1380.47);break;} // ISO 216, 305 mm x 487 mm + case "A4EXTRA": {$sizes = array(666.14,912.76);break;} // ISO 216, 235 mm x 322 mm + case "A4LONG": {$sizes = array(595.28,986.46);break;} // ISO 216, 210 mm x 348 mm + case "A4SUPER": {$sizes = array(649.13,912.76);break;} // ISO 216, 229 mm x 322 mm + case "SUPERA4": {$sizes = array(643.46,1009.13);break;} // ISO 216, 227 mm x 356 mm + case "A5EXTRA": {$sizes = array(490.39,666.14);break;} // ISO 216, 173 mm x 235 mm + case "SOB5EXTRA": {$sizes = array(572.60,782.36);break;} // ISO 216, 202 mm x 276 mm + // Japanese version of the ISO 216 B series + case "JB0": {$sizes = array(2919.69,4127.24);break;} // JIS P 0138-61, 1030 mm x 1456 mm + case "JB1": {$sizes = array(2063.62,2919.69);break;} // JIS P 0138-61, 728 mm x 1030 mm + case "JB2": {$sizes = array(1459.84,2063.62);break;} // JIS P 0138-61, 515 mm x 728 mm + case "JB3": {$sizes = array(1031.81,1459.84);break;} // JIS P 0138-61, 364 mm x 515 mm + case "JB4": {$sizes = array(728.50,1031.81);break;} // JIS P 0138-61, 257 mm x 364 mm + case "JB5": {$sizes = array(515.91,728.50);break;} // JIS P 0138-61, 182 mm x 257 mm + case "JB6": {$sizes = array(362.83,515.91);break;} // JIS P 0138-61, 128 mm x 182 mm + case "JB7": {$sizes = array(257.95,362.83);break;} // JIS P 0138-61, 91 mm x 128 mm + case "JB8": {$sizes = array(181.42,257.95);break;} // JIS P 0138-61, 64 mm x 91 mm + case "JB9": {$sizes = array(127.56,181.42);break;} // JIS P 0138-61, 45 mm x 64 mm + case "JB10":{$sizes = array(90.71,127.56);break;} // JIS P 0138-61, 32 mm x 45 mm + // US pages + case "EXECUTIVE": {$sizes = array(522.00,756.00); break;} // 7.25 in x 10.5 in + case "FOLIO": {$sizes = array(612.00,936.00); break;} // 8.5 in x 13 in + case "FOOLSCAP":{$sizes = array(972.00,1224.00); break;} // 13.5 in x 17 in + case "LEDGER": {$sizes = array(792.00,1224.00); break;} // 11 in x 17 in + case "LEGAL": {$sizes = array(612.00,1008.00); break;} // 8.5 in x 14 in + case "LETTER": {$sizes = array(612.00,792.00); break;} // 8.5 in x 11 in + case "QUARTO": {$sizes = array(609.12,777.5); break;} // 8.46 in x 10.8 in + case "STATEMENT": {$sizes = array(396.00,612.00); break;} // 5.5 in x 8.5 in + case "USGOVT": {$sizes = array(576.00,792.00); break;} // 8 in x 11 in + } + $this->pagew = $sizes[0]; + $this->pageh = $sizes[1]; + } + else { + if ($this->pagew < 10) { + die("<strong>REPORT ERROR PGVReportBase::setup(): </strong>For custom size pages you must set \"customwidth\" larger then this in the XML file"); + } + if ($this->pageh < 10) { + die("<strong>REPORT ERROR PGVReportBase::setup(): </strong>For custom size pages you must set \"customheight\" larger then this in the XML file"); + } + } + return 0; + } + + /** + * Process the Header , Page header, Body or Footer - PGVReportBase + * + * @param string $p Header (H), Page header (PH), Body (B) or Footer (F) + */ + function setProcessing($p) { + $this->processing = $p; + return 0; + } + + /** + * Add the Title when raw character data is used in PGVRTitle - PGVReportBase + * + * @param string $data + */ + function addTitle($data) { + $this->title .= $data; + return 0; + } + + /** + * Add the Description when raw character data is used in PGVRDescription - PGVReportBase + * + * @param string $data + */ + function addDescription($data) { + $this->rsubject .= $data; + return 0; + } + + /** + * Add Style to PGVRStyles array - PGVReportBase + * + * @see PGVRStyleSHandler() + * @param array $style + */ + function addStyle($style) { + $this->PGVRStyles[$style["name"]] = $style; + return 0; + } + + /** + * Get a style from the PGVRStyles array - PGVReportBase + * + * @param string $s Style name + * @return array + */ + function getStyle($s) { + if (!isset($this->PGVRStyles[$s])) { + return current($this->PGVRStyles); + } + return $this->PGVRStyles[$s]; + } + + // static callback functions to sort data + static function CompareBirthDate($x, $y) { + return GedcomDate::Compare($x->getBirthDate(), $y->getBirthDate()); + } + static function CompareDeathDate($x, $y) { + return GedcomDate::Compare($x->getDeathDate(), $y->getDeathDate()); + } + + /** + * @deprecated + * @todo Is this a deprecated function or a future feature? + * + function get_type() { + // remove this die line only if it's cousing problem - It confirms that it's not used + die("<strong>REPORT ERROR PGVReportBase::get_type: </strong> It is used"); + return "PGVReportBase"; + } +*/ +} + +/** + * Main PGV Report Element class that all other page elements are extended from + * + * @package webtrees + * @subpackage Reports + */ +class PGVRElement { + /** + * @var string + */ + public $text = ""; + + /** + * Element renderer + * @param &$renderer + */ + function render(&$renderer) { +// print "Nothing rendered. Something bad happened"; +// debug_print_backtrace(); + //-- to be implemented in inherited classes + return 0; + } + + function getHeight(&$renderer) { + return 0; + } + + function getWidth(&$renderer) { + return 0; + } + + function addText($t) { + global $embed_fonts, $SpecialOrds, $pgvreport, $reportTitle, $reportDescription; + + foreach($SpecialOrds as $ord) { + if (strpos($t, chr($ord))!==false) { + $embed_fonts = true; + } + } + $t = trim($t, "\r\n\t"); + $t = str_replace(array("<br />", " "), array("\n", " "), $t); + if (!WT_RNEW) { + $t = strip_tags($t); + $t = unhtmlentities($t); + } + $this->text .= $t; + + // Adding the title and description to the Document Properties + if ($reportTitle) { + $pgvreport->addTitle($t); + } elseif ($reportDescription) { + $pgvreport->addDescription($t); + } + return 0; + } + + function addNewline() { + $this->text .= "\n"; + return 0; + } + + function getValue() { + return $this->text; + } + + function setWrapWidth($wrapwidth, $cellwidth) { + return 0; + } + + function renderFootnote(&$renderer) { + return false; + //-- to be implemented in inherited classes + } + + /** + * Get the Class name type + * + * @return string PGVRElementBase + */ + function get_type() { + return "PGVRElementBase"; + } + + function setText($text) { + $this->text = $text; + return 0; + } + +} //-- END PGVRElement + +/** +* HTML element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRHtml extends PGVRElement { + public $tag; + public $attrs; + public $elements = array(); + + function PGVRHtml($tag, $attrs) { + $this->tag = $tag; + $this->attrs = $attrs; + return 0; + } + + function getStart() { + $str = "<".$this->tag." "; + foreach($this->attrs as $key=>$value) { + $str .= $key."=\"".$value."\" "; + } + $str .= ">"; + return $str; + } + + function getEnd() { + return "</".$this->tag.">"; + } + + function addElement($element) { + $this->elements[] = $element; + return 0; + } + + /** + * Get the class type + * @return string PGVRHtml + */ + function get_type() { + return "PGVRHtml"; + } +} + +/** + * Cell element class +* +* @package webtrees +* @subpackage Reports +*/ +class PGVRCell extends PGVRElement { + /** + * Allows to center or align the text. Possible values are:<ul><li>left or empty string: left align</li><li>center: center align</li><li>right: right align</li><li>justify: justification (default value when $ishtml=false)</li></ul> + * @var string + */ + public $align = ""; + /** + * Whether or not a border should be printed around this box. 0 = no border, 1 = border. Default is 0. + * Or a string containing some or all of the following characters (in any order):<ul><li>L: left</li><li>T: top</li><li>R: right</li><li>B: bottom</li></ul> + * @var mixed + */ + public $border; + /** + * Border color in HTML code + * @var string + */ + public $bocolor; + /** + * The HTML color code to fill the background of this cell. + * @var string + */ + public $bgcolor; + /** + * Indicates if the cell background must be painted (1) or transparent (0). Default value: 1. + * If no background color is set then it will not be painted + * @var int + */ + public $fill; + /** + * Cell height DEFAULT 0 (expressed in points) + * The starting height of this cell. If the text wraps the height will automatically be adjusted. + * @var int + */ + public $height; + /** + * Left position in user units (X-position). Default is the current position + * @var mixed + */ + public $left; + /** + * Indicates where the current position should go after the call. Possible values are:<ul><li>0: to the right [DEFAULT]</li><li>1: to the beginning of the next line</li><li>2: below</li></ul> + * @var int + */ + public $newline; + /** + * The name of the PGVRStyle that should be used to render the text. + * @var string + */ + public $styleName; + /** + * Stretch carachter mode: <ul><li>0 = disabled (default)</li><li>1 = horizontal scaling only if necessary</li><li>2 = forced horizontal scaling</li><li>3 = character spacing only if necessary</li><li>4 = forced character spacing</li></ul> + * @var int + */ + public $stretch; + /** + * Text color in HTML code + * @var string + */ + public $tcolor; + /** + * Top position in user units (Y-position). Default is the current position + * @var mixed + */ + public $top; + /** + * URL address + * @var string + */ + public $url; + /** + * Cell width DEFAULT 0 (expressed in points) + * Setting the width to 0 will make it the width from the current location to the right margin. + * @var int + */ + public $width; + + public $reseth; + + /** + * CELL - PGVRElement + * + * @param int $width cell width (expressed in points) + * @param int $height cell height (expressed in points) + * @param mixed $border Border style + * @param string $align Text alignement + * @param string $bgcolor Background color code + * @param string $style The name of the text style + * @param int $ln Indicates where the current position should go after the call + * @param mixed $top Y-position + * @param mixed $left X-position + * @param int $fill Indicates if the cell background must be painted (1) or transparent (0). Default value: 0. + * @param int $stretch Stretch carachter mode + * @param string $bocolor Border color + * @param string $tcolor Text color + */ + function PGVRCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth) { + $this->align = $align; + $this->border = $border; + $this->bgcolor = $bgcolor; + $this->bocolor = $bocolor; + $this->fill = $fill; + $this->height = $height; + $this->left = $left; + $this->newline = $ln; + $this->styleName = $style; + $this->text = ""; + $this->tcolor = $tcolor; + $this->top = $top; + $this->url = ""; + $this->stretch = $stretch; + $this->width = $width; + $this->reseth = $reseth; + return 0; + } + /** + * Get the cell height + * @todo add param + * @return float + */ + function getHeight(&$renderer) { + return $this->height; + } + /** + * Sets the current cells URL + * @param string $url The URL address to save + */ + function setUrl($url) { + $this->url = $url; + return 0; + } + /** + * Get the cell width + * @todo add param + * @return float + */ + function getWidth(&$renderer) { + return $this->width; + } + /** + * Get the class type + * @return string PGVRCell + */ + function get_type() { + return "PGVRCell"; + } +} + +/** + * TextBox element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRTextBox extends PGVRElement { + /** + * Array of elements in the TextBox + * @var array + */ + public $elements = array(); + + /** + * Background color in HTML code + * @var string + */ + public $bgcolor; + /** + * Whether or not paint the background + * @var boolean + */ + public $fill; + + /** + * Position the left corner of this box on the page(expressed in points). The default is the current position. + * @var mix + */ + public $left; + /** + * Position the top corner of this box on the page(expressed in points). the default is the current position + * @var mix + */ + public $top; + /** + * After this box is finished rendering, should the next section of text start immediately after the this box or should it start on a new line under this box. 0 = no new line, 1 = force new line. Default is 0 + * @var boolean + */ + public $newline; + + /** + * @var boolean + */ + public $pagecheck; + + /** + * Whether or not a border should be printed around this box. 0 = no border, 1 = border. Default is 0 + * @var boolean + */ + public $border; + /** + * Style of rendering + * + * <ul> + * <li>D or empty string: Draw (default).</li> + * <li>F: Fill.</li> + * <li>DF or FD: Draw and fill.</li> + * <li>CNZ: Clipping mode (using the even-odd rule to determine which regions lie inside the clipping path).</li> + *<li>CEO: Clipping mode (using the nonzero winding number rule to determine which regions lie inside the clipping path).</li> + * </ul> + * @var string + */ + public $style; + + /** + * @var array $borderstyle Border style of rectangle. Array with keys among the following: + * <ul> + * <li>all: Line style of all borders. Array like for {@link SetLineStyle SetLineStyle}.</li> + * <li>L, T, R, B or combinations: Line style of left, top, right or bottom border. Array like for {@link SetLineStyle SetLineStyle}.</li> + * </ul> + * Not yet in use + var $borderstyle; + */ + + /** + * The starting height of this cell. If the text wraps the height will automatically be adjusted + * @var float + */ + public $height; + /** + * Setting the width to 0 will make it the width from the current location to the right margin + * @var float + */ + public $width; + /** + * Use cell padding or not + * @var boolean $padding + */ + public $padding; + /** + * Resets this box last height after it's done + */ + public $reseth; + + /** + * TextBox - PGVRElement - Base + * + * @param float $width Text box width + * @param float $height Text box height + * @param boolean $border + * @param string $bgcolor Background color code in HTML + * @param boolean $newline + * @param mixed $left + * @param mixed $top + * @param boolean $pagecheck + * @param string $style + * @param boolean $fill + * @param boolean $padding + * @param boolean $reseth + */ + function PGVRTextBox($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth) { + $this->border = $border; + $this->bgcolor = $bgcolor; + $this->fill= $fill; + $this->height = $height; + $this->left = $left; + $this->newline = $newline; + $this->pagecheck = $pagecheck; + $this->style = $style; + $this->top = $top; + $this->width = $width; + $this->padding = $padding; + $this->reseth = $reseth; + return 0; + } + + /** + * Add an element to the TextBox + * @param object|string &$element + */ + function addElement($element) { + $this->elements[] = $element; + return 0; + } + + /** + * Get the class type + * @return string PGVRTextBox + */ + function get_type() { + return "PGVRTextBox"; + } +} + +/** + * Text element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRText extends PGVRElement { + /** + * Text color in HTML code + * @var string + */ + public $color; + /** + * Style name + * @var string + */ + public $styleName; + /** + * Remaining width of a cel + * @var int User unit (points) + */ + public $wrapWidthRemaining; + /** + * Original width of a cell + * @var int User unit (points) + */ + public $wrapWidthCell; + + /** + * Create a Text class - Base + * + * @param string $style The name of the text style + * @param string $color HTML color code + */ + function PGVRText($style, $color) { + $this->text = ""; + $this->color = $color; + $this->wrapWidthRemaining = 0; + $this->styleName = $style; + return 0; + } + + function setWrapWidth($wrapwidth, $cellwidth) { + $this->wrapWidthCell = $cellwidth; + if (strpos($this->text, "\n")!==false) { + $this->wrapWidthRemaining = $cellwidth; + } else { + $this->wrapWidthRemaining = $wrapwidth; + } + return $this->wrapWidthRemaining; + } + + function getStyleName() { + return $this->styleName; + } + + /** + * Get the class type + * @return string PGVRText + */ + function get_type() { + return "PGVRText"; + } +} + +/** + * Footnote element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRFootnote extends PGVRElement { + /** + * The name of the style for this element + * @var string + */ + public $styleName = ""; + /** + * Numbers for the links + * @var int + */ + public $num; + /** + * The text that will be printed with the number + * @var string + */ + public $numText = ""; + /** + * Remaining width of a cell + * @var float User unit (points) + */ + public $wrapWidthRemaining; + /** + * Original width of a cell + * @var float User unit (points) + */ + public $wrapWidthCell; + public $addlink; + + function PGVRFootnote($style="") { + $this->text = ""; + if (!empty($style)) { + $this->styleName = $style; + } else { + $this->styleName="footnote"; + } + return 0; + } + + function rerender($renderer) { + return false; + } + + function addText($t) { + global $embed_fonts, $SpecialOrds; + + foreach($SpecialOrds as $ord) { + if (strpos($t, chr($ord))!==false) { + $embed_fonts = true; + } + } + $t = trim($t, "\r\n\t"); + $t = str_replace(array("<br />", " "), array("\n", " "), $t); + if (!WT_RNEW) { + $t = strip_tags($t); + $t = unhtmlentities($t); + } + $this->text .= $t; + return 0; + } + + function setWrapWidth($wrapwidth, $cellwidth) { + $this->wrapWidthCell = $cellwidth; + if (strpos($this->numText, "\n")!==false) { + $this->wrapWidthRemaining = $cellwidth; + } else { + $this->wrapWidthRemaining = $wrapwidth; + } + return $this->wrapWidthRemaining; + } + + function setNum($n) { + $this->num = $n; +//@@ $this->numText = "$n"; + $this->numText = "$n "; //@@ source numbers + return 0; + } + + function setAddlink($a) { + $this->addlink = $a; + return 0; + } + + /** + * Get the class type + * @return string PGVRFootnote + */ + function get_type() { + return "PGVRFootnote"; + } +} + +/** + * PageHeader element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRPageHeader extends PGVRElement { + public $elements = array(); + + function PGVRTextBox() { + $this->elements = array(); + return 0; + } + + function PGVRPageHeader() { + $this->elements = array(); + return 0; + } + + /** + * Add element - PGVRPageHeader + * @param $element + */ + function addElement($element) { + $this->elements[] = $element; + return 0; + } + + /** + * Get the class type + * @return string PGVRPageHeader + */ + function get_type() { + return "PGVRPageHeader"; + } +} + +/** + * Image element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRImage extends PGVRElement { + /** + * File name of the image + * @var string + */ + public $file; + /** + * Height of the image + * @var float + */ + public $height; + /** + * Width of the image + * @var float + */ + public $width; + /** + * X-position (left) of the image + * @var float + */ + public $x; + /** + * Y-position (top) of the image + * @var float + */ + public $y; + /** + * Placement fo the image. L: left, C:center, R:right + * @var string + */ + public $align = ""; + /** + * T:same line, N:next line + * @var string + */ + public $line = ""; + + /** + * PGVRImage class function - Base + * + * @param string $file File name of the image + * @param float $x X-position (left) of the image + * @param float $y Y-position (top) of the image + * @param float $w Width of the image + * @param float $h Height of the image + * @param string $align Placement of the image. L: left, C:center, R:right + * @param string $ln T:same line, N:next line + */ + function PGVRImage($file, $x, $y, $w, $h, $align, $ln) { + $this->file = $file; + $this->width = $w; + $this->height = $h; + $this->x = $x; + $this->y = $y; + $this->align = $align; + $this->line = $ln; + return 0; + } + + function getHeight(&$renderer) { + return $this->height; + } + + function getWidth(&$renderer) { + return $this->width; + } + + /** + * Get the class type + * @return string PGVRImage + */ + function get_type() { + return "PGVRImage"; + } +} + +/** + * Line element class +* +* @package webtrees +* @subpackage Reports +* @todo add info +*/ +class PGVRLine extends PGVRElement { + /** + * Start horizontal position, current position (default) + * @var mixed + */ + public $x1 = "."; + /** + * Start vertical position, current position (default) + * @var mixed + */ + public $y1 = "."; + /** + * End horizontal position, maximum width (default) + * @var mixed + */ + public $x2 = "."; + /** + * End vertical position + * @var mixed + */ + public $y2 = "."; + + /** + * Create a line class - Base + * @param mixed $x1 + * @param mixed $y1 + * @param mixed $x2 + * @param mixed $y2 + */ + function PGVRLine($x1, $y1, $x2, $y2) { + $this->x1 = $x1; + $this->y1 = $y1; + $this->x2 = $x2; + $this->y2 = $y2; + return 0; + } + + function getHeight(&$renderer) { + return abs($this->y2 - $this->y1); + } + + function getWidth(&$renderer) { + return abs($this->x2 - $this->x1); + } + + /** + * Get the class type + * @return string PGVRLine + */ + function get_type() { + return "PGVRLine"; + } +} + +/** + * element handlers array + * + * Converts XML element names into functions + * @global array $elementHandler + */ +$elementHandler = array(); +$elementHandler["br"]["start"] = "brSHandler"; +$elementHandler["PGVRBody"]["start"] = "PGVRBodySHandler"; +$elementHandler["PGVRCell"]["end"] = "PGVRCellEHandler"; +$elementHandler["PGVRCell"]["start"] = "PGVRCellSHandler"; +$elementHandler["PGVRDescription"]["end"] = "PGVRDescriptionEHandler"; +$elementHandler["PGVRDescription"]["start"] = "PGVRDescriptionSHandler"; +$elementHandler["PGVRDoc"]["end"] = "PGVRDocEHandler"; +$elementHandler["PGVRDoc"]["start"] = "PGVRDocSHandler"; +$elementHandler["PGVReport"]["end"] = ""; +$elementHandler["PGVReport"]["start"] = ""; +$elementHandler["PGVRFacts"]["end"] = "PGVRFactsEHandler"; +$elementHandler["PGVRFacts"]["start"] = "PGVRFactsSHandler"; +$elementHandler["PGVRFooter"]["start"] = "PGVRFooterSHandler"; +$elementHandler["PGVRFootnote"]["end"] = "PGVRFootnoteEHandler"; +$elementHandler["PGVRFootnote"]["start"] = "PGVRFootnoteSHandler"; +$elementHandler["PGVRFootnoteTexts"]["start"] = "PGVRFootnoteTextsSHandler"; +$elementHandler["PGVRGedcom"]["end"] = "PGVRGedcomEHandler"; +$elementHandler["PGVRGedcom"]["start"] = "PGVRGedcomSHandler"; +$elementHandler["PGVRGedcomValue"]["start"] = "PGVRGedcomValueSHandler"; +$elementHandler["PGVRGeneration"]["start"] = "PGVRGenerationSHandler"; +$elementHandler["PGVRGetPersonName"]["start"] = "PGVRGetPersonNameSHandler"; +$elementHandler["PGVRHeader"]["start"] = "PGVRHeaderSHandler"; +$elementHandler["PGVRHighlightedImage"]["start"]= "PGVRHighlightedImageSHandler"; +$elementHandler["PGVRif"]["end"] = "PGVRifEHandler"; +$elementHandler["PGVRif"]["start"] = "PGVRifSHandler"; +$elementHandler["PGVRImage"]["start"] = "PGVRImageSHandler"; +$elementHandler["PGVRInput"]["end"] = ""; +$elementHandler["PGVRInput"]["start"] = ""; +$elementHandler["PGVRLine"]["start"] = "PGVRLineSHandler"; +$elementHandler["PGVRList"]["end"] = "PGVRListEHandler"; +$elementHandler["PGVRList"]["start"] = "PGVRListSHandler"; +$elementHandler["PGVRListTotal"]["start"] = "PGVRListTotalSHandler"; +$elementHandler["PGVRNewPage"]["start"] = "PGVRNewPageSHandler"; +$elementHandler["PGVRNow"]["start"] = "PGVRNowSHandler"; +$elementHandler["PGVRPageHeader"]["end"] = "PGVRPageHeaderEHandler"; +$elementHandler["PGVRPageHeader"]["start"] = "PGVRPageHeaderSHandler"; +$elementHandler["PGVRPageNum"]["start"] = "PGVRPageNumSHandler"; +$elementHandler["PGVRRelatives"]["end"] = "PGVRRelativesEHandler"; +$elementHandler["PGVRRelatives"]["start"] = "PGVRRelativesSHandler"; +$elementHandler["PGVRRepeatTag"]["end"] = "PGVRRepeatTagEHandler"; +$elementHandler["PGVRRepeatTag"]["start"] = "PGVRRepeatTagSHandler"; +$elementHandler["PGVRSetVar"]["start"] = "PGVRSetVarSHandler"; +$elementHandler["PGVRStyle"]["start"] = "PGVRStyleSHandler"; +$elementHandler["PGVRText"]["end"] = "PGVRTextEHandler"; +$elementHandler["PGVRText"]["start"] = "PGVRTextSHandler"; +$elementHandler["PGVRTextBox"]["end"] = "PGVRTextBoxEHandler"; +$elementHandler["PGVRTextBox"]["start"] = "PGVRTextBoxSHandler"; +$elementHandler["PGVRTitle"]["end"] = "PGVRTitleEHandler"; +$elementHandler["PGVRTitle"]["start"] = "PGVRTitleSHandler"; +$elementHandler["PGVRTotalPages"]["start"] = "PGVRTotalPagesSHandler"; +$elementHandler["PGVRvar"]["start"] = "PGVRvarSHandler"; +$elementHandler["PGVRvarLetter"]["start"] = "PGVRvarLetterSHandler"; +$elementHandler["sp"]["start"] = "spSHandler"; + +/** +* A new object of the currently used element class +* +* @global object $currentElement +*/ +$currentElement = new PGVRElement(); + +/** + * Should character data be printed + * + * This variable is turned on or off by the element handlers to tell whether the inner character + * Data should be printed + * @global boolean $printData + */ +$printData = false; + +/** +* Title collector. Mark it if it has already been used +* +* @global boolean $reportTitle +*/ +$reportTitle = false; + +/** +* Description collector. Mark it if it has already been used +* +* @global boolean $reportDescription +*/ +$reportDescription = false; + +/** + * Print data stack + * + * As the XML is being processed there will be times when we need to turn on and off the + * <var>$printData</var> variable as we encounter entinties in the XML. The stack allows us to + * keep track of when to turn <var>$printData</var> on and off. + * @global array $printDataStack + */ +$printDataStack = array(); + +/** +* @todo add info +* @global array $pgvreportStack +*/ +$pgvreportStack = array(); + +/** +* @todo add info +* @global array $gedrecStack +*/ +$gedrecStack = array(); + +/** +* @todo add info +* @global array $repeatsStack +*/ +$repeatsStack = array(); + +/** +* @todo add info +* @global array $parserStack +*/ +$parserStack = array(); + +/** +* @todo add info +* @global array $repeats +*/ +$repeats = array(); + +/** +* @todo add info +* @global string $gedrec +*/ +$gedrec = ""; + +/** +* @todo add info +* @global ???? $repeatBytes +*/ +$repeatBytes = 0; + +/** +* @todo add info +* @global resource $parser +*/ +$parser = ""; + +/** +* @todo add info +* @global int $processRepeats +*/ +$processRepeats = 0; + +/** +* @todo add info +* @global ???? $processIfs +*/ +$processIfs = 0; + +/** +* @todo add info +* @global ???? $processGedcoms +*/ +$processGedcoms = 0; + +/** + * Wether or not to print footnote + * true = print, false = don't print + */ +$processFootnote = true; + +/** + *XML start element handler + * + * This function is called whenever a starting element is reached + * The element handler will be called if found, otherwise it must be HTML + * + * @param resource $parser the resource handler for the XML parser + * @param string $name the name of the XML element parsed + * @param array $attrs an array of key value pairs for the attributes + * @see endElement() + */ +function startElement($parser, $name, $attrs) { + global $elementHandler, $processIfs, $processGedcoms, $processRepeats, $vars; + global $processFootnote; + + $newattrs = array(); + $match = array(); + + foreach($attrs as $key=>$value) { + if (preg_match("/^\\$(\w+)$/", $value, $match)) { + if ((isset($vars[$match[1]]["id"]))&&(!isset($vars[$match[1]]["gedcom"]))) { + $value = $vars[$match[1]]["id"]; + } + } + $newattrs[$key] = $value; + } + $attrs = $newattrs; + if (($processFootnote)&&($processIfs==0 || $name=="PGVRif")&&($processGedcoms==0 || $name=="PGVRGedcom")&&($processRepeats==0 || $name=="PGVRFacts" || $name=="PGVRRepeatTag")) { + if (isset($elementHandler[$name]["start"])) { + if ($elementHandler[$name]["start"] != "") { + call_user_func($elementHandler[$name]["start"], $attrs); + } + } elseif (!isset($elementHandler[$name]["end"])) { + HTMLSHandler($name, $attrs); + } + } +} + +/** + * XML end element handler + * + * This function is called whenever an ending element is reached + * The element handler will be called if found, otherwise it must be HTML + * + * @param resource $parser the resource handler for the XML parser + * @param string $name the name of the XML element parsed + * @see startElement() + */ +function endElement($parser, $name) { + global $elementHandler, $processIfs, $processGedcoms, $processRepeats; + global $processFootnote; + + if (($processFootnote || $name=="PGVRFootnote")&&($processIfs==0 || $name=="PGVRif")&&($processGedcoms==0 || $name=="PGVRGedcom")&&($processRepeats==0 || $name=="PGVRFacts" || $name=="PGVRRepeatTag" || $name=="PGVRList" || $name=="PGVRRelatives")) { + if (isset($elementHandler[$name]["end"])) { + if ($elementHandler[$name]["end"]!="") { + call_user_func($elementHandler[$name]["end"]); + } + } elseif (!isset($elementHandler[$name]["start"])) { + HTMLEHandler($name); + } + } +} + +/** + * XML character data handler + * + * This function is called whenever raw character data is reached + * just print it to the screen + * @param resource $parser the resource handler for the XML parser + * @param string $data the name of the XML element parsed + * @todo check this + */ +function characterData($parser, $data) { + global $printData, $currentElement, $processGedcoms, $processIfs, $processRepeats, $reportTitle, $pgvreport, $reportDescription; +// global $processFootnote; + + if ($printData && ($processGedcoms==0) && ($processIfs==0)&&($processRepeats==0)) { + $currentElement->addText($data); + } elseif ($reportTitle) { + $pgvreport->addTitle($data); + } elseif ($reportDescription) { + $pgvreport->addDescription($data); + } +} + +/** +* XML <PGVRStyleSHandler /> elemnt handler +* +* @param array $attrs an array of key value pairs for the attributes +* @see PGVReportBase::$defaultFont +* @see PGVReportBase::$defaultFontSize +* @see PGVReportBase::addStyle() +* @todo add info - update wiki +*/ +function PGVRStyleSHandler($attrs) { + global $pgvreport; + + if (empty($attrs["name"])) { + die("<strong>REPORT ERROR PGVRStyle: </strong> The \"name\" of the style is missing or not set in the XML file."); + } + + // array Style that will be passed on + $s = array(); + + // string Name af the style + $s["name"] = $attrs["name"]; + + // string Name of the DEFAULT font + $s["font"] = $pgvreport->defaultFont; + if (!empty($attrs["font"])) $s["font"] = $attrs["font"]; + + // int The size of the font in points + $s["size"] = $pgvreport->defaultFontSize; + if (!empty($attrs["size"])) $s["size"] = (int)$attrs["size"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + + // string B: bold, I: italic, U: underline, D: line trough, The default value is regular. + $s["style"] = ""; + if (!empty($attrs["style"])) $s["style"] = $attrs["style"]; + + $pgvreport->addStyle($s); +} + +/** +* XML <PGVRDoc> start elemnt handler +* +* Sets up the basics of the document proparties +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRDocEHandler() +* @see PGVReportBase::setup() +* @todo add showGeneratedBy, height, width param to wiki and update the defaults +*/ +function PGVRDocSHandler($attrs) { + global $parser, $xml_parser, $pgvreport; + + $parser = $xml_parser; + + // Custom page width + if (!empty($attrs["customwidth"])) $pgvreport->pagew = (int)$attrs["customwidth"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + // Custom Page height + if (!empty($attrs["customheight"])) $pgvreport->pageh = (int)$attrs["customheight"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + + // Left Margin + if (isset($attrs["leftmargin"])) { + if ($attrs["leftmargin"] === "0") $pgvreport->leftmargin = 0; + elseif (!empty($attrs["leftmargin"])) { + $pgvreport->leftmargin = (int)$attrs["leftmargin"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + } + } + // Right Margin + if (isset($attrs["rightmargin"])) { + if ($attrs["rightmargin"] === "0") $pgvreport->rightmargin = 0; + elseif (!empty($attrs["rightmargin"])) { + $pgvreport->rightmargin = (int)$attrs["rightmargin"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + } + } + // Top Margin + if (isset($attrs["topmargin"])) { + if ($attrs["topmargin"] === "0") $pgvreport->topmargin = 0; + elseif (!empty($attrs["topmargin"])) { + $pgvreport->topmargin = (int)$attrs["topmargin"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + } + } + // Bottom Margin + if (isset($attrs["bottommargin"])) { + if ($attrs["bottommargin"] === "0") $pgvreport->bottommargin = 0; + elseif (!empty($attrs["bottommargin"])) { + $pgvreport->bottommargin = (int)$attrs["bottommargin"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + } + } + // Header Margin + if (isset($attrs["headermargin"])) { + if ($attrs["headermargin"] === "0") $pgvreport->headermargin = 0; + elseif (!empty($attrs["headermargin"])) { + $pgvreport->headermargin = (int)$attrs["headermargin"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + } + } + // Footer Margin + if (isset($attrs["footermargin"])) { + if ($attrs["footermargin"] === "0") $pgvreport->footermargin = 0; + elseif (!empty($attrs["footermargin"])) { + $pgvreport->footermargin = (int)$attrs["footermargin"]; // Get it as int to ignore all decimal points or text (if any text then int(0)) + } + } + + // Page Orientation + if (!empty($attrs["orientation"])) { + if ($attrs["orientation"] == "landscape") $pgvreport->orientation = "landscape"; + elseif ($attrs["orientation"] == "portrait") { + $pgvreport->orientation = "portrait"; + } + } + // Page Size + if (!empty($attrs["pageSize"])) $pgvreport->pageFormat = strtoupper($attrs["pageSize"]); + + // Show Generated By... + if (isset($attrs["showGeneratedBy"])) { + if ($attrs["showGeneratedBy"] === "0") $pgvreport->showGenText = false; + elseif ($attrs["showGeneratedBy"] === "1") { + $pgvreport->showGenText = true; + } + } + + $pgvreport->setup(); +} + +/** +* XML </PGVRDoc> end elemnt handler +* +* @see PGVRDocSHandler() +*/ +function PGVRDocEHandler() { + global $pgvreport; + $pgvreport->run(); +} + +/** +* XML <PGVRHeader> start elemnt handler +* +* @see PGVReportBase::setProcessing() +*/ +function PGVRHeaderSHandler() { + global $pgvreport; + + // Clear the Header before any new elements are added + $pgvreport->clearHeader(); + $pgvreport->setProcessing("H"); +} + +/** +* XML <PGVRPageHeader> start elemnt handler +* +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRPageHeaderEHandler() +*/ +function PGVRPageHeaderSHandler($attrs) { + global $printDataStack, $printData, $pgvreportStack, $pgvreport, $PGVReportRoot; + + array_push($printDataStack, $printData); + $printData = false; + array_push($pgvreportStack, $pgvreport); + $pgvreport = $PGVReportRoot->createPageHeader(); +} + +/** +* XML <PGVRPageHeaderEHandler> end elemnt handler +* +* @see PGVRPageHeaderSHandler() +*/ +function PGVRPageHeaderEHandler() { + global $printData, $printDataStack, $pgvreport, $currentElement, $pgvreportStack; + + $printData = array_pop($printDataStack); + $currentElement = $pgvreport; + $pgvreport = array_pop($pgvreportStack); + $pgvreport->addElement($currentElement); +} + +/** +* XML <PGVRBodySHandler> start elemnt handler +*/ +function PGVRBodySHandler() { + global $pgvreport; + $pgvreport->setProcessing("B"); +} + +/** +* XML <PGVRFooterSHandler> start elemnt handler +*/ +function PGVRFooterSHandler() { + global $pgvreport; + $pgvreport->setProcessing("F"); +} + +/** +* XML <PGVRCell> start elemnt handler +* +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRCellEHandler() +* @see PGVRCell +* @todo defaults to wiki +*/ +function PGVRCellSHandler($attrs) { + global $printData, $printDataStack, $currentElement, $PGVReportRoot, $pgvreport; + + // string The text alignment of the text in this box. + $align= ""; + if (!empty($attrs["align"])) { + $align = $attrs["align"]; + // RTL supported left/right alignment + if ($align == "rightrtl") { + if ($pgvreport->rtl) { + $align = "left"; + } else { + $align = "right"; + } + } elseif ($align == "leftrtl") { + if ($pgvreport->rtl) { + $align = "right"; + } else { + $align = "left"; + } + } + } + + // string The color to fill the background of this cell + $bgcolor = ""; + if (!empty($attrs["bgcolor"])) $bgcolor = $attrs["bgcolor"]; + + // int Whether or not the background should be painted + $fill = 1; + if (isset($attrs["fill"])) { + if ($attrs["fill"] === "0") { + $fill = 0; + } elseif ($attrs["fill"] === "1") { + $fill = 1; + } + } + + $reseth = true; + // boolean if true reset the last cell height (default true) + if (isset($attrs["reseth"])) { + if ($attrs["reseth"] === "0") { + $reseth = false; + } elseif ($attrs["reseth"] === "1") { + $reseth = true; + } + } + + // mixed Whether or not a border should be printed around this box + $border = 0; + if (!empty($attrs["border"])) $border = $attrs["border"]; + // @test Print all borders for testing +// $border = 1; + // string Border color in HTML code + $bocolor = ""; + if (!empty($attrs["bocolor"])) $bocolor = $attrs["bocolor"]; + + // int Cell height (expressed in points) The starting height of this cell. If the text wraps the height will automatically be adjusted. + $height= 0; + if (!empty($attrs["height"])) $height = (int)$attrs["height"]; + // int Cell width (expressed in points) Setting the width to 0 will make it the width from the current location to the right margin. + $width = 0; + if (!empty($attrs["width"])) $width = (int)$attrs["width"]; + + // int Stretch carachter mode + $stretch= 0; + if (!empty($attrs["stretch"])) $stretch = (int)$attrs["stretch"]; + + // mixed Position the left corner of this box on the page. The default is the current position. + $left = "."; + if (isset($attrs["left"])) { + if ($attrs["left"] === ".") { + $left = "."; + } elseif (!empty($attrs["left"])) { + $left = (int)$attrs["left"]; + } elseif ($attrs["left"] === "0") { + $left = 0; + } + } + // mixed Position the top corner of this box on the page. the default is the current position + $top = "."; + if (isset($attrs["top"])) { + if ($attrs["top"] === ".") { + $top = "."; + } elseif (!empty($attrs["top"])) { + $top = (int)$attrs["top"]; + } elseif ($attrs["top"] === "0") { + $top = 0; + } + } + + // string The name of the PGVRStyle that should be used to render the text. + $style = ""; + if (!empty($attrs["style"])) $style = $attrs["style"]; + + // string Text color in html code + $tcolor = ""; + if (!empty($attrs["tcolor"])) $tcolor = $attrs["tcolor"]; + + // int Indicates where the current position should go after the call. + $ln = 0; + if (isset($attrs["newline"])) { + if (!empty($attrs["newline"])) { + $ln = (int)$attrs["newline"]; + } elseif ($attrs["newline"] === "0") { + $ln = 0; + } + } + + if ($align=="left") { + $align="L"; + } elseif ($align=="right") { + $align="R"; + } elseif ($align=="center") { + $align="C"; + } elseif ($align=="justify") { + $align="J"; + } + + array_push($printDataStack, $printData); + $printData = true; + + $currentElement = $PGVReportRoot->createCell($width, $height, $border, $align, $bgcolor, $style, $ln, $top, $left, $fill, $stretch, $bocolor, $tcolor, $reseth); +} + +/** +* XML </PGVRCell> end elemnt handler +* +* @see PGVRCellSHandler() +* @final +*/ +function PGVRCellEHandler() { + global $printData, $printDataStack, $currentElement, $pgvreport; + + $printData = array_pop($printDataStack); + $pgvreport->addElement($currentElement); +} + +/** +* XML <PGVRNow /> elemnt handler +* +* @see PGVRElement::addText() +* @final +*/ +function PGVRNowSHandler() { + global $currentElement; + + $g = timestamp_to_gedcom_date(client_time()); + $currentElement->addText($g->Display()); +} + +/** +* XML <PGVRPageNum /> elemnt handler +* +* @see PGVRElement::addText() +* @final +*/ +function PGVRPageNumSHandler() { + global $currentElement; + $currentElement->addText("#PAGENUM#"); +} + +/** +* XML <PGVRTotalPages /> elemnt handler +* +* @see PGVRElement::addText() +* @final +*/ +function PGVRTotalPagesSHandler() { + global $currentElement; + $currentElement->addText("{{nb}}"); +} + +/** +* @see PGVRGedcomEHandler() +* @todo add info +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRGedcomSHandler($attrs) { + global $vars, $gedrec, $gedrecStack, $processGedcoms, $fact, $desc, $ged_level; + + if ($processGedcoms>0) { + $processGedcoms++; + return; + } + + $id = ""; + $match = array(); + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $id = $match[1]; + } + $tag = $attrs["id"]; + $tag = str_replace("@fact", $fact, $tag); + $tags = explode(":", $tag); + $newgedrec = ""; + if (count($tags)<2) { + $newgedrec = find_gedcom_record($attrs["id"], WT_GED_ID); + } + if (empty($newgedrec)) { + $tgedrec = $gedrec; + $newgedrec = ""; + foreach($tags as $tag) { + if (preg_match("/\\$(.+)/", $tag, $match)) { + if (isset($vars[$match[1]]["gedcom"])) { + $newgedrec = $vars[$match[1]]["gedcom"]; + } else { + $newgedrec = find_gedcom_record($match[1], WT_GED_ID); + } + } else { + if (preg_match("/@(.+)/", $tag, $match)) { + $gmatch = array(); + if (preg_match("/\d $match[1] @([^@]+)@/", $tgedrec, $gmatch)) { + $newgedrec = find_gedcom_record($gmatch[1], WT_GED_ID); + $tgedrec = $newgedrec; + } else { + $newgedrec = ""; + break; + } + } else { + $temp = explode(" ", trim($tgedrec)); + $level = $temp[0] + 1; + if (showFact($tag, $id) && showFactDetails($tag, $id)) { + $newgedrec = get_sub_record($level, "$level $tag", $tgedrec); + $tgedrec = $newgedrec; + } else { + $newgedrec = ""; + break; + } + } + } + } + } + if (!empty($newgedrec)) { + $gedObj = new GedcomRecord($newgedrec); + array_push($gedrecStack, array($gedrec, $fact, $desc)); + $gedrec = $gedObj->getGedcomRecord(); + if (preg_match("/(\d+) (_?[A-Z0-9]+) (.*)/", $gedrec, $match)) { + $ged_level = $match[1]; + $fact = $match[2]; + $desc = trim($match[3]); + } + } else { + $processGedcoms++; + } +} + +/** +* @see PGVRGedcomSHandler() +* @todo add info +*/ +function PGVRGedcomEHandler() { + global $gedrec, $gedrecStack, $processGedcoms, $fact, $desc; + + if ($processGedcoms>0) { + $processGedcoms--; + } else { + $temp = array_pop($gedrecStack); + $gedrec = $temp[0]; + $fact = $temp[1]; + $desc = $temp[2]; + } +} + +/** +* XML <PGVRTextBoxSHandler> start elemnt handler +* +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRTextBoxEHandler() +* @todo defaults to wiki +*/ +function PGVRTextBoxSHandler($attrs) { + global $printData, $printDataStack, $pgvreport, $currentElement, $pgvreportStack, $PGVReportRoot; + + // string Background color code + $bgcolor = ""; + if (!empty($attrs["bgcolor"])) $bgcolor = $attrs["bgcolor"]; + + // boolean Wether or not fill the background color + $fill = true; + if (isset($attrs["fill"])) { + if ($attrs["fill"] === "0") { + $fill = false; + } elseif ($attrs["fill"] === "1") { + $fill = true; + } + } + + // var boolean Whether or not a border should be printed around this box. 0 = no border, 1 = border. Default is 0 + $border = false; + if (isset($attrs["border"])) { + if ($attrs["border"] === "1") { + $border = true; + } elseif ($attrs["border"] === "0") { + $border = false; + } + } + // @test Print all borders for testing +// $border = true; + + /** + * Border style of rectangle. Array with keys among the following + * <ul><li>L, T, R, B or combinations: Line style of left, top, right or bottom border.</li></ul> + * @var string + */ + /** not yet in use + $borderstyle = ""; + if (!empty($attrs["borderstyle"])) $borderstyle = $attrs["borderstyle"]; + */ + + // int The starting height of this cell. If the text wraps the height will automatically be adjusted + $height = 0; + if (!empty($attrs["height"])) $height = (int)$attrs["height"]; + // int Setting the width to 0 will make it the width from the current location to the margin + $width = 0; + if (!empty($attrs["width"])) $width = (int)$attrs["width"]; + + // mixed Position the left corner of this box on the page. The default is the current position. + $left = "."; + if (isset($attrs["left"])) { + if ($attrs["left"] === ".") { + $left = "."; + } elseif (!empty($attrs["left"])) { + $left = (int)$attrs["left"]; + } elseif ($attrs["left"] === "0") { + $left = 0; + } + } + // mixed Position the top corner of this box on the page. the default is the current position + $top = "."; + if (isset($attrs["top"])) { + if ($attrs["top"] === ".") { + $top = "."; + } elseif (!empty($attrs["top"])) { + $top = (int)$attrs["top"]; + } elseif ($attrs["top"] === "0") { + $top = 0; + } + } + // boolean After this box is finished rendering, should the next section of text start immediately after the this box or should it start on a new line under this box. 0 = no new line, 1 = force new line. Default is 0 + $newline = false; + if (isset($attrs["newline"])) { + if ($attrs["newline"] === "1") { + $newline = true; + } elseif ($attrs["newline"] === "0") { + $newline = false; + } + } + // boolean + $pagecheck = true; + if (isset($attrs["pagecheck"])) { + if ($attrs["pagecheck"] === "0") { + $pagecheck = false; + } elseif ($attrs["pagecheck"] === "1") { + $pagecheck = true; + } + } + // boolean Cell padding + $padding = true; + if (isset($attrs["padding"])) { + if ($attrs["padding"] === "0") { + $padding = false; + } elseif ($attrs["padding"] === "1") { + $padding = true; + } + } + // boolean Reset this box Height + $reseth = false; + if (isset($attrs["reseth"])) { + if ($attrs["reseth"] === "1") { + $reseth = true; + } elseif ($attrs["reseth"] === "0") { + $reseth = false; + } + } + + // string Style of rendering + $style = ""; + // fill and border is enought for now for user input +// if (!empty($attrs["style"])) $style = $attrs["style"]; + + array_push($printDataStack, $printData); + $printData = false; + + array_push($pgvreportStack, $pgvreport); + $pgvreport = $PGVReportRoot->createTextBox($width, $height, $border, $bgcolor, $newline, $left, $top, $pagecheck, $style, $fill, $padding, $reseth); +} + +/** +* XML <PGVRTextBoxEHandler> end elemnt handler +* +* @see PGVRTextBoxSHandler() +*/ +function PGVRTextBoxEHandler() { + global $printData, $printDataStack, $pgvreport, $currentElement, $pgvreportStack; + + $printData = array_pop($printDataStack); + $currentElement = $pgvreport; + $pgvreport = array_pop($pgvreportStack); + $pgvreport->addElement($currentElement); +} + +/** +* @see PGVRTextEHandler() +* @todo add info to wiki about "color" +* @todo more variables in PGVRText class, check it out +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRTextSHandler($attrs) { + global $printData, $printDataStack, $currentElement, $PGVReportRoot; + + array_push($printDataStack, $printData); + $printData = true; + + // string The name of the PGVRStyle that should be used to render the text. + $style = ""; + if (!empty($attrs["style"])) $style = $attrs["style"]; + + // string The color of the text - Keep the black color as default + $color = ""; + if (!empty($attrs["color"])) $color = $attrs["color"]; + + $currentElement = $PGVReportRoot->createText($style, $color); +} + +/** +* @see PGVRTextSHandler() +*/ +function PGVRTextEHandler() { + global $printData, $printDataStack, $pgvreport, $currentElement; + + $printData = array_pop($printDataStack); + $pgvreport->addElement($currentElement); +} + +/** +* XML <PGVRGetPersonName> start elemnt handler +* Get the name +* 1. id is empty - current GEDCOM record +* 2. id is set with a record id +* +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRGetPersonNameSHandler($attrs) { + // @deprecated + global $currentElement, $vars, $gedrec; + + $id = ""; + $match = array(); + if (empty($attrs["id"])) { + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $id = $match[1]; + } + } else { + if (preg_match("/\\$(.+)/", $attrs["id"], $match)) { + if (isset($vars[$match[1]]["id"])) { + $id = $vars[$match[1]]["id"]; + } + } else { + if (preg_match("/@(.+)/", $attrs["id"], $match)) { + $gmatch = array(); + if (preg_match("/\d $match[1] @([^@]+)@/", $gedrec, $gmatch)) { + $id = $gmatch[1]; + } + } else { + $id = $attrs["id"]; + } + } + } + if (!empty($id)) { + $record = GedcomRecord::getInstance($id); + if (is_null($record)) { + return; + } + if (!$record->canDisplayName()) { + $currentElement->addText(i18n::translate('Private')); + } else { + $name = $record->getFullName(); + $name = preg_replace("/<span class=\"starredname\">(.*)<\/span> ?/", "\\1* ", $name); //restores the * for underlining a given name + if (!WT_RNEW) { + $name = strip_tags($name); + } + if (!empty($attrs["truncate"])) { + //short-circuit with the faster strlen + if (strlen($name)>$attrs["truncate"] && utf8_strlen($name)>$attrs["truncate"]) { + $name = preg_replace("/\(.*\) ?/", "", $name); //removes () and text inbetween - what about ", [ and { etc? + $words = explode(" ", $name); + $name = $words[count($words)-1]; + for($i=count($words)-2; $i>=0; $i--) { + $len = utf8_strlen($name); + for($j=count($words)-3; $j>=0; $j--) { + $len += utf8_strlen($words[$j]); + } + if ($len>$attrs["truncate"]) { + $first_letter = utf8_substr($words[$i], 0, 1); + //do not show " of nick-names + if ($first_letter != "\"") $name = utf8_substr($words[$i], 0, 1).". ".$name; + } else { + $name = $words[$i]." ".$name; + } + } + } + } else { + $addname = $record->getAddName(); + $addname = preg_replace("/<span class=\"starredname\">(.*)<\/span> ?/", "\\1* ", $addname); //@@ restores the * for underlining a given name + if (!WT_RNEW) { + $addname = strip_tags($addname);//@@ + } + if (!empty($addname)) { + $name .= " ".$addname; + } + } + $currentElement->addText(trim($name)); + } + } +} + +/** +* XML <PGVRGedcomValue> start elemnt handler +* +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRGedcomValueSHandler($attrs) { + // @deprecated + global $currentElement, $gedrec, $fact, $desc; + + $id = ""; + $match = array(); + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $id = $match[1]; + } + + if (isset($attrs["newline"]) && $attrs["newline"]=="1") { + $useBreak = "1"; + } else { + $useBreak = "0"; + } + + $tag = $attrs["tag"]; + if (!empty($tag)) { + if ($tag=="@desc") { + if (showFact($fact, $id) or showFactDetails($fact, $id)) { + $value = $desc; + } else { + $value = ""; + } + $value = trim($value); + $currentElement->addText($value); + } + if ($tag=="@id") { + $currentElement->addText($id); + } else { + $tag = str_replace("@fact", $fact, $tag); + if (empty($attrs["level"])) { + $temp = explode(" ", trim($gedrec)); + $level = $temp[0]; + if ($level==0) { + $level++; + } + } else { + $level = $attrs["level"]; + } + $truncate = ""; + if (isset($attrs["truncate"])) { + $truncate=$attrs["truncate"]; + } + $tags = explode(":", $tag); + //-- check all tags for privacy + foreach($tags as $subtag) { + if (!empty($subtag)) { + if (!showFact($subtag, $id) or !showFactDetails($subtag, $id)) { + return; + } + } + } + if (showFact($fact, $id) or showFactDetails($fact, $id)) { + $value = get_gedcom_value($tag, $level, $gedrec, $truncate); + if ($useBreak == "1") { + // Insert <br /> when multiple dates exist. + // This works around a TCPDF bug that incorrectly wraps RTL dates on LTR pages + $value = str_replace('(', '<br />(', $value); + $value = str_replace('<span dir="ltr"><br />', '<br /><span dir="ltr">', $value); + $value = str_replace('<span dir="rtl"><br />', '<br /><span dir="rtl">', $value); + if (substr($value, 0, 6) == '<br />') { + $value = substr($value, 6); + } + } + $currentElement->addText($value); + } + } + } +} + +/** +* XML <PGVRRepeatTag> start elemnt handler +* +* @see PGVRRepeatTagEHandler() +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRRepeatTagSHandler($attrs) { + // @deprecated +// global $repeats, $repeatsStack, $gedrec, $repeatBytes, $parser, $parserStack, $processRepeats, $fact, $desc; + global $repeats, $repeatsStack, $gedrec, $repeatBytes, $parser, $processRepeats, $fact, $desc; + + $processRepeats++; + if ($processRepeats>1) return; + + array_push($repeatsStack, array($repeats, $repeatBytes)); + $repeats = array(); + $repeatBytes = xml_get_current_line_number($parser); + + $id = ""; + $match = array(); + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $id = $match[1]; + } + + $tag = ""; + if (isset($attrs["tag"])) { + $tag = $attrs["tag"]; + } + if (!empty($tag)) { + if ($tag=="@desc") { + if (showFact($fact, $id) and showFactDetails($fact, $id)) { + $value = $desc; + } else { + $value = ""; + } + $value = trim($value); + $currentElement->addText($value); + } else { + $tag = str_replace("@fact", $fact, $tag); + $tags = explode(":", $tag); + $temp = explode(" ", trim($gedrec)); + $level = $temp[0]; + if ($level == 0) { + $level++; + } + $subrec = $gedrec; + $t = $tag; + $count = count($tags); + $i = 0; + while ($i < $count) { + $t = $tags[$i]; + if (!empty($t)) { + if (($level==1) && (strpos("CHIL,FAMS,FAMC", $t)===false) and (!showFact($t, $id) or !showFactDetails($t, $id))) { + return; + } + if ($i < ($count-1)) { + $subrec = get_sub_record($level, "$level $t", $subrec); + if (empty($subrec)) { + $level--; + $subrec = get_sub_record($level, "@ $t", $gedrec); + if (empty($subrec)) { + return; + } + } + } + $level++; + } + $i++; + } + $level--; + if ( (($level > 0) or (strpos("CHIL,FAMS,FAMC", $t) !== false)) or ((showFact($t, $id)) or (showFactDetails($t, $id))) ) { + $count = preg_match_all("/$level $t(.*)/", $subrec, $match, PREG_SET_ORDER); + $i = 0; + while ($i < $count) { + // Check for privacy + if (showFact($t, $id) and showFactDetails($t, $id)) { + $rec = get_sub_record($level, "$level $t", $subrec, $i + 1); + $repeats[] = trim($rec); + } + $i++; + } + } + } + } +} + +/** +* XML </ PGVRRepeatTag> end elemnt handler +* +* @see PGVRRepeatTagSHandler() +*/ +function PGVRRepeatTagEHandler() { + global $processRepeats, $repeats, $repeatsStack, $repeatBytes; + + $processRepeats--; + if ($processRepeats>0) { + return; + } + + // Check if there is anything to repeat + if (count($repeats)>0) { + // No need to load them if not used... + global $parser, $parserStack, $report, $gedrec; +// @deprecated +// $line = xml_get_current_line_number($parser)-1; + $lineoffset = 0; + foreach($repeatsStack as $rep) { + $lineoffset += $rep[1]; + } + //-- read the xml from the file + $lines = file($report); + while(strpos($lines[$lineoffset + $repeatBytes], "<PGVRRepeatTag")===false) { + $lineoffset--; + } + $lineoffset++; + $reportxml = "<tempdoc>\n"; + $line_nr = $lineoffset + $repeatBytes; + // RepeatTag Level counter + $count = 1; + while(0 < $count) { + if (strstr($lines[$line_nr], "<PGVRRepeatTag")!==false) { + $count++; + } elseif (strstr($lines[$line_nr], "</PGVRRepeatTag")!==false) { + $count--; + } + if (0 < $count) { + $reportxml .= $lines[$line_nr]; + } + $line_nr++; + } + // No need to drag this + unset($lines); + $reportxml .= "</tempdoc>\n"; + // Save original values + array_push($parserStack, $parser); + $oldgedrec = $gedrec; +// PHP 5.2.3 has a bug with foreach(), so don't use that here, while 5.2.3 is on the market + // while() has the fastest execution speed + $count = count($repeats); + $i = 0; + while($i < $count) { + $gedrec = $repeats[$i]; + //-- start the sax parser + $repeat_parser = xml_parser_create(); + $parser = $repeat_parser; + //-- make sure everything is case sensitive + xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); + //-- set the main element handler functions + xml_set_element_handler($repeat_parser, "startElement", "endElement"); + //-- set the character data handler + xml_set_character_data_handler($repeat_parser, "characterData"); + if (!xml_parse($repeat_parser, $reportxml, true)) { + printf($reportxml."\nPGVRRepeatTagEHandler XML error: %s at line %d", xml_error_string(xml_get_error_code($repeat_parser)), xml_get_current_line_number($repeat_parser)); + print_r($repeatsStack); + debug_print_backtrace(); + exit; + } + xml_parser_free($repeat_parser); + $i++; + } + // Restore original values + $gedrec = $oldgedrec; + $parser = array_pop($parserStack); + } + $temp = array_pop($repeatsStack); + $repeats = $temp[0]; + $repeatBytes = $temp[1]; +} + +/** +* Variable lookup +* +* Retrieve predefined variables : +* @ desc GEDCOM fact description, example: +* 1 EVEN This is a description +* @ fact GEDCOM fact tag, such as BIRT, DEAT etc. +* $ pgv_lang[] +* $ factarray[] +* $ language_settings[] +* +* +* Or retrieve variables preset with <PGVRSetVar> element +* +* If the variable is a date and 'date="1"' attribute is set then the date will be reformated +* from Sep to September +* +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRSetVarSHandler() +*/ +function PGVRvarSHandler($attrs) { + // @deprecated + global $currentElement, $type, $parser; + // Retrievable variables + global $desc, $fact, $language_settings, $vars; + + if (empty($attrs["var"])) { + die("<strong>REPORT ERROR PGVRvar: </strong> The attribute \"var=\" is missing or not set in the XML file on line: ".xml_get_current_line_number($parser)); + } + + $var = $attrs["var"]; + // PGVRSetVar element preset variables + if (!empty($vars[$var]["id"])) { + $var = $vars[$var]["id"]; + } else { + $tfact = $fact; + if (($fact == "EVEN" or $fact == "FACT") and $type != " ") { + // Use : + // n TYPE This text if string + $tfact = $type; + } + $var = str_replace(array("[", "]", "@fact", "@desc"), array("['", "']", $tfact, $desc), $var); + eval("if (!empty(\$$var)) \$var = \$$var;"); + $match = array(); + if (preg_match("/factarray\['(.*)'\]/", $var, $match)) { + $var = $match[1]; + } + } + // Check if variable is set as a date and reformat the date + if (isset($attrs["date"])) { + if ($attrs["date"] === "1") { + $g = new GedcomDate($var); + $var = $g->Display(); + } + } + $currentElement->addText($var); +} + +/** +* Variable lookup, retrieve the first letter only +* +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRvarLetterSHandler($attrs) { + global $currentElement, $fact, $desc; + + if (empty($attrs["var"])) { + die("<strong>REPORT ERROR PGVRvarLetter: </strong> The attribute \"var=\" is missing or not set in the XML file."); + } + + $var = $attrs["var"]; + if (!empty($var)) { + $abbrev = substr(strrchr(substr($var, 0, -1), "["), 1); + $tfact = $fact; + $var = str_replace(array("[", "]", "@fact", "@desc"), array("['", "']", $tfact, $desc), $var); + eval("if (!empty(\$$var)) \$var = \$$var;"); + $letter = utf8_substr($var, 0, 1); + $currentElement->addText($letter); + } +} + +/** +* @todo add info +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRFactsEHandler() +*/ +function PGVRFactsSHandler($attrs) { + // @deprecated +// global $repeats, $repeatsStack, $gedrec, $parser, $parserStack, $repeatBytes, $processRepeats, $vars; + global $repeats, $repeatsStack, $gedrec, $parser, $repeatBytes, $processRepeats, $vars; + + $processRepeats++; + if ($processRepeats>1) return; + + // @todo Why is this here when its not used? + + $families = 1; + if (isset($attrs["families"])) { + $families = $attrs["families"]; + } + + array_push($repeatsStack, array($repeats, $repeatBytes)); + $repeats = array(); + $repeatBytes = xml_get_current_line_number($parser); + + $id = ""; + $match = array(); + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $id = $match[1]; + } + $tag = ""; + if (isset($attrs["ignore"])) { + $tag .= $attrs["ignore"]; + } + if (preg_match("/\\$(.+)/", $tag, $match)) { + $tag = $vars[$match[1]]["id"]; + } + + if (empty($attrs["diff"]) && !empty($id)) { + $record = GedcomRecord::getInstance($id); + $facts = $record->getFacts(explode(",", $tag)); + if (!is_array($facts)) { + $facts = array($facts); + } + sort_facts($facts); + $repeats = array(); + foreach($facts as $event) { + if (strpos($tag.",", $event->getTag())===false) { + $repeats[]=$event->getGedComRecord(); + } + } + } else { + global $nonfacts; + $nonfacts = preg_split("/[\s,;:]/", $tag); + $record = new GedcomRecord($gedrec); + switch ($record->getType()) { + case "INDI": + $record=new Person($gedrec); + break; + case "FAM": + $record=new Family($gedrec); + break; + case "SOUR": + $record=new Source($gedrec); + break; + case "REPO": + $record=new Repository($gedrec); + break; + case "NOTE": + $record=new Note($gedrec); + break; + } + $oldrecord = GedcomRecord::getInstance($record->getXref()); + $oldrecord->diffMerge($record); + $facts = $oldrecord->getFacts(); + foreach ($facts as $fact) { + if (strpos($fact->getGedcomRecord(), "WT_NEW")!==false) { + $repeats[]=$fact->getGedcomRecord(); + } + } + } +} + +/** +* XML </ PGVRFacts> end elemnt handler +* +* @see PGVRFactsSHandler() +*/ +function PGVRFactsEHandler() { + global $repeats, $repeatsStack, $repeatBytes, $parser, $parserStack, $report, $gedrec, $fact, $desc, $type, $processRepeats; + + $processRepeats--; + if ($processRepeats>0) { + return; + } + + // Check if there is anything to repeat + if (count($repeats) > 0) { + + $line = xml_get_current_line_number($parser)-1; + $lineoffset = 0; + foreach($repeatsStack as $rep) { + $lineoffset += $rep[1]; + } + + //-- read the xml from the file + $lines = file($report); + while(($lineoffset + $repeatBytes > 0) and (strpos($lines[$lineoffset + $repeatBytes], "<PGVRFacts ")) === false) { + $lineoffset--; + } + $lineoffset++; + $reportxml = "<tempdoc>\n"; + $i = $line + $lineoffset; + $line_nr = $repeatBytes + $lineoffset; + while($line_nr < $i) { + $reportxml .= $lines[$line_nr]; + $line_nr++; + } + // No need to drag this + unset($lines); + $reportxml .= "</tempdoc>\n"; + // Save original values + array_push($parserStack, $parser); + $oldgedrec = $gedrec; + $count = count($repeats); + $i = 0; + $match = array(); + while($i < $count) { + $gedrec = $repeats[$i]; + $fact = ""; + $desc = ""; + if (preg_match("/1 (\w+)(.*)/", $gedrec, $match)) { + $fact = $match[1]; + if ($fact=="EVEN" or $fact=="FACT") { + $tmatch = array(); + if (preg_match("/2 TYPE (.+)/", $gedrec, $tmatch)) { + $type = trim($tmatch[1]); + } else { + $type = " "; + } + } + $desc = trim($match[2]); + $desc .= get_cont(2, $gedrec); + } + //-- start the sax parser + $repeat_parser = xml_parser_create(); + $parser = $repeat_parser; + //-- make sure everything is case sensitive + xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); + //-- set the main element handler functions + xml_set_element_handler($repeat_parser, "startElement", "endElement"); + //-- set the character data handler + xml_set_character_data_handler($repeat_parser, "characterData"); + if (!xml_parse($repeat_parser, $reportxml, true)) { + die(sprintf($reportxml."\nPGVRFactsEHandler XML error: %s at line %d", xml_error_string(xml_get_error_code($repeat_parser)), xml_get_current_line_number($repeat_parser))); + } + xml_parser_free($repeat_parser); + $i++; + } + // Restore original values + $parser = array_pop($parserStack); + $gedrec = $oldgedrec; + } + $temp = array_pop($repeatsStack); + $repeats = $temp[0]; + $repeatBytes = $temp[1]; +} + +/** +* Setting upp or changing variables in the XML +* The XML variable name and value is stored in the global variable $vars +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRSetVarSHandler($attrs) { + global $vars, $gedrec, $fact, $desc, $type, $generation; + + if (empty($attrs["name"])) { + die("<strong>REPORT ERROR PGVRvar: </strong> The attribute \"name=\" is missing or not set in the XML file"); + } + + $name = $attrs["name"]; + $value = $attrs["value"]; + $match = array(); + // Current GEDCOM record strings + if ($value == "@ID") { + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $value = $match[1]; + } + } elseif ($value == "@fact") { + $value = $fact; + } elseif ($value == "@desc") { + $value = $desc; + } elseif ($value == "@generation") { + $value = $generation; + } elseif (preg_match("/@(\w+)/", $value, $match)) { + $gmatch = array(); + if (preg_match("/\d $match[1] (.+)/", $gedrec, $gmatch)) { + $value = str_replace("@", "", trim($gmatch[1])); + } + } + if (preg_match("/\\$(\w+)/", $name, $match)) { + $name = $vars["'".$match[1]."'"]["id"]; + } + // TODO: find an alternative that doesn't use pgv_lang + //if ((substr($value, 0, 10) == "\$pgv_lang[") or (substr($value, 0, 11) == "\$factarray[")) { + // $var = str_replace(array("[", "]"), array("['", "']"), $value); + // eval("\$value = $var;"); + //} + //$count = preg_match_all("/\\$(\w+)/", $value, $match, PREG_SET_ORDER); + //$i=0; + //while($i<$count) { + // $t = $vars[$match[$i][1]]["id"]; + // $value = preg_replace("/\\$".$match[$i][1]."/", $t, $value, 1); + // $i++; + //} + // Arithmetic functions + if (preg_match("/(\d+)\s*([\-\+\*\/])\s*(\d+)/", $value, $match)) { + switch($match[2]) { + case "+": + $t = $match[1] + $match[3]; + $value = preg_replace("/".$match[1]."\s*([\-\+\*\/])\s*".$match[3]."/", $t, $value); + break; + case "-": + $t = $match[1] - $match[3]; + $value = preg_replace("/".$match[1]."\s*([\-\+\*\/])\s*".$match[3]."/", $t, $value); + break; + case "*": + $t = $match[1] * $match[3]; + $value = preg_replace("/".$match[1]."\s*([\-\+\*\/])\s*".$match[3]."/", $t, $value); + break; + case "/": + $t = $match[1] / $match[3]; + $value = preg_replace("/".$match[1]."\s*([\-\+\*\/])\s*".$match[3]."/", $t, $value); + break; + } + } + if (strpos($value, "@")!==false) { + $value=""; + } + $vars[$name]["id"]=$value; +} + +/** +* XML <PGVRif > start element +* @see PGVRifEHandler() +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRifSHandler($attrs) { + global $vars, $gedrec, $processIfs, $fact, $desc, $generation, $POSTAL_CODE; + + if ($processIfs>0) { + $processIfs++; + return; + } + + $vars["POSTAL_CODE"]["id"] = $POSTAL_CODE; + $condition = $attrs["condition"]; + $condition = preg_replace("/\\$(\w+)/", "\$vars[\"$1\"][\"id\"]", $condition); + $condition = str_replace(array(" LT ", " GT "), array("<", ">"), $condition); + // Replace the first accurance only once of @fact:DATE or in any other combinations to the current fact, such as BIRT + $condition = str_replace("@fact", $fact, $condition); + $match = array(); + $count = preg_match_all("/@([\w:\.]+)/", $condition, $match, PREG_SET_ORDER); + $i = 0; + while( $i < $count ) { + $id = $match[$i][1]; + $value="\"\""; + if ($id=="ID") { + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $value = "'".$match[1]."'"; + } + } elseif ($id=="fact") { + $value = "\"$fact\""; + } elseif ($id=="desc") { + $value = "\"$desc\""; + } elseif ($id=="generation") { + $value = "\"$generation\""; + } else { + + $temp = explode(" ", trim($gedrec)); + $level = $temp[0]; + if ($level==0) { + $level++; + } + $value = get_gedcom_value($id, $level, $gedrec, "", false); + if (empty($value)) { + $level++; + $value = get_gedcom_value($id, $level, $gedrec, "", false); + } + $value = "\"".str_replace(array("'", '"'), array("\'", '\"'), $value)."\""; + } + $condition = str_replace("@$id", $value, $condition); + $i++; + } + $condition = "if ($condition) return true; else return false;"; + $ret = @eval($condition); + if (!$ret) { + $processIfs++; + } +} + +/** +* XML <PGVRif /> end element +* @see PGVRifSHandler() +*/ +function PGVRifEHandler() { + global $processIfs; + if ($processIfs>0) $processIfs--; +} + +/** +* XML <PGVRFootnote > start element +* Collect the Footnote links +* GEDCOM Records that are protected by Privacy setting will be ignore +* +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRFootnoteEHandler() +*/ +function PGVRFootnoteSHandler($attrs) { + global $printData, $printDataStack, $currentElement, $footnoteElement, $processFootnote, $gedrec, $PGVReportRoot; + + $match = array(); + $id=""; + $tag=""; + if (preg_match("/[0-9] (.+) @(.+)@/", $gedrec, $match)) { + $tag = $match[1]; + $id = $match[2]; + } + if (displayDetailsById($id, $tag)) { + array_push($printDataStack, $printData); + $printData = true; + $style = ""; + if (!empty($attrs["style"])) { + $style=$attrs["style"]; + } + $footnoteElement = $currentElement; + $currentElement = $PGVReportRoot->createFootnote($style); + } else { + $printData = false; + $processFootnote = false; + } +} + +/** +* XML <PGVRFootnote /> end element +* Print the collected Footnote data +* +* @see PGVRFootnoteSHandler() +*/ +function PGVRFootnoteEHandler() { + // @deprecated +// global $printData, $printDataStack, $currentElement, $footnoteElement, $processFootnote, $gedrec, $pgvreport; + global $printData, $printDataStack, $currentElement, $footnoteElement, $processFootnote, $pgvreport; + + if ($processFootnote) { + $printData = array_pop($printDataStack); + $temp = trim($currentElement->getValue()); + if (strlen($temp)>3) { + $pgvreport->addElement($currentElement); + } + $currentElement = $footnoteElement; + } else { + $processFootnote = true; + } +} + +/** +* XML <PGVRFootnoteTexts /> element +* +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRFootnoteTextsSHandler() { + global $pgvreport; + + $temp = "footnotetexts"; + $pgvreport->addElement($temp); +} + +/** +* XML element Forced line break handler - HTML code +* +*/ +function brSHandler() { + global $printData, $currentElement, $processGedcoms; + if ($printData && ($processGedcoms==0)) $currentElement->addText("<br />"); +} + +/** +* XML <sp />element Forced space handler +* +* @todo add info to wiki - missing function +*/ +function spSHandler() { + global $printData, $currentElement, $processGedcoms; + if ($printData && ($processGedcoms==0)) $currentElement->addText(" "); +} + +/** +* @todo add info +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRHighlightedImageSHandler($attrs) { + global $gedrec, $pgvreport, $PGVReportRoot; + + $id = ""; + $match = array(); + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $id = $match[1]; + } + + // mixed Position the top corner of this box on the page. the default is the current position + $top = "."; + if (isset($attrs["top"])) { + if ($attrs["top"] === "0") { + $top = 0; + } elseif ($attrs["top"] === ".") { + $top = "."; + } elseif (!empty($attrs["top"])) { + $top = (int)$attrs["top"]; + } + } + + // mixed Position the left corner of this box on the page. the default is the current position + $left = "."; + if (isset($attrs["left"])) { + if ($attrs["left"] === "0") { + $left = 0; + } elseif ($attrs["left"] === ".") { + $left = "."; + } elseif (!empty($attrs["left"])) { + $left = (int)$attrs["left"]; + } + } + + // string Align the image in left, center, right + $align = ""; + if (!empty($attrs["align"])) $align = $attrs["align"]; + + // string Next Line should be T:next to the image, N:next line + $ln = ""; + if (!empty($attrs["ln"])) $ln = $attrs["ln"]; + + $width = 0; + $height = 0; + if (!empty($attrs["width"])) $width = (int)$attrs["width"]; + if (!empty($attrs["height"])) $height = (int)$attrs["height"]; + + if (showFact("OBJE", $id)) { + $media = find_highlighted_object($id, WT_GED_ID, $gedrec); + if (!empty($media["file"])) { + if (preg_match("/(jpg)|(jpeg)|(png)$/i", $media["file"])) { + if (file_exists($media["file"])) { + $size = findImageSize($media["file"]); + if (($width>0) and ($height==0)) { + $perc = $width / $size[0]; + $height= round($size[1]*$perc); + } elseif (($height>0) and ($width==0)) { + $perc = $height / $size[1]; + $width= round($size[0]*$perc); + } else { + $width = $size[0]; + $height = $size[1]; + } + $image = $PGVReportRoot->createImage($media["file"], $left, $top, $width, $height, $align, $ln); + $pgvreport->addElement($image); + } + } + } + } +} + +/** +* @todo add info +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRImageSHandler($attrs) { + global $gedrec, $pgvreport, $MEDIA_DIRECTORY, $PGVReportRoot; + + // mixed Position the top corner of this box on the page. the default is the current position + $top = "."; + if (isset($attrs["top"])) { + if ($attrs["top"] === "0") { + $top = 0; + } elseif ($attrs["top"] === ".") { + $top = "."; + } elseif (!empty($attrs["top"])) { + $top = (int)$attrs["top"]; + } + } + + // mixed Position the left corner of this box on the page. the default is the current position + $left = "."; + if (isset($attrs["left"])) { + if ($attrs["left"] === "0") { + $left = 0; + } elseif ($attrs["left"] === ".") { + $left = "."; + } elseif (!empty($attrs["left"])) { + $left = (int)$attrs["left"]; + } + } + + // string Align the image in left, center, right + $align = ""; + if (!empty($attrs["align"])) $align = $attrs["align"]; + + // string Next Line should be T:next to the image, N:next line + $ln = "T"; + if (!empty($attrs["ln"])) $ln = $attrs["ln"]; + + $width = 0; + $height = 0; + if (!empty($attrs["width"])) $width = (int)$attrs["width"]; + if (!empty($attrs["height"])) $height = (int)$attrs["height"]; + + $file = ""; + if (!empty($attrs["file"])) $file = $attrs["file"]; + + if ($file=="@FILE") { + $match = array(); + if (preg_match("/\d OBJE @(.+)@/", $gedrec, $match)) { + $orec = find_gedcom_record($match[1], WT_GED_ID); + } else { + $orec = $gedrec; + } + if (!empty($orec)) { + $fullpath = extract_fullpath($orec); + $filename = ""; + $filename = extract_filename($fullpath); + $filename = $MEDIA_DIRECTORY.$filename; + $filename = trim($filename); + if (!empty($filename)) { + if (preg_match("/(jpg)|(jpeg)|(png)$/i", $filename)) { + if (file_exists($filename)) { + $size = findImageSize($filename); + if (($width > 0) and ($height == 0)) { + $perc = $width / $size[0]; + $height= round($size[1]*$perc); + } elseif (($height > 0) and ($width == 0)) { + $perc = $height / $size[1]; + $width= round($size[0]*$perc); + } else { + $width = $size[0]; + $height = $size[1]; + } + $image = $PGVReportRoot->createImage($filename, $left, $top, $width, $height, $align, $ln); + $pgvreport->addElement($image); + } + } + } + } + } + else { + $filename = $file; + if (preg_match("/(jpg)|(jpeg)|(png)|(gif)$/i", $filename)) { + if (file_exists($filename)) { + $size = findImageSize($filename); + if (($width>0) and ($height==0)) { + $perc = $width / $size[0]; + $height= round($size[1]*$perc); + } elseif (($height>0) and ($width==0)) { + $perc = $height / $size[1]; + $width= round($size[0]*$perc); + } else { + $width = $size[0]; + $height = $size[1]; + } + $image = $PGVReportRoot->createImage($filename, $left, $top, $width, $height, $align, $ln); + $pgvreport->addElement($image); + } + } + } +} + +/** +* XML <PGVRLine> elemnt handler +* +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRLineSHandler($attrs) { + global $pgvreport, $PGVReportRoot; + + // Start horizontal position, current position (default) + $x1 = "."; + if (isset($attrs["x1"])) { + if ($attrs["x1"] === "0") { + $x1 = 0; + } elseif ($attrs["x1"] === ".") { + $x1 = "."; + } elseif (!empty($attrs["x1"])) { + $x1 = (int)$attrs["x1"]; + } + } + // Start vertical position, current position (default) + $y1 = "."; + if (isset($attrs["y1"])) { + if ($attrs["y1"] === "0") { + $y1 = 0; + } elseif ($attrs["y1"] === ".") { + $y1 = "."; + } elseif (!empty($attrs["y1"])) { + $y1 = (int)$attrs["y1"]; + } + } + // End horizontal position, maximum width (default) + $x2 = "."; + if (isset($attrs["x2"])) { + if ($attrs["x2"] === "0") { + $x2 = 0; + } elseif ($attrs["x2"] === ".") { + $x2 = "."; + } elseif (!empty($attrs["x2"])) { + $x2 = (int)$attrs["x2"]; + } + } + // End vertical position + $y2 = "."; + if (isset($attrs["y2"])) { + if ($attrs["y2"] === "0") { + $y2 = 0; + } elseif ($attrs["y2"] === ".") { + $y2 = "."; + } elseif (!empty($attrs["y2"])) { + $y2 = (int)$attrs["y2"]; + } + } + + $line = $PGVReportRoot->createLine($x1, $y1, $x2, $y2); + $pgvreport->addElement($line); +} + +/** +* XML <PGVRList> start elemnt handler +* +* @see PGVRListEHandler() +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRListSHandler($attrs) { + global $gedrec, $repeats, $repeatBytes, $list, $repeatsStack, $processRepeats, $parser, $vars, $sortby; + global $pgv_changes, $GEDCOM, $TBLPREFIX; + + $processRepeats++; + if ($processRepeats > 1) return; + + $match = array(); + if (isset($attrs["sortby"])) { + $sortby = $attrs["sortby"]; + if (preg_match("/\\$(\w+)/", $sortby, $match)) { + $sortby = $vars[$match[1]]["id"]; + $sortby = trim($sortby); + } + } else { + $sortby = "NAME"; + } + + if (isset($attrs["list"])) { + $listname=$attrs["list"]; + } else { + $listname = "individual"; + } + // Some filters/sorts can be applied using SQL, while others require PHP + switch ($listname) { + case "pending": + $list=array(); + foreach ($pgv_changes as $changes) { + $change=end($changes); + if ($change["gedcom"]==$GEDCOM) { + switch ($change["type"]) { + case "replace": + // Update - show the latest version of the record + $list[]=new GedcomRecord($change["undo"]); + break; + case "delete": + // Delete - show the last accepted version of the record + $list[]=GedcomRecord::getInstance($change["gid"]); + break; + } + } + } + break; + case "individual": + case "family": + $sql_col_prefix=substr($listname, 0, 1)."_"; // i_ for individual, f_ for family, etc. + $sql_join=array(); + $sql_where=array($sql_col_prefix."file=".WT_GED_ID); + $sql_order_by=array(); + foreach ($attrs as $attr=>$value) { + if ((strpos($attr, "filter")===0) && $value) { + // Substitute global vars + $value=preg_replace('/\$(\w+)/e', '$vars["\\1"]["id"]', $value); + // Convert the various filters into SQL + if (preg_match('/^(\w+):DATE (LTE|GTE) (.+)$/', $value, $match)) { + $sql_join[]="JOIN {$TBLPREFIX}dates AS {$attr} ON ({$attr}.d_file={$sql_col_prefix}file AND {$attr}.d_gid={$sql_col_prefix}id)"; + $sql_where[]="{$attr}.d_fact='{$match[1]}'"; + $date=new GedcomDate($match[3]); + if ($match[2]=="LTE") { + $sql_where[]="{$attr}.d_julianday2<=".$date->minJD(); + } else { + $sql_where[]="{$attr}.d_julianday1>=".$date->minJD(); + } + if ($sortby==$match[1]) { + $sortby=""; + $sql_order_by[]="{$attr}.d_julianday1"; + } + unset($attrs[$attr]); // This filter has been fully processed + } elseif (($listname=="individual") && (preg_match('/^NAME CONTAINS (.*)$/', $value, $match))){ + // Do nothing, unless you have to + if (($match[1] != "") or ($sortby=="NAME")){ + $sql_join[]="JOIN {$TBLPREFIX}name AS {$attr} ON (n_file={$sql_col_prefix}file AND n_id={$sql_col_prefix}id)"; + // Search the DB only if there is any name supplied + if ($match[1] != ""){ + $names = explode(" ", $match[1]); + foreach ($names as $name){ + $sql_where[]="{$attr}.n_full LIKE ".WT_DB::quote(utf8_strtoupper("%{$name}%")); + } + } + // Let the DB do the name sorting even when no name was entered + if ($sortby=="NAME"){ + $sortby=""; + $sql_order_by[]="{$attr}.n_sort"; + } + } + unset($attrs[$attr]); // This filter has been fully processed + } elseif (($listname=="family") && (preg_match('/^NAME CONTAINS (.+)$/', $value, $match))) { + // Eventually, family "names" will be stored in pgv_name. Until then, an extra is needed.... + $sql_join[]="JOIN {$TBLPREFIX}link AS {$attr}a ON ({$attr}a.l_file={$sql_col_prefix}file AND {$attr}a.l_from={$sql_col_prefix}id)"; + $sql_join[]="JOIN {$TBLPREFIX}name AS {$attr}b ON ({$attr}b.n_file={$sql_col_prefix}file AND n_id={$sql_col_prefix}id)"; + $sql_where[]="{$attr}a.l_type=IN ('HUSB, 'WIFE')"; + $sql_where[]="{$attr}.n_full LIKE ".WT_DB::quote(utf8_strtoupper("%{$match[1]}%")); + if ($sortby=="NAME") { + $sortby=""; + $sql_order_by[]="{$attr}.n_sort"; + } + unset($attrs[$attr]); // This filter has been fully processed + } elseif (preg_match('/^(?:\w+):PLAC CONTAINS (.+)$/', $value, $match)) { + $sql_join[]="JOIN {$TBLPREFIX}places AS {$attr}a ON ({$attr}a.p_file={$sql_col_prefix}file)"; + $sql_join[]="JOIN {$TBLPREFIX}placelinks AS {$attr}b ON ({$attr}a.p_file={$attr}b.pl_file AND {$attr}b.pl_p_id={$attr}a.p_id AND {$attr}b.pl_gid={$sql_col_prefix}id)"; + $sql_where[]="{$attr}a.p_place LIKE ".WT_DB::quote(utf8_strtoupper("%{$match[1]}%")); + // Don't unset this filter. This is just the first primary PLAC filter to reduce the returned list from the DB + } + /** + * General Purpose DB Filter for Individual and Family Lists + * Place any other filter before these filters because they will pick up any filters that has not been processed + * Also, do not unset() these two filters. These are just the first primary filters to reduce the returned list from the DB + */ + elseif (($listname=="individual") and (preg_match('/^(\w*):*(\w*) CONTAINS (.*)$/', $value, $match))){ + $query = ""; + // Level 1 tag + if ($match[1] != "") $query .= "%1 {$match[1]}%"; + // Level 2 tag + if ($match[2] != "") $query .= "%2 {$match[2]}%"; + // Contains what? + if ($match[3] != "") $query .= "%{$match[3]}%"; + $sql_where[] = "i_gedcom LIKE ".WT_DB::quote(utf8_strtoupper($query)); + unset($query); + } elseif (($listname=="family") and (preg_match('/^(\w*):*(\w*) CONTAINS (.*)$/', $value, $match))){ + $query = ""; + // Level 1 tag + if ($match[1] != "") $query .= "%1 {$match[1]}%"; + // Level 2 tag + if ($match[2] != "") $query .= "%2 {$match[2]}%"; + // Contains what? + if ($match[3] != "") $query .= "%{$match[3]}%"; + $sql_where[] = "f_gedcom LIKE ".WT_DB::quote(utf8_strtoupper($query)); + unset($query); + } else { + // TODO: what other filters can we apply in SQL? + } + } + } + if ($listname=="family") { + $list=search_fams_custom($sql_join, $sql_where, $sql_order_by); + } else { + $list=search_indis_custom($sql_join, $sql_where, $sql_order_by); + } + // Clean up the SQL queries - they will not be used again + unset($sql_join, $sql_where, $sql_order_by); + break; + default: + die("Invalid list name: $listname"); + } + + $filters = array(); + $filters2 = array(); + if ((isset($attrs["filter1"])) and (count($list) > 0)) { + foreach($attrs as $key=>$value) { + if (preg_match("/filter(\d)/", $key)) { + $condition = $value; + if (preg_match("/@(\w+)/", $condition, $match)) { + $id = $match[1]; + $value="''"; + if ($id=="ID") { + if (preg_match("/0 @(.+)@/", $gedrec, $match)) { + $value = "'".$match[1]."'"; + } + } elseif ($id=="fact") { + $value = "'$fact'"; + } elseif ($id=="desc") { + $value = "'$desc'"; + } else { + if (preg_match("/\d $id (.+)/", $gedrec, $match)) { + $value = "'".str_replace("@", "", trim($match[1]))."'"; + } + } + $condition = preg_replace("/@$id/", $value, $condition); + } + //-- handle regular expressions + if (preg_match("/([A-Z:]+)\s*([^\s]+)\s*(.+)/", $condition, $match)) { + $tag = trim($match[1]); + $expr = trim($match[2]); + $val = trim($match[3]); + if (preg_match("/\\$(\w+)/", $val, $match)) { + $val = $vars[$match[1]]["id"]; + $val = trim($val); + } + $searchstr = ""; + $tags = explode(":", $tag); + //-- only limit to a level number if we are specifically looking at a level + if (count($tags)>1) { + $level = 1; + foreach($tags as $t) { + if (!empty($searchstr)) { + $searchstr.="[^\n]*(\n[2-9][^\n]*)*\n"; + } + //-- search for both EMAIL and _EMAIL... silly double gedcom standard + if ($t=="EMAIL" || $t=="_EMAIL") { + $t="_?EMAIL"; + } + $searchstr .= $level." ".$t; + $level++; + } + } else { + if ($tag=="EMAIL" || $tag=="_EMAIL") { + $tag="_?EMAIL"; + } + $t = $tag; + $searchstr = "1 ".$tag; + } + switch ($expr) { + case "CONTAINS": + if ($t=="PLAC") { + $searchstr.="[^\n]*[, ]*".$val; + } else { + $searchstr.="[^\n]*".$val; + } + $filters[] = $searchstr; + break; + default: + if (!empty($val)) { + $filters2[] = array("tag"=>$tag, "expr"=>$expr, "val"=>$val); + } + break; + } + } + } + } + } + //-- apply other filters to the list that could not be added to the search string + if ($filters) { + foreach ($list as $key=>$record) { + foreach ($filters as $filter) { + if (!preg_match("/".$filter."/i", $record->getGedcomRecord())) { + unset($list[$key]); + break; + } + } + } + } + if ($filters2) { + $mylist = array(); + foreach($list as $indi) { + $key=$indi->getXref(); + $grec=$indi->getGedcomRecord(); + $keep = true; + foreach($filters2 as $filter) { + if ($keep) { + $tag = $filter["tag"]; + $expr = $filter["expr"]; + $val = $filter["val"]; + if ($val=="''") { + $val = ""; + } + $tags = explode(":", $tag); + $t = end($tags); + $v = get_gedcom_value($tag, 1, $grec, "", false); + //-- check for EMAIL and _EMAIL (silly double gedcom standard :P) + if ($t=="EMAIL" && empty($v)) { + $tag = str_replace("EMAIL", "_EMAIL", $tag); + $tags = explode(":", $tag); + $t = end($tags); + $v = get_sub_record(1, $tag, $grec); + } + + + $level = count($tags); + switch ($expr) { + case "GTE": + if ($t=="DATE") { + $date1 = new GedcomDate($v); + $date2 = new GedcomDate($val); + $keep = (GedcomDate::Compare($date1, $date2)>=0); + } elseif ($val >= $v) { + $keep=true; + } + break; + case "LTE": + if ($t=="DATE") { + $date1 = new GedcomDate($v); + $date2 = new GedcomDate($val); + $keep = (GedcomDate::Compare($date1, $date2)<=0); + } elseif ($val >= $v) { + $keep=true; + } + break; + case "SUBCONTAINS": + $v = get_sub_record($level, $level." ".$tag, $grec); + if (empty($v) && $tag=="ADDR") { + $v = get_sub_record($level+1, ($level+1)." ".$tag, $grec); + } + if (strripos($v, $val)!==false) { + $keep = true; + } else { + $keep = false; + } + break; + default: + if ($v==$val) { + $keep=true; + } else { + $keep = false; + } + break; + } + } + } + if ($keep) $mylist[$key]=$indi; + } + $list = $mylist; + } + + switch ($sortby) { + case "NAME": + uasort($list, array("GedcomRecord", "Compare")); + break; + case "ID": + uasort($list, array("GedcomRecord", "CompareId")); + break; + case "CHAN": + uasort($list, array("GedcomRecord", "CompareChanDate")); + break; + case "BIRT:DATE": + uasort($list, array("Person", "CompareBirtDate")); + break; + case "DEAT:DATE": + uasort($list, array("Person", "CompareDeatDate")); + break; + case "MARR:DATE": + uasort($list, array("Family", "CompareMarrDate")); + break; + default: + // unsorted or already sorted by SQL + break; + } + + array_push($repeatsStack, array($repeats, $repeatBytes)); + $repeatBytes = xml_get_current_line_number($parser)+1; +} + +/** +* XML <PGVRList> end elemnt handler +* @see PGVRListSHandler() +*/ +function PGVRListEHandler() { + global $list, $repeats, $repeatsStack, $repeatBytes, $parser, $parserStack, $report, $gedrec, $processRepeats, $list_total, $list_private; + + $processRepeats--; + if ($processRepeats>0) { + return; + } + + // Check if there is any list + if (count($list) > 0) { + // @deprecated +// $line = xml_get_current_line_number($parser)-1; + $lineoffset = 0; + foreach($repeatsStack as $rep) { + $lineoffset += $rep[1]; + } + //-- read the xml from the file + $lines = file($report); + while((strpos($lines[$lineoffset + $repeatBytes], "<PGVRList")===false) && (($lineoffset + $repeatBytes) > 0)) { + $lineoffset--; + } + $lineoffset++; + $reportxml = "<tempdoc>\n"; + $line_nr = $lineoffset + $repeatBytes; + // List Level counter + $count = 1; + while(0 < $count) { + if (strpos($lines[$line_nr], "<PGVRList")!==false) { + $count++; + } elseif (strpos($lines[$line_nr], "</PGVRList")!==false) { + $count--; + } + if (0 < $count) { + $reportxml .= $lines[$line_nr]; + } + $line_nr++; + } + // No need to drag this + unset($lines); + $reportxml .= "</tempdoc>"; + // Save original values + array_push($parserStack, $parser); + $oldgedrec = $gedrec; + + $list_total = count($list); + $list_private = 0; + foreach ($list as $record) { + if ($record->canDisplayDetails()) { + $gedrec = $record->getGedcomRecord(); + //-- start the sax parser + $repeat_parser = xml_parser_create(); + $parser = $repeat_parser; + //-- make sure everything is case sensitive + xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); + //-- set the main element handler functions + xml_set_element_handler($repeat_parser, "startElement", "endElement"); + //-- set the character data handler + xml_set_character_data_handler($repeat_parser, "characterData"); + if (!xml_parse($repeat_parser, $reportxml, true)) { + printf($reportxml."\nPGVRListEHandler XML error: %s at line %d", xml_error_string(xml_get_error_code($repeat_parser)), xml_get_current_line_number($repeat_parser)); + print_r($repeatsStack); + debug_print_backtrace(); + exit; + } + xml_parser_free($repeat_parser); + } + else $list_private++; + } + // Clean up the GLOBAL list array + unset($list); + $parser = array_pop($parserStack); + $gedrec = $oldgedrec; + } + $temp = array_pop($repeatsStack); + $repeats = $temp[0]; + $repeatBytes = $temp[1]; +} + +/** +* XML <PGVRListTotal> elemnt handler +* +* Prints the total number of records in a list +* The total number is collected from +* PGVRList and PGVRRelatives +* @param array $attrs an array of key value pairs for the attributes +*/ +function PGVRListTotalSHandler() { + global $list_total, $list_private, $currentElement; + + if (empty($list_total)) $list_total = 0; + + if ($list_private==0) { + $currentElement->addText($list_total); + } else { + $currentElement->addText(($list_total - $list_private)." / ".$list_total); + } +} + +/** +* @todo add info +* @param array $attrs an array of key value pairs for the attributes +* @see PGVRRelativesEHandler() +*/ +function PGVRRelativesSHandler($attrs) { + global $repeats, $repeatBytes, $list, $repeatsStack, $processRepeats, $parser, $vars, $sortby; + + $processRepeats++; + if ($processRepeats>1) return; + + $sortby = "NAME"; + if (isset($attrs["sortby"])) $sortby = $attrs["sortby"]; + $match = array(); + if (preg_match("/\\$(\w+)/", $sortby, $match)) { + $sortby = $vars[$match[1]]["id"]; + $sortby = trim($sortby); + } + + $maxgen = -1; + if (isset($attrs["maxgen"])) $maxgen = $attrs["maxgen"]; + if ($maxgen=="*") $maxgen = -1; + + $group = "child-family"; + if (isset($attrs["group"])) $group = $attrs["group"]; + if (preg_match("/\\$(\w+)/", $group, $match)) { + $group = $vars[$match[1]]["id"]; + $group = trim($group); + } + + $id = ""; + if (isset($attrs["id"])) $id = $attrs["id"]; + if (preg_match("/\\$(\w+)/", $id, $match)) { + $id = $vars[$match[1]]["id"]; + $id = trim($id); + } + + $showempty = false; + if (isset($attrs["showempty"])) $showempty = $attrs["showempty"]; + if (preg_match("/\\$(\w+)/", $showempty, $match)) { + $showempty = $vars[$match[1]]["id"]; + $showempty = trim($showempty); + } + + $list = array(); + $person = Person::getInstance($id); + if (!empty($person)) { + $list[$id] = $person; + switch ($group) { + case "child-family": + $famids = $person->getChildFamilies(); + foreach($famids as $family) { + $husband = $family->getHusband(); + $wife = $family->getWife(); + if (!empty($husband)) { + $list[$husband->getXref()] = $husband; + } + if (!empty($wife)) { + $list[$wife->getXref()] = $wife; + } + $children = $family->getChildren(); + foreach($children as $child) { + if (!empty($child)) $list[$child->getXref()] = $child; + } + } + break; + case "spouse-family": + $famids = $person->getSpouseFamilies(); + foreach($famids as $family) { + $husband = $family->getHusband(); + $wife = $family->getWife(); + if (!empty($husband)) { + $list[$husband->getXref()] = $husband; + } + if (!empty($wife)) { + $list[$wife->getXref()] = $wife; + } + $children = $family->getChildren(); + foreach($children as $child) { + if (!empty($child)) $list[$child->getXref()] = $child; + } + } + break; + case "direct-ancestors": + add_ancestors($list, $id, false, $maxgen, $showempty); + break; + case "ancestors": + add_ancestors($list, $id, true, $maxgen, $showempty); + break; + case "descendants": + $list[$id]->generation = 1; + add_descendancy($list, $id, false, $maxgen); + break; + case "all": + add_ancestors($list, $id, true, $maxgen, $showempty); + add_descendancy($list, $id, true, $maxgen); + break; + } + } + + switch ($sortby) { + case "NAME": + uasort($list, array("GedcomRecord", "Compare")); + break; + case "ID": + uasort($list, array("GedcomRecord", "CompareId")); + break; + case "BIRT:DATE": + uasort($list, array("PGVReportBase", "CompareBirthDate")); + break; + case "DEAT:DATE": + uasort($list, array("PGVReportBase", "CompareDeathDate")); + break; + case "generation": + $newarray = array(); + reset($list); + $genCounter = 1; + while (count($newarray) < count($list)) { + foreach ($list as $key => $value) { + $generation = $value->generation; + if ($generation == $genCounter) { + $newarray[$key]->generation=$generation; + } + } + $genCounter++; + } + $list = $newarray; + break; + default: + // unsorted + break; + } + array_push($repeatsStack, array($repeats, $repeatBytes)); + $repeatBytes = xml_get_current_line_number($parser)+1; +} + +/** +* XML </ PGVRRelatives> end elemnt handler +* +* @see PGVRRelativesSHandler() +*/ +function PGVRRelativesEHandler() { + global $list, $repeats, $repeatsStack, $repeatBytes, $parser, $parserStack, $report, $gedrec, $processRepeats, $list_total, $list_private, $generation; + + $processRepeats--; + if ($processRepeats>0) { + return; + } + + // Check if there is any relatives + if (count($list) > 0) { + + // @deprecated +// $line = xml_get_current_line_number($parser)-1; + $lineoffset = 0; + foreach($repeatsStack as $rep) { + $lineoffset += $rep[1]; + } + //-- read the xml from the file + $lines = file($report); + while((strpos($lines[$lineoffset + $repeatBytes], "<PGVRRelatives")===false) && (($lineoffset + $repeatBytes) > 0)) { + $lineoffset--; + } + $lineoffset++; + $reportxml = "<tempdoc>\n"; + $line_nr = $lineoffset + $repeatBytes; + // Relatives Level counter + $count = 1; + while(0 < $count) { + if (strpos($lines[$line_nr], "<PGVRRelatives")!==false) { + $count++; + } elseif (strpos($lines[$line_nr], "</PGVRRelatives")!==false) { + $count--; + } + if (0 < $count) { + $reportxml .= $lines[$line_nr]; + } + $line_nr++; + } + // No need to drag this + unset($lines); + $reportxml .= "</tempdoc>\n"; + // Save original values + array_push($parserStack, $parser); + $oldgedrec = $gedrec; + + $list_total = count($list); + $list_private = 0; + foreach($list as $key => $value) { + if (isset($value->generation)) { + $generation = $value->generation; + } + if (strpos($key, "empty")===0) { + continue; // key can be something like "empty7" + } + $tmp=GedcomRecord::getInstance($key); + $gedrec = $tmp->getGedcomRecord(); + //-- start the sax parser + $repeat_parser = xml_parser_create(); + $parser = $repeat_parser; + //-- make sure everything is case sensitive + xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); + //-- set the main element handler functions + xml_set_element_handler($repeat_parser, "startElement", "endElement"); + //-- set the character data handler + xml_set_character_data_handler($repeat_parser, "characterData"); + + if (!xml_parse($repeat_parser, $reportxml, true)) { + printf($reportxml."\nPGVRRelativesEHandler XML error: %s at line %d", xml_error_string(xml_get_error_code($repeat_parser)), xml_get_current_line_number($repeat_parser)); + print_r($repeatsStack); + debug_print_backtrace(); + exit; + } + xml_parser_free($repeat_parser); + } + // Clean up the GLOBAL list array + unset($list); + $parser = array_pop($parserStack); + $gedrec = $oldgedrec; + } + $temp = array_pop($repeatsStack); + $repeats = $temp[0]; + $repeatBytes = $temp[1]; +} + +/** +* XML <PGVRGeneration /> elemnt handler +* +* Prints the number of generations +* @todo no info on wiki +* @see PGVRElement::addText() +*/ +function PGVRGenerationSHandler() { + global $generation, $currentElement; + + if (empty($generation)) $generation = 1; + + $currentElement->addText($generation); +} + +/** +* XML <PGVRNewPage /> elemnt handler +* +* Has to be placed in an element (header, pageheader, body or footer) +* @final +* @todo update wiki, this element is missing +*/ +function PGVRNewPageSHandler() { + global $pgvreport; + + $temp = "addpage"; + $pgvreport->addElement($temp); +} + +/** +* @todo add info +* @todo not on wiki +* @param array $attrs an array of key value pairs for the attributes +* @param string $tag HTML tag name +* @see HTMLEHandler() +* @see PGVReportBase::createHTML() +*/ +function HTMLSHandler($tag, $attrs) { + global $printData, $printDataStack, $pgvreportStack, $pgvreport, $currentElement, $PGVReportRoot; + + if ($tag=="tempdoc") return; + array_push($pgvreportStack, $pgvreport); + $pgvreport = $PGVReportRoot->createHTML($tag, $attrs); + $currentElement = $pgvreport; + + array_push($printDataStack, $printData); + $printData = true; +} + +/** +* @todo add info +* @param array $attrs an array of key value pairs for the attributes +* @see HTMLSHandler() +*/ +function HTMLEHandler($tag) { + global $printData, $printDataStack, $pgvreport, $currentElement, $pgvreportStack; + if ($tag=="tempdoc") return; + + $printData = array_pop($printDataStack); + $currentElement = $pgvreport; + $pgvreport = array_pop($pgvreportStack); + if (!is_null($pgvreport)) $pgvreport->addElement($currentElement); + else $pgvreport = $currentElement; +} + +/** +* XML <PGVRTitleSHandler> start elemnt handler +* +* @todo add to wiki +* @see PGVRTitleEHandler() +* @final +*/ +function PGVRTitleSHandler() { + global $reportTitle; + $reportTitle = true; +} + +/** +* XML </PGVRTitleEHandler> end elemnt handler +* +* @see PGVRTitleSHandler() +* @final +*/ +function PGVRTitleEHandler() { + global $reportTitle; + $reportTitle = false; +} + +/** +* XML <PGVRDescriptionSHandler> start elemnt handler +* +* @todo add to wiki +* @see PGVRDescriptionEHandler() +* @final +*/ +function PGVRDescriptionSHandler() { + global $reportDescription; + $reportDescription = true; +} + +/** +* XML </PGVRDescriptionEHandler> end elemnt handler +* +* @see PGVRDescriptionSHandler() +* @final +*/ +function PGVRDescriptionEHandler() { + global $reportDescription; + $reportDescription = false; +} +?> |
