diff --git a/src/calibre/gui2/actions/choose_library.py b/src/calibre/gui2/actions/choose_library.py index 30e2f79424..bc22c93c27 100644 --- a/src/calibre/gui2/actions/choose_library.py +++ b/src/calibre/gui2/actions/choose_library.py @@ -5,8 +5,64 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' +import os +from functools import partial + +from PyQt4.Qt import QMenu + +from calibre import isbytestring +from calibre.constants import filesystem_encoding +from calibre.utils.config import prefs +from calibre.gui2 import gprefs from calibre.gui2.actions import InterfaceAction +class LibraryUsageStats(object): + + def __init__(self): + self.stats = {} + self.read_stats() + + def read_stats(self): + stats = gprefs.get('library_usage_stats', {}) + self.stats = stats + + def write_stats(self): + locs = list(self.stats.keys()) + locs.sort(cmp=lambda x, y: cmp(self.stats[x], self.stats[y]), + reverse=True) + for key in locs[15:]: + self.stats.pop(key) + gprefs.set('library_usage_stats', self.stats) + + def canonicalize_path(self, lpath): + if isbytestring(lpath): + lpath = lpath.decode(filesystem_encoding) + lpath = lpath.replace(os.sep, '/') + return lpath + + def library_used(self, db): + lpath = self.canonicalize_path(db.library_path) + if lpath not in self.stats: + self.stats[lpath] = 0 + self.stats[lpath] += 1 + self.write_stats() + + def locations(self, db): + lpath = self.canonicalize_path(db.library_path) + locs = list(self.stats.keys()) + if lpath in locs: + locs.remove(lpath) + locs.sort(cmp=lambda x, y: cmp(self.stats[x], self.stats[y]), + reverse=True) + for loc in locs: + yield self.pretty(loc), loc + + def pretty(self, loc): + if loc.endswith('/'): + loc = loc[:-1] + return loc.split('/')[-1] + + class ChooseLibraryAction(InterfaceAction): name = 'Choose Library' @@ -17,10 +73,62 @@ class ChooseLibraryAction(InterfaceAction): self.count_changed(0) self.qaction.triggered.connect(self.choose_library) + self.stats = LibraryUsageStats() + self.create_action(spec=(_('Switch to library...'), 'lt.png', None, + None), attr='action_choose') + self.action_choose.triggered.connect(self.choose_library) + self.choose_menu = QMenu(self.gui) + self.choose_menu.addAction(self.action_choose) + self.qaction.setMenu(self.choose_menu) + + self.quick_menu = QMenu(_('Quick switch')) + self.quick_menu_action = self.choose_menu.addMenu(self.quick_menu) + self.qs_separator = self.choose_menu.addSeparator() + self.switch_actions = [] + for i in range(5): + ac = self.create_action(spec=('', None, None, None), + attr='switch_action%d'%i) + self.switch_actions.append(ac) + ac.setVisible(False) + ac.triggered.connect(partial(self.qs_requested, i)) + self.choose_menu.addAction(ac) + + def library_used(self, db): + self.stats.library_used(db) + self.build_menus() + + def build_menus(self): + db = self.gui.library_view.model().db + locations = list(self.stats.locations(db)) + for ac in self.switch_actions: + ac.setVisible(False) + self.quick_menu.clear() + self.qs_locations = [i[1] for i in locations] + for name, loc in locations: + self.quick_menu.addAction(name, partial(self.switch_requested, + loc)) + + for i, x in enumerate(locations[:len(self.switch_actions)]): + name, loc = x + ac = self.switch_actions[i] + ac.setText(name) + ac.setVisible(True) + + self.quick_menu_action.setVisible(bool(locations)) + + def location_selected(self, loc): enabled = loc == 'library' self.qaction.setEnabled(enabled) + def switch_requested(self, location): + loc = location.replace('/', os.sep) + prefs['library_path'] = loc + self.gui.library_moved(loc) + + def qs_requested(self, idx, *args): + self.switch_requested(self.qs_locations[idx]) + def count_changed(self, new_count): text = self.action_spec[0]%new_count a = self.qaction diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 9e4b4f3865..820656d0e2 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -251,6 +251,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.donate_button.start_animation() self.iactions['Fetch News'].connect_scheduler() + self.iactions['Choose Library'].library_used(self.library_view.model().db) def start_content_server(self): from calibre.library.server.main import start_threaded_server @@ -368,6 +369,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.library_view.model().count_changed() self.iactions['Fetch News'].database_changed(db) prefs['library_path'] = self.library_path + self.iactions['Choose Library'].library_used(self.library_view.model().db) def location_selected(self, location):