From 6459a6c256c2ea65bd69f1699d09ee52bd29baf2 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 20 Jun 2009 09:10:41 -0700 Subject: [PATCH 01/10] Fix #2670 (Xpath chapter detection wizard not working) --- src/calibre/gui2/convert/xpath_wizard.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/calibre/gui2/convert/xpath_wizard.py b/src/calibre/gui2/convert/xpath_wizard.py index d2a0d55a48..9b8e44ddaa 100644 --- a/src/calibre/gui2/convert/xpath_wizard.py +++ b/src/calibre/gui2/convert/xpath_wizard.py @@ -31,6 +31,8 @@ class WizardWidget(QWidget, Ui_Form): q = '[re:test(@%s, "%s", "i")]'%(attr, val) else: q = '[@%s]'%attr + elif val: + q = '[re:test(., "%s", "i")]'%(val) expr = '//'+tag + q return expr From 50a13466111814cdafa7cc566f880dfc065b9b29 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 20 Jun 2009 09:31:47 -0700 Subject: [PATCH 02/10] Fix #2672 (Error downloading built-in news recipe for El Mundo with 0.6b8) --- src/calibre/ebooks/oeb/base.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 98f1be1068..e9f82715cb 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -785,10 +785,12 @@ class Manifest(object): data = first_pass(data) # Force into the XHTML namespace if barename(data.tag) != 'html': - data = first_pass(''+data+'') - if barename(data.tag) != 'html': - raise NotHTML( - 'File %r does not appear to be (X)HTML' % self.href) + self.log.warn('File %r does not appear to be (X)HTML'%self.href) + nroot = etree.fromstring('') + for child in list(data): + child.getparent.remove(child) + nroot.append(child) + data = nroot elif not namespace(data.tag): data.attrib['xmlns'] = XHTML_NS data = etree.tostring(data, encoding=unicode) From e6309590fc6afcd575cb652f0d87a226770e5f6d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sat, 20 Jun 2009 09:46:22 -0700 Subject: [PATCH 03/10] Improve string_to_authors and use it in more places --- src/calibre/devices/jetbook/driver.py | 3 ++- src/calibre/ebooks/lrf/meta.py | 7 ++----- src/calibre/ebooks/metadata/__init__.py | 4 +++- src/calibre/ebooks/metadata/imp.py | 8 ++------ src/calibre/ebooks/metadata/meta.py | 7 ++----- src/calibre/ebooks/metadata/opf.py | 8 ++------ src/calibre/ebooks/metadata/pdf.py | 8 ++------ src/calibre/ebooks/metadata/rb.py | 8 ++------ src/calibre/ebooks/metadata/rtf.py | 7 ++----- src/calibre/library/database.py | 7 ++++--- src/calibre/library/database2.py | 2 +- 11 files changed, 24 insertions(+), 45 deletions(-) diff --git a/src/calibre/devices/jetbook/driver.py b/src/calibre/devices/jetbook/driver.py index 0d815640b1..2af1b03bf7 100644 --- a/src/calibre/devices/jetbook/driver.py +++ b/src/calibre/devices/jetbook/driver.py @@ -9,6 +9,7 @@ from itertools import cycle from calibre.devices.usbms.driver import USBMS from calibre import sanitize_file_name as sanitize +from calibre.ebooks.metadata import string_to_authors class JETBOOK(USBMS): name = 'Ectaco JetBook Device Interface' @@ -118,7 +119,7 @@ class JETBOOK(USBMS): match = cls.JETBOOK_FILE_NAME_PATTERN.match(fn) if match is not None: mi.title = check_unicode(match.group('title')) - authors = match.group('authors').split('&') + authors = string_to_authors(match.group('authors')) mi.authors = map(check_unicode, authors) return mi diff --git a/src/calibre/ebooks/lrf/meta.py b/src/calibre/ebooks/lrf/meta.py index 6ec87892d6..af1fad128f 100644 --- a/src/calibre/ebooks/lrf/meta.py +++ b/src/calibre/ebooks/lrf/meta.py @@ -19,7 +19,7 @@ import xml.dom.minidom as dom from functools import wraps from calibre.devices.prs500.prstypes import field -from calibre.ebooks.metadata import MetaInformation +from calibre.ebooks.metadata import MetaInformation, string_to_authors BYTE = ">sys.stderr, msg.encode('utf8') diff --git a/src/calibre/ebooks/metadata/rtf.py b/src/calibre/ebooks/metadata/rtf.py index bd8b1098c1..b1ee453218 100644 --- a/src/calibre/ebooks/metadata/rtf.py +++ b/src/calibre/ebooks/metadata/rtf.py @@ -5,7 +5,7 @@ Edit metadata in RTF files. """ import re, cStringIO, sys -from calibre.ebooks.metadata import MetaInformation +from calibre.ebooks.metadata import MetaInformation, string_to_authors title_pat = re.compile(r'\{\\info.*?\{\\title(.*?)(? Date: Sat, 20 Jun 2009 10:25:01 -0700 Subject: [PATCH 04/10] Revert splitting of author strings on commas --- src/calibre/ebooks/metadata/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/ebooks/metadata/__init__.py b/src/calibre/ebooks/metadata/__init__.py index 09632d7bee..9be40f9b49 100644 --- a/src/calibre/ebooks/metadata/__init__.py +++ b/src/calibre/ebooks/metadata/__init__.py @@ -16,7 +16,7 @@ from calibre import relpath _author_pat = re.compile(',?\s+and\s+', re.IGNORECASE) def string_to_authors(raw): raw = _author_pat.sub('&', raw) - raw = raw.replace('&&', u'\uffff').replace(',', '&') + raw = raw.replace('&&', u'\uffff') authors = [a.strip().replace(u'\uffff', '&') for a in raw.split('&')] return authors From 61677b6980f519d617e07aa610eaeac51da77dbc Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 21 Jun 2009 09:20:22 -0700 Subject: [PATCH 05/10] Fix Preferences menu and update Globe and Mail recipe --- src/calibre/ebooks/conversion/cli.py | 2 + src/calibre/gui2/main.py | 6 +- .../feeds/recipes/recipe_globe_and_mail.py | 113 +++++++++++------- 3 files changed, 76 insertions(+), 45 deletions(-) diff --git a/src/calibre/ebooks/conversion/cli.py b/src/calibre/ebooks/conversion/cli.py index dbf86c4d94..3a34fa8675 100644 --- a/src/calibre/ebooks/conversion/cli.py +++ b/src/calibre/ebooks/conversion/cli.py @@ -70,6 +70,8 @@ def option_recommendation_to_cli_option(add_option, rec): switches.append('--'+opt.long_switch) attrs = dict(dest=opt.name, help=opt.help, choices=opt.choices, default=rec.recommended_value) + if opt.long_switch == 'verbose': + attrs['action'] = 'count' if isinstance(rec.recommended_value, type(True)): attrs['action'] = 'store_false' if rec.recommended_value else \ 'store_true' diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 37d40f25fb..11a2dace54 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -315,10 +315,14 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): SIGNAL('triggered(bool)'), self.convert_single) self.convert_menu = cm pm = QMenu() - pm.addAction(self.action_preferences) + ap = self.action_preferences + pm.addAction(ap.icon(), ap.text()) pm.addAction(_('Run welcome wizard')) self.connect(pm.actions()[1], SIGNAL('triggered(bool)'), self.run_wizard) + self.connect(pm.actions()[0], SIGNAL('triggered(bool)'), + self.do_config) + self.action_preferences.setMenu(pm) self.preferences_menu = pm diff --git a/src/calibre/web/feeds/recipes/recipe_globe_and_mail.py b/src/calibre/web/feeds/recipes/recipe_globe_and_mail.py index 6214fa0578..1126990e5b 100644 --- a/src/calibre/web/feeds/recipes/recipe_globe_and_mail.py +++ b/src/calibre/web/feeds/recipes/recipe_globe_and_mail.py @@ -1,44 +1,69 @@ -#!/usr/bin/env python -__license__ = 'GPL v3' -__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' -__docformat__ = 'restructuredtext en' - -''' -globeandmail.com -''' - -from calibre.web.feeds.news import BasicNewsRecipe - -class GlobeAndMail(BasicNewsRecipe): - - title = 'Globe and Mail' - __author__ = 'Kovid Goyal' - language = _('English') - oldest_article = 2.0 - no_stylesheets = True - description = 'Canada\'s national newspaper' - remove_tags_before = dict(id="article-top") - remove_tags = [ - {'id':['util', 'article-tabs', 'comments', 'article-relations', - 'gallery-controls', 'video', 'galleryLoading']}, - ] - remove_tags_after = dict(id='article-content') - - feeds = [ - ('Latest headlines', 'http://www.theglobeandmail.com/?service=rss'), - ('Top stories', 'http://www.theglobeandmail.com/?service=rss&feed=topstories'), - ('National', 'http://www.theglobeandmail.com/news/national/?service=rss'), - ('Politics', 'http://www.theglobeandmail.com/news/politics/?service=rss'), - ('World', 'http://www.theglobeandmail.com/news/world/?service=rss'), - ('Business', 'http://www.theglobeandmail.com/report-on-business/?service=rss'), - ('Opinions', 'http://www.theglobeandmail.com/news/opinions/?service=rss'), - ('Columnists', 'http://www.theglobeandmail.com/news/opinions/columnists/?service=rss'), - ('Globe Investor', 'http://www.theglobeandmail.com/globe-investor/?service=rss'), - ('Sports', 'http://www.theglobeandmail.com/sports/?service=rss'), - ('Technology', 'http://www.theglobeandmail.com/news/technology/?service=rss'), - ('Arts', 'http://www.theglobeandmail.com/news/arts/?service=rss'), - ('Life', 'http://www.theglobeandmail.com/life/?service=rss'), - ('Blogs', 'http://www.theglobeandmail.com/blogs/?service=rss'), - ('Real Estate', 'http://www.theglobeandmail.com/real-estate/?service=rss'), - ('Auto', 'http://www.theglobeandmail.com/auto/?service=rss'), - ] +#!/usr/bin/env python +__license__ = 'GPL v3' + +__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' +__docformat__ = 'restructuredtext en' + +''' +globeandmail.com +''' + +from calibre.web.feeds.news import BasicNewsRecipe + +class GlobeAndMail(BasicNewsRecipe): + title = u'Globe and Mail' + language = _('English') + __author__ = 'Kovid Goyal' + oldest_article = 2 + max_articles_per_feed = 10 + no_stylesheets = True + extra_css = ''' + h3 {font-size: 22pt; font-weight:bold; margin:0px; padding:0px 0px 8pt 0px;} + h4 {margin-top: 0px;} + #byline { font-family: monospace; font-weight:bold; } + #placeline {font-weight:bold;} + #credit {margin-top:0px;} + .tag {font-size: 22pt;}''' + description = 'Canada\'s national newspaper' + remove_tags_before = dict(id="article-top") + remove_tags = [ + {'id':['util', 'article-tabs', 'comments', 'article-relations', + 'gallery-controls', 'video', 'galleryLoading','deck','header'] }, + {'class':['credit','inline-img-caption','tab-pointer'] }, + dict(name='div', attrs={'id':'lead-photo'}), + dict(name='div', attrs={'class':'right'}), + dict(name='div', attrs={'id':'footer'}), + dict(name='div', attrs={'id':'beta-msg'}), + dict(name='img', attrs={'class':'headshot'}), + dict(name='div', attrs={'class':'brand'}), + dict(name='div', attrs={'id':'nav-wrap'}), + dict(name='div', attrs={'id':'featureTopics'}), + dict(name='div', attrs={'id':'videoNav'}), + dict(name='div', attrs={'id':'blog-header'}), + dict(name='div', attrs={'id':'right-rail'}), + dict(name='div', attrs={'id':'group-footer-container'}), + dict(name=['iframe','img']) + ] + remove_tags_after = [{'id':['article-content']}, + {'class':['pull','inline-img'] }, + dict(name='img', attrs={'class':'inline-media-embed'}), + ] + feeds = [ + (u'Latest headlines', u'http://www.theglobeandmail.com/?service=rss'), + (u'Top stories', u'http://www.theglobeandmail.com/?service=rss&feed=topstories'), + (u'National', u'http://www.theglobeandmail.com/news/national/?service=rss'), + (u'Politics', u'http://www.theglobeandmail.com/news/politics/?service=rss'), + (u'World', u'http://www.theglobeandmail.com/news/world/?service=rss'), + (u'Business', u'http://www.theglobeandmail.com/report-on-business/?service=rss'), + (u'Opinions', u'http://www.theglobeandmail.com/news/opinions/?service=rss'), + (u'Columnists', u'http://www.theglobeandmail.com/news/opinions/columnists/?service=rss'), + (u'Globe Investor', u'http://www.theglobeandmail.com/globe-investor/?service=rss'), + (u'Sports', u'http://www.theglobeandmail.com/sports/?service=rss'), + (u'Technology', u'http://www.theglobeandmail.com/news/technology/?service=rss'), + (u'Arts', u'http://www.theglobeandmail.com/news/arts/?service=rss'), + (u'Life', u'http://www.theglobeandmail.com/life/?service=rss'), + (u'Blogs', u'http://www.theglobeandmail.com/blogs/?service=rss'), + (u'Real Estate', u'http://www.theglobeandmail.com/real-estate/?service=rss'), + (u'Auto', u'http://www.theglobeandmail.com/auto/?service=rss') + ] + From f5fb4d9a6ce8c731328bb2da1d16ee8cedafa9ab Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 21 Jun 2009 10:44:04 -0700 Subject: [PATCH 06/10] Fix #2680 (Failed Conversion Error) --- src/calibre/ebooks/oeb/transforms/jacket.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/oeb/transforms/jacket.py b/src/calibre/ebooks/oeb/transforms/jacket.py index 14b19716df..b3eefc46fa 100644 --- a/src/calibre/ebooks/oeb/transforms/jacket.py +++ b/src/calibre/ebooks/oeb/transforms/jacket.py @@ -10,7 +10,7 @@ import textwrap from lxml import etree -from calibre.ebooks.oeb.base import XPNSMAP +from calibre.ebooks.oeb.base import XPath, XPNSMAP from calibre import guess_type class Jacket(object): @@ -41,10 +41,11 @@ class Jacket(object): ''') def remove_first_image(self): + path = XPath('//h:img[@src]') for i, item in enumerate(self.oeb.spine): if i > 2: break - for img in item.data.xpath('//h:img[@src]', namespace=XPNSMAP): - href = item.abshref(img.get('src')) + for img in path(item.data): + href = item.abshref(img.get('src')) image = self.oeb.manifest.hrefs.get(href, None) if image is not None: self.log('Removing first image', img.get('src')) From fb86204423aac5a1f65a1d9f24f54dcfa0649d4e Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 21 Jun 2009 11:00:48 -0700 Subject: [PATCH 07/10] Add support for author and description when parsing NCX files --- src/calibre/ebooks/oeb/base.py | 17 ++++++++++++----- src/calibre/ebooks/oeb/reader.py | 22 ++++++++++++++++++++-- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index e9f82715cb..26bce4e912 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -41,11 +41,14 @@ SVG_NS = 'http://www.w3.org/2000/svg' XLINK_NS = 'http://www.w3.org/1999/xlink' CALIBRE_NS = 'http://calibre.kovidgoyal.net/2009/metadata' RE_NS = 'http://exslt.org/regular-expressions' +MBP_NS = 'http://www.mobipocket.com' XPNSMAP = {'h' : XHTML_NS, 'o1' : OPF1_NS, 'o2' : OPF2_NS, 'd09': DC09_NS, 'd10': DC10_NS, 'd11': DC11_NS, 'xsi': XSI_NS, 'dt' : DCTERMS_NS, 'ncx': NCX_NS, - 'svg': SVG_NS, 'xl' : XLINK_NS, 're': RE_NS} + 'svg': SVG_NS, 'xl' : XLINK_NS, 're': RE_NS, + 'mbp': MBP_NS } + OPF1_NSMAP = {'dc': DC11_NS, 'oebpackage': OPF1_NS} OPF2_NSMAP = {'opf': OPF2_NS, 'dc': DC11_NS, 'dcterms': DCTERMS_NS, 'xsi': XSI_NS, 'calibre': CALIBRE_NS} @@ -1373,9 +1376,11 @@ class TOC(object): :attr:`href`: Book-internal URL referenced by this node. :attr:`klass`: Optional semantic class referenced by this node. :attr:`id`: Option unique identifier for this node. + :attr:`author`: Optional author attribution for periodicals + :attr:`description`: Optional description attribute for periodicals """ def __init__(self, title=None, href=None, klass=None, id=None, - play_order=None): + play_order=None, author=None, description=None): self.title = title self.href = urlnormalize(href) if href else href self.klass = klass @@ -1385,10 +1390,12 @@ class TOC(object): if play_order is None: play_order = self.next_play_order() self.play_order = play_order - - def add(self, title, href, klass=None, id=None, play_order=0): + self.author = author + self.description = description + + def add(self, title, href, klass=None, id=None, play_order=0, author=None, description=None): """Create and return a new sub-node of this node.""" - node = TOC(title, href, klass, id, play_order) + node = TOC(title, href, klass, id, play_order, author, description) self.nodes.append(node) return node diff --git a/src/calibre/ebooks/oeb/reader.py b/src/calibre/ebooks/oeb/reader.py index 4ccc1eeed1..75d92f1815 100644 --- a/src/calibre/ebooks/oeb/reader.py +++ b/src/calibre/ebooks/oeb/reader.py @@ -351,9 +351,27 @@ class OEBReader(object): self.logger.warn('TOC reference %r not found' % href) continue id = child.get('id') - klass = child.get('class') + klass = child.get('class', 'chapter') + po = int(child.get('playOrder', self.oeb.toc.next_play_order())) - node = toc.add(title, href, id=id, klass=klass, play_order=po) + + authorElement = xpath(child, + 'descendant::mbp:meta[@name = "author"]') + if authorElement : + author = authorElement[0].text + else : + author = None + + descriptionElement = xpath(child, + 'descendant::mbp:meta[@name = "description"]') + if descriptionElement : + description = descriptionElement[0].text + else : + description = None + + node = toc.add(title, href, id=id, klass=klass, + play_order=po, description=description, author=author) + self._toc_from_navpoint(item, node, child) def _toc_from_ncx(self, item): From 03dba92e8d32355cba6298b731adc7a20753cc5d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 21 Jun 2009 11:10:22 -0700 Subject: [PATCH 08/10] Fix #2682 (beta testing 0.6.0b8 html not zipping for conversion) --- src/calibre/ebooks/oeb/base.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/calibre/ebooks/oeb/base.py b/src/calibre/ebooks/oeb/base.py index 26bce4e912..a3dadb995d 100644 --- a/src/calibre/ebooks/oeb/base.py +++ b/src/calibre/ebooks/oeb/base.py @@ -48,7 +48,7 @@ XPNSMAP = {'h' : XHTML_NS, 'o1' : OPF1_NS, 'o2' : OPF2_NS, 'xsi': XSI_NS, 'dt' : DCTERMS_NS, 'ncx': NCX_NS, 'svg': SVG_NS, 'xl' : XLINK_NS, 're': RE_NS, 'mbp': MBP_NS } - + OPF1_NSMAP = {'dc': DC11_NS, 'oebpackage': OPF1_NS} OPF2_NSMAP = {'opf': OPF2_NS, 'dc': DC11_NS, 'dcterms': DCTERMS_NS, 'xsi': XSI_NS, 'calibre': CALIBRE_NS} @@ -804,10 +804,11 @@ class Manifest(object): try: data = etree.fromstring(data) except etree.XMLSyntaxError: - self.oeb.logger.warn('Stripping comments from %s'% + self.oeb.logger.warn('Stripping comments and meta tags from %s'% self.href) data = re.compile(r'', re.DOTALL).sub('', data) + data = re.sub(r']+?>', '', data) data = etree.fromstring(data) elif namespace(data.tag) != XHTML_NS: # OEB_DOC_NS, but possibly others @@ -1392,7 +1393,7 @@ class TOC(object): self.play_order = play_order self.author = author self.description = description - + def add(self, title, href, klass=None, id=None, play_order=0, author=None, description=None): """Create and return a new sub-node of this node.""" node = TOC(title, href, klass, id, play_order, author, description) From 119b1549488a8d6a510ad85672c2e03611df078d Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 21 Jun 2009 12:40:26 -0700 Subject: [PATCH 09/10] Add support for date published field to edit metadata dialog. Also preferentially use ISBN13 numbers from ISBNDB --- src/calibre/ebooks/metadata/isbndb.py | 3 +-- src/calibre/gui2/dialogs/fetch_metadata.py | 9 ++++++-- src/calibre/gui2/dialogs/metadata_single.py | 13 ++++++++++- src/calibre/gui2/dialogs/metadata_single.ui | 24 +++++++++++++++++++++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/src/calibre/ebooks/metadata/isbndb.py b/src/calibre/ebooks/metadata/isbndb.py index 7ab2f16949..38c6e68d3c 100644 --- a/src/calibre/ebooks/metadata/isbndb.py +++ b/src/calibre/ebooks/metadata/isbndb.py @@ -49,7 +49,7 @@ class ISBNDBMetadata(MetaInformation): def __init__(self, book): MetaInformation.__init__(self, None, []) - self.isbn = book['isbn'] + self.isbn = book.get('isbn13', book.get('isbn')) self.title = book.find('titlelong').string if not self.title: self.title = book.find('title').string @@ -74,7 +74,6 @@ class ISBNDBMetadata(MetaInformation): self.comments = 'SUMMARY:\n'+summ.string - def build_isbn(base_url, opts): return base_url + 'index1=isbn&value1='+opts.isbn diff --git a/src/calibre/gui2/dialogs/fetch_metadata.py b/src/calibre/gui2/dialogs/fetch_metadata.py index aab564e05d..ea076b42a1 100644 --- a/src/calibre/gui2/dialogs/fetch_metadata.py +++ b/src/calibre/gui2/dialogs/fetch_metadata.py @@ -14,6 +14,7 @@ from calibre.gui2.dialogs.fetch_metadata_ui import Ui_FetchMetadata from calibre.gui2 import error_dialog, NONE, info_dialog from calibre.gui2.widgets import ProgressIndicator from calibre.utils.config import prefs +from calibre import strftime class Fetcher(QThread): @@ -45,7 +46,7 @@ class Matches(QAbstractTableModel): return len(self.matches) def columnCount(self, *args): - return 5 + return 6 def headerData(self, section, orientation, role): if role != Qt.DisplayRole: @@ -57,6 +58,7 @@ class Matches(QAbstractTableModel): elif section == 2: text = _("Author Sort") elif section == 3: text = _("Publisher") elif section == 4: text = _("ISBN") + elif section == 5: text = _("Published") return QVariant(text) else: @@ -80,6 +82,9 @@ class Matches(QAbstractTableModel): res = book.publisher elif col == 4: res = book.isbn + elif col == 5: + if hasattr(book.pubdate, 'timetuple'): + res = strftime('%b %Y', book.pubdate.timetuple()) if not res: return NONE return QVariant(res) @@ -126,7 +131,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata): prefs['isbndb_com_key'] = key else: key = None - title = author = publisher = isbn = None + title = author = publisher = isbn = pubdate = None if self.isbn: isbn = self.isbn if self.title: diff --git a/src/calibre/gui2/dialogs/metadata_single.py b/src/calibre/gui2/dialogs/metadata_single.py index bf153ba932..d25d0609c8 100644 --- a/src/calibre/gui2/dialogs/metadata_single.py +++ b/src/calibre/gui2/dialogs/metadata_single.py @@ -10,8 +10,9 @@ import os import re import time import traceback +from datetime import datetime -from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread +from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread, QDate from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog, QCompleter from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \ @@ -234,6 +235,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.cover.setAcceptDrops(True) self._author_completer = AuthorCompleter(self.db) self.authors.setCompleter(self._author_completer) + self.pubdate.setMinimumDate(QDate(100,1,1)) self.connect(self.cover, SIGNAL('cover_changed()'), self.cover_dropped) QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), \ self.select_cover) @@ -279,6 +281,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): comments = self.db.comments(row) self.comments.setPlainText(comments if comments else '') cover = self.db.cover(row) + pubdate = db.pubdate(self.id, index_is_id=True) + self.pubdate.setDate(QDate(pubdate.year, pubdate.month, + pubdate.day)) exts = self.db.formats(row) if exts: @@ -441,6 +446,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): if book.author_sort: self.author_sort.setText(book.author_sort) if book.publisher: self.publisher.setEditText(book.publisher) if book.isbn: self.isbn.setText(book.isbn) + if book.pubdate: + d = book.pubdate + self.pubdate.setDate(QDate(d.year, d.month, d.day)) summ = book.comments if summ: prefix = qstring_to_unicode(self.comments.toPlainText()) @@ -485,6 +493,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog): self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False) self.db.set_series_index(self.id, self.series_index.value(), notify=False) self.db.set_comment(self.id, qstring_to_unicode(self.comments.toPlainText()), notify=False) + d = self.pubdate.date() + self.db.set_pubdate(self.id, datetime(d.year(), d.month(), d.day())) + if self.cover_changed: self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap())) QDialog.accept(self) diff --git a/src/calibre/gui2/dialogs/metadata_single.ui b/src/calibre/gui2/dialogs/metadata_single.ui index 4163c51583..3f44b28d1c 100644 --- a/src/calibre/gui2/dialogs/metadata_single.ui +++ b/src/calibre/gui2/dialogs/metadata_single.ui @@ -325,6 +325,19 @@ + + + + Publishe&d: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + pubdate + + + @@ -348,6 +361,16 @@ + + + + MMM yyyy + + + true + + + @@ -632,6 +655,7 @@ tag_editor_button remove_series_button isbn + pubdate comments fetch_metadata_button fetch_cover_button From 5adfd154bf52f4bb7b28420c6a8bb963c9e7fb7c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Sun, 21 Jun 2009 13:02:48 -0700 Subject: [PATCH 10/10] Revert changes to window showing/hiding logic as they break starting of GUI --- src/calibre/gui2/main.py | 39 ++++++++++++++++----------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/src/calibre/gui2/main.py b/src/calibre/gui2/main.py index 62e11466cd..11a2dace54 100644 --- a/src/calibre/gui2/main.py +++ b/src/calibre/gui2/main.py @@ -167,7 +167,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.connect(self.quit_action, SIGNAL('triggered(bool)'), self.quit) self.connect(self.donate_action, SIGNAL('triggered(bool)'), self.donate) self.connect(self.restore_action, SIGNAL('triggered()'), - self.show_windows) + self.show) self.connect(self.action_show_book_details, SIGNAL('triggered(bool)'), self.show_book_info) self.connect(self.action_restart, SIGNAL('triggered()'), @@ -317,7 +317,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): pm = QMenu() ap = self.action_preferences pm.addAction(ap.icon(), ap.text()) - pm.addAction(self.preferences_action) pm.addAction(_('Run welcome wizard')) self.connect(pm.actions()[1], SIGNAL('triggered(bool)'), self.run_wizard) @@ -403,9 +402,9 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.card_a_view.connect_dirtied_signal(self.upload_booklists) self.card_b_view.connect_dirtied_signal(self.upload_booklists) - self.show_windows() + self.show() if self.system_tray_icon.isVisible() and opts.start_in_tray: - self.hide_windows() + self.hide() self.stack.setCurrentIndex(0) try: db = LibraryDatabase2(self.library_path) @@ -522,22 +521,16 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): def system_tray_icon_activated(self, r): if r == QSystemTrayIcon.Trigger: if self.isVisible(): - self.hide_windows() + for window in QApplication.topLevelWidgets(): + if isinstance(window, (MainWindow, QDialog)) and \ + window.isVisible(): + window.hide() + setattr(window, '__systray_minimized', True) else: - self.show_windows() - - def hide_windows(self): - for window in QApplication.topLevelWidgets(): - if isinstance(window, (MainWindow, QDialog)) and \ - window.isVisible(): - window.hide() - setattr(window, '__systray_minimized', True) - - def show_windows(self): - for window in QApplication.topLevelWidgets(): - if getattr(window, '__systray_minimized', False): - window.show() - setattr(window, '__systray_minimized', False) + for window in QApplication.topLevelWidgets(): + if getattr(window, '__systray_minimized', False): + window.show() + setattr(window, '__systray_minimized', False) def test_server(self, *args): if self.content_server.exception is not None: @@ -648,7 +641,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.add_filesystem_book(path) self.setWindowState(self.windowState() & \ ~Qt.WindowMinimized|Qt.WindowActive) - self.show_windows() + self.show() self.raise_() self.activateWindow() elif msg.startswith('refreshdb:'): @@ -1665,7 +1658,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): self.spare_servers.pop().close() self.device_manager.keep_going = False self.cover_cache.stop() - self.hide_windows() + self.hide() self.cover_cache.terminate() self.emailer.stop() try: @@ -1677,7 +1670,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): time.sleep(2) except KeyboardInterrupt: pass - self.hide_windows() + self.hide() return True def run_wizard(self, *args): @@ -1701,7 +1694,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI): 'choose Quit in the context menu of the ' 'system tray.')).exec_() dynamic['systray_msg'] = True - self.hide_windows() + self.hide() e.ignore() else: if self.confirm_quit():