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.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +9 -0
- data/.gitignore +5 -2
- data/.hound.yml +2 -0
- data/.rubocop.yml +113 -45
- data/.rubocop_todo.yml +82 -170
- data/.simplecov +5 -1
- data/.travis.yml +45 -0
- data/.yardopts +1 -1
- data/CHANGELOG.md +60 -0
- data/ChangeLog.0 +33 -35
- data/Gemfile +6 -5
- data/INSTALL.md +164 -0
- data/README.md +52 -42
- data/Rakefile +95 -109
- data/TODO.md +9 -1
- data/alexandria-book-collection-manager.gemspec +52 -45
- data/bin/alexandria +31 -53
- data/doc/AUTHORS +61 -0
- data/doc/BUGS +31 -0
- data/doc/FAQ +365 -0
- data/doc/HACKING +19 -0
- data/doc/NEWS +341 -0
- data/doc/alexandria.1 +120 -0
- data/doc/cuecat_support.rdoc +67 -0
- data/doc/dependency_decisions.yml +80 -0
- data/lib/alexandria.rb +29 -37
- data/lib/alexandria/about.rb +52 -51
- data/lib/alexandria/book_providers.rb +94 -101
- data/lib/alexandria/book_providers/adlibris.rb +45 -85
- data/lib/alexandria/book_providers/amazon_aws.rb +105 -113
- data/lib/alexandria/book_providers/amazon_ecs_util.rb +293 -324
- data/lib/alexandria/book_providers/barnes_and_noble.rb +54 -53
- data/lib/alexandria/book_providers/douban.rb +29 -51
- data/lib/alexandria/book_providers/proxis.rb +42 -59
- data/lib/alexandria/book_providers/pseudomarc.rb +79 -99
- data/lib/alexandria/book_providers/siciliano.rb +68 -70
- data/lib/alexandria/book_providers/thalia.rb +46 -45
- data/lib/alexandria/book_providers/web.rb +17 -33
- data/lib/alexandria/book_providers/worldcat.rb +74 -102
- data/lib/alexandria/book_providers/z3950.rb +170 -174
- data/lib/alexandria/config.rb +5 -3
- data/lib/alexandria/console.rb +10 -21
- data/lib/alexandria/default_preferences.rb +37 -0
- data/lib/alexandria/execution_queue.rb +17 -15
- data/lib/alexandria/export_format.rb +47 -0
- data/lib/alexandria/export_library.rb +188 -302
- data/lib/alexandria/import_library.rb +114 -155
- data/lib/alexandria/import_library_csv.rb +46 -96
- data/lib/alexandria/library_collection.rb +79 -0
- data/lib/alexandria/library_sort_order.rb +45 -0
- data/lib/alexandria/library_store.rb +233 -0
- data/lib/alexandria/logging.rb +15 -19
- data/lib/alexandria/models/book.rb +15 -20
- data/lib/alexandria/models/library.rb +81 -363
- data/lib/alexandria/net.rb +7 -6
- data/lib/alexandria/preferences.rb +73 -91
- data/lib/alexandria/scanners.rb +4 -2
- data/lib/alexandria/scanners/{cuecat.rb → cue_cat.rb} +24 -20
- data/lib/alexandria/scanners/keyboard.rb +10 -8
- data/lib/alexandria/smart_library.rb +135 -171
- data/lib/alexandria/ui.rb +17 -15
- data/lib/alexandria/ui/about_dialog.rb +49 -0
- data/lib/alexandria/ui/{dialogs/acquire_dialog.rb → acquire_dialog.rb} +129 -152
- data/lib/alexandria/ui/alert_dialog.rb +64 -0
- data/lib/alexandria/ui/bad_isbns_dialog.rb +41 -0
- data/lib/alexandria/ui/{dialogs/barcode_animation.rb → barcode_animation.rb} +18 -15
- data/lib/alexandria/ui/{dialogs/book_properties_dialog.rb → book_properties_dialog.rb} +44 -61
- data/lib/alexandria/ui/{dialogs/book_properties_dialog_base.rb → book_properties_dialog_base.rb} +84 -89
- data/lib/alexandria/ui/builder_base.rb +9 -27
- data/lib/alexandria/ui/callbacks.rb +188 -186
- data/lib/alexandria/ui/columns.rb +2 -0
- data/lib/alexandria/ui/completion_models.rb +12 -23
- data/lib/alexandria/ui/confirm_erase_dialog.rb +33 -0
- data/lib/alexandria/ui/conflict_while_copying_dialog.rb +34 -0
- data/lib/alexandria/ui/dndable.rb +10 -8
- data/lib/alexandria/ui/error_dialog.rb +25 -0
- data/lib/alexandria/ui/export_dialog.rb +139 -0
- data/lib/alexandria/ui/icons.rb +49 -65
- data/lib/alexandria/ui/iconview.rb +15 -13
- data/lib/alexandria/ui/iconview_tooltips.rb +43 -58
- data/lib/alexandria/ui/import_dialog.rb +157 -0
- data/lib/alexandria/ui/init.rb +23 -33
- data/lib/alexandria/ui/keep_bad_isbn_dialog.rb +36 -0
- data/lib/alexandria/ui/libraries_combo.rb +18 -14
- data/lib/alexandria/ui/listview.rb +77 -88
- data/lib/alexandria/ui/main_app.rb +26 -26
- data/lib/alexandria/ui/misc_dialogs.rb +10 -0
- data/lib/alexandria/ui/multi_drag_treeview.rb +30 -41
- data/lib/alexandria/ui/{dialogs/new_book_dialog.rb → new_book_dialog.rb} +168 -215
- data/lib/alexandria/ui/new_book_dialog_manual.rb +139 -0
- data/lib/alexandria/ui/new_provider_dialog.rb +100 -0
- data/lib/alexandria/ui/new_smart_library_dialog.rb +74 -0
- data/lib/alexandria/ui/preferences_dialog.rb +313 -0
- data/lib/alexandria/ui/provider_preferences_base_dialog.rb +95 -0
- data/lib/alexandria/ui/provider_preferences_dialog.rb +35 -0
- data/lib/alexandria/ui/really_delete_dialog.rb +53 -0
- data/lib/alexandria/ui/{sidepane.rb → sidepane_manager.rb} +62 -72
- data/lib/alexandria/ui/skip_entry_dialog.rb +33 -0
- data/lib/alexandria/ui/smart_library_properties_dialog.rb +60 -0
- data/lib/alexandria/ui/{dialogs/smart_library_properties_dialog_base.rb → smart_library_properties_dialog_base.rb} +96 -172
- data/lib/alexandria/ui/smart_library_rule_box.rb +119 -0
- data/lib/alexandria/ui/sound.rb +13 -13
- data/lib/alexandria/ui/ui_manager.rb +262 -283
- data/lib/alexandria/undo_manager.rb +3 -0
- data/lib/alexandria/version.rb +6 -19
- data/lib/alexandria/web_themes.rb +24 -21
- data/po/Makefile +2 -2
- data/po/cs.po +993 -880
- data/po/cy.po +957 -874
- data/po/de.po +990 -869
- data/po/el.po +989 -869
- data/po/es.po +985 -865
- data/po/fr.po +986 -870
- data/po/ga.po +907 -823
- data/po/gl.po +981 -865
- data/po/it.po +986 -868
- data/po/ja.po +969 -853
- data/po/mk.po +983 -863
- data/po/nb.po +979 -863
- data/po/nl.po +983 -864
- data/po/pl.po +1020 -969
- data/po/pt.po +988 -861
- data/po/pt_BR.po +984 -868
- data/po/ru.po +992 -873
- data/po/sk.po +987 -869
- data/po/sv.po +977 -861
- data/po/uk.po +975 -865
- data/po/zh_TW.po +976 -860
- data/schemas/alexandria.schemas +25 -3
- data/share/alexandria/glade/acquire_dialog__builder.glade +15 -12
- data/share/alexandria/glade/book_properties_dialog__builder.glade +171 -299
- data/share/alexandria/glade/main_app__builder.glade +24 -33
- data/share/alexandria/glade/new_book_dialog__builder.glade +27 -59
- data/share/alexandria/glade/preferences_dialog__builder.glade +250 -290
- data/share/gnome/help/alexandria/C/introduction.xml +0 -8
- data/share/gnome/help/alexandria/C/searching.xml +1 -1
- data/share/gnome/help/alexandria/C/smart-libraries.xml +2 -2
- data/share/gnome/help/alexandria/C/working-with-libraries.xml +1 -1
- data/share/gnome/help/alexandria/fr/alexandria.xml +1 -1
- data/share/gnome/help/alexandria/ja/introduction.xml +0 -8
- data/share/gnome/help/alexandria/ja/smart-libraries.xml +1 -1
- data/spec/alexandria/book_providers/world_cat_provider_spec.rb +160 -0
- data/spec/alexandria/book_providers_spec.rb +77 -210
- data/spec/alexandria/book_spec.rb +16 -12
- data/spec/alexandria/console_spec.rb +27 -0
- data/spec/alexandria/export_library_spec.rb +130 -0
- data/spec/alexandria/library_spec.rb +130 -172
- data/spec/alexandria/library_store_spec.rb +37 -0
- data/spec/alexandria/preferences_spec.rb +46 -17
- data/spec/alexandria/scanners/cue_cat_spec.rb +52 -0
- data/spec/alexandria/smart_library_spec.rb +32 -25
- data/spec/alexandria/ui/about_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/acquire_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/alert_dialog_spec.rb +16 -0
- data/spec/alexandria/ui/bad_isbns_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/book_properties_dialog_spec.rb +17 -0
- data/spec/alexandria/ui/confirm_erase_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/conflict_while_copying_dialog_spec.rb +16 -0
- data/spec/alexandria/ui/error_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/export_dialog_spec.rb +15 -0
- data/spec/alexandria/ui/icons_spec.rb +26 -0
- data/spec/alexandria/ui/iconview_spec.rb +9 -21
- data/spec/alexandria/ui/import_dialog_spec.rb +41 -0
- data/spec/alexandria/ui/keep_bad_isbn_dialog_spec.rb +17 -0
- data/spec/alexandria/ui/main_app_spec.rb +8 -33
- data/spec/alexandria/ui/new_book_dialog_manual_spec.rb +15 -0
- data/spec/alexandria/ui/new_book_dialog_spec.rb +22 -0
- data/spec/alexandria/ui/new_provider_dialog_spec.rb +30 -0
- data/spec/alexandria/ui/new_smart_library_dialog_spec.rb +39 -0
- data/spec/alexandria/ui/preferences_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/provider_preferences_dialog_spec.rb +34 -0
- data/spec/alexandria/ui/really_delete_dialog_spec.rb +16 -0
- data/spec/alexandria/ui/sidepane_manager_spec.rb +15 -0
- data/spec/alexandria/ui/skip_entry_dialog_spec.rb +14 -0
- data/spec/alexandria/ui/smart_library_properties_dialog_spec.rb +32 -0
- data/spec/alexandria/ui/sound_spec.rb +4 -2
- data/spec/alexandria/ui/ui_manager_spec.rb +45 -20
- data/spec/end_to_end/basic_run_spec.rb +57 -0
- data/spec/spec_helper.rb +66 -33
- data/tasks/setup.rb +5 -3
- data/tasks/spec.rake +18 -3
- data/util/rake/fileinstall.rb +38 -40
- data/util/rake/gettextgenerate.rb +15 -70
- data/util/rake/omfgenerate.rb +10 -10
- metadata +176 -60
- data/INSTALL.rdoc +0 -148
- data/dogtail/basic_run_test.py +0 -9
- data/lib/alexandria/book_providers/bol_it.rb +0 -160
- data/lib/alexandria/book_providers/deastore.rb +0 -273
- data/lib/alexandria/book_providers/ibs_it.rb +0 -147
- data/lib/alexandria/book_providers/mcu.rb +0 -169
- data/lib/alexandria/book_providers/renaud.rb +0 -140
- data/lib/alexandria/book_providers/webster_it.rb +0 -167
- data/lib/alexandria/ui/dialogs/about_dialog.rb +0 -59
- data/lib/alexandria/ui/dialogs/alert_dialog.rb +0 -70
- data/lib/alexandria/ui/dialogs/bad_isbns_dialog.rb +0 -43
- data/lib/alexandria/ui/dialogs/export_dialog.rb +0 -171
- data/lib/alexandria/ui/dialogs/import_dialog.rb +0 -196
- data/lib/alexandria/ui/dialogs/misc_dialogs.rb +0 -85
- data/lib/alexandria/ui/dialogs/new_book_dialog_manual.rb +0 -154
- data/lib/alexandria/ui/dialogs/new_smart_library_dialog.rb +0 -74
- data/lib/alexandria/ui/dialogs/preferences_dialog.rb +0 -578
- data/lib/alexandria/ui/dialogs/smart_library_properties_dialog.rb +0 -57
- data/spec/alexandria/scanners/cuecat_spec.rb +0 -65
- data/spec/alexandria/ui/dialogs_spec.rb +0 -94
- data/spec/alexandria/ui/sidepane_spec.rb +0 -27
- data/spec/alexandria/ui/ui_utilities_spec.rb +0 -60
- data/spec/alexandria/utilities_spec.rb +0 -50
- data/tasks/dogtail.rake +0 -4
data/lib/alexandria/ui/sound.rb
CHANGED
@@ -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
|
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
|
-
|
42
|
+
log.debug { "Already playing #{effect}." }
|
41
43
|
else
|
42
|
-
|
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(
|
50
|
-
demuxer = Gst::ElementFactory.make(
|
51
|
-
decoder = Gst::ElementFactory.make(
|
52
|
-
converter = Gst::ElementFactory.make(
|
53
|
-
audiosink = Gst::ElementFactory.make(
|
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(
|
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
|
-
|
78
|
-
|
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
|
-
#
|
2
|
-
|
3
|
-
#
|
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
|
-
#
|
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
|
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,
|
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:
|
21
|
+
GetText.bindtextdomain(Alexandria::TEXTDOMAIN, charset: "UTF-8")
|
31
22
|
|
32
23
|
def initialize(parent)
|
33
|
-
super(
|
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(
|
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 {
|
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(
|
84
|
-
@iconview_model = Gtk::TreeModelSort.new(
|
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 =
|
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 {
|
94
|
+
log.debug { "setup_toolbar" }
|
105
95
|
setup_book_providers
|
106
96
|
add_main_toolbar_items
|
107
|
-
@toolbar = @uimanager.get_widget(
|
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[
|
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,
|
112
|
+
@uimanager.add_ui(mid, "ui/", "MainToolbar", "MainToolbar",
|
123
113
|
:toolbar, false)
|
124
|
-
@uimanager.add_ui(mid,
|
114
|
+
@uimanager.add_ui(mid, "ui/MainToolbar/", "New", "New",
|
125
115
|
:toolitem, false)
|
126
|
-
@uimanager.add_ui(mid,
|
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(
|
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 _(
|
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
|
-
[_(
|
152
|
-
|
153
|
-
_(
|
154
|
-
_(
|
155
|
-
_(
|
156
|
-
_(
|
157
|
-
_(
|
158
|
-
_(
|
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(
|
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 _(
|
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(_(
|
178
|
-
@toolbar_view_as.append_text(_(
|
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(
|
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 _(
|
181
|
+
eb.set_tooltip_text _("Choose how to show books")
|
192
182
|
end
|
193
183
|
|
194
184
|
def setup_book_providers
|
195
|
-
log.debug {
|
185
|
+
log.debug { "setup_book_providers" }
|
196
186
|
mid = @uimanager.new_merge_id
|
197
|
-
|
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
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
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 {
|
211
|
-
[
|
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
|
-
|
204
|
+
"ui", ui_file))
|
214
205
|
end
|
215
206
|
end
|
216
207
|
|
217
208
|
def setup_accel_group
|
218
|
-
log.debug {
|
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(
|
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 {
|
229
|
-
@library_popup = @uimanager.get_widget(
|
230
|
-
@smart_library_popup = @uimanager.get_widget(
|
231
|
-
@nolibrary_popup = @uimanager.get_widget(
|
232
|
-
@book_popup = @uimanager.get_widget(
|
233
|
-
@nobook_popup = @uimanager.get_widget(
|
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 {
|
238
|
-
@main_app.signal_connect(
|
239
|
-
@main_app.signal_connect(
|
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 {
|
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
|
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 {
|
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 {
|
293
|
+
log.debug { "library_button_press_event" }
|
303
294
|
|
304
295
|
# right click
|
305
296
|
if event_is_right_click event
|
306
|
-
log.debug {
|
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 =
|
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
|
-
|
353
|
-
|
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
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
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
|
-
|
384
|
-
|
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 {
|
393
|
-
|
394
|
-
widget.grab_focus
|
375
|
+
log.debug { "books_button_press_event" }
|
376
|
+
event_is_right_click event or return
|
395
377
|
|
396
|
-
|
397
|
-
obj, path = widget.is_a?(Gtk::TreeView) ? [widget.selection, path.first] : [widget, path]
|
378
|
+
widget.grab_focus
|
398
379
|
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
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
|
-
|
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
|
-
|
423
|
-
|
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
|
-
|
428
|
-
|
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
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
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_(
|
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
|
471
|
-
|
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[
|
474
|
-
@actiongroup[
|
455
|
+
@actiongroup["Properties"].sensitive = \
|
456
|
+
@actiongroup["OnlineInformation"].sensitive = \
|
475
457
|
books.length == 1
|
476
|
-
@actiongroup[
|
458
|
+
@actiongroup["SelectAll"].sensitive = \
|
477
459
|
books.length < library.length
|
478
460
|
|
479
|
-
@actiongroup[
|
480
|
-
@actiongroup[
|
481
|
-
@actiongroup[
|
482
|
-
@actiongroup[
|
461
|
+
@actiongroup["Delete"].sensitive = \
|
462
|
+
@actiongroup["DeselectAll"].sensitive = \
|
463
|
+
@actiongroup["Move"].sensitive =
|
464
|
+
@actiongroup["SetRating"].sensitive = !books.empty?
|
483
465
|
|
484
|
-
log.debug
|
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[
|
488
|
-
@actiongroup[
|
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 {
|
516
|
-
@actiongroup[
|
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 {
|
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[
|
528
|
-
@actiongroup[
|
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
|
-
|
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 {
|
543
|
-
@actiongroup[
|
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
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
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
|
-
|
575
|
-
|
576
|
-
@actiongroup[
|
577
|
-
|
578
|
-
|
579
|
-
|
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
|
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(
|
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 {
|
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 {
|
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 =
|
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 = _(
|
647
|
-
|
648
|
-
|
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
|
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(
|
618
|
+
recovery_dialog.signal_connect("response") do |_dialog, response_type|
|
661
619
|
recovery_dialog.destroy
|
662
|
-
if response_type ==
|
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
|
695
|
-
|
696
|
-
library.
|
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'")
|
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
|
-
|
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 {
|
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 {
|
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[
|
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 {
|
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 {
|
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
|
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 {
|
846
|
+
log.debug { "selected_library" }
|
891
847
|
if (iter = @library_listview.selection.selected)
|
892
|
-
|
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 {
|
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 +
|
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[
|
979
|
-
@actiongroup[
|
980
|
-
@actiongroup[
|
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[
|
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[
|
949
|
+
@actiongroup["AsIcons"]
|
992
950
|
when 1
|
993
|
-
@actiongroup[
|
951
|
+
@actiongroup["AsList"]
|
994
952
|
end
|
995
953
|
end
|
996
954
|
|
997
955
|
def restore_preferences
|
998
|
-
log.debug {
|
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[
|
1008
|
-
@actiongroup[
|
1009
|
-
@actiongroup[
|
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 {
|
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[
|
1039
|
-
@prefs.toolbar_visible = @actiongroup[
|
1040
|
-
@prefs.statusbar_visible = @actiongroup[
|
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 =
|
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 {
|
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
|
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
|
-
|
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
|
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
|
1112
|
-
4
|
1113
|
-
5
|
1114
|
-
6
|
1115
|
-
7
|
1116
|
-
8
|
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
|
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
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
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(
|
1195
|
-
@main_app.icon_name =
|
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,
|
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
|