Class: HexaPDF::Type::OutlineItem

Inherits:
Dictionary show all
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: PDF1.7 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

Methods included from Utils::BitField

bit_field

Methods inherited from Dictionary

#[], #[]=, define_field, define_type, #delete, #each, each_field, #empty?, field, #key?, #to_h, type, #type

Methods inherited from Object

#<=>, #==, #cache, #cached?, #clear_cache, deep_copy, #deep_copy, #document?, #eql?, #gen, #gen=, #hash, #indirect?, #initialize, #inspect, make_direct, #must_be_indirect?, #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.



192
193
194
195
196
197
198
199
# File 'lib/hexapdf/type/outline_item.rb', line 192

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.

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

Yields:

  • (item)


252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/hexapdf/type/outline_item.rb', line 252

def add_item(title, destination: nil, action: nil, position: :last, open: true,
             text_color: nil, flags: nil) # :yield: item
  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

  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.



174
175
176
177
178
179
180
181
# File 'lib/hexapdf/type/outline_item.rb', line 174

def destination(value = nil)
  if value
    delete(:A)
    self[:Dest] = document.destinations.use_or_create(value)
  else
    self[:Dest]
  end
end

#each_item(&block) ⇒ Object

:call-seq:

item.each_item {|descendant_item| block }   -> item
item.each_item                              -> Enumerator

Iterates over all descendant items of this one.

The items are yielded in-order, yielding first the item itself and then its descendants.



320
321
322
323
324
325
326
327
328
329
330
331
# File 'lib/hexapdf/type/outline_item.rb', line 320

def each_item(&block)
  return to_enum(__method__) unless block_given?

  item = self[:First]
  while item
    yield(item)
    item.each_item(&block)
    item = item[:Next]
  end

  self
end

#flagsObject

: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]")

#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.



152
153
154
155
156
157
158
159
160
161
162
# File 'lib/hexapdf/type/outline_item.rb', line 152

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.



135
136
137
138
139
140
141
# File 'lib/hexapdf/type/outline_item.rb', line 135

def title(value = nil)
  if value
    self[:Title] = value
  else
    self[:Title]
  end
end