class PDFWalker::Walker

Attributes

explore_history[R]
opened[R]

Public Instance Methods

about() click to toggle source
# File lib/pdfwalker/about.rb, line 25
def about
    AboutDialog.show(self,
        name: "PDF Walker",
        program_name: "PDF Walker",
        version: "#{PDFWalker::VERSION}",
        copyright: "Copyright © 2017\nGuillaume Delugré",
        comments: "A PDF file explorer, based on Origami",
        license: File.read(File.join(__dir__, "../..", "COPYING")),
        wrap_license: true,
    )
end
close() click to toggle source
# File lib/pdfwalker/file.rb, line 29
def close
    @opened = nil
    @filename = ''
    @explorer_history.clear

    @treeview.clear
    @objectview.clear
    @hexview.clear

    # disable all menus.
    [
        @file_menu_close, @file_menu_saveas, @file_menu_refresh,
        @document_menu_search,
        @document_menu_gotocatalog, @document_menu_gotodocinfo, @document_menu_gotometadata,
        @document_menu_gotopage, @document_menu_gotofield, @document_menu_gotorev, @document_menu_gotoobj,
        @document_menu_properties, @document_menu_sign, @document_menu_ur
    ].each do |menu|
        menu.sensitive = false
    end

    @statusbar.pop(@main_context)

    GC.start
end
display_file_properties() click to toggle source
# File lib/pdfwalker/properties.rb, line 27
def display_file_properties
    Properties.new(self, @opened) if @opened
end
display_signing_wizard() click to toggle source
# File lib/pdfwalker/signing.rb, line 25
def display_signing_wizard
    SignWizard.new(self, @opened) if @opened
end
display_usage_rights_wizard() click to toggle source
# File lib/pdfwalker/signing.rb, line 29
def display_usage_rights_wizard
    UsageRightsWizard.new(self, @opened) if @opened
end
open(filename = nil) click to toggle source
# File lib/pdfwalker/file.rb, line 54
def open(filename = nil)
    dialog = Gtk::FileChooserDialog.new("Open PDF File",
                self,
                FileChooser::ACTION_OPEN,
                nil,
                [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
                [Stock::OPEN, Dialog::RESPONSE_ACCEPT])

    last_file = @config.recent_files.first
    unless last_file.nil?
        last_folder = File.dirname(last_file)
        dialog.set_current_folder(last_folder) if File.directory?(last_folder)
    end

    dialog.filter = FileFilter.new.add_pattern("*.acrodata").add_pattern("*.pdf").add_pattern("*.fdf")

    if filename.nil? and dialog.run != Gtk::Dialog::RESPONSE_ACCEPT
        dialog.destroy
        return
    end

    create_progressbar

    filename ||= dialog.filename
    dialog.destroy

    begin
        document = start_profiling do
            parse_file(filename)
        end

        set_active_document(filename, document)

    rescue
        error("Error while parsing file.\n#{$!} (#{$!.class})\n" + $!.backtrace.join("\n"))
    ensure
        close_progressbar
        self.activate_focus
    end
end
save() click to toggle source
# File lib/pdfwalker/file.rb, line 119
def save
    dialog = Gtk::FileChooserDialog.new("Save PDF file",
                self,
                Gtk::FileChooser::ACTION_SAVE,
                nil,
                [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
                [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
    )

    dialog.filter = FileFilter.new.add_pattern("*.acrodata").add_pattern("*.pdf").add_pattern("*.fdf")

    folder = File.dirname(@filename)
    dialog.set_current_folder(folder)

    if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
        begin
            @opened.save(dialog.filename)
        rescue
            error("#{$!.class}: #{$!.message}\n#{$!.backtrace.join($/)}")
        end
    end

    dialog.destroy
end
save_data(caption, data, filename = "") click to toggle source
# File lib/pdfwalker/file.rb, line 95
def save_data(caption, data, filename = "")
    dialog = Gtk::FileChooserDialog.new(caption,
                self,
                Gtk::FileChooser::ACTION_SAVE,
                nil,
                [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
                [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
    )

    dialog.do_overwrite_confirmation = true
    dialog.current_name = File.basename(filename)
    dialog.filter = FileFilter.new.add_pattern("*.*")

    if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
        begin
            File.binwrite(dialog.filename, data)
        rescue
            error("Error: #{$!.message}")
        end
    end

    dialog.destroy
end
show_xrefs(target) click to toggle source
# File lib/pdfwalker/xrefs.rb, line 24
def show_xrefs(target)
    XrefsDialog.new(self, target)
end

Private Instance Methods

close_progressbar() click to toggle source
# File lib/pdfwalker/file.rb, line 316
def close_progressbar
    @progresswin.close
end
create_document_menu() click to toggle source
# File lib/pdfwalker/menu.rb, line 316
def create_document_menu
    doc_ag = Gtk::AccelGroup.new
    @document_menu = Menu.new.set_accel_group(doc_ag)
    add_accel_group(doc_ag)

    entries = [
        @document_menu_search = ImageMenuItem.new(Stock::FIND).set_sensitive(false).set_accel_path("<PDF Walker>/Document/Search"),
        MenuItem.new,
        @document_menu_gotocatalog = MenuItem.new("Jump to Catalog").set_sensitive(false),
        @document_menu_gotodocinfo = MenuItem.new("Jump to Document Info").set_sensitive(false),
        @document_menu_gotometadata = MenuItem.new("Jump to Metadata").set_sensitive(false),
        @document_menu_gotorev = MenuItem.new("Jump to Revision...").set_sensitive(false),
        @document_menu_gotopage = MenuItem.new("Jump to Page...").set_sensitive(false),
        @document_menu_gotofield = MenuItem.new("Jump to Field...").set_sensitive(false),
        @document_menu_gotoobj = MenuItem.new("Jump to Object...").set_sensitive(false),
        MenuItem.new,
        @document_menu_sign = MenuItem.new("Sign the document").set_sensitive(false),
        @document_menu_ur = MenuItem.new("Enable Usage Rights").set_sensitive(false),
        @document_menu_properties = ImageMenuItem.new(Stock::PROPERTIES).set_sensitive(false),
    ]

    @document_menu_search.signal_connect('activate') { search }
    @document_menu_gotocatalog.signal_connect('activate') { goto_catalog }
    @document_menu_gotodocinfo.signal_connect('activate') { goto_docinfo }
    @document_menu_gotometadata.signal_connect('activate') { goto_metadata }
    @document_menu_gotoobj.signal_connect('activate') { goto_object }
    @document_menu_properties.signal_connect('activate') { display_file_properties }
    @document_menu_sign.signal_connect('activate') { display_signing_wizard }
    @document_menu_ur.signal_connect('activate') { display_usage_rights_wizard }

    entries.each do |entry|
        @document_menu.append(entry)
    end

    @menu.append(MenuItem.new('_Document').set_submenu(@document_menu))
end
create_file_menu() click to toggle source
# File lib/pdfwalker/menu.rb, line 287
def create_file_menu
    file_ag = Gtk::AccelGroup.new
    @file_menu = Menu.new.set_accel_group(file_ag).set_accel_path("<PDF Walker>/File")
    add_accel_group(file_ag)

    entries = [
        @file_menu_open = ImageMenuItem.new(Stock::OPEN).set_accel_path("<PDF Walker>/File/Open"),
        @file_menu_recent = MenuItem.new("Last opened"),
        @file_menu_refresh = ImageMenuItem.new(Stock::REFRESH).set_sensitive(false).set_accel_path("<PDF Walker>/File/Refresh"),
        @file_menu_close = ImageMenuItem.new(Stock::CLOSE).set_sensitive(false).set_accel_path("<PDF Walker>/File/Close"),
        @file_menu_saveas = ImageMenuItem.new(Stock::SAVE_AS).set_sensitive(false).set_accel_path("<PDF Walker>/File/Save"),
        @file_menu_exit = ImageMenuItem.new(Stock::QUIT).set_accel_path("<PDF Walker>/File/Quit"),
    ]

    @file_menu_open.signal_connect('activate') { open }
    @file_menu_refresh.signal_connect('activate') { open(@filename) }
    @file_menu_close.signal_connect('activate') { close }
    @file_menu_saveas.signal_connect('activate') { save }
    @file_menu_exit.signal_connect('activate') { self.destroy }

    update_recent_menu

    entries.each do |entry|
        @file_menu.append(entry)
    end

    @menu.append(MenuItem.new('_File').set_submenu(@file_menu))
end
create_help_menu() click to toggle source
# File lib/pdfwalker/menu.rb, line 353
def create_help_menu
    @help_menu = Menu.new

    @help_menu_profile = CheckMenuItem.new("Profiling (Debug purposes only)").set_active(@config.profile?)
    @help_menu_about = ImageMenuItem.new(Stock::ABOUT)

    @help_menu_profile.signal_connect('toggled') do @config.set_profiling(@help_menu_profile.active?) end
    @help_menu_about.signal_connect('activate') { about }

    @help_menu.append(@help_menu_profile)
    @help_menu.append(@help_menu_about)

    @menu.append(MenuItem.new('_Help').set_submenu(@help_menu))
end
create_hexview() click to toggle source
# File lib/pdfwalker/hexview.rb, line 28
def create_hexview
    @hexview = DumpView.new(self)
end
create_menus() click to toggle source
# File lib/pdfwalker/menu.rb, line 272
def create_menus
    AccelMap.add_entry("<PDF Walker>/File/Open", Gdk::Keyval::GDK_O, Gdk::Window::CONTROL_MASK)
    AccelMap.add_entry("<PDF Walker>/File/Refresh", Gdk::Keyval::GDK_R, Gdk::Window::CONTROL_MASK)
    AccelMap.add_entry("<PDF Walker>/File/Close", Gdk::Keyval::GDK_W, Gdk::Window::CONTROL_MASK)
    AccelMap.add_entry("<PDF Walker>/File/Save", Gdk::Keyval::GDK_S, Gdk::Window::CONTROL_MASK)
    AccelMap.add_entry("<PDF Walker>/File/Quit", Gdk::Keyval::GDK_Q, Gdk::Window::CONTROL_MASK)
    AccelMap.add_entry("<PDF Walker>/Document/Search", Gdk::Keyval::GDK_F, Gdk::Window::CONTROL_MASK)

    @menu = MenuBar.new

    create_file_menu 
    create_document_menu
    create_help_menu
end
create_objectview() click to toggle source
# File lib/pdfwalker/textview.rb, line 27
def create_objectview
    @objectview = ObjectView.new(self)
end
create_progressbar() click to toggle source
# File lib/pdfwalker/file.rb, line 310
def create_progressbar
    @progresswin = Dialog.new("Parsing file...", self, Dialog::MODAL)
    @progresswin.vbox.add(@progressbar = ProgressBar.new.set_pulse_step(0.05))
    @progresswin.show_all
end
create_treeview() click to toggle source
# File lib/pdfwalker/treeview.rb, line 27
def create_treeview
    @treeview = PDFTree.new(self).set_headers_visible(false)

    colcontent = Gtk::TreeViewColumn.new("Names",
        Gtk::CellRendererText.new.set_foreground_set(true).set_background_set(true),
            text: PDFTree::TEXTCOL,
            weight: PDFTree::WEIGHTCOL,
            style: PDFTree::STYLECOL,
            foreground: PDFTree::FGCOL,
            background: PDFTree::BGCOL
    )

    @treeview.append_column(colcontent)
end
detect_file_type(path) click to toggle source
# File lib/pdfwalker/file.rb, line 296
def detect_file_type(path)
    supported_types = [ Origami::PDF, Origami::FDF, Origami::PPKLite ]

    File.open(path, 'rb') do |file|
        data = file.read(128)

        supported_types.each do |type|
            return type if data.match(type::Header::MAGIC)
        end
    end

    nil
end
parse_file(path) click to toggle source
# File lib/pdfwalker/file.rb, line 238
def parse_file(path)
    #
    # Try to detect the file type of the document.
    # Fallback to PDF if none is found.
    #
    file_type = detect_file_type(path)
    if file_type.nil?
        file_type = Origami::PDF
        force_mode = true
    else
        force_mode = false
    end

    file_type.read(path,
        verbosity: Origami::Parser::VERBOSE_TRACE,
        ignore_errors: false,
        callback: method(:update_progressbar),
        prompt_password: method(:prompt_password),
        force: force_mode
    )
end
prompt_password() click to toggle source
# File lib/pdfwalker/file.rb, line 265
def prompt_password
    passwd = ""

    dialog = Gtk::Dialog.new(
                "This document is encrypted",
                nil,
                Gtk::Dialog::MODAL,
                [ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ],
                [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ]
    )

    dialog.set_default_response(Gtk::Dialog::RESPONSE_OK)

    label = Gtk::Label.new("Please enter password:")
    entry = Gtk::Entry.new
    entry.signal_connect('activate') {
        dialog.response(Gtk::Dialog::RESPONSE_OK)
    }

    dialog.vbox.add(label)
    dialog.vbox.add(entry)
    dialog.show_all

    dialog.run do |response|
        passwd = entry.text if response == Gtk::Dialog::RESPONSE_OK
    end

    dialog.destroy
    passwd
end
set_active_document(filename, document) click to toggle source
# File lib/pdfwalker/file.rb, line 146
def set_active_document(filename, document)
    close if @opened
    @opened = document
    @filename = filename

    @config.last_opened_file(filename)
    @config.save
    update_recent_menu

    @last_search_result = []
    @last_search =
    {
        :expr => "",
        :regexp => false,
        :type => :body
    }

    self.reload

    # Enable basic file menus.
    [
        @file_menu_close, @file_menu_refresh,
    ].each do |menu|
        menu.sensitive = true
    end

    @explorer_history.clear

    @statusbar.push(@main_context, "Viewing #{filename}")

    setup_pdf_interface if @opened.is_a?(Origami::PDF)
end
setup_field_menu() click to toggle source
# File lib/pdfwalker/file.rb, line 211
def setup_field_menu
    field_menu = Menu.new
    @document_menu_gotofield.remove_submenu
    @opened.each_field do |field|
        field_name =
            if field.T.is_a?(Origami::String)
                field.T.to_utf8
            else
                "<unnamed field>"
            end

        field_menu.append(item = MenuItem.new(field_name).show)
        item.signal_connect("activate") { @treeview.goto(field) }
    end
    @document_menu_gotofield.set_submenu(field_menu)
end
setup_page_menu() click to toggle source
# File lib/pdfwalker/file.rb, line 201
def setup_page_menu
    page_menu = Menu.new
    @document_menu_gotopage.remove_submenu
    @opened.each_page.with_index(1) do |page, index|
        page_menu.append(item = MenuItem.new(index.to_s).show)
        item.signal_connect("activate") { @treeview.goto(page) }
    end
    @document_menu_gotopage.set_submenu(page_menu)
end
setup_pdf_interface() click to toggle source
# File lib/pdfwalker/file.rb, line 179
def setup_pdf_interface
    # Enable save and document menu.
    [
        @file_menu_saveas,
        @document_menu_search,
        @document_menu_gotocatalog, @document_menu_gotopage, @document_menu_gotorev, @document_menu_gotoobj,
        @document_menu_properties, @document_menu_sign, @document_menu_ur
    ].each do |menu|
        menu.sensitive = true
    end

    @document_menu_gotodocinfo.sensitive = true if @opened.document_info?
    @document_menu_gotometadata.sensitive = true if @opened.metadata?
    @document_menu_gotofield.sensitive = true if @opened.form?

    setup_page_menu
    setup_field_menu
    setup_revision_menu

    goto_catalog
end
setup_revision_menu() click to toggle source
# File lib/pdfwalker/file.rb, line 228
def setup_revision_menu
    rev_menu = Menu.new
    @document_menu_gotorev.remove_submenu
    @opened.revisions.each.with_index(1) do |rev, index|
        rev_menu.append(item = MenuItem.new(index.to_s).show)
        item.signal_connect("activate") { @treeview.goto(rev) }
    end
    @document_menu_gotorev.set_submenu(rev_menu)
end
update_progressbar(_obj) click to toggle source
# File lib/pdfwalker/file.rb, line 260
def update_progressbar(_obj)
    @progressbar.pulse if @progressbar
    Gtk.main_iteration while Gtk.events_pending?
end
update_recent_menu() click to toggle source
# File lib/pdfwalker/menu.rb, line 368
def update_recent_menu
    @recent_menu = Menu.new
    @config.recent_files.each { |file|
        menu = MenuItem.new(file)
        menu.signal_connect('activate') do open(file) end

        @recent_menu.append(menu)
    }

    @file_menu_recent.set_submenu(@recent_menu)
    @file_menu_recent.show_all
end