version 0.3.106. Serialised conversion jobs. Fix export_to_dir.

This commit is contained in:
Kovid Goyal 2007-08-25 21:24:44 +00:00
parent a71d0dc341
commit b1f10f3059
5 changed files with 55 additions and 23 deletions

View File

@ -13,7 +13,7 @@
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
''' E-book management software''' ''' E-book management software'''
__version__ = "0.3.105" __version__ = "0.3.106"
__docformat__ = "epytext" __docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
__appname__ = 'libprs500' __appname__ = 'libprs500'

View File

@ -58,7 +58,7 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
self.setup_tooltips() self.setup_tooltips()
self.initialize_options() self.initialize_options()
self.db = db self.db = db
self.row = row.row() self.row = row
self.id = self.db.id(self.row) self.id = self.db.id(self.row)
self.cover_changed = False self.cover_changed = False
self.cpixmap = None self.cpixmap = None
@ -266,7 +266,13 @@ class LRFSingleDialog(QDialog, Ui_LRFSingleDialog):
au = qstring_to_unicode(self.gui_author.text()).split(',') au = qstring_to_unicode(self.gui_author.text()).split(',')
if au: self.db.set_authors(self.id, au) if au: self.db.set_authors(self.id, au)
aus = qstring_to_unicode(self.gui_author_sort.text()) aus = qstring_to_unicode(self.gui_author_sort.text())
if aus: self.db.set_author_sort(self.id, aus) if not aus:
t = self.db.authors(self.id, index_is_id=True)
if not t:
t = 'Unknown'
aus = t.split(',')[0].strip()
print aus
self.db.set_author_sort(self.id, aus)
self.db.set_publisher(self.id, qstring_to_unicode(self.gui_publisher.text())) self.db.set_publisher(self.id, qstring_to_unicode(self.gui_publisher.text()))
self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(',')) self.db.set_tags(self.id, qstring_to_unicode(self.tags.text()).split(','))
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText())) self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()))

View File

@ -12,7 +12,7 @@
## You should have received a copy of the GNU General Public License along ## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import traceback, textwrap, logging, cStringIO import traceback, logging, cStringIO
from PyQt4.QtCore import QAbstractTableModel, QMutex, QObject, SIGNAL, Qt, \ from PyQt4.QtCore import QAbstractTableModel, QMutex, QObject, SIGNAL, Qt, \
QVariant, QThread, QModelIndex QVariant, QThread, QModelIndex
@ -43,6 +43,7 @@ class Job(QThread):
self.percent_done = 0 self.percent_done = 0
self.logger = logging.getLogger('Job #'+str(id)) self.logger = logging.getLogger('Job #'+str(id))
self.logger.setLevel(logging.DEBUG) self.logger.setLevel(logging.DEBUG)
self.is_locked = False
self.log_dest = cStringIO.StringIO() self.log_dest = cStringIO.StringIO()
handler = logging.StreamHandler(self.log_dest) handler = logging.StreamHandler(self.log_dest)
handler.setLevel(logging.DEBUG) handler.setLevel(logging.DEBUG)
@ -50,6 +51,18 @@ class Job(QThread):
self.logger.addHandler(handler) self.logger.addHandler(handler)
def lock(self):
if self.mutex is not None:
self.is_locked = True
self.mutex.lock()
self.is_locked = False
def unlock(self):
if self.mutex is not None:
self.mutex.unlock()
self.is_locked = False
def progress_update(self, val): def progress_update(self, val):
self.percent_done = val self.percent_done = val
self.emit(SIGNAL('status_update(int, int)'), self.id, int(val)) self.emit(SIGNAL('status_update(int, int)'), self.id, int(val))
@ -59,8 +72,7 @@ class DeviceJob(Job):
Jobs that involve communication with the device. Synchronous. Jobs that involve communication with the device. Synchronous.
''' '''
def run(self): def run(self):
if self.mutex != None: self.lock()
self.mutex.lock()
last_traceback, exception = None, None last_traceback, exception = None, None
try: try:
try: try:
@ -69,15 +81,15 @@ class DeviceJob(Job):
exception = err exception = err
last_traceback = traceback.format_exc() last_traceback = traceback.format_exc()
finally: finally:
if self.mutex != None: self.unlock()
self.mutex.unlock()
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
self.id, self.description, self.result, exception, last_traceback) self.id, self.description, self.result, exception, last_traceback)
class ConversionJob(Job): class ConversionJob(Job):
''' Jobs that invlove conversion of content. Asynchronous. ''' ''' Jobs that invlove conversion of content. Synchronous. '''
def run(self): def run(self):
self.lock()
last_traceback, exception = None, None last_traceback, exception = None, None
try: try:
try: try:
@ -87,6 +99,7 @@ class ConversionJob(Job):
exception = err exception = err
last_traceback = traceback.format_exc() last_traceback = traceback.format_exc()
finally: finally:
self.unlock()
self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), self.emit(SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
self.id, self.description, self.result, exception, last_traceback, self.log_dest.getvalue()) self.id, self.description, self.result, exception, last_traceback, self.log_dest.getvalue())
@ -101,6 +114,7 @@ class JobManager(QAbstractTableModel):
self.job_create_lock = QMutex() self.job_create_lock = QMutex()
self.job_remove_lock = QMutex() self.job_remove_lock = QMutex()
self.device_lock = QMutex() self.device_lock = QMutex()
self.conversion_lock = QMutex()
self.cleanup_lock = QMutex() self.cleanup_lock = QMutex()
self.cleanup = {} self.cleanup = {}
self.device_job_icon = QVariant(QIcon(':/images/reader.svg')) self.device_job_icon = QVariant(QIcon(':/images/reader.svg'))
@ -143,8 +157,16 @@ class JobManager(QAbstractTableModel):
return len(self.jobs.values()) > 0 return len(self.jobs.values()) > 0
def run_conversion_job(self, slot, callable, *args, **kwargs): def run_conversion_job(self, slot, callable, *args, **kwargs):
'''
Run a conversion job.
@param slot: The function to call with the job result.
@param callable: The function to call to communicate with the device.
@param args: The arguments to pass to callable
@param kwargs: The keyword arguments to pass to callable
'''
desc = kwargs.pop('job_description', '') desc = kwargs.pop('job_description', '')
job = self.create_job(ConversionJob, desc, None, callable, *args, **kwargs) job = self.create_job(ConversionJob, desc, self.conversion_lock,
callable, *args, **kwargs)
QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'), QObject.connect(job, SIGNAL('jobdone(PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject, PyQt_PyObject)'),
self.job_done) self.job_done)
if slot: if slot:
@ -156,8 +178,7 @@ class JobManager(QAbstractTableModel):
def run_device_job(self, slot, callable, *args, **kwargs): def run_device_job(self, slot, callable, *args, **kwargs):
''' '''
Run a job to communicate with the device. Run a job to communicate with the device.
@param slot: The function to call with the job result. It is called with @param slot: The function to call with the job result.
the parameters id, result, exception, formatted_traceback
@param callable: The function to call to communicate with the device. @param callable: The function to call to communicate with the device.
@param args: The arguments to pass to callable @param args: The arguments to pass to callable
@param kwargs: The keyword arguments to pass to callable @param kwargs: The keyword arguments to pass to callable
@ -237,7 +258,7 @@ class JobManager(QAbstractTableModel):
return QVariant(job.description) return QVariant(job.description)
if col == 1: if col == 1:
status = 'Waiting' status = 'Waiting'
if job.isRunning(): if job.isRunning() and not job.is_locked:
status = 'Working' status = 'Working'
if job.isFinished(): if job.isFinished():
status = 'Done' status = 'Done'

View File

@ -536,14 +536,14 @@ class Main(QObject, Ui_MainWindow):
d.exec_() d.exec_()
changed = False changed = False
for row in rows: for row in [r.row() for r in rows]:
d = LRFSingleDialog(self.window, self.library_view.model().db, row) d = LRFSingleDialog(self.window, self.library_view.model().db, row)
if d.selected_format: if d.selected_format:
d.exec_() d.exec_()
if d.result() == QDialog.Accepted: if d.result() == QDialog.Accepted:
changed = True changed = True
cmdline = d.cmdline cmdline = d.cmdline
data = self.library_view.model().db.format(row.row(), d.selected_format) data = self.library_view.model().db.format(row, d.selected_format)
pt = PersistentTemporaryFile('.'+d.selected_format.lower()) pt = PersistentTemporaryFile('.'+d.selected_format.lower())
pt.write(data) pt.write(data)
pt.close() pt.close()
@ -551,6 +551,7 @@ class Main(QObject, Ui_MainWindow):
of.close() of.close()
cmdline.extend(['-o', of.name]) cmdline.extend(['-o', of.name])
cmdline.append(pt.name) cmdline.append(pt.name)
id = self.job_manager.run_conversion_job(self.book_converted, id = self.job_manager.run_conversion_job(self.book_converted,
any2lrf, args=cmdline, any2lrf, args=cmdline,
job_description='Convert book:'+d.title()) job_description='Convert book:'+d.title())
@ -642,8 +643,9 @@ class Main(QObject, Ui_MainWindow):
settings.setValue("size", QVariant(self.window.size())) settings.setValue("size", QVariant(self.window.size()))
settings.endGroup() settings.endGroup()
settings.beginGroup('Book Views') settings.beginGroup('Book Views')
for view in (self.library_view, self.memory_view): self.library_view.write_settings()
view.write_settings() if self.device_connected:
self.memory_view.write_settings()
settings.endGroup() settings.endGroup()
def close_event(self, e): def close_event(self, e):
@ -686,7 +688,7 @@ def main():
QCoreApplication.setApplicationName(APP_TITLE) QCoreApplication.setApplicationName(APP_TITLE)
initialize_file_icon_provider() initialize_file_icon_provider()
main = Main(window) main = Main(window)
sys.excepthook = main.unhandled_exception sys.excepthook = main.unhandled_exception
return app.exec_() return app.exec_()

View File

@ -694,9 +694,11 @@ class LibraryDatabase(object):
def title(self, index): def title(self, index):
return self.data[index][1] return self.data[index][1]
def authors(self, index): def authors(self, index, index_is_id=False):
''' Authors as a comman separated list or None''' ''' Authors as a comman separated list or None'''
return self.data[index][2] if not index_is_id:
return self.data[index][2]
return self.conn.execute('SELECT authors FROM meta WHERE id=?',(index,)).fetchone()[0]
def author_sort(self, index): def author_sort(self, index):
id = self.id(index) id = self.id(index)
@ -1002,13 +1004,14 @@ class LibraryDatabase(object):
au = self.conn.execute('SELECT author_sort FROM books WHERE id=?', au = self.conn.execute('SELECT author_sort FROM books WHERE id=?',
(id,)).fetchone()[0] (id,)).fetchone()[0]
if not au: if not au:
au = 'Unknown' au = self.authors(index)
if not au:
au = 'Unknown'
au = au.split(',')[0]
if not by_author.has_key(au): if not by_author.has_key(au):
by_author[au] = [] by_author[au] = []
by_author[au].append(index) by_author[au].append(index)
for au in by_author.keys(): for au in by_author.keys():
if not au:
au = 'Unknown'
apath = os.path.join(dir, au) apath = os.path.join(dir, au)
if not os.path.exists(apath): if not os.path.exists(apath):
os.mkdir(apath) os.mkdir(apath)