Class: HexaPDF::Type::OutlineItem
- Inherits:
-
Dictionary
- Object
- Object
- Dictionary
- HexaPDF::Type::OutlineItem
- Extended by:
- Utils::BitField
- Defined in:
- lib/hexapdf/type/outline_item.rb
Overview
Represents an outline item dictionary.
An item has a title and some optional attributes: the action that is activated when clicking (either a simple destination or an explicit action object), the text color, and flags (whether the text should appear bold and/or italic).
Additionally, items may have child items which makes it possible to create a hierarchy of items.
If no destination/action is set, the item just acts as kind of a header. It usually only makes sense to do this when the item has children.
Outline item dictionaries are connected together in the form of a linked list using the /Next and /Prev keys. Each item may have descendant items. If so, the /First and /Last keys point to respectively the first and last descendant items.
Since many dictionary keys need to be kept up-to-date when manipulating the outline item tree, it is not recommended to manually do this but to rely on the provided convenience methods.
See: PDF2.0 s12.3.3
Constant Summary
Constants included from DictionaryFields
DictionaryFields::Boolean, DictionaryFields::PDFByteString, DictionaryFields::PDFDate
Instance Attribute Summary
Attributes inherited from Object
#data, #document, #must_be_indirect
Instance Method Summary collapse
-
#action(value = nil) ⇒ Object
:call-seq: item.action -> action item.action(value) -> action.
-
#add_item(title, destination: nil, action: nil, position: :last, open: true, text_color: nil, flags: nil) {|item| ... } ⇒ Object
Adds, as child to this item, a new outline item with the given title that performs the provided action on clicking.
-
#destination(value = nil) ⇒ Object
:call-seq: item.destination -> destination item.destination(value) -> destination.
-
#destination_page ⇒ Object
Returns the destination page if there is any.
-
#each_item(&block) ⇒ Object
:call-seq: item.each_item {|descendant_item, level| block } -> item item.each_item -> Enumerator.
-
#flags ⇒ Object
:method: unflag :call-seq: flag(*flags).
-
#level ⇒ Object
Returns the outline level this item is one.
-
#must_be_indirect? ⇒ Boolean
Returns
true
since outline items must always be indirect objects. -
#open? ⇒ Boolean
Returns the open state of the item.
-
#text_color(color = nil) ⇒ Object
:call-seq: item.text_color -> color item.text_color(color) -> color.
-
#title(value = nil) ⇒ Object
:call-seq: item.title -> title item.title(value) -> title.
Methods included from Utils::BitField
Methods inherited from Dictionary
#[], #[]=, define_field, define_type, #delete, #each, each_field, #empty?, field, #key?, #to_hash, type, #type
Methods inherited from Object
#<=>, #==, #cache, #cached?, #clear_cache, deep_copy, #deep_copy, #document?, #eql?, field, #gen, #gen=, #hash, #indirect?, #initialize, #inspect, make_direct, #null?, #oid, #oid=, #type, #validate, #value, #value=
Constructor Details
This class inherits a constructor from HexaPDF::Object
Instance Method Details
#action(value = nil) ⇒ Object
:call-seq:
item.action -> action
item.action(value) -> action
Returns the item’s action if no argument is given. Otherwise sets the action to the given value (needs to be a valid HexaPDF::Type::Action dictionary).
If an action is set, the destination has to be unset; and vice versa. So when setting an action value, the destination is automatically deleted.
197 198 199 200 201 202 203 204 |
# File 'lib/hexapdf/type/outline_item.rb', line 197 def action(value = nil) if value delete(:Dest) self[:A] = value else self[:A] end end |
#add_item(title, destination: nil, action: nil, position: :last, open: true, text_color: nil, flags: nil) {|item| ... } ⇒ Object
Adds, as child to this item, a new outline item with the given title that performs the provided action on clicking. Returns the newly added item.
Alternatively, it is possible to provide an already initialized outline item instead of the title. If so, the only other argument that is used is position
. Existing fields /Prev, /Next, /First, /Last, /Parent and /Count are deleted from the given item and set appropriately.
If neither :destination nor :action is specified, the outline item has no associated action. This is only meaningful if the new item will have children as it then acts just as a container.
If a block is specified, the newly created item is yielded.
- destination
-
Specifies the destination that should be activated when clicking on the outline item. See HexaPDF::Document::Destinations#use_or_create for details. The argument :action takes precedence if it is also specified,
- action
-
Specifies the action that should be taken when clicking on the outline item. See HexaPDF::Type::Action for details. If the argument :destination is also specified, the :action argument takes precedence.
- position
-
The position where the new child item should be inserted. Can either be:
:first
-
Insert as first item
:last
-
Insert as last item (default)
- Integer
-
When non-negative inserts before, otherwise after, the item at the given zero-based index.
- open
-
Specifies whether the outline item should be open (i.e. one or more children are shown) or closed. Default:
true
. - text_color
-
The text color of the outline item text which needs to be a valid RGB color (see #text_color for details). If not set, the text appears in black.
- flags
-
An array of font variants (possible values are :bold and :italic) to set for the outline item text, see #flags for detail. Default is to use no variant.
Examples:
doc.destinations.add("Title") do |item| # no action, just container
item.add("Second subitem", destination: doc.pages[1]) # links to page 2
item.add("First subitem", position: :first, destination: doc.pages[0])
end
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 |
# File 'lib/hexapdf/type/outline_item.rb', line 303 def add_item(title, destination: nil, action: nil, position: :last, open: true, text_color: nil, flags: nil) # :yield: item if title.kind_of?(HexaPDF::Object) && title.type == :XXOutlineItem item = title item.delete(:Prev) item.delete(:Next) item.delete(:First) item.delete(:Last) if item[:Count] && item[:Count] >= 0 item[:Count] = 0 else item.delete(:Count) end item[:Parent] = self else item = document.add({Parent: self}, type: :XXOutlineItem) item.title(title) if action item.action(action) else item.destination(destination) end item.text_color(text_color) if text_color item.flag(*flags) if flags item[:Count] = 0 if open # Count=0 means open if items are later added end unless position == :last || position == :first || position.kind_of?(Integer) raise ArgumentError, "position must be :first, :last, or an integer" end if self[:First] case position when :last, -1 item[:Prev] = self[:Last] self[:Last][:Next] = item self[:Last] = item when :first, 0 item[:Next] = self[:First] self[:First][:Prev] = item self[:First] = item when Integer temp, direction = if position > 0 [self[:First], :Next] else position = -position - 2 [self[:Last], :Prev] end position.times { temp &&= temp[direction] } raise ArgumentError, "position out of bounds" if temp.nil? item[:Prev] = temp[:Prev] item[:Next] = temp temp[:Prev] = item item[:Prev][:Next] = item end else self[:First] = self[:Last] = item end # Re-calculate /Count entries temp = self while temp if !temp.key?(:Count) || temp[:Count] < 0 temp[:Count] = (temp[:Count] || 0) - 1 break else temp[:Count] += 1 end temp = temp[:Parent] end yield(item) if block_given? item end |
#destination(value = nil) ⇒ Object
:call-seq:
item.destination -> destination
item.destination(value) -> destination
Returns the item’s destination if no argument is given. Otherwise sets the destination to the given value (see HexaPDF::Document::Destinations#use_or_create for the posssible values).
If an action is set, the destination has to be unset; and vice versa. So when setting a destination value, the action is automatically deleted.
179 180 181 182 183 184 185 186 |
# File 'lib/hexapdf/type/outline_item.rb', line 179 def destination(value = nil) if value delete(:A) self[:Dest] = document.destinations.use_or_create(value) else self[:Dest] end end |
#destination_page ⇒ Object
Returns the destination page if there is any.
-
If a destination is set, the associated page is returned.
-
If an action is set and it is a GoTo action, the associated page is returned.
-
Otherwise
nil
is returned.
241 242 243 244 245 |
# File 'lib/hexapdf/type/outline_item.rb', line 241 def destination_page dest = self[:Dest] dest = action[:D] if !dest && (action = self[:A]) && action[:S] == :GoTo document.destinations.resolve(dest)&.page end |
#each_item(&block) ⇒ Object
:call-seq:
item.each_item {|descendant_item, level| block } -> item
item.each_item -> Enumerator
Iterates over all descendant items of this one.
The descendant items are yielded in-order, yielding first the item itself and then its descendants.
386 387 388 389 390 391 392 393 394 395 396 397 398 |
# File 'lib/hexapdf/type/outline_item.rb', line 386 def each_item(&block) return to_enum(__method__) unless block_given? return self unless (item = self[:First]) level = self.level + 1 while item yield(item, level) item.each_item(&block) item = item[:Next] end self end |
#flags ⇒ Object
:method: unflag :call-seq:
flag(*flags)
Clears the given flags from /F, given as flag names or bit indices.
See #flags for the list of available flags.
125 126 127 |
# File 'lib/hexapdf/type/outline_item.rb', line 125 bit_field(:flags, {italic: 0, bold: 1}, lister: "flags", getter: "flagged?", setter: "flag", unsetter: "unflag", value_getter: "self[:F]", value_setter: "self[:F]") |
#level ⇒ Object
Returns the outline level this item is one.
The level of the items in the main outline dictionary, the root level, is 1.
Here is an illustrated example of items contained in a document outline with their associated level:
Outline dictionary 0
Outline item 1 1
|- Sub item 1 2
|- Sub item 2 2
|- Sub sub item 1 3
|- Sub item 3 2
Outline item 2 1
220 221 222 223 224 225 |
# File 'lib/hexapdf/type/outline_item.rb', line 220 def level count = 0 temp = self count += 1 while (temp = temp[:Parent]) count end |
#must_be_indirect? ⇒ Boolean
Returns true
since outline items must always be indirect objects.
130 131 132 |
# File 'lib/hexapdf/type/outline_item.rb', line 130 def must_be_indirect? true end |
#open? ⇒ Boolean
Returns the open state of the item.
true
-
If this item is open, i.e. showing its child items.
false
-
If this item is closed, i.e. not showing its child items.
nil
-
If this item doesn’t (yet) have any child items.
232 233 234 |
# File 'lib/hexapdf/type/outline_item.rb', line 232 def open? self[:First] && key?(:Count) && self[:Count] >= 0 end |
#text_color(color = nil) ⇒ Object
:call-seq:
item.text_color -> color
item.text_color(color) -> color
Returns the item’s text color as HexaPDF::Content::ColorSpace::DeviceRGB::Color object if no argument is given. Otherwise sets the text color, see HexaPDF::Content::ColorSpace.device_color_from_specification for possible color
values.
Note: The color has to be an RGB color.
157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/hexapdf/type/outline_item.rb', line 157 def text_color(color = nil) if color color = HexaPDF::Content::ColorSpace.device_color_from_specification(color) unless color.color_space.family == :DeviceRGB raise ArgumentError, "The given argument is not a valid RGB color" end self[:C] = color.components else Content::ColorSpace.prenormalized_device_color(self[:C]) end end |
#title(value = nil) ⇒ Object
:call-seq:
item.title -> title
item.title(value) -> title
Returns the item’s title if no argument is given. Otherwise sets the title to the given value.
140 141 142 143 144 145 146 |
# File 'lib/hexapdf/type/outline_item.rb', line 140 def title(value = nil) if value self[:Title] = value else self[:Title] end end |