mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Pull from trunk
This commit is contained in:
commit
d7a3f29b3b
@ -1,7 +1,7 @@
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
""" The GUI """
|
""" The GUI """
|
||||||
import os, sys
|
import os, sys, Queue
|
||||||
from threading import RLock
|
from threading import RLock
|
||||||
|
|
||||||
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
from PyQt4.Qt import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, \
|
||||||
@ -296,6 +296,34 @@ class Dispatcher(QObject):
|
|||||||
def dispatch(self, args, kwargs):
|
def dispatch(self, args, kwargs):
|
||||||
self.func(*args, **kwargs)
|
self.func(*args, **kwargs)
|
||||||
|
|
||||||
|
class FunctionDispatcher(QObject):
|
||||||
|
'''
|
||||||
|
Convenience class to use Qt signals with arbitrary python functions.
|
||||||
|
By default, ensures that a function call always happens in the
|
||||||
|
thread this Dispatcher was created in.
|
||||||
|
'''
|
||||||
|
dispatch_signal = pyqtSignal(object, object, object)
|
||||||
|
|
||||||
|
def __init__(self, func, queued=True, parent=None):
|
||||||
|
QObject.__init__(self, parent)
|
||||||
|
self.func = func
|
||||||
|
typ = Qt.QueuedConnection
|
||||||
|
if not queued:
|
||||||
|
typ = Qt.AutoConnection if queued is None else Qt.DirectConnection
|
||||||
|
self.dispatch_signal.connect(self.dispatch, type=typ)
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
q = Queue.Queue()
|
||||||
|
self.dispatch_signal.emit(q, args, kwargs)
|
||||||
|
return q.get()
|
||||||
|
|
||||||
|
def dispatch(self, q, args, kwargs):
|
||||||
|
try:
|
||||||
|
res = self.func(*args, **kwargs)
|
||||||
|
except:
|
||||||
|
res = None
|
||||||
|
q.put(res)
|
||||||
|
|
||||||
class GetMetadata(QObject):
|
class GetMetadata(QObject):
|
||||||
'''
|
'''
|
||||||
Convenience class to ensure that metadata readers are used only in the
|
Convenience class to ensure that metadata readers are used only in the
|
||||||
|
@ -40,8 +40,7 @@ class TweakEpubAction(InterfaceAction):
|
|||||||
_('No ePub available. First convert the book to ePub.'),
|
_('No ePub available. First convert the book to ePub.'),
|
||||||
show=True)
|
show=True)
|
||||||
|
|
||||||
|
# Launch modal dialog waiting for user to tweak or cancel
|
||||||
# Launch a modal dialog waiting for user to complete or cancel
|
|
||||||
dlg = TweakEpub(self.gui, path_to_epub)
|
dlg = TweakEpub(self.gui, path_to_epub)
|
||||||
if dlg.exec_() == dlg.Accepted:
|
if dlg.exec_() == dlg.Accepted:
|
||||||
self.update_db(book_id, dlg._output)
|
self.update_db(book_id, dlg._output)
|
||||||
|
@ -21,8 +21,6 @@ class TweakEpub(QDialog, Ui_Dialog):
|
|||||||
'''
|
'''
|
||||||
Display controls for tweaking ePubs
|
Display controls for tweaking ePubs
|
||||||
|
|
||||||
To do:
|
|
||||||
- need way to kill file browser proc in cleanup()
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
def __init__(self, parent, epub):
|
def __init__(self, parent, epub):
|
||||||
@ -30,7 +28,6 @@ class TweakEpub(QDialog, Ui_Dialog):
|
|||||||
|
|
||||||
self._epub = epub
|
self._epub = epub
|
||||||
self._exploded = None
|
self._exploded = None
|
||||||
#self._file_browser_proc = None
|
|
||||||
self._output = None
|
self._output = None
|
||||||
|
|
||||||
# Run the dialog setup generated from tweak_epub.ui
|
# Run the dialog setup generated from tweak_epub.ui
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
<string>&Explode ePub</string>
|
<string>&Explode ePub</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
<iconset>
|
||||||
<normaloff>:/images/wizard.png</normaloff>:/images/wizard.png</iconset>
|
<normaloff>:/images/wizard.png</normaloff>:/images/wizard.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -49,7 +49,7 @@
|
|||||||
<string>&Rebuild ePub</string>
|
<string>&Rebuild ePub</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
<iconset>
|
||||||
<normaloff>:/images/exec.png</normaloff>:/images/exec.png</iconset>
|
<normaloff>:/images/exec.png</normaloff>:/images/exec.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -63,7 +63,7 @@
|
|||||||
<string>&Cancel</string>
|
<string>&Cancel</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset resource="../../../../resources/images.qrc">
|
<iconset>
|
||||||
<normaloff>:/images/window-close.png</normaloff>:/images/window-close.png</iconset>
|
<normaloff>:/images/window-close.png</normaloff>:/images/window-close.png</iconset>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
@ -71,7 +71,7 @@
|
|||||||
<item row="0" column="0">
|
<item row="0" column="0">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>First, explode the epub. Then edit is contents by right clicking on the individual files and selecting the editor of your choice. When you are done, click rebuild epub and the epub in your calibre library will be updated with the changes you have made.</string>
|
<string>Explode the ePub to display contents in a file browser window. To tweak individual files, right-click, then 'Open with...' your editor of choice. When tweaks are complete, close the file browser window. Rebuild the ePub, updating your calibre library.</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="wordWrap">
|
<property name="wordWrap">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -12,7 +12,7 @@ from operator import attrgetter
|
|||||||
from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \
|
from PyQt4.Qt import QAbstractTableModel, Qt, pyqtSignal, QIcon, QImage, \
|
||||||
QModelIndex, QVariant, QDate
|
QModelIndex, QVariant, QDate
|
||||||
|
|
||||||
from calibre.gui2 import NONE, config, UNDEFINED_QDATE
|
from calibre.gui2 import NONE, config, UNDEFINED_QDATE, FunctionDispatcher
|
||||||
from calibre.utils.pyparsing import ParseException
|
from calibre.utils.pyparsing import ParseException
|
||||||
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
from calibre.ebooks.metadata import fmt_sidx, authors_to_string, string_to_authors
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
@ -151,7 +151,7 @@ class BooksModel(QAbstractTableModel): # {{{
|
|||||||
self.database_changed.emit(db)
|
self.database_changed.emit(db)
|
||||||
if self.cover_cache is not None:
|
if self.cover_cache is not None:
|
||||||
self.cover_cache.stop()
|
self.cover_cache.stop()
|
||||||
self.cover_cache = CoverCache(db)
|
self.cover_cache = CoverCache(db, FunctionDispatcher(self.db.cover))
|
||||||
self.cover_cache.start()
|
self.cover_cache.start()
|
||||||
def refresh_cover(event, ids):
|
def refresh_cover(event, ids):
|
||||||
if event == 'cover' and self.cover_cache is not None:
|
if event == 'cover' and self.cover_cache is not None:
|
||||||
|
@ -6,7 +6,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import re, itertools
|
import re, itertools, time
|
||||||
from itertools import repeat
|
from itertools import repeat
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from threading import Thread, RLock
|
from threading import Thread, RLock
|
||||||
@ -23,10 +23,11 @@ from calibre import fit_image
|
|||||||
|
|
||||||
class CoverCache(Thread):
|
class CoverCache(Thread):
|
||||||
|
|
||||||
def __init__(self, db):
|
def __init__(self, db, cover_func):
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
self.daemon = True
|
self.daemon = True
|
||||||
self.db = db
|
self.db = db
|
||||||
|
self.cover_func = cover_func
|
||||||
self.load_queue = Queue()
|
self.load_queue = Queue()
|
||||||
self.keep_running = True
|
self.keep_running = True
|
||||||
self.cache = {}
|
self.cache = {}
|
||||||
@ -37,7 +38,8 @@ class CoverCache(Thread):
|
|||||||
self.keep_running = False
|
self.keep_running = False
|
||||||
|
|
||||||
def _image_for_id(self, id_):
|
def _image_for_id(self, id_):
|
||||||
img = self.db.cover(id_, index_is_id=True, as_image=True)
|
time.sleep(0.050) # Limit 20/second to not overwhelm the GUI
|
||||||
|
img = self.cover_func(id_, index_is_id=True, as_image=True)
|
||||||
if img is None:
|
if img is None:
|
||||||
img = QImage()
|
img = QImage()
|
||||||
if not img.isNull():
|
if not img.isNull():
|
||||||
|
Loading…
x
Reference in New Issue
Block a user