class PDFWalker::PDFTree
Constants
- BGCOL
- FGCOL
- LOADCOL
- OBJCOL
- STYLECOL
- TEXTCOL
- WEIGHTCOL
Attributes
parent[R]
Public Class Methods
new(parent)
click to toggle source
Calls superclass method
# File lib/pdfwalker/treeview.rb, line 58 def initialize(parent) @parent = parent reset_appearance @treestore = TreeStore.new(Object::Object, String, Pango::Weight, Pango::Style, String, String, Integer) super(@treestore) signal_connect('cursor-changed') { iter = selection.selected if iter obj = @treestore.get_value(iter, OBJCOL) parent.hexview.load(obj) parent.objectview.load(obj) end } signal_connect('row-activated') { |_tree, path,_column| if selection.selected obj = @treestore.get_value(selection.selected, OBJCOL) if row_expanded?(path) collapse_row(path) else expand_row(path, false) end goto(obj) if obj.is_a?(Origami::Reference) end } signal_connect('row-expanded') { |_tree, iter, _path| obj = @treestore.get_value(iter, OBJCOL) if obj.is_a?(Origami::Stream) and iter.n_children == 1 # Processing with an XRef or Object Stream if obj.is_a?(Origami::ObjectStream) obj.each { |embeddedobj| load_object(iter, embeddedobj) } elsif obj.is_a?(Origami::XRefStream) obj.each { |xref| load_xrefstm(iter, xref) } end end for i in 0...iter.n_children subiter = iter.nth_child(i) subobj = @treestore.get_value(subiter, OBJCOL) load_sub_objects(subiter, subobj) end } add_events(Gdk::Event::BUTTON_PRESS_MASK) signal_connect('button_press_event') { |_widget, event| if event.button == 3 && parent.opened path = get_path(event.x,event.y).first set_cursor(path, nil, false) obj = @treestore.get_value(@treestore.get_iter(path), OBJCOL) popup_menu(obj, event, path) end } end
Public Instance Methods
clear()
click to toggle source
# File lib/pdfwalker/treeview.rb, line 128 def clear @treestore.clear end
goto(obj, follow_references: true)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 132 def goto(obj, follow_references: true) if obj.is_a?(TreePath) set_cursor(obj, nil, false) else if obj.is_a?(Origami::Name) and obj.parent.is_a?(Origami::Dictionary) and obj.parent.has_key?(obj) obj = obj.parent[obj] elsif obj.is_a?(Origami::Reference) and follow_references obj = begin obj.solve rescue Origami::InvalidReferenceError @parent.error("Object not found : #{obj}") return end end _, path = object_to_tree_pos(obj) if path.nil? @parent.error("Object not found : #{obj.type}") return end expand_to_path(path) unless row_expanded?(path) @parent.explorer_history << cursor.first if cursor.first set_cursor(path, nil, false) end end
highlight(obj, color)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 160 def highlight(obj, color) if obj.is_a?(Origami::Name) and obj.parent.is_a?(Origami::Dictionary) and obj.parent.has_key?(obj) obj = obj.parent[obj] end iter, path = object_to_tree_pos(obj) if iter.nil? or path.nil? @parent.error("Object not found : #{obj.type}") return end @treestore.set_value(iter, BGCOL, color) expand_to_path(path) unless row_expanded?(path) end
load(pdf)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 175 def load(pdf) return unless pdf self.clear begin # # Create root entry # root = @treestore.append(nil) @treestore.set_value(root, OBJCOL, pdf) set_node(root, :Filename, @parent.filename) # # Create header entry # header = @treestore.append(root) @treestore.set_value(header, OBJCOL, pdf.header) set_node(header, :Header, "Header (version #{pdf.header.major_version}.#{pdf.header.minor_version})") no = 1 pdf.revisions.each { |revision| load_revision(root, no, revision) no = no + 1 } set_model(@treestore) ensure expand(@treestore.iter_first, 3) set_cursor(@treestore.iter_first.path, nil, false) end end
object_by_path(path)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 212 def object_by_path(path) iter = @treestore.get_iter(path) @treestore.get_value(iter, OBJCOL) end
Private Instance Methods
expand(row, depth)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 253 def expand(row, depth) if row and depth != 0 loop do expand_row(row.path, false) expand(row.first_child, depth - 1) break if not row.next! end end end
get_object_appearance(type)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 402 def get_object_appearance(type) @@appearance[type] end
load_body(rev, body)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 275 def load_body(rev, body) bodyroot = @treestore.append(rev) @treestore.set_value(bodyroot, OBJCOL, body) set_node(bodyroot, :Body, "Body") body.sort_by{|obj| obj.file_offset.to_i }.each { |object| begin load_object(bodyroot, object) rescue msg = "#{$!.class}: #{$!.message}\n#{$!.backtrace.join($/)}" STDERR.puts(msg) #@parent.error(msg) next end } end
load_object(container, object, depth = 1, name = nil)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 294 def load_object(container, object, depth = 1, name = nil) iter = @treestore.append(container) @treestore.set_value(iter, OBJCOL, object) type = object.native_type.to_s.split('::').last.to_sym if name.nil? name = case object when Origami::String '"' + object.to_utf8.tr("\x00", ".") + '"' when Origami::Number, Origami::Name object.value.to_s else object.type.to_s end end set_node(iter, type, name) return unless depth > 0 load_sub_objects(iter, object, depth) end
load_revision(root, no, revision)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 264 def load_revision(root, no, revision) revroot = @treestore.append(root) @treestore.set_value(revroot, OBJCOL, revision) set_node(revroot, :Revision, "Revision #{no}") load_body(revroot, revision.body.values) load_xrefs(revroot, revision.xreftable) load_trailer(revroot, revision.trailer) end
load_sub_objects(container, object, depth = 1)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 318 def load_sub_objects(container, object, depth = 1) return unless depth > 0 and @treestore.get_value(container, LOADCOL) != 1 case object when Origami::Array object.each do |subobject| load_object(container, subobject, depth - 1) end when Origami::Dictionary object.each_key do |subkey| load_object(container, object[subkey.value], depth - 1, subkey.value.to_s) end when Origami::Stream load_object(container, object.dictionary, depth - 1, "Stream Dictionary") end @treestore.set_value(container, LOADCOL, 1) end
load_trailer(rev, trailer)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 373 def load_trailer(rev, trailer) trailer_root = @treestore.append(rev) @treestore.set_value(trailer_root, OBJCOL, trailer) set_node(trailer_root, :Trailer, "Trailer") load_object(trailer_root, trailer.dictionary) unless trailer.dictionary.nil? end
load_xrefs(rev, table)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 350 def load_xrefs(rev, table) return unless table section = @treestore.append(rev) @treestore.set_value(section, OBJCOL, table) set_node(section, :XRefSection, "XRef section") table.each_subsection { |subtable| subsection = @treestore.append(section) @treestore.set_value(subsection, OBJCOL, subtable) set_node(subsection, :XRefSubSection, "#{subtable.range.begin} #{subtable.range.end - subtable.range.begin + 1}") subtable.each { |entry| xref = @treestore.append(subsection) @treestore.set_value(xref, OBJCOL, entry) set_node(xref, :XRef, entry.to_s.chomp) } } end
load_xrefstm(stm, embxref)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 339 def load_xrefstm(stm, embxref) xref = @treestore.append(stm) @treestore.set_value(xref, OBJCOL, embxref) if embxref.is_a?(Origami::XRef) set_node(xref, :XRef, embxref.to_s.chomp) else set_node(xref, :XRef, "xref to ObjectStream #{embxref.objstmno}, object index #{embxref.index}") end end
object_to_tree_pos(obj)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 220 def object_to_tree_pos(obj) # Locate the indirect object. root_obj = obj object_path = [ root_obj ] while root_obj.parent root_obj = root_obj.parent object_path.push(root_obj) end @treestore.each do |_model, path, iter| current_obj = @treestore.get_value(iter, OBJCOL) # Load the intermediate nodes if necessary. if object_path.any?{|object| object.equal?(current_obj)} load_sub_objects(iter, current_obj) end # Unfold the object stream if it's in the object path. if obj.is_a?(Origami::Object) and current_obj.is_a?(Origami::ObjectStream) and root_obj.equal?(current_obj) and iter.n_children == 1 current_obj.each { |embeddedobj| load_object(iter, embeddedobj) } end return [ iter, path ] if obj.equal?(current_obj) end nil end
reset_appearance()
click to toggle source
# File lib/pdfwalker/treeview.rb, line 381 def reset_appearance @@appearance[:Filename] = {Weight: :bold, Style: :normal} @@appearance[:Header] = {Color: "darkgreen", Weight: :bold, Style: :normal} @@appearance[:Revision] = {Color: "blue", Weight: :bold, Style: :normal} @@appearance[:Body] = {Color: "purple", Weight: :bold, Style: :normal} @@appearance[:XRefSection] = {Color: "purple", Weight: :bold, Style: :normal} @@appearance[:XRefSubSection] = {Color: "brown", Weight: :bold, Style: :normal} @@appearance[:XRef] = {Weight: :bold, Style: :normal} @@appearance[:Trailer] = {Color: "purple", Weight: :bold, Style: :normal} @@appearance[:StartXref] = {Weight: :bold, Style: :normal} @@appearance[:String] = {Color: "red", Weight: :normal, Style: :italic} @@appearance[:Name] = {Color: "gray", Weight: :normal, Style: :italic} @@appearance[:Number] = {Color: "orange", Weight: :normal, Style: :normal} @@appearance[:Dictionary] = {Color: "brown", Weight: :bold, Style: :normal} @@appearance[:Stream] = {Color: "darkcyan", Weight: :bold, Style: :normal} @@appearance[:StreamData] = {Color: "darkcyan", Weight: :normal, Style: :oblique} @@appearance[:Array] = {Color: "darkgreen", Weight: :bold, Style: :normal} @@appearance[:Reference] = {Weight: :normal, Style: :oblique} @@appearance[:Boolean] = {Color: "deeppink", Weight: :normal, Style: :normal} end
set_node(node, type, text)
click to toggle source
# File lib/pdfwalker/treeview.rb, line 406 def set_node(node, type, text) @treestore.set_value(node, TEXTCOL, text) app = get_object_appearance(type) @treestore.set_value(node, WEIGHTCOL, app[:Weight]) @treestore.set_value(node, STYLECOL, app[:Style]) @treestore.set_value(node, FGCOL, app[:Color]) end