diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 1e397c42ff..024e403ca7 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -1291,10 +1291,6 @@ class Application(QApplication): ans.setDevicePixelRatio(device_pixel_ratio) return ans - def stylesheet_for_line_edit(self, is_error=False): - col = '#FF2400' if is_error else '#50c878' - return f'QLineEdit {{ border: 2px solid {col}; border-radius: 3px }}' - def _send_file_open_events(self): with self._file_open_lock: if self._file_open_paths: diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index ee84c037e9..f09d28329e 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -7,9 +7,8 @@ import regex from collections import defaultdict, namedtuple from io import BytesIO from qt.core import ( - QApplication, QComboBox, QCompleter, QDateTime, QDialog, QDialogButtonBox, QFont, - QGridLayout, QInputDialog, QLabel, QLineEdit, QProgressBar, QSize, Qt, QVBoxLayout, - pyqtSignal, + QComboBox, QCompleter, QDateTime, QDialog, QDialogButtonBox, QFont, QGridLayout, + QInputDialog, QLabel, QLineEdit, QProgressBar, QSize, Qt, QVBoxLayout, pyqtSignal, ) from threading import Thread @@ -27,7 +26,9 @@ from calibre.gui2.custom_column_widgets import populate_metadata_page from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.gui2.dialogs.template_line_editor import TemplateLineEditor -from calibre.gui2.widgets import LineEditECM +from calibre.gui2.widgets import ( + LineEditECM, setup_status_actions, update_status_actions, +) from calibre.startup import connect_lambda from calibre.utils.config import JSONConfig, dynamic, prefs, tweaks from calibre.utils.date import internal_iso_format_string, qt_to_dt @@ -499,6 +500,7 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): def __init__(self, window, rows, model, tab, refresh_books): QDialog.__init__(self, window) self.setupUi(self) + setup_status_actions(self.test_result) self.series.set_sort_func(title_sort) self.model = model self.db = model.db @@ -899,10 +901,11 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.s_r_search_field_changed(self.search_field.currentIndex()) def s_r_set_colors(self): + tt = '' if self.s_r_error is not None: - self.test_result.setText(error_message(self.s_r_error)) - self.test_result.setStyleSheet( - QApplication.instance().stylesheet_for_line_edit(self.s_r_error is not None)) + tt = error_message(self.s_r_error) + self.test_result.setText(tt) + update_status_actions(self.test_result, self.s_r_error is None, tt) for i in range(0,self.s_r_number_of_books): getattr(self, 'book_%d_result'%(i+1)).setText('') diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 10a616d3e8..d1130e5aa7 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -37,7 +37,7 @@ from calibre.gui2.comments_editor import Editor from calibre.gui2.complete2 import EditWithComplete from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.gui2.languages import LanguagesEdit as LE -from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView +from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView, LineEditIndicators from calibre.gui2.widgets2 import ( DateTimeEdit, Dialog, RatingEditor, RightClickButton, access_key, populate_standard_spinbox_context_menu, @@ -261,7 +261,7 @@ class TitleEdit(EnLineEdit, ToMetadataMixin): self.dialog = None -class TitleSortEdit(TitleEdit, ToMetadataMixin): +class TitleSortEdit(TitleEdit, ToMetadataMixin, LineEditIndicators): TITLE_ATTR = FIELD_NAME = 'title_sort' TOOLTIP = _('Specify how this book should be sorted when by title.' @@ -270,15 +270,16 @@ class TitleSortEdit(TitleEdit, ToMetadataMixin): def __init__(self, parent, title_edit, autogen_button, languages_edit): TitleEdit.__init__(self, parent) + self.setup_status_actions() self.title_edit = title_edit self.languages_edit = languages_edit base = self.TOOLTIP ok_tooltip = '

' + textwrap.fill(base+'

' + _( - ' The green color indicates that the current ' + ' The ok icon indicates that the current ' 'title sort matches the current title')) bad_tooltip = '

'+textwrap.fill(base + '

' + _( - ' The red color warns that the current ' + ' The error icon warns that the current ' 'title sort does not match the current title. ' 'No action is required if this is what you want.')) self.tooltips = (ok_tooltip, bad_tooltip) @@ -314,8 +315,8 @@ class TitleSortEdit(TitleEdit, ToMetadataMixin): def update_state(self, *args): ts = title_sort(self.title_edit.current_val, lang=self.book_lang) normal = ts == self.current_val - self.setStyleSheet(QApplication.instance().stylesheet_for_line_edit(not normal)) tt = self.tooltips[0 if normal else 1] + self.update_status_actions(normal, tt) self.setToolTip(tt) self.setWhatsThis(tt) @@ -456,7 +457,7 @@ class AuthorsEdit(EditWithComplete, ToMetadataMixin): pass -class AuthorSortEdit(EnLineEdit, ToMetadataMixin): +class AuthorSortEdit(EnLineEdit, ToMetadataMixin, LineEditIndicators): TOOLTIP = _('Specify how the author(s) of this book should be sorted. ' 'For example Charles Dickens should be sorted as Dickens, ' @@ -470,15 +471,16 @@ class AuthorSortEdit(EnLineEdit, ToMetadataMixin): def __init__(self, parent, authors_edit, autogen_button, db, copy_a_to_as_action, copy_as_to_a_action, a_to_as, as_to_a): EnLineEdit.__init__(self, parent) + self.setup_status_actions() self.authors_edit = authors_edit self.db = db base = self.TOOLTIP ok_tooltip = '

' + textwrap.fill(base+'

' + _( - ' The green color indicates that the current ' + ' The ok icon indicates that the current ' 'author sort matches the current author')) bad_tooltip = '

'+textwrap.fill(base + '

'+ _( - ' The red color indicates that the current ' + ' The error icon indicates that the current ' 'author sort does not match the current author. ' 'No action is required if this is what you want.')) self.tooltips = (ok_tooltip, bad_tooltip) @@ -529,8 +531,8 @@ class AuthorSortEdit(EnLineEdit, ToMetadataMixin): au = self.author_sort_from_authors(string_to_authors(au)) normal = au == self.current_val - self.setStyleSheet(QApplication.instance().stylesheet_for_line_edit(not normal)) tt = self.tooltips[0 if normal else 1] + self.update_status_actions(normal, tt) self.setToolTip(tt) self.setWhatsThis(tt) @@ -1572,7 +1574,7 @@ class Identifiers(Dialog): Dialog.accept(self) -class IdentifiersEdit(QLineEdit, ToMetadataMixin): +class IdentifiersEdit(QLineEdit, ToMetadataMixin, LineEditIndicators): LABEL = _('&Ids:') BASE_TT = _('Edit the identifiers for this book. ' 'For example: \n\n%s\n\nIf an identifier value contains a comma, you can use the | character to represent it.')%( @@ -1582,6 +1584,7 @@ class IdentifiersEdit(QLineEdit, ToMetadataMixin): def __init__(self, parent): QLineEdit.__init__(self, parent) + self.setup_status_actions() self.pat = re.compile(r'[^0-9a-zA-Z]') self.textChanged.connect(self.validate) self.textChanged.connect(self.data_changed) @@ -1652,16 +1655,17 @@ class IdentifiersEdit(QLineEdit, ToMetadataMixin): isbn = identifiers.get('isbn', '') tt = self.BASE_TT extra = '' + ok = None if not isbn: - sheet = '' + pass elif check_isbn(isbn) is not None: - sheet = QApplication.instance().stylesheet_for_line_edit() + ok = True extra = '\n\n'+_('This ISBN is valid') else: - sheet = QApplication.instance().stylesheet_for_line_edit(True) + ok = False extra = '\n\n' + _('This ISBN is invalid') self.setToolTip(tt+extra) - self.setStyleSheet(sheet) + self.update_status_actions(ok, self.toolTip()) def paste_identifier(self): identifier_found = self.parse_clipboard_for_identifier() @@ -1751,6 +1755,9 @@ class IdentifiersEdit(QLineEdit, ToMetadataMixin): return False # }}} +class IndicatorLineEdit(QLineEdit, LineEditIndicators): + pass + class ISBNDialog(QDialog): # {{{ @@ -1763,7 +1770,8 @@ class ISBNDialog(QDialog): # {{{ l.addWidget(w, 0, 0, 1, 2) w = QLabel(_('ISBN:')) l.addWidget(w, 1, 0, 1, 1) - self.line_edit = w = QLineEdit() + self.line_edit = w = IndicatorLineEdit() + w.setup_status_actions() w.setText(txt) w.selectAll() w.textChanged.connect(self.checkText) @@ -1787,17 +1795,17 @@ class ISBNDialog(QDialog): # {{{ def checkText(self, txt): isbn = str(txt) + ok = None if not isbn: - sheet = '' - extra = '' + pass elif check_isbn(isbn) is not None: - sheet = QApplication.instance().stylesheet_for_line_edit() extra = _('This ISBN is valid') + ok = True else: - sheet = QApplication.instance().stylesheet_for_line_edit(True) extra = _('This ISBN is invalid') + ok = False self.line_edit.setToolTip(extra) - self.line_edit.setStyleSheet(sheet) + self.line_edit.update_status_actions(ok, extra) def text(self): return check_isbn(str(self.line_edit.text())) diff --git a/src/calibre/gui2/search_box.py b/src/calibre/gui2/search_box.py index 4f2b5dc3ff..6070a5fe7a 100644 --- a/src/calibre/gui2/search_box.py +++ b/src/calibre/gui2/search_box.py @@ -158,7 +158,6 @@ class SearchBox2(QComboBox): # {{{ items.append(item) self.addItems(items) self.line_edit.setPlaceholderText(help_text) - self.colorize = colorize self.clear() def clear_history(self): @@ -210,10 +209,6 @@ class SearchBox2(QComboBox): # {{{ self.clear(emit_search=False) return self._in_a_search = ok - if self.colorize: - self.line_edit.setStyleSheet(QApplication.instance().stylesheet_for_line_edit(not ok)) - else: - self.line_edit.setStyleSheet('') # Comes from the lineEdit control def key_pressed(self, event): @@ -337,7 +332,7 @@ class SearchBoxMixin: # {{{ pass def init_search_box_mixin(self): - self.search.initialize('main_search_history', colorize=True, + self.search.initialize('main_search_history', help_text=_('Search (For advanced search click the gear icon to the left)')) self.search.cleared.connect(self.search_box_cleared) # Queued so that search.current_text will be correct diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index da290e9832..aff4faf2df 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -546,6 +546,35 @@ class EnLineEdit(LineEditECM, QLineEdit): # {{{ # }}} +# LineEditIndicators {{{ + +def setup_status_actions(self: QLineEdit): + self.status_actions = ( + self.addAction(QIcon.ic('ok.png'), QLineEdit.ActionPosition.TrailingPosition), + self.addAction(QIcon.ic('dialog_error.png'), QLineEdit.ActionPosition.TrailingPosition)) + self.status_actions[0].setVisible(False) + self.status_actions[1].setVisible(False) + +def update_status_actions(self: QLineEdit, ok, tooltip: str = ''): + self.status_actions[0].setVisible(bool(ok)) + self.status_actions[1].setVisible(not ok) + if ok: + self.status_actions[0].setToolTip(tooltip) + elif ok is None: + self.status_actions[1].setVisible(False) + else: + self.status_actions[1].setToolTip(tooltip) + +class LineEditIndicators: + + def setup_status_actions(self): + setup_status_actions(self) + + def update_status_actions(self, ok, tooltip=''): + update_status_actions(self, ok, tooltip) +# }}} + + class ItemsCompleter(QCompleter): # {{{ '''