alexandria-book-collection-manager 0.7.1 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (210) hide show
  1. checksums.yaml +5 -5
  2. data/.github/dependabot.yml +9 -0
  3. data/.gitignore +5 -2
  4. data/.hound.yml +2 -0
  5. data/.rubocop.yml +113 -45
  6. data/.rubocop_todo.yml +82 -170
  7. data/.simplecov +5 -1
  8. data/.travis.yml +45 -0
  9. data/.yardopts +1 -1
  10. data/CHANGELOG.md +60 -0
  11. data/ChangeLog.0 +33 -35
  12. data/Gemfile +6 -5
  13. data/INSTALL.md +164 -0
  14. data/README.md +52 -42
  15. data/Rakefile +95 -109
  16. data/TODO.md +9 -1
  17. data/alexandria-book-collection-manager.gemspec +52 -45
  18. data/bin/alexandria +31 -53
  19. data/doc/AUTHORS +61 -0
  20. data/doc/BUGS +31 -0
  21. data/doc/FAQ +365 -0
  22. data/doc/HACKING +19 -0
  23. data/doc/NEWS +341 -0
  24. data/doc/alexandria.1 +120 -0
  25. data/doc/cuecat_support.rdoc +67 -0
  26. data/doc/dependency_decisions.yml +80 -0
  27. data/lib/alexandria.rb +29 -37
  28. data/lib/alexandria/about.rb +52 -51
  29. data/lib/alexandria/book_providers.rb +94 -101
  30. data/lib/alexandria/book_providers/adlibris.rb +45 -85
  31. data/lib/alexandria/book_providers/amazon_aws.rb +105 -113
  32. data/lib/alexandria/book_providers/amazon_ecs_util.rb +293 -324
  33. data/lib/alexandria/book_providers/barnes_and_noble.rb +54 -53
  34. data/lib/alexandria/book_providers/douban.rb +29 -51
  35. data/lib/alexandria/book_providers/proxis.rb +42 -59
  36. data/lib/alexandria/book_providers/pseudomarc.rb +79 -99
  37. data/lib/alexandria/book_providers/siciliano.rb +68 -70
  38. data/lib/alexandria/book_providers/thalia.rb +46 -45
  39. data/lib/alexandria/book_providers/web.rb +17 -33
  40. data/lib/alexandria/book_providers/worldcat.rb +74 -102
  41. data/lib/alexandria/book_providers/z3950.rb +170 -174
  42. data/lib/alexandria/config.rb +5 -3
  43. data/lib/alexandria/console.rb +10 -21
  44. data/lib/alexandria/default_preferences.rb +37 -0
  45. data/lib/alexandria/execution_queue.rb +17 -15
  46. data/lib/alexandria/export_format.rb +47 -0
  47. data/lib/alexandria/export_library.rb +188 -302
  48. data/lib/alexandria/import_library.rb +114 -155
  49. data/lib/alexandria/import_library_csv.rb +46 -96
  50. data/lib/alexandria/library_collection.rb +79 -0
  51. data/lib/alexandria/library_sort_order.rb +45 -0
  52. data/lib/alexandria/library_store.rb +233 -0
  53. data/lib/alexandria/logging.rb +15 -19
  54. data/lib/alexandria/models/book.rb +15 -20
  55. data/lib/alexandria/models/library.rb +81 -363
  56. data/lib/alexandria/net.rb +7 -6
  57. data/lib/alexandria/preferences.rb +73 -91
  58. data/lib/alexandria/scanners.rb +4 -2
  59. data/lib/alexandria/scanners/{cuecat.rb → cue_cat.rb} +24 -20
  60. data/lib/alexandria/scanners/keyboard.rb +10 -8
  61. data/lib/alexandria/smart_library.rb +135 -171
  62. data/lib/alexandria/ui.rb +17 -15
  63. data/lib/alexandria/ui/about_dialog.rb +49 -0
  64. data/lib/alexandria/ui/{dialogs/acquire_dialog.rb → acquire_dialog.rb} +129 -152
  65. data/lib/alexandria/ui/alert_dialog.rb +64 -0
  66. data/lib/alexandria/ui/bad_isbns_dialog.rb +41 -0
  67. data/lib/alexandria/ui/{dialogs/barcode_animation.rb → barcode_animation.rb} +18 -15
  68. data/lib/alexandria/ui/{dialogs/book_properties_dialog.rb → book_properties_dialog.rb} +44 -61
  69. data/lib/alexandria/ui/{dialogs/book_properties_dialog_base.rb → book_properties_dialog_base.rb} +84 -89
  70. data/lib/alexandria/ui/builder_base.rb +9 -27
  71. data/lib/alexandria/ui/callbacks.rb +188 -186
  72. data/lib/alexandria/ui/columns.rb +2 -0
  73. data/lib/alexandria/ui/completion_models.rb +12 -23
  74. data/lib/alexandria/ui/confirm_erase_dialog.rb +33 -0
  75. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +34 -0
  76. data/lib/alexandria/ui/dndable.rb +10 -8
  77. data/lib/alexandria/ui/error_dialog.rb +25 -0
  78. data/lib/alexandria/ui/export_dialog.rb +139 -0
  79. data/lib/alexandria/ui/icons.rb +49 -65
  80. data/lib/alexandria/ui/iconview.rb +15 -13
  81. data/lib/alexandria/ui/iconview_tooltips.rb +43 -58
  82. data/lib/alexandria/ui/import_dialog.rb +157 -0
  83. data/lib/alexandria/ui/init.rb +23 -33
  84. data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +36 -0
  85. data/lib/alexandria/ui/libraries_combo.rb +18 -14
  86. data/lib/alexandria/ui/listview.rb +77 -88
  87. data/lib/alexandria/ui/main_app.rb +26 -26
  88. data/lib/alexandria/ui/misc_dialogs.rb +10 -0
  89. data/lib/alexandria/ui/multi_drag_treeview.rb +30 -41
  90. data/lib/alexandria/ui/{dialogs/new_book_dialog.rb → new_book_dialog.rb} +168 -215
  91. data/lib/alexandria/ui/new_book_dialog_manual.rb +139 -0
  92. data/lib/alexandria/ui/new_provider_dialog.rb +100 -0
  93. data/lib/alexandria/ui/new_smart_library_dialog.rb +74 -0
  94. data/lib/alexandria/ui/preferences_dialog.rb +313 -0
  95. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +95 -0
  96. data/lib/alexandria/ui/provider_preferences_dialog.rb +35 -0
  97. data/lib/alexandria/ui/really_delete_dialog.rb +53 -0
  98. data/lib/alexandria/ui/{sidepane.rb → sidepane_manager.rb} +62 -72
  99. data/lib/alexandria/ui/skip_entry_dialog.rb +33 -0
  100. data/lib/alexandria/ui/smart_library_properties_dialog.rb +60 -0
  101. data/lib/alexandria/ui/{dialogs/smart_library_properties_dialog_base.rb → smart_library_properties_dialog_base.rb} +96 -172
  102. data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
  103. data/lib/alexandria/ui/sound.rb +13 -13
  104. data/lib/alexandria/ui/ui_manager.rb +262 -283
  105. data/lib/alexandria/undo_manager.rb +3 -0
  106. data/lib/alexandria/version.rb +6 -19
  107. data/lib/alexandria/web_themes.rb +24 -21
  108. data/po/Makefile +2 -2
  109. data/po/cs.po +993 -880
  110. data/po/cy.po +957 -874
  111. data/po/de.po +990 -869
  112. data/po/el.po +989 -869
  113. data/po/es.po +985 -865
  114. data/po/fr.po +986 -870
  115. data/po/ga.po +907 -823
  116. data/po/gl.po +981 -865
  117. data/po/it.po +986 -868
  118. data/po/ja.po +969 -853
  119. data/po/mk.po +983 -863
  120. data/po/nb.po +979 -863
  121. data/po/nl.po +983 -864
  122. data/po/pl.po +1020 -969
  123. data/po/pt.po +988 -861
  124. data/po/pt_BR.po +984 -868
  125. data/po/ru.po +992 -873
  126. data/po/sk.po +987 -869
  127. data/po/sv.po +977 -861
  128. data/po/uk.po +975 -865
  129. data/po/zh_TW.po +976 -860
  130. data/schemas/alexandria.schemas +25 -3
  131. data/share/alexandria/glade/acquire_dialog__builder.glade +15 -12
  132. data/share/alexandria/glade/book_properties_dialog__builder.glade +171 -299
  133. data/share/alexandria/glade/main_app__builder.glade +24 -33
  134. data/share/alexandria/glade/new_book_dialog__builder.glade +27 -59
  135. data/share/alexandria/glade/preferences_dialog__builder.glade +250 -290
  136. data/share/gnome/help/alexandria/C/introduction.xml +0 -8
  137. data/share/gnome/help/alexandria/C/searching.xml +1 -1
  138. data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
  139. data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
  140. data/share/gnome/help/alexandria/fr/alexandria.xml +1 -1
  141. data/share/gnome/help/alexandria/ja/introduction.xml +0 -8
  142. data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
  143. data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
  144. data/spec/alexandria/book_providers_spec.rb +77 -210
  145. data/spec/alexandria/book_spec.rb +16 -12
  146. data/spec/alexandria/console_spec.rb +27 -0
  147. data/spec/alexandria/export_library_spec.rb +130 -0
  148. data/spec/alexandria/library_spec.rb +130 -172
  149. data/spec/alexandria/library_store_spec.rb +37 -0
  150. data/spec/alexandria/preferences_spec.rb +46 -17
  151. data/spec/alexandria/scanners/cue_cat_spec.rb +52 -0
  152. data/spec/alexandria/smart_library_spec.rb +32 -25
  153. data/spec/alexandria/ui/about_dialog_spec.rb +14 -0
  154. data/spec/alexandria/ui/acquire_dialog_spec.rb +14 -0
  155. data/spec/alexandria/ui/alert_dialog_spec.rb +16 -0
  156. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +14 -0
  157. data/spec/alexandria/ui/book_properties_dialog_spec.rb +17 -0
  158. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +14 -0
  159. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +16 -0
  160. data/spec/alexandria/ui/error_dialog_spec.rb +14 -0
  161. data/spec/alexandria/ui/export_dialog_spec.rb +15 -0
  162. data/spec/alexandria/ui/icons_spec.rb +26 -0
  163. data/spec/alexandria/ui/iconview_spec.rb +9 -21
  164. data/spec/alexandria/ui/import_dialog_spec.rb +41 -0
  165. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +17 -0
  166. data/spec/alexandria/ui/main_app_spec.rb +8 -33
  167. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +15 -0
  168. data/spec/alexandria/ui/new_book_dialog_spec.rb +22 -0
  169. data/spec/alexandria/ui/new_provider_dialog_spec.rb +30 -0
  170. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +39 -0
  171. data/spec/alexandria/ui/preferences_dialog_spec.rb +14 -0
  172. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +34 -0
  173. data/spec/alexandria/ui/really_delete_dialog_spec.rb +16 -0
  174. data/spec/alexandria/ui/sidepane_manager_spec.rb +15 -0
  175. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +14 -0
  176. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +32 -0
  177. data/spec/alexandria/ui/sound_spec.rb +4 -2
  178. data/spec/alexandria/ui/ui_manager_spec.rb +45 -20
  179. data/spec/end_to_end/basic_run_spec.rb +57 -0
  180. data/spec/spec_helper.rb +66 -33
  181. data/tasks/setup.rb +5 -3
  182. data/tasks/spec.rake +18 -3
  183. data/util/rake/fileinstall.rb +38 -40
  184. data/util/rake/gettextgenerate.rb +15 -70
  185. data/util/rake/omfgenerate.rb +10 -10
  186. metadata +176 -60
  187. data/INSTALL.rdoc +0 -148
  188. data/dogtail/basic_run_test.py +0 -9
  189. data/lib/alexandria/book_providers/bol_it.rb +0 -160
  190. data/lib/alexandria/book_providers/deastore.rb +0 -273
  191. data/lib/alexandria/book_providers/ibs_it.rb +0 -147
  192. data/lib/alexandria/book_providers/mcu.rb +0 -169
  193. data/lib/alexandria/book_providers/renaud.rb +0 -140
  194. data/lib/alexandria/book_providers/webster_it.rb +0 -167
  195. data/lib/alexandria/ui/dialogs/about_dialog.rb +0 -59
  196. data/lib/alexandria/ui/dialogs/alert_dialog.rb +0 -70
  197. data/lib/alexandria/ui/dialogs/bad_isbns_dialog.rb +0 -43
  198. data/lib/alexandria/ui/dialogs/export_dialog.rb +0 -171
  199. data/lib/alexandria/ui/dialogs/import_dialog.rb +0 -196
  200. data/lib/alexandria/ui/dialogs/misc_dialogs.rb +0 -85
  201. data/lib/alexandria/ui/dialogs/new_book_dialog_manual.rb +0 -154
  202. data/lib/alexandria/ui/dialogs/new_smart_library_dialog.rb +0 -74
  203. data/lib/alexandria/ui/dialogs/preferences_dialog.rb +0 -578
  204. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog.rb +0 -57
  205. data/spec/alexandria/scanners/cuecat_spec.rb +0 -65
  206. data/spec/alexandria/ui/dialogs_spec.rb +0 -94
  207. data/spec/alexandria/ui/sidepane_spec.rb +0 -27
  208. data/spec/alexandria/ui/ui_utilities_spec.rb +0 -60
  209. data/spec/alexandria/utilities_spec.rb +0 -50
  210. data/tasks/dogtail.rake +0 -4
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # -*- ruby -*-
2
4
  #--
3
5
  # Copyright (C) 2011 Cathal Mc Ginley
@@ -20,7 +22,7 @@
20
22
  # Boston, MA 02110-1301 USA.
21
23
  #++
22
24
 
23
- require 'gst'
25
+ require "gst"
24
26
 
25
27
  module Alexandria
26
28
  module UI
@@ -37,20 +39,20 @@ module Alexandria
37
39
  def play(effect)
38
40
  file = File.join(@sounds_dir, "#{effect}.ogg")
39
41
  if @playing
40
- puts "Already playing #{effect}." if $DEBUG
42
+ log.debug { "Already playing #{effect}." }
41
43
  else
42
- puts "Not playing. Starting #{effect}." if $DEBUG
44
+ log.debug { "Not playing. Starting #{effect}." }
43
45
  @filesrc.location = file
44
46
  start_playback
45
47
  end
46
48
  end
47
49
 
48
50
  def set_up_pipeline
49
- @filesrc = Gst::ElementFactory.make('filesrc')
50
- demuxer = Gst::ElementFactory.make('oggdemux')
51
- decoder = Gst::ElementFactory.make('vorbisdec')
52
- converter = Gst::ElementFactory.make('audioconvert') # #??
53
- audiosink = Gst::ElementFactory.make('autoaudiosink')
51
+ @filesrc = Gst::ElementFactory.make("filesrc")
52
+ demuxer = Gst::ElementFactory.make("oggdemux")
53
+ decoder = Gst::ElementFactory.make("vorbisdec")
54
+ converter = Gst::ElementFactory.make("audioconvert") # #??
55
+ audiosink = Gst::ElementFactory.make("autoaudiosink")
54
56
 
55
57
  @ogg_vorbis_pipeline.add(@filesrc, demuxer, decoder,
56
58
  converter, audiosink)
@@ -59,7 +61,7 @@ module Alexandria
59
61
  # this next must be a dynamic link, as demuxers potentially
60
62
  # have multiple src pads (for audio/video muxed streams)
61
63
 
62
- demuxer.signal_connect('pad-added') do |_parser, ogg_src_pad|
64
+ demuxer.signal_connect("pad-added") do |_parser, ogg_src_pad|
63
65
  vorbis_sink_pad = decoder.sinkpads.first
64
66
  ogg_src_pad.link(vorbis_sink_pad)
65
67
  end
@@ -74,10 +76,8 @@ module Alexandria
74
76
  when Gst::MessageType::EOS
75
77
  stop_playback
76
78
  when Gst::MessageType::ERROR
77
- if $DEBUG
78
- puts 'ERROR loop.quit'
79
- p message.parse
80
- end
79
+ log.debug { "ERROR loop.quit" }
80
+ log.debug { message.parse.inspect }
81
81
  stop_playback
82
82
  end
83
83
  true
@@ -1,36 +1,27 @@
1
- # Copyright (C) 2004-2006 Laurent Sansonetti
2
- # Copyright (C) 2008 Joseph Method
3
- # Copyright (C) 2011, 2016 Matijs van Zuijlen
4
- #
5
- # Alexandria is free software; you can redistribute it and/or
6
- # modify it under the terms of the GNU General Public License as
7
- # published by the Free Software Foundation; either version 2 of the
8
- # License, or (at your option) any later version.
9
- #
10
- # Alexandria is distributed in the hope that it will be useful,
11
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
- # General Public License for more details.
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Alexandria.
14
4
  #
15
- # You should have received a copy of the GNU General Public
16
- # License along with Alexandria; see the file COPYING. If not,
17
- # write to the Free Software Foundation, Inc., 51 Franklin Street,
18
- # Fifth Floor, Boston, MA 02110-1301 USA.
5
+ # See the file README.md for authorship and licensing information.
19
6
 
20
- require 'alexandria/ui/columns'
7
+ require "alexandria/ui/callbacks"
8
+ require "alexandria/ui/columns"
9
+ require "alexandria/ui/conflict_while_copying_dialog"
10
+ require "alexandria/library_sort_order"
21
11
 
22
12
  module Alexandria
23
13
  module UI
24
14
  class UIManager < BuilderBase
25
- attr_accessor :main_app, :actiongroup, :appbar, :prefs, :listview, :iconview, :listview_model,
26
- :iconview_model, :filtered_model
15
+ attr_accessor :main_app, :actiongroup, :appbar, :prefs, :listview, :iconview,
16
+ :listview_model, :iconview_model, :filtered_model
27
17
  attr_reader :model
18
+
28
19
  include Logging
29
20
  include GetText
30
- GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: 'UTF-8')
21
+ GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
31
22
 
32
23
  def initialize(parent)
33
- super('main_app__builder.glade', widget_names)
24
+ super("main_app__builder.glade", widget_names)
34
25
  @parent = parent
35
26
 
36
27
  @library_separator_iter = nil
@@ -58,7 +49,7 @@ module Alexandria
58
49
  log.debug { "UI Manager initialized: #{@iconview.model.inspect}" }
59
50
  @clicking_on_sidepane = true
60
51
 
61
- @library_listview.signal_connect('cursor-changed') do
52
+ @library_listview.signal_connect("cursor-changed") do
62
53
  @clicking_on_sidepane = true
63
54
  end
64
55
  end
@@ -74,24 +65,23 @@ module Alexandria
74
65
  end
75
66
 
76
67
  def create_uimanager
77
- log.debug { 'Adding actiongroup to uimanager' }
68
+ log.debug { "Adding actiongroup to uimanager" }
78
69
  @uimanager = Gtk::UIManager.new
79
70
  @uimanager.insert_action_group(@actiongroup, 0)
80
71
  end
81
72
 
82
73
  def setup_dependents
83
- @listview_model = Gtk::TreeModelSort.new(model: @filtered_model)
84
- @iconview_model = Gtk::TreeModelSort.new(model: @filtered_model)
74
+ @listview_model = Gtk::TreeModelSort.new(@filtered_model)
75
+ @iconview_model = Gtk::TreeModelSort.new(@filtered_model)
85
76
  @listview_manager = ListViewManager.new @listview, self
86
77
  @iconview_manager = IconViewManager.new @iconview, self
87
- @sidepane_manager = SidePaneManager.new @library_listview, self
78
+ @sidepane_manager = SidepaneManager.new @library_listview, self
88
79
  @library_listview = @sidepane_manager.library_listview
89
80
  @listview_manager.setup_listview_columns_visibility
90
81
  @listview_manager.setup_listview_columns_width
91
82
  end
92
83
 
93
84
  def setup_callbacks
94
- require 'alexandria/ui/callbacks'
95
85
  self.class.send(:include, Callbacks)
96
86
  connect_signals
97
87
  end
@@ -101,10 +91,10 @@ module Alexandria
101
91
  end
102
92
 
103
93
  def setup_toolbar
104
- log.debug { 'setup_toolbar' }
94
+ log.debug { "setup_toolbar" }
105
95
  setup_book_providers
106
96
  add_main_toolbar_items
107
- @toolbar = @uimanager.get_widget('/MainToolbar')
97
+ @toolbar = @uimanager.get_widget("/MainToolbar")
108
98
  @toolbar.show_arrow = true
109
99
  @toolbar.insert(Gtk::SeparatorToolItem.new, -1)
110
100
  setup_toolbar_combobox
@@ -112,18 +102,18 @@ module Alexandria
112
102
  @toolbar.insert(Gtk::SeparatorToolItem.new, -1)
113
103
  setup_toolbar_viewas
114
104
  @toolbar.show_all
115
- @actiongroup['Undo'].sensitive = @actiongroup['Redo'].sensitive = false
105
+ @actiongroup["Undo"].sensitive = @actiongroup["Redo"].sensitive = false
116
106
  UndoManager.instance.add_observer(self)
117
107
  @vbox1.add(@toolbar, position: 1, expand: false, fill: false)
118
108
  end
119
109
 
120
110
  def add_main_toolbar_items
121
111
  mid = @uimanager.new_merge_id
122
- @uimanager.add_ui(mid, 'ui/', 'MainToolbar', 'MainToolbar',
112
+ @uimanager.add_ui(mid, "ui/", "MainToolbar", "MainToolbar",
123
113
  :toolbar, false)
124
- @uimanager.add_ui(mid, 'ui/MainToolbar/', 'New', 'New',
114
+ @uimanager.add_ui(mid, "ui/MainToolbar/", "New", "New",
125
115
  :toolitem, false)
126
- @uimanager.add_ui(mid, 'ui/MainToolbar/', 'AddBook', 'AddBook',
116
+ @uimanager.add_ui(mid, "ui/MainToolbar/", "AddBook", "AddBook",
127
117
  :toolitem, false)
128
118
  # @uimanager.add_ui(mid, "ui/MainToolbar/", "sep", "sep",
129
119
  # :separator, false)
@@ -133,11 +123,11 @@ module Alexandria
133
123
 
134
124
  def setup_toolbar_filter_entry
135
125
  @filter_entry = Gtk::Entry.new
136
- @filter_entry.signal_connect('changed', &method(:on_toolbar_filter_entry_changed))
126
+ @filter_entry.signal_connect("changed", &method(:on_toolbar_filter_entry_changed))
137
127
  @toolitem = Gtk::ToolItem.new
138
128
  @toolitem.expand = true
139
129
  @toolitem.border_width = 5
140
- @filter_entry.set_tooltip_text _('Type here the search criterion')
130
+ @filter_entry.set_tooltip_text _("Type here the search criterion")
141
131
  @toolitem << @filter_entry
142
132
  @toolbar.insert(@toolitem, -1)
143
133
  end
@@ -146,20 +136,20 @@ module Alexandria
146
136
  cb = Gtk::ComboBoxText.new
147
137
  cb.set_row_separator_func do |model, iter|
148
138
  # TODO: Replace with iter[0] if possible
149
- model.get_value(iter, 0) == '-'
139
+ model.get_value(iter, 0) == "-"
150
140
  end
151
- [_('Match everything'),
152
- '-',
153
- _('Title contains'),
154
- _('Authors contain'),
155
- _('ISBN contains'),
156
- _('Publisher contains'),
157
- _('Notes contain'),
158
- _('Tags contain')].each do |item|
141
+ [_("Match everything"),
142
+ "-",
143
+ _("Title contains"),
144
+ _("Authors contain"),
145
+ _("ISBN contains"),
146
+ _("Publisher contains"),
147
+ _("Notes contain"),
148
+ _("Tags contain")].each do |item|
159
149
  cb.append_text(item)
160
150
  end
161
151
  cb.active = 0
162
- cb.signal_connect('changed', &method(:on_criterion_combobox_changed))
152
+ cb.signal_connect("changed", &method(:on_criterion_combobox_changed))
163
153
 
164
154
  # Put the combo box in a event box because it is not currently
165
155
  # possible assign a tooltip to a combo box.
@@ -169,16 +159,16 @@ module Alexandria
169
159
  @toolitem.border_width = 5
170
160
  @toolitem << eb
171
161
  @toolbar.insert(@toolitem, -1)
172
- eb.set_tooltip_text _('Change the search type')
162
+ eb.set_tooltip_text _("Change the search type")
173
163
  end
174
164
 
175
165
  def setup_toolbar_viewas
176
166
  @toolbar_view_as = Gtk::ComboBoxText.new
177
- @toolbar_view_as.append_text(_('View as Icons'))
178
- @toolbar_view_as.append_text(_('View as List'))
167
+ @toolbar_view_as.append_text(_("View as Icons"))
168
+ @toolbar_view_as.append_text(_("View as List"))
179
169
  @toolbar_view_as.active = 0
180
170
  @toolbar_view_as_signal_hid = \
181
- @toolbar_view_as.signal_connect('changed', &method(:on_toolbar_view_as_changed))
171
+ @toolbar_view_as.signal_connect("changed", &method(:on_toolbar_view_as_changed))
182
172
 
183
173
  # Put the combo box in a event box because it is not currently
184
174
  # possible assign a tooltip to a combo box.
@@ -188,59 +178,60 @@ module Alexandria
188
178
  @toolitem.border_width = 5
189
179
  @toolitem << eb
190
180
  @toolbar.insert(@toolitem, -1)
191
- eb.set_tooltip_text _('Choose how to show books')
181
+ eb.set_tooltip_text _("Choose how to show books")
192
182
  end
193
183
 
194
184
  def setup_book_providers
195
- log.debug { 'setup_book_providers' }
185
+ log.debug { "setup_book_providers" }
196
186
  mid = @uimanager.new_merge_id
197
- BookProviders.each do |provider|
187
+ ui_paths = ["ui/MainMenubar/ViewMenu/OnlineInformation/",
188
+ "ui/BookPopup/OnlineInformation/",
189
+ "ui/NoBookPopup/OnlineInformation/"]
190
+ BookProviders.list.each do |provider|
198
191
  name = provider.action_name
199
- ['ui/MainMenubar/ViewMenu/OnlineInformation/',
200
- 'ui/BookPopup/OnlineInformation/',
201
- 'ui/NoBookPopup/OnlineInformation/'].each do |path|
202
- log.debug { "Adding #{name} to #{path}" }
203
- @uimanager.add_ui(mid, path, name, name,
204
- :menuitem, false)
205
- end
192
+ ui_paths.each do |path|
193
+ log.debug { "Adding #{name} to #{path}" }
194
+ @uimanager.add_ui(mid, path, name, name,
195
+ :menuitem, false)
196
+ end
206
197
  end
207
198
  end
208
199
 
209
200
  def add_menus_and_popups_from_xml
210
- log.debug { 'add_menus_and_popups_from_xml' }
211
- ['menus.xml', 'popups.xml'].each do |ui_file|
201
+ log.debug { "add_menus_and_popups_from_xml" }
202
+ ["menus.xml", "popups.xml"].each do |ui_file|
212
203
  @uimanager.add_ui(File.join(Alexandria::Config::DATA_DIR,
213
- 'ui', ui_file))
204
+ "ui", ui_file))
214
205
  end
215
206
  end
216
207
 
217
208
  def setup_accel_group
218
- log.debug { 'setup_accel_group' }
209
+ log.debug { "setup_accel_group" }
219
210
  @main_app.add_accel_group(@uimanager.accel_group)
220
211
  end
221
212
 
222
213
  def setup_menus
223
- @menubar = @uimanager.get_widget('/MainMenubar')
214
+ @menubar = @uimanager.get_widget("/MainMenubar")
224
215
  @vbox1.add(@menubar, position: 0, expand: false, fill: false)
225
216
  end
226
217
 
227
218
  def setup_popups
228
- log.debug { 'setup_popups' }
229
- @library_popup = @uimanager.get_widget('/LibraryPopup')
230
- @smart_library_popup = @uimanager.get_widget('/SmartLibraryPopup')
231
- @nolibrary_popup = @uimanager.get_widget('/NoLibraryPopup')
232
- @book_popup = @uimanager.get_widget('/BookPopup')
233
- @nobook_popup = @uimanager.get_widget('/NoBookPopup')
219
+ log.debug { "setup_popups" }
220
+ @library_popup = @uimanager.get_widget("/LibraryPopup")
221
+ @smart_library_popup = @uimanager.get_widget("/SmartLibraryPopup")
222
+ @nolibrary_popup = @uimanager.get_widget("/NoLibraryPopup")
223
+ @book_popup = @uimanager.get_widget("/BookPopup")
224
+ @nobook_popup = @uimanager.get_widget("/NoBookPopup")
234
225
  end
235
226
 
236
227
  def setup_window_events
237
- log.debug { 'setup_window_events' }
238
- @main_app.signal_connect('window-state-event', &method(:on_window_state_event))
239
- @main_app.signal_connect('destroy', &method(:on_window_destroy))
228
+ log.debug { "setup_window_events" }
229
+ @main_app.signal_connect("window-state-event", &method(:on_window_state_event))
230
+ @main_app.signal_connect("destroy", &method(:on_window_destroy))
240
231
  end
241
232
 
242
233
  def setup_active_model
243
- log.debug { 'setting up active model' }
234
+ log.debug { "setting up active model" }
244
235
  # The active model.
245
236
 
246
237
  list = [
@@ -275,13 +266,13 @@ module Alexandria
275
266
  true
276
267
  else
277
268
  data = case @filter_books_mode
278
- when 0 then
279
- (iter[Columns::TITLE] || '') +
280
- (iter[Columns::AUTHORS] || '') +
281
- (iter[Columns::ISBN] || '') +
282
- (iter[Columns::PUBLISHER] || '') +
283
- (iter[Columns::NOTES] || '') +
284
- (iter[Columns::TAGS] || '')
269
+ when 0
270
+ (iter[Columns::TITLE] || "") +
271
+ (iter[Columns::AUTHORS] || "") +
272
+ (iter[Columns::ISBN] || "") +
273
+ (iter[Columns::PUBLISHER] || "") +
274
+ (iter[Columns::NOTES] || "") +
275
+ (iter[Columns::TAGS] || "")
285
276
  when 2 then iter[Columns::TITLE]
286
277
  when 3 then iter[Columns::AUTHORS]
287
278
  when 4 then iter[Columns::ISBN]
@@ -295,19 +286,20 @@ module Alexandria
295
286
 
296
287
  # Give filter entry the initial keyboard focus.
297
288
  @filter_entry.grab_focus
298
- log.debug { 'done setting up active model' }
289
+ log.debug { "done setting up active model" }
299
290
  end
300
291
 
301
292
  def on_library_button_press_event(widget, event)
302
- log.debug { 'library_button_press_event' }
293
+ log.debug { "library_button_press_event" }
303
294
 
304
295
  # right click
305
296
  if event_is_right_click event
306
- log.debug { 'library right click!' }
297
+ log.debug { "library right click!" }
307
298
  library_already_selected = true
308
299
  if (path = widget.get_path_at_pos(event.x, event.y))
309
300
  @clicking_on_sidepane = true
310
- obj, path = widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
301
+ obj, path =
302
+ widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
311
303
  widget.has_focus = true
312
304
 
313
305
  unless obj.path_is_selected?(path)
@@ -348,40 +340,31 @@ module Alexandria
348
340
  # seem to suffice).
349
341
  #
350
342
  # Then we wait a while and only *then* pop up the menu.
343
+ sensitize_library selected_library if library_already_selected
351
344
 
352
- if library_already_selected
353
- sensitize_library selected_library
354
-
355
- GLib::Idle.add do
356
- menu.popup(nil, nil, event.button, event.time)
357
- # @clicking_on_sidepane = false
358
- false
359
- end
360
- else
361
- GLib::Idle.add do
362
- menu.popup(nil, nil, event.button, event.time)
363
- # @clicking_on_sidepane = false
364
-
365
- false
366
- end
345
+ GLib::Idle.add do
346
+ menu.popup(nil, nil, event.button, event.time)
347
+ false
367
348
  end
368
349
 
369
- else
370
350
  # not a right click
371
- if (path = widget.get_path_at_pos(event.x, event.y))
372
- @clicking_on_sidepane = true
373
- obj, path = widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
374
- obj.select_path(path)
375
- sensitize_library selected_library
376
-
377
- end
378
-
351
+ elsif (path = widget.get_path_at_pos(event.x, event.y))
352
+ @clicking_on_sidepane = true
353
+ obj, path =
354
+ widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
355
+ obj.select_path(path)
356
+ sensitize_library selected_library
379
357
  end
380
358
  end
381
359
 
382
360
  def determine_library_popup(widget, event)
383
- # widget.grab_focus
384
- widget.get_path_at_pos(event.x, event.y).nil? ? @nolibrary_popup : selected_library.is_a?(SmartLibrary) ? @smart_library_popup : @library_popup
361
+ if widget.get_path_at_pos(event.x, event.y).nil?
362
+ @nolibrary_popup
363
+ elsif selected_library.is_a?(SmartLibrary)
364
+ @smart_library_popup
365
+ else
366
+ @library_popup
367
+ end
385
368
  end
386
369
 
387
370
  def event_is_right_click(event)
@@ -389,25 +372,26 @@ module Alexandria
389
372
  end
390
373
 
391
374
  def on_books_button_press_event(widget, event)
392
- log.debug { 'books_button_press_event' }
393
- if event_is_right_click event
394
- widget.grab_focus
375
+ log.debug { "books_button_press_event" }
376
+ event_is_right_click event or return
395
377
 
396
- if (path = widget.get_path_at_pos(event.x.to_i, event.y.to_i))
397
- obj, path = widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
378
+ widget.grab_focus
398
379
 
399
- unless obj.path_is_selected?(path)
400
- log.debug { "Select #{path}" }
401
- widget.unselect_all
402
- obj.select_path(path)
403
- end
404
- else
380
+ if (path = widget.get_path_at_pos(event.x.to_i, event.y.to_i))
381
+ obj, path =
382
+ widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
383
+
384
+ unless obj.path_is_selected?(path)
385
+ log.debug { "Select #{path}" }
405
386
  widget.unselect_all
387
+ obj.select_path(path)
406
388
  end
407
-
408
- menu = selected_books.empty? ? @nobook_popup : @book_popup
409
- menu.popup(nil, nil, event.button, event.time)
389
+ else
390
+ widget.unselect_all
410
391
  end
392
+
393
+ menu = selected_books.empty? ? @nobook_popup : @book_popup
394
+ menu.popup(nil, nil, event.button, event.time)
411
395
  end
412
396
 
413
397
  def get_library_selection_text(library)
@@ -418,23 +402,19 @@ module Alexandria
418
402
  else
419
403
  n_unrated = library.n_unrated
420
404
  if n_unrated == library.length
421
- n_("Library '%s' selected, %d unrated book",
422
- "Library '%s' selected, %d unrated books",
423
- library.length) % [library.name,
424
- library.length]
405
+ format(n_("Library '%s' selected, %d unrated book",
406
+ "Library '%s' selected, %d unrated books",
407
+ library.length), library.name, library.length)
425
408
  elsif n_unrated.zero?
426
- n_("Library '%s' selected, %d book",
427
- "Library '%s' selected, %d books",
428
- library.length) % [library.name,
429
- library.length]
409
+ format(n_("Library '%s' selected, %d book",
410
+ "Library '%s' selected, %d books",
411
+ library.length), library.name, library.length)
430
412
  else
431
- n_("Library '%s' selected, %d book, " \
432
- '%d unrated',
433
- "Library '%s' selected, %d books, " \
434
- '%d unrated',
435
- library.length) % [library.name,
436
- library.length,
437
- n_unrated]
413
+ format(n_("Library '%s' selected, %d book, " \
414
+ "%d unrated",
415
+ "Library '%s' selected, %d books, " \
416
+ "%d unrated",
417
+ library.length), library.name, library.length, n_unrated)
438
418
  end
439
419
  end
440
420
  end
@@ -446,7 +426,7 @@ module Alexandria
446
426
  when 1
447
427
  _("'%s' selected") % books.first.title
448
428
  else
449
- n_('%d book selected', '%d books selected',
429
+ n_("%d book selected", "%d books selected",
450
430
  books.length) % books.length
451
431
  end
452
432
  end
@@ -459,7 +439,6 @@ module Alexandria
459
439
  library = selected_library
460
440
  books = selected_books
461
441
  set_status_label(get_appbar_status(library, books))
462
- # selection = @library_listview.selection.selected ? @library_listview.selection.selected.has_focus? : false
463
442
 
464
443
  # Focus is the wrong idiom here.
465
444
  unless @clicking_on_sidepane || (@main_app.focus == @library_listview)
@@ -467,25 +446,30 @@ module Alexandria
467
446
 
468
447
  log.debug { "Currently focused widget: #{@main_app.focus.inspect}" }
469
448
  log.debug { "#{@library_listview} : #{@library_popup} : #{@listview}" }
470
- log.debug { "@library_listview: #{@library_listview.has_focus?} or @library_popup:#{@library_popup.has_focus?}" } # or selection: #{selection}"}
471
- log.debug { '@library_listview does *NOT* have focus' }
449
+ log.debug do
450
+ "@library_listview: #{@library_listview.has_focus?} " \
451
+ "or @library_popup:#{@library_popup.has_focus?}"
452
+ end
453
+ log.debug { "@library_listview does *NOT* have focus" }
472
454
  log.debug { "Books are empty: #{books.empty?}" }
473
- @actiongroup['Properties'].sensitive = \
474
- @actiongroup['OnlineInformation'].sensitive = \
455
+ @actiongroup["Properties"].sensitive = \
456
+ @actiongroup["OnlineInformation"].sensitive = \
475
457
  books.length == 1
476
- @actiongroup['SelectAll'].sensitive = \
458
+ @actiongroup["SelectAll"].sensitive = \
477
459
  books.length < library.length
478
460
 
479
- @actiongroup['Delete'].sensitive = \
480
- @actiongroup['DeselectAll'].sensitive = \
481
- @actiongroup['Move'].sensitive =
482
- @actiongroup['SetRating'].sensitive = !books.empty?
461
+ @actiongroup["Delete"].sensitive = \
462
+ @actiongroup["DeselectAll"].sensitive = \
463
+ @actiongroup["Move"].sensitive =
464
+ @actiongroup["SetRating"].sensitive = !books.empty?
483
465
 
484
- log.debug { "on_books_selection_changed Delete: #{@actiongroup['Delete'].sensitive?}" }
466
+ log.debug do
467
+ "on_books_selection_changed Delete: #{@actiongroup['Delete'].sensitive?}"
468
+ end
485
469
 
486
470
  if library.is_a?(SmartLibrary)
487
- @actiongroup['Delete'].sensitive =
488
- @actiongroup['Move'].sensitive = false
471
+ @actiongroup["Delete"].sensitive =
472
+ @actiongroup["Move"].sensitive = false
489
473
  end
490
474
 
491
475
  # Sensitize providers URL
@@ -493,39 +477,37 @@ module Alexandria
493
477
  b = books.first
494
478
  # FIXME: Clean up endless negation in this logic
495
479
  no_urls = true
496
- BookProviders.each do |provider|
480
+ BookProviders.list.each do |provider|
497
481
  has_no_url = true
498
482
  begin
499
483
  has_no_url = (b.isbn.nil? || b.isbn.strip.empty? || provider.url(b).nil?)
500
- rescue => ex
484
+ rescue StandardError => ex
501
485
  log.warn { "Error determining URL from #{provider.name}; #{ex.message}" }
502
486
  end
503
487
  @actiongroup[provider.action_name].sensitive = !has_no_url
504
488
  no_urls = false unless has_no_url
505
489
  end
506
- if no_urls
507
- @actiongroup['OnlineInformation'].sensitive = false
508
- end
490
+ @actiongroup["OnlineInformation"].sensitive = false if no_urls
509
491
  end
510
492
  end
511
493
  @clicking_on_sidepane = false
512
494
  end
513
495
 
514
496
  def on_switch_page(_notebook, _page, page_num)
515
- log.debug { 'on_switch_page' }
516
- @actiongroup['ArrangeIcons'].sensitive = page_num.zero?
497
+ log.debug { "on_switch_page" }
498
+ @actiongroup["ArrangeIcons"].sensitive = page_num.zero?
517
499
  on_books_selection_changed
518
500
  end
519
501
 
520
502
  def on_focus(widget, _event_focus)
521
503
  if @clicking_on_sidepane || (widget == @library_listview)
522
- log.debug { 'on_focus: @library_listview' }
504
+ log.debug { "on_focus: @library_listview" }
523
505
  GLib::Idle.add do
524
506
  %w(OnlineInformation SelectAll DeselectAll).each do |action|
525
507
  @actiongroup[action].sensitive = false
526
508
  end
527
- @actiongroup['Properties'].sensitive = selected_library.is_a?(SmartLibrary)
528
- @actiongroup['Delete'].sensitive = determine_delete_option
509
+ @actiongroup["Properties"].sensitive = selected_library.is_a?(SmartLibrary)
510
+ @actiongroup["Delete"].sensitive = determine_delete_option
529
511
  false
530
512
  end
531
513
  else
@@ -534,52 +516,33 @@ module Alexandria
534
516
  end
535
517
 
536
518
  def determine_delete_option
537
- sensitive = (@libraries.all_regular_libraries.length > 1 || selected_library.is_a?(SmartLibrary))
538
- sensitive
519
+ @libraries.all_regular_libraries.length > 1 || selected_library.is_a?(SmartLibrary)
539
520
  end
540
521
 
541
522
  def on_close_sidepane
542
- log.debug { 'on_close_sidepane' }
543
- @actiongroup['Sidepane'].active = false
523
+ log.debug { "on_close_sidepane" }
524
+ @actiongroup["Sidepane"].active = false
544
525
  end
545
526
 
527
+ # TODO: Figure out why this frequently selects the wrong book!
546
528
  def select_a_book(book)
547
- select_this_book = proc do |bk, view|
548
- @filtered_model.refilter
549
- iter = iter_from_book bk
550
- next unless iter
551
- path = iter.path
552
- next unless view.model
553
- path = view_path_to_model_path(view, path)
554
- log.debug { "Path for #{bk.ident} is #{path}" }
555
- selection = view.respond_to?(:selection) ? @listview.selection : @iconview
556
- selection.unselect_all
557
- selection.select_path(path)
558
- end
559
- begin
560
- log.debug { 'select_a_book: listview' }
561
- select_this_book.call(book, @listview)
562
- log.debug { 'select_a_book: listview' }
563
- select_this_book.call(book, @iconview)
564
- rescue => ex
565
- trace = ex.backtrace.join("\n> ")
566
- log.warn { "Failed to automatically select book: #{ex.message} #{trace}" }
567
- end
568
- # TODO: Figure out why this frequently selects the wrong book!
529
+ log.debug { "select_a_book: listview" }
530
+ select_book_in_view(book, @listview)
531
+ log.debug { "select_a_book: iconview" }
532
+ select_book_in_view(book, @iconview)
569
533
  end
570
534
 
571
535
  def update(*ary)
572
536
  log.debug { "on_update #{ary}" }
573
537
  caller = ary.first
574
- if caller.is_a?(UndoManager)
575
- @actiongroup['Undo'].sensitive = caller.can_undo?
576
- @actiongroup['Redo'].sensitive = caller.can_redo?
577
- elsif caller.is_a?(Library)
578
- unless caller.updating?
579
- handle_update_caller_library ary
580
- end
538
+ case caller
539
+ when UndoManager
540
+ @actiongroup["Undo"].sensitive = caller.can_undo?
541
+ @actiongroup["Redo"].sensitive = caller.can_redo?
542
+ when Library
543
+ handle_update_caller_library ary unless caller.updating?
581
544
  else
582
- raise 'unrecognized update event'
545
+ raise _("unrecognized update event")
583
546
  end
584
547
  end
585
548
 
@@ -605,18 +568,16 @@ module Alexandria
605
568
  end
606
569
  end
607
570
 
608
- # private
609
-
610
571
  def open_web_browser(url)
611
572
  if url.nil?
612
- log.warn('Attempt to open browser with nil url')
573
+ log.warn("Attempt to open browser with nil url")
613
574
  return
614
575
  end
615
576
  Gtk.show_uri url
616
577
  end
617
578
 
618
579
  def detach_old_libraries
619
- log.debug { 'Un-observing old libraries' }
580
+ log.debug { "Un-observing old libraries" }
620
581
  @libraries.all_regular_libraries.each do |library|
621
582
  if library.is_a?(Library)
622
583
  library.delete_observer(self)
@@ -626,13 +587,13 @@ module Alexandria
626
587
  end
627
588
 
628
589
  def load_libraries
629
- log.info { 'Loading Libraries...' }
590
+ log.info { _("Loading libraries...") }
630
591
  @completion_models = CompletionModels.instance
631
592
  if @libraries
632
593
  detach_old_libraries
633
594
  @libraries.reload
634
595
  else
635
- @libraries = Libraries.instance
596
+ @libraries = LibraryCollection.instance
636
597
  @libraries.reload
637
598
  handle_ruined_books unless @libraries.ruined_books.empty?
638
599
  end
@@ -643,23 +604,20 @@ module Alexandria
643
604
  end
644
605
 
645
606
  def handle_ruined_books
646
- new_message = _("The data files for the following books are malformed or empty. Do you wish to attempt to download new information for them from the online book providers?\n")
647
-
648
- # message = _("These books do not conform to the ISBN-13
649
- # standard. We will attempt to replace them from the book
650
- # providers. Otherwise, we will turn them into manual
651
- # entries.\n" )
607
+ new_message = _(
608
+ "The data files for the following books are malformed or empty. Do you wish to" \
609
+ " attempt to download new information for them from the online book providers?\n")
652
610
 
653
- @libraries.ruined_books.each { |bi|
611
+ @libraries.ruined_books.each do |bi|
654
612
  new_message += "\n#{bi[1] || bi[1].inspect}"
655
- }
613
+ end
656
614
  recovery_dialog = Gtk::MessageDialog.new(@main_app, Gtk::Dialog::MODAL,
657
615
  Gtk::MessageDialog::WARNING,
658
616
  Gtk::MessageDialog::BUTTONS_OK_CANCEL,
659
617
  new_message).show
660
- recovery_dialog.signal_connect('response') do |_dialog, response_type|
618
+ recovery_dialog.signal_connect("response") do |_dialog, response_type|
661
619
  recovery_dialog.destroy
662
- if response_type == :ok
620
+ if response_type == Gtk::ResponseType::OK
663
621
  # progress indicator...
664
622
  @progressbar.fraction = 0
665
623
  @appbar.children.first.visible = true # show the progress bar
@@ -686,20 +644,21 @@ module Alexandria
686
644
  log.debug { "removing old file #{filename}" }
687
645
  begin
688
646
  File.delete(filename)
689
- rescue => ex
647
+ rescue StandardError => ex
690
648
  log.error { "Could not delete empty file #{filename}" }
691
649
  end
692
650
  end
693
651
 
694
- log.debug { "Trying to add #{book.title}, #{cover_uri} in library ''#{library.name}'" }
695
- unless cover_uri.nil?
696
- library.save_cover(book, cover_uri)
652
+ log.debug do
653
+ "Trying to add #{book.title}, #{cover_uri}" \
654
+ " in library ''#{library.name}'"
697
655
  end
656
+ library.save_cover(book, cover_uri) unless cover_uri.nil?
698
657
  library << book
699
658
  library.save(book)
700
- set_status_label(_("Added '%s' to library '%s'") % [book.title, library.name])
701
-
702
- rescue => ex
659
+ set_status_label(format(_("Added '%s' to library '%s'"),
660
+ book.title, library.name))
661
+ rescue StandardError => ex
703
662
  log.error { "Couldn't add book #{isbn}: #{ex}" }
704
663
  log.error { ex.backtrace.join("\n") }
705
664
  end
@@ -720,7 +679,7 @@ module Alexandria
720
679
  ## Hide the progress bar.
721
680
  @appbar.children.first.visible = false
722
681
  ## Refresh the status bar.
723
- set_status_label('')
682
+ set_status_label("")
724
683
  # on_books_selection_changed
725
684
  false
726
685
  end
@@ -745,22 +704,23 @@ module Alexandria
745
704
  iter[Columns::TITLE] = book.title
746
705
  title = book.title.sub(REDUCE_TITLE_REGEX, '\1...')
747
706
  iter[Columns::TITLE_REDUCED] = title
748
- iter[Columns::AUTHORS] = book.authors.join(', ')
707
+ iter[Columns::AUTHORS] = book.authors.join(", ")
749
708
  iter[Columns::ISBN] = book.isbn.to_s
750
709
  iter[Columns::PUBLISHER] = book.publisher
751
710
  iter[Columns::PUBLISH_DATE] = book.publishing_year.to_s
752
711
  iter[Columns::EDITION] = book.edition
753
- iter[Columns::NOTES] = (book.notes || '')
754
- iter[Columns::LOANED_TO] = (book.loaned_to || '')
712
+ iter[Columns::NOTES] = (book.notes || "")
713
+ iter[Columns::LOANED_TO] = (book.loaned_to || "")
755
714
  rating = (book.rating || Book::DEFAULT_RATING)
756
- iter[Columns::RATING] = Book::MAX_RATING_STARS - rating # ascending order is the default
715
+ # ascending order is the default
716
+ iter[Columns::RATING] = Book::MAX_RATING_STARS - rating
757
717
  iter[Columns::OWN] = book.own?
758
718
  iter[Columns::REDD] = book.redd?
759
719
  iter[Columns::WANT] = book.want?
760
720
  iter[Columns::TAGS] = if book.tags
761
- book.tags.join(',')
721
+ book.tags.join(",")
762
722
  else
763
- ''
723
+ ""
764
724
  end
765
725
 
766
726
  icon = Icons.cover(selected_library, book)
@@ -772,11 +732,9 @@ module Alexandria
772
732
  new_height = [ICON_HEIGHT, icon.height].min
773
733
  icon = cache_scaled_icon(icon, new_width, new_height)
774
734
  end
775
- if rating == Book::MAX_RATING_STARS
776
- icon = icon.tag(Icons::FAVORITE_TAG)
777
- end
735
+ icon = Icons.tag_icon(icon, Icons::FAVORITE_TAG) if rating == Book::MAX_RATING_STARS
778
736
  iter[Columns::COVER_ICON] = icon
779
- log.debug { 'Full iter: ' + (0..15).map { |num| iter[num].inspect }.join(', ') }
737
+ log.debug { "Full iter: " + (0..15).map { |num| iter[num].inspect }.join(", ") }
780
738
  end
781
739
 
782
740
  def append_book(book, _tail = nil)
@@ -786,7 +744,7 @@ module Alexandria
786
744
  if iter
787
745
  fill_iter_with_book(iter, book)
788
746
  else
789
- log.debug { '@model.append' }
747
+ log.debug { "@model.append" }
790
748
  iter = @model.append
791
749
  fill_iter_with_book(iter, book)
792
750
  log.debug { "no iter for book #{book}" }
@@ -805,9 +763,7 @@ module Alexandria
805
763
  model = @library_listview.model
806
764
  is_smart = library.is_a?(SmartLibrary)
807
765
  if is_smart
808
- if @library_separator_iter.nil?
809
- @library_separator_iter = append_library_separator
810
- end
766
+ @library_separator_iter = append_library_separator if @library_separator_iter.nil?
811
767
  iter = model.append
812
768
  else
813
769
  iter = if @library_separator_iter.nil?
@@ -825,13 +781,13 @@ module Alexandria
825
781
  @library_listview.set_cursor(iter.path,
826
782
  @library_listview.get_column(0),
827
783
  true)
828
- @actiongroup['Sidepane'].active = true
784
+ @actiongroup["Sidepane"].active = true
829
785
  end
830
786
  iter
831
787
  end
832
788
 
833
789
  def append_library_separator
834
- log.debug { 'append_library_separator' }
790
+ log.debug { "append_library_separator" }
835
791
  iter = @library_listview.model.append
836
792
  iter[0] = nil
837
793
  iter[1] = nil
@@ -841,12 +797,12 @@ module Alexandria
841
797
  end
842
798
 
843
799
  def refresh_books
844
- log.debug { 'refresh_books' }
800
+ log.debug { "refresh_books" }
845
801
  @library_listview.set_sensitive(false)
846
802
  library = selected_library
847
- @model.clear
848
803
  @iconview.freeze
849
- @listview.freeze # NEW / bdewey
804
+ @listview.freeze
805
+ @model.clear
850
806
  @progressbar.fraction = 0
851
807
  @appbar.children.first.visible = true # show the progress bar
852
808
  set_status_label(_("Loading '%s'...") % library.name)
@@ -860,7 +816,7 @@ module Alexandria
860
816
  if book
861
817
  begin
862
818
  append_book(book)
863
- rescue => ex
819
+ rescue StandardError => ex
864
820
  trace = ex.backtrace.join("\n > ")
865
821
  log.error { "append_books failed #{ex.message} #{trace}" }
866
822
  end
@@ -887,9 +843,10 @@ module Alexandria
887
843
  end
888
844
 
889
845
  def selected_library
890
- log.debug { 'selected_library' }
846
+ log.debug { "selected_library" }
891
847
  if (iter = @library_listview.selection.selected)
892
- @libraries.all_libraries.find { |x| x.name == iter[1] }
848
+ target_name = iter[1]
849
+ @libraries.all_libraries.find { |it| it.name == target_name }
893
850
  else
894
851
  @libraries.all_libraries.first
895
852
  end
@@ -916,9 +873,10 @@ module Alexandria
916
873
  def iter_from_ident(ident)
917
874
  log.debug { ident.to_s }
918
875
  iter = @model.iter_first
919
- ok = true
876
+ ok = true if iter
920
877
  while ok
921
878
  return iter if iter[Columns::IDENT] == ident
879
+
922
880
  ok = iter.next!
923
881
  end
924
882
  nil
@@ -957,11 +915,11 @@ module Alexandria
957
915
  end
958
916
 
959
917
  def refresh_libraries
960
- log.debug { 'refresh_libraries' }
918
+ log.debug { "refresh_libraries" }
961
919
  library = selected_library
962
920
 
963
921
  # Change the application's title.
964
- @main_app.title = library.name + ' - ' + TITLE
922
+ @main_app.title = library.name + " - " + TITLE
965
923
 
966
924
  # Disable the selected library in the move libraries actions.
967
925
  @libraries.all_regular_libraries.each do |i_library|
@@ -975,11 +933,11 @@ module Alexandria
975
933
  smart = library.is_a?(SmartLibrary)
976
934
  log.debug { "sensitize_library: smartlibrary = #{smart}" }
977
935
  GLib::Idle.add do
978
- @actiongroup['AddBook'].sensitive = !smart
979
- @actiongroup['AddBookManual'].sensitive = !smart
980
- @actiongroup['Properties'].sensitive = smart
936
+ @actiongroup["AddBook"].sensitive = !smart
937
+ @actiongroup["AddBookManual"].sensitive = !smart
938
+ @actiongroup["Properties"].sensitive = smart
981
939
  can_delete = smart || (@libraries.all_regular_libraries.length > 1)
982
- @actiongroup['Delete'].sensitive = can_delete ## true #(@libraries.all_regular_libraries.length > 1)
940
+ @actiongroup["Delete"].sensitive = can_delete
983
941
  log.debug { "sensitize_library delete: #{@actiongroup['Delete'].sensitive?}" }
984
942
  false
985
943
  end
@@ -988,14 +946,14 @@ module Alexandria
988
946
  def get_view_actiongroup
989
947
  case @prefs.view_as
990
948
  when 0
991
- @actiongroup['AsIcons']
949
+ @actiongroup["AsIcons"]
992
950
  when 1
993
- @actiongroup['AsList']
951
+ @actiongroup["AsList"]
994
952
  end
995
953
  end
996
954
 
997
955
  def restore_preferences
998
- log.debug { 'Restoring preferences...' }
956
+ log.debug { "Restoring preferences" }
999
957
  if @prefs.maximized
1000
958
  @main_app.maximize
1001
959
  else
@@ -1004,9 +962,9 @@ module Alexandria
1004
962
  @maximized = false
1005
963
  end
1006
964
  @paned.position = @prefs.sidepane_position
1007
- @actiongroup['Sidepane'].active = @prefs.sidepane_visible
1008
- @actiongroup['Toolbar'].active = @prefs.toolbar_visible
1009
- @actiongroup['Statusbar'].active = @prefs.statusbar_visible
965
+ @actiongroup["Sidepane"].active = @prefs.sidepane_visible
966
+ @actiongroup["Toolbar"].active = @prefs.toolbar_visible
967
+ @actiongroup["Statusbar"].active = @prefs.statusbar_visible
1010
968
  @appbar.visible = @prefs.statusbar_visible
1011
969
  action = get_view_actiongroup
1012
970
  action.activate
@@ -1030,29 +988,29 @@ module Alexandria
1030
988
  end
1031
989
 
1032
990
  def save_preferences
1033
- log.debug { 'save_preferences' }
991
+ log.debug { "save_preferences" }
1034
992
  @prefs.position = @main_app.position
1035
993
  @prefs.size = @main_app.allocation.to_a[2..3]
1036
994
  @prefs.maximized = @maximized
1037
995
  @prefs.sidepane_position = @paned.position
1038
- @prefs.sidepane_visible = @actiongroup['Sidepane'].active?
1039
- @prefs.toolbar_visible = @actiongroup['Toolbar'].active?
1040
- @prefs.statusbar_visible = @actiongroup['Statusbar'].active?
996
+ @prefs.sidepane_visible = @actiongroup["Sidepane"].active?
997
+ @prefs.toolbar_visible = @actiongroup["Toolbar"].active?
998
+ @prefs.statusbar_visible = @actiongroup["Statusbar"].active?
1041
999
  @prefs.view_as = @notebook.page
1042
1000
  @prefs.selected_library = selected_library.name
1043
1001
  cols_width = {}
1044
1002
  @listview.columns.each do |c|
1045
1003
  cols_width[c.title] = c.width
1046
1004
  end
1047
- @prefs.cols_width = '{' + cols_width.to_a.map do |t, v|
1005
+ @prefs.cols_width = "{" + cols_width.to_a.map do |t, v|
1048
1006
  '"' + t + '": ' + v.to_s
1049
- end.join(', ') + '}'
1007
+ end.join(", ") + "}"
1050
1008
  log.debug { "cols_width: #{@prefs.cols_width} " }
1051
1009
  @prefs.save!
1052
1010
  end
1053
1011
 
1054
1012
  def undoable_move(source, dest, books)
1055
- log.debug { 'undoable_move' }
1013
+ log.debug { "undoable_move" }
1056
1014
  Library.move(source, dest, *books)
1057
1015
  UndoManager.instance.push { undoable_move(dest, source, books) }
1058
1016
  end
@@ -1069,7 +1027,8 @@ module Alexandria
1069
1027
 
1070
1028
  def setup_move_actions
1071
1029
  @actiongroup.actions.each do |action|
1072
- next unless /^MoveIn/ =~ action.name
1030
+ next unless action.name.start_with?("MoveIn")
1031
+
1073
1032
  @actiongroup.remove_action(action)
1074
1033
  end
1075
1034
  actions = []
@@ -1083,10 +1042,11 @@ module Alexandria
1083
1042
  @actiongroup.add_actions(actions)
1084
1043
  @uimanager.remove_ui(@move_mid) if @move_mid
1085
1044
  @move_mid = @uimanager.new_merge_id
1045
+ ui_paths = ["ui/MainMenubar/EditMenu/Move/",
1046
+ "ui/BookPopup/Move/"]
1086
1047
  @libraries.all_regular_libraries.each do |library|
1087
1048
  name = library.action_name
1088
- ['ui/MainMenubar/EditMenu/Move/',
1089
- 'ui/BookPopup/Move/'].each do |path|
1049
+ ui_paths.each do |path|
1090
1050
  @uimanager.add_ui(@move_mid, path, name, name,
1091
1051
  :menuitem, false)
1092
1052
  end
@@ -1105,19 +1065,22 @@ module Alexandria
1105
1065
  # Gets the sort order of the current library, for use by export
1106
1066
  def library_sort_order
1107
1067
  # added by Cathal Mc Ginley, 23 Oct 2007
1108
- log.debug { "library_sort_order #{@notebook.page}: #{@iconview.model.inspect} #{@listview.model.inspect}" }
1068
+ log.debug do
1069
+ "library_sort_order #{@notebook.page}: " \
1070
+ "#{@iconview.model.inspect} #{@listview.model.inspect}"
1071
+ end
1109
1072
  result, sort_column, sort_order = current_view.model.sort_column_id
1110
1073
  if result
1111
- column_ids_to_attributes = { 2 => :title,
1112
- 4 => :authors,
1113
- 5 => :isbn,
1114
- 6 => :publisher,
1115
- 7 => :publishing_year,
1116
- 8 => :edition, # binding
1074
+ column_ids_to_attributes = { 2 => :title,
1075
+ 4 => :authors,
1076
+ 5 => :isbn,
1077
+ 6 => :publisher,
1078
+ 7 => :publishing_year,
1079
+ 8 => :edition, # binding
1117
1080
  12 => :redd,
1118
1081
  13 => :own,
1119
1082
  14 => :want,
1120
- 9 => :rating }
1083
+ 9 => :rating }
1121
1084
 
1122
1085
  sort_attribute = column_ids_to_attributes.fetch sort_column
1123
1086
  ascending = (sort_order == :ascending)
@@ -1167,10 +1130,10 @@ module Alexandria
1167
1130
  end
1168
1131
 
1169
1132
  def remove_library_separator
1170
- if !@library_separator_iter.nil? && @libraries.all_smart_libraries.empty?
1171
- @library_listview.model.remove(@library_separator_iter)
1172
- @library_separator_iter = nil
1173
- end
1133
+ return if @library_separator_iter.nil? || @libraries.all_smart_libraries.any?
1134
+
1135
+ @library_listview.model.remove(@library_separator_iter)
1136
+ @library_separator_iter = nil
1174
1137
  end
1175
1138
 
1176
1139
  def undoable_undelete(library, books = nil)
@@ -1191,13 +1154,14 @@ module Alexandria
1191
1154
 
1192
1155
  def setup_window_icons
1193
1156
  @main_app.icon = Icons::ALEXANDRIA_SMALL
1194
- Gtk::Window.set_default_icon_name('alexandria')
1195
- @main_app.icon_name = 'alexandria'
1157
+ Gtk::Window.set_default_icon_name("alexandria")
1158
+ @main_app.icon_name = "alexandria"
1196
1159
  end
1197
1160
 
1198
1161
  ICONS_SORTS = [
1199
1162
  Columns::TITLE, Columns::AUTHORS, Columns::ISBN,
1200
- Columns::PUBLISHER, Columns::EDITION, Columns::RATING, Columns::REDD, Columns::OWN, Columns::WANT
1163
+ Columns::PUBLISHER, Columns::EDITION, Columns::RATING,
1164
+ Columns::REDD, Columns::OWN, Columns::WANT
1201
1165
  ].freeze
1202
1166
 
1203
1167
  def setup_books_iconview_sorting
@@ -1209,6 +1173,21 @@ module Alexandria
1209
1173
 
1210
1174
  private
1211
1175
 
1176
+ def select_book_in_view(book, view)
1177
+ @filtered_model.refilter
1178
+ iter = iter_from_book book
1179
+ return unless iter
1180
+
1181
+ path = iter.path
1182
+ return unless view.model
1183
+
1184
+ path = view_path_to_model_path(view, path)
1185
+ log.debug { "Path for #{book.ident} is #{path}" }
1186
+ selection = view.respond_to?(:selection) ? view.selection : view
1187
+ selection.unselect_all
1188
+ selection.select_path(path)
1189
+ end
1190
+
1212
1191
  def view_path_to_model_path(view, path)
1213
1192
  path = view.model.convert_path_to_child_path(path)
1214
1193
  @filtered_model.convert_path_to_child_path(path) if path