diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index a907970fcc..d73e3cd9d9 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -9,10 +9,10 @@ __docformat__ = 'restructuredtext en' import os from functools import partial -from PyQt5.Qt import (QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTimeEdit, +from PyQt5.Qt import (QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTime, QGroupBox, QVBoxLayout, QSizePolicy, QGridLayout, QUrl, QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, QLineEdit, - QPushButton, QMessageBox, QToolButton, Qt, QPlainTextEdit) + QPushButton, QMessageBox, QToolButton, QPlainTextEdit) from calibre.utils.date import qt_to_dt, now, as_local_time, as_utc, internal_iso_format_string from calibre.gui2.complete2 import EditWithComplete @@ -23,7 +23,7 @@ from calibre.utils.config import tweaks from calibre.utils.icu import sort_key from calibre.library.comments import comments_to_html from calibre.gui2.library.delegates import ClearingDoubleSpinBox, ClearingSpinBox -from calibre.gui2.widgets2 import RatingEditor +from calibre.gui2.widgets2 import RatingEditor, DateTimeEdit as DateTimeEditBase from polyglot.builtins import unicode_type @@ -275,15 +275,15 @@ class Rating(Base): self.signals_to_disconnect.append(self.widgets[1].currentTextChanged) -class DateTimeEdit(QDateTimeEdit): +class DateTimeEdit(DateTimeEditBase): def focusInEvent(self, x): self.setSpecialValueText('') - QDateTimeEdit.focusInEvent(self, x) + DateTimeEditBase.focusInEvent(self, x) def focusOutEvent(self, x): self.setSpecialValueText(_('Undefined')) - QDateTimeEdit.focusOutEvent(self, x) + DateTimeEditBase.focusOutEvent(self, x) def set_to_today(self): self.setDateTime(now()) @@ -292,16 +292,6 @@ class DateTimeEdit(QDateTimeEdit): self.setDateTime(now()) self.setDateTime(UNDEFINED_QDATETIME) - def keyPressEvent(self, ev): - if ev.key() == Qt.Key_Minus: - ev.accept() - self.setDateTime(self.minimumDateTime()) - elif ev.key() == Qt.Key_Equal: - ev.accept() - self.setDateTime(QDateTime.currentDateTime()) - else: - return QDateTimeEdit.keyPressEvent(self, ev) - class DateTime(Base): diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 48dae76705..61fbfa51bb 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -26,7 +26,6 @@ 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.metadata.basic_widgets import CalendarWidget from calibre.utils.config import JSONConfig, dynamic, prefs, tweaks from calibre.utils.date import qt_to_dt, internal_iso_format_string from calibre.utils.icu import capitalize, sort_key @@ -503,10 +502,6 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.series.editTextChanged.connect(self.series_changed) self.tag_editor_button.clicked.connect(self.tag_editor) self.autonumber_series.stateChanged[int].connect(self.auto_number_changed) - self.pubdate.setMinimumDateTime(UNDEFINED_QDATETIME) - self.pubdate_cw = CalendarWidget(self.pubdate) - self.pubdate_cw.setVerticalHeaderFormat(self.pubdate_cw.NoVerticalHeader) - self.pubdate.setCalendarWidget(self.pubdate_cw) pubdate_format = tweaks['gui_pubdate_display_format'] if pubdate_format == 'iso': pubdate_format = internal_iso_format_string() @@ -516,10 +511,6 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): self.clear_pubdate_button.clicked.connect(self.clear_pubdate) self.pubdate.dateTimeChanged.connect(self.do_apply_pubdate) self.adddate.setDateTime(QDateTime.currentDateTime()) - self.adddate.setMinimumDateTime(UNDEFINED_QDATETIME) - self.adddate_cw = CalendarWidget(self.adddate) - self.adddate_cw.setVerticalHeaderFormat(self.adddate_cw.NoVerticalHeader) - self.adddate.setCalendarWidget(self.adddate_cw) adddate_format = tweaks['gui_timestamp_display_format'] if adddate_format == 'iso': adddate_format = internal_iso_format_string() diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 8f415b90e0..406d327713 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -401,7 +401,7 @@ from the value in the box - + MMM yyyy @@ -445,7 +445,7 @@ from the value in the box - + d MMM yyyy @@ -726,8 +726,8 @@ for e.g., EPUB to EPUB, calibre saves the original EPUB 0 0 - 935 - 639 + 777 + 388 @@ -1205,8 +1205,8 @@ not multiple and the destination field is multiple 0 0 - 917 - 319 + 203 + 70 @@ -1329,6 +1329,11 @@ is completed. This can be slow on large libraries. QComboBox
calibre/gui2/widgets2.h
+ + DateTimeEdit + QDateTimeEdit +
calibre/gui2/widgets2.h
+
central_widget diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index cfd040c981..9b86fe9f9c 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -17,7 +17,7 @@ from calibre.ebooks.metadata import rating_to_stars from calibre.gui2 import UNDEFINED_QDATETIME, rating_font from calibre.constants import iswindows from calibre.gui2.widgets import EnLineEdit -from calibre.gui2.widgets2 import populate_standard_spinbox_context_menu, RatingEditor +from calibre.gui2.widgets2 import populate_standard_spinbox_context_menu, RatingEditor, DateTimeEdit as DateTimeEditBase from calibre.gui2.complete2 import EditWithComplete from calibre.utils.date import now, format_date, qt_to_dt, is_date_undefined, internal_iso_format_string @@ -112,43 +112,15 @@ class UpdateEditorGeometry(object): editor.setGeometry(initial_geometry) -class DateTimeEdit(QDateTimeEdit): # {{{ +class DateTimeEdit(DateTimeEditBase): # {{{ def __init__(self, parent, format_): - QDateTimeEdit.__init__(self, parent) + DateTimeEditBase.__init__(self, parent) self.setFrame(False) - self.setMinimumDateTime(UNDEFINED_QDATETIME) - self.setSpecialValueText(_('Undefined')) - self.setCalendarPopup(True) if format_ == 'iso': format_ = internal_iso_format_string() self.setDisplayFormat(format_) - def contextMenuEvent(self, ev): - m = QMenu(self) - m.addAction(_('Set date to undefined') + '\t' + QKeySequence(Qt.Key_Minus).toString(QKeySequence.NativeText), - self.clear_date) - m.addAction(_('Set date to today') + '\t' + QKeySequence(Qt.Key_Equal).toString(QKeySequence.NativeText), - self.today_date) - m.addSeparator() - populate_standard_spinbox_context_menu(self, m) - m.popup(ev.globalPos()) - - def today_date(self): - self.setDateTime(QDateTime.currentDateTime()) - - def clear_date(self): - self.setDateTime(UNDEFINED_QDATETIME) - - def keyPressEvent(self, ev): - if ev.key() == Qt.Key_Minus: - ev.accept() - self.clear_date() - elif ev.key() == Qt.Key_Equal: - self.today_date() - ev.accept() - else: - return QDateTimeEdit.keyPressEvent(self, ev) # }}} # Number Editor {{{ diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 93a61e15b6..902945c6d2 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -10,20 +10,20 @@ import textwrap, re, os, shutil, weakref from datetime import date, datetime from PyQt5.Qt import ( - Qt, QDateTimeEdit, pyqtSignal, QMessageBox, QIcon, QToolButton, QWidget, + Qt, pyqtSignal, QMessageBox, QIcon, QToolButton, QWidget, QLabel, QGridLayout, QApplication, QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu, QLineEdit, QSizePolicy, QKeySequence, - QDialogButtonBox, QAction, QCalendarWidget, QDate, QDateTime, QUndoCommand, + QDialogButtonBox, QAction, QDateTime, QUndoCommand, QUndoStack, QVBoxLayout, QPlainTextEdit, QUrl) from calibre.gui2.widgets import EnLineEdit, FormatList as _FormatList, ImageView -from calibre.gui2.widgets2 import access_key, populate_standard_spinbox_context_menu, RightClickButton, Dialog, RatingEditor +from calibre.gui2.widgets2 import access_key, populate_standard_spinbox_context_menu, RightClickButton, Dialog, RatingEditor, DateTimeEdit from calibre.utils.icu import sort_key from calibre.utils.config import tweaks, prefs from calibre.ebooks.metadata import ( title_sort, string_to_authors, check_isbn, authors_to_sort_string) from calibre.ebooks.metadata.meta import get_metadata -from calibre.gui2 import (file_icon_provider, UNDEFINED_QDATETIME, +from calibre.gui2 import (file_icon_provider, choose_files, error_dialog, choose_images, gprefs) from calibre.gui2.complete2 import EditWithComplete from calibre.utils.date import ( @@ -1797,14 +1797,7 @@ class PublisherEdit(EditWithComplete, ToMetadataMixin): # {{{ # DateEdit {{{ -class CalendarWidget(QCalendarWidget): - - def showEvent(self, ev): - if self.selectedDate().year() == UNDEFINED_DATE.year: - self.setSelectedDate(QDate.currentDate()) - - -class DateEdit(make_undoable(QDateTimeEdit), ToMetadataMixin): +class DateEdit(make_undoable(DateTimeEdit), ToMetadataMixin): TOOLTIP = '' LABEL = _('&Date:') @@ -1824,12 +1817,6 @@ class DateEdit(make_undoable(QDateTimeEdit), ToMetadataMixin): elif fmt == 'iso': fmt = internal_iso_format_string() self.setDisplayFormat(fmt) - self.setCalendarPopup(True) - self.cw = CalendarWidget(self) - self.cw.setVerticalHeaderFormat(self.cw.NoVerticalHeader) - self.setCalendarWidget(self.cw) - self.setMinimumDateTime(UNDEFINED_QDATETIME) - self.setSpecialValueText(_('Undefined')) if create_clear_button: self.clear_button = QToolButton(parent) self.clear_button.setIcon(QIcon(I('trash.png'))) @@ -1867,13 +1854,7 @@ class DateEdit(make_undoable(QDateTimeEdit), ToMetadataMixin): return o != c def keyPressEvent(self, ev): - if ev.key() == Qt.Key_Minus: - ev.accept() - self.setDateTime(self.minimumDateTime()) - elif ev.key() == Qt.Key_Equal: - ev.accept() - self.setDateTime(QDateTime.currentDateTime()) - elif ev.key() == Qt.Key_Up and is_date_undefined(self.current_val): + if ev.key() == Qt.Key_Up and is_date_undefined(self.current_val): self.setDateTime(QDateTime.currentDateTime()) elif ev.key() == Qt.Key_Tab and is_date_undefined(self.current_val): ev.ignore() diff --git a/src/calibre/gui2/widgets2.py b/src/calibre/gui2/widgets2.py index c221d4af6f..7feef8a2ef 100644 --- a/src/calibre/gui2/widgets2.py +++ b/src/calibre/gui2/widgets2.py @@ -7,18 +7,20 @@ from __future__ import absolute_import, division, print_function, unicode_litera import weakref from PyQt5.Qt import ( - QApplication, QCheckBox, QColor, QColorDialog, QComboBox, QDialog, - QDialogButtonBox, QFont, QFontInfo, QFontMetrics, QIcon, QKeySequence, QLabel, - QLayout, QPalette, QPixmap, QPoint, QPushButton, QRect, QScrollArea, QSize, + QApplication, QByteArray, QCalendarWidget, QCheckBox, QColor, QColorDialog, + QComboBox, QDate, QDateTime, QDateTimeEdit, QDialog, QDialogButtonBox, QFont, + QFontInfo, QFontMetrics, QIcon, QKeySequence, QLabel, QLayout, QLineEdit, QMenu, + QMimeData, QPalette, QPixmap, QPoint, QPushButton, QRect, QScrollArea, QSize, QSizePolicy, QStyle, QStyledItemDelegate, Qt, QTabWidget, QTextBrowser, - QToolButton, QUndoCommand, QUndoStack, QWidget, pyqtSignal, QByteArray + QToolButton, QUndoCommand, QUndoStack, QWidget, pyqtSignal, pyqtSlot ) from calibre.ebooks.metadata import rating_to_stars -from calibre.gui2 import gprefs, rating_font +from calibre.gui2 import UNDEFINED_QDATETIME, gprefs, rating_font from calibre.gui2.complete2 import EditWithComplete, LineEdit from calibre.gui2.widgets import history from calibre.utils.config_base import tweaks +from calibre.utils.date import UNDEFINED_DATE from polyglot.builtins import unicode_type from polyglot.functools import lru_cache @@ -555,6 +557,93 @@ def to_plain_text(self): return ans.rstrip('\0') +class LineEditForDateTimeEdit(QLineEdit): + + date_time_pasted = pyqtSignal(object) + date_time_copied = pyqtSignal(object) + MIME_TYPE = 'application/x-calibre-datetime-value' + + @pyqtSlot() + def copy(self): + self.date_time_copied.emit(self.selectedText()) + + @pyqtSlot() + def paste(self): + md = QApplication.instance().clipboard().mimeData() + if md.hasFormat(self.MIME_TYPE): + self.date_time_pasted.emit(QDateTime.fromString(md.data(self.MIME_TYPE).data().decode('ascii'), Qt.ISODate)) + else: + QLineEdit.paste(self) + + +class CalendarWidget(QCalendarWidget): + + def showEvent(self, ev): + if self.selectedDate().year() == UNDEFINED_DATE.year: + self.setSelectedDate(QDate.currentDate()) + + +class DateTimeEdit(QDateTimeEdit): + + def __init__(self, parent=None): + QDateTimeEdit.__init__(self, parent) + le = LineEditForDateTimeEdit(self) + self.setLineEdit(le) + le.date_time_pasted.connect(self.date_time_pasted, type=Qt.QueuedConnection) + le.date_time_copied.connect(self.date_time_copied, type=Qt.QueuedConnection) + self.setMinimumDateTime(UNDEFINED_QDATETIME) + self.setCalendarPopup(True) + self.cw = CalendarWidget(self) + self.cw.setVerticalHeaderFormat(self.cw.NoVerticalHeader) + self.setCalendarWidget(self.cw) + self.setSpecialValueText(_('Undefined')) + + def date_time_copied(self, text): + md = QMimeData() + md.setText(text or self.dateTime().toString()) + md.setData(LineEditForDateTimeEdit.MIME_TYPE, self.dateTime().toString(Qt.ISODate).encode('ascii')) + QApplication.instance().clipboard().setMimeData(md) + + def date_time_pasted(self, qt_dt): + self.setDateTime(qt_dt) + + def create_context_menu(self): + m = QMenu(self) + m.addAction(_('Set date to undefined') + '\t' + QKeySequence(Qt.Key_Minus).toString(QKeySequence.NativeText), + self.clear_date) + m.addAction(_('Set date to today') + '\t' + QKeySequence(Qt.Key_Equal).toString(QKeySequence.NativeText), + self.today_date) + m.addSeparator() + populate_standard_spinbox_context_menu(self, m) + return m + + def contextMenuEvent(self, ev): + m = self.create_context_menu() + m.popup(ev.globalPos()) + + def today_date(self): + self.setDateTime(QDateTime.currentDateTime()) + + def clear_date(self): + self.setDateTime(UNDEFINED_QDATETIME) + + def keyPressEvent(self, ev): + if ev.key() == Qt.Key_Minus: + ev.accept() + self.clear_date() + elif ev.key() == Qt.Key_Equal: + self.today_date() + ev.accept() + elif ev.matches(QKeySequence.Copy): + self.lineEdit().copy() + ev.accept() + elif ev.matches(QKeySequence.Paste): + self.lineEdit().paste() + ev.accept() + else: + return QDateTimeEdit.keyPressEvent(self, ev) + + if __name__ == '__main__': from calibre.gui2 import Application app = Application([])