origami 2.0.4 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,36 +0,0 @@
1
- =begin
2
-
3
- This file is part of PDF Walker, a graphical PDF file browser
4
- Copyright (C) 2016 Guillaume Delugré.
5
-
6
- PDF Walker is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- PDF Walker is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU General Public License for more details.
15
-
16
- You should have received a copy of the GNU General Public License
17
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- =end
20
-
21
- module PDFWalker
22
-
23
- class Walker < Window
24
-
25
- def about
26
- AboutDialog.show(self,
27
- name: "PDF Walker",
28
- program_name: "PDF Walker",
29
- version: Origami::VERSION,
30
- copyright: "Copyright (C) 2016\nGuillaume Delugré",
31
- comments: "A graphical PDF parser front-end",
32
- license: File.read(File.join(__dir__, "COPYING"))
33
- )
34
- end
35
- end
36
- end
@@ -1,120 +0,0 @@
1
- =begin
2
-
3
- This file is part of PDF Walker, a graphical PDF file browser
4
- Copyright (C) 2016 Guillaume Delugré.
5
-
6
- PDF Walker is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- PDF Walker is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU General Public License for more details.
15
-
16
- You should have received a copy of the GNU General Public License
17
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- =end
20
-
21
- require 'origami'
22
- require 'yaml'
23
-
24
- module PDFWalker
25
-
26
- class Walker < Window
27
-
28
- class Config
29
- DEFAULT_CONFIG_FILE = "#{File.expand_path("~")}/.pdfwalker.conf.yml"
30
- DEFAULT_CONFIG =
31
- {
32
- "Debug" =>
33
- {
34
- "Profiling" => false,
35
- "ProfilingOutputDir" => "prof",
36
- "Verbosity" => Origami::Parser::VERBOSE_TRACE,
37
- "IgnoreFileHeader" => true
38
- },
39
-
40
- "UI" =>
41
- {
42
- "LastOpenedDocuments" => []
43
- }
44
- }
45
- NLOG_RECENT_FILES = 5
46
-
47
- def initialize(configfile = DEFAULT_CONFIG_FILE)
48
- begin
49
- @conf = YAML.load(File.open(configfile))
50
- rescue
51
- @conf = DEFAULT_CONFIG
52
- ensure
53
- @filename = configfile
54
- set_missing_values
55
- end
56
- end
57
-
58
- def last_opened_file(filepath)
59
- @conf["UI"]['LastOpenedDocuments'].push(filepath).uniq!
60
- @conf["UI"]['LastOpenedDocuments'].delete_at(0) while @conf["UI"]['LastOpenedDocuments'].size > NLOG_RECENT_FILES
61
-
62
- save
63
- end
64
-
65
- def recent_files(n = NLOG_RECENT_FILES)
66
- @conf["UI"]['LastOpenedDocuments'].last(n).reverse
67
- end
68
-
69
- def set_profiling(bool)
70
- @conf["Debug"]['Profiling'] = bool
71
- save
72
- end
73
-
74
- def profile?
75
- @conf["Debug"]['Profiling']
76
- end
77
-
78
- def profile_output_dir
79
- @conf["Debug"]['ProfilingOutputDir']
80
- end
81
-
82
- def set_ignore_header(bool)
83
- @conf["Debug"]['IgnoreFileHeader'] = bool
84
- save
85
- end
86
-
87
- def ignore_header?
88
- @conf["Debug"]['IgnoreFileHeader']
89
- end
90
-
91
- def set_verbosity(level)
92
- @conf["Debug"]['Verbosity'] = level
93
- save
94
- end
95
-
96
- def verbosity
97
- @conf["Debug"]['Verbosity']
98
- end
99
-
100
- def save
101
- File.open(@filename, "w").write(@conf.to_yaml)
102
- end
103
-
104
- private
105
-
106
- def set_missing_values
107
- @conf ||= {}
108
-
109
- DEFAULT_CONFIG.each_key do |cat|
110
- @conf[cat] = {} unless @conf.include?(cat)
111
-
112
- DEFAULT_CONFIG[cat].each_pair do |key, value|
113
- @conf[cat][key] = value unless @conf[cat].include?(key)
114
- end
115
- end
116
- end
117
- end
118
-
119
- end
120
- end
@@ -1,314 +0,0 @@
1
- =begin
2
-
3
- This file is part of PDF Walker, a graphical PDF file browser
4
- Copyright (C) 2016 Guillaume Delugré.
5
-
6
- PDF Walker is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- PDF Walker is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU General Public License for more details.
15
-
16
- You should have received a copy of the GNU General Public License
17
- along with PDF Walker. If not, see <http://www.gnu.org/licenses/>.
18
-
19
- =end
20
-
21
- require 'origami'
22
-
23
- module PDFWalker
24
-
25
- class Walker < Window
26
- attr_reader :opened
27
- attr_reader :explore_history
28
-
29
- def close
30
- @opened = nil
31
- @filename = ''
32
- @explorer_history.clear
33
-
34
- @treeview.clear
35
- @objectview.clear
36
- @hexview.clear
37
-
38
- # disable all menus.
39
- [
40
- @file_menu_close, @file_menu_saveas, @file_menu_refresh,
41
- @document_menu_search,
42
- @document_menu_gotocatalog, @document_menu_gotodocinfo, @document_menu_gotometadata,
43
- @document_menu_gotopage, @document_menu_gotofield, @document_menu_gotorev, @document_menu_gotoobj,
44
- @document_menu_properties, @document_menu_sign, @document_menu_ur
45
- ].each do |menu|
46
- menu.sensitive = false
47
- end
48
-
49
- @statusbar.pop(@main_context)
50
-
51
- GC.start
52
- end
53
-
54
- def open(filename = nil)
55
- dialog = Gtk::FileChooserDialog.new("Open PDF File",
56
- self,
57
- FileChooser::ACTION_OPEN,
58
- nil,
59
- [Stock::CANCEL, Dialog::RESPONSE_CANCEL],
60
- [Stock::OPEN, Dialog::RESPONSE_ACCEPT])
61
-
62
- last_file = @config.recent_files.first
63
- unless last_file.nil?
64
- last_folder = File.dirname(last_file)
65
- dialog.set_current_folder(last_folder) if File.directory?(last_folder)
66
- end
67
-
68
- dialog.filter = FileFilter.new.add_pattern("*.acrodata").add_pattern("*.pdf").add_pattern("*.fdf")
69
-
70
- if filename.nil? and dialog.run != Gtk::Dialog::RESPONSE_ACCEPT
71
- dialog.destroy
72
- return
73
- end
74
-
75
- create_progressbar
76
-
77
- filename ||= dialog.filename
78
- dialog.destroy
79
-
80
- begin
81
- document = start_profiling do
82
- parse_file(filename)
83
- end
84
-
85
- set_active_document(filename, document)
86
-
87
- rescue
88
- error("Error while parsing file.\n#{$!} (#{$!.class})\n" + $!.backtrace.join("\n"))
89
- ensure
90
- close_progressbar
91
- self.activate_focus
92
- end
93
- end
94
-
95
- def save_data(caption, data, filename = "")
96
- dialog = Gtk::FileChooserDialog.new(caption,
97
- self,
98
- Gtk::FileChooser::ACTION_SAVE,
99
- nil,
100
- [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
101
- [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
102
- )
103
-
104
- dialog.do_overwrite_confirmation = true
105
- dialog.current_name = File.basename(filename)
106
- dialog.filter = FileFilter.new.add_pattern("*.*")
107
-
108
- if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
109
- begin
110
- File.binwrite(dialog.filename, data)
111
- rescue
112
- error("Error: #{$!.message}")
113
- end
114
- end
115
-
116
- dialog.destroy
117
- end
118
-
119
- def save
120
- dialog = Gtk::FileChooserDialog.new("Save PDF file",
121
- self,
122
- Gtk::FileChooser::ACTION_SAVE,
123
- nil,
124
- [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
125
- [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
126
- )
127
-
128
- dialog.filter = FileFilter.new.add_pattern("*.acrodata").add_pattern("*.pdf").add_pattern("*.fdf")
129
-
130
- folder = File.dirname(@filename)
131
- dialog.set_current_folder(folder)
132
-
133
- if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
134
- begin
135
- @opened.save(dialog.filename)
136
- rescue
137
- error("#{$!.class}: #{$!.message}\n#{$!.backtrace.join($/)}")
138
- end
139
- end
140
-
141
- dialog.destroy
142
- end
143
-
144
- private
145
-
146
- def set_active_document(filename, document)
147
- close if @opened
148
- @opened = document
149
- @filename = filename
150
-
151
- @config.last_opened_file(filename)
152
- @config.save
153
- update_recent_menu
154
-
155
- @last_search_result = []
156
- @last_search =
157
- {
158
- :expr => "",
159
- :regexp => false,
160
- :type => :body
161
- }
162
-
163
- self.reload
164
-
165
- # Enable basic file menus.
166
- [
167
- @file_menu_close, @file_menu_refresh,
168
- ].each do |menu|
169
- menu.sensitive = true
170
- end
171
-
172
- @explorer_history.clear
173
-
174
- @statusbar.push(@main_context, "Viewing #{filename}")
175
-
176
- setup_pdf_interface if @opened.is_a?(Origami::PDF)
177
- end
178
-
179
- def setup_pdf_interface
180
- # Enable save and document menu.
181
- [
182
- @file_menu_saveas,
183
- @document_menu_search,
184
- @document_menu_gotocatalog, @document_menu_gotopage, @document_menu_gotorev, @document_menu_gotoobj,
185
- @document_menu_properties, @document_menu_sign, @document_menu_ur
186
- ].each do |menu|
187
- menu.sensitive = true
188
- end
189
-
190
- @document_menu_gotodocinfo.sensitive = true if @opened.document_info?
191
- @document_menu_gotometadata.sensitive = true if @opened.metadata?
192
- @document_menu_gotofield.sensitive = true if @opened.form?
193
-
194
- setup_page_menu
195
- setup_field_menu
196
- setup_revision_menu
197
-
198
- goto_catalog
199
- end
200
-
201
- def setup_page_menu
202
- page_menu = Menu.new
203
- @document_menu_gotopage.remove_submenu
204
- @opened.each_page.with_index(1) do |page, index|
205
- page_menu.append(item = MenuItem.new(index.to_s).show)
206
- item.signal_connect("activate") { @treeview.goto(page) }
207
- end
208
- @document_menu_gotopage.set_submenu(page_menu)
209
- end
210
-
211
- def setup_field_menu
212
- field_menu = Menu.new
213
- @document_menu_gotofield.remove_submenu
214
- @opened.each_field do |field|
215
- field_name = field.T || "<unnamed field>"
216
- field_menu.append(item = MenuItem.new(field_name).show)
217
- item.signal_connect("activate") { @treeview.goto(field) }
218
- end
219
- @document_menu_gotofield.set_submenu(field_menu)
220
- end
221
-
222
- def setup_revision_menu
223
- rev_menu = Menu.new
224
- @document_menu_gotorev.remove_submenu
225
- @opened.revisions.each.with_index(1) do |rev, index|
226
- rev_menu.append(item = MenuItem.new(index.to_s).show)
227
- item.signal_connect("activate") { @treeview.goto(rev) }
228
- end
229
- @document_menu_gotorev.set_submenu(rev_menu)
230
- end
231
-
232
- def parse_file(path)
233
- #
234
- # Try to detect the file type of the document.
235
- # Fallback to PDF if none is found.
236
- #
237
- file_type = detect_file_type(path)
238
- if file_type.nil?
239
- file_type = Origami::PDF
240
- force_mode = true
241
- else
242
- force_mode = false
243
- end
244
-
245
- file_type.read(path,
246
- verbosity: Origami::Parser::VERBOSE_TRACE,
247
- ignore_errors: false,
248
- callback: method(:update_progressbar),
249
- prompt_password: method(:prompt_password),
250
- force: force_mode
251
- )
252
- end
253
-
254
- def update_progressbar(_obj)
255
- @progressbar.pulse if @progressbar
256
- Gtk.main_iteration while Gtk.events_pending?
257
- end
258
-
259
- def prompt_password
260
- passwd = ""
261
-
262
- dialog = Gtk::Dialog.new(
263
- "This document is encrypted",
264
- nil,
265
- Gtk::Dialog::MODAL,
266
- [ Gtk::Stock::OK, Gtk::Dialog::RESPONSE_OK ],
267
- [ Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL ]
268
- )
269
-
270
- dialog.set_default_response(Gtk::Dialog::RESPONSE_OK)
271
-
272
- label = Gtk::Label.new("Please enter password:")
273
- entry = Gtk::Entry.new
274
- entry.signal_connect('activate') {
275
- dialog.response(Gtk::Dialog::RESPONSE_OK)
276
- }
277
-
278
- dialog.vbox.add(label)
279
- dialog.vbox.add(entry)
280
- dialog.show_all
281
-
282
- dialog.run do |response|
283
- passwd = entry.text if response == Gtk::Dialog::RESPONSE_OK
284
- end
285
-
286
- dialog.destroy
287
- passwd
288
- end
289
-
290
- def detect_file_type(path)
291
- supported_types = [ Origami::PDF, Origami::FDF, Origami::PPKLite ]
292
-
293
- File.open(path, 'rb') do |file|
294
- data = file.read(128)
295
-
296
- supported_types.each do |type|
297
- return type if data.match(type::Header::MAGIC)
298
- end
299
- end
300
-
301
- nil
302
- end
303
-
304
- def create_progressbar
305
- @progresswin = Dialog.new("Parsing file...", self, Dialog::MODAL)
306
- @progresswin.vbox.add(@progressbar = ProgressBar.new.set_pulse_step(0.05))
307
- @progresswin.show_all
308
- end
309
-
310
- def close_progressbar
311
- @progresswin.close
312
- end
313
- end
314
- end