C0 code coverage information
Generated on Tue Oct 16 11:40:50 -0400 2007 with rcov 0.8.0
Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
1 # -*- Mode: ruby; ruby-indent-level: 4 -*-
2 #
3 # Copyright (C) 2004-2006 Laurent Sansonetti
4 # Copyright (C) 2007 Cathal Mc Ginley
5 #
6 # Alexandria is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; either version 2 of the
9 # License, or (at your option) any later version.
10 #
11 # Alexandria 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 GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public
17 # License along with Alexandria; see the file COPYING. If not,
18 # write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 # Boston, MA 02111-1307, USA.
20
21 #require 'monitor'
22 require 'alexandria/scanners/cuecat'
23
24 module Alexandria
25 module UI
26 class AcquireDialog < GladeBase
27 include GetText
28 include Logging
29 extend GetText
30 GetText.bindtextdomain(Alexandria::TEXTDOMAIN, nil, nil, "UTF-8")
31
32 def initialize(parent, selected_library=nil, &block)
33 super('acquire_dialog.glade')
34 @acquire_dialog.transient_for = @parent = parent
35 @block = block
36
37 libraries = Libraries.instance.all_regular_libraries
38 if selected_library.is_a?(SmartLibrary)
39 selected_library = libraries.first
40 end
41 @combo_libraries.populate_with_libraries(libraries,
42 selected_library)
43
44 @add_button.sensitive = false
45 setup_scanner_area
46 init_treeview
47 @book_results = Hash.new
48 end
49
50 def on_add
51 model = @barcodes_treeview.model
52 selection = @barcodes_treeview.selection
53 isbns = []
54 if selection.count_selected_rows > 0
55 model.freeze_notify do
56 # capture isbns
57 selection.selected_each do |model, path, iter|
58 isbns << iter[0]
59 end
60 # remove list items (complex, cf. tutorial...)
61 # http://ruby-gnome2.sourceforge.jp/hiki.cgi?tut-treeview-model-remove
62 #row_refs = []
63 #paths = selection.selected_rows
64 #paths.each do |path|
65 # row_refs << Gtk::TreeRowReference.new(model, path)
66 #end
67 #row_refs.each do |ref|
68 # model.remove(model.get_iter(ref.path))
69 #end
70
71 # try it this way... works because of persistent iters
72 row_iters = []
73 selection.selected_rows.each do |path|
74 row_iters << model.get_iter(path)
75 end
76 row_iters.each do |iter|
77 model.remove(iter)
78 end
79
80 end
81 else
82 model.freeze_notify do
83 # capture isbns
84 model.each do |model, path, iter|
85 isbns << iter[0]
86 end
87 # remove list items
88 model.clear
89 end
90 end
91
92 libraries = Libraries.instance.all_libraries
93 library, new_library =
94 @combo_libraries.selection_from_libraries(libraries)
95 isbns.each do |isbn|
96 log.debug { "Adding #{isbn}" }
97 result = @book_results[isbn]
98 book = result[0]
99 cover_uri = result[1]
100
101 unless cover_uri.nil?
102 library.save_cover(book, cover_uri)
103 end
104 library << book
105 library.save(book)
106 end
107 end
108
109 def on_cancel
110 @acquire_dialog.destroy
111 end
112
113 def on_help
114 end
115
116 def read_barcode_scan
117 log.debug { "reading CueCat data #{@scanner_buffer}" }
118 barcode_text = nil
119 isbn = nil
120 begin
121 barcode_text = @scanner.decode(@scanner_buffer)
122 log.debug { "got barcode text #{barcode_text}" }
123 isbn = Library.canonicalise_isbn(barcode_text)
124 # TODO :: use an AppFacade
125 # isbn = LookupBook.get_isbn(barcode_text)
126 rescue StandardError => err
127 log.error { "Bad scan: #{@scanner_buffer} #{err}" }
128 ensure
129 @scanner_buffer = ""
130 end
131 if isbn
132 log.debug { "Got ISBN #{isbn}" }
133 # TODO :: sound
134 # play_sound("gnometris/turn")
135
136 @barcodes_treeview.model.freeze_notify do
137 iter = @barcodes_treeview.model.append
138 iter[0] = isbn
139 iter[1] = Icons::BOOK
140 iter[2] = ""
141 end
142 lookup_book(isbn)
143 else
144 log.debug { "was not an ISBN barcode" }
145 # TODO :: sound
146 # play_sound("question")
147 end
148 end
149
150 private
151
152 def lookup_book(isbn)
153 lookup_thread = Thread.new(isbn) do |isbn|
154 begin
155 results = Alexandria::BookProviders.isbn_search(isbn)
156 book = results[0]
157 cover_uri = results[1]
158 @book_results[isbn] = results
159 set_cover_image_async(isbn, cover_uri)
160 @barcodes_treeview.model.freeze_notify do
161 iter = @barcodes_treeview.model.each do |model, path, iter|
162 if iter[0] == isbn
163 iter[2] = book.title
164 model.row_changed(path, iter)
165 end
166 end
167 end
168
169 @add_button.sensitive = true
170 rescue StandardError => err
171 log.error { "Book Search failed: #{err.message}"}
172 log << err if log.error?
173 end
174 end
175 end
176
177 def set_cover_image_async(isbn, cover_uri)
178 image_thread = Thread.new(isbn, cover_uri) do |isbn, cover_uri|
179 begin
180 pixbuf = nil
181 if cover_uri
182 image_data = nil
183 if URI.parse(cover_uri).scheme.nil?
184 File.open(cover_uri, "r") do |io|
185 image = io.read
186 end
187 else
188 image_data = URI.parse(cover_uri).read
189 end
190 loader = Gdk::PixbufLoader.new
191 loader.last_write(image_data)
192 pixbuf = loader.pixbuf
193 else
194 pixbuf = Icons::BOOK
195 end
196
197 @barcodes_treeview.model.freeze_notify do
198 iter = @barcodes_treeview.model.each do |model, path, iter|
199 if iter[0] == isbn
200 iter[1] = pixbuf
201 model.row_changed(path, iter)
202 end
203 end
204 end
205
206
207 rescue StandardError => err
208 log.error {
209 "Failed to load cover image icon: #{err.message}"
210 }
211 log << err if log.error?
212
213 end
214 end
215 end
216
217 def setup_scanner_area
218 @scanner_buffer = ""
219 @scanner = Alexandria::Scanners::CueCat.new # HACK :: use Registry
220
221 # attach signals
222 @scan_area.signal_connect("button-press-event") do |widget, event|
223 @scan_area.grab_focus
224 end
225 @scan_area.signal_connect("focus-in-event") do |widget, event|
226 @barcode_label.label = _("_Barcode Scanner Ready")
227 @scanner_buffer = ""
228 begin
229 # @frame1.modify_bg(Gtk::STATE_NORMAL, Gdk::Color.new(0, 0, 0xEE))
230 # @frame1.modify_bg(Gtk::STATE_ACTIVE, Gdk::Color.new(0, 0, 0xEE))
231 points = [[-100,-10], [300,-10], [300,300], [-100,300]]
232 @scanner_background = Gnome::CanvasPolygon.new(@barcode_canvas.root,
233 {:points => points, :fill_color_rgba => 0xFDFDFDFF})
234 rescue StandardError => err
235 log.error { "Error drawing to Gnome Canvas" }
236 log << err if log.error?
237 end
238 end
239 @scan_area.signal_connect("focus-out-event") do |widget, event|
240 @barcode_label.label = _("Click below to scan _barcodes")
241 @scanner_buffer = ""
242 @scanner_background.destroy
243 end
244
245 @@debug_index = 0
246 @scan_area.signal_connect("key-press-event") do |button, event|
247 #log.debug { event.keyval }
248 if event.keyval < 255
249 if @scanner_buffer.empty?
250 if event.keyval.chr == '`' # backtick key for devs
251 developer_test_scan
252 next
253 else
254 # this is our first character, notify user
255 log.debug { "Scanning! Received first character." }
256 end
257 # TODO :: sound
258 # play_sound("iagno/flip-piece")
259 end
260 @scanner_buffer << event.keyval.chr
261
262 # or get event.keyval == 65293 meaning Enter key
263 if @scanner.match? @scanner_buffer
264 read_barcode_scan
265 end
266 end
267 end
268
269
270 # TODO :: sound
271 # Gnome::Sound.init("localhost")
272
273 end
274
275 def developer_test_scan
276 log.info { "Developer test scan." }
277 scans = [".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7C3j3C3f1Dxj3Dq.",
278 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7C3z0CNj3Dhj1EW.",
279 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7C3r2DNbXCxTZCW.",
280 ".C3nZC3nZC3n2ChnWENz7DxnY.cGf2.ENr7C3z0DNn0ENnWE3nZDhP6.",
281 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7CNT2CxT2ChP0Dq.",
282 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7CNT6E3f7CNbWDa.",
283 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7C3b3ENjYDxv3EW.",
284 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7C3b2DxjZE3b3Dq.",
285 ".C3nZC3nZC3n2ChnWENz7DxnY.cGen.ENr7C3n6CNr6DxvYDa."]
286 @scanner_buffer = scans[@@debug_index % scans.size]
287 @@debug_index += 1
288 read_barcode_scan
289 end
290
291 def init_treeview
292 liststore = Gtk::ListStore.new(String, Gdk::Pixbuf, String)
293
294 @barcodes_treeview.selection.mode = Gtk::SELECTION_MULTIPLE
295
296 @barcodes_treeview.model = liststore
297
298 text_renderer = Gtk::CellRendererText.new
299 text_renderer.editable = false
300
301 # Add column using our renderer
302 col = Gtk::TreeViewColumn.new("ISBN", text_renderer, :text => 0)
303 @barcodes_treeview.append_column(col)
304
305 # Middle colulmn is cover-image renderer
306 pixbuf_renderer = Gtk::CellRendererPixbuf.new
307 col = Gtk::TreeViewColumn.new("Cover", pixbuf_renderer)
308
309 col.set_cell_data_func(pixbuf_renderer) do |column, cell, model, iter|
310 pixbuf = iter[1]
311 if (pixbuf)
312 max_height = 25
313
314 if pixbuf.height > max_height
315 new_width = pixbuf.width * (max_height.to_f / pixbuf.height)
316 pixbuf = pixbuf.scale(new_width, max_height)
317 end
318
319 cell.pixbuf = pixbuf
320 end
321
322 end
323
324
325 @barcodes_treeview.append_column(col)
326
327 # Add column using the second renderer
328 col = Gtk::TreeViewColumn.new("Title", text_renderer, :text => 2)
329 @barcodes_treeview.append_column(col)
330
331
332 @barcodes_treeview.model.signal_connect("row-deleted") do |model, path|
333 if not model.iter_first
334 @add_button.sensitive = false
335 end
336 end
337
338 end
339
340 #def play_sound(filename)
341 # dir = "/usr/share/sounds"
342 # Gnome::Sound.play("#{dir}/#{filename}.wav")
343 #end
344
345 end
346 end
347 end
Generated using the rcov code coverage analysis tool for Ruby version 0.8.0.