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[a-zA-Z\d]{10,})-type_(?P\w{4})-v_(?P\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 ################################