alexandria-book-collection-manager 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +9 -0
  3. data/.gitignore +4 -1
  4. data/.rubocop.yml +51 -29
  5. data/.rubocop_todo.yml +33 -155
  6. data/.simplecov +5 -2
  7. data/.travis.yml +10 -4
  8. data/CHANGELOG.md +19 -0
  9. data/INSTALL.md +23 -11
  10. data/README.md +36 -35
  11. data/Rakefile +7 -5
  12. data/alexandria-book-collection-manager.gemspec +8 -3
  13. data/doc/dependency_decisions.yml +22 -3
  14. data/lib/alexandria.rb +2 -2
  15. data/lib/alexandria/book_providers.rb +47 -49
  16. data/lib/alexandria/book_providers/adlibris.rb +8 -13
  17. data/lib/alexandria/book_providers/amazon_aws.rb +47 -60
  18. data/lib/alexandria/book_providers/amazon_ecs_util.rb +283 -298
  19. data/lib/alexandria/book_providers/barnes_and_noble.rb +8 -8
  20. data/lib/alexandria/book_providers/douban.rb +2 -2
  21. data/lib/alexandria/book_providers/proxis.rb +12 -11
  22. data/lib/alexandria/book_providers/pseudomarc.rb +60 -70
  23. data/lib/alexandria/book_providers/siciliano.rb +5 -6
  24. data/lib/alexandria/book_providers/thalia.rb +8 -9
  25. data/lib/alexandria/book_providers/worldcat.rb +25 -31
  26. data/lib/alexandria/book_providers/z3950.rb +62 -69
  27. data/lib/alexandria/default_preferences.rb +37 -0
  28. data/lib/alexandria/execution_queue.rb +13 -12
  29. data/lib/alexandria/export_library.rb +4 -8
  30. data/lib/alexandria/import_library.rb +38 -62
  31. data/lib/alexandria/import_library_csv.rb +16 -16
  32. data/lib/alexandria/library_sort_order.rb +3 -1
  33. data/lib/alexandria/library_store.rb +16 -16
  34. data/lib/alexandria/logging.rb +4 -8
  35. data/lib/alexandria/models/book.rb +2 -2
  36. data/lib/alexandria/models/library.rb +18 -14
  37. data/lib/alexandria/net.rb +1 -2
  38. data/lib/alexandria/preferences.rb +27 -31
  39. data/lib/alexandria/scanners.rb +2 -2
  40. data/lib/alexandria/scanners/cue_cat.rb +5 -5
  41. data/lib/alexandria/scanners/keyboard.rb +1 -1
  42. data/lib/alexandria/smart_library.rb +22 -26
  43. data/lib/alexandria/ui.rb +7 -7
  44. data/lib/alexandria/ui/about_dialog.rb +1 -1
  45. data/lib/alexandria/ui/acquire_dialog.rb +9 -10
  46. data/lib/alexandria/ui/alert_dialog.rb +34 -19
  47. data/lib/alexandria/ui/bad_isbns_dialog.rb +13 -9
  48. data/lib/alexandria/ui/barcode_animation.rb +5 -5
  49. data/lib/alexandria/ui/book_properties_dialog.rb +2 -2
  50. data/lib/alexandria/ui/book_properties_dialog_base.rb +23 -17
  51. data/lib/alexandria/ui/callbacks.rb +141 -120
  52. data/lib/alexandria/ui/completion_models.rb +1 -1
  53. data/lib/alexandria/ui/confirm_erase_dialog.rb +1 -1
  54. data/lib/alexandria/ui/conflict_while_copying_dialog.rb +1 -1
  55. data/lib/alexandria/ui/error_dialog.rb +1 -1
  56. data/lib/alexandria/ui/export_dialog.rb +13 -15
  57. data/lib/alexandria/ui/icons.rb +34 -40
  58. data/lib/alexandria/ui/iconview_tooltips.rb +40 -53
  59. data/lib/alexandria/ui/import_dialog.rb +48 -47
  60. data/lib/alexandria/ui/init.rb +3 -2
  61. data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +2 -2
  62. data/lib/alexandria/ui/libraries_combo.rb +10 -9
  63. data/lib/alexandria/ui/listview.rb +5 -6
  64. data/lib/alexandria/ui/main_app.rb +2 -2
  65. data/lib/alexandria/ui/multi_drag_treeview.rb +4 -6
  66. data/lib/alexandria/ui/new_book_dialog.rb +52 -52
  67. data/lib/alexandria/ui/new_provider_dialog.rb +12 -11
  68. data/lib/alexandria/ui/new_smart_library_dialog.rb +39 -27
  69. data/lib/alexandria/ui/preferences_dialog.rb +23 -82
  70. data/lib/alexandria/ui/provider_preferences_base_dialog.rb +9 -5
  71. data/lib/alexandria/ui/provider_preferences_dialog.rb +5 -5
  72. data/lib/alexandria/ui/really_delete_dialog.rb +1 -1
  73. data/lib/alexandria/ui/sidepane_manager.rb +35 -37
  74. data/lib/alexandria/ui/skip_entry_dialog.rb +3 -2
  75. data/lib/alexandria/ui/smart_library_properties_dialog.rb +35 -36
  76. data/lib/alexandria/ui/smart_library_properties_dialog_base.rb +59 -138
  77. data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
  78. data/lib/alexandria/ui/sound.rb +4 -6
  79. data/lib/alexandria/ui/ui_manager.rb +62 -64
  80. data/lib/alexandria/version.rb +2 -2
  81. data/lib/alexandria/web_themes.rb +15 -15
  82. data/po/cs.po +991 -874
  83. data/po/cy.po +957 -870
  84. data/po/de.po +991 -866
  85. data/po/el.po +987 -863
  86. data/po/es.po +986 -862
  87. data/po/fr.po +988 -868
  88. data/po/ga.po +910 -822
  89. data/po/gl.po +983 -863
  90. data/po/it.po +984 -862
  91. data/po/ja.po +969 -849
  92. data/po/mk.po +983 -859
  93. data/po/nb.po +982 -862
  94. data/po/nl.po +992 -869
  95. data/po/pl.po +1018 -963
  96. data/po/pt.po +983 -852
  97. data/po/pt_BR.po +983 -863
  98. data/po/ru.po +992 -869
  99. data/po/sk.po +986 -864
  100. data/po/sv.po +980 -860
  101. data/po/uk.po +975 -861
  102. data/po/zh_TW.po +974 -854
  103. data/share/alexandria/glade/main_app__builder.glade +6 -21
  104. data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
  105. data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
  106. data/share/gnome/help/alexandria/fr/alexandria.xml +1 -1
  107. data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
  108. data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
  109. data/spec/alexandria/book_providers_spec.rb +73 -129
  110. data/spec/alexandria/console_spec.rb +0 -5
  111. data/spec/alexandria/export_library_spec.rb +27 -38
  112. data/spec/alexandria/library_spec.rb +56 -44
  113. data/spec/alexandria/preferences_spec.rb +29 -3
  114. data/spec/alexandria/scanners/cue_cat_spec.rb +1 -1
  115. data/spec/alexandria/ui/about_dialog_spec.rb +1 -1
  116. data/spec/alexandria/ui/acquire_dialog_spec.rb +1 -1
  117. data/spec/alexandria/ui/alert_dialog_spec.rb +1 -1
  118. data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +1 -1
  119. data/spec/alexandria/ui/book_properties_dialog_spec.rb +1 -1
  120. data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +1 -1
  121. data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +1 -1
  122. data/spec/alexandria/ui/error_dialog_spec.rb +1 -1
  123. data/spec/alexandria/ui/export_dialog_spec.rb +1 -1
  124. data/spec/alexandria/ui/icons_spec.rb +26 -0
  125. data/spec/alexandria/ui/iconview_spec.rb +1 -1
  126. data/spec/alexandria/ui/import_dialog_spec.rb +30 -3
  127. data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +1 -1
  128. data/spec/alexandria/ui/main_app_spec.rb +1 -1
  129. data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +1 -1
  130. data/spec/alexandria/ui/new_provider_dialog_spec.rb +19 -3
  131. data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +28 -3
  132. data/spec/alexandria/ui/preferences_dialog_spec.rb +1 -1
  133. data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +23 -8
  134. data/spec/alexandria/ui/really_delete_dialog_spec.rb +1 -1
  135. data/spec/alexandria/ui/sidepane_manager_spec.rb +2 -2
  136. data/spec/alexandria/ui/skip_entry_dialog_spec.rb +1 -1
  137. data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +21 -7
  138. data/spec/alexandria/ui/ui_manager_spec.rb +39 -2
  139. data/spec/spec_helper.rb +46 -3
  140. data/tasks/spec.rake +3 -5
  141. data/util/rake/fileinstall.rb +12 -11
  142. metadata +82 -10
  143. data/spec/alexandria/ui/ui_utilities_spec.rb +0 -62
  144. data/spec/alexandria/utilities_spec.rb +0 -52
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file is part of Alexandria.
4
+ #
5
+ # See the file README.md for authorship and licensing information.
6
+
7
+ module Alexandria
8
+ module UI
9
+ class SmartLibraryRuleBox
10
+ attr_accessor :rule_box,
11
+ :left_operand_combo, :operator_combo,
12
+ :value_entry, :date_entry, :entry_label,
13
+ :add_button, :remove_button
14
+
15
+ def initialize(parent)
16
+ @parent = parent
17
+
18
+ self.rule_box = Gtk::Box.new :horizontal
19
+ rule_box.spacing = 8
20
+
21
+ self.left_operand_combo = Gtk::ComboBoxText.new
22
+ self.operator_combo = Gtk::ComboBoxText.new
23
+
24
+ self.value_entry = Gtk::Entry.new
25
+
26
+ self.date_entry = Gtk::Entry.new.tap do |entry|
27
+ entry.primary_icon_name = Gtk::Stock::EDIT
28
+
29
+ entry.primary_icon_activatable = true
30
+ entry.signal_connect("icon-press") do |widget, primary, _icon|
31
+ @parent.handle_date_icon_press(widget, primary, icon)
32
+ end
33
+ end
34
+
35
+ self.entry_label = Gtk::Label.new("")
36
+
37
+ self.add_button = Gtk::Button.new(label: "").tap do |widget|
38
+ widget.remove(widget.children.first)
39
+ widget << Gtk::Image.new(stock: Gtk::Stock::ADD,
40
+ size: Gtk::IconSize::BUTTON)
41
+
42
+ widget.signal_connect("clicked") { @parent.handle_add_rule_clicked }
43
+ end
44
+
45
+ self.remove_button = Gtk::Button.new(label: "")
46
+ remove_button.remove(remove_button.children.first)
47
+ remove_button << Gtk::Image.new(stock: Gtk::Stock::REMOVE,
48
+ size: Gtk::IconSize::BUTTON)
49
+
50
+ remove_button.signal_connect("clicked") do |_button|
51
+ @parent.handle_remove_rule_clicked(self)
52
+ end
53
+
54
+ operands.each do |operand|
55
+ left_operand_combo.append_text(operand.name)
56
+ end
57
+
58
+ operator_combo.signal_connect("changed") do
59
+ handle_operator_changed
60
+ end
61
+
62
+ left_operand_combo.signal_connect("changed") do
63
+ handle_left_operand_changed
64
+ end
65
+
66
+ rule_box.pack_start(left_operand_combo, expand: false, fill: false)
67
+ rule_box.pack_start(operator_combo, expand: false, fill: false)
68
+ rule_box.pack_start(value_entry)
69
+ rule_box.pack_start(date_entry)
70
+ rule_box.pack_start(entry_label, expand: false, fill: false)
71
+ rule_box.pack_end(remove_button, expand: false, fill: false)
72
+ rule_box.pack_end(add_button, expand: false, fill: false)
73
+
74
+ value_entry.visible = date_entry.visible = entry_label.visible = false
75
+ end
76
+
77
+ def operands
78
+ SmartLibrary::Rule::Operands::LEFT
79
+ end
80
+
81
+ def handle_operator_changed
82
+ operand = operands[left_operand_combo.active]
83
+ operations = SmartLibrary::Rule.operations_for_operand(operand)
84
+ operation = operations[operator_combo.active]
85
+
86
+ value_entry.visible = date_entry.visible = entry_label.visible = false
87
+ right_operand = operation.last
88
+ unless right_operand.nil?
89
+ entry = case right_operand.klass.name
90
+ when "Time"
91
+ date_entry
92
+ else
93
+ value_entry
94
+ end
95
+ entry.visible = true
96
+ unless right_operand.name.nil?
97
+ entry_label.text = right_operand.name
98
+ entry_label.visible = true
99
+ end
100
+ end
101
+
102
+ @parent.apply_smart_rule_for_rule_box(rule_box, operand, operation)
103
+ end
104
+
105
+ def handle_left_operand_changed
106
+ operand = operands[left_operand_combo.active]
107
+ operator_combo.freeze_notify do
108
+ operator_combo.remove_all
109
+ operations = SmartLibrary::Rule.operations_for_operand(operand)
110
+ operations.each do |operation|
111
+ operator = operation.first
112
+ operator_combo.append_text(operator.name)
113
+ end
114
+ operator_combo.active = 0
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -39,9 +39,9 @@ module Alexandria
39
39
  def play(effect)
40
40
  file = File.join(@sounds_dir, "#{effect}.ogg")
41
41
  if @playing
42
- puts "Already playing #{effect}." if $DEBUG
42
+ log.debug { "Already playing #{effect}." }
43
43
  else
44
- puts "Not playing. Starting #{effect}." if $DEBUG
44
+ log.debug { "Not playing. Starting #{effect}." }
45
45
  @filesrc.location = file
46
46
  start_playback
47
47
  end
@@ -76,10 +76,8 @@ module Alexandria
76
76
  when Gst::MessageType::EOS
77
77
  stop_playback
78
78
  when Gst::MessageType::ERROR
79
- if $DEBUG
80
- puts "ERROR loop.quit"
81
- p message.parse
82
- end
79
+ log.debug { "ERROR loop.quit" }
80
+ log.debug { message.parse.inspect }
83
81
  stop_playback
84
82
  end
85
83
  true
@@ -15,6 +15,7 @@ module Alexandria
15
15
  attr_accessor :main_app, :actiongroup, :appbar, :prefs, :listview, :iconview,
16
16
  :listview_model, :iconview_model, :filtered_model
17
17
  attr_reader :model
18
+
18
19
  include Logging
19
20
  include GetText
20
21
  GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
@@ -74,7 +75,7 @@ module Alexandria
74
75
  @iconview_model = Gtk::TreeModelSort.new(@filtered_model)
75
76
  @listview_manager = ListViewManager.new @listview, self
76
77
  @iconview_manager = IconViewManager.new @iconview, self
77
- @sidepane_manager = SidePaneManager.new @library_listview, self
78
+ @sidepane_manager = SidepaneManager.new @library_listview, self
78
79
  @library_listview = @sidepane_manager.library_listview
79
80
  @listview_manager.setup_listview_columns_visibility
80
81
  @listview_manager.setup_listview_columns_width
@@ -183,15 +184,16 @@ module Alexandria
183
184
  def setup_book_providers
184
185
  log.debug { "setup_book_providers" }
185
186
  mid = @uimanager.new_merge_id
186
- 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|
187
191
  name = provider.action_name
188
- ["ui/MainMenubar/ViewMenu/OnlineInformation/",
189
- "ui/BookPopup/OnlineInformation/",
190
- "ui/NoBookPopup/OnlineInformation/"].each do |path|
191
- log.debug { "Adding #{name} to #{path}" }
192
- @uimanager.add_ui(mid, path, name, name,
193
- :menuitem, false)
194
- 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
195
197
  end
196
198
  end
197
199
 
@@ -371,25 +373,25 @@ module Alexandria
371
373
 
372
374
  def on_books_button_press_event(widget, event)
373
375
  log.debug { "books_button_press_event" }
374
- if event_is_right_click event
375
- widget.grab_focus
376
+ event_is_right_click event or return
376
377
 
377
- if (path = widget.get_path_at_pos(event.x.to_i, event.y.to_i))
378
- obj, path =
379
- widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
378
+ widget.grab_focus
380
379
 
381
- unless obj.path_is_selected?(path)
382
- log.debug { "Select #{path}" }
383
- widget.unselect_all
384
- obj.select_path(path)
385
- end
386
- 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}" }
387
386
  widget.unselect_all
387
+ obj.select_path(path)
388
388
  end
389
-
390
- menu = selected_books.empty? ? @nobook_popup : @book_popup
391
- menu.popup(nil, nil, event.button, event.time)
389
+ else
390
+ widget.unselect_all
392
391
  end
392
+
393
+ menu = selected_books.empty? ? @nobook_popup : @book_popup
394
+ menu.popup(nil, nil, event.button, event.time)
393
395
  end
394
396
 
395
397
  def get_library_selection_text(library)
@@ -475,7 +477,7 @@ module Alexandria
475
477
  b = books.first
476
478
  # FIXME: Clean up endless negation in this logic
477
479
  no_urls = true
478
- BookProviders.each do |provider|
480
+ BookProviders.list.each do |provider|
479
481
  has_no_url = true
480
482
  begin
481
483
  has_no_url = (b.isbn.nil? || b.isbn.strip.empty? || provider.url(b).nil?)
@@ -522,43 +524,25 @@ module Alexandria
522
524
  @actiongroup["Sidepane"].active = false
523
525
  end
524
526
 
527
+ # TODO: Figure out why this frequently selects the wrong book!
525
528
  def select_a_book(book)
526
- select_this_book = proc do |bk, view|
527
- @filtered_model.refilter
528
- iter = iter_from_book bk
529
- next unless iter
530
-
531
- path = iter.path
532
- next unless view.model
533
-
534
- path = view_path_to_model_path(view, path)
535
- log.debug { "Path for #{bk.ident} is #{path}" }
536
- selection = view.respond_to?(:selection) ? @listview.selection : @iconview
537
- selection.unselect_all
538
- selection.select_path(path)
539
- end
540
- begin
541
- log.debug { "select_a_book: listview" }
542
- select_this_book.call(book, @listview)
543
- log.debug { "select_a_book: listview" }
544
- select_this_book.call(book, @iconview)
545
- rescue StandardError => ex
546
- trace = ex.backtrace.join("\n> ")
547
- log.warn { "Failed to automatically select book: #{ex.message} #{trace}" }
548
- end
549
- # 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)
550
533
  end
551
534
 
552
535
  def update(*ary)
553
536
  log.debug { "on_update #{ary}" }
554
537
  caller = ary.first
555
- if caller.is_a?(UndoManager)
538
+ case caller
539
+ when UndoManager
556
540
  @actiongroup["Undo"].sensitive = caller.can_undo?
557
541
  @actiongroup["Redo"].sensitive = caller.can_redo?
558
- elsif caller.is_a?(Library)
542
+ when Library
559
543
  handle_update_caller_library ary unless caller.updating?
560
544
  else
561
- raise "unrecognized update event"
545
+ raise _("unrecognized update event")
562
546
  end
563
547
  end
564
548
 
@@ -584,8 +568,6 @@ module Alexandria
584
568
  end
585
569
  end
586
570
 
587
- # private
588
-
589
571
  def open_web_browser(url)
590
572
  if url.nil?
591
573
  log.warn("Attempt to open browser with nil url")
@@ -605,7 +587,7 @@ module Alexandria
605
587
  end
606
588
 
607
589
  def load_libraries
608
- log.info { "Loading libraries..." }
590
+ log.info { _("Loading libraries...") }
609
591
  @completion_models = CompletionModels.instance
610
592
  if @libraries
611
593
  detach_old_libraries
@@ -750,7 +732,7 @@ module Alexandria
750
732
  new_height = [ICON_HEIGHT, icon.height].min
751
733
  icon = cache_scaled_icon(icon, new_width, new_height)
752
734
  end
753
- icon = icon.tag(Icons::FAVORITE_TAG) if rating == Book::MAX_RATING_STARS
735
+ icon = Icons.tag_icon(icon, Icons::FAVORITE_TAG) if rating == Book::MAX_RATING_STARS
754
736
  iter[Columns::COVER_ICON] = icon
755
737
  log.debug { "Full iter: " + (0..15).map { |num| iter[num].inspect }.join(", ") }
756
738
  end
@@ -891,7 +873,7 @@ module Alexandria
891
873
  def iter_from_ident(ident)
892
874
  log.debug { ident.to_s }
893
875
  iter = @model.iter_first
894
- ok = true
876
+ ok = true if iter
895
877
  while ok
896
878
  return iter if iter[Columns::IDENT] == ident
897
879
 
@@ -971,7 +953,7 @@ module Alexandria
971
953
  end
972
954
 
973
955
  def restore_preferences
974
- log.debug { "Restoring preferences..." }
956
+ log.debug { "Restoring preferences" }
975
957
  if @prefs.maximized
976
958
  @main_app.maximize
977
959
  else
@@ -1045,7 +1027,7 @@ module Alexandria
1045
1027
 
1046
1028
  def setup_move_actions
1047
1029
  @actiongroup.actions.each do |action|
1048
- next unless /^MoveIn/.match?(action.name)
1030
+ next unless action.name.start_with?("MoveIn")
1049
1031
 
1050
1032
  @actiongroup.remove_action(action)
1051
1033
  end
@@ -1060,10 +1042,11 @@ module Alexandria
1060
1042
  @actiongroup.add_actions(actions)
1061
1043
  @uimanager.remove_ui(@move_mid) if @move_mid
1062
1044
  @move_mid = @uimanager.new_merge_id
1045
+ ui_paths = ["ui/MainMenubar/EditMenu/Move/",
1046
+ "ui/BookPopup/Move/"]
1063
1047
  @libraries.all_regular_libraries.each do |library|
1064
1048
  name = library.action_name
1065
- ["ui/MainMenubar/EditMenu/Move/",
1066
- "ui/BookPopup/Move/"].each do |path|
1049
+ ui_paths.each do |path|
1067
1050
  @uimanager.add_ui(@move_mid, path, name, name,
1068
1051
  :menuitem, false)
1069
1052
  end
@@ -1147,10 +1130,10 @@ module Alexandria
1147
1130
  end
1148
1131
 
1149
1132
  def remove_library_separator
1150
- if !@library_separator_iter.nil? && @libraries.all_smart_libraries.empty?
1151
- @library_listview.model.remove(@library_separator_iter)
1152
- @library_separator_iter = nil
1153
- 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
1154
1137
  end
1155
1138
 
1156
1139
  def undoable_undelete(library, books = nil)
@@ -1190,6 +1173,21 @@ module Alexandria
1190
1173
 
1191
1174
  private
1192
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
+
1193
1191
  def view_path_to_model_path(view, path)
1194
1192
  path = view.model.convert_path_to_child_path(path)
1195
1193
  @filtered_model.convert_path_to_child_path(path) if path
@@ -5,7 +5,7 @@
5
5
  # See the file README.md for authorship and licensing information.
6
6
 
7
7
  module Alexandria
8
- VERSION = "0.7.5"
8
+ VERSION = "0.7.6"
9
9
  DATA_VERSION = "0.6.3"
10
- DISPLAY_VERSION = "0.7.5"
10
+ DISPLAY_VERSION = "0.7.6"
11
11
  end
@@ -22,6 +22,17 @@ module Alexandria
22
22
  class WebTheme
23
23
  attr_reader :name, :css_file, :preview_file, :pixmaps_directory
24
24
 
25
+ def initialize(css_file, preview_file, pixmaps_directory)
26
+ @name = File.basename(css_file, ".css").capitalize
27
+ @css_file = css_file
28
+ @preview_file = preview_file
29
+ @pixmaps_directory = pixmaps_directory
30
+ end
31
+
32
+ def has_pixmaps?
33
+ File.exist?(@pixmaps_directory)
34
+ end
35
+
25
36
  def self.all
26
37
  themes_dir = [
27
38
  # System dir
@@ -33,18 +44,12 @@ module Alexandria
33
44
  themes_dir.map { |x| load(x) }.flatten
34
45
  end
35
46
 
36
- def has_pixmaps?
37
- File.exist?(@pixmaps_directory)
38
- end
39
-
40
- private
41
-
42
47
  def self.load(themes_dir)
43
48
  themes = []
44
49
  if File.exist?(themes_dir)
45
50
  Dir.entries(themes_dir).each do |file|
46
51
  # ignore hidden files
47
- next if /^\./.match?(file)
52
+ next if file.start_with?(".")
48
53
 
49
54
  # ignore non-directories
50
55
  path = File.join(themes_dir, file)
@@ -55,7 +60,9 @@ module Alexandria
55
60
  css_file = File.join(path, file + ".css")
56
61
  preview_file = File.join(path, "preview.jpg")
57
62
  [css_file, preview_file].each do |helper_file|
58
- raise "#{helper_file} not found" unless File.exist?(helper_file)
63
+ unless File.exist?(helper_file)
64
+ raise format(_("File %<file>s not found"), file: helper_file)
65
+ end
59
66
  end
60
67
  themes << WebTheme.new(css_file, preview_file,
61
68
  File.join(path, file, "pixmaps"))
@@ -65,12 +72,5 @@ module Alexandria
65
72
  end
66
73
  themes
67
74
  end
68
-
69
- def initialize(css_file, preview_file, pixmaps_directory)
70
- @name = File.basename(css_file, ".css").capitalize
71
- @css_file = css_file
72
- @preview_file = preview_file
73
- @pixmaps_directory = pixmaps_directory
74
- end
75
75
  end
76
76
  end