Merge from trunk

This commit is contained in:
Charles Haley 2012-03-24 10:55:19 +01:00
commit 16c81b450d
8 changed files with 75 additions and 26 deletions

View File

@ -23,7 +23,8 @@
date: 2012-03-23
new features:
- title: "E-book viewer: A whole new full screen mode, with no toolbars to distract from the text and the ability to set the width of the column of text via Preferences in the ebook viewer."
- title: "E-book viewer: A whole new full screen mode."
description: "The new mode has no toolbars to distract from the text and the ability to set the width of the column of text via Preferences in the ebook viewer. Click the Fullscreen button on the toolbar in the viewer to enter fullscreen mode (or press the F11 or Ctrl+Shit+F keys)"
type: major
tickets: [959830]

View File

@ -328,7 +328,7 @@ class MOBIHeader(object): # {{{
(self.sect_idx, self.skel_idx, self.datp_idx, self.oth_idx
) = struct.unpack_from(b'>4L', self.raw, 248)
self.unknown9 = self.raw[264:self.length]
if self.meta_orth_indx != self.sect_idx:
if self.meta_orth_indx not in {NULL_INDEX, self.sect_idx}:
raise ValueError('KF8 header has different Meta orth and '
'section indices')

View File

@ -9,10 +9,10 @@ import re, os
from lxml import html
from PyQt4.Qt import QApplication, QFontInfo, QSize, QWidget, QPlainTextEdit, \
QToolBar, QVBoxLayout, QAction, QIcon, Qt, QTabWidget, QUrl, \
QSyntaxHighlighter, QColor, QChar, QColorDialog, QMenu, QInputDialog, \
QHBoxLayout
from PyQt4.Qt import (QApplication, QFontInfo, QSize, QWidget, QPlainTextEdit,
QToolBar, QVBoxLayout, QAction, QIcon, Qt, QTabWidget, QUrl,
QSyntaxHighlighter, QColor, QChar, QColorDialog, QMenu, QInputDialog,
QHBoxLayout, QKeySequence)
from PyQt4.QtWebKit import QWebView, QWebPage
from calibre.ebooks.chardet import xml_to_unicode
@ -32,6 +32,7 @@ class PageAction(QAction): # {{{
type=Qt.QueuedConnection)
self.page_action.changed.connect(self.update_state,
type=Qt.QueuedConnection)
self.update_state()
@property
def page_action(self):
@ -66,6 +67,12 @@ class EditorWidget(QWebView): # {{{
self.comments_pat = re.compile(r'<!--.*?-->', re.DOTALL)
extra_shortcuts = {
'ToggleBold': 'Bold',
'ToggleItalic': 'Italic',
'ToggleUnderline': 'Underline',
}
for wac, name, icon, text, checkable in [
('ToggleBold', 'bold', 'format-text-bold', _('Bold'), True),
('ToggleItalic', 'italic', 'format-text-italic', _('Italic'),
@ -106,6 +113,9 @@ class EditorWidget(QWebView): # {{{
]:
ac = PageAction(wac, icon, text, checkable, self)
setattr(self, 'action_'+name, ac)
ss = extra_shortcuts.get(wac, None)
if ss:
ac.setShortcut(QKeySequence(getattr(QKeySequence, ss)))
self.action_color = QAction(QIcon(I('format-text-color')), _('Foreground color'),
self)

View File

@ -6,8 +6,8 @@ __copyright__ = '2011, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
from PyQt4.Qt import QLineEdit, QAbstractListModel, Qt, \
QApplication, QCompleter
from PyQt4.Qt import (QLineEdit, QAbstractListModel, Qt,
QApplication, QCompleter, QMetaObject)
from calibre.utils.icu import sort_key, lower
from calibre.gui2 import NONE
@ -182,14 +182,27 @@ class MultiCompleteComboBox(EnComboBox):
def set_add_separator(self, what):
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)
le = self.lineEdit()
if not what.strip():
QMetaObject.invokeMethod(self, 'clearEditText',
Qt.QueuedConnection)
else:
self.setEditText(what)
le.selectAll()
if __name__ == '__main__':
from PyQt4.Qt import QDialog, QVBoxLayout
app = QApplication([])
d = QDialog()
d.setLayout(QVBoxLayout())
le = MultiCompleteLineEdit(d)
le = MultiCompleteComboBox(d)
d.layout().addWidget(le)
le.all_items = ['one', 'otwo', 'othree', 'ooone', 'ootwo', 'oothree']
d.exec_()

View File

@ -128,8 +128,7 @@ class TextDelegate(QStyledItemDelegate): # {{{
for item in sorted(complete_items, key=sort_key):
editor.addItem(item)
ct = index.data(Qt.DisplayRole).toString()
editor.setEditText(ct)
editor.lineEdit().selectAll()
editor.show_initial_value(ct)
else:
editor = EnLineEdit(parent)
return editor
@ -170,8 +169,7 @@ class CompleteDelegate(QStyledItemDelegate): # {{{
for item in sorted(all_items, key=sort_key):
editor.addItem(item)
ct = index.data(Qt.DisplayRole).toString()
editor.setEditText(ct)
editor.lineEdit().selectAll()
editor.show_initial_value(ct)
else:
editor = EnLineEdit(parent)
return editor
@ -190,8 +188,7 @@ class LanguagesDelegate(QStyledItemDelegate): # {{{
editor = LanguagesEdit(parent=parent)
editor.init_langs(index.model().db)
ct = index.data(Qt.DisplayRole).toString()
editor.setEditText(ct)
editor.lineEdit().selectAll()
editor.show_initial_value(ct)
return editor
def setModelData(self, editor, model, index):

View File

@ -882,6 +882,11 @@ class FullFetch(QDialog): # {{{
self.covers_widget.chosen.connect(self.ok_clicked)
self.stack.addWidget(self.covers_widget)
# Workaround for Qt 4.8.0 bug that causes the frame of the window to go
# off the top of the screen if a max height is not set for the
# QWebView. Seems to only happen on windows, but keep it for all
# platforms just in case.
self.identify_widget.comments_view.setMaximumHeight(500)
self.resize(850, 550)
self.finished.connect(self.cleanup)

View File

@ -709,7 +709,7 @@ class DocumentView(QWebView): # {{{
if self.manager is not None:
self.manager.load_started()
self.loading_url = QUrl.fromLocalFile(path)
html = re.sub(r'<\s*title\s*/\s*>', '', html, flags=re.IGNORECASE)
html = re.sub(ur'<\s*title\s*/\s*>', u'', html, flags=re.IGNORECASE)
if has_svg:
self.setContent(QByteArray(html.encode(path.encoding)), mt, QUrl.fromLocalFile(path))
else:

View File

@ -204,7 +204,8 @@ class DevNull(object):
pass
NULL = DevNull()
def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
def do_add(db, paths, one_book_per_directory, recurse, add_duplicates, otitle,
oauthors, oisbn, otags, oseries, oseries_index):
orig = sys.stdout
#sys.stdout = NULL
try:
@ -231,6 +232,11 @@ def do_add(db, paths, one_book_per_directory, recurse, add_duplicates):
mi.title = os.path.splitext(os.path.basename(book))[0]
if not mi.authors:
mi.authors = [_('Unknown')]
for x in ('title', 'authors', 'isbn', 'tags', 'series'):
val = locals()[x]
if val: setattr(mi, x[1:], val)
if oseries:
mi.series_index = oseries_index
formats.append(format)
metadata.append(mi)
@ -302,39 +308,56 @@ the directory related options below.
parser.add_option('-e', '--empty', action='store_true', default=False,
help=_('Add an empty book (a book with no formats)'))
parser.add_option('-t', '--title', default=None,
help=_('Set the title of the added empty book'))
help=_('Set the title of the added book(s)'))
parser.add_option('-a', '--authors', default=None,
help=_('Set the authors of the added empty book'))
help=_('Set the authors of the added book(s)'))
parser.add_option('-i', '--isbn', default=None,
help=_('Set the ISBN of the added empty book'))
help=_('Set the ISBN of the added book(s)'))
parser.add_option('-T', '--tags', default=None,
help=_('Set the tags of the added book(s)'))
parser.add_option('-s', '--series', default=None,
help=_('Set the series of the added book(s)'))
parser.add_option('-S', '--series-index', default=1.0, type=float,
help=_('Set the series number of the added book(s)'))
return parser
def do_add_empty(db, title, authors, isbn):
from calibre.ebooks.metadata import MetaInformation, string_to_authors
def do_add_empty(db, title, authors, isbn, tags, series, series_index):
from calibre.ebooks.metadata import MetaInformation
mi = MetaInformation(None)
if title is not None:
mi.title = title
if authors:
mi.authors = string_to_authors(authors)
mi.authors = authors
if isbn:
mi.isbn = isbn
if tags:
mi.tags = tags
if series:
mi.series, mi.series_index = series, series_index
db.import_book(mi, [])
write_dirtied(db)
send_message()
def command_add(args, dbpath):
from calibre.ebooks.metadata import string_to_authors
parser = add_option_parser()
opts, args = parser.parse_args(sys.argv[:1] + args)
aut = string_to_authors(opts.authors) if opts.authors else []
tags = [x.strip() for x in opts.tags.split(',')] if opts.tags else []
if opts.empty:
do_add_empty(get_db(dbpath, opts), opts.title, opts.authors, opts.isbn)
do_add_empty(get_db(dbpath, opts), opts.title, aut, opts.isbn, tags,
opts.series, opts.series_index)
return 0
if len(args) < 2:
parser.print_help()
print
print >>sys.stderr, _('You must specify at least one file to add')
return 1
do_add(get_db(dbpath, opts), args[1:], opts.one_book_per_directory, opts.recurse, opts.duplicates)
do_add(get_db(dbpath, opts), args[1:], opts.one_book_per_directory,
opts.recurse, opts.duplicates, opts.title, opts.author, opts.isbn,
tags, opts.series, opts.series_index)
return 0
def do_remove(db, ids):