Qt::Horizontal
@@ -893,7 +911,6 @@ not multiple and the destination field is multiple
swap_title_and_author
change_title_to_title_case
button_box
- central_widget
search_field
search_mode
s_r_template
diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py
index c2588f57a8..a4e8bb6972 100644
--- a/src/calibre/gui2/dialogs/metadata_single.py
+++ b/src/calibre/gui2/dialogs/metadata_single.py
@@ -823,7 +823,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
if book.series_index is not None:
self.series_index.setValue(book.series_index)
if book.has_cover:
- if d.opt_auto_download_cover.isChecked() and book.has_cover:
+ if d.opt_auto_download_cover.isChecked():
self.fetch_cover()
else:
self.fetch_cover_button.setFocus(Qt.OtherFocusReason)
diff --git a/src/calibre/gui2/library/models.py b/src/calibre/gui2/library/models.py
index 670a2d823e..6fa23c2813 100644
--- a/src/calibre/gui2/library/models.py
+++ b/src/calibre/gui2/library/models.py
@@ -384,8 +384,9 @@ class BooksModel(QAbstractTableModel): # {{{
name, val = mi.format_field(key)
if mi.metadata_for_field(key)['datatype'] == 'comments':
name += ':html'
- if val:
+ if val and name not in data:
data[name] = val
+
return data
diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py
index a6eeabd57f..01d3180778 100644
--- a/src/calibre/gui2/ui.py
+++ b/src/calibre/gui2/ui.py
@@ -468,12 +468,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
try:
if 'calibre.ebooks.DRMError' in job.details:
if not minz:
- d = error_dialog(self, _('Conversion Error'),
- _('Could not convert: %s
It is a '
- 'DRMed book. You must first remove the '
- 'DRM using third party tools.')%\
- (job.description.split(':')[-1],
- 'http://bugs.calibre-ebook.com/wiki/DRM'))
+ from calibre.gui2.dialogs.drm_error import DRMErrorMessage
+ d = DRMErrorMessage(self, job.description.split(':')[-1])
d.setModal(False)
d.show()
self._modeless_dialogs.append(d)
diff --git a/src/calibre/gui2/viewer/main.py b/src/calibre/gui2/viewer/main.py
index 25f69b1558..c5001659a0 100644
--- a/src/calibre/gui2/viewer/main.py
+++ b/src/calibre/gui2/viewer/main.py
@@ -26,6 +26,7 @@ from calibre.gui2.search_box import SearchBox2
from calibre.ebooks.metadata import MetaInformation
from calibre.customize.ui import available_input_formats
from calibre.gui2.viewer.dictionary import Lookup
+from calibre import as_unicode
class TOCItem(QStandardItem):
@@ -626,13 +627,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
QApplication.processEvents()
if worker.exception is not None:
if isinstance(worker.exception, DRMError):
- error_dialog(self, _('DRM Error'),
- _('
This book is protected by DRM')
- %'http://wiki.mobileread.com/wiki/DRM').exec_()
+ from calibre.gui2.dialogs.drm_error import DRMErrorMessage
+ DRMErrorMessage(self).exec_()
else:
r = getattr(worker.exception, 'reason', worker.exception)
error_dialog(self, _('Could not open ebook'),
- unicode(r), det_msg=worker.traceback, show=True)
+ as_unicode(r), det_msg=worker.traceback, show=True)
self.close_progress_indicator()
else:
self.metadata.show_opf(self.iterator.opf, os.path.splitext(pathtoebook)[1][1:])
diff --git a/src/calibre/library/catalog.py b/src/calibre/library/catalog.py
index 98cc4b7ecd..5cda9baa8c 100644
--- a/src/calibre/library/catalog.py
+++ b/src/calibre/library/catalog.py
@@ -1531,10 +1531,23 @@ class EPUB_MOBI(CatalogPlugin):
self.opts.header_note_source_field,
index_is_id=True)
if notes:
- if field_md['datatype'] == 'text' and isinstance(notes,list):
- notes = ' · '.join(notes)
+ if field_md['datatype'] == 'text':
+ if isinstance(notes,list):
+ notes = ' · '.join(notes)
elif field_md['datatype'] == 'datetime':
notes = format_date(notes,'dd MMM yyyy')
+ elif field_md['datatype'] == 'composite':
+ m = re.match(r'\[(.+)\]$', notes)
+ if m is not None:
+ # Sniff for special pseudo-list string "[- ]"
+ bracketed_content = m.group(1)
+ if ',' in bracketed_content:
+ # Recast the comma-separated items as a list
+ items = bracketed_content.split(',')
+ items = [i.strip() for i in items]
+ notes = ' · '.join(items)
+ else:
+ notes = bracketed_content
this_title['notes'] = {'source':field_md['name'],
'content':notes}
diff --git a/src/calibre/library/database2.py b/src/calibre/library/database2.py
index 8a72ec040c..c2381938fb 100644
--- a/src/calibre/library/database2.py
+++ b/src/calibre/library/database2.py
@@ -709,6 +709,8 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
formats = row[fm['formats']]
if not formats:
formats = None
+ else:
+ formats = formats.split(',')
mi.formats = formats
tags = row[fm['tags']]
if tags:
diff --git a/src/calibre/trac/bzr_commit_plugin.py b/src/calibre/trac/bzr_commit_plugin.py
index df6bf699d1..6c36115cae 100644
--- a/src/calibre/trac/bzr_commit_plugin.py
+++ b/src/calibre/trac/bzr_commit_plugin.py
@@ -110,6 +110,7 @@ class cmd_commit(_cmd_commit):
suffix = 'The fix will be in the next release.'
action = action+'ed'
msg = '%s in branch %s. %s'%(action, nick, suffix)
+ msg = msg.replace('Fixesed', 'Fixed')
server = xmlrpclib.ServerProxy(url)
server.ticket.update(int(bug), msg,
{'status':'closed', 'resolution':'fixed'},
diff --git a/src/calibre/utils/cleantext.py b/src/calibre/utils/cleantext.py
index b4afe7576d..938960df93 100644
--- a/src/calibre/utils/cleantext.py
+++ b/src/calibre/utils/cleantext.py
@@ -3,7 +3,7 @@ __license__ = 'GPL 3'
__copyright__ = '2010, sengian '
__docformat__ = 'restructuredtext en'
-import re
+import re, htmlentitydefs
_ascii_pat = None
@@ -21,3 +21,32 @@ def clean_ascii_chars(txt, charlist=None):
pat = re.compile(u'|'.join(map(unichr, charlist)))
return pat.sub('', txt)
+##
+# Fredrik Lundh: http://effbot.org/zone/re-sub.htm#unescape-html
+# Removes HTML or XML character references and entities from a text string.
+#
+# @param text The HTML (or XML) source text.
+# @return The plain text, as a Unicode string, if necessary.
+
+def unescape(text, rm=False, rchar=u''):
+ def fixup(m, rm=rm, rchar=rchar):
+ text = m.group(0)
+ if text[:2] == "":
+ # character reference
+ try:
+ if text[:3] == "":
+ return unichr(int(text[3:-1], 16))
+ else:
+ return unichr(int(text[2:-1]))
+ except ValueError:
+ pass
+ else:
+ # named entity
+ try:
+ text = unichr(htmlentitydefs.name2codepoint[text[1:-1]])
+ except KeyError:
+ pass
+ if rm:
+ return rchar #replace by char
+ return text # leave as is
+ return re.sub("?\w+;", fixup, text)
diff --git a/src/calibre/utils/magick/draw.py b/src/calibre/utils/magick/draw.py
index c03a8660c8..ad4b681b43 100644
--- a/src/calibre/utils/magick/draw.py
+++ b/src/calibre/utils/magick/draw.py
@@ -92,7 +92,10 @@ def identify_data(data):
or raises an Exception if data is not an image.
'''
img = Image()
- img.load(data)
+ if hasattr(img, 'identify'):
+ img.identify(data)
+ else:
+ img.load(data)
width, height = img.size
fmt = img.format
return (width, height, fmt)
diff --git a/src/calibre/utils/magick/magick.c b/src/calibre/utils/magick/magick.c
index fd9563529a..869b77c736 100644
--- a/src/calibre/utils/magick/magick.c
+++ b/src/calibre/utils/magick/magick.c
@@ -456,6 +456,26 @@ magick_Image_load(magick_Image *self, PyObject *args, PyObject *kwargs) {
// }}}
+// Image.identify {{{
+static PyObject *
+magick_Image_identify(magick_Image *self, PyObject *args, PyObject *kwargs) {
+ const char *data;
+ Py_ssize_t dlen;
+ MagickBooleanType res;
+
+ NULL_CHECK(NULL)
+ if (!PyArg_ParseTuple(args, "s#", &data, &dlen)) return NULL;
+
+ res = MagickPingImageBlob(self->wand, data, dlen);
+
+ if (!res)
+ return magick_set_exception(self->wand);
+
+ Py_RETURN_NONE;
+}
+
+// }}}
+
// Image.open {{{
static PyObject *
magick_Image_read(magick_Image *self, PyObject *args, PyObject *kwargs) {
@@ -993,6 +1013,10 @@ static PyMethodDef magick_Image_methods[] = {
{"destroy", (PyCFunction)magick_Image_destroy, METH_VARARGS,
"Destroy the underlying ImageMagick Wand. WARNING: After using this method, all methods on this object will raise an exception."},
+ {"identify", (PyCFunction)magick_Image_identify, METH_VARARGS,
+ "Identify an image from a byte buffer (string)"
+ },
+
{"load", (PyCFunction)magick_Image_load, METH_VARARGS,
"Load an image from a byte buffer (string)"
},
diff --git a/src/calibre/utils/wmf/parse.py b/src/calibre/utils/wmf/parse.py
new file mode 100644
index 0000000000..c618884e33
--- /dev/null
+++ b/src/calibre/utils/wmf/parse.py
@@ -0,0 +1,269 @@
+#!/usr/bin/env python
+# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai
+
+__license__ = 'GPL v3'
+__copyright__ = '2011, Kovid Goyal '
+__docformat__ = 'restructuredtext en'
+
+import sys, struct
+
+
+
+class WMFHeader(object):
+
+ '''
+ For header documentation, see
+ http://www.skynet.ie/~caolan/publink/libwmf/libwmf/doc/ora-wmf.html
+ '''
+
+ def __init__(self, data, log, verbose):
+ self.log, self.verbose = log, verbose
+ offset = 0
+ file_type, header_size, windows_version = struct.unpack_from(' 0:
+ params = data[offset:offset+delta]
+ offset += delta
+
+ func = self.function_map.get(func, func)
+
+ if self.verbose > 3:
+ self.log.debug('WMF Record:', size, func)
+ self.records.append((func, params))
+
+ for rec in self.records:
+ f = getattr(self, rec[0], None)
+ if callable(f):
+ f(rec[1])
+ elif self.verbose > 2:
+ self.log.debug('Ignoring record:', rec[0])
+
+ self.has_raster_image = len(self.bitmaps) > 0
+
+
+ def SetMapMode(self, params):
+ if len(params) == 2:
+ self.map_mode = struct.unpack('