%PDF- %PDF-
| Direktori : /usr/lib/calibre/calibre/gui2/actions/ |
| Current File : //usr/lib/calibre/calibre/gui2/actions/annotate.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from qt.core import pyqtSignal, QModelIndex, QThread, Qt
from calibre.gui2 import error_dialog
from calibre.gui2.actions import InterfaceAction
from calibre.devices.usbms.device import Device
from calibre.gui2.dialogs.progress import ProgressDialog
from polyglot.builtins import iteritems
class Updater(QThread): # {{{
update_progress = pyqtSignal(int)
update_done = pyqtSignal()
def __init__(self, parent, db, device, annotation_map, done_callback):
QThread.__init__(self, parent)
self.errors = {}
self.db = db
self.keep_going = True
self.pd = ProgressDialog(_('Merging user annotations into database'), '',
0, len(annotation_map), parent=parent)
self.device = device
self.annotation_map = annotation_map
self.done_callback = done_callback
self.pd.canceled_signal.connect(self.canceled)
self.pd.setModal(True)
self.pd.show()
self.update_progress.connect(self.pd.set_value,
type=Qt.ConnectionType.QueuedConnection)
self.update_done.connect(self.pd.hide, type=Qt.ConnectionType.QueuedConnection)
def canceled(self):
self.keep_going = False
self.pd.hide()
def run(self):
for i, id_ in enumerate(self.annotation_map):
if not self.keep_going:
break
bm = Device.UserAnnotation(self.annotation_map[id_][0],
self.annotation_map[id_][1])
try:
self.device.add_annotation_to_library(self.db, id_, bm)
except:
import traceback
self.errors[id_] = traceback.format_exc()
self.update_progress.emit(i)
self.update_done.emit()
self.done_callback(list(self.annotation_map.keys()), self.errors)
# }}}
class FetchAnnotationsAction(InterfaceAction):
name = 'Fetch Annotations'
action_spec = (_('Fetch annotations (experimental)'), None, None, ())
dont_add_to = frozenset(('menubar', 'toolbar', 'context-menu', 'toolbar-child'))
action_type = 'current'
def genesis(self):
self.qaction.triggered.connect(self.fetch_annotations)
def fetch_annotations(self, *args):
# Generate a path_map from selected ids
def get_ids_from_selected_rows():
rows = self.gui.library_view.selectionModel().selectedRows()
if not rows or len(rows) < 2:
rows = range(self.gui.library_view.model().rowCount(QModelIndex()))
ids = list(map(self.gui.library_view.model().id, rows))
return ids
def get_formats(id):
formats = db.formats(id, index_is_id=True)
fmts = []
if formats:
for format in formats.split(','):
fmts.append(format.lower())
return fmts
def get_device_path_from_id(id_):
paths = []
for x in ('memory', 'card_a', 'card_b'):
x = getattr(self.gui, x+'_view').model()
paths += x.paths_for_db_ids({id_}, as_map=True)[id_]
return paths[0].path if paths else None
def generate_annotation_paths(ids, db, device):
# Generate path templates
# Individual storage mount points scanned/resolved in driver.get_annotations()
path_map = {}
for id in ids:
path = get_device_path_from_id(id)
mi = db.get_metadata(id, index_is_id=True)
a_path = device.create_annotations_path(mi, device_path=path)
path_map[id] = dict(path=a_path, fmts=get_formats(id))
return path_map
device = self.gui.device_manager.device
if not getattr(device, 'SUPPORTS_ANNOTATIONS', False):
return error_dialog(self.gui, _('Not supported'),
_('Fetching annotations is not supported for this device'),
show=True)
if self.gui.current_view() is not self.gui.library_view:
return error_dialog(self.gui, _('Use library only'),
_('User annotations generated from main library only'),
show=True)
db = self.gui.library_view.model().db
# Get the list of ids
ids = get_ids_from_selected_rows()
if not ids:
return error_dialog(self.gui, _('No books selected'),
_('No books selected to fetch annotations from'),
show=True)
# Map ids to paths
path_map = generate_annotation_paths(ids, db, device)
# Dispatch to devices.kindle.driver.get_annotations()
self.gui.device_manager.annotations(self.Dispatcher(self.annotations_fetched),
path_map)
def annotations_fetched(self, job):
if not job.result:
return
if self.gui.current_view() is not self.gui.library_view:
return error_dialog(self.gui, _('Use library only'),
_('User annotations generated from main library only'),
show=True)
db = self.gui.library_view.model().db
device = self.gui.device_manager.device
self.__annotation_updater = Updater(self.gui, db, device, job.result,
self.Dispatcher(self.annotations_updated))
self.__annotation_updater.start()
def annotations_updated(self, ids, errors):
self.gui.library_view.model().refresh_ids(ids)
if errors:
db = self.gui.library_view.model().db
entries = []
for id_, tb in iteritems(errors):
title = id_
if isinstance(id_, int):
title = db.title(id_, index_is_id=True)
entries.extend([title, tb, ''])
error_dialog(self.gui, _('Some errors'),
_('Could not fetch annotations for some books. Click '
'"Show details" to see which ones.'),
det_msg='\n'.join(entries), show=True)