diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 2d4e89492b..0d6f041736 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -129,18 +129,18 @@ class Plugin(object): zip_safe = False if zip_safe: sys.path.insert(0, self.plugin_path) - self._sys_insertion_path = self.plugin_path + self.sys_insertion_path = self.plugin_path else: from calibre.ptempfile import TemporaryDirectory self._sys_insertion_tdir = TemporaryDirectory('plugin_unzip') - self._sys_insertion_path = self._sys_insertion_tdir.__enter__(*args) - zf.extractall(self._sys_insertion_path) - sys.path.insert(0, self._sys_insertion_path) + self.sys_insertion_path = self._sys_insertion_tdir.__enter__(*args) + zf.extractall(self.sys_insertion_path) + sys.path.insert(0, self.sys_insertion_path) zf.close() def __exit__(self, *args): - ip, it = getattr(self, '_sys_insertion_path', None), getattr(self, + ip, it = getattr(self, 'sys_insertion_path', None), getattr(self, '_sys_insertion_tdir', None) if ip in sys.path: sys.path.remove(ip) diff --git a/src/calibre/devices/kindle/driver.py b/src/calibre/devices/kindle/driver.py index 96aa296b5d..3499f3b076 100644 --- a/src/calibre/devices/kindle/driver.py +++ b/src/calibre/devices/kindle/driver.py @@ -44,6 +44,7 @@ class KINDLE(USBMS): EBOOK_DIR_CARD_A = 'documents' DELETE_EXTS = ['.mbp'] SUPPORTS_SUB_DIRS = True + SUPPORTS_ANNOTATIONS = True WIRELESS_FILE_NAME_PATTERN = re.compile( r'(?P[^-]+)-asin_(?P<asin>[a-zA-Z\d]{10,})-type_(?P<type>\w{4})-v_(?P<index>\d+).*') @@ -60,6 +61,9 @@ class KINDLE(USBMS): 'replace') return mi + def get_annotations(self, path_map): + return {} + class KINDLE2(KINDLE): diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 679e86ab48..04219a387f 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -8,7 +8,7 @@ from functools import partial from binascii import unhexlify from PyQt4.Qt import QMenu, QAction, QActionGroup, QIcon, SIGNAL, QPixmap, \ - Qt + Qt, pyqtSignal from calibre.customize.ui import available_input_formats, available_output_formats, \ device_plugins @@ -218,6 +218,16 @@ class DeviceManager(Thread): '''Return callable that returns the list of books on device as two booklists''' return self.create_job(self._books, done, description=_('Get list of books on device')) + def _annotations(self, path_map): + return self.device.get_annotations(path_map) + + def annotations(self, path_map, done): + '''Return mapping of ids to annotations. Each annotation is of the + form (type, location_info, content). path_map is a mapping of + ids to paths on the device.''' + return self.create_job(self._annotations, done, args=[path_map], + description=_('Get annotations from device')) + def _sync_booklists(self, booklists): '''Sync metadata to device''' self.device.sync_booklists(booklists, end_session=False) @@ -298,6 +308,8 @@ class DeviceAction(QAction): class DeviceMenu(QMenu): + fetch_annotations = pyqtSignal() + def __init__(self, parent=None): QMenu.__init__(self, parent) self.group = QActionGroup(self) @@ -389,10 +401,16 @@ class DeviceMenu(QMenu): self.connect(self.group, SIGNAL('triggered(QAction*)'), self.change_default_action) - self.enable_device_actions(False) if opts.accounts: self.addSeparator() self.addMenu(self.email_to_menu) + self.addSeparator() + annot = self.addAction(_('Fetch annotations (experimental)')) + annot.setEnabled(False) + annot.triggered.connect(lambda x : + self.fetch_annotations.emit()) + self.annotation_action = annot + self.enable_device_actions(False) def change_default_action(self, action): config['default_send_to_device_action'] = repr(action) @@ -409,7 +427,8 @@ class DeviceMenu(QMenu): self.action_triggered(action) break - def enable_device_actions(self, enable, card_prefix=(None, None)): + def enable_device_actions(self, enable, card_prefix=(None, None), + device=None): for action in self.actions: if action.dest in ('main:', 'carda:0', 'cardb:0'): if not enable: @@ -428,6 +447,9 @@ class DeviceMenu(QMenu): else: action.setEnabled(False) + annot_enable = enable and getattr(device, 'SUPPORTS_ANNOTATIONS', False) + self.annotation_action.setEnabled(annot_enable) + class Emailer(Thread): diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index abafd4e58c..888600ebb2 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -617,6 +617,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.dispatch_sync_event) self.connect(self.action_sync, SIGNAL('triggered(bool)'), self._sync_menu.trigger_default) + self._sync_menu.fetch_annotations.connect(self.fetch_annotations) def add_spare_server(self, *args): self.spare_servers.append(Server(limit=int(config['worker_limit']/2.0))) @@ -855,7 +856,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.device_manager.device.__class__.get_gui_name()+\ _(' detected.'), 3000) self.device_connected = True - self._sync_menu.enable_device_actions(True, self.device_manager.device.card_prefix()) + self._sync_menu.enable_device_actions(True, + self.device_manager.device.card_prefix(), + self.device_manager.device) self.location_view.model().device_connected(self.device_manager.device) else: self.save_device_view_settings() @@ -918,7 +921,26 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.sync_catalogs() ############################################################################ + ######################### Fetch annotations ################################ + def fetch_annotations(self, *args): + #current_device = self.device_manager.device + path_map = {} + # code to calculate path_map + self.device_manager.annotations(Dispatcher(self.annotations_fetched), + path_map) + + def annotations_fetched(self, annotation_map): + if not annotation_map: return + from calibre.gui2.dialogs.progress import ProgressDialog + pd = ProgressDialog(_('Adding annotations'), + _('Annotations will be saved in the comments field'), + min=0, max=0, parent=self) + # code to add annotations to database should run in a separate + # thread as it could potentially take a long time + pd.exec_() + + ############################################################################ ################################# Add books ################################