Merge from trunk

This commit is contained in:
Charles Haley 2011-12-07 16:57:45 +01:00
commit ad23762ae6
15 changed files with 84 additions and 23 deletions

View File

@ -131,7 +131,7 @@ class ZeitEPUBAbo(BasicNewsRecipe):
browser.form['pass']=self.password browser.form['pass']=self.password
browser.submit() browser.submit()
# now find the correct file, we will still use the ePub file # now find the correct file, we will still use the ePub file
epublink = browser.find_link(text_regex=re.compile('.*Ausgabe als Datei im ePub-Format.*')) epublink = browser.find_link(text_regex=re.compile('.*Download als Datei im ePub-Format für eReader.*'))
response = browser.follow_link(epublink) response = browser.follow_link(epublink)
self.report_progress(1,_('next step')) self.report_progress(1,_('next step'))

View File

@ -224,7 +224,7 @@ class TREKSTOR(USBMS):
FORMATS = ['epub', 'txt', 'pdf'] FORMATS = ['epub', 'txt', 'pdf']
VENDOR_ID = [0x1e68] VENDOR_ID = [0x1e68]
PRODUCT_ID = [0x0041, 0x0042, 0x0052, PRODUCT_ID = [0x0041, 0x0042, 0x0052, 0x004e,
0x003e # This is for the EBOOK_PLAYER_5M https://bugs.launchpad.net/bugs/792091 0x003e # This is for the EBOOK_PLAYER_5M https://bugs.launchpad.net/bugs/792091
] ]
BCD = [0x0002] BCD = [0x0002]

View File

@ -30,6 +30,8 @@ CONTENT_TAGS = set(['img', 'hr', 'br'])
NOT_VTAGS = HEADER_TAGS | NESTABLE_TAGS | TABLE_TAGS | SPECIAL_TAGS | \ NOT_VTAGS = HEADER_TAGS | NESTABLE_TAGS | TABLE_TAGS | SPECIAL_TAGS | \
CONTENT_TAGS CONTENT_TAGS
LEAF_TAGS = set(['base', 'basefont', 'frame', 'link', 'meta', 'area', 'br',
'col', 'hr', 'img', 'input', 'param'])
PAGE_BREAKS = set(['always', 'left', 'right']) PAGE_BREAKS = set(['always', 'left', 'right'])
COLLAPSE = re.compile(r'[ \t\r\n\v]+') COLLAPSE = re.compile(r'[ \t\r\n\v]+')
@ -246,7 +248,17 @@ class MobiMLizer(object):
last.text = None last.text = None
else: else:
last = bstate.body[-1] last = bstate.body[-1]
last.addprevious(anchor) # We use append instead of addprevious so that inline
# anchors in large blocks point to the correct place. See
# https://bugs.launchpad.net/calibre/+bug/899831
# This could potentially break if inserting an anchor at
# this point in the markup is illegal, but I cannot think
# of such a case offhand.
if barename(last.tag) in LEAF_TAGS:
last.addprevious(anchor)
else:
last.append(anchor)
istate.ids.clear() istate.ids.clear()
if not text: if not text:
return return
@ -528,7 +540,11 @@ class MobiMLizer(object):
old_mim = self.opts.mobi_ignore_margins old_mim = self.opts.mobi_ignore_margins
self.opts.mobi_ignore_margins = False self.opts.mobi_ignore_margins = False
if text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS: if (text or tag in CONTENT_TAGS or tag in NESTABLE_TAGS or (
# We have an id but no text and no children, the id should still
# be added.
istate.ids and tag in ('a', 'span', 'i', 'b', 'u') and
len(elem)==0)):
self.mobimlize_content(tag, text, bstate, istates) self.mobimlize_content(tag, text, bstate, istates)
for child in elem: for child in elem:
self.mobimlize_elem(child, stylizer, bstate, istates) self.mobimlize_elem(child, stylizer, bstate, istates)

View File

@ -18,7 +18,8 @@ from calibre.ebooks.chardet import xml_to_unicode
from calibre.utils.zipfile import safe_replace from calibre.utils.zipfile import safe_replace
from calibre.utils.config import DynamicConfig from calibre.utils.config import DynamicConfig
from calibre.utils.logging import Log from calibre.utils.logging import Log
from calibre import guess_type, prints, prepare_string_for_xml from calibre import (guess_type, prints, prepare_string_for_xml,
xml_replace_entities)
from calibre.ebooks.oeb.transforms.cover import CoverManager from calibre.ebooks.oeb.transforms.cover import CoverManager
from calibre.constants import filesystem_encoding from calibre.constants import filesystem_encoding
@ -96,13 +97,19 @@ class EbookIterator(object):
self.ebook_ext = ext.replace('original_', '') self.ebook_ext = ext.replace('original_', '')
def search(self, text, index, backwards=False): def search(self, text, index, backwards=False):
text = text.lower() text = prepare_string_for_xml(text.lower())
pmap = [(i, path) for i, path in enumerate(self.spine)] pmap = [(i, path) for i, path in enumerate(self.spine)]
if backwards: if backwards:
pmap.reverse() pmap.reverse()
for i, path in pmap: for i, path in pmap:
if (backwards and i < index) or (not backwards and i > index): if (backwards and i < index) or (not backwards and i > index):
if text in open(path, 'rb').read().decode(path.encoding).lower(): with open(path, 'rb') as f:
raw = f.read().decode(path.encoding)
try:
raw = xml_replace_entities(raw)
except:
pass
if text in raw.lower():
return i return i
def find_missing_css_files(self): def find_missing_css_files(self):

View File

@ -9,7 +9,7 @@ from PyQt4.Qt import QThread, QObject, Qt, QProgressDialog, pyqtSignal, QTimer
from calibre.gui2.dialogs.progress import ProgressDialog from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.gui2 import (question_dialog, error_dialog, info_dialog, gprefs, from calibre.gui2 import (question_dialog, error_dialog, info_dialog, gprefs,
warning_dialog) warning_dialog, available_width)
from calibre.ebooks.metadata.opf2 import OPF from calibre.ebooks.metadata.opf2 import OPF
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
from calibre.constants import preferred_encoding, filesystem_encoding, DEBUG from calibre.constants import preferred_encoding, filesystem_encoding, DEBUG
@ -244,6 +244,7 @@ class Adder(QObject): # {{{
def __init__(self, parent, db, callback, spare_server=None): def __init__(self, parent, db, callback, spare_server=None):
QObject.__init__(self, parent) QObject.__init__(self, parent)
self.pd = ProgressDialog(_('Adding...'), parent=parent) self.pd = ProgressDialog(_('Adding...'), parent=parent)
self.pd.setMaximumWidth(min(600, int(available_width()*0.75)))
self.spare_server = spare_server self.spare_server = spare_server
self.db = db self.db = db
self.pd.setModal(True) self.pd.setModal(True)

View File

@ -25,7 +25,8 @@ from calibre.utils.logging import Log
class BulkConfig(Config): class BulkConfig(Config):
def __init__(self, parent, db, preferred_output_format=None): def __init__(self, parent, db, preferred_output_format=None,
has_saved_settings=True):
ResizableDialog.__init__(self, parent) ResizableDialog.__init__(self, parent)
self.setup_output_formats(db, preferred_output_format) self.setup_output_formats(db, preferred_output_format)
@ -54,6 +55,12 @@ class BulkConfig(Config):
rb = self.buttonBox.button(self.buttonBox.RestoreDefaults) rb = self.buttonBox.button(self.buttonBox.RestoreDefaults)
rb.setVisible(False) rb.setVisible(False)
self.groups.setMouseTracking(True) self.groups.setMouseTracking(True)
if not has_saved_settings:
o = self.opt_individual_saved_settings
o.setEnabled(False)
o.setToolTip(_('None of the selected books have saved conversion '
'settings.'))
o.setChecked(False)
def setup_pipeline(self, *args): def setup_pipeline(self, *args):

View File

@ -70,7 +70,7 @@ if pictureflow is not None:
ans = '' ans = ''
except: except:
ans = '' ans = ''
return ans return ans.replace('&', '&&')
def subtitle(self, index): def subtitle(self, index):
try: try:

View File

@ -5,8 +5,9 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import os import os, itertools, operator
from functools import partial from functools import partial
from future_builtins import map
from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal, from PyQt4.Qt import (QTableView, Qt, QAbstractItemView, QMenu, pyqtSignal,
QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication, QModelIndex, QIcon, QItemSelection, QMimeData, QDrag, QApplication,
@ -793,8 +794,13 @@ class BooksView(QTableView): # {{{
sel = QItemSelection() sel = QItemSelection()
m = self.model() m = self.model()
max_col = m.columnCount(QModelIndex()) - 1 max_col = m.columnCount(QModelIndex()) - 1
for row in rows: # Create a range based selector for each set of contiguous rows
sel.select(m.index(row, 0), m.index(row, max_col)) # as supplying selectors for each individual row causes very poor
# performance if a large number of rows has to be selected.
for k, g in itertools.groupby(enumerate(rows), lambda (i,x):i-x):
group = list(map(operator.itemgetter(1), g))
sel.merge(QItemSelection(m.index(min(group), 0),
m.index(max(group), max_col)), sm.Select)
sm.select(sel, sm.ClearAndSelect) sm.select(sel, sm.ClearAndSelect)
def get_selected_ids(self): def get_selected_ids(self):

View File

@ -252,7 +252,7 @@ class SearchDialog(QDialog, Ui_Dialog):
# Milliseconds # Milliseconds
self.hang_time = self.config.get('hang_time', 75) * 1000 self.hang_time = self.config.get('hang_time', 75) * 1000
self.max_results = self.config.get('max_results', 10) self.max_results = self.config.get('max_results', 15)
self.should_open_external = self.config.get('open_external', True) self.should_open_external = self.config.get('open_external', True)
# Number of threads to run for each type of operation # Number of threads to run for each type of operation

View File

@ -14,7 +14,7 @@
<string>Get Books</string> <string>Get Books</string>
</property> </property>
<property name="windowIcon"> <property name="windowIcon">
<iconset resource="../../../../../resources/images.qrc"> <iconset>
<normaloff>:/images/store.png</normaloff>:/images/store.png</iconset> <normaloff>:/images/store.png</normaloff>:/images/store.png</iconset>
</property> </property>
<property name="sizeGripEnabled"> <property name="sizeGripEnabled">
@ -82,8 +82,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>173</width> <width>193</width>
<height>106</height> <height>127</height>
</rect> </rect>
</property> </property>
</widget> </widget>
@ -254,6 +254,19 @@
<header>widgets.h</header> <header>widgets.h</header>
</customwidget> </customwidget>
</customwidgets> </customwidgets>
<tabstops>
<tabstop>search_edit</tabstop>
<tabstop>search</tabstop>
<tabstop>results_view</tabstop>
<tabstop>store_list</tabstop>
<tabstop>select_all_stores</tabstop>
<tabstop>select_invert_stores</tabstop>
<tabstop>select_none_stores</tabstop>
<tabstop>configure</tabstop>
<tabstop>open_external</tabstop>
<tabstop>close</tabstop>
<tabstop>adv_search_button</tabstop>
</tabstops>
<resources> <resources>
<include location="../../../../../resources/images.qrc"/> <include location="../../../../../resources/images.qrc"/>
</resources> </resources>

View File

@ -40,9 +40,9 @@ class ChitankaStore(BasicStoreConfig, StorePlugin):
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):
# check for cyrilic symbols before performing search # check for cyrillic symbols before performing search
uquery = unicode(query.strip(), 'utf-8') uquery = unicode(query.strip(), 'utf-8')
reObj = re.search(u'^[а-яА-Я\\d]{4,}[а-яА-Я\\d\\s]*$', uquery) reObj = re.search(u'^[а-яА-Я\\d\\s]{3,}$', uquery)
if not reObj: if not reObj:
return return

View File

@ -46,9 +46,9 @@ class eKnigiStore(BasicStoreConfig, StorePlugin):
d.exec_() d.exec_()
def search(self, query, max_results=10, timeout=60): def search(self, query, max_results=10, timeout=60):
# check for cyrilic symbols before performing search # check for cyrillic symbols before performing search
uquery = unicode(query.strip(), 'utf-8') uquery = unicode(query.strip(), 'utf-8')
reObj = re.search(u'^[а-яА-Я\\d]{2,}[а-яА-Я\\d\\s]*$', uquery) reObj = re.search(u'^[а-яА-Я\\d\\s]{2,}$', uquery)
if not reObj: if not reObj:
return return

View File

@ -112,7 +112,10 @@ def convert_bulk_ebook(parent, queue, db, book_ids, out_format=None, args=[]):
if total == 0: if total == 0:
return None, None, None return None, None, None
d = BulkConfig(parent, db, out_format) has_saved_settings = db.has_conversion_options(book_ids)
d = BulkConfig(parent, db, out_format,
has_saved_settings=has_saved_settings)
if d.exec_() != QDialog.Accepted: if d.exec_() != QDialog.Accepted:
return None return None

View File

@ -359,7 +359,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
'log will be displayed automatically.')%self.gui_debug, show=True) 'log will be displayed automatically.')%self.gui_debug, show=True)
def esc(self, *args): def esc(self, *args):
self.search.clear() self.clear_button.click()
def start_content_server(self, check_started=True): def start_content_server(self, check_started=True):
from calibre.library.server.main import start_threaded_server from calibre.library.server.main import start_threaded_server

View File

@ -1085,6 +1085,14 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
return cPickle.loads(str(data)) return cPickle.loads(str(data))
return None return None
def has_conversion_options(self, ids, format='PIPE'):
ids = tuple(ids)
if len(ids) > 50000:
return True
return self.conn.get('''
SELECT data FROM conversion_options WHERE book IN %r AND
format=? LIMIT 1'''%(ids,), (format,), all=False) is not None
def delete_conversion_options(self, id, format, commit=True): def delete_conversion_options(self, id, format, commit=True):
self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?', self.conn.execute('DELETE FROM conversion_options WHERE book=? AND format=?',
(id, format.upper())) (id, format.upper()))