Fix error message in OSX when dragging and dropping a cover onto the edit metadata dialog

This commit is contained in:
Kovid Goyal 2009-03-25 12:55:42 -07:00
parent ff57c45613
commit 7448079aa8
4 changed files with 99 additions and 93 deletions

View File

@ -57,7 +57,7 @@ r'''
def _check_symlinks_prescript(): def _check_symlinks_prescript():
import os, tempfile, traceback, sys import os, tempfile, traceback, sys
from Authorization import Authorization, kAuthorizationFlagDestroyRights from Authorization import Authorization, kAuthorizationFlagDestroyRights
AUTHTOOL="""#!%(sp)s AUTHTOOL="""#!%(sp)s
import os import os
scripts = %(sp)s scripts = %(sp)s
@ -71,13 +71,13 @@ for s, l in zip(scripts, links):
os.symlink(s, l) os.symlink(s, l)
os.umask(omask) os.umask(omask)
""" """
dest_path = %(dest_path)s dest_path = %(dest_path)s
resources_path = os.environ['RESOURCEPATH'] resources_path = os.environ['RESOURCEPATH']
scripts = %(scripts)s scripts = %(scripts)s
links = [os.path.join(dest_path, i) for i in scripts] links = [os.path.join(dest_path, i) for i in scripts]
scripts = [os.path.join(resources_path, 'loaders', i) for i in scripts] scripts = [os.path.join(resources_path, 'loaders', i) for i in scripts]
bad = False bad = False
for s, l in zip(scripts, links): for s, l in zip(scripts, links):
if os.path.exists(l) and os.path.exists(os.path.realpath(l)): if os.path.exists(l) and os.path.exists(os.path.realpath(l)):
@ -111,22 +111,22 @@ _check_symlinks_prescript()
packages=self.packages, packages=self.packages,
excludes=self.excludes, excludes=self.excludes,
debug=debug) debug=debug)
@classmethod @classmethod
def makedmg(cls, d, volname, def makedmg(cls, d, volname,
destdir='dist', destdir='dist',
internet_enable=True, internet_enable=True,
format='UDBZ'): format='UDBZ'):
''' Copy a directory d into a dmg named volname ''' ''' Copy a directory d into a dmg named volname '''
dmg = os.path.join(destdir, volname+'.dmg') dmg = os.path.join(destdir, volname+'.dmg')
if os.path.exists(dmg): if os.path.exists(dmg):
os.unlink(dmg) os.unlink(dmg)
subprocess.check_call(['/usr/bin/hdiutil', 'create', '-srcfolder', os.path.abspath(d), subprocess.check_call(['/usr/bin/hdiutil', 'create', '-srcfolder', os.path.abspath(d),
'-volname', volname, '-format', format, dmg]) '-volname', volname, '-format', format, dmg])
if internet_enable: if internet_enable:
subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg]) subprocess.check_call(['/usr/bin/hdiutil', 'internet-enable', '-yes', dmg])
return dmg return dmg
@classmethod @classmethod
def qt_dependencies(cls, path): def qt_dependencies(cls, path):
pipe = subprocess.Popen('/usr/bin/otool -L '+path, shell=True, stdout=subprocess.PIPE).stdout pipe = subprocess.Popen('/usr/bin/otool -L '+path, shell=True, stdout=subprocess.PIPE).stdout
@ -134,12 +134,12 @@ _check_symlinks_prescript()
for l in pipe.readlines(): for l in pipe.readlines():
match = re.search(r'(.*)\(', l) match = re.search(r'(.*)\(', l)
if not match: if not match:
continue continue
lib = match.group(1).strip() lib = match.group(1).strip()
if lib.startswith(BuildAPP.QT_PREFIX): if lib.startswith(BuildAPP.QT_PREFIX):
deps.append(lib) deps.append(lib)
return deps return deps
@classmethod @classmethod
def fix_qt_dependencies(cls, path, deps): def fix_qt_dependencies(cls, path, deps):
fp = '@executable_path/../Frameworks/' fp = '@executable_path/../Frameworks/'
@ -155,8 +155,8 @@ _check_symlinks_prescript()
newpath = fp + '%s.framework/Versions/Current/%s'%(module, module) newpath = fp + '%s.framework/Versions/Current/%s'%(module, module)
cmd = ' '.join(['/usr/bin/install_name_tool', '-change', dep, newpath, path]) cmd = ' '.join(['/usr/bin/install_name_tool', '-change', dep, newpath, path])
subprocess.check_call(cmd, shell=True) subprocess.check_call(cmd, shell=True)
def add_qt_plugins(self): def add_qt_plugins(self):
macos_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'MacOS') macos_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'MacOS')
for root, dirs, files in os.walk(BuildAPP.QT_PREFIX+'/plugins'): for root, dirs, files in os.walk(BuildAPP.QT_PREFIX+'/plugins'):
@ -172,14 +172,14 @@ _check_symlinks_prescript()
shutil.copymode(path, target) shutil.copymode(path, target)
deps = BuildAPP.qt_dependencies(target) deps = BuildAPP.qt_dependencies(target)
BuildAPP.fix_qt_dependencies(target, deps) BuildAPP.fix_qt_dependencies(target, deps)
#deps = BuildAPP.qt_dependencies(path) #deps = BuildAPP.qt_dependencies(path)
def fix_python_dependencies(self, files): def fix_python_dependencies(self, files):
for f in files: for f in files:
subprocess.check_call(['/usr/bin/install_name_tool', '-change', '/Library/Frameworks/Python.framework/Versions/2.6/Python', '@executable_path/../Frameworks/Python.framework/Versions/2.6/Python', f]) subprocess.check_call(['/usr/bin/install_name_tool', '-change', '/Library/Frameworks/Python.framework/Versions/2.6/Python', '@executable_path/../Frameworks/Python.framework/Versions/2.6/Python', f])
def fix_misc_dependencies(self, files): def fix_misc_dependencies(self, files):
for path in files: for path in files:
frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks') frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks')
@ -195,15 +195,15 @@ _check_symlinks_prescript()
if os.path.exists(bundle): if os.path.exists(bundle):
subprocess.check_call(['/usr/bin/install_name_tool', '-change', dep, subprocess.check_call(['/usr/bin/install_name_tool', '-change', dep,
'@executable_path/../Frameworks/'+name, path]) '@executable_path/../Frameworks/'+name, path])
def add_plugins(self): def add_plugins(self):
self.add_qt_plugins() self.add_qt_plugins()
frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks') frameworks_dir = os.path.join(self.dist_dir, APPNAME + '.app', 'Contents', 'Frameworks')
plugins_dir = os.path.join(frameworks_dir, 'plugins') plugins_dir = os.path.join(frameworks_dir, 'plugins')
if not os.path.exists(plugins_dir): if not os.path.exists(plugins_dir):
os.mkdir(plugins_dir) os.mkdir(plugins_dir)
maps = {} maps = {}
for f in glob.glob('src/calibre/plugins/*'): for f in glob.glob('src/calibre/plugins/*'):
tgt = plugins_dir tgt = plugins_dir
@ -217,8 +217,8 @@ _check_symlinks_prescript()
deps.append(dst) deps.append(dst)
self.fix_python_dependencies(deps) self.fix_python_dependencies(deps)
self.fix_misc_dependencies(deps) self.fix_misc_dependencies(deps)
def run(self): def run(self):
py2app.run(self) py2app.run(self)
resource_dir = os.path.join(self.dist_dir, resource_dir = os.path.join(self.dist_dir,
@ -242,8 +242,8 @@ _check_symlinks_prescript()
os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\ os.chmod(path, stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH|stat.S_IREAD\
|stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP) |stat.S_IWUSR|stat.S_IROTH|stat.S_IRGRP)
self.add_plugins() self.add_plugins()
print print
print 'Adding pdftohtml' print 'Adding pdftohtml'
os.link(os.path.expanduser('~/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml')) os.link(os.path.expanduser('~/pdftohtml'), os.path.join(frameworks_dir, 'pdftohtml'))
@ -259,21 +259,21 @@ _check_symlinks_prescript()
if os.path.exists(dst): if os.path.exists(dst):
shutil.rmtree(dst) shutil.rmtree(dst)
shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False) shutil.copytree('/usr/local/etc/fonts', dst, symlinks=False)
print print
print 'Adding IPython' print 'Adding IPython'
dst = os.path.join(resource_dir, 'lib', 'python2.6', 'IPython') dst = os.path.join(resource_dir, 'lib', 'python2.6', 'IPython')
if os.path.exists(dst): shutil.rmtree(dst) if os.path.exists(dst): shutil.rmtree(dst)
shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), dst) shutil.copytree(os.path.expanduser('~/build/ipython/IPython'), dst)
print print
print 'Adding ImageMagick' print 'Adding ImageMagick'
dest = os.path.join(frameworks_dir, 'ImageMagick') dest = os.path.join(frameworks_dir, 'ImageMagick')
if os.path.exists(dest): if os.path.exists(dest):
sutil.rmtree(dest) shutil.rmtree(dest)
shutil.copytree(os.path.expanduser('~/ImageMagick'), dest, True) shutil.copytree(os.path.expanduser('~/ImageMagick'), dest, True)
shutil.copyfile('/usr/local/lib/libpng12.0.dylib', os.path.join(dest, 'lib', 'libpng12.0.dylib')) shutil.copyfile('/usr/local/lib/libpng12.0.dylib', os.path.join(dest, 'lib', 'libpng12.0.dylib'))
print print
print 'Installing prescipt' print 'Installing prescipt'
sf = [os.path.basename(s) for s in all_names] sf = [os.path.basename(s) for s in all_names]
@ -293,13 +293,13 @@ sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), '
print >>f, 'import sys, os' print >>f, 'import sys, os'
f.write(src) f.write(src)
f.close() f.close()
print print
print 'Adding main scripts to site-packages' print 'Adding main scripts to site-packages'
f = zipfile.ZipFile(os.path.join(self.dist_dir, APPNAME+'.app', 'Contents', 'Resources', 'lib', 'python'+sys.version[:3], 'site-packages.zip'), 'a', zipfile.ZIP_DEFLATED) f = zipfile.ZipFile(os.path.join(self.dist_dir, APPNAME+'.app', 'Contents', 'Resources', 'lib', 'python'+sys.version[:3], 'site-packages.zip'), 'a', zipfile.ZIP_DEFLATED)
for script in scripts['gui']+scripts['console']: for script in scripts['gui']+scripts['console']:
f.write(script, script.partition('/')[-1]) f.write(script, script.partition('/')[-1])
f.close() f.close()
print print
print 'Creating console.app' print 'Creating console.app'
contents_dir = os.path.dirname(resource_dir) contents_dir = os.path.dirname(resource_dir)
cc_dir = os.path.join(contents_dir, 'console.app', 'Contents') cc_dir = os.path.join(contents_dir, 'console.app', 'Contents')
@ -312,7 +312,7 @@ sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), '
plist['LSUIElement'] = '1' plist['LSUIElement'] = '1'
plistlib.writePlist(plist, os.path.join(cc_dir, x)) plistlib.writePlist(plist, os.path.join(cc_dir, x))
else: else:
os.symlink(os.path.join('../..', x), os.symlink(os.path.join('../..', x),
os.path.join(cc_dir, x)) os.path.join(cc_dir, x))
print print
print 'Building disk image' print 'Building disk image'
@ -343,9 +343,10 @@ def main():
'calibre.ebooks.lrf.any.*', 'calibre.ebooks.lrf.feeds.*', 'calibre.ebooks.lrf.any.*', 'calibre.ebooks.lrf.feeds.*',
'keyword', 'codeop', 'pydoc', 'readline', 'keyword', 'codeop', 'pydoc', 'readline',
'BeautifulSoup', 'calibre.ebooks.lrf.fonts.prs500.*', 'BeautifulSoup', 'calibre.ebooks.lrf.fonts.prs500.*',
'dateutil', 'dateutil', 'email.iterators',
'email.generator',
], ],
'packages' : ['PIL', 'Authorization', 'lxml'], 'packages' : ['PIL', 'Authorization', 'lxml', 'dns'],
'excludes' : ['IPython'], 'excludes' : ['IPython'],
'plist' : { 'CFBundleGetInfoString' : '''calibre, an E-book management application.''' 'plist' : { 'CFBundleGetInfoString' : '''calibre, an E-book management application.'''
''' Visit http://calibre.kovidgoyal.net for details.''', ''' Visit http://calibre.kovidgoyal.net for details.''',

View File

@ -11,7 +11,7 @@ from calibre.utils.config import OptionParser
class FetchGoogle(Thread): class FetchGoogle(Thread):
name = 'Google Books' name = 'Google Books'
def __init__(self, title, author, publisher, isbn, verbose): def __init__(self, title, author, publisher, isbn, verbose):
self.title = title self.title = title
self.verbose = verbose self.verbose = verbose
@ -21,17 +21,17 @@ class FetchGoogle(Thread):
Thread.__init__(self, None) Thread.__init__(self, None)
self.daemon = True self.daemon = True
self.exception, self.tb = None, None self.exception, self.tb = None, None
def run(self): def run(self):
from calibre.ebooks.metadata.google_books import search from calibre.ebooks.metadata.google_books import search
try: try:
self.results = search(self.title, self.author, self.publisher, self.results = search(self.title, self.author, self.publisher,
self.isbn, max_results=10, self.isbn, max_results=10,
verbose=self.verbose) verbose=self.verbose)
except Exception, e: except Exception, e:
self.results = [] self.results = []
self.exception = e self.exception = e
self.tb = traceback.format_exc() self.tb = traceback.format_exc()
class FetchISBNDB(Thread): class FetchISBNDB(Thread):
@ -46,19 +46,21 @@ class FetchISBNDB(Thread):
self.daemon = True self.daemon = True
self.exception, self.tb = None, None self.exception, self.tb = None, None
self.key = key self.key = key
def run(self): def run(self):
from calibre.ebooks.metadata.isbndb import option_parser, create_books from calibre.ebooks.metadata.isbndb import option_parser, create_books
args = ['isbndb'] args = ['isbndb']
if self.isbn: if self.isbn:
args.extend(['--isbn', self.isbn]) args.extend(['--isbn', self.isbn])
else: else:
if self.title: if self.title:
args.extend(['--title', self.title]) args.extend(['--title', self.title])
if self.author: if self.author:
args.extend(['--author', self.author]) args.extend(['--author', self.author])
if self.publisher: if self.publisher:
args.extend(['--publisher', self.publisher]) args.extend(['--publisher', self.publisher])
if self.verbose:
args.extend(['--verbose'])
args.append(self.key) args.append(self.key)
try: try:
opts, args = option_parser().parse_args(args) opts, args = option_parser().parse_args(args)
@ -75,7 +77,7 @@ def result_index(source, result):
if x.isbn == result.isbn: if x.isbn == result.isbn:
return i return i
return -1 return -1
def merge_results(one, two): def merge_results(one, two):
for x in two: for x in two:
idx = result_index(one, x) idx = result_index(one, x)
@ -90,42 +92,42 @@ def search(title=None, author=None, publisher=None, isbn=None, isbndb_key=None,
isbn is None) isbn is None)
fetchers = [FetchGoogle(title, author, publisher, isbn, verbose)] fetchers = [FetchGoogle(title, author, publisher, isbn, verbose)]
if isbndb_key: if isbndb_key:
fetchers.append(FetchISBNDB(title, author, publisher, isbn, verbose, fetchers.append(FetchISBNDB(title, author, publisher, isbn, verbose,
isbndb_key)) isbndb_key))
for fetcher in fetchers: for fetcher in fetchers:
fetcher.start() fetcher.start()
for fetcher in fetchers: for fetcher in fetchers:
fetcher.join() fetcher.join()
for fetcher in fetchers[1:]: for fetcher in fetchers[1:]:
merge_results(fetchers[0].results, fetcher.results) merge_results(fetchers[0].results, fetcher.results)
results = sorted(fetchers[0].results, cmp=lambda x, y : cmp( results = sorted(fetchers[0].results, cmp=lambda x, y : cmp(
(x.comments.strip() if x.comments else ''), (x.comments.strip() if x.comments else ''),
(y.comments.strip() if y.comments else '') (y.comments.strip() if y.comments else '')
), reverse=True) ), reverse=True)
return results, [(x.name, x.exception, x.tb) for x in fetchers] return results, [(x.name, x.exception, x.tb) for x in fetchers]
def option_parser(): def option_parser():
parser = OptionParser(textwrap.dedent( parser = OptionParser(textwrap.dedent(
'''\ '''\
%prog [options] %prog [options]
Fetch book metadata from online sources. You must specify at least one Fetch book metadata from online sources. You must specify at least one
of title, author, publisher or ISBN. If you specify ISBN, the others of title, author, publisher or ISBN. If you specify ISBN, the others
are ignored. are ignored.
''' '''
)) ))
parser.add_option('-t', '--title', help='Book title') parser.add_option('-t', '--title', help='Book title')
parser.add_option('-a', '--author', help='Book author(s)') parser.add_option('-a', '--author', help='Book author(s)')
parser.add_option('-p', '--publisher', help='Book publisher') parser.add_option('-p', '--publisher', help='Book publisher')
parser.add_option('-i', '--isbn', help='Book ISBN') parser.add_option('-i', '--isbn', help='Book ISBN')
parser.add_option('-m', '--max-results', default=10, parser.add_option('-m', '--max-results', default=10,
help='Maximum number of results to fetch') help='Maximum number of results to fetch')
parser.add_option('-k', '--isbndb-key', parser.add_option('-k', '--isbndb-key',
help=('The access key for your ISBNDB.com account. ' help=('The access key for your ISBNDB.com account. '
'Only needed if you want to search isbndb.com')) 'Only needed if you want to search isbndb.com'))
parser.add_option('-v', '--verbose', default=0, action='count', parser.add_option('-v', '--verbose', default=0, action='count',
@ -135,19 +137,19 @@ def option_parser():
def main(args=sys.argv): def main(args=sys.argv):
parser = option_parser() parser = option_parser()
opts, args = parser.parse_args(args) opts, args = parser.parse_args(args)
results, exceptions = search(opts.title, opts.author, opts.publisher, results, exceptions = search(opts.title, opts.author, opts.publisher,
opts.isbn, opts.isbndb_key, opts.verbose) opts.isbn, opts.isbndb_key, opts.verbose)
for result in results: for result in results:
print unicode(result).encode(preferred_encoding) print unicode(result).encode(preferred_encoding)
print print
for name, exception, tb in exceptions: for name, exception, tb in exceptions:
if exception is not None: if exception is not None:
print 'WARNING: Fetching from', name, 'failed with error:' print 'WARNING: Fetching from', name, 'failed with error:'
print exception print exception
print tb print tb
return 0 return 0
if __name__ == '__main__': if __name__ == '__main__':
sys.exit(main()) sys.exit(main())

View File

@ -10,10 +10,10 @@ from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
from calibre import __appname__ from calibre import __appname__
class ProgressBarDelegate(QAbstractItemDelegate): class ProgressBarDelegate(QAbstractItemDelegate):
def sizeHint(self, option, index): def sizeHint(self, option, index):
return QSize(120, 30) return QSize(120, 30)
def paint(self, painter, option, index): def paint(self, painter, option, index):
opts = QStyleOptionProgressBarV2() opts = QStyleOptionProgressBarV2()
opts.rect = option.rect opts.rect = option.rect
@ -44,20 +44,23 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.jobs_view.model().kill_job) self.jobs_view.model().kill_job)
self.pb_delegate = ProgressBarDelegate(self) self.pb_delegate = ProgressBarDelegate(self)
self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate) self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate)
self.running_time_timer = QTimer(self) self.running_time_timer = QTimer(self)
self.connect(self.running_time_timer, SIGNAL('timeout()'), self.update_running_time) self.connect(self.running_time_timer, SIGNAL('timeout()'), self.update_running_time)
self.running_time_timer.start(1000) self.running_time_timer.start(1000)
def update_running_time(self, *args): def update_running_time(self, *args):
self.model.running_time_updated() try:
self.model.running_time_updated()
except: # Raises random exceptions on OS X
pass
def kill_job(self): def kill_job(self):
for index in self.jobs_view.selectedIndexes(): for index in self.jobs_view.selectedIndexes():
row = index.row() row = index.row()
self.model.kill_job(row, self) self.model.kill_job(row, self)
return return
def closeEvent(self, e): def closeEvent(self, e):
self.jobs_view.write_settings() self.jobs_view.write_settings()
e.accept() e.accept()

View File

@ -18,27 +18,27 @@ from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
NONE = QVariant() NONE = QVariant()
class JobManager(QAbstractTableModel): class JobManager(QAbstractTableModel):
def __init__(self): def __init__(self):
QAbstractTableModel.__init__(self) QAbstractTableModel.__init__(self)
self.wait_icon = QVariant(QIcon(':/images/jobs.svg')) self.wait_icon = QVariant(QIcon(':/images/jobs.svg'))
self.running_icon = QVariant(QIcon(':/images/exec.svg')) self.running_icon = QVariant(QIcon(':/images/exec.svg'))
self.error_icon = QVariant(QIcon(':/images/dialog_error.svg')) self.error_icon = QVariant(QIcon(':/images/dialog_error.svg'))
self.done_icon = QVariant(QIcon(':/images/ok.svg')) self.done_icon = QVariant(QIcon(':/images/ok.svg'))
self.jobs = [] self.jobs = []
self.server = Server() self.server = Server()
self.add_job = Dispatcher(self._add_job) self.add_job = Dispatcher(self._add_job)
self.status_update = Dispatcher(self._status_update) self.status_update = Dispatcher(self._status_update)
self.start_work = Dispatcher(self._start_work) self.start_work = Dispatcher(self._start_work)
self.job_done = Dispatcher(self._job_done) self.job_done = Dispatcher(self._job_done)
def columnCount(self, parent=QModelIndex()): def columnCount(self, parent=QModelIndex()):
return 4 return 4
def rowCount(self, parent=QModelIndex()): def rowCount(self, parent=QModelIndex()):
return len(self.jobs) return len(self.jobs)
def headerData(self, section, orientation, role): def headerData(self, section, orientation, role):
if role != Qt.DisplayRole: if role != Qt.DisplayRole:
return NONE return NONE
@ -50,14 +50,14 @@ class JobManager(QAbstractTableModel):
return QVariant(text) return QVariant(text)
else: else:
return QVariant(section+1) return QVariant(section+1)
def data(self, index, role): def data(self, index, role):
try: try:
if role not in (Qt.DisplayRole, Qt.DecorationRole): if role not in (Qt.DisplayRole, Qt.DecorationRole):
return NONE return NONE
row, col = index.row(), index.column() row, col = index.row(), index.column()
job = self.jobs[row] job = self.jobs[row]
if role == Qt.DisplayRole: if role == Qt.DisplayRole:
if col == 0: if col == 0:
desc = job.description desc = job.description
@ -102,31 +102,31 @@ class JobManager(QAbstractTableModel):
import traceback import traceback
traceback.print_exc() traceback.print_exc()
return NONE return NONE
def _add_job(self, job): def _add_job(self, job):
self.emit(SIGNAL('layoutAboutToBeChanged()')) self.emit(SIGNAL('layoutAboutToBeChanged()'))
self.jobs.append(job) self.jobs.append(job)
self.jobs.sort() self.jobs.sort()
self.emit(SIGNAL('job_added(int)'), self.rowCount()) self.emit(SIGNAL('job_added(int)'), self.rowCount())
self.emit(SIGNAL('layoutChanged()')) self.emit(SIGNAL('layoutChanged()'))
def done_jobs(self): def done_jobs(self):
return [j for j in self.jobs if j.status() in ['DONE', 'ERROR']] return [j for j in self.jobs if j.status() in ['DONE', 'ERROR']]
def row_to_job(self, row): def row_to_job(self, row):
return self.jobs[row] return self.jobs[row]
def _start_work(self, job): def _start_work(self, job):
self.emit(SIGNAL('layoutAboutToBeChanged()')) self.emit(SIGNAL('layoutAboutToBeChanged()'))
self.jobs.sort() self.jobs.sort()
self.emit(SIGNAL('layoutChanged()')) self.emit(SIGNAL('layoutChanged()'))
def _job_done(self, job): def _job_done(self, job):
self.emit(SIGNAL('layoutAboutToBeChanged()')) self.emit(SIGNAL('layoutAboutToBeChanged()'))
self.jobs.sort() self.jobs.sort()
self.emit(SIGNAL('job_done(int)'), len(self.jobs) - len(self.done_jobs())) self.emit(SIGNAL('job_done(int)'), len(self.jobs) - len(self.done_jobs()))
self.emit(SIGNAL('layoutChanged()')) self.emit(SIGNAL('layoutChanged()'))
def _status_update(self, job): def _status_update(self, job):
try: try:
row = self.jobs.index(job) row = self.jobs.index(job)
@ -134,38 +134,38 @@ class JobManager(QAbstractTableModel):
return return
self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'),
self.index(row, 0), self.index(row, 3)) self.index(row, 0), self.index(row, 3))
def running_time_updated(self): def running_time_updated(self, *args):
for job in self.jobs: for job in self.jobs:
if not job.is_running: if not job.is_running:
continue continue
row = self.jobs.index(job) row = self.jobs.index(job)
self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'),
self.index(row, 3), self.index(row, 3)) self.index(row, 3), self.index(row, 3))
def has_device_jobs(self): def has_device_jobs(self):
for job in self.jobs: for job in self.jobs:
if job.is_running and isinstance(job, DeviceJob): if job.is_running and isinstance(job, DeviceJob):
return True return True
return False return False
def has_jobs(self): def has_jobs(self):
for job in self.jobs: for job in self.jobs:
if job.is_running: if job.is_running:
return True return True
return False return False
def run_job(self, done, func, args=[], kwargs={}, def run_job(self, done, func, args=[], kwargs={},
description=None): description=None):
job = ParallelJob(func, done, self, args=args, kwargs=kwargs, job = ParallelJob(func, done, self, args=args, kwargs=kwargs,
description=description) description=description)
self.server.add_job(job) self.server.add_job(job)
return job return job
def output(self, job): def output(self, job):
self.emit(SIGNAL('output_received()')) self.emit(SIGNAL('output_received()'))
def kill_job(self, row, view): def kill_job(self, row, view):
job = self.jobs[row] job = self.jobs[row]
if isinstance(job, DeviceJob): if isinstance(job, DeviceJob):
@ -183,20 +183,20 @@ class JobManager(QAbstractTableModel):
self.server.kill(job) self.server.kill(job)
def terminate_all_jobs(self): def terminate_all_jobs(self):
pass pass
class DetailView(QDialog, Ui_Dialog): class DetailView(QDialog, Ui_Dialog):
def __init__(self, parent, job): def __init__(self, parent, job):
QDialog.__init__(self, parent) QDialog.__init__(self, parent)
self.setupUi(self) self.setupUi(self)
self.setWindowTitle(job.description) self.setWindowTitle(job.description)
self.job = job self.job = job
self.update() self.update()
def update(self): def update(self):
self.log.setPlainText(self.job.console_text()) self.log.setPlainText(self.job.console_text())
vbar = self.log.verticalScrollBar() vbar = self.log.verticalScrollBar()