Allow drag and drop of books onto formats in the Tag Browser to convert them. Fixes #1945890 [[Enhancement] Drag book to format in the Tag browser to convert it to that format](https://bugs.launchpad.net/calibre/+bug/1945890)

This commit is contained in:
Kovid Goyal 2021-10-05 13:17:38 +05:30
parent afe7d69681
commit 200b62d25c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 27 additions and 6 deletions

View File

@ -160,7 +160,15 @@ class ConvertAction(InterfaceAction):
return return
self.do_convert(book_ids, bulk=bulk) self.do_convert(book_ids, bulk=bulk)
def do_convert(self, book_ids, bulk=None): def convert_ebooks_to_format(self, book_ids, to_fmt):
from calibre.customize.ui import available_output_formats
to_fmt = to_fmt.upper()
if to_fmt.lower() not in available_output_formats():
return error_dialog(self.gui, _('Cannot convert'), _(
'Conversion to the {} format is not supported').format(to_fmt), show=True)
self.do_convert(book_ids, output_fmt=to_fmt, auto_conversion=True)
def do_convert(self, book_ids, bulk=None, auto_conversion=False, output_fmt=None):
previous = self.gui.library_view.currentIndex() previous = self.gui.library_view.currentIndex()
rows = [x.row() for x in rows = [x.row() for x in
self.gui.library_view.selectionModel().selectedRows()] self.gui.library_view.selectionModel().selectedRows()]
@ -168,14 +176,14 @@ class ConvertAction(InterfaceAction):
if bulk or (bulk is None and len(book_ids) > 1): if bulk or (bulk is None and len(book_ids) > 1):
self.__bulk_queue = convert_bulk_ebook(self.gui, self.queue_convert_jobs, self.__bulk_queue = convert_bulk_ebook(self.gui, self.queue_convert_jobs,
self.gui.library_view.model().db, book_ids, self.gui.library_view.model().db, book_ids,
out_format=prefs['output_format'], args=(rows, previous, out_format=output_fmt or prefs['output_format'], args=(rows, previous,
self.book_converted)) self.book_converted))
if self.__bulk_queue is None: if self.__bulk_queue is None:
return return
num = len(self.__bulk_queue.book_ids) num = len(self.__bulk_queue.book_ids)
else: else:
jobs, changed, bad = convert_single_ebook(self.gui, jobs, changed, bad = convert_single_ebook(self.gui,
self.gui.library_view.model().db, book_ids, out_format=prefs['output_format']) self.gui.library_view.model().db, book_ids, out_format=output_fmt or prefs['output_format'], auto_conversion=auto_conversion)
self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.queue_convert_jobs(jobs, changed, bad, rows, previous,
self.book_converted) self.book_converted)
num = len(jobs) num = len(jobs)

View File

@ -317,6 +317,7 @@ class TagsModel(QAbstractItemModel): # {{{
user_categories_edited = pyqtSignal(object, object) user_categories_edited = pyqtSignal(object, object)
user_category_added = pyqtSignal() user_category_added = pyqtSignal()
show_error_after_event_loop_tick_signal = pyqtSignal(object, object, object) show_error_after_event_loop_tick_signal = pyqtSignal(object, object, object)
convert_requested = pyqtSignal(object, object)
def __init__(self, parent, prefs=gprefs): def __init__(self, parent, prefs=gprefs):
QAbstractItemModel.__init__(self, parent) QAbstractItemModel.__init__(self, parent)
@ -977,7 +978,7 @@ class TagsModel(QAbstractItemModel): # {{{
if node.type == TagTreeItem.TAG: if node.type == TagTreeItem.TAG:
fm = self.db.metadata_for_field(node.tag.category) fm = self.db.metadata_for_field(node.tag.category)
if node.tag.category in \ if node.tag.category in \
('tags', 'series', 'authors', 'rating', 'publisher', 'languages') or \ ('tags', 'series', 'authors', 'rating', 'publisher', 'languages', 'formats') or \
(fm['is_custom'] and ( (fm['is_custom'] and (
fm['datatype'] in ['text', 'rating', 'series', fm['datatype'] in ['text', 'rating', 'series',
'enumeration'] or ( 'enumeration'] or (
@ -1038,9 +1039,15 @@ class TagsModel(QAbstractItemModel): # {{{
self.refresh_required.emit() self.refresh_required.emit()
self.user_category_added.emit() self.user_category_added.emit()
def handle_drop_on_format(self, fmt, book_ids):
self.convert_requested.emit(book_ids, fmt)
def handle_drop(self, on_node, ids): def handle_drop(self, on_node, ids):
# print 'Dropped ids:', ids, on_node.tag # print 'Dropped ids:', ids, on_node.tag
key = on_node.tag.category key = on_node.tag.category
if key == 'formats':
self.handle_drop_on_format(on_node.tag.name, ids)
return
if (key == 'authors' and len(ids) >= 5): if (key == 'authors' and len(ids) >= 5):
if not confirm('<p>'+_('Changing the authors for several books can ' if not confirm('<p>'+_('Changing the authors for several books can '
'take a while. Are you sure?') + 'take a while. Are you sure?') +
@ -1393,12 +1400,13 @@ class TagsModel(QAbstractItemModel): # {{{
ans |= Qt.ItemFlag.ItemIsDragEnabled ans |= Qt.ItemFlag.ItemIsDragEnabled
fm = self.db.metadata_for_field(category) fm = self.db.metadata_for_field(category)
if category in \ if category in \
('tags', 'series', 'authors', 'rating', 'publisher', 'languages') or \ ('tags', 'series', 'authors', 'rating', 'publisher', 'languages', 'formats') or \
(fm['is_custom'] and (fm['is_custom'] and
fm['datatype'] in ['text', 'rating', 'series', 'enumeration']): fm['datatype'] in ['text', 'rating', 'series', 'enumeration']):
ans |= Qt.ItemFlag.ItemIsDropEnabled ans |= Qt.ItemFlag.ItemIsDropEnabled
else: else:
ans |= Qt.ItemFlag.ItemIsDropEnabled if node.type != TagTreeItem.CATEGORY or node.category_key != 'formats':
ans |= Qt.ItemFlag.ItemIsDropEnabled
return ans return ans
def supportedDropActions(self): def supportedDropActions(self):

View File

@ -216,9 +216,14 @@ class TagsView(QTreeView): # {{{
self._model.user_categories_edited.connect(self.user_categories_edited, self._model.user_categories_edited.connect(self.user_categories_edited,
type=Qt.ConnectionType.QueuedConnection) type=Qt.ConnectionType.QueuedConnection)
self._model.drag_drop_finished.connect(self.drag_drop_finished) self._model.drag_drop_finished.connect(self.drag_drop_finished)
self._model.convert_requested.connect(self.convert_requested)
self.set_look_and_feel(first=True) self.set_look_and_feel(first=True)
QApplication.instance().palette_changed.connect(self.set_style_sheet, type=Qt.ConnectionType.QueuedConnection) QApplication.instance().palette_changed.connect(self.set_style_sheet, type=Qt.ConnectionType.QueuedConnection)
def convert_requested(self, book_ids, to_fmt):
from calibre.gui2.ui import get_gui
get_gui().iactions['Convert Books'].convert_ebooks_to_format(book_ids, to_fmt)
def set_style_sheet(self): def set_style_sheet(self):
stylish_tb = ''' stylish_tb = '''
QTreeView { QTreeView {