mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Merge upstream changes
This commit is contained in:
commit
3b5b9f1849
@ -3,7 +3,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
''' Create an OSX installer '''
|
''' Create an OSX installer '''
|
||||||
|
|
||||||
import sys, re, os, shutil, subprocess, stat, glob, zipfile
|
import sys, re, os, shutil, subprocess, stat, glob, zipfile, plistlib
|
||||||
l = {}
|
l = {}
|
||||||
exec open('setup.py').read() in l
|
exec open('setup.py').read() in l
|
||||||
VERSION = l['VERSION']
|
VERSION = l['VERSION']
|
||||||
@ -36,7 +36,7 @@ loader = open(loader_path, 'w')
|
|||||||
site_packages = glob.glob(resources_dir+'/lib/python*/site-packages.zip')[0]
|
site_packages = glob.glob(resources_dir+'/lib/python*/site-packages.zip')[0]
|
||||||
print >>loader, '#!'+python
|
print >>loader, '#!'+python
|
||||||
print >>loader, 'import sys'
|
print >>loader, 'import sys'
|
||||||
print >>loader, 'sys.path.remove('+repr(dirpath)+')'
|
print >>loader, 'if', repr(dirpath), 'in sys.path: sys.path.remove(', repr(dirpath), ')'
|
||||||
print >>loader, 'sys.path.append(', repr(site_packages), ')'
|
print >>loader, 'sys.path.append(', repr(site_packages), ')'
|
||||||
print >>loader, 'sys.frozen = "macosx_app"'
|
print >>loader, 'sys.frozen = "macosx_app"'
|
||||||
print >>loader, 'sys.frameworks_dir =', repr(frameworks_dir)
|
print >>loader, 'sys.frameworks_dir =', repr(frameworks_dir)
|
||||||
@ -294,11 +294,26 @@ sys.frameworks_dir = os.path.join(os.path.dirname(os.environ['RESOURCEPATH']), '
|
|||||||
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', 'python2.6', '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'
|
||||||
|
contents_dir = os.path.dirname(resource_dir)
|
||||||
|
cc_dir = os.path.join(contents_dir, 'console.app', 'Contents')
|
||||||
|
os.makedirs(cc_dir)
|
||||||
|
for x in os.listdir(contents_dir):
|
||||||
|
if x == 'console.app':
|
||||||
|
continue
|
||||||
|
if x == 'Info.plist':
|
||||||
|
plist = plistlib.readPlist(os.path.join(contents_dir, x))
|
||||||
|
plist['LSUIElement'] = '1'
|
||||||
|
plistlib.writePlist(plist, os.path.join(cc_dir, x))
|
||||||
|
else:
|
||||||
|
os.symlink(os.path.join('../..', x),
|
||||||
|
os.path.join(cc_dir, x))
|
||||||
|
print
|
||||||
print 'Building disk image'
|
print 'Building disk image'
|
||||||
BuildAPP.makedmg(os.path.join(self.dist_dir, APPNAME+'.app'), APPNAME+'-'+VERSION)
|
BuildAPP.makedmg(os.path.join(self.dist_dir, APPNAME+'.app'), APPNAME+'-'+VERSION)
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ Run an embedded python interpreter.
|
|||||||
'Module specifications are of the form full.name.of.module,path_to_module.py', default=None
|
'Module specifications are of the form full.name.of.module,path_to_module.py', default=None
|
||||||
)
|
)
|
||||||
parser.add_option('-c', '--command', help='Run python code.', default=None)
|
parser.add_option('-c', '--command', help='Run python code.', default=None)
|
||||||
|
parser.add_option('-e', '--exec-file', default=None, help='Run the python code in file.')
|
||||||
parser.add_option('-g', '--gui', default=False, action='store_true',
|
parser.add_option('-g', '--gui', default=False, action='store_true',
|
||||||
help='Run the GUI',)
|
help='Run the GUI',)
|
||||||
parser.add_option('--migrate', action='store_true', default=False,
|
parser.add_option('--migrate', action='store_true', default=False,
|
||||||
@ -87,6 +88,9 @@ def main(args=sys.argv):
|
|||||||
elif opts.command:
|
elif opts.command:
|
||||||
sys.argv = args[:1]
|
sys.argv = args[:1]
|
||||||
exec opts.command
|
exec opts.command
|
||||||
|
elif opts.exec_file:
|
||||||
|
sys.argv = args[:1]
|
||||||
|
execfile(opts.exec_file)
|
||||||
elif opts.migrate:
|
elif opts.migrate:
|
||||||
if len(args) < 3:
|
if len(args) < 3:
|
||||||
print 'You must specify the path to library1.db and the path to the new library folder'
|
print 'You must specify the path to library1.db and the path to the new library folder'
|
||||||
|
@ -194,6 +194,8 @@ class HTMLProcessor(Processor, Rationalizer):
|
|||||||
if not tag.text and not tag.get('src', False):
|
if not tag.text and not tag.get('src', False):
|
||||||
tag.getparent().remove(tag)
|
tag.getparent().remove(tag)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
for meta in list(self.root.xpath('//meta')):
|
for meta in list(self.root.xpath('//meta')):
|
||||||
meta.getparent().remove(meta)
|
meta.getparent().remove(meta)
|
||||||
|
@ -417,39 +417,44 @@ class Parser(PreProcessor, LoggingInterface):
|
|||||||
self.level = self.htmlfile.level
|
self.level = self.htmlfile.level
|
||||||
for f in self.htmlfiles:
|
for f in self.htmlfiles:
|
||||||
name = os.path.basename(f.path)
|
name = os.path.basename(f.path)
|
||||||
|
name = os.path.splitext(name)[0] + '.xhtml'
|
||||||
if name in self.htmlfile_map.values():
|
if name in self.htmlfile_map.values():
|
||||||
name = os.path.splitext(name)[0] + '_cr_%d'%save_counter + os.path.splitext(name)[1]
|
name = os.path.splitext(name)[0] + '_cr_%d'%save_counter + os.path.splitext(name)[1]
|
||||||
save_counter += 1
|
save_counter += 1
|
||||||
self.htmlfile_map[f.path] = name
|
self.htmlfile_map[f.path] = name
|
||||||
|
|
||||||
self.parse_html()
|
self.parse_html()
|
||||||
|
# Handle <image> tags inside embedded <svg>
|
||||||
|
# At least one source of EPUB files (Penguin) uses xlink:href
|
||||||
|
# without declaring the xlink namespace
|
||||||
|
for image in self.root.xpath('//image'):
|
||||||
|
for attr in image.attrib.keys():
|
||||||
|
if attr.endswith(':href'):
|
||||||
|
nhref = self.rewrite_links(image.get(attr))
|
||||||
|
image.set(attr, nhref)
|
||||||
|
|
||||||
self.root.rewrite_links(self.rewrite_links, resolve_base_href=False)
|
self.root.rewrite_links(self.rewrite_links, resolve_base_href=False)
|
||||||
for bad in ('xmlns', 'lang', 'xml:lang'): # lxml also adds these attributes for XHTML documents, leading to duplicates
|
for bad in ('xmlns', 'lang', 'xml:lang'): # lxml also adds these attributes for XHTML documents, leading to duplicates
|
||||||
if self.root.get(bad, None) is not None:
|
if self.root.get(bad, None) is not None:
|
||||||
self.root.attrib.pop(bad)
|
self.root.attrib.pop(bad)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def save_path(self):
|
def save_path(self):
|
||||||
return os.path.join(self.tdir, self.htmlfile_map[self.htmlfile.path])
|
return os.path.join(self.tdir, self.htmlfile_map[self.htmlfile.path])
|
||||||
|
|
||||||
def declare_xhtml_namespace(self, match):
|
|
||||||
if not match.group('raw'):
|
|
||||||
return '<html xmlns="http://www.w3.org/1999/xhtml">'
|
|
||||||
raw = match.group('raw')
|
|
||||||
m = re.search(r'(?i)xmlns\s*=\s*[\'"](?P<uri>[^"\']*)[\'"]', raw)
|
|
||||||
if not m:
|
|
||||||
return '<html xmlns="http://www.w3.org/1999/xhtml" %s>'%raw
|
|
||||||
else:
|
|
||||||
return match.group().replace(m.group('uri'), "http://www.w3.org/1999/xhtml")
|
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
'''
|
'''
|
||||||
Save processed HTML into the content directory.
|
Save processed HTML into the content directory.
|
||||||
Should be called after all HTML processing is finished.
|
Should be called after all HTML processing is finished.
|
||||||
'''
|
'''
|
||||||
ans = tostring(self.root, pretty_print=self.opts.pretty_print)
|
self.root.set('xmlns', 'http://www.w3.org/1999/xhtml')
|
||||||
ans = re.sub(r'(?i)<\s*html(?P<raw>\s+[^>]*){0,1}>', self.declare_xhtml_namespace, ans[:1000]) + ans[1000:]
|
self.root.set('xmlns:xlink', 'http://www.w3.org/1999/xlink')
|
||||||
ans = re.compile(r'<head>', re.IGNORECASE).sub('<head>\n\t<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n', ans[:1000])+ans[1000:]
|
for svg in self.root.xpath('//svg'):
|
||||||
|
svg.set('xmlns', 'http://www.w3.org/2000/svg')
|
||||||
|
|
||||||
|
ans = tostring(self.root, pretty_print=self.opts.pretty_print)
|
||||||
|
ans = re.compile(r'<head>', re.IGNORECASE).sub('<head>\n\t<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />\n', ans[:1000])+ans[1000:]
|
||||||
with open(self.save_path(), 'wb') as f:
|
with open(self.save_path(), 'wb') as f:
|
||||||
f.write(ans)
|
f.write(ans)
|
||||||
return f.name
|
return f.name
|
||||||
|
@ -46,9 +46,10 @@ class SVGRasterizer(object):
|
|||||||
data = QByteArray(xml2str(elem))
|
data = QByteArray(xml2str(elem))
|
||||||
svg = QSvgRenderer(data)
|
svg = QSvgRenderer(data)
|
||||||
size = svg.defaultSize()
|
size = svg.defaultSize()
|
||||||
|
view_box = elem.get('viewBox', elem.get('viewbox', None))
|
||||||
if size.width() == 100 and size.height() == 100 \
|
if size.width() == 100 and size.height() == 100 \
|
||||||
and 'viewBox' in elem.attrib:
|
and view_box is not None:
|
||||||
box = [float(x) for x in elem.attrib['viewBox'].split()]
|
box = [float(x) for x in view_box.split()]
|
||||||
size.setWidth(box[2] - box[0])
|
size.setWidth(box[2] - box[0])
|
||||||
size.setHeight(box[3] - box[1])
|
size.setHeight(box[3] - box[1])
|
||||||
if width or height:
|
if width or height:
|
||||||
|
@ -63,7 +63,8 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
p.end()
|
p.end()
|
||||||
self.default_thumbnail = (pixmap.width(), pixmap.height(), pixmap_to_data(pixmap))
|
self.default_thumbnail = (pixmap.width(), pixmap.height(), pixmap_to_data(pixmap))
|
||||||
|
|
||||||
def __init__(self, single_instance, opts, parent=None):
|
def __init__(self, single_instance, opts, actions, parent=None):
|
||||||
|
self.preferences_action, self.quit_action = actions
|
||||||
MainWindow.__init__(self, opts, parent)
|
MainWindow.__init__(self, opts, parent)
|
||||||
# Initialize fontconfig in a separate thread as this can be a lengthy
|
# Initialize fontconfig in a separate thread as this can be a lengthy
|
||||||
# process if run for the first time on this machine
|
# process if run for the first time on this machine
|
||||||
@ -100,7 +101,6 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.system_tray_menu = QMenu()
|
self.system_tray_menu = QMenu()
|
||||||
self.restore_action = self.system_tray_menu.addAction(QIcon(':/images/page.svg'), _('&Restore'))
|
self.restore_action = self.system_tray_menu.addAction(QIcon(':/images/page.svg'), _('&Restore'))
|
||||||
self.donate_action = self.system_tray_menu.addAction(QIcon(':/images/donate.svg'), _('&Donate'))
|
self.donate_action = self.system_tray_menu.addAction(QIcon(':/images/donate.svg'), _('&Donate'))
|
||||||
self.quit_action = QAction(QIcon(':/images/window-close.svg'), _('&Quit'), self)
|
|
||||||
self.addAction(self.quit_action)
|
self.addAction(self.quit_action)
|
||||||
self.action_restart = QAction(_('&Restart'), self)
|
self.action_restart = QAction(_('&Restart'), self)
|
||||||
self.addAction(self.action_restart)
|
self.addAction(self.action_restart)
|
||||||
@ -242,6 +242,7 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
|
self.tool_bar.setContextMenuPolicy(Qt.PreventContextMenu)
|
||||||
|
|
||||||
QObject.connect(self.config_button, SIGNAL('clicked(bool)'), self.do_config)
|
QObject.connect(self.config_button, SIGNAL('clicked(bool)'), self.do_config)
|
||||||
|
self.connect(self.preferences_action, SIGNAL('triggered(bool)'), self.do_config)
|
||||||
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'), self.do_advanced_search)
|
QObject.connect(self.advanced_search_button, SIGNAL('clicked(bool)'), self.do_advanced_search)
|
||||||
|
|
||||||
####################### Library view ########################
|
####################### Library view ########################
|
||||||
@ -1547,6 +1548,7 @@ def main(args=sys.argv):
|
|||||||
prefs.set('library_path', opts.with_library)
|
prefs.set('library_path', opts.with_library)
|
||||||
print 'Using library at', prefs['library_path']
|
print 'Using library at', prefs['library_path']
|
||||||
app = Application(args)
|
app = Application(args)
|
||||||
|
actions = tuple(Main.create_application_menubar())
|
||||||
app.setWindowIcon(QIcon(':/library'))
|
app.setWindowIcon(QIcon(':/library'))
|
||||||
QCoreApplication.setOrganizationName(ORG_NAME)
|
QCoreApplication.setOrganizationName(ORG_NAME)
|
||||||
QCoreApplication.setApplicationName(APP_UID)
|
QCoreApplication.setApplicationName(APP_UID)
|
||||||
@ -1561,7 +1563,7 @@ def main(args=sys.argv):
|
|||||||
'<p>%s is already running. %s</p>'%(__appname__, extra))
|
'<p>%s is already running. %s</p>'%(__appname__, extra))
|
||||||
return 1
|
return 1
|
||||||
initialize_file_icon_provider()
|
initialize_file_icon_provider()
|
||||||
main = Main(single_instance, opts)
|
main = Main(single_instance, opts, actions)
|
||||||
sys.excepthook = main.unhandled_exception
|
sys.excepthook = main.unhandled_exception
|
||||||
if len(args) > 1:
|
if len(args) > 1:
|
||||||
main.add_filesystem_book(args[1])
|
main.add_filesystem_book(args[1])
|
||||||
|
@ -3,7 +3,8 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
|
|
||||||
import StringIO, traceback, sys
|
import StringIO, traceback, sys
|
||||||
|
|
||||||
from PyQt4.Qt import QMainWindow, QString, Qt, QFont, QCoreApplication, SIGNAL
|
from PyQt4.Qt import QMainWindow, QString, Qt, QFont, QCoreApplication, SIGNAL,\
|
||||||
|
QAction, QMenu, QMenuBar, QIcon
|
||||||
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
|
from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
|
||||||
from calibre.utils.config import OptionParser
|
from calibre.utils.config import OptionParser
|
||||||
|
|
||||||
@ -34,6 +35,27 @@ class DebugWindow(ConversionErrorDialog):
|
|||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
|
|
||||||
|
_menu_bar = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_application_menubar(cls):
|
||||||
|
mb = QMenuBar(None)
|
||||||
|
menu = QMenu()
|
||||||
|
for action in cls.get_menubar_actions():
|
||||||
|
menu.addAction(action)
|
||||||
|
yield action
|
||||||
|
mb.addMenu(menu)
|
||||||
|
cls._menu_bar = mb
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_menubar_actions(cls):
|
||||||
|
preferences_action = QAction(QIcon(':/images/config.svg'), _('&Preferences'), None)
|
||||||
|
quit_action = QAction(QIcon(':/images/window-close.svg'), _('&Quit'), None)
|
||||||
|
preferences_action.setMenuRole(QAction.PreferencesRole)
|
||||||
|
quit_action.setMenuRole(QAction.QuitRole)
|
||||||
|
return preferences_action, quit_action
|
||||||
|
|
||||||
def __init__(self, opts, parent=None):
|
def __init__(self, opts, parent=None):
|
||||||
QMainWindow.__init__(self, parent)
|
QMainWindow.__init__(self, parent)
|
||||||
app = QCoreApplication.instance()
|
app = QCoreApplication.instance()
|
||||||
|
@ -158,21 +158,27 @@ class WorkerMother(object):
|
|||||||
self.executable = os.path.join(os.path.dirname(sys.executable),
|
self.executable = os.path.join(os.path.dirname(sys.executable),
|
||||||
'calibre-parallel.exe' if isfrozen else 'Scripts\\calibre-parallel.exe')
|
'calibre-parallel.exe' if isfrozen else 'Scripts\\calibre-parallel.exe')
|
||||||
elif isosx:
|
elif isosx:
|
||||||
self.executable = sys.executable
|
self.executable = self.gui_executable = sys.executable
|
||||||
self.prefix = ''
|
self.prefix = ''
|
||||||
if isfrozen:
|
if isfrozen:
|
||||||
fd = getattr(sys, 'frameworks_dir')
|
fd = getattr(sys, 'frameworks_dir')
|
||||||
contents = os.path.dirname(fd)
|
contents = os.path.dirname(fd)
|
||||||
resources = os.path.join(contents, 'Resources')
|
self.gui_executable = os.path.join(contents, 'MacOS',
|
||||||
sp = os.path.join(resources, 'lib', 'python'+sys.version[:3], 'site-packages.zip')
|
os.path.basename(sys.executable))
|
||||||
|
contents = os.path.join(contents, 'console.app', 'Contents')
|
||||||
|
self.executable = os.path.join(contents, 'MacOS',
|
||||||
|
os.path.basename(sys.executable))
|
||||||
|
|
||||||
|
resources = os.path.join(contents, 'Resources')
|
||||||
|
fd = os.path.join(contents, 'Frameworks')
|
||||||
|
sp = os.path.join(resources, 'lib', 'python'+sys.version[:3], 'site-packages.zip')
|
||||||
self.prefix += 'import sys; sys.frameworks_dir = "%s"; sys.frozen = "macosx_app"; '%fd
|
self.prefix += 'import sys; sys.frameworks_dir = "%s"; sys.frozen = "macosx_app"; '%fd
|
||||||
self.prefix += 'sys.path.insert(0, %s); '%repr(sp)
|
self.prefix += 'sys.path.insert(0, %s); '%repr(sp)
|
||||||
if fd not in os.environ['PATH']:
|
if fd not in os.environ['PATH']:
|
||||||
self.env['PATH'] = os.environ['PATH']+':'+fd
|
self.env['PATH'] = os.environ['PATH']+':'+fd
|
||||||
self.env['PYTHONHOME'] = resources
|
self.env['PYTHONHOME'] = resources
|
||||||
self.env['MAGICK_HOME'] = os.path.join(getattr(sys, 'frameworks_dir'), 'ImageMagick')
|
self.env['MAGICK_HOME'] = os.path.join(fd, 'ImageMagick')
|
||||||
self.env['DYLD_LIBRARY_PATH'] = os.path.join(getattr(sys, 'frameworks_dir'), 'ImageMagick', 'lib')
|
self.env['DYLD_LIBRARY_PATH'] = os.path.join(fd, 'ImageMagick', 'lib')
|
||||||
else:
|
else:
|
||||||
self.executable = os.path.join(getattr(sys, 'frozen_path'), 'calibre-parallel') \
|
self.executable = os.path.join(getattr(sys, 'frozen_path'), 'calibre-parallel') \
|
||||||
if isfrozen else 'calibre-parallel'
|
if isfrozen else 'calibre-parallel'
|
||||||
@ -219,7 +225,8 @@ class WorkerMother(object):
|
|||||||
|
|
||||||
def spawn_free_spirit_osx(self, arg, type='free_spirit'):
|
def spawn_free_spirit_osx(self, arg, type='free_spirit'):
|
||||||
script = 'from calibre.parallel import main; main(args=["calibre-parallel", %s]);'%repr(arg)
|
script = 'from calibre.parallel import main; main(args=["calibre-parallel", %s]);'%repr(arg)
|
||||||
cmdline = [self.executable, '-c', self.prefix+script]
|
exe = self.gui_executable if type == 'free_spirit' else self.executable
|
||||||
|
cmdline = [exe, '-c', self.prefix+script]
|
||||||
child = WorkerStatus(subprocess.Popen(cmdline, env=self.get_env()))
|
child = WorkerStatus(subprocess.Popen(cmdline, env=self.get_env()))
|
||||||
atexit.register(self.cleanup_child_linux, child)
|
atexit.register(self.cleanup_child_linux, child)
|
||||||
return child
|
return child
|
||||||
|
Loading…
x
Reference in New Issue
Block a user