Fix bug in ebook viewer that could cause it to hang wen finding a bookmark

This commit is contained in:
Kovid Goyal 2009-03-29 10:53:55 -07:00
parent 411c397bed
commit f45e84bbe4
2 changed files with 82 additions and 82 deletions

View File

@ -18,7 +18,7 @@ function find_enclosing_block(y) {
if (min != 0 && min.height() < 200) break;
}
if (y <= 0) return document.body;
if (min == 0) { return find_enclosing_block(x, y-20); }
if (min == 0) { return find_enclosing_block(y-20); }
return min;
}
@ -93,7 +93,7 @@ function enter_reference_mode() {
}
function leave_reference_mode() {
$("p").unbind("mouseenter mouseleave", toggle_reference);
$("p").unbind("mouseenter mouseleave", toggle_reference);
}
function goto_reference(ref) {
@ -118,4 +118,4 @@ $(document.body).click(function(e) {
$(document).ready(enter_reference_mode);
'''
'''

View File

@ -25,7 +25,7 @@ from calibre.gui2.library import SearchBox
from calibre.ebooks.metadata import MetaInformation
class TOCItem(QStandardItem):
def __init__(self, toc):
QStandardItem.__init__(self, toc.text if toc.text else '')
self.abspath = toc.abspath
@ -33,23 +33,23 @@ class TOCItem(QStandardItem):
for t in toc:
self.appendRow(TOCItem(t))
self.setFlags(Qt.ItemIsEnabled|Qt.ItemIsSelectable)
@classmethod
def type(cls):
return QStandardItem.UserType+10
class TOC(QStandardItemModel):
def __init__(self, toc):
QStandardItemModel.__init__(self)
for t in toc:
self.appendRow(TOCItem(t))
self.setHorizontalHeaderItem(0, QStandardItem(_('Table of Contents')))
class Worker(Thread):
def run(self):
try:
Thread.run(self)
@ -59,7 +59,7 @@ class Worker(Thread):
self.traceback = traceback.format_exc()
class ProgressIndicator(QWidget):
def __init__(self, *args):
QWidget.__init__(self, *args)
self.setGeometry(0, 0, 300, 500)
@ -74,7 +74,7 @@ class ProgressIndicator(QWidget):
self.status.font().setBold(True)
self.status.font().setPointSize(self.font().pointSize()+6)
self.setVisible(False)
def start(self, msg=''):
view = self.parent()
pwidth, pheight = view.size().width(), view.size().height()
@ -87,25 +87,25 @@ class ProgressIndicator(QWidget):
self.status.setText(msg)
self.setVisible(True)
self.movie.setPaused(False)
def stop(self):
if self.movie.state() == self.movie.Running:
self.movie.setPaused(True)
self.setVisible(False)
class History(collections.deque):
def __init__(self, action_back, action_forward):
self.action_back = action_back
self.action_forward = action_forward
collections.deque.__init__(self)
self.pos = 0
self.set_actions()
def set_actions(self):
self.action_back.setDisabled(self.pos < 1)
self.action_forward.setDisabled(self.pos + 1 >= len(self))
def back(self, from_pos):
if self.pos - 1 < 0: return None
if self.pos == len(self):
@ -114,56 +114,56 @@ class History(collections.deque):
self.pos -= 1
self.set_actions()
return self[self.pos]
def forward(self):
if self.pos + 1 >= len(self): return None
self.pos += 1
self.set_actions()
return self[self.pos]
def add(self, item):
while len(self) > self.pos+1:
self.pop()
self.append(item)
self.pos += 1
self.set_actions()
class Metadata(QLabel):
def __init__(self, parent):
QTextBrowser.__init__(self, parent.centralWidget())
self.view = parent.splitter
self.setGeometry(self.view.geometry())
self.setWordWrap(True)
self.setVisible(False)
def show_opf(self, opf):
mi = MetaInformation(opf)
html = '<h2 align="center">%s</h2>%s'%(_('Metadata'), u''.join(mi.to_html()))
self.setText(html)
def setVisible(self, x):
self.setGeometry(self.view.geometry())
QLabel.setVisible(self, x)
def paintEvent(self, ev):
p = QPainter(self)
p.fillRect(ev.region().boundingRect(), QBrush(QColor(200, 200, 200, 220), Qt.SolidPattern))
p.end()
QLabel.paintEvent(self, ev)
class DoubleSpinBox(QDoubleSpinBox):
def set_value(self, val):
self.blockSignals(True)
self.setValue(val)
self.blockSignals(False)
class HelpfulLineEdit(QLineEdit):
HELP_TEXT = _('Go to...')
def __init__(self, *args):
QLineEdit.__init__(self, *args)
self.default_palette = QApplication.palette(self)
@ -172,22 +172,22 @@ class HelpfulLineEdit(QLineEdit):
self.connect(self, SIGNAL('editingFinished()'),
lambda : self.emit(SIGNAL('goto(PyQt_PyObject)'), unicode(self.text())))
self.clear_to_help_mode()
def focusInEvent(self, ev):
self.setPalette(QApplication.palette(self))
if self.in_help_mode():
self.setText('')
return QLineEdit.focusInEvent(self, ev)
def in_help_mode(self):
return unicode(self.text()) == self.HELP_TEXT
def clear_to_help_mode(self):
self.setPalette(self.gray)
self.setText(self.HELP_TEXT)
class EbookViewer(MainWindow, Ui_EbookViewer):
def __init__(self, pathtoebook=None):
MainWindow.__init__(self, None)
self.setupUi(self)
@ -222,14 +222,14 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.action_quit = QAction(self)
self.addAction(self.action_quit)
self.action_quit.setShortcut(Qt.CTRL+Qt.Key_Q)
self.connect(self.action_quit, SIGNAL('triggered(bool)'),
self.connect(self.action_quit, SIGNAL('triggered(bool)'),
lambda x:QApplication.instance().quit())
self.action_copy.setDisabled(True)
self.action_metadata.setCheckable(True)
self.action_metadata.setShortcut(Qt.CTRL+Qt.Key_I)
self.action_table_of_contents.setCheckable(True)
self.action_reference_mode.setCheckable(True)
self.connect(self.action_reference_mode, SIGNAL('triggered(bool)'),
self.connect(self.action_reference_mode, SIGNAL('triggered(bool)'),
lambda x: self.view.reference_mode(x))
self.connect(self.action_metadata, SIGNAL('triggered(bool)'), lambda x:self.metadata.setVisible(x))
self.connect(self.action_table_of_contents, SIGNAL('triggered(bool)'), lambda x:self.toc.setVisible(x))
@ -244,7 +244,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
lambda x:self.view.next_page())
self.connect(self.action_previous_page, SIGNAL('triggered(bool)'),
lambda x:self.view.previous_page())
self.connect(self.action_find_next, SIGNAL('triggered(bool)'),
self.connect(self.action_find_next, SIGNAL('triggered(bool)'),
lambda x:self.find(unicode(self.search.text()), True, repeat=True))
self.connect(self.action_full_screen, SIGNAL('triggered(bool)'),
self.toggle_fullscreen)
@ -254,12 +254,12 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.connect(self.action_forward, SIGNAL('triggered(bool)'), self.forward)
self.connect(self.action_preferences, SIGNAL('triggered(bool)'), lambda x: self.view.config(self))
self.connect(self.pos, SIGNAL('valueChanged(double)'), self.goto_page)
self.connect(self.vertical_scrollbar, SIGNAL('valueChanged(int)'),
self.connect(self.vertical_scrollbar, SIGNAL('valueChanged(int)'),
lambda x: self.goto_page(x/100.))
self.connect(self.search, SIGNAL('search(PyQt_PyObject, PyQt_PyObject)'), self.find)
self.connect(self.toc, SIGNAL('clicked(QModelIndex)'), self.toc_clicked)
self.connect(self.reference, SIGNAL('goto(PyQt_PyObject)'), self.goto)
self.set_bookmarks([])
if pathtoebook is not None:
f = functools.partial(self.load_ebook, pathtoebook)
@ -277,18 +277,18 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.showNormal()
else:
self.showFullScreen()
def goto(self, ref):
if ref:
tokens = ref.split('.')
if len(tokens) > 1:
spine_index = int(tokens[0]) -1
spine_index = int(tokens[0]) -1
if spine_index == self.current_index:
self.view.goto(ref)
else:
self.pending_reference = ref
self.load_path(self.iterator.spine[spine_index])
def goto_bookmark(self, bm):
m = bm[1].split('#')
if len(m) > 1:
@ -298,39 +298,39 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
else:
self.pending_bookmark = bm
self.load_path(self.iterator.spine[spine_index])
def toc_clicked(self, index):
item = self.toc_model.itemFromIndex(index)
url = QUrl.fromLocalFile(item.abspath)
if item.fragment:
url.setFragment(item.fragment)
self.link_clicked(url)
def selection_changed(self, selected_text):
self.selected_text = selected_text.strip()
self.action_copy.setEnabled(bool(self.selected_text))
def copy(self, x):
if self.selected_text:
QApplication.clipboard().setText(self.selected_text)
def back(self, x):
pos = self.history.back(self.pos.value())
if pos is not None:
self.goto_page(pos)
def forward(self, x):
pos = self.history.forward()
if pos is not None:
self.goto_page(pos)
def goto_start(self):
self.goto_page(1)
def goto_end(self):
self.goto_page(self.pos.maximum())
def goto_page(self, new_page):
if self.current_page is not None:
for page in self.iterator.spine:
@ -343,7 +343,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.view.scroll_to(frac)
else:
self.load_path(page, pos=frac)
def open_ebook(self, checked):
files = choose_files(self, 'ebook viewer open dialog',
_('Choose ebook'),
@ -351,19 +351,19 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
select_only_single_file=True)
if files:
self.load_ebook(files[0])
def font_size_larger(self, checked):
frac = self.view.magnify_fonts()
self.action_font_size_larger.setEnabled(self.view.multiplier() < 3)
self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2)
self.set_page_number(frac)
def font_size_smaller(self, checked):
frac = self.view.shrink_fonts()
self.action_font_size_larger.setEnabled(self.view.multiplier() < 3)
self.action_font_size_smaller.setEnabled(self.view.multiplier() > 0.2)
self.set_page_number(frac)
def bookmark(self, *args):
title, ok = QInputDialog.getText(self, _('Add bookmark'), _('Enter title for bookmark:'))
title = unicode(title).strip()
@ -372,8 +372,8 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
bookmark = '%d#%s'%(self.current_index, pos)
self.iterator.add_bookmark((title, bookmark))
self.set_bookmarks(self.iterator.bookmarks)
def find(self, text, refinement, repeat=False):
if not text:
return
@ -385,18 +385,18 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
if self.current_index > 0:
index = self.iterator.search(text, 0)
if index is None:
info_dialog(self, _('No matches found'),
info_dialog(self, _('No matches found'),
_('No matches found for: %s')%text).exec_()
return
return
self.pending_search = text
self.load_path(self.iterator.spine[index])
def do_search(self, text):
self.pending_search = None
if self.view.search(text):
self.scrolled(self.view.scroll_fraction)
def keyPressEvent(self, event):
if event.key() == Qt.Key_F3:
text = unicode(self.search.text())
@ -405,10 +405,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.search.setFocus(Qt.OtherFocusReason)
else:
return MainWindow.keyPressEvent(self, event)
def internal_link_clicked(self, frac):
self.history.add(self.pos.value())
def link_clicked(self, url):
path = os.path.abspath(unicode(url.toLocalFile()))
frag = None
@ -424,10 +424,10 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.view.scroll_to(frag)
else:
QDesktopServices.openUrl(url)
def load_started(self):
self.open_progress_indicator(_('Loading flow...'))
def load_finished(self, ok):
self.close_progress_indicator()
path = self.view.path()
@ -451,11 +451,11 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.goto_bookmark(self.pending_bookmark)
self.pending_bookmark = None
return self.current_index
def load_path(self, path, pos=0.0):
self.open_progress_indicator(_('Laying out %s')%self.current_title)
self.view.load_path(path, pos=pos)
def viewport_resized(self, frac):
new_page = self.pos.value()
if self.current_page is not None:
@ -466,20 +466,20 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.view.scroll_to(frac, notify=False)
else:
self.set_page_number(frac)
def close_progress_indicator(self):
self.pi.stop()
for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'):
getattr(self, o).setEnabled(True)
self.unsetCursor()
self.view.setFocus(Qt.PopupFocusReason)
def open_progress_indicator(self, msg=''):
self.pi.start(msg)
for o in ('tool_bar', 'tool_bar2', 'view', 'horizontal_scrollbar', 'vertical_scrollbar'):
getattr(self, o).setEnabled(False)
self.setCursor(Qt.BusyCursor)
def set_bookmarks(self, bookmarks):
menu = QMenu()
current_page = None
@ -491,7 +491,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.action_bookmark.setMenu(menu)
self._menu = menu
return current_page
def save_current_position(self):
try:
pos = self.view.bookmark()
@ -499,7 +499,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.iterator.add_bookmark(('calibre_current_page_bookmark', bookmark))
except:
traceback.print_exc()
def load_ebook(self, pathtoebook):
if self.iterator is not None:
self.save_current_position()
@ -515,7 +515,7 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
if isinstance(worker.exception, DRMError):
error_dialog(self, _('DRM Error'), _('<p>This book is protected by <a href="%s">DRM</a>')%'http://wiki.mobileread.com/wiki/DRM').exec_()
else:
ConversionErrorDialog(self, _('Could not open ebook'),
ConversionErrorDialog(self, _('Could not open ebook'),
_('<b>%s</b><br/><p>%s</p>')%(worker.exception, worker.traceback.replace('\n', '<br>')), show=True)
self.close_progress_indicator()
else:
@ -543,37 +543,37 @@ class EbookViewer(MainWindow, Ui_EbookViewer):
self.goto_bookmark(previous)
else:
self.next_document()
def set_vscrollbar_value(self, pagenum):
self.vertical_scrollbar.blockSignals(True)
self.vertical_scrollbar.setValue(int(pagenum*100))
self.vertical_scrollbar.blockSignals(False)
def set_page_number(self, frac):
if getattr(self, 'current_page', None) is not None:
page = self.current_page.start_page + frac*float(self.current_page.pages-1)
self.pos.set_value(page)
self.set_vscrollbar_value(page)
def scrolled(self, frac):
self.set_page_number(frac)
def next_document(self):
if self.current_index < len(self.iterator.spine) - 1:
self.load_path(self.iterator.spine[self.current_index+1])
def previous_document(self):
if self.current_index > 0:
self.load_path(self.iterator.spine[self.current_index-1], pos=1.0)
def __enter__(self):
return self
def __exit__(self, *args):
if self.iterator is not None:
self.save_current_position()
self.iterator.__exit__(*args)
def config(defaults=None):
desc = _('Options to control the ebook viewer')
@ -581,8 +581,8 @@ def config(defaults=None):
c = Config('viewer', desc)
else:
c = StringConfig(defaults, desc)
c.add_opt('raise_window', ['--raise-window'], default=False,
c.add_opt('raise_window', ['--raise-window'], default=False,
help=_('If specified, viewer window will try to come to the '
'front when started.'))
return c
@ -592,7 +592,7 @@ def option_parser():
return c.option_parser(usage=_('''\
%prog [options] file
View an ebook.
View an ebook.
'''))
@ -611,7 +611,7 @@ def main(args=sys.argv):
if opts.raise_window:
main.raise_()
with main:
return app.exec_()
return app.exec_()
return 0
if __name__ == '__main__':