PageRenderTime 29ms CodeModel.GetById 15ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/zend/Zend/Pdf/Outline/Loaded.php

http://zoop.googlecode.com/
PHP | 462 lines | 260 code | 56 blank | 146 comment | 58 complexity | a4fb4524eefd992e5a7461eef3e38af2 MD5 | raw file
  1<?php
  2/**
  3 * Zend Framework
  4 *
  5 * LICENSE
  6 *
  7 * This source file is subject to the new BSD license that is bundled
  8 * with this package in the file LICENSE.txt.
  9 * It is also available through the world-wide-web at this URL:
 10 * http://framework.zend.com/license/new-bsd
 11 * If you did not receive a copy of the license and are unable to
 12 * obtain it through the world-wide-web, please send an email
 13 * to license@zend.com so we can send you a copy immediately.
 14 *
 15 * @category   Zend
 16 * @package    Zend_Pdf
 17 * @subpackage Actions
 18 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 19 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 20 * @version    $Id: Loaded.php 20096 2010-01-06 02:05:09Z bkarwin $
 21 */
 22
 23
 24/** Internally used classes */
 25require_once 'Zend/Pdf/Element.php';
 26require_once 'Zend/Pdf/Element/Array.php';
 27require_once 'Zend/Pdf/Element/Numeric.php';
 28require_once 'Zend/Pdf/Element/String.php';
 29
 30
 31/** Zend_Pdf_Outline */
 32require_once 'Zend/Pdf/Outline.php';
 33
 34/**
 35 * Traceable PDF outline representation class
 36 *
 37 * Instances of this class trace object update uperations. That allows to avoid outlines PDF tree update
 38 * which should be performed at each document update otherwise.
 39 *
 40 * @package    Zend_Pdf
 41 * @subpackage Outlines
 42 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
 43 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 44 */
 45class Zend_Pdf_Outline_Loaded extends Zend_Pdf_Outline
 46{
 47    /**
 48     * Outline dictionary object
 49     *
 50     * @var Zend_Pdf_Element_Dictionary|Zend_Pdf_Element_Object|Zend_Pdf_Element_Reference
 51     */
 52    protected $_outlineDictionary;
 53
 54    /**
 55     * original array of child outlines
 56     *
 57     * @var array
 58     */
 59    protected $_originalChildOutlines = array();
 60
 61    /**
 62     * Get outline title.
 63     *
 64     * @return string
 65     * @throws Zend_Pdf_Exception
 66     */
 67    public function getTitle()
 68    {
 69        if ($this->_outlineDictionary->Title === null) {
 70            require_once 'Zend/Pdf/Exception.php';
 71            throw new Zend_Pdf_Exception('Outline dictionary Title entry is required.');
 72        }
 73        return $this->_outlineDictionary->Title->value;
 74    }
 75
 76    /**
 77     * Set outline title
 78     *
 79     * @param string $title
 80     * @return Zend_Pdf_Outline
 81     */
 82    public function setTitle($title)
 83    {
 84        $this->_outlineDictionary->Title->touch();
 85        $this->_outlineDictionary->Title = new Zend_Pdf_Element_String($title);
 86        return $this;
 87    }
 88
 89    /**
 90     * Sets 'isOpen' outline flag
 91     *
 92     * @param boolean $isOpen
 93     * @return Zend_Pdf_Outline
 94     */
 95    public function setIsOpen($isOpen)
 96    {
 97        parent::setIsOpen($isOpen);
 98
 99        if ($this->_outlineDictionary->Count === null) {
100            // Do Nothing.
101            return this;
102        }
103
104        $childrenCount = $this->_outlineDictionary->Count->value;
105        $isOpenCurrentState = ($childrenCount > 0);
106        if ($isOpen != $isOpenCurrentState) {
107            $this->_outlineDictionary->Count->touch();
108            $this->_outlineDictionary->Count->value = ($isOpen? 1 : -1)*abs($childrenCount);
109        }
110
111        return $this;
112    }
113
114    /**
115     * Returns true if outline item is displayed in italic
116     *
117     * @return boolean
118     */
119    public function isItalic()
120    {
121        if ($this->_outlineDictionary->F === null) {
122            return false;
123        }
124        return $this->_outlineDictionary->F->value & 1;
125    }
126
127    /**
128     * Sets 'isItalic' outline flag
129     *
130     * @param boolean $isItalic
131     * @return Zend_Pdf_Outline
132     */
133    public function setIsItalic($isItalic)
134    {
135        if ($this->_outlineDictionary->F === null) {
136            $this->_outlineDictionary->touch();
137            $this->_outlineDictionary->F = new Zend_Pdf_Element_Numeric($isItalic? 1 : 0);
138        } else {
139            $this->_outlineDictionary->F->touch();
140            if ($isItalic) {
141                $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | 1;
142            } else {
143                $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | ~1;
144            }
145        }
146        return $this;
147    }
148
149    /**
150     * Returns true if outline item is displayed in bold
151     *
152     * @return boolean
153     */
154    public function isBold()
155    {
156        if ($this->_outlineDictionary->F === null) {
157            return false;
158        }
159        return $this->_outlineDictionary->F->value & 2;
160    }
161
162    /**
163     * Sets 'isBold' outline flag
164     *
165     * @param boolean $isBold
166     * @return Zend_Pdf_Outline
167     */
168    public function setIsBold($isBold)
169    {
170        if ($this->_outlineDictionary->F === null) {
171            $this->_outlineDictionary->touch();
172            $this->_outlineDictionary->F = new Zend_Pdf_Element_Numeric($isBold? 2 : 0);
173        } else {
174            $this->_outlineDictionary->F->touch();
175            if ($isBold) {
176                $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | 2;
177            } else {
178                $this->_outlineDictionary->F->value = $this->_outlineDictionary->F->value | ~2;
179            }
180        }
181        return $this;
182    }
183
184
185    /**
186     * Get outline text color.
187     *
188     * @return Zend_Pdf_Color_Rgb
189     */
190    public function getColor()
191    {
192        if ($this->_outlineDictionary->C === null) {
193            return null;
194        }
195
196        $components = $this->_outlineDictionary->C->items;
197
198        require_once 'Zend/Pdf/Color/Rgb.php';
199        return new Zend_Pdf_Color_Rgb($components[0], $components[1], $components[2]);
200    }
201
202    /**
203     * Set outline text color.
204     * (null means default color which is black)
205     *
206     * @param Zend_Pdf_Color_Rgb $color
207     * @return Zend_Pdf_Outline
208     */
209    public function setColor(Zend_Pdf_Color_Rgb $color)
210    {
211        $this->_outlineDictionary->touch();
212
213        if ($color === null) {
214            $this->_outlineDictionary->C = null;
215        } else {
216            $components = $color->getComponents();
217            $colorComponentElements = array(new Zend_Pdf_Element_Numeric($components[0]),
218                                            new Zend_Pdf_Element_Numeric($components[1]),
219                                            new Zend_Pdf_Element_Numeric($components[2]));
220            $this->_outlineDictionary->C = new Zend_Pdf_Element_Array($colorComponentElements);
221        }
222
223        return $this;
224    }
225
226    /**
227     * Get outline target.
228     *
229     * @return Zend_Pdf_Target
230     * @throws Zend_Pdf_Exception
231     */
232    public function getTarget()
233    {
234        if ($this->_outlineDictionary->Dest !== null) {
235            if ($this->_outlineDictionary->A !== null) {
236                require_once 'Zend/Pdf/Exception.php';
237                throw new Zend_Pdf_Exception('Outline dictionary may contain Dest or A entry, but not both.');
238            }
239
240            require_once 'Zend/Pdf/Destination.php';
241            return Zend_Pdf_Destination::load($this->_outlineDictionary->Dest);
242        } else if ($this->_outlineDictionary->A !== null) {
243            require_once 'Zend/Pdf/Action.php';
244            return Zend_Pdf_Action::load($this->_outlineDictionary->A);
245        }
246
247        return null;
248    }
249
250    /**
251     * Set outline target.
252     * Null means no target
253     *
254     * @param Zend_Pdf_Target|string $target
255     * @return Zend_Pdf_Outline
256     * @throws Zend_Pdf_Exception
257     */
258    public function setTarget($target = null)
259    {
260        $this->_outlineDictionary->touch();
261
262        if (is_string($target)) {
263            require_once 'Zend/Pdf/Destination/Named.php';
264            $target = Zend_Pdf_Destination_Named::create($target);
265        }
266
267        if ($target === null) {
268            $this->_outlineDictionary->Dest = null;
269            $this->_outlineDictionary->A    = null;
270        } else if ($target instanceof Zend_Pdf_Destination) {
271            $this->_outlineDictionary->Dest = $target->getResource();
272            $this->_outlineDictionary->A    = null;
273        } else if ($target instanceof Zend_Pdf_Action) {
274            $this->_outlineDictionary->Dest = null;
275            $this->_outlineDictionary->A    = $target->getResource();
276        } else {
277            require_once 'Zend/Pdf/Exception.php';
278            throw new Zend_Pdf_Exception('Outline target has to be Zend_Pdf_Destination or Zend_Pdf_Action object or string');
279        }
280
281        return $this;
282    }
283
284    /**
285     * Set outline options
286     *
287     * @param array $options
288     * @return Zend_Pdf_Actions_Traceable
289     * @throws Zend_Pdf_Exception
290     */
291    public function setOptions(array $options)
292    {
293        parent::setOptions($options);
294
295        return $this;
296    }
297
298
299
300    /**
301     * Create PDF outline object using specified dictionary
302     *
303     * @internal
304     * @param Zend_Pdf_Element $dictionary (It's actually Dictionary or Dictionary Object or Reference to a Dictionary Object)
305     * @param Zend_Pdf_Action  $parentAction
306     * @param SplObjectStorage $processedOutlines  List of already processed Outline dictionaries,
307     *                                             used to avoid cyclic references
308     * @return Zend_Pdf_Action
309     * @throws Zend_Pdf_Exception
310     */
311    public function __construct(Zend_Pdf_Element $dictionary, SplObjectStorage $processedDictionaries = null)
312    {
313        if ($dictionary->getType() != Zend_Pdf_Element::TYPE_DICTIONARY) {
314            require_once 'Zend/Pdf/Exception.php';
315            throw new Zend_Pdf_Exception('$dictionary mast be an indirect dictionary object.');
316        }
317
318        if ($processedDictionaries === null) {
319            $processedDictionaries = new SplObjectStorage();
320        }
321        $processedDictionaries->attach($dictionary);
322
323        $this->_outlineDictionary = $dictionary;
324
325        if ($dictionary->Count !== null) {
326            if ($dictionary->Count->getType() != Zend_Pdf_Element::TYPE_NUMERIC) {
327                require_once 'Zend/Pdf/Exception.php';
328                throw new Zend_Pdf_Exception('Outline dictionary Count entry must be a numeric element.');
329            }
330
331            $childOutlinesCount = $dictionary->Count->value;
332            if ($childOutlinesCount > 0) {
333                $this->_open = true;
334            }
335            $childOutlinesCount = abs($childOutlinesCount);
336
337            $childDictionary = $dictionary->First;
338            for ($count = 0; $count < $childOutlinesCount; $count++) {
339                if ($childDictionary === null) {
340                    require_once 'Zend/Pdf/Exception.php';
341                    throw new Zend_Pdf_Exception('Outline childs load error.');
342                }
343
344                if (!$processedDictionaries->contains($childDictionary)) {
345                    $this->childOutlines[] = new Zend_Pdf_Outline_Loaded($childDictionary, $processedDictionaries);
346                }
347
348                $childDictionary = $childDictionary->Next;
349            }
350
351            if ($childDictionary !== null) {
352                require_once 'Zend/Pdf/Exception.php';
353                throw new Zend_Pdf_Exception('Outline childs load error.');
354            }
355
356            $this->_originalChildOutlines = $this->childOutlines;
357        }
358    }
359
360    /**
361     * Dump Outline and its child outlines into PDF structures
362     *
363     * Returns dictionary indirect object or reference
364     *
365     * @internal
366     * @param Zend_Pdf_ElementFactory    $factory object factory for newly created indirect objects
367     * @param boolean $updateNavigation  Update navigation flag
368     * @param Zend_Pdf_Element $parent   Parent outline dictionary reference
369     * @param Zend_Pdf_Element $prev     Previous outline dictionary reference
370     * @param SplObjectStorage $processedOutlines  List of already processed outlines
371     * @return Zend_Pdf_Element
372     * @throws Zend_Pdf_Exception
373     */
374    public function dumpOutline(Zend_Pdf_ElementFactory_Interface $factory,
375                                                                  $updateNavigation,
376                                                 Zend_Pdf_Element $parent,
377                                                 Zend_Pdf_Element $prev = null,
378                                                 SplObjectStorage $processedOutlines = null)
379    {
380        if ($processedOutlines === null) {
381            $processedOutlines = new SplObjectStorage();
382        }
383        $processedOutlines->attach($this);
384
385        if ($updateNavigation) {
386            $this->_outlineDictionary->touch();
387
388            $this->_outlineDictionary->Parent = $parent;
389            $this->_outlineDictionary->Prev   = $prev;
390            $this->_outlineDictionary->Next   = null;
391        }
392
393        $updateChildNavigation = false;
394        if (count($this->_originalChildOutlines) != count($this->childOutlines)) {
395            // If original and current children arrays have different size then children list was updated
396            $updateChildNavigation = true;
397        } else if ( !(array_keys($this->_originalChildOutlines) === array_keys($this->childOutlines)) ) {
398            // If original and current children arrays have different keys (with a glance to an order) then children list was updated
399            $updateChildNavigation = true;
400        } else {
401            foreach ($this->childOutlines as $key => $childOutline) {
402                if ($this->_originalChildOutlines[$key] !== $childOutline) {
403                    $updateChildNavigation = true;
404                    break;
405                }
406            }
407        }
408
409        $lastChild = null;
410        if ($updateChildNavigation) {
411            $this->_outlineDictionary->touch();
412            $this->_outlineDictionary->First = null;
413
414            foreach ($this->childOutlines as $childOutline) {
415                if ($processedOutlines->contains($childOutline)) {
416                    require_once 'Zend/Pdf/Exception.php';
417                    throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.');
418                }
419
420                if ($lastChild === null) {
421                    // First pass. Update Outlines dictionary First entry using corresponding value
422                    $lastChild = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, null, $processedOutlines);
423                    $this->_outlineDictionary->First = $lastChild;
424                } else {
425                    // Update previous outline dictionary Next entry (Prev is updated within dumpOutline() method)
426                    $childOutlineDictionary = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, $lastChild, $processedOutlines);
427                    $lastChild->Next = $childOutlineDictionary;
428                    $lastChild       = $childOutlineDictionary;
429                }
430            }
431
432            $this->_outlineDictionary->Last  = $lastChild;
433
434            if (count($this->childOutlines) != 0) {
435                $this->_outlineDictionary->Count = new Zend_Pdf_Element_Numeric(($this->isOpen()? 1 : -1)*count($this->childOutlines));
436            } else {
437                $this->_outlineDictionary->Count = null;
438            }
439        } else {
440            foreach ($this->childOutlines as $childOutline) {
441                if ($processedOutlines->contains($childOutline)) {
442                    require_once 'Zend/Pdf/Exception.php';
443                    throw new Zend_Pdf_Exception('Outlines cyclyc reference is detected.');
444                }
445                $lastChild = $childOutline->dumpOutline($factory, $updateChildNavigation, $this->_outlineDictionary, $lastChild, $processedOutlines);
446            }
447        }
448
449        return $this->_outlineDictionary;
450    }
451
452    public function dump($level = 0)
453    {
454        printf(":%3d:%s:%s:%s%s  :\n", count($this->childOutlines),$this->isItalic()? 'i':' ', $this->isBold()? 'b':' ', str_pad('', 4*$level), $this->getTitle());
455
456        if ($this->isOpen()  ||  true) {
457            foreach ($this->childOutlines as $child) {
458                $child->dump($level + 1);
459            }
460        }
461    }
462}