diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py index ed26ae86e1..7a9562f136 100644 --- a/src/calibre/devices/apple/driver.py +++ b/src/calibre/devices/apple/driver.py @@ -17,9 +17,9 @@ from calibre.ebooks.metadata import authors_to_string, MetaInformation, \ title_sort from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.epub import set_metadata -from calibre.gui2.dialogs.confirm_delete import _config_name +from calibre.gui2.dialogs.confirm_delete import config_name from calibre.library.server.utils import strftime -from calibre.utils.config import config_dir, dynamic, DynamicConfig, 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 @@ -33,8 +33,8 @@ class AppleOpenFeedback(OpenFeedback): self.plugin = plugin def custom_dialog(self, parent): - from PyQt4.Qt import (QCheckBox, QDialog, QDialogButtonBox, QIcon, - QLabel, QPixmap, QPushButton, QSize, QVBoxLayout) + from PyQt4.Qt import (QDialog, QDialogButtonBox, QIcon, + QLabel, QPushButton, QVBoxLayout) class Dialog(QDialog): @@ -45,19 +45,20 @@ class AppleOpenFeedback(OpenFeedback): self.l = l = QVBoxLayout() self.setLayout(l) msg = QLabel() - msg.setText( + msg.setText(_( '

If you do not want calibre to recognize your Apple iDevice ' 'when it is connected to your computer, ' 'click Disable Apple Driver.

' '

To transfer books to your iDevice, ' 'click Disable Apple Driver, ' "then use the 'Connect to iTunes' method recommended in the " - 'Calibre + iDevices FAQ, ' + 'Calibre + iDevices FAQ, ' 'using the Connect/Share|Connect to iTunes menu item.

' '

Enabling the Apple driver for direct connection to iDevices ' 'is an unsupported advanced user mode.

' '

' - ) + )) + msg.setOpenExternalLinks(True) msg.setWordWrap(True) l.addWidget(msg) @@ -75,16 +76,18 @@ class AppleOpenFeedback(OpenFeedback): self.setWindowIcon(QIcon(I(pixmap))) self.resize(self.sizeHint()) - if Dialog(parent).exec_(): - # Enable Apple driver, inhibit future display of dialog - # Reset dialog with Preferences|Behavior|Reset all disabled confirmation dialogs - self.log.info(" Apple driver ENABLED") - dynamic[_config_name(self.plugin.DISPLAY_DISABLE_DIALOG)] = False - else: - # Disable Apple driver - from calibre.customize.ui import disable_plugin - self.log.info(" Apple driver DISABLED") - disable_plugin(self.plugin) + self.finished.connect(self.do_it) + + def do_it(self, return_code): + if return_code == self.Accepted: + self.log.info(" Apple driver ENABLED") + dynamic[config_name(self.plugin.DISPLAY_DISABLE_DIALOG)] = False + else: + from calibre.customize.ui import disable_plugin + self.log.info(" Apple driver DISABLED") + disable_plugin(self.plugin) + + return Dialog(parent) from PIL import Image as PILImage @@ -179,7 +182,7 @@ class ITUNES(DriverBase): #: The version of this plugin as a 3-tuple (major, minor, revision) version = (1,0,0) - DISPLAY_DISABLE_DIALOG = "display_disable_dialog" + DISPLAY_DISABLE_DIALOG = "display_disable_apple_driver_dialog" # EXTRA_CUSTOMIZATION_MESSAGE indexes USE_SERIES_AS_CATEGORY = 0 @@ -805,7 +808,7 @@ class ITUNES(DriverBase): # Display a dialog recommending using 'Connect to iTunes' if user hasn't # previously disabled the dialog - if dynamic.get(_config_name(self.DISPLAY_DISABLE_DIALOG),True): + if dynamic.get(config_name(self.DISPLAY_DISABLE_DIALOG),True): raise AppleOpenFeedback(self) else: if DEBUG: diff --git a/src/calibre/devices/errors.py b/src/calibre/devices/errors.py index 05c30c2f72..7b11b6933f 100644 --- a/src/calibre/devices/errors.py +++ b/src/calibre/devices/errors.py @@ -43,8 +43,8 @@ class OpenFeedback(DeviceError): def custom_dialog(self, parent): ''' - If you need to show the user a custom dialog, create and - run it from a custom_dialog() method in your subclass. + If you need to show the user a custom dialog, instead if just + displaying the feedback_msg, create and return it here. ''' raise NotImplementedError diff --git a/src/calibre/ebooks/conversion/plumber.py b/src/calibre/ebooks/conversion/plumber.py index 6272e7b10b..b26befe075 100644 --- a/src/calibre/ebooks/conversion/plumber.py +++ b/src/calibre/ebooks/conversion/plumber.py @@ -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() diff --git a/src/calibre/ebooks/metadata/meta.py b/src/calibre/ebooks/metadata/meta.py index cbd9db3f04..b0c43a8182 100644 --- a/src/calibre/ebooks/metadata/meta.py +++ b/src/calibre/ebooks/metadata/meta.py @@ -182,6 +182,19 @@ def metadata_from_filename(name, pat=None): mi.isbn = si except (IndexError, ValueError): pass + try: + publisher = match.group('publisher') + mi.publisher = publisher + except (IndexError, ValueError): + pass + try: + pubdate = match.group('published') + if pubdate: + from calibre.utils.date import parse_date + mi.pubdate = parse_date(pubdate) + except: + pass + if mi.is_null('title'): mi.title = name return mi diff --git a/src/calibre/ebooks/metadata/sources/identify.py b/src/calibre/ebooks/metadata/sources/identify.py index 53fb3a9ea4..5bc0c5b256 100644 --- a/src/calibre/ebooks/metadata/sources/identify.py +++ b/src/calibre/ebooks/metadata/sources/identify.py @@ -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 diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py index 189739986d..40ad5e9e78 100644 --- a/src/calibre/ebooks/mobi/mobiml.py +++ b/src/calibre/ebooks/mobi/mobiml.py @@ -102,6 +102,7 @@ class MobiMLizer(object): def __call__(self, oeb, context): oeb.logger.info('Converting XHTML to Mobipocket markup...') self.oeb = oeb + self.log = self.oeb.logger self.opts = context self.profile = profile = context.dest self.fnums = fnums = dict((v, k) for k, v in profile.fnums.items()) @@ -118,6 +119,10 @@ class MobiMLizer(object): del oeb.guide['cover'] item = oeb.manifest.hrefs[href] if item.spine_position is not None: + self.log.warn('Found an HTML cover,', item.href, 'removing it.', + 'If you find some content missing from the output MOBI, it ' + 'is because you misidentified the HTML cover in the input ' + 'document') oeb.spine.remove(item) if item.media_type in OEB_DOCS: self.oeb.manifest.remove(item) @@ -206,7 +211,11 @@ class MobiMLizer(object): vspace = bstate.vpadding + bstate.vmargin bstate.vpadding = bstate.vmargin = 0 if tag not in TABLE_TAGS: - wrapper.attrib['height'] = self.mobimlize_measure(vspace) + if tag in ('ul', 'ol') and vspace > 0: + wrapper.addprevious(etree.Element(XHTML('div'), + height=self.mobimlize_measure(vspace))) + else: + wrapper.attrib['height'] = self.mobimlize_measure(vspace) para.attrib['width'] = self.mobimlize_measure(indent) elif tag == 'table' and vspace > 0: vspace = int(round(vspace / self.profile.fbase)) diff --git a/src/calibre/ebooks/oeb/transforms/margins.py b/src/calibre/ebooks/oeb/transforms/margins.py deleted file mode 100644 index fbdf2e63fd..0000000000 --- a/src/calibre/ebooks/oeb/transforms/margins.py +++ /dev/null @@ -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 ' -__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 - diff --git a/src/calibre/ebooks/oeb/transforms/page_margin.py b/src/calibre/ebooks/oeb/transforms/page_margin.py index 589f004dd1..c415dda0e0 100644 --- a/src/calibre/ebooks/oeb/transforms/page_margin.py +++ b/src/calibre/ebooks/oeb/transforms/page_margin.py @@ -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): ''' diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 39a638850d..6163c01d27 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -623,7 +623,7 @@ class DeviceMixin(object): # {{{ self.__of_dev_mem__ = d = e.custom_dialog(self) except NotImplementedError: self.__of_dev_mem__ = d = info_dialog(self, devname, e.feedback_msg) - d.show() + d.show() def auto_convert_question(self, msg, autos): autos = u'\n'.join(map(unicode, map(force_unicode, autos))) diff --git a/src/calibre/gui2/dialogs/confirm_delete.py b/src/calibre/gui2/dialogs/confirm_delete.py index 9cdd46712f..6cd6fcaf51 100644 --- a/src/calibre/gui2/dialogs/confirm_delete.py +++ b/src/calibre/gui2/dialogs/confirm_delete.py @@ -7,7 +7,7 @@ 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): +def config_name(name): return name + '_again' class Dialog(QDialog, Ui_Dialog): @@ -22,11 +22,11 @@ class Dialog(QDialog, Ui_Dialog): self.buttonBox.setFocus(Qt.OtherFocusReason) def toggle(self, *args): - dynamic[_config_name(self.name)] = self.again.isChecked() + dynamic[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(config_name(name), True): return True d = Dialog(msg, name, parent) d.label.setPixmap(QPixmap(I(pixmap))) diff --git a/src/calibre/gui2/filename_pattern.ui b/src/calibre/gui2/filename_pattern.ui index 68b3108e06..c8a9b4f6f6 100644 --- a/src/calibre/gui2/filename_pattern.ui +++ b/src/calibre/gui2/filename_pattern.ui @@ -206,6 +206,46 @@ + + + + Publisher: + + + + + + + Regular expression (?P<publisher>) + + + No match + + + true + + + + + + + Published: + + + + + + + Regular expression (?P<published>) + + + No match + + + true + + + diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index ea0509b51a..e5f1c94342 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -121,6 +121,12 @@ class FilenamePattern(QWidget, Ui_Form): else: self.series_index.setText(_('No match')) + if mi.publisher: + self.publisher.setText(mi.publisher) + + if mi.pubdate: + self.pubdate.setText(mi.pubdate.strftime('%Y-%m-%d')) + self.isbn.setText(_('No match') if mi.isbn is None else str(mi.isbn)) diff --git a/src/calibre/library/custom_columns.py b/src/calibre/library/custom_columns.py index 48960ac871..8eed121b21 100644 --- a/src/calibre/library/custom_columns.py +++ b/src/calibre/library/custom_columns.py @@ -76,6 +76,8 @@ class CustomColumns(object): 'num':record[6], 'is_multiple':record[7], } + if data['display'] is None: + data['display'] = {} table, lt = self.custom_table_names(data['num']) if table not in custom_tables or (data['normalized'] and lt not in custom_tables): diff --git a/src/calibre/trac/bzr_commit_plugin.py b/src/calibre/trac/bzr_commit_plugin.py index 7e5a1367cb..c596425a68 100644 --- a/src/calibre/trac/bzr_commit_plugin.py +++ b/src/calibre/trac/bzr_commit_plugin.py @@ -31,8 +31,11 @@ class cmd_commit(_cmd_commit): summary = '' raw = urllib.urlopen('https://bugs.launchpad.net/calibre/+bug/' + bug).read() - h1 = html.fromstring(raw).xpath('//h1[@id="edit-title"]')[0] - summary = html.tostring(h1, method='text', encoding=unicode).strip() + try: + h1 = html.fromstring(raw).xpath('//h1[@id="edit-title"]')[0] + summary = html.tostring(h1, method='text', encoding=unicode).strip() + except: + summary = 'Private bug' print 'Working on bug:', summary if summary: msg = msg.replace('#%s'%bug, '#%s (%s)'%(bug, summary))