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)
ALL_COLUMNS = ['title', 'authors', 'size', 'timestamp', 'rating', 'publisher',
'tags', 'series', 'pubdate']
'tags', 'series', 'pubdate', 'ondevice']
def _config():
c = Config('gui', 'preferences for the calibre GUI')

View File

@ -1,7 +1,7 @@
from __future__ import with_statement
__license__ = 'GPL v3'
__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 itertools import repeat
from functools import partial
@ -978,3 +978,55 @@ class DeviceGUI(object):
getattr(f, 'close', lambda : True)()
if memory and 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"),
'tags' : _("Tags"),
'series' : _("Series"),
'ondevice' : _("On Device"),
}
def __init__(self, parent=None, buffer=40):
QAbstractTableModel.__init__(self, parent)
self.db = None
self.book_on_device = None
self.editable_cols = ['title', 'authors', 'rating', 'publisher',
'tags', 'series', 'timestamp', 'pubdate']
self.default_image = QImage(I('book.svg'))
@ -359,6 +361,9 @@ class BooksModel(QAbstractTableModel):
self.reset()
self.emit(SIGNAL('columns_sorted()'))
def set_book_on_device_func(self, func):
self.book_on_device = func
def set_database(self, db):
self.db = db
self.custom_columns = self.db.custom_column_label_map
@ -799,6 +804,8 @@ class BooksModel(QAbstractTableModel):
'series' : functools.partial(series,
idx=self.db.FIELD_MAP['series'],
siix=self.db.FIELD_MAP['series_index']),
'ondevice' : functools.partial(text_type,
idx=self.db.FIELD_MAP['ondevice'], mult=False),
}
self.dc_decorator = {}
@ -1255,6 +1262,12 @@ class DeviceBooksModel(BooksModel):
self.marked_for_deletion = {}
self.search_engine = OnDeviceSearch(self)
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):
self.marked_for_deletion[job] = self.indices(rows)
@ -1342,8 +1355,11 @@ class DeviceBooksModel(BooksModel):
def tagscmp(x, y):
x, y = ','.join(self.db[x].tags), ','.join(self.db[y].tags)
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 \
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)
if len(self.map) == len(self.db):
self.sorted_map = list(self.map)
@ -1357,7 +1373,7 @@ class DeviceBooksModel(BooksModel):
def columnCount(self, parent):
if parent and parent.isValid():
return 0
return 5
return 6
def rowCount(self, parent):
if parent and parent.isValid():
@ -1398,7 +1414,6 @@ class DeviceBooksModel(BooksModel):
'''
return [ self.map[r.row()] for r in rows]
def data(self, index, role):
if role == Qt.DisplayRole or role == Qt.EditRole:
row, col = index.row(), index.column()
@ -1426,6 +1441,10 @@ class DeviceBooksModel(BooksModel):
tags = self.db[self.map[row]].tags
if 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]:
return QVariant(Qt.AlignRight | Qt.AlignVCenter)
elif role == Qt.ToolTipRole and index.isValid():
@ -1446,6 +1465,7 @@ class DeviceBooksModel(BooksModel):
elif section == 2: text = _("Size (MB)")
elif section == 3: text = _("Date")
elif section == 4: text = _("Tags")
elif section == 5: text = _("In Library")
return QVariant(text)
else:
return QVariant(section+1)
@ -1479,4 +1499,3 @@ class DeviceBooksModel(BooksModel):
def set_search_restriction(self, s):
pass

View File

@ -543,7 +543,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
else:
self.library_path = dir
db = LibraryDatabase2(self.library_path)
db.set_book_on_device_func(self.book_on_device)
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
self.library_view.restore_sort_at_startup(dynamic.get('sort_history', [('timestamp', Qt.DescendingOrder)]))
if not self.library_view.restore_column_widths():
@ -978,6 +980,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
self.status_bar.reset_info()
self.location_view.setCurrentIndex(self.location_view.model().index(0))
self.eject_action.setEnabled(False)
self.refresh_ondevice_info (clear_info = True)
def info_read(self, job):
'''
@ -1012,10 +1015,13 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
return
mainlist, cardalist, cardblist = job.result
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.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_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)
for view in (self.memory_view, self.card_a_view, self.card_b_view):
view.sortByColumn(3, Qt.DescendingOrder)
@ -1025,6 +1031,18 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
view.resize_on_select = not view.isVisible()
self.sync_news()
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 ################################
@ -2250,7 +2268,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
def library_moved(self, newloc):
if newloc is None: return
db = LibraryDatabase2(newloc)
db.set_book_on_device_func(self.book_on_device)
self.library_view.set_database(db)
self.library_view.model().set_book_on_device_func(self.book_on_device)
self.status_bar.clearMessage()
self.search.clear_to_help()
self.status_bar.reset_info()

View File

@ -518,6 +518,7 @@ class ResultCache(SearchQueryParser):
try:
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.book_on_device_string(id, index_is_id=True))
except IndexError:
return None
try:
@ -533,6 +534,7 @@ class ResultCache(SearchQueryParser):
for id in ids:
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.book_on_device_string(id, index_is_id=True))
self._map[0:0] = ids
self._map_filtered[0:0] = ids
@ -553,6 +555,7 @@ class ResultCache(SearchQueryParser):
for item in self._data:
if item is not None:
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]
if field is not None:
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 \
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):
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['cover'] = base+1
self.FIELD_MAP['ondevice'] = base+2
script = '''
DROP VIEW IF EXISTS meta2;
@ -230,6 +231,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
self.conn.executescript(script)
self.conn.commit()
self.book_on_device_func = None
self.data = ResultCache(self.FIELD_MAP, self.custom_column_label_map)
self.search = self.data.search
self.refresh = functools.partial(self.data.refresh, self)
@ -465,6 +467,27 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
im = PILImage.open(f)
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):
formats = self.conn.get('SELECT DISTINCT format from data')
if not formats: