mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Move the cover cache into its own module
This commit is contained in:
parent
7fe8d334d4
commit
e844dd117f
@ -9,8 +9,7 @@ __copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
import itertools, operator, os
|
import itertools, operator, os
|
||||||
from types import MethodType
|
from types import MethodType
|
||||||
from time import time
|
from time import time
|
||||||
from collections import OrderedDict
|
from threading import Event, Thread
|
||||||
from threading import Lock, Event, Thread, current_thread
|
|
||||||
from Queue import Queue
|
from Queue import Queue
|
||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
from textwrap import wrap
|
from textwrap import wrap
|
||||||
@ -24,6 +23,7 @@ from PyQt4.Qt import (
|
|||||||
|
|
||||||
from calibre import fit_image
|
from calibre import fit_image
|
||||||
from calibre.gui2 import gprefs, config
|
from calibre.gui2 import gprefs, config
|
||||||
|
from calibre.gui2.library.caches import CoverCache
|
||||||
from calibre.utils.config import prefs
|
from calibre.utils.config import prefs
|
||||||
|
|
||||||
CM_TO_INCH = 0.393701
|
CM_TO_INCH = 0.393701
|
||||||
@ -271,69 +271,7 @@ class AlternateViews(object):
|
|||||||
view.set_context_menu(menu)
|
view.set_context_menu(menu)
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Caching and rendering of covers {{{
|
# Rendering of covers {{{
|
||||||
class CoverCache(dict):
|
|
||||||
|
|
||||||
def __init__(self, limit=200):
|
|
||||||
self.items = OrderedDict()
|
|
||||||
self.lock = Lock()
|
|
||||||
self.limit = limit
|
|
||||||
self.pixmap_staging = []
|
|
||||||
self.gui_thread = current_thread()
|
|
||||||
|
|
||||||
def clear_staging(self):
|
|
||||||
' Must be called in the GUI thread '
|
|
||||||
self.pixmap_staging = []
|
|
||||||
|
|
||||||
def invalidate(self, book_id):
|
|
||||||
with self.lock:
|
|
||||||
self._pop(book_id)
|
|
||||||
|
|
||||||
def _pop(self, book_id):
|
|
||||||
val = self.items.pop(book_id, None)
|
|
||||||
if type(val) is QPixmap and current_thread() is not self.gui_thread:
|
|
||||||
self.pixmap_staging.append(val)
|
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
' Must be called in the GUI thread '
|
|
||||||
with self.lock:
|
|
||||||
self.clear_staging()
|
|
||||||
ans = self.items.pop(key, False) # pop() so that item is moved to the top
|
|
||||||
if ans is not False:
|
|
||||||
if type(ans) is QImage:
|
|
||||||
# Convert to QPixmap, since rendering QPixmap is much
|
|
||||||
# faster
|
|
||||||
ans = QPixmap.fromImage(ans)
|
|
||||||
self.items[key] = ans
|
|
||||||
|
|
||||||
return ans
|
|
||||||
|
|
||||||
def set(self, key, val):
|
|
||||||
with self.lock:
|
|
||||||
self._pop(key) # pop() so that item is moved to the top
|
|
||||||
self.items[key] = val
|
|
||||||
if len(self.items) > self.limit:
|
|
||||||
del self.items[next(self.items.iterkeys())]
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
with self.lock:
|
|
||||||
if current_thread() is not self.gui_thread:
|
|
||||||
pixmaps = (x for x in self.items.itervalues() if type(x) is QPixmap)
|
|
||||||
self.pixmap_staging.extend(pixmaps)
|
|
||||||
self.items.clear()
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return id(self)
|
|
||||||
|
|
||||||
def set_limit(self, limit):
|
|
||||||
with self.lock:
|
|
||||||
self.limit = limit
|
|
||||||
if len(self.items) > self.limit:
|
|
||||||
extra = len(self.items) - self.limit
|
|
||||||
remove = tuple(self.iterkeys())[:extra]
|
|
||||||
for k in remove:
|
|
||||||
self._pop(k)
|
|
||||||
|
|
||||||
class CoverDelegate(QStyledItemDelegate):
|
class CoverDelegate(QStyledItemDelegate):
|
||||||
|
|
||||||
@pyqtProperty(float)
|
@pyqtProperty(float)
|
||||||
@ -458,6 +396,7 @@ def join_with_timeout(q, timeout=2):
|
|||||||
q.all_tasks_done.release()
|
q.all_tasks_done.release()
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
|
# The View {{{
|
||||||
@setup_dnd_interface
|
@setup_dnd_interface
|
||||||
class GridView(QListView):
|
class GridView(QListView):
|
||||||
|
|
||||||
@ -699,4 +638,4 @@ class GridView(QListView):
|
|||||||
|
|
||||||
def restore_hpos(self, hpos):
|
def restore_hpos(self, hpos):
|
||||||
pass
|
pass
|
||||||
|
# }}}
|
||||||
|
77
src/calibre/gui2/library/caches.py
Normal file
77
src/calibre/gui2/library/caches.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# vim:fileencoding=utf-8
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import,
|
||||||
|
print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
|
from threading import Lock, current_thread
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from PyQt4.Qt import QImage, QPixmap
|
||||||
|
|
||||||
|
class CoverCache(dict):
|
||||||
|
|
||||||
|
' This is a RAM cache to speed up rendering of covers by storing them as QPixmaps '
|
||||||
|
|
||||||
|
def __init__(self, limit=200):
|
||||||
|
self.items = OrderedDict()
|
||||||
|
self.lock = Lock()
|
||||||
|
self.limit = limit
|
||||||
|
self.pixmap_staging = []
|
||||||
|
self.gui_thread = current_thread()
|
||||||
|
|
||||||
|
def clear_staging(self):
|
||||||
|
' Must be called in the GUI thread '
|
||||||
|
self.pixmap_staging = []
|
||||||
|
|
||||||
|
def invalidate(self, book_id):
|
||||||
|
with self.lock:
|
||||||
|
self._pop(book_id)
|
||||||
|
|
||||||
|
def _pop(self, book_id):
|
||||||
|
val = self.items.pop(book_id, None)
|
||||||
|
if type(val) is QPixmap and current_thread() is not self.gui_thread:
|
||||||
|
self.pixmap_staging.append(val)
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
' Must be called in the GUI thread '
|
||||||
|
with self.lock:
|
||||||
|
self.clear_staging()
|
||||||
|
ans = self.items.pop(key, False) # pop() so that item is moved to the top
|
||||||
|
if ans is not False:
|
||||||
|
if type(ans) is QImage:
|
||||||
|
# Convert to QPixmap, since rendering QPixmap is much
|
||||||
|
# faster
|
||||||
|
ans = QPixmap.fromImage(ans)
|
||||||
|
self.items[key] = ans
|
||||||
|
|
||||||
|
return ans
|
||||||
|
|
||||||
|
def set(self, key, val):
|
||||||
|
with self.lock:
|
||||||
|
self._pop(key) # pop() so that item is moved to the top
|
||||||
|
self.items[key] = val
|
||||||
|
if len(self.items) > self.limit:
|
||||||
|
del self.items[next(self.items.iterkeys())]
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
with self.lock:
|
||||||
|
if current_thread() is not self.gui_thread:
|
||||||
|
pixmaps = (x for x in self.items.itervalues() if type(x) is QPixmap)
|
||||||
|
self.pixmap_staging.extend(pixmaps)
|
||||||
|
self.items.clear()
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return id(self)
|
||||||
|
|
||||||
|
def set_limit(self, limit):
|
||||||
|
with self.lock:
|
||||||
|
self.limit = limit
|
||||||
|
if len(self.items) > self.limit:
|
||||||
|
extra = len(self.items) - self.limit
|
||||||
|
remove = tuple(self.iterkeys())[:extra]
|
||||||
|
for k in remove:
|
||||||
|
self._pop(k)
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user