alexandria-book-collection-manager 0.7.5 → 0.7.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.github/workflows/ruby.yml +72 -0
  4. data/.gitignore +4 -1
  5. data/.rubocop.yml +65 -30
  6. data/.rubocop_todo.yml +49 -165
  7. data/.simplecov +5 -2
  8. data/CHANGELOG.md +64 -0
  9. data/ChangeLog.0 +19 -19
  10. data/INSTALL.md +26 -16
  11. data/README.md +31 -35
  12. data/Rakefile +18 -16
  13. data/alexandria-book-collection-manager.gemspec +35 -29
  14. data/doc/FAQ +2 -2
  15. data/doc/dependency_decisions.yml +22 -3
  16. data/lib/alexandria/about.rb +1 -1
  17. data/lib/alexandria/book_providers/bl_provider.rb +88 -0
  18. data/lib/alexandria/book_providers/douban.rb +2 -2
  19. data/lib/alexandria/book_providers/loc_provider.rb +38 -0
  20. data/lib/alexandria/book_providers/pseudomarc.rb +61 -71
  21. data/lib/alexandria/book_providers/sbn_provider.rb +108 -0
  22. data/lib/alexandria/book_providers/{thalia.rb → thalia_provider.rb} +37 -74
  23. data/lib/alexandria/book_providers/web.rb +2 -2
  24. data/lib/alexandria/book_providers/worldcat.rb +34 -38
  25. data/lib/alexandria/book_providers/z3950_provider.rb +199 -0
  26. data/lib/alexandria/book_providers.rb +48 -65
  27. data/lib/alexandria/default_preferences.rb +2 -1
  28. data/lib/alexandria/execution_queue.rb +13 -12
  29. data/lib/alexandria/export_library.rb +21 -22
  30. data/lib/alexandria/image_fetcher.rb +25 -0
  31. data/lib/alexandria/import_library.rb +46 -70
  32. data/lib/alexandria/import_library_csv.rb +16 -16
  33. data/lib/alexandria/library_sort_order.rb +3 -1
  34. data/lib/alexandria/library_store.rb +19 -20
  35. data/lib/alexandria/logging.rb +5 -9
  36. data/lib/alexandria/models/book.rb +15 -2
  37. data/lib/alexandria/models/library.rb +31 -35
  38. data/lib/alexandria/net.rb +1 -2
  39. data/lib/alexandria/preferences.rb +27 -33
  40. data/lib/alexandria/scanners/cue_cat.rb +6 -6
  41. data/lib/alexandria/scanners/keyboard.rb +1 -1
  42. data/lib/alexandria/scanners.rb +2 -2
  43. data/lib/alexandria/smart_library.rb +22 -26
  44. data/lib/alexandria/ui/about_dialog.rb +1 -1
  45. data/lib/alexandria/ui/acquire_dialog.rb +15 -19
  46. data/lib/alexandria/ui/alert_dialog.rb +36 -19
  47. data/lib/alexandria/ui/bad_isbns_dialog.rb +13 -9
  48. data/lib/alexandria/ui/barcode_animation.rb +6 -6
  49. data/lib/alexandria/ui/book_properties_dialog.rb +2 -3
  50. data/lib/alexandria/ui/book_properties_dialog_base.rb +35 -137
  51. data/lib/alexandria/ui/calendar_popup.rb +58 -0
  52. data/lib/alexandria/ui/callbacks.rb +144 -123
  53. data/lib/alexandria/ui/completion_models.rb +2 -6
  54. data/lib/alexandria/ui/confirm_erase_dialog.rb +1 -1
  55. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +2 -2
  56. data/lib/alexandria/ui/error_dialog.rb +1 -1
  57. data/lib/alexandria/ui/export_dialog.rb +19 -18
  58. data/lib/alexandria/ui/icons.rb +34 -40
  59. data/lib/alexandria/ui/iconview_tooltips.rb +40 -53
  60. data/lib/alexandria/ui/import_dialog.rb +49 -48
  61. data/lib/alexandria/ui/init.rb +14 -12
  62. data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +2 -2
  63. data/lib/alexandria/ui/libraries_combo.rb +10 -9
  64. data/lib/alexandria/ui/listview.rb +6 -7
  65. data/lib/alexandria/ui/main_app.rb +2 -2
  66. data/lib/alexandria/ui/multi_drag_treeview.rb +5 -7
  67. data/lib/alexandria/ui/new_book_dialog.rb +63 -65
  68. data/lib/alexandria/ui/new_book_dialog_manual.rb +1 -1
  69. data/lib/alexandria/ui/new_provider_dialog.rb +12 -11
  70. data/lib/alexandria/ui/new_smart_library_dialog.rb +39 -27
  71. data/lib/alexandria/ui/preferences_dialog.rb +25 -84
  72. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +10 -6
  73. data/lib/alexandria/ui/provider_preferences_dialog.rb +5 -5
  74. data/lib/alexandria/ui/really_delete_dialog.rb +2 -2
  75. data/lib/alexandria/ui/sidepane_manager.rb +38 -38
  76. data/lib/alexandria/ui/skip_entry_dialog.rb +3 -2
  77. data/lib/alexandria/ui/smart_library_properties_dialog.rb +35 -36
  78. data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +61 -244
  79. data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
  80. data/lib/alexandria/ui/sound.rb +4 -6
  81. data/lib/alexandria/ui/ui_manager.rb +80 -83
  82. data/lib/alexandria/ui.rb +7 -7
  83. data/lib/alexandria/version.rb +2 -2
  84. data/lib/alexandria/web_themes.rb +15 -15
  85. data/lib/alexandria.rb +2 -2
  86. data/po/cs.po +947 -865
  87. data/po/cy.po +913 -864
  88. data/po/de.po +961 -865
  89. data/po/el.po +956 -861
  90. data/po/es.po +952 -857
  91. data/po/fr.po +950 -865
  92. data/po/ga.po +866 -819
  93. data/po/gl.po +946 -861
  94. data/po/it.po +945 -858
  95. data/po/ja.po +921 -836
  96. data/po/mk.po +953 -858
  97. data/po/nb.po +932 -847
  98. data/po/nl.po +955 -849
  99. data/po/pl.po +999 -963
  100. data/po/pt.po +946 -850
  101. data/po/pt_BR.po +944 -859
  102. data/po/ru.po +959 -868
  103. data/po/sk.po +950 -863
  104. data/po/sv.po +944 -859
  105. data/po/uk.po +925 -846
  106. data/po/zh_TW.po +926 -841
  107. data/schemas/alexandria.schemas +1 -1
  108. data/share/alexandria/glade/main_app__builder.glade +6 -21
  109. data/share/gnome/help/alexandria/C/adding-books.xml +3 -4
  110. data/share/gnome/help/alexandria/C/introduction.xml +0 -16
  111. data/share/gnome/help/alexandria/C/searching.xml +1 -4
  112. data/share/gnome/help/alexandria/C/settings.xml +0 -30
  113. data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
  114. data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
  115. data/share/gnome/help/alexandria/fr/alexandria.xml +5 -160
  116. data/share/gnome/help/alexandria/ja/adding-books.xml +1 -1
  117. data/share/gnome/help/alexandria/ja/introduction.xml +0 -15
  118. data/share/gnome/help/alexandria/ja/searching.xml +3 -7
  119. data/share/gnome/help/alexandria/ja/settings.xml +0 -27
  120. data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
  121. data/spec/alexandria/book_providers/bl_provider_spec.rb +13 -0
  122. data/spec/alexandria/book_providers/loc_provider_spec.rb +17 -0
  123. data/spec/alexandria/book_providers/sbn_provider_spec.rb +13 -0
  124. data/spec/alexandria/book_providers/thalia_provider_spec.rb +119 -0
  125. data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
  126. data/spec/alexandria/book_providers_spec.rb +0 -154
  127. data/spec/alexandria/console_spec.rb +0 -5
  128. data/spec/alexandria/export_library_spec.rb +27 -38
  129. data/spec/alexandria/library_spec.rb +76 -46
  130. data/spec/alexandria/preferences_spec.rb +29 -3
  131. data/spec/alexandria/scanners/cue_cat_spec.rb +1 -1
  132. data/spec/alexandria/ui/about_dialog_spec.rb +1 -1
  133. data/spec/alexandria/ui/acquire_dialog_spec.rb +1 -1
  134. data/spec/alexandria/ui/alert_dialog_spec.rb +1 -1
  135. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +1 -1
  136. data/spec/alexandria/ui/book_properties_dialog_spec.rb +47 -5
  137. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +1 -1
  138. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +1 -1
  139. data/spec/alexandria/ui/error_dialog_spec.rb +1 -1
  140. data/spec/alexandria/ui/export_dialog_spec.rb +25 -4
  141. data/spec/alexandria/ui/icons_spec.rb +26 -0
  142. data/spec/alexandria/ui/iconview_spec.rb +1 -1
  143. data/spec/alexandria/ui/import_dialog_spec.rb +35 -3
  144. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +1 -1
  145. data/spec/alexandria/ui/main_app_spec.rb +1 -1
  146. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +39 -3
  147. data/spec/alexandria/ui/new_provider_dialog_spec.rb +19 -3
  148. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +28 -3
  149. data/spec/alexandria/ui/preferences_dialog_spec.rb +2 -2
  150. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +23 -8
  151. data/spec/alexandria/ui/really_delete_dialog_spec.rb +1 -1
  152. data/spec/alexandria/ui/sidepane_manager_spec.rb +2 -2
  153. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +1 -1
  154. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +37 -6
  155. data/spec/alexandria/ui/ui_manager_spec.rb +116 -2
  156. data/spec/data/libraries/0.6.2/My Library/9780571147168.yaml +2 -0
  157. data/spec/end_to_end/basic_run_spec.rb +3 -8
  158. data/spec/fixtures/cover.jpg +0 -0
  159. data/spec/spec_helper.rb +47 -3
  160. data/tasks/spec.rake +3 -5
  161. data/util/rake/fileinstall.rb +16 -15
  162. data/util/rake/omfgenerate.rb +1 -1
  163. metadata +141 -52
  164. data/.travis.yml +0 -39
  165. data/lib/alexandria/book_providers/adlibris.rb +0 -196
  166. data/lib/alexandria/book_providers/amazon_aws.rb +0 -252
  167. data/lib/alexandria/book_providers/amazon_ecs_util.rb +0 -388
  168. data/lib/alexandria/book_providers/barnes_and_noble.rb +0 -209
  169. data/lib/alexandria/book_providers/proxis.rb +0 -175
  170. data/lib/alexandria/book_providers/siciliano.rb +0 -257
  171. data/lib/alexandria/book_providers/z3950.rb +0 -415
  172. data/spec/alexandria/ui/ui_utilities_spec.rb +0 -62
  173. data/spec/alexandria/utilities_spec.rb +0 -52
@@ -13,7 +13,7 @@ module Alexandria
13
13
 
14
14
  def on_new(*)
15
15
  name = Library.generate_new_name(@libraries.all_libraries)
16
- library = Library.load(name)
16
+ library = @libraries.library_store.load_library(name)
17
17
  @libraries.add_library(library)
18
18
  append_library(library, true)
19
19
  setup_move_actions
@@ -21,17 +21,17 @@ module Alexandria
21
21
  end
22
22
 
23
23
  def on_new_smart(*)
24
- NewSmartLibraryDialog.new(@main_app).acquire do |smart_library|
25
- smart_library.refilter
26
- @libraries.add_library(smart_library)
27
- append_library(smart_library, true)
28
- smart_library.save
29
- end
24
+ smart_library = NewSmartLibraryDialog.new(@main_app).acquire or return
25
+
26
+ smart_library.refilter
27
+ @libraries.add_library(smart_library)
28
+ append_library(smart_library, true)
29
+ smart_library.save
30
30
  end
31
31
 
32
32
  def on_add_book(*)
33
33
  log.info { "on_add_book" }
34
- NewBookDialog.new(@main_app, selected_library) do |_books, library, is_new|
34
+ dialog = NewBookDialog.new(@main_app, selected_library) do |_books, library, is_new|
35
35
  if is_new
36
36
  append_library(library, true)
37
37
  setup_move_actions
@@ -39,13 +39,15 @@ module Alexandria
39
39
  select_library(library)
40
40
  end
41
41
  end
42
+ dialog.show
42
43
  end
43
44
 
44
45
  def on_add_book_manual(*)
45
46
  library = selected_library
46
- NewBookDialogManual.new(@main_app, library) do |_book|
47
+ dialog = NewBookDialogManual.new(@main_app, library) do |_book|
47
48
  refresh_books
48
49
  end
50
+ dialog.show
49
51
  end
50
52
 
51
53
  def on_import(*)
@@ -53,14 +55,12 @@ module Alexandria
53
55
  unless bad_isbns.empty?
54
56
  log.debug { "bad_isbn" }
55
57
  message = _("The following lines are not valid ISBNs and were not imported:")
56
- bad_isbn_warn = BadIsbnsDialog.new(@main_app, message, bad_isbns)
57
- bad_isbn_warn.signal_connect("response") { bad_isbn_warn.destroy }
58
+ BadIsbnsDialog.new(@main_app, message, bad_isbns).show
58
59
  end
59
60
  unless failed_isbns.nil? || failed_isbns.empty?
60
61
  log.debug { "failed lookup of #{failed_isbns.size} ISBNs" }
61
62
  message = _("Books could not be found for the following ISBNs:")
62
- failed_lookup = BadIsbnsDialog.new(@main_app, message, failed_isbns)
63
- failed_lookup.signal_connect("response") { failed_lookup.destroy }
63
+ BadIsbnsDialog.new(@main_app, message, failed_isbns).show
64
64
  end
65
65
  @libraries.add_library(library)
66
66
  append_library(library, true)
@@ -76,9 +76,9 @@ module Alexandria
76
76
  log.debug { "end window-state-event" }
77
77
  end
78
78
 
79
- def on_toolbar_view_as_changed(cb)
79
+ def on_toolbar_view_as_changed(widget)
80
80
  log.debug { "changed" }
81
- action = case cb.active
81
+ action = case widget.active
82
82
  when 0
83
83
  @actiongroup["AsIcons"]
84
84
  when 1
@@ -100,9 +100,9 @@ module Alexandria
100
100
  @iconview.unfreeze
101
101
  end
102
102
 
103
- def on_criterion_combobox_changed(cb)
103
+ def on_criterion_combobox_changed(widget)
104
104
  log.debug { "changed" }
105
- @filter_books_mode = cb.active
105
+ @filter_books_mode = widget.active
106
106
  @filter_entry.text.strip!
107
107
  @iconview.freeze
108
108
  @filtered_model.refilter
@@ -114,22 +114,25 @@ module Alexandria
114
114
  end
115
115
 
116
116
  def on_acquire(*)
117
- AcquireDialog.new(@main_app,
118
- selected_library) do |_books, library, is_new|
119
- if is_new
120
- append_library(library, true)
121
- setup_move_actions
122
- elsif selected_library != library
123
- select_library(library)
124
- end
125
- end
117
+ dialog =
118
+ AcquireDialog.new(@main_app, selected_library) do |_books, library, is_new|
119
+ if is_new
120
+ append_library(library, true)
121
+ setup_move_actions
122
+ elsif selected_library != library
123
+ select_library(library)
124
+ end
125
+ end
126
+ dialog.show
126
127
  end
127
128
 
128
129
  def on_properties(*)
129
130
  if @library_listview.focus? || selected_books.empty?
130
131
  library = selected_library
131
132
  if library.is_a?(SmartLibrary)
132
- SmartLibraryPropertiesDialog.new(@main_app, library).acquire do
133
+ success = SmartLibraryPropertiesDialog.new(@main_app, library).acquire
134
+
135
+ if success
133
136
  library.refilter
134
137
  refresh_books
135
138
  end
@@ -138,9 +141,10 @@ module Alexandria
138
141
  books = selected_books
139
142
  if books.length == 1
140
143
  book = books.first
141
- BookPropertiesDialog.new(@main_app,
142
- selected_library,
143
- book) # { |modified_book| }
144
+ dialog = BookPropertiesDialog.new(@main_app,
145
+ selected_library,
146
+ book)
147
+ dialog.show
144
148
  end
145
149
  end
146
150
  end
@@ -197,9 +201,9 @@ module Alexandria
197
201
 
198
202
  def on_rename(*)
199
203
  iter = @library_listview.selection.selected
200
- @library_listview.set_cursor(iter.path,
201
- @library_listview.get_column(0),
202
- true)
204
+ column = @library_listview.get_column(0)
205
+ cell = column.cells.last
206
+ @library_listview.set_cursor_on_cell(iter.path, column, cell, true)
203
207
  end
204
208
 
205
209
  def on_delete(*)
@@ -236,9 +240,10 @@ module Alexandria
236
240
  end
237
241
 
238
242
  def on_preferences(*)
239
- PreferencesDialog.new(@main_app) do
243
+ dialog = PreferencesDialog.new(@main_app) do
240
244
  @listview_manager.setup_listview_columns_visibility
241
245
  end
246
+ dialog.show
242
247
  end
243
248
 
244
249
  def on_submit_bug_report(*)
@@ -276,90 +281,36 @@ module Alexandria
276
281
  end
277
282
 
278
283
  def connect_signals
279
- # rubocop:disable Layout/LineLength
280
- standard_actions = [
281
- ["LibraryMenu", nil, _("_Library")],
282
- ["New", Gtk::Stock::NEW, _("_New Library"), "<control>L", _("Create a new library"), method(:on_new)],
283
- ["NewSmart", nil, _("New _Smart Library..."), "<control><shift>L", _("Create a new smart library"), method(:on_new_smart)],
284
- ["AddBook", Gtk::Stock::ADD, _("_Add Book..."), "<control>N", _("Add a new book from the Internet"), method(:on_add_book)],
285
- ["AddBookManual", nil, _("Add Book _Manually..."), "<control><shift>N", _("Add a new book manually"), method(:on_add_book_manual)],
286
- ["Import", nil, _("_Import..."), "<control>I", _("Import a library"), method(:on_import)],
287
- ["Export", nil, _("_Export..."), "<control><shift>E", _("Export the selected library"), method(:on_export)],
288
- ["Acquire", nil, _("A_cquire from Scanner..."), "<control><shift>S", _("Acquire books from a scanner"), method(:on_acquire)],
289
- ["Properties", Gtk::Stock::PROPERTIES, _("_Properties"), nil, _("Edit the properties of the selected book"), method(:on_properties)],
290
- ["Quit", Gtk::Stock::QUIT, _("_Quit"), "<control>Q", _("Quit the program"), method(:on_quit)],
291
- ["EditMenu", nil, _("_Edit")],
292
- ["Undo", Gtk::Stock::UNDO, _("_Undo"), "<control>Z", _("Undo the last action"), method(:on_undo)],
293
- ["Redo", Gtk::Stock::REDO, _("_Redo"), "<control><shift>Z", _("Redo the undone action"), method(:on_redo)],
294
- ["SelectAll", nil, _("_Select All"), "<control>A", _("Select all visible books"), method(:on_select_all)],
295
- ["DeselectAll", nil, _("Dese_lect All"), "<control><shift>A", _("Deselect everything"), method(:on_deselect_all)],
296
- ["SetRating", nil, _("My _Rating")],
297
- ["SetRating0", nil, _("None"), nil, nil, proc { on_set_rating[0].call }],
298
- ["SetRating1", nil, _("One Star"), nil, nil, proc { on_set_rating[1].call }],
299
- ["SetRating2", nil, _("Two Stars"), nil, nil, proc { on_set_rating[2].call }],
300
- ["SetRating3", nil, _("Three Stars"), nil, nil, proc { on_set_rating[3].call }],
301
- ["SetRating4", nil, _("Four Stars"), nil, nil, proc { on_set_rating[4].call }],
302
- ["SetRating5", nil, _("Five Stars"), nil, nil, proc { on_set_rating[5].call }],
303
- ["Move", nil, _("_Move")],
304
- ["Rename", nil, _("_Rename"), nil, nil, method(:on_rename)],
305
- ["Delete", Gtk::Stock::DELETE, _("_Delete"), "Delete", _("Delete the selected books or library"), method(:on_delete)],
306
- ["Search", Gtk::Stock::FIND, _("_Search"), "<control>F", _("Filter books"), method(:on_search)],
307
- ["ClearSearchResult", Gtk::Stock::CLEAR, _("_Clear Results"), "<control><alt>B", _("Clear the search results"), method(:on_clear_search_results)],
308
- ["Preferences", Gtk::Stock::PREFERENCES, _("_Preferences"), "<control>O", _("Change Alexandria's settings"), method(:on_preferences)],
309
- ["ViewMenu", nil, _("_View")],
310
- ["ArrangeIcons", nil, _("Arran_ge Icons")],
311
- ["OnlineInformation", nil, _("Display Online _Information")],
312
-
313
- ["HelpMenu", nil, _("_Help")],
314
- ["SubmitBugReport", Gtk::Stock::EDIT, _("Submit _Bug Report"), nil, _("Submit a bug report to the developers"), method(:on_submit_bug_report)],
315
- ["Help", Gtk::Stock::HELP, _("Contents"), "F1", _("View Alexandria's manual"), method(:on_help)],
316
- ["About", Gtk::Stock::ABOUT, _("_About"), nil, _("Show information about Alexandria"), method(:on_about)],
317
- ]
318
-
319
- toggle_actions = [
320
- ["Sidepane", nil, _("Side _Pane"), "F9", nil, method(:on_view_sidepane), true],
321
- ["Toolbar", nil, _("_Toolbar"), nil, nil, method(:on_view_toolbar), true],
322
- ["Statusbar", nil, _("_Statusbar"), nil, nil, method(:on_view_statusbar), true],
323
- ["ReversedOrder", nil, _("Re_versed Order"), nil, nil, method(:on_reverse_order), false],
324
- ]
325
-
326
- view_as_actions = [
327
- ["AsIcons", nil, _("View as _Icons"), nil, nil, 0],
328
- ["AsList", nil, _("View as _List"), nil, nil, 1]
329
- ]
330
-
331
- arrange_icons_actions = [
332
- ["ByTitle", nil, _("By _Title"), nil, nil, 0],
333
- ["ByAuthors", nil, _("By _Authors"), nil, nil, 1],
334
- ["ByISBN", nil, _("By _ISBN"), nil, nil, 2],
335
- ["ByPublisher", nil, _("By _Publisher"), nil, nil, 3],
336
- ["ByEdition", nil, _("By _Binding"), nil, nil, 4],
337
- ["ByRating", nil, _("By _Rating"), nil, nil, 5]
338
- ]
339
- # rubocop:enable Layout/LineLength
340
-
341
- providers_actions = BookProviders.map do |provider|
342
- [provider.action_name, Gtk::Stock::JUMP_TO,
343
- _("At _%s") % provider.fullname, nil, nil,
344
- proc { open_web_browser(provider.url(selected_books.first)) }]
345
- end
346
-
347
284
  log.debug { "Adding actions to @actiongroup" }
348
285
 
349
286
  @actiongroup = Gtk::ActionGroup.new("actions")
350
287
 
351
- standard_actions.each do |name, stock_id, label, accelerator, tooltip, callback|
352
- action = Gtk::Action.new(name, label: label, tooltip: tooltip, stock_id: stock_id)
353
- @actiongroup.add_action_with_accel(action, accelerator)
354
- action.signal_connect("activate", &callback) if callback
355
- end
288
+ connect_standard_actions
289
+ connect_providers_actions
290
+ connect_toggle_actions
291
+ connect_view_actions
292
+ connect_arrange_icons_actions
293
+ end
294
+
295
+ private
296
+
297
+ def connect_standard_actions
298
+ connect_actions standard_actions
299
+ end
300
+
301
+ def connect_providers_actions
302
+ connect_actions providers_actions
303
+ end
356
304
 
357
- providers_actions.each do |name, stock_id, label, accelerator, tooltip, callback|
305
+ def connect_actions(actions)
306
+ actions.each do |name, stock_id, label, accelerator, tooltip, callback|
358
307
  action = Gtk::Action.new(name, label: label, tooltip: tooltip, stock_id: stock_id)
359
308
  @actiongroup.add_action_with_accel(action, accelerator)
360
309
  action.signal_connect("activate", &callback) if callback
361
310
  end
311
+ end
362
312
 
313
+ def connect_toggle_actions
363
314
  toggle_actions
364
315
  .each do |name, stock_id, label, accelerator, tooltip, callback, is_active|
365
316
  action = Gtk::ToggleAction.new(name, label: label, tooltip: tooltip,
@@ -368,18 +319,10 @@ module Alexandria
368
319
  @actiongroup.add_action_with_accel(action, accelerator)
369
320
  action.signal_connect("toggled", &callback) if callback
370
321
  end
322
+ end
371
323
 
372
- first_action = nil
373
- view_as_actions.each do |name, stock_id, label, accelerator, tooltip, value|
374
- action = Gtk::RadioAction.new(name, value, label: label, tooltip: tooltip,
375
- stock_id: stock_id)
376
- if first_action
377
- action.join_group first_action
378
- else
379
- first_action = action
380
- end
381
- @actiongroup.add_action_with_accel(action, accelerator)
382
- end
324
+ def connect_view_actions
325
+ first_action = connect_radio_actions view_as_actions
383
326
 
384
327
  first_action.signal_connect "changed" do |_action, current, _user_data|
385
328
  @notebook.page = current.current_value
@@ -388,9 +331,20 @@ module Alexandria
388
331
  @toolbar_view_as.active = current.current_value
389
332
  end
390
333
  end
334
+ end
391
335
 
336
+ def connect_arrange_icons_actions
337
+ first_action = connect_radio_actions arrange_icons_actions
338
+
339
+ first_action.signal_connect "changed" do |_action, current, _user_data|
340
+ @prefs.arrange_icons_mode = current.current_value
341
+ setup_books_iconview_sorting
342
+ end
343
+ end
344
+
345
+ def connect_radio_actions(actions)
392
346
  first_action = nil
393
- arrange_icons_actions.each do |name, stock_id, label, accelerator, tooltip, value|
347
+ actions.each do |name, stock_id, label, accelerator, tooltip, value|
394
348
  action = Gtk::RadioAction.new(name, value, label: label, tooltip: tooltip,
395
349
  stock_id: stock_id)
396
350
  if first_action
@@ -400,12 +354,79 @@ module Alexandria
400
354
  end
401
355
  @actiongroup.add_action_with_accel(action, accelerator)
402
356
  end
357
+ first_action
358
+ end
403
359
 
404
- first_action.signal_connect "changed" do |_action, current, _user_data|
405
- @prefs.arrange_icons_mode = current.current_value
406
- setup_books_iconview_sorting
360
+ def standard_actions
361
+ # rubocop:disable Layout/LineLength
362
+ [["LibraryMenu", nil, _("_Library")],
363
+ ["New", Gtk::Stock::NEW, _("_New Library"), "<control>L", _("Create a new library"), method(:on_new)],
364
+ ["NewSmart", nil, _("New _Smart Library..."), "<control><shift>L", _("Create a new smart library"), method(:on_new_smart)],
365
+ ["AddBook", Gtk::Stock::ADD, _("_Add Book..."), "<control>N", _("Add a new book from the Internet"), method(:on_add_book)],
366
+ ["AddBookManual", nil, _("Add Book _Manually..."), "<control><shift>N", _("Add a new book manually"), method(:on_add_book_manual)],
367
+ ["Import", nil, _("_Import..."), "<control>I", _("Import a library"), method(:on_import)],
368
+ ["Export", nil, _("_Export..."), "<control><shift>E", _("Export the selected library"), method(:on_export)],
369
+ ["Acquire", nil, _("A_cquire from Scanner..."), "<control><shift>S", _("Acquire books from a scanner"), method(:on_acquire)],
370
+ ["Properties", Gtk::Stock::PROPERTIES, _("_Properties"), nil, _("Edit the properties of the selected book"), method(:on_properties)],
371
+ ["Quit", Gtk::Stock::QUIT, _("_Quit"), "<control>Q", _("Quit the program"), method(:on_quit)],
372
+ ["EditMenu", nil, _("_Edit")],
373
+ ["Undo", Gtk::Stock::UNDO, _("_Undo"), "<control>Z", _("Undo the last action"), method(:on_undo)],
374
+ ["Redo", Gtk::Stock::REDO, _("_Redo"), "<control><shift>Z", _("Redo the undone action"), method(:on_redo)],
375
+ ["SelectAll", nil, _("_Select All"), "<control>A", _("Select all visible books"), method(:on_select_all)],
376
+ ["DeselectAll", nil, _("Dese_lect All"), "<control><shift>A", _("Deselect everything"), method(:on_deselect_all)],
377
+ ["SetRating", nil, _("My _Rating")],
378
+ ["SetRating0", nil, _("None"), nil, nil, proc { on_set_rating[0].call }],
379
+ ["SetRating1", nil, _("One Star"), nil, nil, proc { on_set_rating[1].call }],
380
+ ["SetRating2", nil, _("Two Stars"), nil, nil, proc { on_set_rating[2].call }],
381
+ ["SetRating3", nil, _("Three Stars"), nil, nil, proc { on_set_rating[3].call }],
382
+ ["SetRating4", nil, _("Four Stars"), nil, nil, proc { on_set_rating[4].call }],
383
+ ["SetRating5", nil, _("Five Stars"), nil, nil, proc { on_set_rating[5].call }],
384
+ ["Move", nil, _("_Move")],
385
+ ["Rename", nil, _("_Rename"), nil, nil, method(:on_rename)],
386
+ ["Delete", Gtk::Stock::DELETE, _("_Delete"), "Delete", _("Delete the selected books or library"), method(:on_delete)],
387
+ ["Search", Gtk::Stock::FIND, _("_Search"), "<control>F", _("Filter books"), method(:on_search)],
388
+ ["ClearSearchResult", Gtk::Stock::CLEAR, _("_Clear Results"), "<control><alt>B", _("Clear the search results"), method(:on_clear_search_results)],
389
+ ["Preferences", Gtk::Stock::PREFERENCES, _("_Preferences"), "<control>O", _("Change Alexandria's settings"), method(:on_preferences)],
390
+ ["ViewMenu", nil, _("_View")],
391
+ ["ArrangeIcons", nil, _("Arran_ge Icons")],
392
+ ["OnlineInformation", nil, _("Display Online _Information")],
393
+
394
+ ["HelpMenu", nil, _("_Help")],
395
+ ["SubmitBugReport", Gtk::Stock::EDIT, _("Submit _Bug Report"), nil, _("Submit a bug report to the developers"), method(:on_submit_bug_report)],
396
+ ["Help", Gtk::Stock::HELP, _("Contents"), "F1", _("View Alexandria's manual"), method(:on_help)],
397
+ ["About", Gtk::Stock::ABOUT, _("_About"), nil, _("Show information about Alexandria"), method(:on_about)]]
398
+ # rubocop:enable Layout/LineLength
399
+ end
400
+
401
+ def providers_actions
402
+ BookProviders.list.map do |provider|
403
+ [provider.action_name, Gtk::Stock::JUMP_TO,
404
+ _("At _%s") % provider.fullname, nil, nil,
405
+ proc { open_web_browser(provider.url(selected_books.first)) }]
407
406
  end
408
407
  end
408
+
409
+ def toggle_actions
410
+ [["Sidepane", nil, _("Side_pane"), "F9", nil, method(:on_view_sidepane), true],
411
+ ["Toolbar", nil, _("_Toolbar"), nil, nil, method(:on_view_toolbar), true],
412
+ ["Statusbar", nil, _("_Statusbar"), nil, nil, method(:on_view_statusbar), true],
413
+ ["ReversedOrder", nil, _("Re_versed Order"), nil, nil,
414
+ method(:on_reverse_order), false]]
415
+ end
416
+
417
+ def view_as_actions
418
+ [["AsIcons", nil, _("View as _Icons"), nil, nil, 0],
419
+ ["AsList", nil, _("View as _List"), nil, nil, 1]]
420
+ end
421
+
422
+ def arrange_icons_actions
423
+ [["ByTitle", nil, _("By _Title"), nil, nil, 0],
424
+ ["ByAuthors", nil, _("By _Authors"), nil, nil, 1],
425
+ ["ByISBN", nil, _("By _ISBN"), nil, nil, 2],
426
+ ["ByPublisher", nil, _("By _Publisher"), nil, nil, 3],
427
+ ["ByEdition", nil, _("By _Binding"), nil, nil, 4],
428
+ ["ByRating", nil, _("By _Rating"), nil, nil, 5]]
429
+ end
409
430
  end
410
431
  end
411
432
  end
@@ -44,11 +44,7 @@ module Alexandria
44
44
  cur_tag = key.split(",").last.strip
45
45
  if cur_tag.size >= min
46
46
  begin
47
- if /^#{cur_tag}/.match?(iter[0])
48
- true
49
- else
50
- false
51
- end
47
+ /^#{cur_tag}/.match?(iter[0])
52
48
  rescue StandardError
53
49
  false
54
50
  end
@@ -164,7 +160,7 @@ module Alexandria
164
160
  editions << book.edition
165
161
  borrowers << book.loaned_to
166
162
  # TODO: Ensure #tags is always an array
167
- (book.tags || []).each { |tag| tags << tag }
163
+ tags.concat(book.tags) if book.tags
168
164
  end
169
165
  end
170
166
 
@@ -20,7 +20,7 @@ module Alexandria
20
20
  _("A file named '%s' already exists. Do you want " \
21
21
  "to replace it with the one you are generating?") % filename)
22
22
  # FIXME: Should accept just :cancel
23
- self.default_response = Gtk::ResponseType::CANCEL
23
+ dialog.default_response = Gtk::ResponseType::CANCEL
24
24
  end
25
25
 
26
26
  def erase?
@@ -15,13 +15,13 @@ module Alexandria
15
15
  def initialize(parent, library, book)
16
16
  super(parent,
17
17
  format(_("The book '%s' already exists in '%s'. Would you like " \
18
- "to replace it?"), book.title, library.name),
18
+ "to replace it?"), book.title, library.name),
19
19
  Gtk::Stock::DIALOG_QUESTION,
20
20
  [[_("_Skip"), Gtk::ResponseType::CANCEL],
21
21
  [_("_Replace"), Gtk::ResponseType::OK]],
22
22
  _("If you replace the existing book, its contents will " \
23
23
  "be overwritten."))
24
- self.default_response = Gtk::ResponseType::CANCEL
24
+ dialog.default_response = Gtk::ResponseType::CANCEL
25
25
  end
26
26
 
27
27
  def replace?
@@ -13,7 +13,7 @@ module Alexandria
13
13
  super(parent, title, Gtk::Stock::DIALOG_ERROR,
14
14
  [[Gtk::Stock::OK, :ok]], message)
15
15
  # FIXME: Should accept just :ok
16
- self.default_response = Gtk::ResponseType::OK
16
+ dialog.default_response = Gtk::ResponseType::OK
17
17
  end
18
18
 
19
19
  def display
@@ -10,7 +10,7 @@ require "alexandria/ui/error_dialog"
10
10
 
11
11
  module Alexandria
12
12
  module UI
13
- class ExportDialog < SimpleDelegator
13
+ class ExportDialog
14
14
  include GetText
15
15
  extend GetText
16
16
  GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
@@ -18,17 +18,17 @@ module Alexandria
18
18
  FORMATS = Alexandria::ExportFormat.all
19
19
  THEMES = Alexandria::WebTheme.all
20
20
 
21
- def initialize(parent, library, sort_order)
22
- @export_dialog = Gtk::FileChooserDialog.new(title: _("Export '%s'") % library.name,
23
- parent: parent,
24
- action: :save,
25
- buttons: [[Gtk::Stock::HELP, :help],
26
- [Gtk::Stock::CANCEL, :cancel],
27
- [_("_Export"), :accept]])
28
- super(@export_dialog)
21
+ attr_reader :dialog
29
22
 
30
- self.current_name = library.name
31
- signal_connect("destroy") { hide }
23
+ def initialize(parent, library, sort_order)
24
+ @dialog = Gtk::FileChooserDialog.new(title: _("Export '%s'") % library.name,
25
+ parent: parent,
26
+ action: :save,
27
+ buttons: [[Gtk::Stock::HELP, :help],
28
+ [Gtk::Stock::CANCEL, :cancel],
29
+ [_("_Export"), :accept]])
30
+ @dialog.current_name = library.name
31
+ @dialog.signal_connect("destroy") { @dialog.hide }
32
32
 
33
33
  @parent = parent
34
34
  @library = library
@@ -84,11 +84,11 @@ module Alexandria
84
84
  grid.attach theme_label, 0, 1, 1, 1
85
85
  grid.attach @theme_combo, 1, 1, 1, 1
86
86
  grid.attach preview_image, 2, 0, 1, 3
87
- set_extra_widget grid
87
+ @dialog.set_extra_widget grid
88
88
  end
89
89
 
90
90
  def perform
91
- while ((response = run) != Gtk::ResponseType::CANCEL) &&
91
+ while ((response = dialog.run) != Gtk::ResponseType::CANCEL) &&
92
92
  (response != Gtk::ResponseType::DELETE_EVENT)
93
93
 
94
94
  if response == Gtk::ResponseType::HELP
@@ -98,21 +98,22 @@ module Alexandria
98
98
  break if on_export(FORMATS[@types_combo.active],
99
99
  THEMES[@theme_combo.active])
100
100
  rescue StandardError => ex
101
- ErrorDialog.new(@export_dialog, _("Export failed"), ex.message).display
101
+ ErrorDialog.new(@dialog, _("Export failed"), ex.message).display
102
+ break
102
103
  end
103
104
  end
104
105
  end
105
- destroy
106
+ dialog.destroy
106
107
  end
107
108
 
108
109
  private
109
110
 
110
111
  def on_export(format, theme)
111
- filename = self.filename
112
+ filename = dialog.filename
112
113
  if format.ext
113
114
  filename += "." + format.ext if File.extname(filename).empty?
114
115
  if File.exist?(filename)
115
- dialog = ConfirmEraseDialog.new(@export_dialog, filename)
116
+ dialog = ConfirmEraseDialog.new(@dialog, filename)
116
117
  return unless dialog.erase?
117
118
 
118
119
  FileUtils.rm(filename)
@@ -125,7 +126,7 @@ module Alexandria
125
126
  "file. A directory is needed for this " \
126
127
  "operation. Please select a directory and " \
127
128
  "try again.") % filename
128
- ErrorDialog.new(@export_dialog, _("Not a directory"), msg).display
129
+ ErrorDialog.new(@dialog, _("Not a directory"), msg).display
129
130
  return
130
131
  end
131
132
  else
@@ -4,41 +4,6 @@
4
4
  #
5
5
  # See the file README.md for authorship and licensing information.
6
6
 
7
- class GdkPixbuf::Pixbuf
8
- def tag(tag_pixbuf)
9
- # Computes some tweaks.
10
- tweak_x = tag_pixbuf.width / 3
11
- tweak_y = tag_pixbuf.height / 3
12
-
13
- # Creates the destination pixbuf.
14
- new_pixbuf = GdkPixbuf::Pixbuf.new(colorspace: :rgb,
15
- has_alpha: true,
16
- bits_per_sample: 8,
17
- width: width + tweak_x,
18
- height: height + tweak_y)
19
-
20
- # Fills with blank.
21
- new_pixbuf.fill!(0)
22
-
23
- # Copies the current pixbuf there (south-west).
24
- copy_area(0, 0,
25
- width, height,
26
- new_pixbuf,
27
- 0, tweak_y)
28
-
29
- # Copies the tag pixbuf there (north-est).
30
- tag_pixbuf_x = width - (tweak_x * 2)
31
- new_pixbuf.composite!(tag_pixbuf,
32
- dest_x: 0, dest_y: 0,
33
- dest_width: tag_pixbuf.width + tag_pixbuf_x,
34
- dest_height: tag_pixbuf.height,
35
- offset_x: tag_pixbuf_x, offset_y: 0,
36
- scale_x: 1, scale_y: 1,
37
- interpolation_type: :hyper, overall_alpha: 255)
38
- new_pixbuf
39
- end
40
- end
41
-
42
7
  module Alexandria
43
8
  module UI
44
9
  module Icons
@@ -53,7 +18,7 @@ module Alexandria
53
18
  # Alexandria::UI::Icons namespace, e.g., Icons::STAR_SET
54
19
  def self.load_icon_images
55
20
  Dir.entries(ICONS_DIR).each do |file|
56
- next unless /\.png$/.match?(file) # skip non '.png' files
21
+ next unless file.end_with?(".png") # skip non '.png' files
57
22
 
58
23
  # Don't use upcase and use tr instead
59
24
  # For example in Turkish the upper case of 'i' is still 'i'.
@@ -77,13 +42,42 @@ module Alexandria
77
42
  BOOK_ICON
78
43
  end
79
44
 
45
+ def self.tag_icon(icon_pixbuf, tag_pixbuf)
46
+ # Computes some tweaks.
47
+ tweak_x = tag_pixbuf.width / 3
48
+ tweak_y = tag_pixbuf.height / 3
49
+
50
+ # Creates the destination pixbuf.
51
+ new_pixbuf = GdkPixbuf::Pixbuf.new(colorspace: :rgb,
52
+ has_alpha: true,
53
+ bits_per_sample: 8,
54
+ width: icon_pixbuf.width + tweak_x,
55
+ height: icon_pixbuf.height + tweak_y)
56
+
57
+ # Fills with blank.
58
+ new_pixbuf.fill!(0)
59
+
60
+ # Copies the current pixbuf there (south-west).
61
+ icon_pixbuf.copy_area(0, 0,
62
+ icon_pixbuf.width, icon_pixbuf.height,
63
+ new_pixbuf,
64
+ 0, tweak_y)
65
+
66
+ # Copies the tag pixbuf there (north-est).
67
+ tag_pixbuf_x = icon_pixbuf.width - (tweak_x * 2)
68
+ new_pixbuf.composite!(tag_pixbuf,
69
+ dest_x: 0, dest_y: 0,
70
+ dest_width: tag_pixbuf.width + tag_pixbuf_x,
71
+ dest_height: tag_pixbuf.height,
72
+ offset_x: tag_pixbuf_x, offset_y: 0,
73
+ scale_x: 1, scale_y: 1,
74
+ interpolation_type: :hyper, overall_alpha: 255)
75
+ new_pixbuf
76
+ end
77
+
80
78
  def self.blank?(filename)
81
79
  pixbuf = GdkPixbuf::Pixbuf.new(file: filename)
82
80
  (pixbuf.width == 1) && (pixbuf.height == 1)
83
- rescue StandardError => ex
84
- puts ex.message
85
- puts ex.backtrace.join("\n> ")
86
- true
87
81
  end
88
82
  end
89
83
  end