origami 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. data/COPYING.LESSER +165 -0
  2. data/README +77 -0
  3. data/VERSION +1 -0
  4. data/bin/config/pdfcop.conf.yml +237 -0
  5. data/bin/gui/about.rb +46 -0
  6. data/bin/gui/config.rb +132 -0
  7. data/bin/gui/file.rb +385 -0
  8. data/bin/gui/hexdump.rb +74 -0
  9. data/bin/gui/hexview.rb +91 -0
  10. data/bin/gui/imgview.rb +72 -0
  11. data/bin/gui/menu.rb +392 -0
  12. data/bin/gui/properties.rb +132 -0
  13. data/bin/gui/signing.rb +635 -0
  14. data/bin/gui/textview.rb +107 -0
  15. data/bin/gui/treeview.rb +409 -0
  16. data/bin/gui/walker.rb +282 -0
  17. data/bin/gui/xrefs.rb +79 -0
  18. data/bin/pdf2graph +121 -0
  19. data/bin/pdf2ruby +353 -0
  20. data/bin/pdfcocoon +104 -0
  21. data/bin/pdfcop +455 -0
  22. data/bin/pdfdecompress +104 -0
  23. data/bin/pdfdecrypt +95 -0
  24. data/bin/pdfencrypt +112 -0
  25. data/bin/pdfextract +221 -0
  26. data/bin/pdfmetadata +123 -0
  27. data/bin/pdfsh +13 -0
  28. data/bin/pdfwalker +7 -0
  29. data/bin/shell/.irbrc +104 -0
  30. data/bin/shell/console.rb +136 -0
  31. data/bin/shell/hexdump.rb +83 -0
  32. data/origami.rb +36 -0
  33. data/origami/3d.rb +239 -0
  34. data/origami/acroform.rb +321 -0
  35. data/origami/actions.rb +299 -0
  36. data/origami/adobe/fdf.rb +259 -0
  37. data/origami/adobe/ppklite.rb +489 -0
  38. data/origami/annotations.rb +775 -0
  39. data/origami/array.rb +187 -0
  40. data/origami/boolean.rb +101 -0
  41. data/origami/catalog.rb +486 -0
  42. data/origami/destinations.rb +213 -0
  43. data/origami/dictionary.rb +188 -0
  44. data/origami/docmdp.rb +96 -0
  45. data/origami/encryption.rb +1293 -0
  46. data/origami/export.rb +283 -0
  47. data/origami/file.rb +222 -0
  48. data/origami/filters.rb +250 -0
  49. data/origami/filters/ascii.rb +189 -0
  50. data/origami/filters/ccitt.rb +515 -0
  51. data/origami/filters/crypt.rb +47 -0
  52. data/origami/filters/dct.rb +61 -0
  53. data/origami/filters/flate.rb +112 -0
  54. data/origami/filters/jbig2.rb +63 -0
  55. data/origami/filters/jpx.rb +53 -0
  56. data/origami/filters/lzw.rb +195 -0
  57. data/origami/filters/predictors.rb +276 -0
  58. data/origami/filters/runlength.rb +117 -0
  59. data/origami/font.rb +209 -0
  60. data/origami/functions.rb +93 -0
  61. data/origami/graphics.rb +33 -0
  62. data/origami/graphics/colors.rb +191 -0
  63. data/origami/graphics/instruction.rb +126 -0
  64. data/origami/graphics/path.rb +154 -0
  65. data/origami/graphics/patterns.rb +180 -0
  66. data/origami/graphics/state.rb +164 -0
  67. data/origami/graphics/text.rb +224 -0
  68. data/origami/graphics/xobject.rb +493 -0
  69. data/origami/header.rb +90 -0
  70. data/origami/linearization.rb +318 -0
  71. data/origami/metadata.rb +114 -0
  72. data/origami/name.rb +170 -0
  73. data/origami/null.rb +75 -0
  74. data/origami/numeric.rb +188 -0
  75. data/origami/obfuscation.rb +233 -0
  76. data/origami/object.rb +527 -0
  77. data/origami/outline.rb +59 -0
  78. data/origami/page.rb +559 -0
  79. data/origami/parser.rb +268 -0
  80. data/origami/parsers/fdf.rb +45 -0
  81. data/origami/parsers/pdf.rb +27 -0
  82. data/origami/parsers/pdf/linear.rb +113 -0
  83. data/origami/parsers/ppklite.rb +86 -0
  84. data/origami/pdf.rb +1144 -0
  85. data/origami/reference.rb +113 -0
  86. data/origami/signature.rb +474 -0
  87. data/origami/stream.rb +575 -0
  88. data/origami/string.rb +416 -0
  89. data/origami/trailer.rb +173 -0
  90. data/origami/webcapture.rb +87 -0
  91. data/origami/xfa.rb +3027 -0
  92. data/origami/xreftable.rb +447 -0
  93. data/templates/patterns.rb +66 -0
  94. data/templates/widgets.rb +173 -0
  95. data/templates/xdp.rb +92 -0
  96. data/tests/dataset/test.dummycrt +28 -0
  97. data/tests/dataset/test.dummykey +27 -0
  98. data/tests/tc_actions.rb +32 -0
  99. data/tests/tc_annotations.rb +85 -0
  100. data/tests/tc_pages.rb +37 -0
  101. data/tests/tc_pdfattach.rb +24 -0
  102. data/tests/tc_pdfencrypt.rb +110 -0
  103. data/tests/tc_pdfnew.rb +32 -0
  104. data/tests/tc_pdfparse.rb +98 -0
  105. data/tests/tc_pdfsig.rb +37 -0
  106. data/tests/tc_streams.rb +129 -0
  107. data/tests/ts_pdf.rb +45 -0
  108. metadata +193 -0
@@ -0,0 +1,74 @@
1
+ =begin
2
+
3
+ = File
4
+ hexdump.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ class String #:nodoc:
27
+
28
+ def hexdump(bytesperline = 16, upcase = true, offsets = true)
29
+
30
+ dump = ""
31
+ counter = 0
32
+
33
+ while counter < length
34
+
35
+ offset = sprintf("%010u", counter)
36
+
37
+ linelen = (counter < length - bytesperline) ? bytesperline : (length - counter)
38
+ bytes = ""
39
+ linelen.times do |i|
40
+
41
+ byte = self[counter + i].ord.to_s(16)
42
+ if byte.size < 2 then byte.insert(0, "0") end
43
+ bytes << byte
44
+ bytes << " " unless i == bytesperline - 1
45
+
46
+ end
47
+
48
+ ascii = self[counter, linelen].ascii_print
49
+
50
+ if upcase
51
+ offset.upcase!
52
+ bytes.upcase!
53
+ end
54
+
55
+ dump << "#{offset if offsets} #{bytes.to_s.ljust(bytesperline * 3 - 1)} #{ascii}\n"
56
+
57
+ counter += bytesperline
58
+
59
+ end
60
+
61
+ dump
62
+ end
63
+
64
+ def ascii_print
65
+
66
+ printable = ""
67
+ self.each_byte do |c|
68
+ if c >= ' '[0].ord && c <= '~'[0].ord then printable << c else printable << '.' end
69
+ end
70
+
71
+ printable
72
+ end
73
+
74
+ end
@@ -0,0 +1,91 @@
1
+ =begin
2
+
3
+ = File
4
+ hexview.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugré <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ require 'gui/hexdump'
27
+
28
+ module PDFWalker
29
+
30
+ class Walker < Window
31
+
32
+ private
33
+
34
+ def create_hexview
35
+ @hexview = DumpView.new(self)
36
+ end
37
+
38
+ class DumpView < ScrolledWindow
39
+
40
+ def initialize(parent)
41
+ @parent = parent
42
+ super()
43
+
44
+ set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
45
+
46
+ @current_obj = nil
47
+ @valuebuffer = TextBuffer.new
48
+ @valueview = TextView.new(@valuebuffer).set_editable(false).set_cursor_visible(false).set_left_margin(5).set_right_margin(5)
49
+
50
+ @valuebuffer.create_tag( "HexView",
51
+ :weight => Pango::WEIGHT_BOLD,
52
+ :foreground => "black",
53
+ :family => "Courier",
54
+ :scale => Pango::AttrScale::LARGE
55
+ )
56
+
57
+ add_with_viewport @valueview
58
+ end
59
+
60
+ def clear
61
+ @valuebuffer.set_text("")
62
+ end
63
+
64
+ def load(object)
65
+ return if @current_obj.equal?(object)
66
+
67
+ begin
68
+ self.clear
69
+
70
+ case object
71
+ when Origami::Stream
72
+ @valuebuffer.set_text(object.data.to_s.hexdump)
73
+ when Origami::HexaString
74
+ @valuebuffer.set_text(object.value.to_s.hexdump)
75
+ when Origami::ByteString
76
+ @valuebuffer.set_text(object.to_utf8)
77
+ end
78
+
79
+ @valuebuffer.apply_tag("HexView", @valuebuffer.start_iter, @valuebuffer.end_iter)
80
+ @current_obj = object
81
+
82
+ rescue Exception => e
83
+ @parent.error("An error occured while loading this object.\n#{e} (#{e.class})")
84
+ end
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,72 @@
1
+ =begin
2
+
3
+ = File
4
+ imgview.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ module PDFWalker
27
+
28
+ class ImgViewer < Window
29
+ attr_reader :image
30
+
31
+ def initialize
32
+ super()
33
+
34
+ set_title "Image view"
35
+ set_decorated false
36
+ set_resizable false
37
+
38
+ add_events(Gdk::Event::KEY_RELEASE_MASK)
39
+ signal_connect('key_release_event') { |w, event|
40
+ destroy if event.keyval == Gdk::Keyval::GDK_Escape
41
+ }
42
+ end
43
+
44
+ def show_raw_img(data, w, h, bpp, bpr)
45
+ set_default_size w,h
46
+
47
+ pixbuf = Gdk::Pixbuf.new data,
48
+ Gdk::Pixbuf::ColorSpace::RGB, false, bpp,
49
+ w, h,
50
+ bpr
51
+
52
+ @image = Gtk::Image.new(pixbuf)
53
+ add @image
54
+
55
+ show_all
56
+ end
57
+
58
+ def show_compressed_img(data)
59
+ loader = Gdk::PixbufLoader.new
60
+ loader.last_write data
61
+
62
+ pixbuf = loader.pixbuf
63
+ set_default_size pixbuf.width, pixbuf.height
64
+
65
+ @image = Gtk::Image.new(pixbuf)
66
+ add @image
67
+
68
+ show_all
69
+ end
70
+ end
71
+
72
+ end
@@ -0,0 +1,392 @@
1
+ =begin
2
+
3
+ = File
4
+ menu.rb
5
+
6
+ = Info
7
+ This file is part of Origami, PDF manipulation framework for Ruby
8
+ Copyright (C) 2010 Guillaume Delugr� <guillaume@security-labs.org>
9
+ All right reserved.
10
+
11
+ Origami is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU Lesser General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ Origami is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU Lesser General Public License for more details.
20
+
21
+ You should have received a copy of the GNU Lesser General Public License
22
+ along with Origami. If not, see <http://www.gnu.org/licenses/>.
23
+
24
+ =end
25
+
26
+ module PDFWalker
27
+
28
+ module Popable
29
+
30
+ @@menus = Hash.new([])
31
+ @@menus[:"PDF File"] =
32
+ [
33
+ {
34
+ :Name => Stock::SAVE_AS,
35
+ :Sensitive => true,
36
+ :Callback => lambda { |widget, viewer, path|
37
+ viewer.parent.save
38
+ }
39
+ },
40
+ {
41
+ :Name => "Serialize",
42
+ :Sensitive => true,
43
+ :Callback => lambda { |widget, viewer, path|
44
+ viewer.parent.serialize
45
+ }
46
+ },
47
+ {
48
+ :Name => :"---"
49
+ },
50
+ {
51
+ :Name => Stock::PROPERTIES,
52
+ :Sensitive => true,
53
+ :Callback => lambda { |widget, viewer, path|
54
+ viewer.parent.display_file_properties
55
+ }
56
+ },
57
+ {
58
+ :Name => :"---"
59
+ },
60
+ {
61
+ :Name => Stock::CLOSE,
62
+ :Sensitive => true,
63
+ :Callback => lambda { |widget, viewer, path|
64
+ viewer.parent.close
65
+ }
66
+ }
67
+ ]
68
+
69
+ @@menus[:Reference] =
70
+ [
71
+ {
72
+ :Name => Stock::JUMP_TO,
73
+ :Sensitive => true,
74
+ :Callback => lambda { |widget, viewer, path|
75
+ viewer.row_activated(path, viewer.get_column(viewer.class::TEXTCOL))
76
+ }
77
+ }
78
+ ]
79
+
80
+ @@menus[:Revision] =
81
+ [
82
+ {
83
+ :Name => "Save to this revision",
84
+ :Sensitive => true,
85
+ :Callback => lambda { |widget, viewer, path|
86
+ revstr = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::TEXTCOL)
87
+ revstr.slice!(0, "Revision ".size)
88
+
89
+ revnum = revstr.to_i
90
+
91
+ dialog = Gtk::FileChooserDialog.new("Save PDF File",
92
+ viewer.parent,
93
+ Gtk::FileChooser::ACTION_SAVE,
94
+ nil,
95
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
96
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT]
97
+ )
98
+
99
+ dialog.filter = FileFilter.new.add_pattern("*.pdf")
100
+
101
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
102
+ viewer.parent.opened.save_upto(revnum, dialog.filename)
103
+ end
104
+
105
+ dialog.destroy
106
+ }
107
+ }
108
+ ]
109
+
110
+ @@menus[:Stream] =
111
+ [
112
+ {
113
+ :Name => "Dump encoded stream",
114
+ :Sensitive => true,
115
+ :Callback => lambda { |widget, viewer, path|
116
+ stream = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL)
117
+
118
+ viewer.parent.save_data("Save stream to file", stream.rawdata)
119
+ }
120
+ },
121
+ {
122
+ :Name => "Dump decoded stream",
123
+ :Sensitive => true,
124
+ :Callback => lambda { |widget, viewer, path|
125
+ stream = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL)
126
+
127
+ viewer.parent.save_data("Save stream to file", stream.data)
128
+ }
129
+ }
130
+ ]
131
+
132
+ @@menus[:String] =
133
+ [
134
+ {
135
+ :Name => "Dump string",
136
+ :Sensitive => true,
137
+ :Callback => lambda { |widget, viewer, path|
138
+ string = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL)
139
+
140
+ viewer.parent.save_data("Save string to file", string.value)
141
+ }
142
+ }
143
+ ]
144
+
145
+ @@menus[:Image] = @@menus[:Stream] +
146
+ [
147
+ {
148
+ :Name => :"---"
149
+ },
150
+ {
151
+ :Name => "View image",
152
+ :Sensitive => true,
153
+ :Callback => lambda { |widget, viewer, path|
154
+ stm = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL)
155
+ w,h = stm[:Width], stm[:Height]
156
+ bpp = stm[:BitsPerComponent] || 8
157
+ bpr = (bpp >> 3) * 3 * w
158
+ data = stm.data
159
+
160
+ begin
161
+ imgview = ImgViewer.new
162
+ if stm[:Filter] == :DCTDecode or (stm[:Filter].is_a?(Array) and stm[:Filter][0] == :DCTDecode)
163
+ imgview.show_compressed_img data
164
+ else
165
+ imgview.show_raw_img data, w, h, bpp, bpr
166
+ end
167
+ rescue Exception => e
168
+ viewer.parent.error("#{e.class}: #{e.message}")
169
+ end
170
+ }
171
+ }
172
+ ]
173
+
174
+ def popup_menu(obj, event, path)
175
+
176
+ menu = Menu.new
177
+
178
+ type = if obj.is_a?(Origami::Object)
179
+ if obj.is_a?(Graphics::ImageXObject)
180
+ :Image
181
+ else
182
+ obj.real_type.to_s.split("::").last.to_sym
183
+ end
184
+ else case obj
185
+ when Origami::PDF
186
+ :"PDF File"
187
+ when Origami::PDF::Revision, Origami::Adobe::PPKLite::Revision
188
+ :Revision
189
+ when ::Array
190
+ :Body
191
+ when Origami::PDF::Header, Origami::Adobe::PPKLite::Header
192
+ :Header
193
+ when Origami::Trailer
194
+ :Trailer
195
+ when Origami::XRef::Section
196
+ :XRefSection
197
+ when Origami::XRef::Subsection
198
+ :XRefSubsection
199
+ when Origami::XRef, Origami::XRefToCompressedObj
200
+ :XRef
201
+ else
202
+ :Unknown
203
+ end
204
+ end
205
+
206
+ title = obj.is_a?(Origami::Object) ? "Object : " : ""
207
+ title << type.to_s
208
+ menu.append(MenuItem.new(title).set_sensitive(false).modify_text(Gtk::STATE_INSENSITIVE, Gdk::Color.new(255,0,255)))
209
+
210
+ if obj.is_a?(Origami::Object)
211
+ if obj.is_indirect?
212
+ menu.append(MenuItem.new("Number : #{obj.no}; Generation : #{obj.generation}").set_sensitive(false))
213
+ menu.append(MenuItem.new("File offset : #{obj.file_offset}").set_sensitive(false))
214
+ xrefsproc = lambda { |widget,viewer,path|
215
+ ref = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL)
216
+ viewer.parent.show_xrefs(ref)
217
+ }
218
+ getxrefs = MenuItem.new("Search references to this object").set_sensitive(true)
219
+ getxrefs.signal_connect("activate", self, path, &xrefsproc)
220
+
221
+ menu.append(getxrefs)
222
+ elsif not obj.parent.nil?
223
+ gotoproc = lambda { |widget,viewer,path|
224
+ dest = viewer.model.get_value(viewer.model.get_iter(path), viewer.class::OBJCOL).parent
225
+ viewer.goto(dest)
226
+ }
227
+ gotoparent = MenuItem.new("Goto Parent Object").set_sensitive(true)
228
+ gotoparent.signal_connect("activate", self, path, &gotoproc)
229
+
230
+ menu.append(gotoparent)
231
+ end
232
+ end
233
+
234
+ items = @@menus[type]
235
+ menu.append(SeparatorMenuItem.new) if not items.empty?
236
+
237
+ items.each { |item|
238
+
239
+ if item[:Name] == :"---"
240
+ entry = SeparatorMenuItem.new
241
+ else
242
+ if item[:Name].is_a?(String)
243
+ entry = MenuItem.new(item[:Name])
244
+ else entry = ImageMenuItem.new(item[:Name])
245
+ end
246
+
247
+ entry.set_sensitive(item[:Sensitive])
248
+ entry.signal_connect("activate", self, path, &item[:Callback])
249
+ end
250
+
251
+ menu.append(entry)
252
+ }
253
+
254
+ menu.show_all
255
+ menu.popup(nil, nil, event.button, event.time)
256
+
257
+ end
258
+
259
+ end
260
+
261
+ class Walker < Window
262
+
263
+ private
264
+
265
+ def create_menus
266
+
267
+ AccelMap.add_entry("<PDF Walker>/File/Open", Gdk::Keyval::GDK_O, Gdk::Window::CONTROL_MASK)
268
+ AccelMap.add_entry("<PDF Walker>/File/Refresh", Gdk::Keyval::GDK_R, Gdk::Window::CONTROL_MASK)
269
+ AccelMap.add_entry("<PDF Walker>/File/Close", Gdk::Keyval::GDK_X, Gdk::Window::CONTROL_MASK)
270
+ AccelMap.add_entry("<PDF Walker>/File/Save", Gdk::Keyval::GDK_S, Gdk::Window::CONTROL_MASK)
271
+ AccelMap.add_entry("<PDF Walker>/File/Quit", Gdk::Keyval::GDK_Q, Gdk::Window::CONTROL_MASK)
272
+ AccelMap.add_entry("<PDF Walker>/Document/Search", Gdk::Keyval::GDK_F, Gdk::Window::CONTROL_MASK)
273
+
274
+ @menu = MenuBar.new
275
+
276
+ ####################################################
277
+ file_ag = Gtk::AccelGroup.new
278
+ @file_menu = Menu.new.set_accel_group(file_ag).set_accel_path("<PDF Walker>/File")
279
+ add_accel_group(file_ag)
280
+
281
+ @file_menu_open = ImageMenuItem.new(Stock::OPEN).set_accel_path("<PDF Walker>/File/Open")
282
+ @file_menu_recent = MenuItem.new("Last opened")
283
+ @file_menu_deserialize = MenuItem.new("Deserialize")
284
+ @file_menu_refresh = ImageMenuItem.new(Stock::REFRESH).set_sensitive(false).set_accel_path("<PDF Walker>/File/Refresh")
285
+ @file_menu_close = ImageMenuItem.new(Stock::CLOSE).set_sensitive(false).set_accel_path("<PDF Walker>/File/Close")
286
+ @file_menu_saveas = ImageMenuItem.new(Stock::SAVE_AS).set_sensitive(false)
287
+ @file_menu_serialize = MenuItem.new("Serialize").set_sensitive(false)
288
+ @file_menu_exit = ImageMenuItem.new(Stock::QUIT).set_accel_path("<PDF Walker>/File/Quit")
289
+
290
+ @export_menu = Menu.new
291
+ @export_pdf_menu = MenuItem.new("As reassembled PDF").set_accel_path("<PDF Walker>/File/Save")
292
+ @export_graph_menu = MenuItem.new("As GraphViz dot file")
293
+ @export_graphml_menu = MenuItem.new("As GraphML file")
294
+
295
+ @export_pdf_menu.signal_connect('activate') do save end
296
+ @export_graph_menu.signal_connect('activate') do save_dot end
297
+ @export_graphml_menu.signal_connect('activate') do save_graphml end
298
+
299
+ @export_menu.append(@export_pdf_menu)
300
+ @export_menu.append(@export_graph_menu)
301
+ @export_menu.append(@export_graphml_menu)
302
+
303
+ @file_menu_saveas.set_submenu(@export_menu)
304
+
305
+ @file_menu_open.signal_connect('activate') do open end
306
+ @file_menu_deserialize.signal_connect('activate') do deserialize end
307
+ @file_menu_refresh.signal_connect('activate') do open(@filename) end
308
+ @file_menu_close.signal_connect('activate') do close end
309
+ @file_menu_serialize.signal_connect('activate') do serialize end
310
+ @file_menu_exit.signal_connect('activate') do self.destroy end
311
+
312
+ update_recent_menu
313
+
314
+ @file_menu.append(@file_menu_open)
315
+ @file_menu.append(@file_menu_recent)
316
+ @file_menu.append(@file_menu_deserialize)
317
+ @file_menu.append(@file_menu_refresh)
318
+ @file_menu.append(@file_menu_close)
319
+ @file_menu.append(@file_menu_saveas)
320
+ @file_menu.append(@file_menu_serialize)
321
+ @file_menu.append(@file_menu_exit)
322
+
323
+ @menu.append(MenuItem.new('_File').set_submenu(@file_menu))
324
+ ####################################################
325
+
326
+ doc_ag = Gtk::AccelGroup.new
327
+ @document_menu = Menu.new.set_accel_group(doc_ag)
328
+ add_accel_group(doc_ag)
329
+
330
+ @document_menu_search = ImageMenuItem.new(Stock::FIND).set_sensitive(false).set_accel_path("<PDF Walker>/Document/Search")
331
+ @document_menu_gotocatalog = MenuItem.new("Jump To Catalog").set_sensitive(false)
332
+ @document_menu_gotorev = MenuItem.new("Jump To Revision...").set_sensitive(false)
333
+ @document_menu_gotopage = MenuItem.new("Jump To Page...").set_sensitive(false)
334
+ @document_menu_gotoobj = MenuItem.new("Jump To Object...").set_sensitive(false)
335
+ @document_menu_properties = ImageMenuItem.new(Stock::PROPERTIES).set_sensitive(false)
336
+ @document_menu_sign = MenuItem.new("Sign the document").set_sensitive(false)
337
+ @document_menu_ur = MenuItem.new("Enable Usage Rights").set_sensitive(false)
338
+
339
+ @document_menu_search.signal_connect('activate') do search end
340
+ @document_menu_gotocatalog.signal_connect('activate') do goto_catalog end
341
+ @document_menu_gotoobj.signal_connect('activate') do goto_object end
342
+ @document_menu_properties.signal_connect('activate') do display_file_properties end
343
+ @document_menu_sign.signal_connect('activate') do display_signing_wizard end
344
+ @document_menu_ur.signal_connect('activate') do display_usage_rights_wizard end
345
+
346
+ @document_menu.append(@document_menu_search)
347
+ @document_menu.append(MenuItem.new)
348
+ @document_menu.append(@document_menu_gotocatalog)
349
+ @document_menu.append(@document_menu_gotorev)
350
+ @document_menu.append(@document_menu_gotopage)
351
+ @document_menu.append(@document_menu_gotoobj)
352
+ @document_menu.append(MenuItem.new)
353
+ @document_menu.append(@document_menu_sign)
354
+ @document_menu.append(@document_menu_ur)
355
+ @document_menu.append(@document_menu_properties)
356
+
357
+ @menu.append(MenuItem.new('_Document').set_submenu(@document_menu))
358
+ ####################################################
359
+ @help_menu = Menu.new
360
+ @help_menu_profile = CheckMenuItem.new("Profiling (Debug purposes only)").set_active(@config.profile?)
361
+ @help_menu_profile.signal_connect('toggled') do @config.set_profiling(@help_menu_profile.active?) end
362
+
363
+ @help_menu_about = ImageMenuItem.new(Stock::ABOUT)
364
+
365
+ @help_menu_about.signal_connect('activate') do about end
366
+
367
+ @help_menu.append(@help_menu_profile)
368
+ @help_menu.append(@help_menu_about)
369
+
370
+ @menu.append(MenuItem.new('_Help').set_submenu(@help_menu))
371
+ ####################################################
372
+
373
+ end
374
+
375
+ def update_recent_menu
376
+
377
+ @recent_menu = Menu.new
378
+ @config.recent_files.each { |file|
379
+
380
+ menu = MenuItem.new(file)
381
+ menu.signal_connect('activate') do open(file) end
382
+
383
+ @recent_menu.append(menu)
384
+ }
385
+
386
+ @file_menu_recent.set_submenu(@recent_menu)
387
+ @file_menu_recent.show_all
388
+ end
389
+
390
+ end
391
+
392
+ end