origami 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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