diff --git a/src/calibre/gui2/__init__.py b/src/calibre/gui2/__init__.py index 8ce4e53649..53dc75cc6c 100644 --- a/src/calibre/gui2/__init__.py +++ b/src/calibre/gui2/__init__.py @@ -17,11 +17,12 @@ from calibre.utils.config import Config, ConfigProxy, dynamic, JSONConfig from calibre.utils.localization import set_qt_translator from calibre.ebooks.metadata.meta import get_metadata, metadata_from_formats from calibre.ebooks.metadata import MetaInformation +from calibre.utils.date import UNDEFINED_DATE gprefs = JSONConfig('gui') NONE = QVariant() #: Null value to return from the data function of item models -UNDEFINED_DATE = QDate(101,1,1) +UNDEFINED_QDATE = QDate(UNDEFINED_DATE) ALL_COLUMNS = ['title', '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 d68bb4d809..c25a705f30 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -14,7 +14,7 @@ from PyQt4.Qt import QComboBox, QLabel, QSpinBox, QDoubleSpinBox, QDateEdit, \ from calibre.utils.date import qt_to_dt from calibre.gui2.widgets import TagsLineEdit, EnComboBox -from calibre.gui2 import UNDEFINED_DATE +from calibre.gui2 import UNDEFINED_QDATE from calibre.utils.config import tweaks class Base(object): @@ -123,15 +123,24 @@ class Rating(Int): val *= 2 return val +class DateEdit(QDateEdit): + + def focusInEvent(self, x): + print 'focus in' + self.setSpecialValueText('') + + def focusOutEvent(self, x): + self.setSpecialValueText(_('Undefined')) + class DateTime(Base): def setup_ui(self, parent): self.widgets = [QLabel('&'+self.col_metadata['name']+':', parent), - QDateEdit(parent)] + DateEdit(parent)] w = self.widgets[1] w.setDisplayFormat('dd MMM yyyy') w.setCalendarPopup(True) - w.setMinimumDate(UNDEFINED_DATE) + w.setMinimumDate(UNDEFINED_QDATE) w.setSpecialValueText(_('Undefined')) def setter(self, val): @@ -143,7 +152,7 @@ class DateTime(Base): def getter(self): val = self.widgets[1].date() - if val == UNDEFINED_DATE: + if val == UNDEFINED_QDATE: val = None else: val = qt_to_dt(val) diff --git a/src/calibre/gui2/library.py b/src/calibre/gui2/library.py index 85ac5e8aa8..ba9a5b0b29 100644 --- a/src/calibre/gui2/library.py +++ b/src/calibre/gui2/library.py @@ -19,7 +19,7 @@ from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, pyqtSignal, \ from calibre import strftime from calibre.ebooks.metadata import string_to_authors, fmt_sidx, authors_to_string from calibre.ebooks.metadata.meta import set_metadata as _set_metadata -from calibre.gui2 import NONE, TableView, config, error_dialog, UNDEFINED_DATE +from calibre.gui2 import NONE, TableView, config, error_dialog, UNDEFINED_QDATE from calibre.gui2.dialogs.comments_dialog import CommentsDialog from calibre.gui2.widgets import EnLineEdit, TagsLineEdit from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, REGEXP_MATCH @@ -103,7 +103,7 @@ class DateDelegate(QStyledItemDelegate): def displayText(self, val, locale): d = val.toDate() - if d == UNDEFINED_DATE: + if d == UNDEFINED_QDATE: return '' return d.toString('dd MMM yyyy') @@ -113,7 +113,7 @@ class DateDelegate(QStyledItemDelegate): if 'yyyy' not in stdformat: stdformat = stdformat.replace('yy', 'yyyy') qde.setDisplayFormat(stdformat) - qde.setMinimumDate(UNDEFINED_DATE) + qde.setMinimumDate(UNDEFINED_QDATE) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) return qde @@ -122,14 +122,14 @@ class PubDateDelegate(QStyledItemDelegate): def displayText(self, val, locale): d = val.toDate() - if d == UNDEFINED_DATE: + if d == UNDEFINED_QDATE: return '' return d.toString('MMM yyyy') def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) qde.setDisplayFormat('MM yyyy') - qde.setMinimumDate(UNDEFINED_DATE) + qde.setMinimumDate(UNDEFINED_QDATE) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) return qde @@ -192,14 +192,14 @@ class CcDateDelegate(QStyledItemDelegate): def displayText(self, val, locale): d = val.toDate() - if d == UNDEFINED_DATE: + if d == UNDEFINED_QDATE: return '' return d.toString(self.format) def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) qde.setDisplayFormat(self.format) - qde.setMinimumDate(UNDEFINED_DATE) + qde.setMinimumDate(UNDEFINED_QDATE) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) return qde @@ -213,6 +213,12 @@ class CcDateDelegate(QStyledItemDelegate): val = now() editor.setDate(val) + def setModelData(self, editor, model, index): + val = editor.date() + if val == UNDEFINED_QDATE: + val = None + model.setData(index, QVariant(val), Qt.EditRole) + class CcTextDelegate(QStyledItemDelegate): ''' Delegate for text/int/float data. @@ -748,7 +754,7 @@ class BooksModel(QAbstractTableModel): if val is not None: return QVariant(QDate(val)) else: - return QVariant(UNDEFINED_DATE) + return QVariant(UNDEFINED_QDATE) def bool_type(r, idx=-1): return None # displayed using a decorator @@ -883,9 +889,12 @@ class BooksModel(QAbstractTableModel): val = None elif typ == 'datetime': val = value.toDate() - if val.isNull() or not val.isValid(): - return False - val = qt_to_dt(val, as_utc=False) + if val.isNull(): + val = None + else: + if not val.isValid(): + return False + val = qt_to_dt(val, as_utc=False) self.db.set_custom(self.db.id(row), val, label=colhead, num=None, append=False, notify=True) return True diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index 55b6a00e99..2e7c7c4ca8 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -14,7 +14,7 @@ from PyQt4.QtCore import QThread, QReadWriteLock from PyQt4.QtGui import QImage from calibre.utils.config import tweaks -from calibre.utils.date import parse_date, now +from calibre.utils.date import parse_date, now, UNDEFINED_DATE from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.pyparsing import ParseException @@ -573,11 +573,13 @@ class ResultCache(SearchQueryParser): except AttributeError: # Some entries may be None ans = cmp(self._data[x][loc], self._data[y][loc]) except TypeError: ## raised when a datetime is None - if self._data[x][loc] is None: - if self._data[y][loc] is None: - return 0 # Both None. Return eq - return 1 # x is None, y not. Return gt - return -1 # x is not None and (therefore) y is. return lt + x = self._data[x][loc] + if x is None: + x = UNDEFINED_DATE + y = self._data[y][loc] + if y is None: + y = UNDEFINED_DATE + return cmp(x, y) if subsort and ans == 0: return cmp(self._data[x][11].lower(), self._data[y][11].lower()) return ans diff --git a/src/calibre/utils/date.py b/src/calibre/utils/date.py index cb1b1fe1ad..a43927c9c5 100644 --- a/src/calibre/utils/date.py +++ b/src/calibre/utils/date.py @@ -40,6 +40,8 @@ parse_date_day_first = compute_locale_info_for_parse_date() utc_tz = _utc_tz = tzutc() local_tz = _local_tz = SafeLocalTimeZone() +UNDEFINED_DATE = datetime(101,1,1, tzinfo=utc_tz) + def parse_date(date_string, assume_utc=False, as_utc=True, default=None): ''' Parse a date/time string into a timezone aware datetime object. The timezone