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;}
+ '''
diff --git a/resources/compiled_coffeescript.zip b/resources/compiled_coffeescript.zip
index ae77254da8..d7fad735ba 100644
Binary files a/resources/compiled_coffeescript.zip and b/resources/compiled_coffeescript.zip differ
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/customize/builtins.py b/src/calibre/customize/builtins.py
index 495d923289..af5bfc74fb 100644
--- a/src/calibre/customize/builtins.py
+++ b/src/calibre/customize/builtins.py
@@ -643,7 +643,7 @@ from calibre.devices.cybook.driver import CYBOOK, ORIZON
from calibre.devices.eb600.driver import (EB600, COOL_ER, SHINEBOOK,
POCKETBOOK360, GER2, ITALICA, ECLICTO, DBOOK, INVESBOOK,
BOOQ, ELONEX, POCKETBOOK301, MENTOR, POCKETBOOK602,
- POCKETBOOK701, POCKETBOOK360P, PI2)
+ POCKETBOOK701, POCKETBOOK360P, PI2, POCKETBOOK622)
from calibre.devices.iliad.driver import ILIAD
from calibre.devices.irexdr.driver import IREXDR1000, IREXDR800
from calibre.devices.jetbook.driver import (JETBOOK, MIBUK, JETBOOK_MINI,
@@ -689,7 +689,7 @@ plugins += [
JETBOOK, JETBOOK_MINI, MIBUK, JETBOOK_COLOR,
SHINEBOOK,
POCKETBOOK360, POCKETBOOK301, POCKETBOOK602, POCKETBOOK701, POCKETBOOK360P,
- PI2,
+ POCKETBOOK622, PI2,
KINDLE, KINDLE2, KINDLE_DX, KINDLE_FIRE,
NOOK, NOOK_COLOR,
PRS505, PRST1,
diff --git a/src/calibre/devices/android/driver.py b/src/calibre/devices/android/driver.py
index 2abfd9bbe9..822b309619 100644
--- a/src/calibre/devices/android/driver.py
+++ b/src/calibre/devices/android/driver.py
@@ -115,7 +115,6 @@ class ANDROID(USBMS):
0xc004 : [0x0226],
0x8801 : [0x0226, 0x0227],
0xe115 : [0x0216], # PocketBook A10
- 0xe107 : [0x326], # PocketBook 622
},
# Acer
diff --git a/src/calibre/devices/apple/driver.py b/src/calibre/devices/apple/driver.py
index 929c7b9ba0..fffe34ad34 100644
--- a/src/calibre/devices/apple/driver.py
+++ b/src/calibre/devices/apple/driver.py
@@ -828,7 +828,15 @@ class ITUNES(DriverBase):
if DEBUG:
logger().info("ITUNES.get_file(): exporting '%s'" % path)
- outfile.write(open(self.cached_books[path]['lib_book'].location().path).read())
+ try:
+ outfile.write(open(self.cached_books[path]['lib_book'].location().path).read())
+ except:
+ # Clean up
+ logger().info(" unable to extract books from iDevices")
+ logger().info(" deleting empty ", outfile.name)
+ outfile.close()
+ os.remove(outfile.name)
+ raise UserFeedback("Unable to extract books from iDevices", details=None, level=UserFeedback.WARN)
def open(self, connected_device, library_uuid):
'''
diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py
index 74c98b3716..4cf9ee5cf9 100644
--- a/src/calibre/devices/eb600/driver.py
+++ b/src/calibre/devices/eb600/driver.py
@@ -251,6 +251,19 @@ class POCKETBOOK602(USBMS):
WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['PB602', 'PB603', 'PB902',
'PB903', 'PB']
+class POCKETBOOK622(POCKETBOOK602):
+
+ name = 'PocketBook 622 Device Interface'
+ description = _('Communicate with the PocketBook 622 reader.')
+ EBOOK_DIR_MAIN = ''
+
+ VENDOR_ID = [0x0489]
+ PRODUCT_ID = [0xe107]
+ BCD = [0x0326]
+
+ VENDOR_NAME = 'LINUX'
+ WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = 'FILE-STOR_GADGET'
+
class POCKETBOOK360P(POCKETBOOK602):
name = 'PocketBook 360+ Device Interface'
diff --git a/src/calibre/devices/user_defined/driver.py b/src/calibre/devices/user_defined/driver.py
index 6c4e1f77d9..a88264c517 100644
--- a/src/calibre/devices/user_defined/driver.py
+++ b/src/calibre/devices/user_defined/driver.py
@@ -66,6 +66,9 @@ class USER_DEFINED(USBMS):
_('Card A folder') + ':::
' +
_('Enter the folder where the books are to be stored. This folder '
'is prepended to any send_to_device template') + '
',
+ _('Swap main and card A') + ':::' +
+ _('Check this box if the device\'s main memory is being seen as '
+ 'card a and the card is being seen as main memory') + '
',
]
EXTRA_CUSTOMIZATION_DEFAULT = [
'0xffff',
@@ -78,16 +81,19 @@ class USER_DEFINED(USBMS):
'',
'',
'',
+ False,
]
OPT_USB_VENDOR_ID = 0
OPT_USB_PRODUCT_ID = 1
OPT_USB_REVISION_ID = 2
+ # OPT 3 isn't used
OPT_USB_WINDOWS_MM_VEN_ID = 4
OPT_USB_WINDOWS_MM_ID = 5
OPT_USB_WINDOWS_CA_VEN_ID = 6
OPT_USB_WINDOWS_CA_ID = 7
OPT_MAIN_MEM_FOLDER = 8
OPT_CARD_A_FOLDER = 9
+ OPT_SWAP_MAIN_AND_CARD = 10
def initialize(self):
self.plugin_needs_delayed_initialization = True
@@ -113,4 +119,41 @@ class USER_DEFINED(USBMS):
traceback.print_exc()
self.plugin_needs_delayed_initialization = False
+ def windows_sort_drives(self, drives):
+ if len(drives) < 2: return drives
+ e = self.settings().extra_customization
+ if not e[self.OPT_SWAP_MAIN_AND_CARD]:
+ return drives
+ main = drives.get('main', None)
+ carda = drives.get('carda', None)
+ if main and carda:
+ drives['main'] = carda
+ drives['carda'] = main
+ return drives
+
+ def linux_swap_drives(self, drives):
+ if len(drives) < 2 or not drives[1] or not drives[2]: return drives
+ e = self.settings().extra_customization
+ if not e[self.OPT_SWAP_MAIN_AND_CARD]:
+ return drives
+ drives = list(drives)
+ t = drives[0]
+ drives[0] = drives[1]
+ drives[1] = t
+ return tuple(drives)
+
+ def osx_sort_names(self, names):
+ if len(names) < 2: return names
+ e = self.settings().extra_customization
+ if not e[self.OPT_SWAP_MAIN_AND_CARD]:
+ return names
+ main = names.get('main', None)
+ card = names.get('carda', None)
+
+ if main is not None and card is not None:
+ names['main'] = card
+ names['carda'] = main
+
+ return names
+
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/complete.py b/src/calibre/gui2/complete.py
index fb1f39dfa3..5aa3d5af9b 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,25 @@ 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):
+ c = self.le._completer
+ v = c.currentCompletion()
+ c.setCompletionPrefix('')
+ c.complete()
+ cs = c.caseSensitivity()
+ i = 0
+ while c.setCurrentRow(i):
+ cr = c.currentIndex().data().toString()
+ if cr.startsWith(v, cs):
+ c.popup().setCurrentIndex(c.currentIndex())
+ return
+ i += 1
+ c.setCurrentRow(0)
def update_items_cache(self, complete_items):
self.lineEdit().update_items_cache(complete_items)
@@ -187,18 +191,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 +203,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..6d43abdf63 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:
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,
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 руб.
+ #215.00
+ #
+
+ # 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):
diff --git a/src/calibre/library/server/mobile.py b/src/calibre/library/server/mobile.py
index eef131e89f..aa98412d27 100644
--- a/src/calibre/library/server/mobile.py
+++ b/src/calibre/library/server/mobile.py
@@ -97,6 +97,7 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS,
search_box = build_search_box(num, search, sort, order, prefix)
navigation = build_navigation(start, num, total, prefix+url_base)
+ navigation2 = build_navigation(start, num, total, prefix+url_base)
bookt = TABLE(id='listing')
body = BODY(
@@ -104,7 +105,9 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS,
search_box,
navigation,
HR(CLASS('spacer')),
- bookt
+ bookt,
+ HR(CLASS('spacer')),
+ navigation2
)
# Book list {{{
@@ -155,7 +158,6 @@ def build_index(books, num, search, sort, order, start, total, url_base, CKEYS,
bookt.append(TR(thumbnail, data))
# }}}
- body.append(HR())
body.append(DIV(
A(_('Switch to the full interface (non-mobile interface)'),
href=prefix+"/browse",
diff --git a/src/calibre/linux.py b/src/calibre/linux.py
index f1a53603e7..90cacd0180 100644
--- a/src/calibre/linux.py
+++ b/src/calibre/linux.py
@@ -354,8 +354,8 @@ class PostInstall:
check_call('xdg-icon-resource install --noupdate --context mimetypes --size 128 calibre-lrf.png text-lrs', shell=True)
self.icon_resources.append(('mimetypes', 'application-lrs',
'128'))
- render_img('lt.png', 'calibre-gui.png')
- check_call('xdg-icon-resource install --noupdate --size 128 calibre-gui.png calibre-gui', shell=True)
+ render_img('lt.png', 'calibre-gui.png', width=256, height=256)
+ check_call('xdg-icon-resource install --noupdate --size 256 calibre-gui.png calibre-gui', shell=True)
self.icon_resources.append(('apps', 'calibre-gui', '128'))
render_img('viewer.png', 'calibre-viewer.png')
check_call('xdg-icon-resource install --size 128 calibre-viewer.png calibre-viewer', shell=True)