diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py index 37d7d56ce1..e0d5c64961 100644 --- a/src/calibre/gui2/library/models.py +++ b/src/calibre/gui2/library/models.py @@ -12,7 +12,7 @@ from operator import attrgetter from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \ QModelIndex, QVariant, QDate -from calibre.gui2 import NONE, config, UNDEFINED_QDATE, FunctionDispatcher +from calibre.gui2 import NONE, config, UNDEFINED_QDATE from calibre.utils.pyparsing import ParseException from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors from calibre.ptempfile import PersistentTemporaryFile @@ -22,7 +22,7 @@ from calibre.utils.icu import sort_key, strcmp as icu_strcmp from calibre.ebooks.metadata.meta import set_metadata as _set_metadata from calibre.utils.search_query_parser import SearchQueryParser from calibre.library.caches import _match, CONTAINS_MATCH, EQUALS_MATCH, \ - REGEXP_MATCH, CoverCache, MetadataBackup + REGEXP_MATCH, MetadataBackup from calibre.library.cli import parse_series_string from calibre import strftime, isbytestring, prepare_string_for_xml from calibre.constants import filesystem_encoding, DEBUG @@ -89,7 +89,6 @@ class BooksModel(QAbstractTableModel): # {{{ self.headers = {} self.alignment_map = {} self.buffer_size = buffer - self.cover_cache = None self.metadata_backup = None self.bool_yes_icon = QIcon(I('ok.png')) self.bool_no_icon = QIcon(I('list_remove.png')) @@ -113,10 +112,6 @@ class BooksModel(QAbstractTableModel): # {{{ def is_custom_column(self, cc_label): return cc_label in self.custom_columns - def clear_caches(self): - if self.cover_cache: - self.cover_cache.clear_cache() - def read_config(self): self.use_roman_numbers = config['use_roman_numerals_for_series_number'] @@ -154,18 +149,8 @@ class BooksModel(QAbstractTableModel): # {{{ self.build_data_convertors() self.reset() self.database_changed.emit(db) - if self.cover_cache is not None: - self.cover_cache.stop() - # Would like to to a join here, but the thread might be waiting to - # do something on the GUI thread. Deadlock. - self.cover_cache = CoverCache(db, FunctionDispatcher(self.db.cover)) - self.cover_cache.start() self.stop_metadata_backup() self.start_metadata_backup() - def refresh_cover(event, ids): - if event == 'cover' and self.cover_cache is not None: - self.cover_cache.refresh(ids) - db.add_listener(refresh_cover) def start_metadata_backup(self): self.metadata_backup = MetadataBackup(self.db) @@ -225,7 +210,6 @@ class BooksModel(QAbstractTableModel): # {{{ def books_deleted(self): self.count_changed() - self.clear_caches() self.reset() def delete_books(self, indices): @@ -254,7 +238,6 @@ class BooksModel(QAbstractTableModel): # {{{ return self.last_search = text if reset: - self.clear_caches() self.reset() if self.last_search: # Do not issue search done for the null search. It is used to clear @@ -269,7 +252,6 @@ class BooksModel(QAbstractTableModel): # {{{ label = self.column_map[col] self.db.sort(label, ascending) if reset: - self.clear_caches() self.reset() self.sorted_on = (label, order) self.sort_history.insert(0, self.sorted_on) @@ -357,26 +339,10 @@ class BooksModel(QAbstractTableModel): # {{{ data[name] = val return data - def set_cache(self, idx): - l, r = 0, self.count()-1 - if self.cover_cache is not None: - l = max(l, idx-self.buffer_size) - r = min(r, idx+self.buffer_size) - k = min(r-idx, idx-l) - ids = [idx] - for i in range(1, k): - ids.extend([idx-i, idx+i]) - ids = ids + [i for i in range(l, r, 1) if i not in ids] - try: - ids = [self.db.id(i) for i in ids] - except IndexError: - return - self.cover_cache.set_cache(ids) def current_changed(self, current, previous, emit_signal=True): if current.isValid(): idx = current.row() - self.set_cache(idx) data = self.get_book_display_info(idx) if emit_signal: self.new_bookdisplay_data.emit(data) @@ -533,13 +499,7 @@ class BooksModel(QAbstractTableModel): # {{{ def cover(self, row_number): data = None try: - id = self.db.id(row_number) - if self.cover_cache is not None: - img = self.cover_cache.cover(id) - if not img.isNull(): - return img - if not data: - data = self.db.cover(row_number) + data = self.db.cover(row_number) except IndexError: # Happens if database has not yet been refreshed pass diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index c3e0bcb0da..219a76bceb 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -583,9 +583,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ while self.spare_servers: self.spare_servers.pop().close() self.device_manager.keep_going = False - cc = self.library_view.model().cover_cache - if cc is not None: - cc.stop() mb = self.library_view.model().metadata_backup if mb is not None: mb.stop() diff --git a/src/calibre/library/caches.py b/src/calibre/library/caches.py index a99c9df125..ff3aa0bf67 100644 --- a/src/calibre/library/caches.py +++ b/src/calibre/library/caches.py @@ -9,10 +9,8 @@ __docformat__ = 'restructuredtext en' import re, itertools, time, traceback from itertools import repeat from datetime import timedelta -from threading import Thread, RLock -from Queue import Queue, Empty - -from PyQt4.Qt import QImage, Qt +from threading import Thread +from Queue import Empty from calibre.utils.config import tweaks from calibre.utils.date import parse_date, now, UNDEFINED_DATE @@ -20,7 +18,7 @@ from calibre.utils.search_query_parser import SearchQueryParser from calibre.utils.pyparsing import ParseException from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata.opf2 import metadata_to_opf -from calibre import fit_image, prints +from calibre import prints class MetadataBackup(Thread): # {{{ ''' @@ -118,113 +116,6 @@ class MetadataBackup(Thread): # {{{ # }}} -class CoverCache(Thread): # {{{ - - def __init__(self, db, cover_func): - Thread.__init__(self) - self.daemon = True - self.db = db - self.cover_func = cover_func - self.load_queue = Queue() - self.keep_running = True - self.cache = {} - self.lock = RLock() - self.allowed_ids = frozenset([]) - self.null_image = QImage() - - def stop(self): - self.keep_running = False - - def _image_for_id(self, id_): - img = self.cover_func(id_, index_is_id=True, as_image=True) - if img is None: - img = QImage() - if not img.isNull(): - scaled, nwidth, nheight = fit_image(img.width(), - img.height(), 600, 800) - if scaled: - img = img.scaled(nwidth, nheight, Qt.KeepAspectRatio, - Qt.SmoothTransformation) - - return img - - def run(self): - while self.keep_running: - try: - # The GUI puts the same ID into the queue many times. The code - # below emptys the queue, building a set of unique values. When - # the queue is empty, do the work - ids = set() - id_ = self.load_queue.get(True, 2) - ids.add(id_) - try: - while True: - # Give the gui some time to put values into the queue - id_ = self.load_queue.get(True, 0.5) - ids.add(id_) - except Empty: - pass - except: - # Happens during shutdown - break - except Empty: - continue - except: - #Happens during interpreter shutdown - break - if not self.keep_running: - break - for id_ in ids: - time.sleep(0.050) # Limit 20/second to not overwhelm the GUI - if not self.keep_running: - return - with self.lock: - if id_ not in self.allowed_ids: - continue - try: - img = self._image_for_id(id_) - except: - try: - traceback.print_exc() - except: - # happens during shutdown - break - continue - try: - with self.lock: - self.cache[id_] = img - except: - # Happens during interpreter shutdown - break - - def set_cache(self, ids): - with self.lock: - self.allowed_ids = frozenset(ids) - already_loaded = set([]) - for id in self.cache.keys(): - if id in ids: - already_loaded.add(id) - else: - self.cache.pop(id) - for id_ in set(ids) - already_loaded: - self.load_queue.put(id_) - - def cover(self, id_): - with self.lock: - return self.cache.get(id_, self.null_image) - - def clear_cache(self): - with self.lock: - self.cache = {} - - def refresh(self, ids): - with self.lock: - for id_ in ids: - cover = self.cache.pop(id_, None) - if cover is not None: - self.load_queue.put(id_) -# }}} - ### Global utility function for get_match here and in gui2/library.py CONTAINS_MATCH = 0 EQUALS_MATCH = 1