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

View File

@ -11,7 +11,7 @@ from calibre.utils.config import OptionParser
class FetchGoogle(Thread):
name = 'Google Books'
def __init__(self, title, author, publisher, isbn, verbose):
self.title = title
self.verbose = verbose
@ -21,17 +21,17 @@ class FetchGoogle(Thread):
Thread.__init__(self, None)
self.daemon = True
self.exception, self.tb = None, None
def run(self):
from calibre.ebooks.metadata.google_books import search
try:
self.results = search(self.title, self.author, self.publisher,
self.isbn, max_results=10,
self.results = search(self.title, self.author, self.publisher,
self.isbn, max_results=10,
verbose=self.verbose)
except Exception, e:
self.results = []
self.exception = e
self.tb = traceback.format_exc()
self.tb = traceback.format_exc()
class FetchISBNDB(Thread):
@ -46,19 +46,21 @@ class FetchISBNDB(Thread):
self.daemon = True
self.exception, self.tb = None, None
self.key = key
def run(self):
from calibre.ebooks.metadata.isbndb import option_parser, create_books
args = ['isbndb']
if self.isbn:
args.extend(['--isbn', self.isbn])
else:
else:
if self.title:
args.extend(['--title', self.title])
if self.author:
args.extend(['--author', self.author])
if self.publisher:
args.extend(['--publisher', self.publisher])
if self.verbose:
args.extend(['--verbose'])
args.append(self.key)
try:
opts, args = option_parser().parse_args(args)
@ -75,7 +77,7 @@ def result_index(source, result):
if x.isbn == result.isbn:
return i
return -1
def merge_results(one, two):
for x in two:
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)
fetchers = [FetchGoogle(title, author, publisher, isbn, verbose)]
if isbndb_key:
fetchers.append(FetchISBNDB(title, author, publisher, isbn, verbose,
fetchers.append(FetchISBNDB(title, author, publisher, isbn, verbose,
isbndb_key))
for fetcher in fetchers:
fetcher.start()
for fetcher in fetchers:
fetcher.join()
for fetcher in fetchers[1:]:
merge_results(fetchers[0].results, fetcher.results)
results = sorted(fetchers[0].results, cmp=lambda x, y : cmp(
(x.comments.strip() if x.comments else ''),
(y.comments.strip() if y.comments else '')
), reverse=True)
return results, [(x.name, x.exception, x.tb) for x in fetchers]
def option_parser():
parser = OptionParser(textwrap.dedent(
'''\
%prog [options]
Fetch book metadata from online sources. You must specify at least one
of title, author, publisher or ISBN. If you specify ISBN, the others
are ignored.
Fetch book metadata from online sources. You must specify at least one
of title, author, publisher or ISBN. If you specify ISBN, the others
are ignored.
'''
))
parser.add_option('-t', '--title', help='Book title')
parser.add_option('-a', '--author', help='Book author(s)')
parser.add_option('-p', '--publisher', help='Book publisher')
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')
parser.add_option('-k', '--isbndb-key',
parser.add_option('-k', '--isbndb-key',
help=('The access key for your ISBNDB.com account. '
'Only needed if you want to search isbndb.com'))
parser.add_option('-v', '--verbose', default=0, action='count',
@ -135,19 +137,19 @@ def option_parser():
def main(args=sys.argv):
parser = option_parser()
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)
for result in results:
print unicode(result).encode(preferred_encoding)
print
for name, exception, tb in exceptions:
if exception is not None:
print 'WARNING: Fetching from', name, 'failed with error:'
print exception
print tb
return 0
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__
class ProgressBarDelegate(QAbstractItemDelegate):
def sizeHint(self, option, index):
return QSize(120, 30)
def paint(self, painter, option, index):
opts = QStyleOptionProgressBarV2()
opts.rect = option.rect
@ -44,20 +44,23 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.jobs_view.model().kill_job)
self.pb_delegate = ProgressBarDelegate(self)
self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate)
self.running_time_timer = QTimer(self)
self.connect(self.running_time_timer, SIGNAL('timeout()'), self.update_running_time)
self.running_time_timer.start(1000)
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):
for index in self.jobs_view.selectedIndexes():
row = index.row()
self.model.kill_job(row, self)
return
def closeEvent(self, e):
self.jobs_view.write_settings()
e.accept()

View File

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