alexandria-book-collection-manager 0.6.9 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (86) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +34 -30
  4. data/.rubocop_todo.yml +139 -54
  5. data/CHANGELOG.md +10 -0
  6. data/Gemfile +1 -0
  7. data/Rakefile +10 -11
  8. data/alexandria-book-collection-manager.gemspec +3 -2
  9. data/bin/alexandria +1 -1
  10. data/lib/alexandria.rb +3 -6
  11. data/lib/alexandria/about.rb +9 -9
  12. data/lib/alexandria/book_providers.rb +12 -12
  13. data/lib/alexandria/book_providers/adlibris.rb +14 -18
  14. data/lib/alexandria/book_providers/amazon_aws.rb +17 -31
  15. data/lib/alexandria/book_providers/amazon_ecs_util.rb +5 -6
  16. data/lib/alexandria/book_providers/barnes_and_noble.rb +51 -76
  17. data/lib/alexandria/book_providers/bol_it.rb +12 -12
  18. data/lib/alexandria/book_providers/deastore.rb +27 -31
  19. data/lib/alexandria/book_providers/douban.rb +9 -13
  20. data/lib/alexandria/book_providers/ibs_it.rb +10 -10
  21. data/lib/alexandria/book_providers/mcu.rb +12 -18
  22. data/lib/alexandria/book_providers/proxis.rb +14 -22
  23. data/lib/alexandria/book_providers/pseudomarc.rb +8 -18
  24. data/lib/alexandria/book_providers/renaud.rb +16 -16
  25. data/lib/alexandria/book_providers/siciliano.rb +25 -38
  26. data/lib/alexandria/book_providers/thalia.rb +13 -16
  27. data/lib/alexandria/book_providers/webster_it.rb +14 -18
  28. data/lib/alexandria/book_providers/worldcat.rb +21 -25
  29. data/lib/alexandria/book_providers/z3950.rb +19 -23
  30. data/lib/alexandria/config.rb +2 -2
  31. data/lib/alexandria/execution_queue.rb +3 -1
  32. data/lib/alexandria/export_library.rb +19 -22
  33. data/lib/alexandria/import_library.rb +14 -18
  34. data/lib/alexandria/import_library_csv.rb +12 -30
  35. data/lib/alexandria/models/book.rb +7 -9
  36. data/lib/alexandria/models/library.rb +44 -44
  37. data/lib/alexandria/net.rb +1 -1
  38. data/lib/alexandria/preferences.rb +12 -57
  39. data/lib/alexandria/scanners.rb +10 -6
  40. data/lib/alexandria/scanners/cuecat.rb +2 -2
  41. data/lib/alexandria/smart_library.rb +12 -12
  42. data/lib/alexandria/ui.rb +5 -2
  43. data/lib/alexandria/ui/callbacks.rb +106 -65
  44. data/lib/alexandria/ui/completion_models.rb +55 -51
  45. data/lib/alexandria/ui/dialogs/about_dialog.rb +1 -1
  46. data/lib/alexandria/ui/dialogs/acquire_dialog.rb +25 -51
  47. data/lib/alexandria/ui/dialogs/alert_dialog.rb +13 -11
  48. data/lib/alexandria/ui/dialogs/bad_isbns_dialog.rb +2 -2
  49. data/lib/alexandria/ui/dialogs/barcode_animation.rb +39 -23
  50. data/lib/alexandria/ui/dialogs/book_properties_dialog.rb +16 -21
  51. data/lib/alexandria/ui/dialogs/book_properties_dialog_base.rb +23 -24
  52. data/lib/alexandria/ui/dialogs/export_dialog.rb +46 -45
  53. data/lib/alexandria/ui/dialogs/import_dialog.rb +26 -35
  54. data/lib/alexandria/ui/dialogs/misc_dialogs.rb +11 -11
  55. data/lib/alexandria/ui/dialogs/new_book_dialog.rb +47 -59
  56. data/lib/alexandria/ui/dialogs/new_book_dialog_manual.rb +14 -13
  57. data/lib/alexandria/ui/dialogs/new_smart_library_dialog.rb +12 -11
  58. data/lib/alexandria/ui/dialogs/preferences_dialog.rb +37 -43
  59. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog.rb +9 -8
  60. data/lib/alexandria/ui/dialogs/smart_library_properties_dialog_base.rb +47 -53
  61. data/lib/alexandria/ui/dndable.rb +5 -4
  62. data/lib/alexandria/ui/icons.rb +19 -19
  63. data/lib/alexandria/ui/iconview.rb +7 -12
  64. data/lib/alexandria/ui/iconview_tooltips.rb +22 -109
  65. data/lib/alexandria/ui/init.rb +7 -15
  66. data/lib/alexandria/ui/libraries_combo.rb +54 -48
  67. data/lib/alexandria/ui/listview.rb +30 -85
  68. data/lib/alexandria/ui/multi_drag_treeview.rb +110 -107
  69. data/lib/alexandria/ui/sidepane.rb +23 -25
  70. data/lib/alexandria/ui/sound.rb +18 -27
  71. data/lib/alexandria/ui/ui_manager.rb +126 -204
  72. data/lib/alexandria/undo_manager.rb +2 -2
  73. data/lib/alexandria/version.rb +4 -4
  74. data/spec/alexandria/book_providers_spec.rb +7 -4
  75. data/spec/alexandria/library_spec.rb +13 -16
  76. data/spec/alexandria/scanners/cuecat_spec.rb +1 -2
  77. data/spec/alexandria/ui/dialogs_spec.rb +5 -1
  78. data/spec/alexandria/ui/main_app_spec.rb +3 -3
  79. data/{lib/alexandria/utils.rb → spec/alexandria/ui/sound_spec.rb} +6 -11
  80. data/spec/alexandria/ui/ui_utilities_spec.rb +3 -3
  81. data/spec/spec_helper.rb +2 -2
  82. data/util/rake/fileinstall.rb +17 -33
  83. data/util/rake/gettextgenerate.rb +2 -4
  84. data/util/rake/omfgenerate.rb +1 -3
  85. metadata +23 -11
  86. data/lib/alexandria/ui/gtk_thread_help.rb +0 -89
@@ -1,7 +1,7 @@
1
1
  # Copyright (C) 2004-2006 Laurent Sansonetti
2
2
  # Copyright (C) 2008 Joseph Method
3
3
  # Copyright (C) 2010 Cathal Mc Ginley
4
- # Copyright (C) 2011 Matijs van Zuijlen
4
+ # Copyright (C) 2011, 2016 Matijs van Zuijlen
5
5
  #
6
6
  # Alexandria is free software; you can redistribute it and/or
7
7
  # modify it under the terms of the GNU General Public License aso
@@ -27,7 +27,7 @@ module Alexandria
27
27
  include Logging
28
28
  include GetText
29
29
  include DragAndDropable
30
- BOOKS_TARGET_TABLE = [['ALEXANDRIA_BOOKS', Gtk::Drag::TARGET_SAME_APP, 0]]
30
+ BOOKS_TARGET_TABLE = [['ALEXANDRIA_BOOKS', :same_app, 0]].freeze
31
31
 
32
32
  MAX_RATING_STARS = 5
33
33
  module Columns
@@ -51,55 +51,21 @@ module Alexandria
51
51
  title = _('Title')
52
52
  log.debug { 'Create listview column for %s' % title }
53
53
  column = Gtk::TreeViewColumn.new(title)
54
- column.widget = Gtk::Label.new(title).show
54
+
55
55
  renderer = Gtk::CellRendererPixbuf.new
56
56
  column.pack_start(renderer, false)
57
- column.set_cell_data_func(renderer) do |_col, cell, _model, iter|
58
- iter = @listview_model.convert_iter_to_child_iter(iter)
59
- iter = @filtered_model.convert_iter_to_child_iter(iter)
60
- cell.pixbuf = iter[Columns::COVER_LIST]
61
- end
62
- renderer = Gtk::CellRendererText.new
63
- renderer.ellipsize = Pango::ELLIPSIZE_END if Pango.ellipsizable?
64
- # Editable tree views are behaving strangely
65
- # make_renderer_editable renderer
57
+ column.add_attribute(renderer, 'pixbuf', Columns::COVER_LIST)
66
58
 
59
+ renderer = Gtk::CellRendererText.new
60
+ renderer.ellipsize = Pango::ELLIPSIZE_END
67
61
  column.pack_start(renderer, true)
68
-
69
- column.set_cell_data_func(renderer) do |_col, cell, _model, iter|
70
- iter = @listview_model.convert_iter_to_child_iter(iter)
71
- iter = @filtered_model.convert_iter_to_child_iter(iter)
72
- cell.text = iter[Columns::TITLE]
73
- cell.editable = false # true
74
- end
62
+ column.add_attribute(renderer, 'text', Columns::TITLE)
75
63
 
76
64
  column.sort_column_id = Columns::TITLE
77
65
  column.resizable = true
78
66
  @listview.append_column(column)
79
67
  end
80
68
 
81
- def make_renderer_editable(renderer)
82
- renderer.signal_connect('editing_started') do |_cell, entry, _path_string|
83
- log.debug { 'editing_started' }
84
- entry.complete_titles
85
- end
86
-
87
- renderer.signal_connect('edited') do |_cell, path_string, new_string|
88
- log.debug { 'edited' }
89
- path = Gtk::TreePath.new(path_string)
90
- path = @listview_model.convert_path_to_child_path(path)
91
- path = @filtered_model.convert_path_to_child_path(path)
92
- iter = @listview.model.get_iter(path)
93
- book = @parent.book_from_iter(@parent.selected_library, iter)
94
- book.title = new_string
95
- @listview.freeze
96
- @iconview.freeze
97
- @parent.fill_iter_with_book(iter, book)
98
- @iconview.unfreeze
99
- @listview.unfreeze
100
- end
101
- end
102
-
103
69
  TEXT_COLUMNS = [
104
70
  [_('Authors'), Columns::AUTHORS],
105
71
  [_('ISBN'), Columns::ISBN],
@@ -107,12 +73,12 @@ module Alexandria
107
73
  [_('Publish Year'), Columns::PUBLISH_DATE],
108
74
  [_('Binding'), Columns::EDITION],
109
75
  [_('Loaned To'), Columns::LOANED_TO]
110
- ]
76
+ ].freeze
111
77
  CHECK_COLUMNS = [
112
78
  [_('Read'), Columns::REDD],
113
79
  [_('Own'), Columns::OWN],
114
80
  [_('Want'), Columns::WANT]
115
- ]
81
+ ].freeze
116
82
 
117
83
  def setup_books_listview
118
84
  log.debug { 'setup_books_listview' }
@@ -125,13 +91,13 @@ module Alexandria
125
91
  setup_check_column title, iterid
126
92
  end
127
93
  setup_rating_column
128
- @listview.selection.mode = Gtk::SELECTION_MULTIPLE
94
+ @listview.selection.mode = :multiple
129
95
  @listview.selection.signal_connect('changed') do
130
96
  log.debug { 'changed' }
131
97
  @parent.on_books_selection_changed
132
98
  end
133
99
  setup_tags_column
134
- setup_listview_hack
100
+ setup_row_activation
135
101
  setup_view_source_dnd(@listview)
136
102
  end
137
103
 
@@ -140,24 +106,19 @@ module Alexandria
140
106
  title = _('Tags')
141
107
  log.debug { 'Create listview column for tags...' }
142
108
  renderer = Gtk::CellRendererText.new
143
- renderer.ellipsize = Pango::ELLIPSIZE_END if Pango.ellipsizable?
109
+ renderer.ellipsize = Pango::ELLIPSIZE_END
144
110
  column = Gtk::TreeViewColumn.new(title, renderer,
145
111
  text: Columns::TAGS)
146
- column.widget = Gtk::Label.new(title).show
147
112
  column.sort_column_id = Columns::TAGS
148
113
  column.resizable = true
149
114
  @listview.append_column(column)
150
115
  end
151
116
 
152
- def setup_listview_hack
117
+ def setup_row_activation
153
118
  @listview.signal_connect('row-activated') do
154
- # Dirty hack to avoid the beginning of a drag within this
155
- # handler.
156
119
  log.debug { 'row-activated' }
157
- Gtk.timeout_add(100) do
158
- @actiongroup['Properties'].activate
159
- false
160
- end
120
+ @actiongroup['Properties'].activate
121
+ false
161
122
  end
162
123
  end
163
124
 
@@ -165,16 +126,14 @@ module Alexandria
165
126
  title = _('Rating')
166
127
  log.debug { 'Create listview column for %s...' % title }
167
128
  column = Gtk::TreeViewColumn.new(title)
168
- column.widget = Gtk::Label.new(title).show
169
- column.sizing = Gtk::TreeViewColumn::FIXED
170
- column.fixed_width = column.min_width = column.max_width =
171
- (Icons::STAR_SET.width + 1) * MAX_RATING_STARS
129
+ column.sizing = :fixed
130
+ width = (Icons::STAR_SET.width + 1) * MAX_RATING_STARS
131
+ column.fixed_width = column.min_width = column.max_width = width
172
132
  MAX_RATING_STARS.times do |i|
173
133
  renderer = Gtk::CellRendererPixbuf.new
134
+ renderer.xalign = 0.0
174
135
  column.pack_start(renderer, false)
175
- column.set_cell_data_func(renderer) do |_col, cell, _model, iter|
176
- iter = @listview_model.convert_iter_to_child_iter(iter)
177
- iter = @filtered_model.convert_iter_to_child_iter(iter)
136
+ column.set_cell_data_func(renderer) do |_tree_column, cell, _tree_model, iter|
178
137
  rating = (iter[Columns::RATING] - MAX_RATING_STARS).abs
179
138
  cell.pixbuf = rating >= i.succ ?
180
139
  Icons::STAR_SET : Icons::STAR_UNSET
@@ -225,30 +184,15 @@ module Alexandria
225
184
  end
226
185
  end
227
186
  column = Gtk::TreeViewColumn.new(title, renderer, text: iterid)
228
- column.widget = Gtk::Label.new(title).show
229
187
  column.sort_column_id = iterid
230
188
  column.resizable = true
231
189
  log.debug { 'Create listview column for %s...' % title }
232
- setup_column = proc do |iter, cell, col|
233
- state = iter[col]
234
- cell.set_active(state)
235
- cell.activatable = true
236
- end
237
- log.debug { "Setting cell_data_func for #{renderer}" }
238
- column.set_cell_data_func(renderer) do |_col, cell, _model, iter|
239
- iter = @listview_model.convert_iter_to_child_iter(iter)
240
- iter = @filtered_model.convert_iter_to_child_iter(iter)
241
- case iterid
242
- when 12
243
- setup_column.call(iter, cell, Columns::REDD)
244
- when 13
245
- setup_column.call(iter, cell, Columns::OWN)
246
- when 14
247
- setup_column.call(iter, cell, Columns::WANT)
248
- own_state = iter[Columns::OWN]
249
- cell.inconsistent = own_state
250
- end
190
+
191
+ column.add_attribute(renderer, 'active', iterid)
192
+ if iterid == Columns::WANT
193
+ column.add_attribute(renderer, 'inconsistent', Columns::OWN)
251
194
  end
195
+
252
196
  log.debug { "append_column #{column}" }
253
197
  @listview.append_column(column)
254
198
  end
@@ -256,10 +200,9 @@ module Alexandria
256
200
  def setup_text_column(title, iterid)
257
201
  log.debug { 'Create listview column for %s...' % title }
258
202
  renderer = Gtk::CellRendererText.new
259
- renderer.ellipsize = Pango::ELLIPSIZE_END if Pango.ellipsizable?
203
+ renderer.ellipsize = Pango::ELLIPSIZE_END
260
204
  column = Gtk::TreeViewColumn.new(title, renderer,
261
205
  text: iterid)
262
- column.widget = Gtk::Label.new(title).show
263
206
  column.sort_column_id = iterid
264
207
  column.resizable = true
265
208
  @listview.append_column(column)
@@ -298,8 +241,10 @@ module Alexandria
298
241
  @listview.columns.each do |c|
299
242
  if cols_width.key?(c.title)
300
243
  log.debug { "#{c.title} : #{cols_width[c.title]}" }
301
- c.sizing = Gtk::TreeViewColumn::FIXED
302
- c.fixed_width = cols_width[c.title]
244
+ width = cols_width[c.title]
245
+ next if width.zero?
246
+ c.sizing = :fixed
247
+ c.fixed_width = width
303
248
  end
304
249
  end
305
250
  end
@@ -1,5 +1,5 @@
1
1
  # Copyright (C) 2004-2006 Laurent Sansonetti
2
- # Copyright (C) 2011 Matijs van Zuijlen
2
+ # Copyright (C) 2011, 2016 Matijs van Zuijlen
3
3
  #
4
4
  # Alexandria is free software; you can redistribute it and/or
5
5
  # modify it under the terms of the GNU General Public License as
@@ -16,133 +16,136 @@
16
16
  # write to the Free Software Foundation, Inc., 51 Franklin Street,
17
17
  # Fifth Floor, Boston, MA 02110-1301 USA.
18
18
 
19
- class Gdk::Event
20
- def ==(obj)
21
- obj.is_a?(self.class) and time == obj.time and x == obj.x and y == obj.y and button == obj.button
19
+ module Alexandria
20
+ module EventOverrides
21
+ def ==(obj)
22
+ obj.is_a?(self.class) && (time == obj.time) && (x == obj.x) && (y == obj.y) && (button == obj.button)
23
+ end
22
24
  end
23
- end
24
25
 
25
- class Gtk::TreeView
26
- # include Alexandria::Logging
27
-
28
- class Context < Struct.new(:pressed_button,
29
- :x,
30
- :y,
31
- :cell_x,
32
- :cell_y,
33
- :button_press_handler,
34
- :motion_notify_handler,
35
- :button_release_handler,
36
- :drag_data_get_handler,
37
- :events,
38
- :source_start_button_mask,
39
- :source_targets,
40
- :source_actions,
41
- :pending_event,
42
- :drag_context)
43
-
44
- def initialize(*ary)
45
- super
46
- self.events ||= []
47
- end
26
+ module TreeViewOverrides
27
+ # include Alexandria::Logging
28
+
29
+ class Context < Struct.new(:pressed_button,
30
+ :x,
31
+ :y,
32
+ :cell_x,
33
+ :cell_y,
34
+ :button_press_handler,
35
+ :motion_notify_handler,
36
+ :button_release_handler,
37
+ :drag_data_get_handler,
38
+ :events,
39
+ :source_start_button_mask,
40
+ :source_targets,
41
+ :source_actions,
42
+ :pending_event,
43
+ :drag_context)
44
+
45
+ def initialize(*ary)
46
+ super
47
+ self.events ||= []
48
+ end
48
49
 
49
- def pending_event?
50
- pending_event
50
+ def pending_event?
51
+ pending_event
52
+ end
51
53
  end
52
- end
53
-
54
- alias_method :old_enable_model_drag_source, :enable_model_drag_source
55
- def enable_model_drag_source(start_button_mask, targets, actions)
56
- old_enable_model_drag_source(start_button_mask, targets, actions)
57
54
 
58
- @context = Context.new
59
- @context.source_start_button_mask = start_button_mask
60
- @context.source_targets = Gtk::TargetList.new(targets)
61
- @context.source_actions = actions
55
+ def enable_model_drag_source(start_button_mask, targets, actions)
56
+ super
62
57
 
63
- @context.button_press_handler =
64
- signal_connect('button_press_event') do |_widget, event, _data|
65
- button_press_event(event)
66
- end
67
- end
58
+ @context = Context.new
59
+ @context.source_start_button_mask = start_button_mask
60
+ @context.source_targets = Gtk::TargetList.new(targets)
61
+ @context.source_actions = actions
68
62
 
69
- def drag_context
70
- @context.drag_context
71
- end
63
+ @context.button_press_handler =
64
+ signal_connect('button_press_event') do |_widget, event, _data|
65
+ button_press_event(event)
66
+ end
67
+ end
72
68
 
73
- private
69
+ def drag_context
70
+ @context.drag_context
71
+ end
74
72
 
75
- def stop_drag_check
76
- raise if @context.nil?
77
- @context.events.clear
78
- @context.pending_event = false
79
- signal_handler_disconnect(@context.motion_notify_handler)
80
- signal_handler_disconnect(@context.button_release_handler)
81
- end
73
+ private
82
74
 
83
- def button_release_event(_event)
84
- @context.events.each { |evnt| Gtk.propagate_event(self, evnt) }
85
- stop_drag_check
86
- false
87
- end
75
+ def stop_drag_check
76
+ raise if @context.nil?
77
+ @context.events.clear
78
+ @context.pending_event = false
79
+ signal_handler_disconnect(@context.motion_notify_handler)
80
+ signal_handler_disconnect(@context.button_release_handler)
81
+ end
88
82
 
89
- def motion_notify_event(event)
90
- if Gtk::Drag.threshold?(self, @context.x, @context.y, event.x, event.y)
83
+ def button_release_event(_event)
84
+ @context.events.each { |evnt| Gtk.propagate_event(self, evnt) }
91
85
  stop_drag_check
92
- paths = []
93
- selection.selected_each { |_model, path, _iter| paths << path }
94
- @context.drag_context = Gtk::Drag.begin(self,
95
- @context.source_targets,
96
- @context.source_actions,
97
- @context.pressed_button,
98
- event)
86
+ false
99
87
  end
100
- true
101
- end
102
-
103
- def button_press_event(event)
104
- return false if event.button == 3
105
- return false if event.window != bin_window
106
- return false if @context.events.include?(event)
107
88
 
108
- if @context.pending_event?
109
- @context.events << event
110
- return true
89
+ def motion_notify_event(event)
90
+ if drag_check_threshold(@context.x, @context.y, event.x, event.y)
91
+ stop_drag_check
92
+ paths = []
93
+ selection.each { |_model, path, _iter| paths << path }
94
+ @context.drag_context = drag_begin(@context.source_targets,
95
+ @context.source_actions,
96
+ @context.pressed_button,
97
+ event)
98
+ end
99
+ true
111
100
  end
112
101
 
113
- return false if event.event_type == Gdk::Event::BUTTON2_PRESS
102
+ def button_press_event(event)
103
+ return false if event.button == 3
104
+ return false if event.window != bin_window
105
+ return false if @context.events.include?(event)
114
106
 
115
- path, _, cell_x, cell_y = get_path_at_pos(event.x, event.y)
116
- return false if path.nil?
107
+ if @context.pending_event?
108
+ @context.events << event
109
+ return true
110
+ end
117
111
 
118
- # call_parent = (event.state.control_mask? or event.state.shift_mask?) or !selected or event.button != 1
119
- call_parent = !selection.path_is_selected?(path) or
120
- event.button != 1
112
+ return false if event.event_type == :'2button_press'
121
113
 
122
- if call_parent
123
- signal_handler_block(@context.button_press_handler) do
124
- signal_emit('button_press_event', event)
125
- end
126
- end
114
+ path, _, cell_x, cell_y = get_path_at_pos(event.x, event.y)
115
+ return false if path.nil?
127
116
 
128
- if selection.path_is_selected?(path)
129
- @context.pending_event = true
130
- @context.pressed_button = event.button
131
- @context.x = event.x
132
- @context.y = event.y
133
- @context.cell_x = cell_x
134
- @context.cell_y = cell_y
135
- @context.motion_notify_handler =
136
- signal_connect('motion_notify_event') do |_widget, evnt, _data|
137
- motion_notify_event(evnt)
138
- end
139
- @context.button_release_handler =
140
- signal_connect('button_release_event') do |_widget, evnt, _data|
141
- button_release_event(evnt)
117
+ # call_parent = (event.state.control_mask? or event.state.shift_mask?) or !selected or event.button != 1
118
+ (call_parent = !selection.path_is_selected?(path)) ||
119
+ (event.button != 1)
120
+
121
+ if call_parent
122
+ signal_handler_block(@context.button_press_handler) do
123
+ signal_emit('button_press_event', event)
142
124
  end
143
- @context.events << event unless call_parent
144
- end
125
+ end
145
126
 
146
- true
127
+ if selection.path_is_selected?(path)
128
+ @context.pending_event = true
129
+ @context.pressed_button = event.button
130
+ @context.x = event.x
131
+ @context.y = event.y
132
+ @context.cell_x = cell_x
133
+ @context.cell_y = cell_y
134
+ @context.motion_notify_handler =
135
+ signal_connect('motion_notify_event') do |_widget, evnt, _data|
136
+ motion_notify_event(evnt)
137
+ end
138
+ @context.button_release_handler =
139
+ signal_connect('button_release_event') do |_widget, evnt, _data|
140
+ button_release_event(evnt)
141
+ end
142
+ @context.events << event unless call_parent
143
+ end
144
+
145
+ true
146
+ end
147
147
  end
148
148
  end
149
+
150
+ Gdk::Event.prepend Alexandria::EventOverrides
151
+ Gtk::TreeView.prepend Alexandria::TreeViewOverrides