Commit before merge from trunk

This commit is contained in:
Charles Haley 2010-05-09 06:57:15 +01:00
parent 431b9e15bc
commit a61b71ccb1
7 changed files with 126 additions and 6 deletions

View File

@ -25,7 +25,7 @@ NONE = QVariant() #: Null value to return from the data function of item models
UNDEFINED_QDATE = QDate(UNDEFINED_DATE) UNDEFINED_QDATE = QDate(UNDEFINED_DATE)
ALL_COLUMNS = ['title', 'authors', 'size', 'timestamp', 'rating', 'publisher', ALL_COLUMNS = ['title', 'authors', 'size', 'timestamp', 'rating', 'publisher',
'tags', 'series', 'pubdate'] 'tags', 'series', 'pubdate', 'ondevice']
def _config(): def _config():
c = Config('gui', 'preferences for the calibre GUI') c = Config('gui', 'preferences for the calibre GUI')

View File

@ -1,7 +1,7 @@
from __future__ import with_statement from __future__ import with_statement
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import os, traceback, Queue, time, socket, cStringIO import os, traceback, Queue, time, socket, cStringIO, re
from threading import Thread, RLock from threading import Thread, RLock
from itertools import repeat from itertools import repeat
from functools import partial from functools import partial
@ -978,3 +978,55 @@ class DeviceGUI(object):
getattr(f, 'close', lambda : True)() getattr(f, 'close', lambda : True)()
if memory and memory[1]: if memory and memory[1]:
self.library_view.model().delete_books_by_id(memory[1]) self.library_view.model().delete_books_by_id(memory[1])
def book_on_device(self, index, index_is_id=False, format=None):
loc = [None, None, None]
db_title = self.library_view.model().db.title(index, index_is_id).lower()
db_title = re.sub('(?u)\W|[_]', '', db_title)
au = self.library_view.model().db.authors(index, index_is_id)
db_authors = au.lower() if au else ''
db_authors = re.sub('(?u)\W|[_]', '', db_authors)
for i, l in enumerate(self.booklists()):
for book in l:
book_title = book.title.lower() if book.title else ''
book_title = re.sub('(?u)\W|[_]', '', book_title)
book_authors = authors_to_string(book.authors).lower()
book_authors = re.sub('(?u)\W|[_]', '', book_authors)
if book_title == db_title and book_authors == db_authors:
loc[i] = True
break
return loc
def book_in_library(self, index, oncard=None):
'''
Used to determine if a book on the device is in the library.
Returns the book's id in the library.
'''
bl = []
if oncard == 'carda':
bl = self.booklists()[1]
elif oncard == 'cardb':
bl = self.booklists()[2]
else:
bl = self.booklists()[0]
book = bl[index]
book_title = book.title.lower() if book.title else ''
book_title = re.sub('(?u)\W|[_]', '', book_title)
book_authors = authors_to_string(book.authors).lower() if book.authors else ''
book_authors = re.sub('(?u)\W|[_]', '', book_authors)
# if getattr(book, 'application_id', None) != None and self.library_view.model().db.has_id(book.application_id):
# if book.uuid and self.library_view.model().db.uuid(book.application_id, index_is_id=True) == book.uuid:
# return book.application_id
for id, title in self.library_view.model().db.all_titles():
title = re.sub('(?u)\W|[_]', '', title.lower())
if title == book_title:
au = self.library_view.model().db.authors(id, index_is_id=True)
authors = au.lower() if au else ''
authors = re.sub('(?u)\W|[_]', '', authors)
if authors == book_authors:
return id
return None

View File

@ -316,11 +316,13 @@ class BooksModel(QAbstractTableModel):
'publisher' : _("Publisher"), 'publisher' : _("Publisher"),
'tags' : _("Tags"), 'tags' : _("Tags"),
'series' : _("Series"), 'series' : _("Series"),
'ondevice' : _("On Device"),
} }
def __init__(self, parent=None, buffer=40): def __init__(self, parent=None, buffer=40):
QAbstractTableModel.__init__(self, parent) QAbstractTableModel.__init__(self, parent)
self.db = None self.db = None
self.book_on_device = None
self.editable_cols = ['title', 'authors', 'rating', 'publisher', self.editable_cols = ['title', 'authors', 'rating', 'publisher',
'tags', 'series', 'timestamp', 'pubdate'] 'tags', 'series', 'timestamp', 'pubdate']
self.default_image = QImage(I('book.svg')) self.default_image = QImage(I('book.svg'))
@ -359,6 +361,9 @@ class BooksModel(QAbstractTableModel):
self.reset() self.reset()
self.emit(SIGNAL('columns_sorted()')) self.emit(SIGNAL('columns_sorted()'))
def set_book_on_device_func(self, func):
self.book_on_device = func
def set_database(self, db): def set_database(self, db):
self.db = db self.db = db
self.custom_columns = self.db.custom_column_label_map self.custom_columns = self.db.custom_column_label_map
@ -799,6 +804,8 @@ class BooksModel(QAbstractTableModel):
'series' : functools.partial(series, 'series' : functools.partial(series,
idx=self.db.FIELD_MAP['series'], idx=self.db.FIELD_MAP['series'],
siix=self.db.FIELD_MAP['series_index']), siix=self.db.FIELD_MAP['series_index']),
'ondevice' : functools.partial(text_type,
idx=self.db.FIELD_MAP['ondevice'], mult=False),
} }
self.dc_decorator = {} self.dc_decorator = {}
@ -1255,6 +1262,12 @@ class DeviceBooksModel(BooksModel):
self.marked_for_deletion = {} self.marked_for_deletion = {}
self.search_engine = OnDeviceSearch(self) self.search_engine = OnDeviceSearch(self)
self.editable = True self.editable = True
self.book_in_library = None
self.loc = None
def set_book_in_library_func(self, func, loc):
self.book_in_library = func
self.loc = loc
def mark_for_deletion(self, job, rows): def mark_for_deletion(self, job, rows):
self.marked_for_deletion[job] = self.indices(rows) self.marked_for_deletion[job] = self.indices(rows)
@ -1342,8 +1355,11 @@ class DeviceBooksModel(BooksModel):
def tagscmp(x, y): def tagscmp(x, y):
x, y = ','.join(self.db[x].tags), ','.join(self.db[y].tags) x, y = ','.join(self.db[x].tags), ','.join(self.db[y].tags)
return cmp(x, y) return cmp(x, y)
def libcmp(x, y):
x, y = self.book_in_library(self.map[x], self.loc), self.book_in_library(self.map[y], self.loc)
return cmp(x, y)
fcmp = strcmp('title_sorter') if col == 0 else strcmp('authors') if col == 1 else \ fcmp = strcmp('title_sorter') if col == 0 else strcmp('authors') if col == 1 else \
sizecmp if col == 2 else datecmp if col == 3 else tagscmp sizecmp if col == 2 else datecmp if col == 3 else tagscmp if col == 4 else libcmp
self.map.sort(cmp=fcmp, reverse=descending) self.map.sort(cmp=fcmp, reverse=descending)
if len(self.map) == len(self.db): if len(self.map) == len(self.db):
self.sorted_map = list(self.map) self.sorted_map = list(self.map)
@ -1357,7 +1373,7 @@ class DeviceBooksModel(BooksModel):
def columnCount(self, parent): def columnCount(self, parent):
if parent and parent.isValid(): if parent and parent.isValid():
return 0 return 0
return 5 return 6
def rowCount(self, parent): def rowCount(self, parent):
if parent and parent.isValid(): if parent and parent.isValid():
@ -1398,7 +1414,6 @@ class DeviceBooksModel(BooksModel):
''' '''
return [ self.map[r.row()] for r in rows] return [ self.map[r.row()] for r in rows]
def data(self, index, role): def data(self, index, role):
if role == Qt.DisplayRole or role == Qt.EditRole: if role == Qt.DisplayRole or role == Qt.EditRole:
row, col = index.row(), index.column() row, col = index.row(), index.column()
@ -1426,6 +1441,10 @@ class DeviceBooksModel(BooksModel):
tags = self.db[self.map[row]].tags tags = self.db[self.map[row]].tags
if tags: if tags:
return QVariant(', '.join(tags)) return QVariant(', '.join(tags))
elif col == 5:
if self.book_in_library:
if self.book_in_library(self.map[row], self.loc) != None:
return QVariant(_("True"))
elif role == Qt.TextAlignmentRole and index.column() in [2, 3]: elif role == Qt.TextAlignmentRole and index.column() in [2, 3]:
return QVariant(Qt.AlignRight | Qt.AlignVCenter) return QVariant(Qt.AlignRight | Qt.AlignVCenter)
elif role == Qt.ToolTipRole and index.isValid(): elif role == Qt.ToolTipRole and index.isValid():
@ -1446,6 +1465,7 @@ class DeviceBooksModel(BooksModel):
elif section == 2: text = _("Size (MB)") elif section == 2: text = _("Size (MB)")
elif section == 3: text = _("Date") elif section == 3: text = _("Date")
elif section == 4: text = _("Tags") elif section == 4: text = _("Tags")
elif section == 5: text = _("In Library")
return QVariant(text) return QVariant(text)
else: else:
return QVariant(section+1) return QVariant(section+1)
@ -1479,4 +1499,3 @@ class DeviceBooksModel(BooksModel):
def set_search_restriction(self, s): def set_search_restriction(self, s):
pass pass

View File

@ -543,7 +543,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
else: else:
self.library_path = dir self.library_path = dir
db = LibraryDatabase2(self.library_path) db = LibraryDatabase2(self.library_path)
db.set_book_on_device_func(self.book_on_device)
self.library_view.set_database(db) self.library_view.set_database(db)
self.library_view.model().set_book_on_device_func(self.book_on_device)
prefs['library_path'] = self.library_path prefs['library_path'] = self.library_path
self.library_view.restore_sort_at_startup(dynamic.get('sort_history', [('timestamp', Qt.DescendingOrder)])) self.library_view.restore_sort_at_startup(dynamic.get('sort_history', [('timestamp', Qt.DescendingOrder)]))
if not self.library_view.restore_column_widths(): if not self.library_view.restore_column_widths():
@ -978,6 +980,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.status_bar.reset_info() self.status_bar.reset_info()
self.location_view.setCurrentIndex(self.location_view.model().index(0)) self.location_view.setCurrentIndex(self.location_view.model().index(0))
self.eject_action.setEnabled(False) self.eject_action.setEnabled(False)
self.refresh_ondevice_info (clear_info = True)
def info_read(self, job): def info_read(self, job):
''' '''
@ -1012,10 +1015,13 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return return
mainlist, cardalist, cardblist = job.result mainlist, cardalist, cardblist = job.result
self.memory_view.set_database(mainlist) self.memory_view.set_database(mainlist)
self.memory_view.model().set_book_in_library_func(self.book_in_library, 'main')
self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA) self.memory_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
self.card_a_view.set_database(cardalist) self.card_a_view.set_database(cardalist)
self.card_a_view.model().set_book_in_library_func(self.book_in_library, 'carda')
self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA) self.card_a_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
self.card_b_view.set_database(cardblist) self.card_b_view.set_database(cardblist)
self.card_b_view.model().set_book_in_library_func(self.book_in_library, 'cardb')
self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA) self.card_b_view.set_editable(self.device_manager.device.CAN_SET_METADATA)
for view in (self.memory_view, self.card_a_view, self.card_b_view): for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.sortByColumn(3, Qt.DescendingOrder) view.sortByColumn(3, Qt.DescendingOrder)
@ -1025,6 +1031,18 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
view.resize_on_select = not view.isVisible() view.resize_on_select = not view.isVisible()
self.sync_news() self.sync_news()
self.sync_catalogs() self.sync_catalogs()
self.refresh_ondevice_info()
############################################################################
### Force the library view to refresh, taking into consideration books information
def refresh_ondevice_info(self, clear_flags = False):
# self.library_view.model().db.set_all_ondevice('')
# if not clear_flags:
# for id in self.library_view.model().db:
# self.library_view.model().db.set_book_on_device_string(id, index_is_id=True))
self.library_view.model().refresh()
############################################################################
############################################################################ ############################################################################
######################### Fetch annotations ################################ ######################### Fetch annotations ################################
@ -2250,7 +2268,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
def library_moved(self, newloc): def library_moved(self, newloc):
if newloc is None: return if newloc is None: return
db = LibraryDatabase2(newloc) db = LibraryDatabase2(newloc)
db.set_book_on_device_func(self.book_on_device)
self.library_view.set_database(db) self.library_view.set_database(db)
self.library_view.model().set_book_on_device_func(self.book_on_device)
self.status_bar.clearMessage() self.status_bar.clearMessage()
self.search.clear_to_help() self.search.clear_to_help()
self.status_bar.reset_info() self.status_bar.reset_info()

View File

@ -518,6 +518,7 @@ class ResultCache(SearchQueryParser):
try: try:
self._data[id] = db.conn.get('SELECT * from meta2 WHERE id=?', (id,))[0] self._data[id] = db.conn.get('SELECT * from meta2 WHERE id=?', (id,))[0]
self._data[id].append(db.has_cover(id, index_is_id=True)) self._data[id].append(db.has_cover(id, index_is_id=True))
self._data[id].append(db.book_on_device_string(id, index_is_id=True))
except IndexError: except IndexError:
return None return None
try: try:
@ -533,6 +534,7 @@ class ResultCache(SearchQueryParser):
for id in ids: for id in ids:
self._data[id] = db.conn.get('SELECT * from meta2 WHERE id=?', (id,))[0] self._data[id] = db.conn.get('SELECT * from meta2 WHERE id=?', (id,))[0]
self._data[id].append(db.has_cover(id, index_is_id=True)) self._data[id].append(db.has_cover(id, index_is_id=True))
self._data[id].append(db.book_on_device_string(id, index_is_id=True))
self._map[0:0] = ids self._map[0:0] = ids
self._map_filtered[0:0] = ids self._map_filtered[0:0] = ids
@ -553,6 +555,7 @@ class ResultCache(SearchQueryParser):
for item in self._data: for item in self._data:
if item is not None: if item is not None:
item.append(db.has_cover(item[0], index_is_id=True)) item.append(db.has_cover(item[0], index_is_id=True))
item.append(db.book_on_device_string(item[0], index_is_id=True))
self._map = [i[0] for i in self._data if i is not None] self._map = [i[0] for i in self._data if i is not None]
if field is not None: if field is not None:
self.sort(field, ascending) self.sort(field, ascending)

View File

@ -1070,6 +1070,9 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
return [ (i[0], i[1]) for i in \ return [ (i[0], i[1]) for i in \
self.conn.get('SELECT id, name FROM tags')] self.conn.get('SELECT id, name FROM tags')]
def all_titles(self):
return [ (i[0], i[1]) for i in \
self.conn.get('SELECT id, title FROM books')]
def conversion_options(self, id, format): def conversion_options(self, id, format):
data = self.conn.get('SELECT data FROM conversion_options WHERE book=? AND format=?', (id, format.upper()), all=False) data = self.conn.get('SELECT data FROM conversion_options WHERE book=? AND format=?', (id, format.upper()), all=False)

View File

@ -219,6 +219,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.FIELD_MAP[col] = base = base+1 self.FIELD_MAP[col] = base = base+1
self.FIELD_MAP['cover'] = base+1 self.FIELD_MAP['cover'] = base+1
self.FIELD_MAP['ondevice'] = base+2
script = ''' script = '''
DROP VIEW IF EXISTS meta2; DROP VIEW IF EXISTS meta2;
@ -230,6 +231,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.conn.executescript(script) self.conn.executescript(script)
self.conn.commit() self.conn.commit()
self.book_on_device_func = None
self.data = ResultCache(self.FIELD_MAP, self.custom_column_label_map) self.data = ResultCache(self.FIELD_MAP, self.custom_column_label_map)
self.search = self.data.search self.search = self.data.search
self.refresh = functools.partial(self.data.refresh, self) self.refresh = functools.partial(self.data.refresh, self)
@ -465,6 +467,27 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
im = PILImage.open(f) im = PILImage.open(f)
im.convert('RGB').save(path, 'JPEG') im.convert('RGB').save(path, 'JPEG')
def book_on_device(self, index, index_is_id=False):
if self.book_on_device_func:
return self.book_on_device_func(index, index_is_id)
return None
def book_on_device_string(self, index, index_is_id=False):
loc = []
on = self.book_on_device(index, index_is_id)
if on is not None:
m, a, b = on
if m is not None:
loc.append(_('Main'))
if a is not None:
loc.append(_('Card A'))
if b is not None:
loc.append(_('Card B'))
return ', '.join(loc)
def set_book_on_device_func(self, func):
self.book_on_device_func = func
def all_formats(self): def all_formats(self):
formats = self.conn.get('SELECT DISTINCT format from data') formats = self.conn.get('SELECT DISTINCT format from data')
if not formats: if not formats: