From 4d0a2ad7bd72e2279d8f484671f01afd1bc897a4 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Tue, 8 Nov 2011 11:30:43 +0100 Subject: [PATCH] Convert gui to use datetime instead of date for all date fields. --- src/calibre/gui2/__init__.py | 4 +- src/calibre/gui2/custom_column_widgets.py | 52 +++++++++++---------- src/calibre/gui2/dialogs/metadata_bulk.py | 25 +++++----- src/calibre/gui2/dialogs/metadata_bulk.ui | 4 +- src/calibre/gui2/library/delegates.py | 54 +++++++++++----------- src/calibre/gui2/library/models.py | 12 ++--- src/calibre/gui2/metadata/basic_widgets.py | 28 +++++------ src/calibre/utils/date.py | 5 +- 8 files changed, 95 insertions(+), 89 deletions(-) diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 6676bc30e1..b1a6167203 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -6,7 +6,7 @@ from threading import RLock from urllib import unquote from PyQt4.Qt import (QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QByteArray, QTranslator, QCoreApplication, QThread, - QEvent, QTimer, pyqtSignal, QDate, QDesktopServices, + QEvent, QTimer, pyqtSignal, QDateTime, QDesktopServices, QFileDialog, QFileIconProvider, QSettings, QIcon, QApplication, QDialog, QUrl, QFont) @@ -104,7 +104,7 @@ gprefs.defaults['show_files_after_save'] = True # }}} NONE = QVariant() #: Null value to return from the data function of item models -UNDEFINED_QDATE = QDate(UNDEFINED_DATE) +UNDEFINED_QDATETIME = QDateTime(UNDEFINED_DATE) ALL_COLUMNS = ['title', 'ondevice', 'authors', 'size', 'timestamp', 'rating', 'publisher', 'tags', 'series', 'pubdate'] diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 9e4bd41bbd..9a303011ca 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -7,15 +7,15 @@ __docformat__ = 'restructuredtext en' from functools import partial -from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ - QDate, QGroupBox, QVBoxLayout, QSizePolicy, \ +from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateTimeEdit, \ + QDateTime, QGroupBox, QVBoxLayout, QSizePolicy, \ QSpacerItem, QIcon, QCheckBox, QWidget, QHBoxLayout, SIGNAL, \ QPushButton from calibre.utils.date import qt_to_dt, now from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox from calibre.gui2.comments_editor import Editor as CommentsEditor -from calibre.gui2 import UNDEFINED_QDATE, error_dialog +from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog from calibre.utils.config import tweaks from calibre.utils.icu import sort_key from calibre.library.comments import comments_to_html @@ -142,27 +142,27 @@ class Rating(Int): val *= 2 return val -class DateEdit(QDateEdit): +class DateTimeEdit(QDateTimeEdit): def focusInEvent(self, x): self.setSpecialValueText('') - QDateEdit.focusInEvent(self, x) + QDateTimeEdit.focusInEvent(self, x) def focusOutEvent(self, x): self.setSpecialValueText(_('Undefined')) - QDateEdit.focusOutEvent(self, x) + QDateTimeEdit.focusOutEvent(self, x) def set_to_today(self): - self.setDate(now()) + self.setDateTime(now()) def set_to_clear(self): - self.setDate(UNDEFINED_QDATE) + self.setDateTime(UNDEFINED_QDATETIME) class DateTime(Base): def setup_ui(self, parent): cm = self.col_metadata - self.widgets = [QLabel('&'+cm['name']+':', parent), DateEdit(parent)] + self.widgets = [QLabel('&'+cm['name']+':', parent), DateTimeEdit(parent)] self.widgets.append(QLabel('')) w = QWidget(parent) self.widgets.append(w) @@ -179,24 +179,25 @@ class DateTime(Base): w = self.widgets[1] format = cm['display'].get('date_format','') if not format: - format = 'dd MMM yyyy' + format = 'dd MMM yyyy hh:mm' w.setDisplayFormat(format) w.setCalendarPopup(True) - w.setMinimumDate(UNDEFINED_QDATE) + w.setMinimumDateTime(UNDEFINED_QDATETIME) w.setSpecialValueText(_('Undefined')) self.today_button.clicked.connect(w.set_to_today) self.clear_button.clicked.connect(w.set_to_clear) def setter(self, val): if val is None: - val = self.widgets[1].minimumDate() + val = self.widgets[1].minimumDateTime() else: - val = QDate(val.year, val.month, val.day) - self.widgets[1].setDate(val) + val = QDateTime(val) + self.widgets[1].setDateTime(val) def getter(self): - val = self.widgets[1].date() - if val == UNDEFINED_QDATE: + val = self.widgets[1].dateTime() + print val + if val <= UNDEFINED_QDATETIME: val = None else: val = qt_to_dt(val) @@ -537,9 +538,9 @@ class BulkBase(Base): if hasattr(self.main_widget, 'valueChanged'): # spinbox widgets self.main_widget.valueChanged.connect(self.a_c_checkbox_changed) - if hasattr(self.main_widget, 'dateChanged'): + if hasattr(self.main_widget, 'dateTimeChanged'): # dateEdit widgets - self.main_widget.dateChanged.connect(self.a_c_checkbox_changed) + self.main_widget.dateTimeChanged.connect(self.a_c_checkbox_changed) def a_c_checkbox_changed(self): if not self.ignore_change_signals: @@ -658,7 +659,7 @@ class BulkDateTime(BulkBase): def setup_ui(self, parent): cm = self.col_metadata - self.make_widgets(parent, DateEdit) + self.make_widgets(parent, DateTimeEdit) self.widgets.append(QLabel('')) w = QWidget(parent) self.widgets.append(w) @@ -678,25 +679,26 @@ class BulkDateTime(BulkBase): format = 'dd MMM yyyy' w.setDisplayFormat(format) w.setCalendarPopup(True) - w.setMinimumDate(UNDEFINED_QDATE) + w.setMinimumDateTime(UNDEFINED_QDATETIME) w.setSpecialValueText(_('Undefined')) self.today_button.clicked.connect(w.set_to_today) self.clear_button.clicked.connect(w.set_to_clear) def setter(self, val): if val is None: - val = self.main_widget.minimumDate() + val = self.main_widget.minimumDateTime() else: - val = QDate(val.year, val.month, val.day) - self.main_widget.setDate(val) + val = QDateTime(val) + self.main_widget.setDateTime(val) self.ignore_change_signals = False def getter(self): - val = self.main_widget.date() - if val == UNDEFINED_QDATE: + val = self.main_widget.dateTime() + if val <= UNDEFINED_QDATETIME: val = None else: val = qt_to_dt(val) + print val return val class BulkSeries(BulkBase): diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 322c09ecbf..60ea1b62e9 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -7,14 +7,14 @@ import re, os, inspect from PyQt4.Qt import Qt, QDialog, QGridLayout, QVBoxLayout, QFont, QLabel, \ pyqtSignal, QDialogButtonBox, QInputDialog, QLineEdit, \ - QDate, QCompleter + QDateTime, QCompleter from calibre.gui2.dialogs.metadata_bulk_ui import Ui_MetadataBulkDialog from calibre.gui2.dialogs.tag_editor import TagEditor from calibre.ebooks.metadata import string_to_authors, authors_to_string, title_sort from calibre.ebooks.metadata.book.base import SafeFormat from calibre.gui2.custom_column_widgets import populate_metadata_page -from calibre.gui2 import error_dialog, ResizableDialog, UNDEFINED_QDATE, \ +from calibre.gui2 import error_dialog, ResizableDialog, UNDEFINED_QDATETIME, \ gprefs, question_dialog from calibre.gui2.progress_indicator import ProgressIndicator from calibre.utils.config import dynamic, JSONConfig @@ -306,18 +306,21 @@ class MetadataBulkDialog(ResizableDialog, 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.setMinimumDate(UNDEFINED_QDATE) + self.pubdate.setMinimumDateTime(UNDEFINED_QDATETIME) pubdate_format = tweaks['gui_pubdate_display_format'] if pubdate_format is not None: self.pubdate.setDisplayFormat(pubdate_format) self.pubdate.setSpecialValueText(_('Undefined')) self.clear_pubdate_button.clicked.connect(self.clear_pubdate) - self.pubdate.dateChanged.connect(self.do_apply_pubdate) - self.adddate.setDate(QDate.currentDate()) - self.adddate.setMinimumDate(UNDEFINED_QDATE) + self.pubdate.dateTimeChanged.connect(self.do_apply_pubdate) + self.adddate.setDateTime(QDateTime.currentDateTime()) + self.adddate.setMinimumDateTime(UNDEFINED_QDATETIME) + adddate_format = tweaks['gui_timestamp_display_format'] + if adddate_format is not None: + self.adddate.setDisplayFormat(adddate_format) self.adddate.setSpecialValueText(_('Undefined')) self.clear_adddate_button.clicked.connect(self.clear_adddate) - self.adddate.dateChanged.connect(self.do_apply_adddate) + self.adddate.dateTimeChanged.connect(self.do_apply_adddate) if len(self.db.custom_field_keys(include_composites=False)) == 0: self.central_widget.removeTab(1) @@ -347,13 +350,13 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): self.apply_pubdate.setChecked(True) def clear_pubdate(self, *args): - self.pubdate.setDate(UNDEFINED_QDATE) + self.pubdate.setMinimumDateTime(UNDEFINED_QDATETIME) def do_apply_adddate(self, *args): self.apply_adddate.setChecked(True) def clear_adddate(self, *args): - self.adddate.setDate(UNDEFINED_QDATE) + self.adddate.setMinimumDateTime(UNDEFINED_QDATETIME) def button_clicked(self, which): if which == self.button_box.button(QDialogButtonBox.Apply): @@ -935,9 +938,9 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): languages = self.languages.lang_codes pubdate = adddate = None if self.apply_pubdate.isChecked(): - pubdate = qt_to_dt(self.pubdate.date()) + pubdate = qt_to_dt(self.pubdate.dateTime()) if self.apply_adddate.isChecked(): - adddate = qt_to_dt(self.adddate.date()) + adddate = qt_to_dt(self.adddate.dateTime()) cover_action = None if self.cover_remove.isChecked(): diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index c2e6635f98..525c27e6ed 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -366,7 +366,7 @@ from the value in the box - + d MMM yyyy @@ -411,7 +411,7 @@ from the value in the box - + MMM yyyy diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 880d70c5a6..31947278aa 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -12,9 +12,9 @@ from PyQt4.Qt import (QColor, Qt, QModelIndex, QSize, QApplication, QPen, QStyle, QPainter, QStyleOptionViewItemV4, QIcon, QDoubleSpinBox, QVariant, QSpinBox, QStyledItemDelegate, QComboBox, QTextDocument, - QAbstractTextDocumentLayout) + QAbstractTextDocumentLayout, QDateTime) -from calibre.gui2 import UNDEFINED_QDATE, error_dialog +from calibre.gui2 import UNDEFINED_QDATETIME, error_dialog from calibre.gui2.widgets import EnLineEdit from calibre.gui2.complete import MultiCompleteLineEdit, MultiCompleteComboBox from calibre.utils.date import now, format_date @@ -107,25 +107,23 @@ class RatingDelegate(QStyledItemDelegate): # {{{ class DateDelegate(QStyledItemDelegate): # {{{ def __init__(self, parent, tweak_name='gui_timestamp_display_format', - default_format='dd MMM yyyy', editor_format='dd MMM yyyy'): + default_format='dd MMM yyyy'): QStyledItemDelegate.__init__(self, parent) self.tweak_name = tweak_name - self.default_format = default_format - self.editor_format = editor_format + self.format = tweaks[self.tweak_name] + if self.format is None: + format = default_format def displayText(self, val, locale): - d = val.toDate() - if d <= UNDEFINED_QDATE: + d = val.toDateTime() + if d <= UNDEFINED_QDATETIME: return '' - format = tweaks[self.tweak_name] - if format is None: - format = self.default_format - return format_date(d.toPyDate(), format) + return format_date(d.toPyDateTime(), self.format) def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) - qde.setDisplayFormat(self.editor_format) - qde.setMinimumDate(UNDEFINED_QDATE) + qde.setDisplayFormat(self.format) + qde.setMinimumDateTime(UNDEFINED_QDATETIME) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) return qde @@ -134,18 +132,18 @@ class DateDelegate(QStyledItemDelegate): # {{{ class PubDateDelegate(QStyledItemDelegate): # {{{ def displayText(self, val, locale): - d = val.toDate() - if d <= UNDEFINED_QDATE: + d = val.toDateTime() + if d <= UNDEFINED_QDATETIME: return '' - format = tweaks['gui_pubdate_display_format'] - if format is None: - format = 'MMM yyyy' - return format_date(d.toPyDate(), format) + self.format = tweaks['gui_pubdate_display_format'] + if self.format is None: + self.format = 'MMM yyyy' + return format_date(d.toPyDateTime(), self.format) def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) - qde.setDisplayFormat('MM yyyy') - qde.setMinimumDate(UNDEFINED_QDATE) + qde.setDisplayFormat(self.format) + qde.setMinimumDateTime(UNDEFINED_QDATETIME) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) return qde @@ -259,15 +257,15 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ self.format = format def displayText(self, val, locale): - d = val.toDate() - if d <= UNDEFINED_QDATE: + d = val.toDateTime() + if d <= UNDEFINED_QDATETIME: return '' - return format_date(d.toPyDate(), self.format) + return format_date(d.toPyDateTime(), self.format) def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) qde.setDisplayFormat(self.format) - qde.setMinimumDate(UNDEFINED_QDATE) + qde.setMinimumDateTime(UNDEFINED_QDATETIME) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) return qde @@ -279,11 +277,11 @@ class CcDateDelegate(QStyledItemDelegate): # {{{ val = m.db.data[index.row()][m.custom_columns[m.column_map[index.column()]]['rec_index']] if val is None: val = now() - editor.setDate(val) + editor.setDateTime(val) def setModelData(self, editor, model, index): - val = editor.date() - if val <= UNDEFINED_QDATE: + val = editor.dateTime() + if val <= UNDEFINED_QDATETIME: val = None model.setData(index, QVariant(val), Qt.EditRole) diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 9c456ac771..4e15deb3e6 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -9,9 +9,9 @@ import functools, re, os, traceback from collections import defaultdict from PyQt4.Qt import (QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, - QModelIndex, QVariant, QDate, QColor) + QModelIndex, QVariant, QDateTime, QColor) -from calibre.gui2 import NONE, UNDEFINED_QDATE +from calibre.gui2 import NONE, UNDEFINED_QDATETIME from calibre.utils.pyparsing import ParseException from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors from calibre.ebooks.metadata.book.base import SafeFormat @@ -580,9 +580,9 @@ class BooksModel(QAbstractTableModel): # {{{ def datetime_type(r, idx=-1): val = self.db.data[r][idx] if val is not None: - return QVariant(QDate(val)) + return QVariant(QDateTime(val)) else: - return QVariant(UNDEFINED_QDATE) + return QVariant(UNDEFINED_QDATETIME) def bool_type(r, idx=-1): return None # displayed using a decorator @@ -815,7 +815,7 @@ class BooksModel(QAbstractTableModel): # {{{ if not val: val = None elif typ == 'datetime': - val = value.toDate() + val = value.toDateTime() if val.isNull(): val = None else: @@ -860,7 +860,7 @@ class BooksModel(QAbstractTableModel): # {{{ if column not in self.editable_cols: return False val = int(value.toInt()[0]) if column == 'rating' else \ - value.toDate() if column in ('timestamp', 'pubdate') else \ + value.toDateTime() if column in ('timestamp', 'pubdate') else \ unicode(value.toString()).strip() id = self.db.id(row) books_to_refresh = set([id]) diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 267462bd5e..991e1dbd01 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -9,7 +9,7 @@ __docformat__ = 'restructuredtext en' import textwrap, re, os, errno, shutil -from PyQt4.Qt import (Qt, QDateEdit, QDate, pyqtSignal, QMessageBox, +from PyQt4.Qt import (Qt, QDateTimeEdit, pyqtSignal, QMessageBox, QIcon, QToolButton, QWidget, QLabel, QGridLayout, QApplication, QDoubleSpinBox, QListWidgetItem, QSize, QPixmap, QDialog, QMenu, QPushButton, QSpinBox, QLineEdit, QSizePolicy, QDialogButtonBox, QAction) @@ -21,7 +21,7 @@ from calibre.utils.config import tweaks, prefs from calibre.ebooks.metadata import (title_sort, authors_to_string, 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_QDATE, +from calibre.gui2 import (file_icon_provider, UNDEFINED_QDATETIME, choose_files, error_dialog, choose_images) from calibre.utils.date import (local_tz, qt_to_dt, as_local_time, UNDEFINED_DATE) @@ -1377,25 +1377,24 @@ class PublisherEdit(MultiCompleteComboBox): # {{{ # }}} -class DateEdit(QDateEdit): # {{{ +class DateEdit(QDateTimeEdit): # {{{ TOOLTIP = '' LABEL = _('&Date:') - FMT = 'd MMM yyyy' + FMT = 'dd MMM yyyy hh:mm:ss' ATTR = 'timestamp' + TWEAK = 'gui_timestamp_display_format' def __init__(self, parent): - QDateEdit.__init__(self, parent) + QDateTimeEdit.__init__(self, parent) self.setToolTip(self.TOOLTIP) self.setWhatsThis(self.TOOLTIP) - fmt = self.FMT + fmt = tweaks[self.TWEAK] if fmt is None: - fmt = tweaks['gui_pubdate_display_format'] - if fmt is None: - fmt = 'MMM yyyy' + fmt = self.FMT self.setDisplayFormat(fmt) self.setCalendarPopup(True) - self.setMinimumDate(UNDEFINED_QDATE) + self.setMinimumDateTime(UNDEFINED_QDATETIME) self.setSpecialValueText(_('Undefined')) self.clear_button = QToolButton(parent) self.clear_button.setIcon(QIcon(I('trash.png'))) @@ -1408,12 +1407,12 @@ class DateEdit(QDateEdit): # {{{ @dynamic_property def current_val(self): def fget(self): - return qt_to_dt(self.date(), as_utc=False) + return qt_to_dt(self.dateTime(), as_utc=False) def fset(self, val): if val is None: val = UNDEFINED_DATE val = as_local_time(val) - self.setDate(QDate(val.year, val.month, val.day)) + self.setDateTime(val) return property(fget=fget, fset=fset) def initialize(self, db, id_): @@ -1429,11 +1428,12 @@ class DateEdit(QDateEdit): # {{{ @property def changed(self): o, c = self.original_val, self.current_val - return o.year != c.year or o.month != c.month or o.day != c.day + return o != c class PubdateEdit(DateEdit): LABEL = _('Publishe&d:') - FMT = None + FMT = 'MMM yyyy' ATTR = 'pubdate' + TWEAK = 'gui_pubdate_display_format' # }}} diff --git a/src/calibre/utils/date.py b/src/calibre/utils/date.py index baaac05260..5b0e15749c 100644 --- a/src/calibre/utils/date.py +++ b/src/calibre/utils/date.py @@ -7,7 +7,7 @@ __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' import re -from datetime import datetime +from datetime import datetime, time from functools import partial from dateutil.parser import parse @@ -161,6 +161,9 @@ def format_date(dt, format, assume_utc=False, as_utc=False): if not format: format = 'dd MMM yyyy' + if not isinstance(dt, datetime): + dt = datetime.combine(dt, time()) + if hasattr(dt, 'tzinfo'): if dt.tzinfo is None: dt = dt.replace(tzinfo=_utc_tz if assume_utc else