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
@@ -6,6 +6,7 @@
6
6
 
7
7
  class Gtk::Entry
8
8
  attr_writer :mandatory
9
+
9
10
  def mandatory?
10
11
  @mandatory
11
12
  end
@@ -13,18 +14,21 @@ end
13
14
 
14
15
  module Alexandria
15
16
  module UI
16
- class ProviderPreferencesBaseDialog < SimpleDelegator
17
+ class ProviderPreferencesBaseDialog
18
+ attr_reader :dialog
19
+
17
20
  def initialize(title:, parent:, flags:, buttons:)
18
- dialog = Gtk::Dialog.new(title: title, parent: parent, flags: flags,
21
+ @dialog = Gtk::Dialog.new(title: title, parent: parent, flags: flags,
19
22
  buttons: buttons)
20
- super(dialog)
21
23
 
22
- self.resizable = false
23
- child.border_width = 12
24
+ @dialog.resizable = false
25
+ @dialog.child.border_width = 12
24
26
 
25
27
  @controls = []
26
28
  end
27
29
 
30
+ private
31
+
28
32
  def fill_table(table, provider)
29
33
  i = table.n_rows
30
34
  table.resize(table.n_rows + provider.prefs.length,
@@ -20,15 +20,15 @@ module Alexandria
20
20
 
21
21
  table = Gtk::Table.new(0, 0)
22
22
  fill_table(table, provider)
23
- child.pack_start(table)
23
+ dialog.child.pack_start(table)
24
24
 
25
- signal_connect("destroy") { sync_variables }
25
+ dialog.signal_connect("destroy") { sync_variables }
26
26
  end
27
27
 
28
28
  def acquire
29
- show_all
30
- run
31
- destroy
29
+ dialog.show_all
30
+ dialog.run
31
+ dialog.destroy
32
32
  end
33
33
  end
34
34
  end
@@ -40,7 +40,7 @@ module Alexandria
40
40
  [Gtk::Stock::DELETE, Gtk::ResponseType::OK]],
41
41
  description)
42
42
 
43
- self.default_response = Gtk::ResponseType::CANCEL
43
+ dialog.default_response = Gtk::ResponseType::CANCEL
44
44
  end
45
45
 
46
46
  def ok?
@@ -8,10 +8,11 @@ require "alexandria/ui/error_dialog"
8
8
 
9
9
  module Alexandria
10
10
  module UI
11
- class SidePaneManager
11
+ class SidepaneManager
12
12
  include Logging
13
13
  include GetText
14
14
  attr_accessor :library_listview
15
+
15
16
  def initialize(library_listview, parent)
16
17
  @library_listview = library_listview
17
18
  @parent = parent
@@ -32,12 +33,11 @@ module Alexandria
32
33
  # otherwise returns nil
33
34
  def contains_illegal_character(new_text)
34
35
  new_text.unpack("U*") # attempt to unpack as UTF-8 characters
35
- match = %r{(^\.|/)}.match(new_text)
36
36
  # forbid / character (since Library names become dir names)
37
37
  # also no initial . since that hides the Library (hidden file)
38
38
  # forbidding an initial dot also disallows "." and ".."
39
39
  # which are of course pre-existing directories.
40
- match
40
+ %r{(^\.|/)}.match(new_text)
41
41
  rescue StandardError => ex
42
42
  log.warn { "New library name not valid UTF-8: #{ex.message}" }
43
43
  true
@@ -46,42 +46,40 @@ module Alexandria
46
46
 
47
47
  def on_edited_library(cell, path_string, new_text)
48
48
  log.debug { "edited library name #{new_text}" }
49
- ## new_text = new_text.reverse # for testing;
50
- # a great way to generate broken UTF-8
51
- if cell.text != new_text
52
- if (match = contains_illegal_character(new_text))
53
- if match.instance_of? MatchData
54
- chars = match[1].gsub(/&/, "&amp;")
55
- ErrorDialog.new(@main_app, _("Invalid library name '%s'") % new_text,
56
- _("The name provided contains the " \
57
- "disallowed character <b>%s</b> ") % chars).display
58
- else
59
- ErrorDialog.new(@main_app, _("Invalid library name"),
60
- _("The name provided contains " \
61
- "invalid characters.")).display
62
- end
63
-
64
- elsif new_text.strip.empty?
65
- log.debug { "Empty text" }
66
- ErrorDialog.new(@main_app, _("The library name " \
67
- "can not be empty")).display
68
- elsif library_already_exists new_text
69
- log.debug { "Already exists" }
70
- ErrorDialog.new(@main_app,
71
- _("The library can not be renamed"),
72
- _("There is already a library named " \
73
- "'%s'. Please choose a different " \
74
- "name.") % new_text.strip).display
49
+ return if cell.text == new_text
50
+
51
+ if (match = contains_illegal_character(new_text))
52
+ if match.instance_of? MatchData
53
+ chars = match[1].gsub(/&/, "&amp;")
54
+ ErrorDialog.new(@main_app, _("Invalid library name '%s'") % new_text,
55
+ _("The name provided contains the " \
56
+ "disallowed character <b>%s</b>") % chars).display
75
57
  else
76
- log.debug { "Attempting to apply #{path_string}, #{new_text}" }
77
- path = Gtk::TreePath.new(path_string)
78
- iter = @library_listview.model.get_iter(path)
79
- library_name = new_text.strip
80
- log.info { "library name is #{library_name}" }
81
- iter[1] = @parent.selected_library.name = library_name
82
- @parent.setup_move_actions
83
- @parent.refresh_libraries
58
+ ErrorDialog.new(@main_app, _("Invalid library name"),
59
+ _("The name provided contains " \
60
+ "invalid characters.")).display
84
61
  end
62
+
63
+ elsif new_text.strip.empty?
64
+ log.debug { "Empty text" }
65
+ ErrorDialog.new(@main_app, _("The library name " \
66
+ "can not be empty")).display
67
+ elsif library_already_exists new_text
68
+ log.debug { "Already exists" }
69
+ ErrorDialog.new(@main_app,
70
+ _("The library can not be renamed"),
71
+ _("There is already a library named " \
72
+ "'%s'. Please choose a different " \
73
+ "name.") % new_text.strip).display
74
+ else
75
+ log.debug { "Attempting to apply #{path_string}, #{new_text}" }
76
+ path = Gtk::TreePath.new(path_string)
77
+ iter = @library_listview.model.get_iter(path)
78
+ library_name = new_text.strip
79
+ log.info { "library name is #{library_name}" }
80
+ iter[1] = @parent.selected_library.name = library_name
81
+ @parent.setup_move_actions
82
+ @parent.refresh_libraries
85
83
  end
86
84
  end
87
85
 
@@ -10,6 +10,7 @@ module Alexandria
10
10
  module UI
11
11
  class SkipEntryDialog < AlertDialog
12
12
  include GetText
13
+ include Logging
13
14
  GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
14
15
 
15
16
  def initialize(parent, message)
@@ -18,8 +19,8 @@ module Alexandria
18
19
  [[Gtk::Stock::CANCEL, Gtk::ResponseType::CANCEL],
19
20
  [_("_Continue"), Gtk::ResponseType::OK]],
20
21
  message)
21
- puts "Opened SkipEntryDialog #{inspect}" if $DEBUG
22
- self.default_response = Gtk::ResponseType::CANCEL
22
+ log.debug { "Opened SkipEntryDialog #{inspect}" }
23
+ dialog.default_response = Gtk::ResponseType::CANCEL
23
24
  end
24
25
 
25
26
  def continue?
@@ -1,21 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (C) 2004-2006 Laurent Sansonetti
3
+ # This file is part of Alexandria.
4
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.
14
- #
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
7
  module Alexandria
21
8
  module UI
@@ -26,35 +13,47 @@ module Alexandria
26
13
  def initialize(parent, smart_library)
27
14
  super(parent)
28
15
 
29
- add_buttons([Gtk::Stock::CANCEL, :cancel],
30
- [Gtk::Stock::SAVE, :ok])
16
+ @smart_library = smart_library
17
+
18
+ dialog.add_buttons([Gtk::Stock::CANCEL, :cancel],
19
+ [Gtk::Stock::SAVE, :ok])
31
20
 
32
- self.title = _("Properties for '%s'") % smart_library.name
21
+ dialog.title = _("Properties for '%s'") % @smart_library.name
33
22
  # FIXME: Should accept just :cancel
34
- self.default_response = Gtk::ResponseType::CANCEL
23
+ dialog.default_response = Gtk::ResponseType::CANCEL
24
+ @smart_library.rules.each { |x| insert_new_rule(x) }
25
+ update_rules_header_box(@smart_library.predicate_operator_rule)
35
26
  end
36
27
 
37
28
  def acquire
38
- show_all
39
- smart_library.rules.each { |x| insert_new_rule(x) }
40
- update_rules_header_box(smart_library.predicate_operator_rule)
41
-
42
- while (response = run) != Gtk::ResponseType::CANCEL
43
- if response == Gtk::ResponseType::HELP
44
- Alexandria::UI.display_help(self, "edit-smart-library")
45
- elsif response == Gtk::ResponseType::OK
46
- if user_confirms_possible_weirdnesses_before_saving?
47
- smart_library.rules = smart_library_rules
48
- smart_library.predicate_operator_rule =
49
- predicate_operator_rule
50
- smart_library.save
51
- yield(smart_library)
52
- break
53
- end
29
+ dialog.show_all
30
+
31
+ while (response = dialog.run) != Gtk::ResponseType::CANCEL
32
+ case response
33
+ when Gtk::ResponseType::HELP
34
+ handle_help_response
35
+ when Gtk::ResponseType::OK
36
+ break if handle_ok_response
54
37
  end
55
38
  end
56
39
 
57
- destroy
40
+ dialog.destroy
41
+ end
42
+
43
+ private
44
+
45
+ def handle_ok_response
46
+ user_confirms_possible_weirdnesses_before_saving? or return
47
+
48
+ @smart_library.rules = smart_library_rules
49
+ @smart_library.predicate_operator_rule =
50
+ predicate_operator_rule
51
+ @smart_library.save
52
+ true
53
+ end
54
+
55
+ def handle_help_response
56
+ Alexandria::UI.display_help(self, "edit-smart-library")
58
57
  end
59
58
  end
60
59
  end
@@ -1,49 +1,36 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (C) 2004-2006 Laurent Sansonetti
4
- # Copyright (C) 2011, 2016 Matijs van Zuijlen
3
+ # This file is part of Alexandria.
5
4
  #
6
- # Alexandria is free software; you can redistribute it and/or
7
- # modify it under the terms of the GNU General Public License as
8
- # published by the Free Software Foundation; either version 2 of the
9
- # License, or (at your option) any later version.
10
- #
11
- # Alexandria is distributed in the hope that it will be useful,
12
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
- # General Public License for more details.
15
- #
16
- # You should have received a copy of the GNU General Public
17
- # License along with Alexandria; see the file COPYING. If not,
18
- # write to the Free Software Foundation, Inc., 51 Franklin Street,
19
- # Fifth Floor, Boston, MA 02110-1301 USA.
5
+ # See the file README.md for authorship and licensing information.
6
+
7
+ require "alexandria/ui/smart_library_rule_box"
20
8
 
21
9
  module Alexandria
22
10
  module UI
23
- class SmartLibraryPropertiesDialogBase < SimpleDelegator
11
+ class SmartLibraryPropertiesDialogBase
24
12
  include Logging
25
13
  include GetText
26
14
  GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
27
15
 
28
- attr_reader :predicate_operator_rule
16
+ attr_reader :predicate_operator_rule, :dialog
29
17
 
30
18
  def initialize(parent)
31
19
  @dialog = Gtk::Dialog.new(title: "",
32
20
  parent: parent,
33
21
  flags: :modal,
34
22
  buttons: [[Gtk::Stock::HELP, :help]])
35
- super(@dialog)
36
23
 
37
- self.window_position = :center
38
- self.resizable = true
39
- self.border_width = 4
40
- child.border_width = 12
24
+ @dialog.window_position = :center
25
+ @dialog.resizable = true
26
+ @dialog.border_width = 4
27
+ @dialog.child.border_width = 12
41
28
 
42
29
  main_box = Gtk::Box.new :vertical
43
30
  main_box.border_width = 4
44
31
  main_box.spacing = 8
45
32
 
46
- child << main_box
33
+ @dialog.child << main_box
47
34
 
48
35
  @smart_library_rules = []
49
36
 
@@ -65,13 +52,34 @@ module Alexandria
65
52
  setup_calendar_widgets
66
53
  end
67
54
 
68
- protected
55
+ def handle_date_icon_press(widget, primary, _icon)
56
+ display_calendar_popup(widget) if primary.nick == "primary"
57
+ end
69
58
 
70
- def smart_library_rules
71
- fill_smart_library_rules_values
72
- @smart_library_rules
59
+ def handle_add_rule_clicked
60
+ insert_new_rule
73
61
  end
74
62
 
63
+ def handle_remove_rule_clicked(box_controller)
64
+ remove_rule_box(box_controller.rule_box)
65
+ end
66
+
67
+ # TODO: Move logic to SmartLibraryRuleBox
68
+ def apply_smart_rule_for_rule_box(rule_box, operand, operation)
69
+ idx = @rules_box.children.index(rule_box)
70
+ smart_library_rules[idx] ||= SmartLibrary::Rule.new(operand,
71
+ operation.first,
72
+ nil)
73
+ new_rule = smart_library_rules[idx]
74
+ new_rule.operand = operand
75
+ new_rule.operation = operation.first
76
+ new_rule.value = nil
77
+ end
78
+
79
+ protected
80
+
81
+ attr_reader :smart_library_rules
82
+
75
83
  def has_weirdnesses?
76
84
  fill_smart_library_rules_values
77
85
  smart_library_rules.each do |rule|
@@ -135,140 +143,53 @@ module Alexandria
135
143
  @rules_header_box.show_all
136
144
  end
137
145
 
138
- def insert_new_rule(rule = nil)
139
- rule_box = Gtk::Box.new :horizontal
140
- rule_box.spacing = 8
141
-
142
- left_operand_combo = Gtk::ComboBoxText.new
143
- operator_combo = Gtk::ComboBoxText.new
144
-
145
- value_entry = Gtk::Entry.new
146
-
147
- date_entry = Gtk::Entry.new
148
- date_entry.primary_icon_name = Gtk::Stock::EDIT
149
- date_entry.primary_icon_activatable = true
150
- date_entry.signal_connect("icon-press") do |entry, primary, _icon|
151
- display_calendar_popup(entry) if primary.nick == "primary"
152
- end
153
-
154
- # Really hide the time part of the date entry, as the constructor
155
- # does not seem to do it...
156
- # ##date_entry.children[2..3].each { |x| date_entry.remove(x) }
157
- # ##date_entry.spacing = 8
158
- entry_label = Gtk::Label.new("")
159
-
160
- add_button = Gtk::Button.new(label: "")
161
- add_button.remove(add_button.children.first)
162
- add_button << Gtk::Image.new(stock: Gtk::Stock::ADD,
163
- size: Gtk::IconSize::BUTTON)
164
-
165
- add_button.signal_connect("clicked") { insert_new_rule }
166
-
167
- remove_button = Gtk::Button.new(label: "")
168
- remove_button.remove(remove_button.children.first)
169
- remove_button << Gtk::Image.new(stock: Gtk::Stock::REMOVE,
170
- size: Gtk::IconSize::BUTTON)
171
-
172
- remove_button.signal_connect("clicked") do |_button|
173
- idx = @rules_box.children.index(rule_box)
174
- raise if idx.nil?
175
-
176
- @smart_library_rules.delete_at(idx)
177
- @rules_box.remove(rule_box)
178
- sensitize_remove_rule_buttons
179
- update_rules_header_box
180
- end
181
-
182
- operands = SmartLibrary::Rule::Operands::LEFT
183
- operands.each do |operand|
184
- left_operand_combo.append_text(operand.name)
185
- end
186
- operator_combo.signal_connect("changed") do
187
- operand = operands[left_operand_combo.active]
188
- operations = SmartLibrary::Rule.operations_for_operand(operand)
189
- operation = operations[operator_combo.active]
190
-
191
- value_entry.visible = date_entry.visible = entry_label.visible = false
192
- right_operand = operation.last
193
- unless right_operand.nil?
194
- entry = case right_operand.klass.name
195
- when "Time"
196
- date_entry
197
- else
198
- value_entry
199
- end
200
- entry.visible = true
201
- unless right_operand.name.nil?
202
- entry_label.text = right_operand.name
203
- entry_label.visible = true
204
- end
205
- end
206
-
207
- idx = @rules_box.children.index(rule_box)
208
- new_rule = @smart_library_rules[idx]
209
- if new_rule.nil?
210
- new_rule = SmartLibrary::Rule.new(operand,
211
- operation.first,
212
- nil)
213
- @smart_library_rules << new_rule
214
- end
215
- new_rule.operand = operand
216
- new_rule.operation = operation.first
217
- new_rule.value = nil
218
- end
219
- left_operand_combo.signal_connect("changed") do
220
- operand = operands[left_operand_combo.active]
221
- operator_combo.freeze_notify do
222
- operator_combo.remove_all
223
- operations = SmartLibrary::Rule.operations_for_operand(operand)
224
- operations.each do |operation|
225
- operator = operation.first
226
- operator_combo.append_text(operator.name)
227
- end
228
- operator_combo.active = 0
229
- end
230
- end
231
-
232
- rule_box.pack_start(left_operand_combo, expand: false, fill: false)
233
- rule_box.pack_start(operator_combo, expand: false, fill: false)
234
- rule_box.pack_start(value_entry)
235
- rule_box.pack_start(date_entry)
236
- rule_box.pack_start(entry_label, expand: false, fill: false)
237
- rule_box.pack_end(remove_button, expand: false, fill: false)
238
- rule_box.pack_end(add_button, expand: false, fill: false)
239
-
146
+ def make_rule_box(rule = nil)
147
+ box_controller = SmartLibraryRuleBox.new self
148
+ rule_box = box_controller.rule_box
240
149
  rule_box.show_all
241
- value_entry.visible = date_entry.visible = entry_label.visible = false
242
-
243
150
  @rules_box.pack_start(rule_box, expand: false, fill: true)
244
151
 
245
152
  if rule
153
+ operands = SmartLibrary::Rule::Operands::LEFT
246
154
  operand_idx = operands.index(rule.operand)
247
155
  operations =
248
156
  SmartLibrary::Rule.operations_for_operand(rule.operand)
249
157
  operation_idx = operations.map(&:first).index(rule.operation)
250
158
 
251
159
  if !operand_idx.nil? && !operation_idx.nil?
252
- left_operand_combo.active = operand_idx
253
- operator_combo.active = operation_idx
160
+ box_controller.left_operand_combo.active = operand_idx
161
+ box_controller.operator_combo.active = operation_idx
254
162
  unless rule.value.nil?
255
163
  case rule.value
256
164
  when String
257
- value_entry.text = rule.value
165
+ box_controller.value_entry.text = rule.value
258
166
  when Time
259
- date_entry.text = format_date(rule.value)
167
+ box_controller.date_entry.text = format_date(rule.value)
260
168
  end
261
169
  end
262
170
  end
263
171
  else
264
- left_operand_combo.active = 0
172
+ box_controller.left_operand_combo.active = 0
265
173
  end
174
+ end
266
175
 
176
+ def insert_new_rule(rule = nil)
177
+ make_rule_box(rule)
267
178
  @rules_box.check_resize # force a layout
268
179
  update_rules_header_box
269
180
  sensitize_remove_rule_buttons
270
181
  end
271
182
 
183
+ def remove_rule_box(rule_box)
184
+ idx = @rules_box.children.index(rule_box)
185
+ raise if idx.nil?
186
+
187
+ smart_library_rules.delete_at(idx)
188
+ @rules_box.remove(rule_box)
189
+ sensitize_remove_rule_buttons
190
+ update_rules_header_box
191
+ end
192
+
272
193
  def sensitize_remove_rule_buttons
273
194
  boxes = @rules_box.children
274
195
  state = boxes.length > 1
@@ -296,7 +217,7 @@ module Alexandria
296
217
  value = Time.now
297
218
  end
298
219
  end
299
- @smart_library_rules[i].value = value
220
+ smart_library_rules[i].value = value
300
221
  end
301
222
  end
302
223