mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
On device indication, temporary implementation
This commit is contained in:
commit
6b6dcf8c40
@ -55,7 +55,13 @@ class JETBOOK(USBMS):
|
|||||||
au = mi.format_authors()
|
au = mi.format_authors()
|
||||||
if not au:
|
if not au:
|
||||||
au = 'Unknown'
|
au = 'Unknown'
|
||||||
return '%s#%s%s' % (au, title, fileext)
|
suffix = ''
|
||||||
|
if getattr(mi, 'application_id', None) is not None:
|
||||||
|
base = fname.rpartition('.')[0]
|
||||||
|
suffix = '_%s'%mi.application_id
|
||||||
|
if base.endswith(suffix):
|
||||||
|
suffix = ''
|
||||||
|
return '%s#%s%s%s' % (au, title, fileext, suffix)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def metadata_from_path(cls, path):
|
def metadata_from_path(cls, path):
|
||||||
|
@ -60,11 +60,6 @@ class KINDLE(USBMS):
|
|||||||
'replace')
|
'replace')
|
||||||
return mi
|
return mi
|
||||||
|
|
||||||
def filename_callback(self, fname, mi):
|
|
||||||
if fname.startswith('.'):
|
|
||||||
return 'x'+fname[1:]
|
|
||||||
return fname
|
|
||||||
|
|
||||||
def get_annotations(self, path_map):
|
def get_annotations(self, path_map):
|
||||||
MBP_FORMATS = [u'azw', u'mobi', u'prc', u'txt']
|
MBP_FORMATS = [u'azw', u'mobi', u'prc', u'txt']
|
||||||
mbp_formats = set(MBP_FORMATS)
|
mbp_formats = set(MBP_FORMATS)
|
||||||
|
@ -121,14 +121,6 @@ class PRS505(CLI, Device):
|
|||||||
self.report_progress(1.0, _('Getting list of books on device...'))
|
self.report_progress(1.0, _('Getting list of books on device...'))
|
||||||
return bl
|
return bl
|
||||||
|
|
||||||
def filename_callback(self, fname, mi):
|
|
||||||
if getattr(mi, 'application_id', None) is not None:
|
|
||||||
base = fname.rpartition('.')[0]
|
|
||||||
suffix = '_%s'%mi.application_id
|
|
||||||
if not base.endswith(suffix):
|
|
||||||
fname = base + suffix + '.' + fname.rpartition('.')[-1]
|
|
||||||
return fname
|
|
||||||
|
|
||||||
def upload_books(self, files, names, on_card=None, end_session=True,
|
def upload_books(self, files, names, on_card=None, end_session=True,
|
||||||
metadata=None):
|
metadata=None):
|
||||||
|
|
||||||
|
@ -46,6 +46,12 @@ class Book(object):
|
|||||||
return self.title.encode('utf-8') + " by " + \
|
return self.title.encode('utf-8') + " by " + \
|
||||||
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
self.authors.encode('utf-8') + " at " + self.path.encode('utf-8')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def db_id(self):
|
||||||
|
'''The database id in the application database that this file corresponds to'''
|
||||||
|
match = re.search(r'_(\d+)$', self.rpath.rpartition('.')[0])
|
||||||
|
if match:
|
||||||
|
return int(match.group(1))
|
||||||
|
|
||||||
class BookList(_BookList):
|
class BookList(_BookList):
|
||||||
|
|
||||||
|
@ -784,8 +784,14 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
def filename_callback(self, default, mi):
|
def filename_callback(self, default, mi):
|
||||||
'''
|
'''
|
||||||
Callback to allow drivers to change the default file name
|
Callback to allow drivers to change the default file name
|
||||||
set by :method:`create_upload_path`.
|
set by :method:`create_upload_path`. By default, add the DB_ID
|
||||||
|
to the end of the string. Helps with ondevice doc matching
|
||||||
'''
|
'''
|
||||||
|
if getattr(mi, 'application_id', None) is not None:
|
||||||
|
base = default.rpartition('.')[0]
|
||||||
|
suffix = '_%s'%mi.application_id
|
||||||
|
if not base.endswith(suffix):
|
||||||
|
default = base + suffix + '.' + default.rpartition('.')[-1]
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def sanitize_path_components(self, components):
|
def sanitize_path_components(self, components):
|
||||||
@ -826,7 +832,7 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
if not isinstance(template, unicode):
|
if not isinstance(template, unicode):
|
||||||
template = template.decode('utf-8')
|
template = template.decode('utf-8')
|
||||||
app_id = str(getattr(mdata, 'application_id', ''))
|
app_id = str(getattr(mdata, 'application_id', ''))
|
||||||
# The SONY readers need to have the db id in the created filename
|
# The db id will be in the created filename
|
||||||
extra_components = get_components(template, mdata, fname,
|
extra_components = get_components(template, mdata, fname,
|
||||||
length=250-len(app_id)-1)
|
length=250-len(app_id)-1)
|
||||||
if not extra_components:
|
if not extra_components:
|
||||||
@ -835,6 +841,9 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
else:
|
else:
|
||||||
extra_components[-1] = sanitize(self.filename_callback(extra_components[-1]+ext, mdata))
|
extra_components[-1] = sanitize(self.filename_callback(extra_components[-1]+ext, mdata))
|
||||||
|
|
||||||
|
if extra_components[-1] and extra_components[-1][0] in ('.', '_'):
|
||||||
|
extra_components[-1] = 'x' + extra_components[-1][1:]
|
||||||
|
|
||||||
if special_tag is not None:
|
if special_tag is not None:
|
||||||
name = extra_components[-1]
|
name = extra_components[-1]
|
||||||
extra_components = []
|
extra_components = []
|
||||||
|
@ -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')
|
||||||
|
@ -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,69 @@ 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, format=None, reset=False):
|
||||||
|
loc = [None, None, None]
|
||||||
|
|
||||||
|
if reset:
|
||||||
|
self.book_on_device_cache = None
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.book_on_device_cache is None:
|
||||||
|
self.book_on_device_cache = []
|
||||||
|
for i, l in enumerate(self.booklists()):
|
||||||
|
self.book_on_device_cache.append({})
|
||||||
|
for book in l:
|
||||||
|
book_title = book.title.lower() if book.title else ''
|
||||||
|
book_title = re.sub('(?u)\W|[_]', '', book_title)
|
||||||
|
if book_title not in self.book_on_device_cache[i]:
|
||||||
|
self.book_on_device_cache[i][book_title] = \
|
||||||
|
{'authors':set(), 'db_ids':set()}
|
||||||
|
book_authors = authors_to_string(book.authors).lower()
|
||||||
|
book_authors = re.sub('(?u)\W|[_]', '', book_authors)
|
||||||
|
self.book_on_device_cache[i][book_title]['authors'].add(book_authors)
|
||||||
|
self.book_on_device_cache[i][book_title]['db_ids'].add(book.db_id)
|
||||||
|
|
||||||
|
db_title = self.library_view.model().db.title(index, index_is_id=True).lower()
|
||||||
|
db_title = re.sub('(?u)\W|[_]', '', db_title)
|
||||||
|
au = self.library_view.model().db.authors(index, index_is_id=True)
|
||||||
|
db_authors = au.lower() if au else ''
|
||||||
|
db_authors = re.sub('(?u)\W|[_]', '', db_authors)
|
||||||
|
for i, l in enumerate(self.booklists()):
|
||||||
|
d = self.book_on_device_cache[i].get(db_title, None)
|
||||||
|
if d and (index in d['db_ids'] or db_authors in d['authors']):
|
||||||
|
loc[i] = True
|
||||||
|
break
|
||||||
|
return loc
|
||||||
|
|
||||||
|
def set_books_in_library(self, booklist, reset = False):
|
||||||
|
if reset:
|
||||||
|
self.book_in_library_cache = None
|
||||||
|
return
|
||||||
|
|
||||||
|
# First build a self.book_in_library_cache of the library, so the search isn't On**2
|
||||||
|
self.book_in_library_cache = {}
|
||||||
|
for id, title in self.library_view.model().db.all_titles():
|
||||||
|
title = re.sub('(?u)\W|[_]', '', title.lower())
|
||||||
|
if title not in self.book_in_library_cache:
|
||||||
|
self.book_in_library_cache[title] = {'authors':set(), 'db_ids':set()}
|
||||||
|
au = self.library_view.model().db.authors(id, index_is_id=True)
|
||||||
|
authors = au.lower() if au else ''
|
||||||
|
authors = re.sub('(?u)\W|[_]', '', authors)
|
||||||
|
self.book_in_library_cache[title]['authors'].add(authors)
|
||||||
|
self.book_in_library_cache[title]['db_ids'].add(id)
|
||||||
|
|
||||||
|
# Now iterate through all the books on the device, setting the in_library field
|
||||||
|
for book in booklist:
|
||||||
|
book_title = book.title.lower() if book.title else ''
|
||||||
|
book_title = re.sub('(?u)\W|[_]', '', book_title)
|
||||||
|
book.in_library = False
|
||||||
|
d = self.book_in_library_cache.get(book_title, None)
|
||||||
|
if d is not None:
|
||||||
|
if book.db_id in d['db_ids']:
|
||||||
|
book.in_library = True
|
||||||
|
continue
|
||||||
|
book_authors = authors_to_string(book.authors).lower() if book.authors else ''
|
||||||
|
book_authors = re.sub('(?u)\W|[_]', '', book_authors)
|
||||||
|
if book_authors in d['authors']:
|
||||||
|
book.in_library = True
|
||||||
|
@ -319,11 +319,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'))
|
||||||
@ -362,6 +364,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
|
||||||
@ -802,6 +807,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 = {}
|
||||||
|
|
||||||
@ -1258,6 +1265,7 @@ 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
|
||||||
|
|
||||||
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)
|
||||||
@ -1345,8 +1353,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.db[x].in_library, self.db[y].in_library
|
||||||
|
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)
|
||||||
@ -1360,7 +1371,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():
|
||||||
@ -1401,7 +1412,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()
|
||||||
@ -1417,7 +1427,7 @@ class DeviceBooksModel(BooksModel):
|
|||||||
if role == Qt.EditRole:
|
if role == Qt.EditRole:
|
||||||
return QVariant(au)
|
return QVariant(au)
|
||||||
authors = string_to_authors(au)
|
authors = string_to_authors(au)
|
||||||
return QVariant("\n".join(authors))
|
return QVariant(" & ".join(authors))
|
||||||
elif col == 2:
|
elif col == 2:
|
||||||
size = self.db[self.map[row]].size
|
size = self.db[self.map[row]].size
|
||||||
return QVariant(BooksView.human_readable(size))
|
return QVariant(BooksView.human_readable(size))
|
||||||
@ -1429,6 +1439,9 @@ 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:
|
||||||
|
return QVariant(_('Yes')) \
|
||||||
|
if self.db[self.map[row]].in_library else QVariant(_('No'))
|
||||||
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():
|
||||||
@ -1449,6 +1462,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)
|
||||||
@ -1482,4 +1496,3 @@ class DeviceBooksModel(BooksModel):
|
|||||||
|
|
||||||
def set_search_restriction(self, s):
|
def set_search_restriction(self, s):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -520,7 +520,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
if self.system_tray_icon.isVisible() and opts.start_in_tray:
|
if self.system_tray_icon.isVisible() and opts.start_in_tray:
|
||||||
self.hide_windows()
|
self.hide_windows()
|
||||||
self.stack.setCurrentIndex(0)
|
self.stack.setCurrentIndex(0)
|
||||||
|
self.book_on_device(None, reset=True)
|
||||||
|
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():
|
||||||
@ -956,6 +959,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):
|
||||||
'''
|
'''
|
||||||
@ -988,12 +992,16 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
else:
|
else:
|
||||||
self.device_job_exception(job)
|
self.device_job_exception(job)
|
||||||
return
|
return
|
||||||
|
self.set_books_in_library(None, reset=True)
|
||||||
mainlist, cardalist, cardblist = job.result
|
mainlist, cardalist, cardblist = job.result
|
||||||
self.memory_view.set_database(mainlist)
|
self.memory_view.set_database(mainlist)
|
||||||
|
self.set_books_in_library(mainlist)
|
||||||
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.set_books_in_library(cardalist)
|
||||||
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.set_books_in_library(cardblist)
|
||||||
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)
|
||||||
@ -1001,8 +1009,19 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
if not view.restore_column_widths():
|
if not view.restore_column_widths():
|
||||||
view.resizeColumnsToContents()
|
view.resizeColumnsToContents()
|
||||||
view.resize_on_select = not view.isVisible()
|
view.resize_on_select = not view.isVisible()
|
||||||
|
if view.model().rowCount(None) > 1:
|
||||||
|
view.resizeRowToContents(0)
|
||||||
|
height = view.rowHeight(0)
|
||||||
|
view.verticalHeader().setDefaultSectionSize(height)
|
||||||
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.book_on_device(None, reset=True)
|
||||||
|
self.library_view.model().refresh()
|
||||||
############################################################################
|
############################################################################
|
||||||
|
|
||||||
######################### Fetch annotations ################################
|
######################### Fetch annotations ################################
|
||||||
@ -2228,7 +2247,10 @@ 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)
|
||||||
|
self.book_on_device(None, reset=True)
|
||||||
|
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()
|
||||||
|
@ -370,7 +370,7 @@ class ResultCache(SearchQueryParser):
|
|||||||
location += 's'
|
location += 's'
|
||||||
|
|
||||||
all = ('title', 'authors', 'publisher', 'tags', 'comments', 'series',
|
all = ('title', 'authors', 'publisher', 'tags', 'comments', 'series',
|
||||||
'formats', 'isbn', 'rating', 'cover')
|
'formats', 'isbn', 'rating', 'cover', 'ondevice')
|
||||||
MAP = {}
|
MAP = {}
|
||||||
|
|
||||||
for x in all: # get the db columns for the standard searchables
|
for x in all: # get the db columns for the standard searchables
|
||||||
@ -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))
|
||||||
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))
|
||||||
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]))
|
||||||
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)
|
||||||
|
@ -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)
|
||||||
|
@ -222,6 +222,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;
|
||||||
@ -233,6 +234,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)
|
||||||
@ -468,6 +470,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):
|
||||||
|
if callable(self.book_on_device_func):
|
||||||
|
return self.book_on_device_func(index)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def book_on_device_string(self, index):
|
||||||
|
loc = []
|
||||||
|
on = self.book_on_device(index)
|
||||||
|
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:
|
||||||
|
@ -100,6 +100,7 @@ class SearchQueryParser(object):
|
|||||||
'search',
|
'search',
|
||||||
'date',
|
'date',
|
||||||
'pubdate',
|
'pubdate',
|
||||||
|
'ondevice',
|
||||||
'all',
|
'all',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user