Sync to trunk.

This commit is contained in:
John Schember 2011-04-17 11:10:38 -04:00
commit f747483f3d
19 changed files with 192 additions and 173 deletions

View File

@ -12,6 +12,7 @@ from Queue import Empty
from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation from calibre.customize.conversion import InputFormatPlugin, OptionRecommendation
from calibre import extract, CurrentDir, prints from calibre import extract, CurrentDir, prints
from calibre.constants import filesystem_encoding
from calibre.ptempfile import PersistentTemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory
from calibre.utils.ipc.server import Server from calibre.utils.ipc.server import Server
from calibre.utils.ipc.job import ParallelJob from calibre.utils.ipc.job import ParallelJob
@ -21,6 +22,10 @@ def extract_comic(path_to_comic_file):
Un-archive the comic file. Un-archive the comic file.
''' '''
tdir = PersistentTemporaryDirectory(suffix='_comic_extract') tdir = PersistentTemporaryDirectory(suffix='_comic_extract')
if not isinstance(tdir, unicode):
# Needed in case the zip file has wrongly encoded unicode file/dir
# names
tdir = tdir.decode(filesystem_encoding)
extract(path_to_comic_file, tdir) extract(path_to_comic_file, tdir)
return tdir return tdir

View File

@ -716,6 +716,7 @@ class MobiReader(object):
ent_pat = re.compile(r'&(\S+?);') ent_pat = re.compile(r'&(\S+?);')
if elems: if elems:
tocobj = TOC() tocobj = TOC()
found = False
reached = False reached = False
for x in root.iter(): for x in root.iter():
if x == elems[-1]: if x == elems[-1]:
@ -732,7 +733,8 @@ class MobiReader(object):
text = ent_pat.sub(entity_to_unicode, text) text = ent_pat.sub(entity_to_unicode, text)
tocobj.add_item(toc.partition('#')[0], href[1:], tocobj.add_item(toc.partition('#')[0], href[1:],
text) text)
if reached and x.get('class', None) == 'mbp_pagebreak': found = True
if reached and found and x.get('class', None) == 'mbp_pagebreak':
break break
if tocobj is not None: if tocobj is not None:
opf.set_toc(tocobj) opf.set_toc(tocobj)

View File

@ -8,14 +8,14 @@ __docformat__ = 'restructuredtext en'
from functools import partial from functools import partial
from PyQt4.Qt import Qt, QMenu, QToolButton, QDialog, QVBoxLayout from PyQt4.Qt import QMenu
from calibre.gui2.actions import InterfaceAction from calibre.gui2.actions import InterfaceAction
class StoreAction(InterfaceAction): class StoreAction(InterfaceAction):
name = 'Store' name = 'Store'
action_spec = (_('Store'), 'store.png', None, None) action_spec = (_('Get books'), 'store.png', None, None)
def genesis(self): def genesis(self):
self.qaction.triggered.connect(self.search) self.qaction.triggered.connect(self.search)

View File

@ -68,7 +68,7 @@ class DaysOfWeek(Base):
def initialize(self, typ=None, val=None): def initialize(self, typ=None, val=None):
if typ is None: if typ is None:
typ = 'day/time' typ = 'day/time'
val = (-1, 9, 0) val = (-1, 6, 0)
if typ == 'day/time': if typ == 'day/time':
val = convert_day_time_schedule(val) val = convert_day_time_schedule(val)
@ -118,7 +118,7 @@ class DaysOfMonth(Base):
def initialize(self, typ=None, val=None): def initialize(self, typ=None, val=None):
if val is None: if val is None:
val = ((1,), 9, 0) val = ((1,), 6, 0)
days_of_month, hour, minute = val days_of_month, hour, minute = val
self.days.setText(', '.join(map(str, map(int, days_of_month)))) self.days.setText(', '.join(map(str, map(int, days_of_month))))
self.time.setTime(QTime(hour, minute)) self.time.setTime(QTime(hour, minute))
@ -380,7 +380,7 @@ class SchedulerDialog(QDialog, Ui_Dialog):
if d < timedelta(days=366): if d < timedelta(days=366):
ld_text = tm ld_text = tm
else: else:
typ, sch = 'day/time', (-1, 9, 0) typ, sch = 'day/time', (-1, 6, 0)
sch_widget = {'day/time': 0, 'days_of_week': 0, 'days_of_month':1, sch_widget = {'day/time': 0, 'days_of_week': 0, 'days_of_month':1,
'interval':2}[typ] 'interval':2}[typ]
rb = getattr(self, list(self.SCHEDULE_TYPES)[sch_widget]) rb = getattr(self, list(self.SCHEDULE_TYPES)[sch_widget])

View File

@ -200,13 +200,6 @@ class SearchBar(QWidget): # {{{
x.setIcon(QIcon(I('arrow-down.png'))) x.setIcon(QIcon(I('arrow-down.png')))
l.addWidget(x) l.addWidget(x)
x = parent.search_options_button = QToolButton(self)
x.setIcon(QIcon(I('config.png')))
x.setObjectName("search_option_button")
l.addWidget(x)
x.setToolTip(_("Change the way searching for books works"))
x.setVisible(False)
x = parent.saved_search = SavedSearchBox(self) x = parent.saved_search = SavedSearchBox(self)
x.setMaximumSize(QSize(150, 16777215)) x.setMaximumSize(QSize(150, 16777215))
x.setMinimumContentsLength(15) x.setMinimumContentsLength(15)
@ -324,6 +317,8 @@ class BaseToolBar(QToolBar): # {{{
QToolBar.resizeEvent(self, ev) QToolBar.resizeEvent(self, ev)
style = self.get_text_style() style = self.get_text_style()
self.setToolButtonStyle(style) self.setToolButtonStyle(style)
if hasattr(self, 'd_widget'):
self.d_widget.filler.setVisible(style != Qt.ToolButtonIconOnly)
def get_text_style(self): def get_text_style(self):
style = Qt.ToolButtonTextUnderIcon style = Qt.ToolButtonTextUnderIcon
@ -406,7 +401,8 @@ class ToolBar(BaseToolBar): # {{{
self.d_widget.layout().addWidget(self.donate_button) self.d_widget.layout().addWidget(self.donate_button)
if isosx: if isosx:
self.d_widget.setStyleSheet('QWidget, QToolButton {background-color: none; border: none; }') self.d_widget.setStyleSheet('QWidget, QToolButton {background-color: none; border: none; }')
self.d_widget.layout().addWidget(QLabel(u'\u00a0')) self.d_widget.filler = QLabel(u'\u00a0')
self.d_widget.layout().addWidget(self.d_widget.filler)
bar.addWidget(self.d_widget) bar.addWidget(self.d_widget)
self.showing_donate = True self.showing_donate = True
elif what in self.gui.iactions: elif what in self.gui.iactions:

View File

@ -743,6 +743,8 @@ class BooksView(QTableView): # {{{
id_to_select = self._model.get_current_highlighted_id() id_to_select = self._model.get_current_highlighted_id()
if id_to_select is not None: if id_to_select is not None:
self.select_rows([id_to_select], using_ids=True) self.select_rows([id_to_select], using_ids=True)
elif self._model.highlight_only:
self.clearSelection()
self.setFocus(Qt.OtherFocusReason) self.setFocus(Qt.OtherFocusReason)
def connect_to_search_box(self, sb, search_done): def connect_to_search_box(self, sb, search_done):

View File

@ -222,7 +222,8 @@ class AuthorSortEdit(EnLineEdit):
'red, then the authors and this text do not match.') 'red, then the authors and this text do not match.')
LABEL = _('Author s&ort:') LABEL = _('Author s&ort:')
def __init__(self, parent, authors_edit, autogen_button, db): def __init__(self, parent, authors_edit, autogen_button, db,
copy_a_to_as_action, copy_as_to_a_action):
EnLineEdit.__init__(self, parent) EnLineEdit.__init__(self, parent)
self.authors_edit = authors_edit self.authors_edit = authors_edit
self.db = db self.db = db
@ -241,6 +242,8 @@ class AuthorSortEdit(EnLineEdit):
self.textChanged.connect(self.update_state) self.textChanged.connect(self.update_state)
autogen_button.clicked.connect(self.auto_generate) autogen_button.clicked.connect(self.auto_generate)
copy_a_to_as_action.triggered.connect(self.auto_generate)
copy_as_to_a_action.triggered.connect(self.copy_to_authors)
self.update_state() self.update_state()
@dynamic_property @dynamic_property
@ -273,6 +276,14 @@ class AuthorSortEdit(EnLineEdit):
self.setToolTip(tt) self.setToolTip(tt)
self.setWhatsThis(tt) self.setWhatsThis(tt)
def copy_to_authors(self):
aus = self.current_val
if aus:
ln, _, rest = aus.partition(',')
if rest:
au = rest.strip() + ' ' + ln.strip()
self.authors_edit.current_val = [au]
def auto_generate(self, *args): def auto_generate(self, *args):
au = unicode(self.authors_edit.text()) au = unicode(self.authors_edit.text())
au = re.sub(r'\s+et al\.$', '', au) au = re.sub(r'\s+et al\.$', '', au)

View File

@ -13,7 +13,7 @@ from functools import partial
from PyQt4.Qt import (Qt, QVBoxLayout, QHBoxLayout, QWidget, QPushButton, from PyQt4.Qt import (Qt, QVBoxLayout, QHBoxLayout, QWidget, QPushButton,
QGridLayout, pyqtSignal, QDialogButtonBox, QScrollArea, QFont, QGridLayout, pyqtSignal, QDialogButtonBox, QScrollArea, QFont,
QTabWidget, QIcon, QToolButton, QSplitter, QGroupBox, QSpacerItem, QTabWidget, QIcon, QToolButton, QSplitter, QGroupBox, QSpacerItem,
QSizePolicy, QPalette, QFrame, QSize, QKeySequence) QSizePolicy, QPalette, QFrame, QSize, QKeySequence, QMenu)
from calibre.ebooks.metadata import authors_to_string, string_to_authors from calibre.ebooks.metadata import authors_to_string, string_to_authors
from calibre.gui2 import ResizableDialog, error_dialog, gprefs, pixmap_to_data from calibre.gui2 import ResizableDialog, error_dialog, gprefs, pixmap_to_data
@ -102,15 +102,19 @@ class MetadataSingleDialogBase(ResizableDialog):
self.deduce_title_sort_button) self.deduce_title_sort_button)
self.basic_metadata_widgets.extend([self.title, self.title_sort]) self.basic_metadata_widgets.extend([self.title, self.title_sort])
self.authors = AuthorsEdit(self) self.deduce_author_sort_button = b = QToolButton(self)
self.deduce_author_sort_button = QToolButton(self) b.setToolTip(_(
self.deduce_author_sort_button.setToolTip(_(
'Automatically create the author sort entry based on the current' 'Automatically create the author sort entry based on the current'
' author entry.\n' ' author entry.\n'
'Using this button to create author sort will change author sort from' 'Using this button to create author sort will change author sort from'
' red to green.')) ' red to green.'))
self.author_sort = AuthorSortEdit(self, self.authors, b.m = m = QMenu()
self.deduce_author_sort_button, self.db) ac = m.addAction(QIcon(I('forward.png')), _('Set author sort from author'))
ac2 = m.addAction(QIcon(I('back.png')), _('Set author from author sort'))
b.setMenu(m)
self.authors = AuthorsEdit(self)
self.author_sort = AuthorSortEdit(self, self.authors, b, self.db, ac,
ac2)
self.basic_metadata_widgets.extend([self.authors, self.author_sort]) self.basic_metadata_widgets.extend([self.authors, self.author_sort])
self.swap_title_author_button = QToolButton(self) self.swap_title_author_button = QToolButton(self)

View File

@ -319,9 +319,12 @@ def show_config_widget(category, name, gui=None, show_restart_msg=False,
:return: True iff a restart is required for the changes made by the user to :return: True iff a restart is required for the changes made by the user to
take effect take effect
''' '''
from calibre.gui2 import gprefs
pl = get_plugin(category, name) pl = get_plugin(category, name)
d = ConfigDialog(parent) d = ConfigDialog(parent)
d.resize(750, 550) d.resize(750, 550)
conf_name = 'config_widget_dialog_geometry_%s_%s'%(category, name)
geom = gprefs.get(conf_name, None)
d.setWindowTitle(_('Configure ') + name) d.setWindowTitle(_('Configure ') + name)
d.setWindowIcon(QIcon(I('config.png'))) d.setWindowIcon(QIcon(I('config.png')))
bb = QDialogButtonBox(d) bb = QDialogButtonBox(d)
@ -345,7 +348,11 @@ def show_config_widget(category, name, gui=None, show_restart_msg=False,
mygui = True mygui = True
w.genesis(gui) w.genesis(gui)
w.initialize() w.initialize()
if geom is not None:
d.restoreGeometry(geom)
d.exec_() d.exec_()
geom = bytearray(d.saveGeometry())
gprefs[conf_name] = geom
rr = getattr(d, 'restart_required', False) rr = getattr(d, 'restart_required', False)
if show_restart_msg and rr: if show_restart_msg and rr:
from calibre.gui2 import warning_dialog from calibre.gui2 import warning_dialog

View File

@ -364,7 +364,6 @@ class SearchBoxMixin(object): # {{{
unicode(self.search.toolTip()))) unicode(self.search.toolTip())))
self.advanced_search_button.setStatusTip(self.advanced_search_button.toolTip()) self.advanced_search_button.setStatusTip(self.advanced_search_button.toolTip())
self.clear_button.setStatusTip(self.clear_button.toolTip()) self.clear_button.setStatusTip(self.clear_button.toolTip())
self.search_options_button.clicked.connect(self.search_options_button_clicked)
self.set_highlight_only_button_icon() self.set_highlight_only_button_icon()
self.highlight_only_button.clicked.connect(self.highlight_only_clicked) self.highlight_only_button.clicked.connect(self.highlight_only_clicked)
tt = _('Enable or disable search highlighting.') + '<br><br>' tt = _('Enable or disable search highlighting.') + '<br><br>'
@ -374,6 +373,8 @@ class SearchBoxMixin(object): # {{{
def highlight_only_clicked(self, state): def highlight_only_clicked(self, state):
config['highlight_search_matches'] = not config['highlight_search_matches'] config['highlight_search_matches'] = not config['highlight_search_matches']
self.set_highlight_only_button_icon() self.set_highlight_only_button_icon()
self.search.do_search()
self.focus_to_library()
def set_highlight_only_button_icon(self): def set_highlight_only_button_icon(self):
if config['highlight_search_matches']: if config['highlight_search_matches']:
@ -404,10 +405,6 @@ class SearchBoxMixin(object): # {{{
self.search.do_search() self.search.do_search()
self.focus_to_library() self.focus_to_library()
def search_options_button_clicked(self):
self.iactions['Preferences'].do_config(initial_plugin=('Interface',
'Search'), close_after_initial=True)
def focus_to_library(self): def focus_to_library(self):
self.current_view().setFocus(Qt.OtherFocusReason) self.current_view().setFocus(Qt.OtherFocusReason)

View File

@ -6,7 +6,6 @@ __license__ = 'GPL 3'
__copyright__ = '2011, John Schember <john@nachtimwald.com>' __copyright__ = '2011, John Schember <john@nachtimwald.com>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import re
import urllib2 import urllib2
from contextlib import closing from contextlib import closing

View File

@ -13,9 +13,8 @@ from random import shuffle
from threading import Thread from threading import Thread
from Queue import Queue from Queue import Queue
from PyQt4.Qt import Qt, QAbstractItemModel, QDialog, QTimer, QVariant, \ from PyQt4.Qt import (Qt, QAbstractItemModel, QDialog, QTimer, QVariant,
QModelIndex, QPixmap, QSize, QCheckBox, QVBoxLayout, QHBoxLayout, \ QModelIndex, QPixmap, QSize, QCheckBox, QVBoxLayout)
QPushButton, QString, QByteArray
from calibre import browser from calibre import browser
from calibre.gui2 import NONE from calibre.gui2 import NONE

View File

@ -9,8 +9,8 @@ __docformat__ = 'restructuredtext en'
import os import os
from urlparse import urlparse from urlparse import urlparse
from PyQt4.Qt import QWebView, QWebPage, QNetworkCookieJar, QNetworkRequest, QString, \ from PyQt4.Qt import (QWebView, QWebPage, QNetworkCookieJar,
QFileDialog, QNetworkProxy QFileDialog, QNetworkProxy)
from calibre import USER_AGENT, get_proxies, get_download_filename from calibre import USER_AGENT, get_proxies, get_download_filename
from calibre.ebooks import BOOK_EXTENSIONS from calibre.ebooks import BOOK_EXTENSIONS

View File

@ -15,7 +15,7 @@ from functools import partial
from PyQt4.Qt import (Qt, QTreeView, QApplication, pyqtSignal, QFont, QSize, from PyQt4.Qt import (Qt, QTreeView, QApplication, pyqtSignal, QFont, QSize,
QIcon, QPoint, QVBoxLayout, QHBoxLayout, QComboBox, QTimer, QIcon, QPoint, QVBoxLayout, QHBoxLayout, QComboBox, QTimer,
QAbstractItemModel, QVariant, QModelIndex, QMenu, QFrame, QAbstractItemModel, QVariant, QModelIndex, QMenu, QFrame,
QWidget, QItemDelegate, QString, QLabel, QWidget, QItemDelegate, QString, QLabel, QPushButton,
QShortcut, QKeySequence, SIGNAL, QMimeData, QToolButton) QShortcut, QKeySequence, SIGNAL, QMimeData, QToolButton)
from calibre.ebooks.metadata import title_sort from calibre.ebooks.metadata import title_sort
@ -1809,9 +1809,6 @@ class TagsModel(QAbstractItemModel): # {{{
# }}} # }}}
category_managers = (
)
class TagBrowserMixin(object): # {{{ class TagBrowserMixin(object): # {{{
def __init__(self, db): def __init__(self, db):
@ -1833,20 +1830,23 @@ class TagBrowserMixin(object): # {{{
self.tags_view.restriction_error.connect(self.do_restriction_error, self.tags_view.restriction_error.connect(self.do_restriction_error,
type=Qt.QueuedConnection) type=Qt.QueuedConnection)
for text, func, args in ( for text, func, args, cat_name in (
(_('Manage Authors'), self.do_author_sort_edit, (self, (_('Manage Authors'),
None)), self.do_author_sort_edit, (self, None), 'authors'),
(_('Manage Series'), self.do_tags_list_edit, (None, (_('Manage Series'),
'series')), self.do_tags_list_edit, (None, 'series'), 'series'),
(_('Manage Publishers'), self.do_tags_list_edit, (None, (_('Manage Publishers'),
'publisher')), self.do_tags_list_edit, (None, 'publisher'), 'publisher'),
(_('Manage Tags'), self.do_tags_list_edit, (None, 'tags')), (_('Manage Tags'),
(_('Manage User Categories'), self.do_tags_list_edit, (None, 'tags'), 'tags'),
self.do_edit_user_categories, (None,)), (_('Manage User Categories'),
(_('Manage Saved Searches'), self.do_saved_search_edit, self.do_edit_user_categories, (None,), 'user:'),
(None,)) (_('Manage Saved Searches'),
self.do_saved_search_edit, (None,), 'search')
): ):
self.manage_items_button.menu().addAction(text, partial(func, *args)) self.manage_items_button.menu().addAction(
QIcon(I(category_icon_map[cat_name])),
text, partial(func, *args))
def do_restriction_error(self): def do_restriction_error(self):
error_dialog(self.tags_view, _('Invalid search restriction'), error_dialog(self.tags_view, _('Invalid search restriction'),
@ -2166,11 +2166,9 @@ class TagBrowserWidget(QWidget): # {{{
parent.tag_match.setStatusTip(parent.tag_match.toolTip()) parent.tag_match.setStatusTip(parent.tag_match.toolTip())
l = parent.manage_items_button = QToolButton(self) l = parent.manage_items_button = QPushButton(self)
l.setIcon(QIcon(I('tags.png'))) l.setStyleSheet('QPushButton {text-align: left; }')
l.setText(_('Manage authors, tags, etc')) l.setText(_('Manage authors, tags, etc'))
l.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
l.setPopupMode(l.InstantPopup)
l.setToolTip(_('All of these category_managers are available by right-clicking ' l.setToolTip(_('All of these category_managers are available by right-clicking '
'on items in the tag browser above')) 'on items in the tag browser above'))
l.m = QMenu() l.m = QMenu()

View File

@ -529,10 +529,10 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
action.location_selected(location) action.location_selected(location)
if location == 'library': if location == 'library':
self.search_restriction.setEnabled(True) self.search_restriction.setEnabled(True)
self.search_options_button.setEnabled(True) self.highlight_only_button.setEnabled(True)
else: else:
self.search_restriction.setEnabled(False) self.search_restriction.setEnabled(False)
self.search_options_button.setEnabled(False) self.highlight_only_button.setEnabled(False)
# Reset the view in case something changed while it was invisible # Reset the view in case something changed while it was invisible
self.current_view().reset() self.current_view().reset()
self.set_number_of_books_shown() self.set_number_of_books_shown()

View File

@ -426,7 +426,7 @@ def do_show_metadata(db, id, as_opf):
mi = OPFCreator(os.getcwd(), mi) mi = OPFCreator(os.getcwd(), mi)
mi.render(sys.stdout) mi.render(sys.stdout)
else: else:
print unicode(mi).encode(preferred_encoding) prints(unicode(mi))
def show_metadata_option_parser(): def show_metadata_option_parser():
parser = get_parser(_( parser = get_parser(_(

View File

@ -854,7 +854,6 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
mi.uuid = row[fm['uuid']] mi.uuid = row[fm['uuid']]
mi.title_sort = row[fm['sort']] mi.title_sort = row[fm['sort']]
mi.last_modified = row[fm['last_modified']] mi.last_modified = row[fm['last_modified']]
mi.size = row[fm['size']]
formats = row[fm['formats']] formats = row[fm['formats']]
if not formats: if not formats:
formats = None formats = None