From da14165c63f2259292e7de77b2dc8bf2cc5b5ce1 Mon Sep 17 00:00:00 2001 From: John Schember Date: Sun, 1 Jul 2012 13:47:23 -0400 Subject: [PATCH 01/10] Store: Fix Weightless. --- src/calibre/gui2/store/stores/weightless_books_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/calibre/gui2/store/stores/weightless_books_plugin.py b/src/calibre/gui2/store/stores/weightless_books_plugin.py index 3fa1c76851..330f3fdf0f 100644 --- a/src/calibre/gui2/store/stores/weightless_books_plugin.py +++ b/src/calibre/gui2/store/stores/weightless_books_plugin.py @@ -41,7 +41,7 @@ class WeightlessBooksStore(BasicStoreConfig, StorePlugin): counter = max_results with closing(br.open(url, timeout=timeout)) as f: doc = html.fromstring(f.read()) - for data in doc.xpath('//li[@id="product"]'): + for data in doc.xpath('//li[@class="product"]'): if counter <= 0: break From 67b3e063ce5328df42058dec2cd06a881bf87b84 Mon Sep 17 00:00:00 2001 From: John Schember Date: Sun, 1 Jul 2012 13:49:23 -0400 Subject: [PATCH 02/10] Store: Remove OReilly plugin. --- src/calibre/customize/builtins.py | 10 --- .../gui2/store/stores/oreilly_plugin.py | 81 ------------------- 2 files changed, 91 deletions(-) delete mode 100644 src/calibre/gui2/store/stores/oreilly_plugin.py diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index cced3b194f..495d923289 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -1511,15 +1511,6 @@ class StoreOpenBooksStore(StoreBase): drm_free_only = True headquarters = 'US' -class StoreOReillyStore(StoreBase): - name = 'OReilly' - description = u'Programming and tech ebooks from OReilly.' - actual_plugin = 'calibre.gui2.store.stores.oreilly_plugin:OReillyStore' - - drm_free_only = True - headquarters = 'US' - formats = ['APK', 'DAISY', 'EPUB', 'MOBI', 'PDF'] - class StoreOzonRUStore(StoreBase): name = 'OZON.ru' description = u'ebooks from OZON.ru' @@ -1659,7 +1650,6 @@ plugins += [ StoreMobileReadStore, StoreNextoStore, StoreOpenBooksStore, - StoreOReillyStore, StoreOzonRUStore, StorePragmaticBookshelfStore, StoreRW2010Store, diff --git a/src/calibre/gui2/store/stores/oreilly_plugin.py b/src/calibre/gui2/store/stores/oreilly_plugin.py deleted file mode 100644 index e45c072eea..0000000000 --- a/src/calibre/gui2/store/stores/oreilly_plugin.py +++ /dev/null @@ -1,81 +0,0 @@ -# -*- coding: utf-8 -*- - -from __future__ import (unicode_literals, division, absolute_import, print_function) - -__license__ = 'GPL 3' -__copyright__ = '2011, John Schember ' -__docformat__ = 'restructuredtext en' - -import urllib -from contextlib import closing - -from lxml import html - -from PyQt4.Qt import QUrl - -from calibre import browser, url_slash_cleaner -from calibre.gui2 import open_url -from calibre.gui2.store import StorePlugin -from calibre.gui2.store.basic_config import BasicStoreConfig -from calibre.gui2.store.search_result import SearchResult -from calibre.gui2.store.web_store_dialog import WebStoreDialog - -class OReillyStore(BasicStoreConfig, StorePlugin): - - def open(self, parent=None, detail_item=None, external=False): - url = 'http://oreilly.com/ebooks/' - - if external or self.config.get('open_external', False): - open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url))) - else: - d = WebStoreDialog(self.gui, url, parent, detail_item) - d.setWindowTitle(self.name) - d.set_tags(self.config.get('tags', '')) - d.exec_() - - def search(self, query, max_results=10, timeout=60): - url = 'http://search.oreilly.com/?t1=Books&t2=Format&t3=Ebook&q=' + urllib.quote_plus(query) - - br = browser() - - counter = max_results - with closing(br.open(url, timeout=timeout)) as f: - doc = html.fromstring(f.read()) - for data in doc.xpath('//div[@class="result"]'): - if counter <= 0: - break - - ebook = ' '.join(data.xpath('.//p[@class="note"]/text()')) - if 'ebook' not in ebook.lower(): - continue - - id = ''.join(data.xpath('./div[@class="book_text"]//p[@class="title"]/a/@href')) - - cover_url = ''.join(data.xpath('./a/img[1]/@src')) - - title = ''.join(data.xpath('./div[@class="book_text"]/p[@class="title"]/a/text()')) - author = ''.join(data.xpath('./div[@class="book_text"]/p[@class="note"][1]/text()')) - author = author.split('By ')[-1].strip() - - # Get the detail here because we need to get the ebook id for the detail_item. - with closing(br.open(id, timeout=timeout)) as nf: - idoc = html.fromstring(nf.read()) - - for td in idoc.xpath('//td[@class="optionsTd"]'): - if 'ebook' in ''.join(td.xpath('.//text()')).lower(): - price = ''.join(td.xpath('.//span[@class="price"]/text()')).strip() - formats = ''.join(td.xpath('.//a[@id="availableFormats"]/text()')).strip() - break - - counter -= 1 - - s = SearchResult() - s.cover_url = cover_url.strip() - s.title = title.strip() - s.author = author.strip() - s.detail_item = id.strip() - s.price = price.strip() - s.drm = SearchResult.DRM_UNLOCKED - s.formats = formats.upper() - - yield s From 340998fbee0fdfdc28e482480cc7f58182f08538 Mon Sep 17 00:00:00 2001 From: John Schember Date: Sun, 1 Jul 2012 13:59:20 -0400 Subject: [PATCH 03/10] Store: ebooks.com fix author and cover display. --- src/calibre/gui2/store/stores/ebooks_com_plugin.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/calibre/gui2/store/stores/ebooks_com_plugin.py b/src/calibre/gui2/store/stores/ebooks_com_plugin.py index 656984a86d..7bf6704d9f 100644 --- a/src/calibre/gui2/store/stores/ebooks_com_plugin.py +++ b/src/calibre/gui2/store/stores/ebooks_com_plugin.py @@ -64,11 +64,11 @@ class EbookscomStore(BasicStoreConfig, StorePlugin): continue id = mo.group() - cover_url = ''.join(data.xpath('.//div[@class="img"]//img/@src')) + cover_url = ''.join(data.xpath('.//div[contains(@class, "img")]//img/@src')) title = ''.join(data.xpath( 'descendant::span[@class="book-title"]/a/text()')).strip() - author = ''.join(data.xpath( + author = ', '.join(data.xpath( 'descendant::span[@class="author"]/a/text()')).strip() if not title or not author: continue From 343d8f448c59fdd456c195b56460f75a7b71ebe1 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 10:17:54 +0530 Subject: [PATCH 04/10] Get Books: Fix ozon.ru --- src/calibre/ebooks/metadata/sources/ozon.py | 81 ++++++++++--------- .../gui2/store/stores/ozon_ru_plugin.py | 53 +++++++----- 2 files changed, 80 insertions(+), 54 deletions(-) diff --git a/src/calibre/ebooks/metadata/sources/ozon.py b/src/calibre/ebooks/metadata/sources/ozon.py index 3845ebf97b..ebb104818f 100644 --- a/src/calibre/ebooks/metadata/sources/ozon.py +++ b/src/calibre/ebooks/metadata/sources/ozon.py @@ -54,30 +54,35 @@ class Ozon(Source): # for ozon.ru search we have to format ISBN with '-' isbn = _format_isbn(log, identifiers.get('isbn', None)) - # TODO: format isbn! - qItems = set([isbn, title]) - if authors: - qItems |= frozenset(authors) - qItems.discard(None) - qItems.discard('') - qItems = map(_quoteString, qItems) - - q = u' '.join(qItems).strip() - log.info(u'search string: ' + q) - - if isinstance(q, unicode): - q = q.encode('utf-8') - if not q: - return None - - search_url += quote_plus(q) + ozonid = identifiers.get('ozon', None) + + unk = unicode(_('Unknown')).upper() + if (title and title != unk) or (authors and authors != [unk]) or isbn or not ozonid: + qItems = set([isbn, title]) + if authors: + qItems |= frozenset(authors) + qItems.discard(None) + qItems.discard('') + qItems = map(_quoteString, qItems) + + q = u' '.join(qItems).strip() + log.info(u'search string: ' + q) + + if isinstance(q, unicode): + q = q.encode('utf-8') + if not q: + return None + + search_url += quote_plus(q) + else: + search_url = self.ozon_url + '/webservices/OzonWebSvc.asmx/ItemDetail?ID=%s' % ozonid + log.debug(u'search url: %r'%search_url) - return search_url # }}} def identify(self, log, result_queue, abort, title=None, authors=None, - identifiers={}, timeout=30): # {{{ + identifiers={}, timeout=60): # {{{ from lxml import etree from calibre.ebooks.chardet import xml_to_unicode @@ -99,7 +104,7 @@ class Ozon(Source): try: parser = etree.XMLParser(recover=True, no_network=True) feed = etree.fromstring(xml_to_unicode(raw, strip_encoding_pats=True, assume_utf8=True)[0], parser=parser) - entries = feed.xpath('//*[local-name() = "SearchItems"]') + entries = feed.xpath('//*[local-name()="SearchItems" or local-name()="ItemDetail"]') if entries: metadata = self.get_metadata(log, entries, title, authors, identifiers) self.get_all_details(log, metadata, abort, result_queue, identifiers, timeout) @@ -112,8 +117,8 @@ class Ozon(Source): def get_metadata(self, log, entries, title, authors, identifiers): # {{{ # some book titles have extra characters like this # TODO: make a twick - reRemoveFromTitle = None - #reRemoveFromTitle = re.compile(r'[?!:.,;+-/&%"\'=]') + #reRemoveFromTitle = None + reRemoveFromTitle = re.compile(r'[?!:.,;+-/&%"\'=]') title = unicode(title).upper() if title else '' if reRemoveFromTitle: @@ -163,7 +168,7 @@ class Ozon(Source): metadata.append(mi) #log.debug(u'added metadata %s %s.'%(mi.title, mi.authors)) else: - log.debug(u'skipped metadata %s %s. (does not match the query)'%(mi.title, mi.authors)) + log.debug(u'skipped metadata %s %s. (does not match the query)'%(unicode(mi.title), mi.authors)) return metadata # }}} @@ -301,7 +306,7 @@ class Ozon(Source): if series: metadata.series = series - xpt = u'normalize-space(substring-after(//meta[@name="description"]/@content, "ISBN"))' + xpt = u'normalize-space(//*[@class="product-detail"]//text()[starts-with(., "ISBN")])' isbn_str = doc.xpath(xpt) if isbn_str: all_isbns = [check_isbn(isbn) for isbn in self.isbnRegex.findall(isbn_str) if _verifyISBNIntegrity(log, isbn)] @@ -326,7 +331,7 @@ class Ozon(Source): # can be set before from xml search responce if not metadata.pubdate: - xpt = u'normalize-space(//div[@class="product-misc"]//text()[contains(., "г.")])' + xpt = u'normalize-space(substring-after(//div[@class="product-detail"]//text()[contains(., "г.")],";"))' yearIn = doc.xpath(xpt) if yearIn: matcher = re.search(r'\d{4}', yearIn) @@ -334,17 +339,20 @@ class Ozon(Source): metadata.pubdate = toPubdate(log, matcher.group(0)) # overwrite comments from HTML if any - xpt = u'//table[@id="detail_description"]//tr/td' + xpt = u'//*[@id="detail_description"]//*[contains(text(), "От производителя")]/../node()[not(self::comment())][not(self::br)][preceding::*[contains(text(), "От производителя")]]' + from lxml.etree import ElementBase comment_elem = doc.xpath(xpt) if comment_elem: - comments = unicode(etree.tostring(comment_elem[0], encoding=unicode)) - if comments: - # cleanup root tag, TODO: remove tags like object/embeded - comments = re.sub(ur'\A.*?|.*\Z', u'', comments.strip(), re.MULTILINE).strip() - if comments and (not metadata.comments or len(comments) > len(metadata.comments)): - metadata.comments = comments - else: - log.debug('HTML book description skipped in favour of search service xml responce') + comments = u'' + for node in comment_elem: + if isinstance(node, ElementBase): + comments += unicode(etree.tostring(node, encoding=unicode)) + elif isinstance(node, basestring) and node.strip(): + comments += unicode(node) + u'\n' + if comments and (not metadata.comments or len(comments) > len(metadata.comments)): + metadata.comments = comments + else: + log.debug('HTML book description skipped in favour of search service xml responce') else: log.debug('No book description found in HTML') # }}} @@ -430,7 +438,8 @@ def _translageLanguageToCode(displayLang): # {{{ u'Китайский': 'zh', u'Японский': 'ja', u'Финский' : 'fi', - u'Польский' : 'pl',} + u'Польский' : 'pl', + u'Украинский' : 'uk',} return langTbl.get(displayLang, None) # }}} @@ -454,7 +463,7 @@ def toPubdate(log, yearAsString): # {{{ res = None if yearAsString: try: - res = parse_only_date(yearAsString) + res = parse_only_date(u"01.01." + yearAsString) except: log.error('cannot parse to date %s'%yearAsString) return res diff --git a/src/calibre/gui2/store/stores/ozon_ru_plugin.py b/src/calibre/gui2/store/stores/ozon_ru_plugin.py index 5d977700c8..b54bf01daf 100644 --- a/src/calibre/gui2/store/stores/ozon_ru_plugin.py +++ b/src/calibre/gui2/store/stores/ozon_ru_plugin.py @@ -46,30 +46,37 @@ class OzonRUStore(BasicStoreConfig, StorePlugin): d.set_tags(self.config.get('tags', '')) d.exec_() - - def search(self, query, max_results=10, timeout=60): + def search(self, query, max_results=15, timeout=60): search_url = self.shop_url + '/webservice/webservice.asmx/SearchWebService?'\ 'searchText=%s&searchContext=ebook' % urllib2.quote(query) + search_urls = [ search_url ] + + ## add this as the fist try if it looks like ozon ID + if re.match("^\d{6,9}$", query): + ozon_detail = self.shop_url + '/webservices/OzonWebSvc.asmx/ItemDetail?ID=%s' % query + search_urls.insert(0, ozon_detail) + xp_template = 'normalize-space(./*[local-name() = "{0}"]/text())' - counter = max_results br = browser() - with closing(br.open(search_url, timeout=timeout)) as f: - raw = xml_to_unicode(f.read(), strip_encoding_pats=True, assume_utf8=True)[0] - doc = etree.fromstring(raw) - for data in doc.xpath('//*[local-name() = "SearchItems"]'): - if counter <= 0: - break - counter -= 1 + + for url in search_urls: + with closing(br.open(url, timeout=timeout)) as f: + raw = xml_to_unicode(f.read(), strip_encoding_pats=True, assume_utf8=True)[0] + doc = etree.fromstring(raw) + for data in doc.xpath('//*[local-name()="SearchItems" or local-name()="ItemDetail"]'): + if counter <= 0: + break + counter -= 1 - s = SearchResult() - s.detail_item = data.xpath(xp_template.format('ID')) - s.title = data.xpath(xp_template.format('Name')) - s.author = data.xpath(xp_template.format('Author')) - s.price = data.xpath(xp_template.format('Price')) - s.cover_url = data.xpath(xp_template.format('Picture')) - s.price = format_price_in_RUR(s.price) - yield s + s = SearchResult() + s.detail_item = data.xpath(xp_template.format('ID')) + s.title = data.xpath(xp_template.format('Name')) + s.author = data.xpath(xp_template.format('Author')) + s.price = data.xpath(xp_template.format('Price')) + s.cover_url = data.xpath(xp_template.format('Picture')) + s.price = format_price_in_RUR(s.price) + yield s def get_details(self, search_result, timeout=60): url = self.shop_url + '/context/detail/id/' + urllib2.quote(search_result.detail_item) @@ -97,6 +104,16 @@ class OzonRUStore(BasicStoreConfig, StorePlugin): search_result.formats = ', '.join(_parse_ebook_formats(formats)) # unfortunately no direct links to download books (only buy link) # search_result.downloads['BF2'] = self.shop_url + '/order/digitalorder.aspx?id=' + + urllib2.quote(search_result.detail_item) + + #

21500 руб.

+ # + # + + # if the price not in the search result (the ID search case) + if not search_result.price: + price = doc.xpath(u'normalize-space(//*[@itemprop="price"]/text())') + search_result.price = format_price_in_RUR(price) + return result def format_price_in_RUR(price): From e6788b5814226fc812447ca258c05c62c2baebbd Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 10:21:10 +0530 Subject: [PATCH 05/10] Update FHM UK --- recipes/fhm_uk.recipe | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/recipes/fhm_uk.recipe b/recipes/fhm_uk.recipe index 07f2b4b64e..6ee5ae3fb6 100644 --- a/recipes/fhm_uk.recipe +++ b/recipes/fhm_uk.recipe @@ -2,19 +2,19 @@ from calibre.web.feeds.news import BasicNewsRecipe class AdvancedUserRecipe1325006965(BasicNewsRecipe): title = u'FHM UK' - description = 'Good News for Men' + description = 'Good News for Men.' cover_url = 'http://www.greatmagazines.co.uk/covers/large/w197/current/fhm.jpg' # cover_url = 'http://profile.ak.fbcdn.net/hprofile-ak-snc4/373529_38324934806_64930243_n.jpg' masthead_url = 'http://www.fhm.com/App_Resources/Images/Site/re-design/logo.gif' __author__ = 'Dave Asbury' - # last updated 14/4/12 + # last updated 1/7/12 language = 'en_GB' oldest_article = 28 - max_articles_per_feed = 12 + max_articles_per_feed = 8 remove_empty_feeds = True no_stylesheets = True #auto_cleanup = True - #articles_are_obfuscated = True + # articles_are_obfuscated = True keep_only_tags = [ dict(name='h1'), dict(name='img',attrs={'id' : 'ctl00_Body_imgMainImage'}), @@ -28,11 +28,18 @@ class AdvancedUserRecipe1325006965(BasicNewsRecipe): #] feeds = [ - (u'From the Homepage',u'http://feed43.com/0032328550253453.xml'), - #http://feed43.com/8053226782885416.xml'), - (u'Funny - The Very Best Of The Internet',u'http://feed43.com/4538510106331565.xml'), - (u'Upgrade',u'http://feed43.com/0877305847443234.xml'), - #(u'The Final Countdown', u'http://feed43.com/3576106158530118.xml'), - #(u'Gaming',u'http://feed43.com/0755006465351035.xml'), - (u'Gaming',u'http://feed43.com/6537162612465672.xml'), + (u'Homepage 1',u'http://feed43.com/6655867614547036.xml'), + (u'Homepage 2',u'http://feed43.com/4167731873103110.xml'), + (u'Homepage 3',u'http://feed43.com/7667138788771570.xml'), + (u'Homepage 4',u'http://feed43.com/6550421522527341.xml'), + (u'Funny - The Very Best Of The Internet',u'http://feed43.com/4538510106331565.xml'), + (u'Gaming',u'http://feed43.com/6537162612465672.xml'), + (u'Girls',u'http://feed43.com/3674777224513254.xml'), ] + + extra_css = ''' + h1{font-family:Arial,Helvetica,sans-serif; font-weight:bold;font-size:large;} + h2{font-family:Arial,Helvetica,sans-serif; font-weight:normal;font-size:small;} + p{font-family:Arial,Helvetica,sans-serif;font-size:small;} + body{font-family:Helvetica,Arial,sans-serif;font-size:small;} + ''' From c8b5db52098f5a417ecf1f58343db1ef1d3c1668 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 14:12:28 +0530 Subject: [PATCH 06/10] Fix (I hope) crashes in MultiCompleteComboBox. Also the drop down arrow now only shows the items that start with whatever text is currently entered in the box --- src/calibre/gui2/complete.py | 43 ++++++++-------------- src/calibre/gui2/convert/metadata.py | 28 +++----------- src/calibre/gui2/custom_column_widgets.py | 30 ++------------- src/calibre/gui2/dialogs/add_empty_book.py | 12 +----- src/calibre/gui2/dialogs/metadata_bulk.py | 19 ++-------- src/calibre/gui2/dialogs/search.py | 9 +---- src/calibre/gui2/languages.py | 2 - src/calibre/gui2/library/delegates.py | 4 -- src/calibre/gui2/metadata/basic_widgets.py | 43 ++++++---------------- 9 files changed, 41 insertions(+), 149 deletions(-) diff --git a/src/calibre/gui2/complete.py b/src/calibre/gui2/complete.py index fb1f39dfa3..9d78003231 100644 --- a/src/calibre/gui2/complete.py +++ b/src/calibre/gui2/complete.py @@ -7,7 +7,7 @@ __docformat__ = 'restructuredtext en' from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt, - QApplication, QCompleter, pyqtSignal) + QApplication, QCompleter) from calibre.utils.icu import sort_key, lower from calibre.gui2 import NONE @@ -56,7 +56,7 @@ class MultiCompleteLineEdit(QLineEdit, LineEditECM): to complete non multiple fields as well. ''' - def __init__(self, parent=None): + def __init__(self, parent=None, completer_widget=None): QLineEdit.__init__(self, parent) self.sep = ',' @@ -66,7 +66,7 @@ class MultiCompleteLineEdit(QLineEdit, LineEditECM): self._model = CompleteModel(parent=self) self._completer = c = QCompleter(self._model, self) - c.setWidget(self) + c.setWidget(self if completer_widget is None else completer_widget) c.setCompletionMode(QCompleter.PopupCompletion) c.setCaseSensitivity(Qt.CaseInsensitive) c.setModelSorting(self._model.sorting) @@ -158,21 +158,13 @@ class MultiCompleteLineEdit(QLineEdit, LineEditECM): class MultiCompleteComboBox(EnComboBox): - clear_edit_text = pyqtSignal() - def __init__(self, *args): EnComboBox.__init__(self, *args) - self.setLineEdit(MultiCompleteLineEdit(self)) - # Needed to allow changing the case of an existing item - # otherwise on focus out, the text is changed to the - # item that matches case insensitively - c = self.lineEdit().completer() - c.setCaseSensitivity(Qt.CaseSensitive) - self.dummy_model = CompleteModel(self) - c.setModel(self.dummy_model) - self.lineEdit()._completer.setWidget(self) - self.clear_edit_text.connect(self.clearEditText, - type=Qt.QueuedConnection) + self.le = MultiCompleteLineEdit(self, completer_widget=self) + self.setLineEdit(self.le) + + def showPopup(self): + self.le._completer.complete() def update_items_cache(self, complete_items): self.lineEdit().update_items_cache(complete_items) @@ -187,18 +179,10 @@ class MultiCompleteComboBox(EnComboBox): self.lineEdit().set_add_separator(what) def show_initial_value(self, what): - ''' - Show an initial value. Handle the case of the initial value being blank - correctly (on Qt 4.8.0 having a blank value causes the first value from - the completer to be shown, when the event loop runs). - ''' - what = unicode(what) + what = unicode(what) if what else u'' le = self.lineEdit() - if not what.strip(): - self.clear_edit_text.emit() - else: - self.setEditText(what) - le.selectAll() + self.setEditText(what) + le.selectAll() if __name__ == '__main__': from PyQt4.Qt import QDialog, QVBoxLayout @@ -207,5 +191,8 @@ if __name__ == '__main__': d.setLayout(QVBoxLayout()) le = MultiCompleteComboBox(d) d.layout().addWidget(le) - le.all_items = ['one', 'otwo', 'othree', 'ooone', 'ootwo', 'oothree'] + items = ['one', 'otwo', 'othree', 'ooone', 'ootwo', + 'oothree'] + le.update_items_cache(items) + le.show_initial_value('') d.exec_() diff --git a/src/calibre/gui2/convert/metadata.py b/src/calibre/gui2/convert/metadata.py index ba2fa0713e..3643e5548e 100644 --- a/src/calibre/gui2/convert/metadata.py +++ b/src/calibre/gui2/convert/metadata.py @@ -12,8 +12,8 @@ from PyQt4.Qt import QPixmap, SIGNAL from calibre.gui2 import choose_images, error_dialog from calibre.gui2.convert.metadata_ui import Ui_Form -from calibre.ebooks.metadata import (authors_to_string, string_to_authors, - MetaInformation, title_sort) +from calibre.ebooks.metadata import (string_to_authors, MetaInformation, + title_sort) from calibre.ebooks.metadata.opf2 import metadata_to_opf from calibre.ptempfile import PersistentTemporaryFile from calibre.gui2.convert import Widget @@ -74,14 +74,12 @@ class MetadataWidget(Widget, Ui_Form): mi = self.db.get_metadata(self.book_id, index_is_id=True) self.title.setText(mi.title) - if mi.publisher: - self.publisher.setCurrentIndex(self.publisher.findText(mi.publisher)) + self.publisher.show_initial_value(mi.publisher if mi.publisher else '') self.author_sort.setText(mi.author_sort if mi.author_sort else '') self.tags.setText(', '.join(mi.tags if mi.tags else [])) self.tags.update_items_cache(self.db.all_tags()) self.comment.html = comments_to_html(mi.comments) if mi.comments else '' - if mi.series: - self.series.setCurrentIndex(self.series.findText(mi.series)) + self.series.show_initial_value(mi.series if mi.series else '') if mi.series_index is not None: try: self.series_index.setValue(mi.series_index) @@ -118,16 +116,11 @@ class MetadataWidget(Widget, Ui_Form): self.author.set_add_separator(tweaks['authors_completer_append_separator']) self.author.update_items_cache(self.db.all_author_names()) - for i in all_authors: - id, name = i - name = authors_to_string([name.strip().replace('|', ',') for n in name.split(',')]) - self.author.addItem(name) - au = self.db.authors(self.book_id, True) if not au: au = _('Unknown') au = ' & '.join([a.strip().replace('|', ',') for a in au.split(',')]) - self.author.setEditText(au) + self.author.show_initial_value(au) def initialize_series(self): all_series = self.db.all_series() @@ -135,22 +128,12 @@ class MetadataWidget(Widget, Ui_Form): self.series.set_separator(None) self.series.update_items_cache([x[1] for x in all_series]) - for i in all_series: - id, name = i - self.series.addItem(name) - self.series.setCurrentIndex(-1) - def initialize_publisher(self): all_publishers = self.db.all_publishers() all_publishers.sort(key=lambda x : sort_key(x[1])) self.publisher.set_separator(None) self.publisher.update_items_cache([x[1] for x in all_publishers]) - for i in all_publishers: - id, name = i - self.publisher.addItem(name) - self.publisher.setCurrentIndex(-1) - def get_title_and_authors(self): title = unicode(self.title.text()).strip() if not title: @@ -179,6 +162,7 @@ class MetadataWidget(Widget, Ui_Form): if tags: mi.tags = tags + print (mi) return mi def select_cover(self): diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index 654a9f4b5b..c9c8255076 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -314,14 +314,7 @@ class Text(Base): if self.col_metadata['is_multiple']: self.setter(val) else: - idx = None - for i, c in enumerate(values): - if c == val: - idx = i - self.widgets[1].addItem(c) - self.widgets[1].setEditText('') - if idx is not None: - self.widgets[1].setCurrentIndex(idx) + self.widgets[1].show_initial_value(val) def setter(self, val): if self.col_metadata['is_multiple']: @@ -396,16 +389,8 @@ class Series(Base): self.initial_index = s_index self.initial_val = val val = self.normalize_db_val(val) - idx = None - self.name_widget.clear() - for i, c in enumerate(values): - if c == val: - idx = i - self.name_widget.addItem(c) self.name_widget.update_items_cache(values) - self.name_widget.setEditText('') - if idx is not None: - self.widgets[1].setCurrentIndex(idx) + self.name_widget.show_initial_value(val) def getter(self): n = unicode(self.name_widget.currentText()).strip() @@ -860,8 +845,6 @@ class BulkSeries(BulkBase): self.idx_widget.setChecked(False) self.main_widget.set_separator(None) self.main_widget.update_items_cache(self.all_values) - for c in self.all_values: - self.main_widget.addItem(c) self.main_widget.setEditText('') self.a_c_checkbox.setChecked(False) @@ -1005,15 +988,8 @@ class BulkText(BulkBase): if not self.col_metadata['is_multiple']: val = self.get_initial_value(book_ids) self.initial_val = val = self.normalize_db_val(val) - idx = None self.main_widget.blockSignals(True) - for i, c in enumerate(self.all_values): - if c == val: - idx = i - self.main_widget.addItem(c) - self.main_widget.setEditText('') - if idx is not None: - self.main_widget.setCurrentIndex(idx) + self.main_widget.show_initial_value(val) self.main_widget.blockSignals(False) def commit(self, book_ids, notify=False): diff --git a/src/calibre/gui2/dialogs/add_empty_book.py b/src/calibre/gui2/dialogs/add_empty_book.py index d4990e14d4..218bd90483 100644 --- a/src/calibre/gui2/dialogs/add_empty_book.py +++ b/src/calibre/gui2/dialogs/add_empty_book.py @@ -6,8 +6,7 @@ __license__ = 'GPL v3' from PyQt4.Qt import QDialog, QGridLayout, QLabel, QDialogButtonBox, \ QApplication, QSpinBox, QToolButton, QIcon -from calibre.ebooks.metadata import authors_to_string, string_to_authors -from calibre.utils.icu import sort_key +from calibre.ebooks.metadata import string_to_authors from calibre.gui2.complete import MultiCompleteComboBox from calibre.utils.config import tweaks @@ -56,17 +55,10 @@ class AddEmptyBookDialog(QDialog): self.authors_combo.setEditText(_('Unknown')) def initialize_authors(self, db, author): - all_authors = db.all_authors() - all_authors.sort(key=lambda x : sort_key(x[1])) - for i in all_authors: - id, name = i - name = [name.strip().replace('|', ',') for n in name.split(',')] - self.authors_combo.addItem(authors_to_string(name)) - au = author if not au: au = _('Unknown') - self.authors_combo.setEditText(au.replace('|', ',')) + self.authors_combo.show_initial_value(au.replace('|', ',')) self.authors_combo.set_separator('&') self.authors_combo.set_space_before_sep(True) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index 09a244debd..b8f30f3541 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -876,38 +876,25 @@ class MetadataBulkDialog(ResizableDialog, Ui_MetadataBulkDialog): all_authors = self.db.all_authors() all_authors.sort(key=lambda x : sort_key(x[1])) - for i in all_authors: - id, name = i - name = name.strip().replace('|', ',') - self.authors.addItem(name) - self.authors.setEditText('') - self.authors.set_separator('&') self.authors.set_space_before_sep(True) self.authors.set_add_separator(tweaks['authors_completer_append_separator']) self.authors.update_items_cache(self.db.all_author_names()) + self.authors.show_initial_value('') def initialize_series(self): all_series = self.db.all_series() all_series.sort(key=lambda x : sort_key(x[1])) self.series.set_separator(None) self.series.update_items_cache([x[1] for x in all_series]) - - for i in all_series: - id, name = i - self.series.addItem(name) - self.series.setEditText('') + self.series.show_initial_value('') def initialize_publisher(self): all_publishers = self.db.all_publishers() all_publishers.sort(key=lambda x : sort_key(x[1])) self.publisher.set_separator(None) self.publisher.update_items_cache([x[1] for x in all_publishers]) - - for i in all_publishers: - id, name = i - self.publisher.addItem(name) - self.publisher.setEditText('') + self.publisher.show_initial_value('') def tag_editor(self, *args): d = TagEditor(self, self.db, None) diff --git a/src/calibre/gui2/dialogs/search.py b/src/calibre/gui2/dialogs/search.py index 8736ae2259..cf63d150e6 100644 --- a/src/calibre/gui2/dialogs/search.py +++ b/src/calibre/gui2/dialogs/search.py @@ -25,10 +25,6 @@ class SearchDialog(QDialog, Ui_Dialog): all_authors = db.all_authors() all_authors.sort(key=lambda x : sort_key(x[1])) - for i in all_authors: - id, name = i - name = name.strip().replace('|', ',') - self.authors_box.addItem(name) self.authors_box.setEditText('') self.authors_box.set_separator('&') self.authors_box.set_space_before_sep(True) @@ -39,10 +35,7 @@ class SearchDialog(QDialog, Ui_Dialog): all_series.sort(key=lambda x : sort_key(x[1])) self.series_box.set_separator(None) self.series_box.update_items_cache([x[1] for x in all_series]) - for i in all_series: - id, name = i - self.series_box.addItem(name) - self.series_box.setEditText('') + self.series_box.show_initial_value('') all_tags = db.all_tags() self.tags_box.update_items_cache(all_tags) diff --git a/src/calibre/gui2/languages.py b/src/calibre/gui2/languages.py index 0dfbb38b08..f067027097 100644 --- a/src/calibre/gui2/languages.py +++ b/src/calibre/gui2/languages.py @@ -32,8 +32,6 @@ class LanguagesEdit(MultiCompleteComboBox): all_items = sorted(self._lang_map.itervalues(), key=lambda x: (-pmap.get(x, 0), sort_key(x))) self.update_items_cache(all_items) - for item in all_items: - self.addItem(item) @property def vals(self): diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 60b8e3445d..77c3152842 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -125,8 +125,6 @@ class TextDelegate(QStyledItemDelegate): # {{{ editor.set_separator(None) complete_items = [i[1] for i in self.auto_complete_function()] editor.update_items_cache(complete_items) - for item in sorted(complete_items, key=sort_key): - editor.addItem(item) ct = index.data(Qt.DisplayRole).toString() editor.show_initial_value(ct) else: @@ -166,8 +164,6 @@ class CompleteDelegate(QStyledItemDelegate): # {{{ all_items = list(self.db.all_custom( label=self.db.field_metadata.key_to_label(col))) editor.update_items_cache(all_items) - for item in sorted(all_items, key=sort_key): - editor.addItem(item) ct = index.data(Qt.DisplayRole).toString() editor.show_initial_value(ct) else: diff --git a/src/calibre/gui2/metadata/basic_widgets.py b/src/calibre/gui2/metadata/basic_widgets.py index 250d4ffad2..d2a983415f 100644 --- a/src/calibre/gui2/metadata/basic_widgets.py +++ b/src/calibre/gui2/metadata/basic_widgets.py @@ -246,14 +246,6 @@ class AuthorsEdit(MultiCompleteComboBox): def initialize(self, db, id_): self.books_to_refresh = set([]) - all_authors = db.all_authors() - all_authors.sort(key=lambda x : sort_key(x[1])) - self.clear() - for i in all_authors: - id, name = i - name = name.strip().replace('|', ',') - self.addItem(name) - self.set_separator('&') self.set_space_before_sep(True) self.set_add_separator(tweaks['authors_completer_append_separator']) @@ -299,7 +291,6 @@ class AuthorsEdit(MultiCompleteComboBox): self.setEditText(' & '.join([x.strip() for x in val])) self.lineEdit().setCursorPosition(0) - return property(fget=fget, fset=fset) def break_cycles(self): @@ -488,19 +479,12 @@ class SeriesEdit(MultiCompleteComboBox): all_series.sort(key=lambda x : sort_key(x[1])) self.update_items_cache([x[1] for x in all_series]) series_id = db.series_id(id_, index_is_id=True) - idx, c = None, 0 - self.clear() + inval = '' for i in all_series: - id, name = i - if id == series_id: - idx = c - self.addItem(name) - c += 1 - - self.lineEdit().setText('') - if idx is not None: - self.setCurrentIndex(idx) - self.original_val = self.current_val + if i[0] == series_id: + inval = i[1] + break + self.original_val = self.current_val = inval def commit(self, db, id_): series = self.current_val @@ -1373,17 +1357,12 @@ class PublisherEdit(MultiCompleteComboBox): # {{{ all_publishers.sort(key=lambda x : sort_key(x[1])) self.update_items_cache([x[1] for x in all_publishers]) publisher_id = db.publisher_id(id_, index_is_id=True) - idx = None - self.clear() - for i, x in enumerate(all_publishers): - id_, name = x - if id_ == publisher_id: - idx = i - self.addItem(name) - - self.setEditText('') - if idx is not None: - self.setCurrentIndex(idx) + inval = '' + for pid, name in all_publishers: + if pid == publisher_id: + inval = name + break + self.original_val = self.current_val = inval def commit(self, db, id_): self.books_to_refresh |= db.set_publisher(id_, self.current_val, From 7ace9fafb29b20a335fc41f98f65c25a2e1d57c5 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 14:15:48 +0530 Subject: [PATCH 07/10] ... --- setup/installer/windows/notes.rst | 2 +- src/calibre/gui2/convert/metadata.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/setup/installer/windows/notes.rst b/setup/installer/windows/notes.rst index 0a9c904ff7..f987f83a3b 100644 --- a/setup/installer/windows/notes.rst +++ b/setup/installer/windows/notes.rst @@ -97,7 +97,7 @@ Now, run configure and make:: -no-plugin-manifests is needed so that loading the plugins does not fail looking for the CRT assembly - configure -opensource -release -qt-zlib -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs -no-plugin-manifests -openssl -I Q:\openssl\include -L Q:\openssl\lib && nmake + configure -ltcg -opensource -release -qt-zlib -qt-libmng -qt-libpng -qt-libtiff -qt-libjpeg -release -platform win32-msvc2008 -no-qt3support -webkit -xmlpatterns -no-phonon -no-style-plastique -no-style-cleanlooks -no-style-motif -no-style-cde -no-declarative -no-scripttools -no-audio-backend -no-multimedia -no-dbus -no-openvg -no-opengl -no-qt3support -confirm-license -nomake examples -nomake demos -nomake docs -no-plugin-manifests -openssl -I Q:\openssl\include -L Q:\openssl\lib && nmake Add the path to the bin folder inside the Qt dir to your system PATH. diff --git a/src/calibre/gui2/convert/metadata.py b/src/calibre/gui2/convert/metadata.py index 3643e5548e..6d43abdf63 100644 --- a/src/calibre/gui2/convert/metadata.py +++ b/src/calibre/gui2/convert/metadata.py @@ -162,7 +162,6 @@ class MetadataWidget(Widget, Ui_Form): if tags: mi.tags = tags - print (mi) return mi def select_cover(self): From 31e3a273927c8da0d31489b5c7db29db699bfb90 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 14:31:19 +0530 Subject: [PATCH 08/10] Create separate driver for Pocketbook 622 rather than using Android driver --- resources/compiled_coffeescript.zip | Bin 43332 -> 43332 bytes src/calibre/customize/builtins.py | 4 ++-- src/calibre/devices/android/driver.py | 1 - src/calibre/devices/eb600/driver.py | 13 +++++++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/resources/compiled_coffeescript.zip b/resources/compiled_coffeescript.zip index ae77254da8f689bd2542197920179ffd126ff5c8..d7fad735ba651cfe4b99775b7f301581150e1182 100644 GIT binary patch delta 32 kcmX?diRs8CCf)#VW)=|!5cpg8Xd`dn3T7ZZIdR2f0Jt;^%>V!Z delta 32 kcmX?diRs8CCf)#VW)=|!5V% Date: Mon, 2 Jul 2012 16:09:44 +0530 Subject: [PATCH 09/10] ... --- src/calibre/gui2/complete.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/calibre/gui2/complete.py b/src/calibre/gui2/complete.py index 9d78003231..e66255cc05 100644 --- a/src/calibre/gui2/complete.py +++ b/src/calibre/gui2/complete.py @@ -164,7 +164,13 @@ class MultiCompleteComboBox(EnComboBox): self.setLineEdit(self.le) def showPopup(self): - self.le._completer.complete() + c = self.le._completer + c.setCompletionPrefix('') + c.complete() + + def hidePopup(self): + self.le.update_completions() + EnComboBox.hidePopup(self) def update_items_cache(self, complete_items): self.lineEdit().update_items_cache(complete_items) From 0201e87440d9a089cd6c6f728a7fc8223837bb48 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 2 Jul 2012 16:15:22 +0530 Subject: [PATCH 10/10] ... --- src/calibre/gui2/complete.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/calibre/gui2/complete.py b/src/calibre/gui2/complete.py index e66255cc05..947493cbb9 100644 --- a/src/calibre/gui2/complete.py +++ b/src/calibre/gui2/complete.py @@ -168,10 +168,6 @@ class MultiCompleteComboBox(EnComboBox): c.setCompletionPrefix('') c.complete() - def hidePopup(self): - self.le.update_completions() - EnComboBox.hidePopup(self) - def update_items_cache(self, complete_items): self.lineEdit().update_items_cache(complete_items)