Category editor: Add a right click menu to change case of the selected entries. Fixes #1899316 [[Enhancement] Add the context menu in the Category editor and add the ability to change cases for the selected entries](https://bugs.launchpad.net/calibre/+bug/1899316)

Quickview: Fix nothing shown after clearing the search. Fixes #1899318 [No item is shown in the Quickview panel after clearing the search](https://bugs.launchpad.net/calibre/+bug/1899318)

Merge branch 'master' of https://github.com/cbhaley/calibre into master
This commit is contained in:
Kovid Goyal 2020-10-11 16:39:27 +05:30
commit 84eaea86b7
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 103 additions and 16 deletions

View File

@ -259,7 +259,7 @@ class Quickview(QDialog, Ui_Quickview):
self.books_table.horizontalHeader().sectionResized.connect(self.section_resized) self.books_table.horizontalHeader().sectionResized.connect(self.section_resized)
self.dock_button.clicked.connect(self.show_as_pane_changed) self.dock_button.clicked.connect(self.show_as_pane_changed)
self.gui.search.cleared.connect(self.indicate_no_items) self.view.model().search_done.connect(self.check_for_no_items)
# Enable the refresh button only when QV is locked # Enable the refresh button only when QV is locked
self.refresh_button.setEnabled(False) self.refresh_button.setEnabled(False)
@ -555,9 +555,12 @@ class Quickview(QDialog, Ui_Quickview):
self.fill_in_books_box(vals[0]) self.fill_in_books_box(vals[0])
else: else:
self.indicate_no_items() self.indicate_no_items()
self.items.blockSignals(False) self.items.blockSignals(False)
def check_for_no_items(self):
if not self.is_closed and self.view.model().count() == 0:
self.indicate_no_items()
def indicate_no_items(self): def indicate_no_items(self):
self.no_valid_items = True self.no_valid_items = True
self.items.clear() self.items.clear()

View File

@ -3,9 +3,11 @@
# License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net> # License: GPLv3 Copyright: 2008, Kovid Goyal <kovid at kovidgoyal.net>
from functools import partial
from PyQt5.Qt import (Qt, QDialog, QTableWidgetItem, QIcon, QByteArray, QSize, from PyQt5.Qt import (Qt, QDialog, QTableWidgetItem, QIcon, QByteArray, QSize,
QDialogButtonBox, QTableWidget, QItemDelegate, QApplication, QDialogButtonBox, QTableWidget, QItemDelegate, QApplication,
pyqtSignal, QAction, QFrame, QLabel, QTimer) pyqtSignal, QAction, QFrame, QLabel, QTimer, QMenu)
from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor from calibre.gui2.dialogs.tag_list_editor_ui import Ui_TagListEditor
from calibre.gui2.complete2 import EditWithComplete from calibre.gui2.complete2 import EditWithComplete
@ -249,6 +251,85 @@ class TagListEditor(QDialog, Ui_TagListEditor):
self.search_item_row = -1 self.search_item_row = -1
self.fill_in_table(None, tag_to_match, ttm_is_first_letter) self.fill_in_table(None, tag_to_match, ttm_is_first_letter)
self.table.setContextMenuPolicy(Qt.CustomContextMenu)
self.table.customContextMenuRequested.connect(self.show_context_menu)
def show_context_menu(self, point):
idx = self.table.indexAt(point)
if idx.column() != 0:
return
m = self.au_context_menu = QMenu(self)
item = self.table.itemAt(point)
disable_copy_paste = len(self.table.selectedItems()) != 1 or item.is_deleted
ca = m.addAction(_('Copy'))
ca.triggered.connect(partial(self.copy_to_clipboard, item))
if disable_copy_paste:
ca.setEnabled(False)
ca = m.addAction(_('Paste'))
ca.triggered.connect(partial(self.paste_from_clipboard, item))
if disable_copy_paste:
ca.setEnabled(False)
ca = m.addAction(_('Undo'))
ca.triggered.connect(self.undo_edit)
ca.setEnabled(False)
for item in self.table.selectedItems():
if (item.text() != self.original_names[int(item.data(Qt.UserRole))]
or item.is_deleted):
ca.setEnabled(True)
break
ca = m.addAction(_('Edit'))
ca.triggered.connect(self.rename_tag)
ca = m.addAction(_('Delete'))
ca.triggered.connect(self.delete_tags)
m.addSeparator()
case_menu = QMenu(_('Change case'))
action_upper_case = case_menu.addAction(_('Upper case'))
action_lower_case = case_menu.addAction(_('Lower case'))
action_swap_case = case_menu.addAction(_('Swap case'))
action_title_case = case_menu.addAction(_('Title case'))
action_capitalize = case_menu.addAction(_('Capitalize'))
action_upper_case.triggered.connect(partial(self.do_case, self.upper_case))
action_lower_case.triggered.connect(partial(self.do_case, self.lower_case))
action_swap_case.triggered.connect(partial(self.do_case, self.swap_case))
action_title_case.triggered.connect(partial(self.do_case, self.title_case))
action_capitalize.triggered.connect(partial(self.do_case, self.capitalize))
m.addMenu(case_menu)
m.exec_(self.table.mapToGlobal(point))
def copy_to_clipboard(self, item):
cb = QApplication.clipboard()
cb.setText(unicode_type(item.text()))
def paste_from_clipboard(self, item):
cb = QApplication.clipboard()
item.setText(cb.text())
def do_case(self, func):
items = self.table.selectedItems()
# block signals to avoid the "edit one changes all" behavior
self.table.blockSignals(True)
for item in items:
func(item)
self.table.blockSignals(False)
def upper_case(self, item):
item.setText(icu_upper(unicode_type(item.text())))
def lower_case(self, item):
item.setText(icu_lower(unicode_type(item.text())))
def swap_case(self, item):
item.setText(unicode_type(item.text()).swapcase())
def title_case(self, item):
from calibre.utils.titlecase import titlecase
item.setText(titlecase(unicode_type(item.text())))
def capitalize(self, item):
from calibre.utils.icu import capitalize
item.setText(capitalize(unicode_type(item.text())))
def vl_box_changed(self): def vl_box_changed(self):
self.search_item_row = -1 self.search_item_row = -1
self.fill_in_table(None, None, False) self.fill_in_table(None, None, False)
@ -449,19 +530,22 @@ class TagListEditor(QDialog, Ui_TagListEditor):
error_dialog(self, _('No item selected'), error_dialog(self, _('No item selected'),
_('You must select one item from the list of Available items.')).exec_() _('You must select one item from the list of Available items.')).exec_()
return return
col_zero_item = self.table.item(item.row(), 0) for col_zero_item in self.table.selectedItems():
if col_zero_item.is_deleted: if col_zero_item.is_deleted:
if not question_dialog(self, _('Undelete item?'), if not question_dialog(self, _('Undelete items?'),
'<p>'+_('That item is deleted. Do you want to undelete it?')+'<br>'): '<p>'+_('Items must be undeleted to continue. Do you want '
return 'to do this?')+'<br>'):
col_zero_item.set_is_deleted(False) return
self.to_delete.discard(int(col_zero_item.data(Qt.UserRole))) self.table.blockSignals(True)
orig = self.table.item(col_zero_item.row(), 2) for col_zero_item in self.table.selectedItems():
self.table.blockSignals(True) # undelete any deleted items
orig.setData(Qt.DisplayRole, '') if col_zero_item.is_deleted:
self.table.blockSignals(False) col_zero_item.set_is_deleted(False)
else: self.to_delete.discard(int(col_zero_item.data(Qt.UserRole)))
self.table.editItem(item) orig = self.table.item(col_zero_item.row(), 2)
orig.setData(Qt.DisplayRole, '')
self.table.blockSignals(False)
self.table.editItem(item)
def delete_pressed(self): def delete_pressed(self):
if self.table.currentColumn() == 0: if self.table.currentColumn() == 0: