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 date: 2012-03-23
new features: 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 type: major
tickets: [959830] tickets: [959830]

View File

@ -328,7 +328,7 @@ class MOBIHeader(object): # {{{
(self.sect_idx, self.skel_idx, self.datp_idx, self.oth_idx (self.sect_idx, self.skel_idx, self.datp_idx, self.oth_idx
) = struct.unpack_from(b'>4L', self.raw, 248) ) = struct.unpack_from(b'>4L', self.raw, 248)
self.unknown9 = self.raw[264:self.length] 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 ' raise ValueError('KF8 header has different Meta orth and '
'section indices') 'section indices')

View File

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

View File

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

View File

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

View File

@ -882,6 +882,11 @@ class FullFetch(QDialog): # {{{
self.covers_widget.chosen.connect(self.ok_clicked) self.covers_widget.chosen.connect(self.ok_clicked)
self.stack.addWidget(self.covers_widget) 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.resize(850, 550)
self.finished.connect(self.cleanup) self.finished.connect(self.cleanup)

View File

@ -709,7 +709,7 @@ class DocumentView(QWebView): # {{{
if self.manager is not None: if self.manager is not None:
self.manager.load_started() self.manager.load_started()
self.loading_url = QUrl.fromLocalFile(path) 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: if has_svg:
self.setContent(QByteArray(html.encode(path.encoding)), mt, QUrl.fromLocalFile(path)) self.setContent(QByteArray(html.encode(path.encoding)), mt, QUrl.fromLocalFile(path))
else: else:

View File

@ -204,7 +204,8 @@ class DevNull(object):
pass pass
NULL = DevNull() 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 orig = sys.stdout
#sys.stdout = NULL #sys.stdout = NULL
try: 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] mi.title = os.path.splitext(os.path.basename(book))[0]
if not mi.authors: if not mi.authors:
mi.authors = [_('Unknown')] 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) formats.append(format)
metadata.append(mi) metadata.append(mi)
@ -302,39 +308,56 @@ the directory related options below.
parser.add_option('-e', '--empty', action='store_true', default=False, parser.add_option('-e', '--empty', action='store_true', default=False,
help=_('Add an empty book (a book with no formats)')) help=_('Add an empty book (a book with no formats)'))
parser.add_option('-t', '--title', default=None, 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, 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, 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 return parser
def do_add_empty(db, title, authors, isbn): def do_add_empty(db, title, authors, isbn, tags, series, series_index):
from calibre.ebooks.metadata import MetaInformation, string_to_authors from calibre.ebooks.metadata import MetaInformation
mi = MetaInformation(None) mi = MetaInformation(None)
if title is not None: if title is not None:
mi.title = title mi.title = title
if authors: if authors:
mi.authors = string_to_authors(authors) mi.authors = authors
if isbn: if isbn:
mi.isbn = isbn mi.isbn = isbn
if tags:
mi.tags = tags
if series:
mi.series, mi.series_index = series, series_index
db.import_book(mi, []) db.import_book(mi, [])
write_dirtied(db) write_dirtied(db)
send_message() send_message()
def command_add(args, dbpath): def command_add(args, dbpath):
from calibre.ebooks.metadata import string_to_authors
parser = add_option_parser() parser = add_option_parser()
opts, args = parser.parse_args(sys.argv[:1] + args) 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: 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 return 0
if len(args) < 2: if len(args) < 2:
parser.print_help() parser.print_help()
print print
print >>sys.stderr, _('You must specify at least one file to add') print >>sys.stderr, _('You must specify at least one file to add')
return 1 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 return 0
def do_remove(db, ids): def do_remove(db, ids):