mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Add a couple of date related functions to the template language
This commit is contained in:
commit
c3ca6c64ba
@ -5,11 +5,13 @@ __docformat__ = 'restructuredtext en'
|
|||||||
|
|
||||||
|
|
||||||
from PyQt4.Qt import (Qt, QDialog, QAbstractItemView, QTableWidgetItem,
|
from PyQt4.Qt import (Qt, QDialog, QAbstractItemView, QTableWidgetItem,
|
||||||
QListWidgetItem, QByteArray, QModelIndex, QCoreApplication)
|
QListWidgetItem, QByteArray, QCoreApplication,
|
||||||
|
QApplication)
|
||||||
|
|
||||||
|
from calibre.customize.ui import find_plugin
|
||||||
|
from calibre.gui2 import gprefs
|
||||||
from calibre.gui2.dialogs.quickview_ui import Ui_Quickview
|
from calibre.gui2.dialogs.quickview_ui import Ui_Quickview
|
||||||
from calibre.utils.icu import sort_key
|
from calibre.utils.icu import sort_key
|
||||||
from calibre.gui2 import gprefs
|
|
||||||
|
|
||||||
class TableItem(QTableWidgetItem):
|
class TableItem(QTableWidgetItem):
|
||||||
'''
|
'''
|
||||||
@ -55,8 +57,9 @@ class Quickview(QDialog, Ui_Quickview):
|
|||||||
self.is_closed = False
|
self.is_closed = False
|
||||||
self.current_book_id = None
|
self.current_book_id = None
|
||||||
self.current_key = None
|
self.current_key = None
|
||||||
self.use_current_key_for_next_refresh = False
|
|
||||||
self.last_search = None
|
self.last_search = None
|
||||||
|
self.current_column = None
|
||||||
|
self.current_item = None
|
||||||
|
|
||||||
self.items.setSelectionMode(QAbstractItemView.SingleSelection)
|
self.items.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
self.items.currentTextChanged.connect(self.item_selected)
|
self.items.currentTextChanged.connect(self.item_selected)
|
||||||
@ -87,16 +90,24 @@ class Quickview(QDialog, Ui_Quickview):
|
|||||||
# Add the data
|
# Add the data
|
||||||
self.refresh(row)
|
self.refresh(row)
|
||||||
|
|
||||||
self.view.selectionModel().currentChanged[QModelIndex,QModelIndex].connect(self.slave)
|
self.view.clicked.connect(self.slave)
|
||||||
QCoreApplication.instance().aboutToQuit.connect(self.save_state)
|
QCoreApplication.instance().aboutToQuit.connect(self.save_state)
|
||||||
self.search_button.clicked.connect(self.do_search)
|
self.search_button.clicked.connect(self.do_search)
|
||||||
|
view.model().new_bookdisplay_data.connect(self.book_was_changed)
|
||||||
|
|
||||||
# search button
|
# search button
|
||||||
def do_search(self):
|
def do_search(self):
|
||||||
if self.last_search is not None:
|
if self.last_search is not None:
|
||||||
self.use_current_key_for_next_refresh = True
|
|
||||||
self.gui.search.set_search_string(self.last_search)
|
self.gui.search.set_search_string(self.last_search)
|
||||||
|
|
||||||
|
# Called when book information is changed in the library view. Make that
|
||||||
|
# book current. This means that prev and next in edit metadata will move
|
||||||
|
# the current book.
|
||||||
|
def book_was_changed(self, mi):
|
||||||
|
if self.is_closed or self.current_column is None:
|
||||||
|
return
|
||||||
|
self.refresh(self.view.model().index(self.db.row(mi.id), self.current_column))
|
||||||
|
|
||||||
# clicks on the items listWidget
|
# clicks on the items listWidget
|
||||||
def item_selected(self, txt):
|
def item_selected(self, txt):
|
||||||
self.fill_in_books_box(unicode(txt))
|
self.fill_in_books_box(unicode(txt))
|
||||||
@ -104,22 +115,15 @@ class Quickview(QDialog, Ui_Quickview):
|
|||||||
# Given a cell in the library view, display the information
|
# Given a cell in the library view, display the information
|
||||||
def refresh(self, idx):
|
def refresh(self, idx):
|
||||||
bv_row = idx.row()
|
bv_row = idx.row()
|
||||||
key = self.view.model().column_map[idx.column()]
|
self.current_column = idx.column()
|
||||||
|
key = self.view.model().column_map[self.current_column]
|
||||||
book_id = self.view.model().id(bv_row)
|
book_id = self.view.model().id(bv_row)
|
||||||
|
|
||||||
# Double-clicking on a book to show it in the library view will result
|
# Only show items for categories
|
||||||
# in a signal emitted for column 1 of the book row. Use the original
|
if not self.db.field_metadata[key]['is_category']:
|
||||||
# column for this signal.
|
if self.current_key is None:
|
||||||
if self.use_current_key_for_next_refresh:
|
return
|
||||||
key = self.current_key
|
key = self.current_key
|
||||||
self.use_current_key_for_next_refresh = False
|
|
||||||
else:
|
|
||||||
# Only show items for categories
|
|
||||||
if not self.db.field_metadata[key]['is_category']:
|
|
||||||
if self.current_key is None:
|
|
||||||
return
|
|
||||||
key = self.current_key
|
|
||||||
self.items_label.setText('{0} ({1})'.format(
|
self.items_label.setText('{0} ({1})'.format(
|
||||||
self.db.field_metadata[key]['name'], key))
|
self.db.field_metadata[key]['name'], key))
|
||||||
|
|
||||||
@ -147,6 +151,7 @@ class Quickview(QDialog, Ui_Quickview):
|
|||||||
self.items.blockSignals(False)
|
self.items.blockSignals(False)
|
||||||
|
|
||||||
def fill_in_books_box(self, selected_item):
|
def fill_in_books_box(self, selected_item):
|
||||||
|
self.current_item = selected_item
|
||||||
# Do a bit of fix-up on the items so that the search works.
|
# Do a bit of fix-up on the items so that the search works.
|
||||||
if selected_item.startswith('.'):
|
if selected_item.startswith('.'):
|
||||||
sv = '.' + selected_item
|
sv = '.' + selected_item
|
||||||
@ -162,19 +167,26 @@ class Quickview(QDialog, Ui_Quickview):
|
|||||||
|
|
||||||
select_item = None
|
select_item = None
|
||||||
self.books_table.setSortingEnabled(False)
|
self.books_table.setSortingEnabled(False)
|
||||||
|
tt = ('<p>' +
|
||||||
|
_('Double-click on a book to change the selection in the library view. '
|
||||||
|
'Shift- or control-double-click to edit the metadata of a book')
|
||||||
|
+ '</p>')
|
||||||
for row, b in enumerate(books):
|
for row, b in enumerate(books):
|
||||||
mi = self.db.get_metadata(b, index_is_id=True, get_user_categories=False)
|
mi = self.db.get_metadata(b, index_is_id=True, get_user_categories=False)
|
||||||
a = TableItem(mi.title, mi.title_sort)
|
a = TableItem(mi.title, mi.title_sort)
|
||||||
a.setData(Qt.UserRole, b)
|
a.setData(Qt.UserRole, b)
|
||||||
|
a.setToolTip(tt)
|
||||||
self.books_table.setItem(row, 0, a)
|
self.books_table.setItem(row, 0, a)
|
||||||
if b == self.current_book_id:
|
if b == self.current_book_id:
|
||||||
select_item = a
|
select_item = a
|
||||||
a = TableItem(' & '.join(mi.authors), mi.author_sort)
|
a = TableItem(' & '.join(mi.authors), mi.author_sort)
|
||||||
|
a.setToolTip(tt)
|
||||||
self.books_table.setItem(row, 1, a)
|
self.books_table.setItem(row, 1, a)
|
||||||
series = mi.format_field('series')[1]
|
series = mi.format_field('series')[1]
|
||||||
if series is None:
|
if series is None:
|
||||||
series = ''
|
series = ''
|
||||||
a = TableItem(series, series)
|
a = TableItem(series, series)
|
||||||
|
a.setToolTip(tt)
|
||||||
self.books_table.setItem(row, 2, a)
|
self.books_table.setItem(row, 2, a)
|
||||||
self.books_table.setRowHeight(row, self.books_table_row_height)
|
self.books_table.setRowHeight(row, self.books_table_row_height)
|
||||||
|
|
||||||
@ -201,11 +213,16 @@ class Quickview(QDialog, Ui_Quickview):
|
|||||||
self.save_state()
|
self.save_state()
|
||||||
|
|
||||||
def book_doubleclicked(self, row, column):
|
def book_doubleclicked(self, row, column):
|
||||||
self.use_current_key_for_next_refresh = True
|
book_id = self.books_table.item(row, 0).data(Qt.UserRole).toInt()[0]
|
||||||
self.view.select_rows([self.books_table.item(row, 0).data(Qt.UserRole).toInt()[0]])
|
self.view.select_rows([book_id])
|
||||||
|
modifiers = int(QApplication.keyboardModifiers())
|
||||||
|
if modifiers in (Qt.CTRL, Qt.SHIFT):
|
||||||
|
em = find_plugin('Edit Metadata')
|
||||||
|
if em is not None:
|
||||||
|
em.actual_plugin_.edit_metadata(None)
|
||||||
|
|
||||||
# called when a book is clicked on the library view
|
# called when a book is clicked on the library view
|
||||||
def slave(self, current, previous):
|
def slave(self, current):
|
||||||
if self.is_closed:
|
if self.is_closed:
|
||||||
return
|
return
|
||||||
self.refresh(current)
|
self.refresh(current)
|
||||||
|
@ -12,7 +12,7 @@ import inspect, re, traceback
|
|||||||
|
|
||||||
from calibre.utils.titlecase import titlecase
|
from calibre.utils.titlecase import titlecase
|
||||||
from calibre.utils.icu import capitalize, strcmp, sort_key
|
from calibre.utils.icu import capitalize, strcmp, sort_key
|
||||||
from calibre.utils.date import parse_date, format_date
|
from calibre.utils.date import parse_date, format_date, now, UNDEFINED_DATE
|
||||||
|
|
||||||
|
|
||||||
class FormatterFunctions(object):
|
class FormatterFunctions(object):
|
||||||
@ -579,7 +579,7 @@ class BuiltinSubitems(BuiltinFormatterFunction):
|
|||||||
class BuiltinFormatDate(BuiltinFormatterFunction):
|
class BuiltinFormatDate(BuiltinFormatterFunction):
|
||||||
name = 'format_date'
|
name = 'format_date'
|
||||||
arg_count = 2
|
arg_count = 2
|
||||||
category = 'Get values from metadata'
|
category = 'Date functions'
|
||||||
__doc__ = doc = _('format_date(val, format_string) -- format the value, '
|
__doc__ = doc = _('format_date(val, format_string) -- format the value, '
|
||||||
'which must be a date, using the format_string, returning a string. '
|
'which must be a date, using the format_string, returning a string. '
|
||||||
'The formatting codes are: '
|
'The formatting codes are: '
|
||||||
@ -754,6 +754,39 @@ class BuiltinMergeLists(BuiltinFormatterFunction):
|
|||||||
res.append(i)
|
res.append(i)
|
||||||
return ', '.join(sorted(res, key=sort_key))
|
return ', '.join(sorted(res, key=sort_key))
|
||||||
|
|
||||||
|
class BuiltinToday(BuiltinFormatterFunction):
|
||||||
|
name = 'today'
|
||||||
|
arg_count = 0
|
||||||
|
category = 'Date functions'
|
||||||
|
__doc__ = doc = _('today() -- '
|
||||||
|
'return a date string for today. This value is designed for use in '
|
||||||
|
'format_date or days_between, but can be manipulated like any '
|
||||||
|
'other string. The date is in ISO format.')
|
||||||
|
def evaluate(self, formatter, kwargs, mi, locals):
|
||||||
|
return format_date(now(), 'iso')
|
||||||
|
|
||||||
|
class BuiltinDaysBetween(BuiltinFormatterFunction):
|
||||||
|
name = 'days_between'
|
||||||
|
arg_count = 2
|
||||||
|
category = 'Date functions'
|
||||||
|
__doc__ = doc = _('days_between(date1, date2) -- '
|
||||||
|
'return the number of days between date1 and date2. The number is '
|
||||||
|
'positive if date1 is greater than date2, otherwise negative. If '
|
||||||
|
'either date1 or date2 are not dates, the function returns the '
|
||||||
|
'empty string.')
|
||||||
|
def evaluate(self, formatter, kwargs, mi, locals, date1, date2):
|
||||||
|
try:
|
||||||
|
d1 = parse_date(date1)
|
||||||
|
if d1 == UNDEFINED_DATE:
|
||||||
|
return ''
|
||||||
|
d2 = parse_date(date2)
|
||||||
|
if d2 == UNDEFINED_DATE:
|
||||||
|
return ''
|
||||||
|
except:
|
||||||
|
return ''
|
||||||
|
i = d1 - d2
|
||||||
|
return str(i.days)
|
||||||
|
|
||||||
|
|
||||||
builtin_add = BuiltinAdd()
|
builtin_add = BuiltinAdd()
|
||||||
builtin_and = BuiltinAnd()
|
builtin_and = BuiltinAnd()
|
||||||
@ -763,6 +796,7 @@ builtin_capitalize = BuiltinCapitalize()
|
|||||||
builtin_cmp = BuiltinCmp()
|
builtin_cmp = BuiltinCmp()
|
||||||
builtin_contains = BuiltinContains()
|
builtin_contains = BuiltinContains()
|
||||||
builtin_count = BuiltinCount()
|
builtin_count = BuiltinCount()
|
||||||
|
builtin_days_between= BuiltinDaysBetween()
|
||||||
builtin_divide = BuiltinDivide()
|
builtin_divide = BuiltinDivide()
|
||||||
builtin_eval = BuiltinEval()
|
builtin_eval = BuiltinEval()
|
||||||
builtin_first_non_empty = BuiltinFirstNonEmpty()
|
builtin_first_non_empty = BuiltinFirstNonEmpty()
|
||||||
@ -795,6 +829,7 @@ builtin_switch = BuiltinSwitch()
|
|||||||
builtin_template = BuiltinTemplate()
|
builtin_template = BuiltinTemplate()
|
||||||
builtin_test = BuiltinTest()
|
builtin_test = BuiltinTest()
|
||||||
builtin_titlecase = BuiltinTitlecase()
|
builtin_titlecase = BuiltinTitlecase()
|
||||||
|
builtin_today = BuiltinToday()
|
||||||
builtin_uppercase = BuiltinUppercase()
|
builtin_uppercase = BuiltinUppercase()
|
||||||
|
|
||||||
class FormatterUserFunction(FormatterFunction):
|
class FormatterUserFunction(FormatterFunction):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user