Allow the date to be edited by double clicking the field in the list of books.

This commit is contained in:
Kovid Goyal 2009-01-03 12:55:31 -08:00
parent a8af6cecdd
commit d92e8f4d1f
4 changed files with 57 additions and 19 deletions

View File

@ -458,6 +458,8 @@ class Parser(PreProcessor, LoggingInterface):
def parse_html(self): def parse_html(self):
''' Create lxml ElementTree from HTML ''' ''' Create lxml ElementTree from HTML '''
self.log_info('\tParsing '+os.sep.join(self.htmlfile.path.split(os.sep)[-3:])) self.log_info('\tParsing '+os.sep.join(self.htmlfile.path.split(os.sep)[-3:]))
if self.htmlfile.is_binary:
raise ValueError('Not a valid HTML file: '+self.htmlfile.path)
src = open(self.htmlfile.path, 'rb').read().decode(self.htmlfile.encoding, 'replace').strip() src = open(self.htmlfile.path, 'rb').read().decode(self.htmlfile.encoding, 'replace').strip()
src = src.replace('\x00', '') src = src.replace('\x00', '')
src = self.preprocess(src) src = self.preprocess(src)

View File

@ -8,9 +8,9 @@ from math import cos, sin, pi
from PyQt4.QtGui import QTableView, QAbstractItemView, QColor, \ from PyQt4.QtGui import QTableView, QAbstractItemView, QColor, \
QItemDelegate, QPainterPath, QLinearGradient, QBrush, \ QItemDelegate, QPainterPath, QLinearGradient, QBrush, \
QPen, QStyle, QPainter, QLineEdit, \ QPen, QStyle, QPainter, QLineEdit, \
QPalette, QImage, QApplication, QMenu QPalette, QImage, QApplication, QMenu, QStyledItemDelegate
from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \ from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \
SIGNAL, QObject, QSize, QModelIndex SIGNAL, QObject, QSize, QModelIndex, QDate
from calibre import strftime from calibre import strftime
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
@ -82,6 +82,17 @@ class LibraryDelegate(QItemDelegate):
sb.setMaximum(5) sb.setMaximum(5)
return sb return sb
class DateDelegate(QStyledItemDelegate):
def displayText(self, val, locale):
d = val.toDate()
return d.toString('dd MMM yyyy')
if d.isNull():
return ''
d = datetime(d.year(), d.month(), d.day())
return strftime(BooksView.TIME_FMT, d.timetuple())
class BooksModel(QAbstractTableModel): class BooksModel(QAbstractTableModel):
coding = zip( coding = zip(
[1000,900,500,400,100,90,50,40,10,9,5,4,1], [1000,900,500,400,100,90,50,40,10,9,5,4,1],
@ -114,7 +125,8 @@ class BooksModel(QAbstractTableModel):
QAbstractTableModel.__init__(self, parent) QAbstractTableModel.__init__(self, parent)
self.db = None self.db = None
self.column_map = config['column_map'] self.column_map = config['column_map']
self.editable_cols = ['title', 'authors', 'rating', 'publisher', 'tags', 'series'] self.editable_cols = ['title', 'authors', 'rating', 'publisher',
'tags', 'series', 'timestamp']
self.default_image = QImage(':/images/book.svg') self.default_image = QImage(':/images/book.svg')
self.sorted_on = ('timestamp', Qt.AscendingOrder) self.sorted_on = ('timestamp', Qt.AscendingOrder)
self.last_search = '' # The last search performed on this model self.last_search = '' # The last search performed on this model
@ -136,7 +148,12 @@ class BooksModel(QAbstractTableModel):
idx = self.column_map.index('rating') idx = self.column_map.index('rating')
except ValueError: except ValueError:
idx = -1 idx = -1
self.emit(SIGNAL('columns_sorted(int)'), idx) try:
tidx = self.column_map.index('timestamp')
except ValueError:
tidx = -1
self.emit(SIGNAL('columns_sorted(int,int)'), idx, tidx)
def set_database(self, db): def set_database(self, db):
@ -443,7 +460,7 @@ class BooksModel(QAbstractTableModel):
dt = self.db.data[r][tmdx] dt = self.db.data[r][tmdx]
if dt: if dt:
dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight) dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
return strftime(BooksView.TIME_FMT, dt.timetuple()) return QDate(dt.year, dt.month, dt.day)
def rating(r): def rating(r):
r = self.db.data[r][ridx] r = self.db.data[r][ridx]
@ -508,35 +525,40 @@ class BooksModel(QAbstractTableModel):
return flags return flags
def setData(self, index, value, role): def setData(self, index, value, role):
done = False
if role == Qt.EditRole: if role == Qt.EditRole:
row, col = index.row(), index.column() row, col = index.row(), index.column()
column = self.column_map[col] column = self.column_map[col]
if column not in self.editable_cols: if column not in self.editable_cols:
return False return False
val = unicode(value.toString().toUtf8(), 'utf-8').strip() if column != 'rating' else \ val = int(value.toInt()[0]) if column == 'rating' else \
int(value.toInt()[0]) value.toDate() if column == 'timestamp' else \
unicode(value.toString())
id = self.db.id(row)
if column == 'rating': if column == 'rating':
val = 0 if val < 0 else 5 if val > 5 else val val = 0 if val < 0 else 5 if val > 5 else val
val *= 2 val *= 2
if column == 'series': elif column == 'series':
pat = re.compile(r'\[(\d+)\]') pat = re.compile(r'\[(\d+)\]')
match = pat.search(val) match = pat.search(val)
id = self.db.id(row)
if match is not None: if match is not None:
self.db.set_series_index(id, int(match.group(1))) self.db.set_series_index(id, int(match.group(1)))
val = pat.sub('', val) val = pat.sub('', val)
val = val.strip() val = val.strip()
if val: if val:
self.db.set_series(id, val) self.db.set_series(id, val)
elif column == 'timestamp':
if val.isNull() or not val.isValid():
return False
dt = datetime(val.year(), val.month(), val.day()) + timedelta(seconds=time.timezone) - timedelta(hours=time.daylight)
self.db.set_timestamp(id, dt)
else: else:
self.db.set(row, column, val) self.db.set(row, column, val)
self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), \ self.emit(SIGNAL("dataChanged(QModelIndex, QModelIndex)"), \
index, index) index, index)
if column == self.sorted_on[0]: if column == self.sorted_on[0]:
self.resort() self.resort()
done = True
return done return True
class BooksView(TableView): class BooksView(TableView):
TIME_FMT = '%d %b %Y' TIME_FMT = '%d %b %Y'
@ -555,25 +577,29 @@ class BooksView(TableView):
def __init__(self, parent, modelcls=BooksModel): def __init__(self, parent, modelcls=BooksModel):
TableView.__init__(self, parent) TableView.__init__(self, parent)
self.rating_delegate = LibraryDelegate(self) self.rating_delegate = LibraryDelegate(self)
self.timestamp_delegate = DateDelegate(self)
self.display_parent = parent self.display_parent = parent
self._model = modelcls(self) self._model = modelcls(self)
self.setModel(self._model) self.setModel(self._model)
self.setSelectionBehavior(QAbstractItemView.SelectRows) self.setSelectionBehavior(QAbstractItemView.SelectRows)
self.setSortingEnabled(True) self.setSortingEnabled(True)
try: try:
self.columns_sorted(self._model.column_map.index('rating')) self.columns_sorted(self._model.column_map.index('rating'),
self._model.column_map.index('timestamp'))
except ValueError: except ValueError:
pass pass
QObject.connect(self.selectionModel(), SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'), QObject.connect(self.selectionModel(), SIGNAL('currentRowChanged(QModelIndex, QModelIndex)'),
self._model.current_changed) self._model.current_changed)
self.connect(self._model, SIGNAL('columns_sorted(int)'), self.columns_sorted, Qt.QueuedConnection) self.connect(self._model, SIGNAL('columns_sorted(int, int)'), self.columns_sorted, Qt.QueuedConnection)
def columns_sorted(self, col): def columns_sorted(self, rating_col, timestamp_col):
for i in range(self.model().columnCount(None)): for i in range(self.model().columnCount(None)):
if self.itemDelegateForColumn(i) == self.rating_delegate: if self.itemDelegateForColumn(i) == self.rating_delegate:
self.setItemDelegateForColumn(i, self.itemDelegate()) self.setItemDelegateForColumn(i, self.itemDelegate())
if col > -1: if rating_col > -1:
self.setItemDelegateForColumn(col, self.rating_delegate) self.setItemDelegateForColumn(rating_col, self.rating_delegate)
if timestamp_col > -1:
self.setItemDelegateForColumn(timestamp_col, self.timestamp_delegate)
def set_context_menu(self, edit_metadata, send_to_device, convert, view, def set_context_menu(self, edit_metadata, send_to_device, convert, view,
save, open_folder, book_details, similar_menu=None): save, open_folder, book_details, similar_menu=None):

View File

@ -583,6 +583,7 @@ class Main(MainWindow, Ui_MainWindow):
try: try:
duplicates = self.library_view.model().db.recursive_import(root, single, callback=callback) duplicates = self.library_view.model().db.recursive_import(root, single, callback=callback)
finally: finally:
progress.hide()
progress.close() progress.close()
if duplicates: if duplicates:
files = _('<p>Books with the same title as the following already exist in the database. Add them anyway?<ul>') files = _('<p>Books with the same title as the following already exist in the database. Add them anyway?<ul>')
@ -702,7 +703,8 @@ class Main(MainWindow, Ui_MainWindow):
else: else:
self.upload_books(paths, list(map(sanitize_file_name, names)), infos, on_card=on_card) self.upload_books(paths, list(map(sanitize_file_name, names)), infos, on_card=on_card)
finally: finally:
progress.setValue(len(paths)) progress.setValue(progress.maximum())
progress.hide()
progress.close() progress.close()
def upload_books(self, files, names, metadata, on_card=False, memory=None): def upload_books(self, files, names, metadata, on_card=False, memory=None):

View File

@ -878,6 +878,14 @@ class LibraryDatabase2(LibraryDatabase):
if notify: if notify:
self.notify('metadata', [id]) self.notify('metadata', [id])
def set_timestamp(self, id, dt, notify=True):
if dt:
self.conn.execute('UPDATE books SET timestamp=? WHERE id=?', (dt, id))
self.data.set(id, FIELD_MAP['timestamp'], dt, row_is_id=True)
self.conn.commit()
if notify:
self.notify('metadata', [id])
def set_publisher(self, id, publisher, notify=True): def set_publisher(self, id, publisher, notify=True):
self.conn.execute('DELETE FROM books_publishers_link WHERE book=?',(id,)) self.conn.execute('DELETE FROM books_publishers_link WHERE book=?',(id,))
self.conn.execute('DELETE FROM publishers WHERE (SELECT COUNT(id) FROM books_publishers_link WHERE publisher=publishers.id) < 1') self.conn.execute('DELETE FROM publishers WHERE (SELECT COUNT(id) FROM books_publishers_link WHERE publisher=publishers.id) < 1')