mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-08 18:54:09 -04:00
Merge from main branch
This commit is contained in:
commit
b305655e12
@ -61,6 +61,9 @@ def osx_version():
|
||||
if m:
|
||||
return int(m.group(1)), int(m.group(2)), int(m.group(3))
|
||||
|
||||
def confirm_config_name(name):
|
||||
return name + '_again'
|
||||
|
||||
_filename_sanitize = re.compile(r'[\xae\0\\|\?\*<":>\+/]')
|
||||
_filename_sanitize_unicode = frozenset([u'\\', u'|', u'?', u'*', u'<',
|
||||
u'"', u':', u'>', u'+', u'/'] + list(map(unichr, xrange(32))))
|
||||
|
@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en'
|
||||
|
||||
import cStringIO, ctypes, datetime, os, re, shutil, subprocess, sys, tempfile, time
|
||||
from calibre.constants import __appname__, __version__, DEBUG
|
||||
from calibre import fit_image
|
||||
from calibre import fit_image, confirm_config_name
|
||||
from calibre.constants import isosx, iswindows
|
||||
from calibre.devices.errors import OpenFeedback, UserFeedback
|
||||
from calibre.devices.usbms.deviceconfig import DeviceConfig
|
||||
@ -18,34 +18,76 @@ from calibre.ebooks.metadata import authors_to_string, MetaInformation, \
|
||||
from calibre.ebooks.metadata.book.base import Metadata
|
||||
from calibre.ebooks.metadata.epub import set_metadata
|
||||
from calibre.library.server.utils import strftime
|
||||
from calibre.utils.config import config_dir, prefs
|
||||
from calibre.utils.config import config_dir, dynamic, prefs
|
||||
from calibre.utils.date import now, parse_date
|
||||
from calibre.utils.logging import Log
|
||||
from calibre.utils.zipfile import ZipFile
|
||||
|
||||
|
||||
|
||||
class AppleOpenFeedback(OpenFeedback):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, plugin):
|
||||
OpenFeedback.__init__(self, u'')
|
||||
self.log = plugin.log
|
||||
self.plugin = plugin
|
||||
|
||||
def custom_dialog(self, parent):
|
||||
from PyQt4.Qt import (QDialog, QVBoxLayout, QLabel, QDialogButtonBox)
|
||||
from PyQt4.Qt import (QDialog, QDialogButtonBox, QIcon,
|
||||
QLabel, QPushButton, QVBoxLayout)
|
||||
|
||||
class Dialog(QDialog):
|
||||
|
||||
def __init__(self, p):
|
||||
def __init__(self, p, cd, pixmap='dialog_information.png'):
|
||||
QDialog.__init__(self, p)
|
||||
self.cd = cd
|
||||
self.setWindowTitle("Apple iDevice detected")
|
||||
self.l = l = QVBoxLayout()
|
||||
self.setLayout(l)
|
||||
l.addWidget(QLabel('test'))
|
||||
self.bb = QDialogButtonBox(QDialogButtonBox.OK)
|
||||
msg = QLabel()
|
||||
msg.setText(_(
|
||||
'<p>If you do not want calibre to recognize your Apple iDevice '
|
||||
'when it is connected to your computer, '
|
||||
'click <b>Disable Apple Driver</b>.</p>'
|
||||
'<p>To transfer books to your iDevice, '
|
||||
'click <b>Disable Apple Driver</b>, '
|
||||
"then use the 'Connect to iTunes' method recommended in the "
|
||||
'<a href="http://www.mobileread.com/forums/showthread.php?t=118559">Calibre + iDevices FAQ</a>, '
|
||||
'using the <em>Connect/Share</em>|<em>Connect to iTunes</em> menu item.</p>'
|
||||
'<p>Enabling the Apple driver for direct connection to iDevices '
|
||||
'is an unsupported advanced user mode.</p>'
|
||||
'<p></p>'
|
||||
))
|
||||
msg.setOpenExternalLinks(True)
|
||||
msg.setWordWrap(True)
|
||||
l.addWidget(msg)
|
||||
|
||||
self.bb = QDialogButtonBox()
|
||||
disable_driver = QPushButton(_("Disable Apple driver"))
|
||||
disable_driver.setDefault(True)
|
||||
self.bb.addButton(disable_driver, QDialogButtonBox.RejectRole)
|
||||
|
||||
enable_driver = QPushButton(_("Enable Apple driver"))
|
||||
self.bb.addButton(enable_driver, QDialogButtonBox.AcceptRole)
|
||||
l.addWidget(self.bb)
|
||||
self.bb.accepted.connect(self.accept)
|
||||
self.bb.rejected.connect(self.reject)
|
||||
|
||||
return Dialog(parent)
|
||||
self.setWindowIcon(QIcon(I(pixmap)))
|
||||
self.resize(self.sizeHint())
|
||||
|
||||
self.finished.connect(self.do_it)
|
||||
|
||||
def do_it(self, return_code):
|
||||
if return_code == self.Accepted:
|
||||
self.cd.log.info(" Apple driver ENABLED")
|
||||
dynamic[confirm_config_name(self.cd.plugin.DISPLAY_DISABLE_DIALOG)] = False
|
||||
else:
|
||||
from calibre.customize.ui import disable_plugin
|
||||
self.cd.log.info(" Apple driver DISABLED")
|
||||
disable_plugin(self.cd.plugin)
|
||||
|
||||
return Dialog(parent, self)
|
||||
|
||||
|
||||
from PIL import Image as PILImage
|
||||
from lxml import etree
|
||||
@ -77,15 +119,11 @@ class DriverBase(DeviceConfig, DevicePlugin):
|
||||
'iBooks Category'),
|
||||
_('Cache covers from iTunes/iBooks') +
|
||||
':::' +
|
||||
_('Enable to cache and display covers from iTunes/iBooks'),
|
||||
_("Skip 'Connect to iTunes' recommendation") +
|
||||
':::' +
|
||||
_("Enable to skip the 'Connect to iTunes' recommendation dialog")
|
||||
_('Enable to cache and display covers from iTunes/iBooks')
|
||||
]
|
||||
EXTRA_CUSTOMIZATION_DEFAULT = [
|
||||
True,
|
||||
True,
|
||||
False,
|
||||
]
|
||||
|
||||
|
||||
@ -141,12 +179,13 @@ class ITUNES(DriverBase):
|
||||
supported_platforms = ['osx','windows']
|
||||
author = 'GRiker'
|
||||
#: The version of this plugin as a 3-tuple (major, minor, revision)
|
||||
version = (0,9,0)
|
||||
version = (1,0,0)
|
||||
|
||||
DISPLAY_DISABLE_DIALOG = "display_disable_apple_driver_dialog"
|
||||
|
||||
# EXTRA_CUSTOMIZATION_MESSAGE indexes
|
||||
USE_SERIES_AS_CATEGORY = 0
|
||||
CACHE_COVERS = 1
|
||||
SKIP_CONNECT_TO_ITUNES_DIALOG = 2
|
||||
|
||||
OPEN_FEEDBACK_MESSAGE = _(
|
||||
'Apple device detected, launching iTunes, please wait ...')
|
||||
@ -762,15 +801,17 @@ class ITUNES(DriverBase):
|
||||
Note that most of the initialization is necessarily performed in can_handle(), as
|
||||
we need to talk to iTunes to discover if there's a connected iPod
|
||||
'''
|
||||
|
||||
if DEBUG:
|
||||
self.log.info("ITUNES.open()")
|
||||
|
||||
# Display a dialog recommending using 'Connect to iTunes'
|
||||
if False and not self.settings().extra_customization[self.SKIP_CONNECT_TO_ITUNES_DIALOG]:
|
||||
raise AppleOpenFeedback()
|
||||
|
||||
if DEBUG:
|
||||
self.log.info(" advanced user mode, directly connecting to iDevice")
|
||||
# Display a dialog recommending using 'Connect to iTunes' if user hasn't
|
||||
# previously disabled the dialog
|
||||
if dynamic.get(confirm_config_name(self.DISPLAY_DISABLE_DIALOG),True):
|
||||
raise AppleOpenFeedback(self)
|
||||
else:
|
||||
if DEBUG:
|
||||
self.log.info(" advanced user mode, directly connecting to iDevice")
|
||||
|
||||
# Confirm/create thumbs archive
|
||||
if not os.path.exists(self.cache_dir):
|
||||
|
@ -43,7 +43,7 @@ class OpenFeedback(DeviceError):
|
||||
|
||||
def custom_dialog(self, parent):
|
||||
'''
|
||||
If you need to show the user a custom dialog, instead if just
|
||||
If you need to show the user a custom dialog, instead of just
|
||||
displaying the feedback_msg, create and return it here.
|
||||
'''
|
||||
raise NotImplementedError
|
||||
|
@ -1003,8 +1003,10 @@ OptionRecommendation(name='sr3_replace',
|
||||
self.opts.insert_blank_line = oibl
|
||||
self.opts.remove_paragraph_spacing = orps
|
||||
|
||||
from calibre.ebooks.oeb.transforms.page_margin import RemoveFakeMargins
|
||||
from calibre.ebooks.oeb.transforms.page_margin import \
|
||||
RemoveFakeMargins, RemoveAdobeMargins
|
||||
RemoveFakeMargins()(self.oeb, self.log, self.opts)
|
||||
RemoveAdobeMargins()(self.oeb, self.log, self.opts)
|
||||
|
||||
pr(0.9)
|
||||
self.flush()
|
||||
|
@ -79,7 +79,7 @@ def identify(log, abort, title=None, authors=None, identifiers=[], timeout=30):
|
||||
time.sleep(0.2)
|
||||
|
||||
if get_results() and first_result_at is None:
|
||||
first_result_at = time.time()
|
||||
first_result_at = time.time()
|
||||
|
||||
if not is_worker_alive(workers):
|
||||
break
|
||||
|
@ -1,56 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
|
||||
class RemoveFakeMargins(object):
|
||||
'''
|
||||
Try to detect and remove fake margins inserted by asinine ebook creation
|
||||
software on each paragraph/wrapper div. Can be used only after CSS
|
||||
flattening.
|
||||
'''
|
||||
|
||||
def __call__(self, oeb, opts, log):
|
||||
self.oeb, self.opts, self.log = oeb, opts, log
|
||||
|
||||
from calibre.ebooks.oeb.base import XPath, OEB_STYLES
|
||||
|
||||
stylesheet = None
|
||||
for item in self.oeb.manifest:
|
||||
if item.media_type.lower() in OEB_STYLES:
|
||||
stylesheet = item.data
|
||||
break
|
||||
|
||||
if stylesheet is None:
|
||||
return
|
||||
|
||||
|
||||
top_level_elements = {}
|
||||
second_level_elements = {}
|
||||
|
||||
for x in self.oeb.spine:
|
||||
root = x.data
|
||||
body = XPath('//h:body')(root)
|
||||
if body:
|
||||
body = body[0]
|
||||
|
||||
if not hasattr(body, 'xpath'):
|
||||
continue
|
||||
|
||||
# Check for margins on top level elements
|
||||
for lb in XPath('./h:div|./h:p|./*/h:div|./*/h:p')(body):
|
||||
cls = lb.get('class', '')
|
||||
level = top_level_elements if lb.getparent() is body else \
|
||||
second_level_elements
|
||||
if cls not in level:
|
||||
level[cls] = []
|
||||
top_level_elements[cls] = []
|
||||
level[cls].append(lb)
|
||||
|
||||
|
||||
def get_margins(self, stylesheet, cls):
|
||||
pass
|
||||
|
@ -11,6 +11,26 @@ from collections import Counter
|
||||
|
||||
from calibre.ebooks.oeb.base import OEB_STYLES, barename, XPath
|
||||
|
||||
class RemoveAdobeMargins(object):
|
||||
'''
|
||||
Remove margins specified in Adobe's page templates.
|
||||
'''
|
||||
|
||||
def __call__(self, oeb, log, opts):
|
||||
self.oeb, self.opts, self.log = oeb, opts, log
|
||||
|
||||
for item in self.oeb.manifest:
|
||||
if item.media_type == 'application/vnd.adobe-page-template+xml':
|
||||
self.log('Removing page margins specified in the'
|
||||
' Adobe page template')
|
||||
for elem in item.data.xpath(
|
||||
'//*[@margin-bottom or @margin-top '
|
||||
'or @margin-left or @margin-right]'):
|
||||
for margin in ('left', 'right', 'top', 'bottom'):
|
||||
attr = 'margin-'+margin
|
||||
elem.attrib.pop(attr, None)
|
||||
|
||||
|
||||
class RemoveFakeMargins(object):
|
||||
|
||||
'''
|
||||
|
@ -3,12 +3,11 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from calibre.gui2 import dynamic
|
||||
from calibre.gui2.dialogs.confirm_delete_ui import Ui_Dialog
|
||||
from PyQt4.Qt import QDialog, Qt, QPixmap, QIcon
|
||||
|
||||
def _config_name(name):
|
||||
return name + '_again'
|
||||
from calibre import confirm_config_name
|
||||
from calibre.gui2 import dynamic
|
||||
from calibre.gui2.dialogs.confirm_delete_ui import Ui_Dialog
|
||||
|
||||
class Dialog(QDialog, Ui_Dialog):
|
||||
|
||||
@ -22,11 +21,11 @@ class Dialog(QDialog, Ui_Dialog):
|
||||
self.buttonBox.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
def toggle(self, *args):
|
||||
dynamic[_config_name(self.name)] = self.again.isChecked()
|
||||
dynamic[confirm_config_name(self.name)] = self.again.isChecked()
|
||||
|
||||
|
||||
def confirm(msg, name, parent=None, pixmap='dialog_warning.png'):
|
||||
if not dynamic.get(_config_name(name), True):
|
||||
if not dynamic.get(confirm_config_name(name), True):
|
||||
return True
|
||||
d = Dialog(msg, name, parent)
|
||||
d.label.setPixmap(QPixmap(I(pixmap)))
|
||||
|
Loading…
x
Reference in New Issue
Block a user