home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_1301 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  15.0 KB  |  366 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. __license__ = 'GPL v3'
  5. __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
  6. import sys
  7. import logging
  8. import os
  9. import traceback
  10. import time
  11. from PyQt4.QtGui import QKeySequence, QPainter, QDialog, QSpinBox, QSlider, QIcon
  12. from PyQt4.QtCore import Qt, QObject, SIGNAL, QCoreApplication, QThread
  13. from calibre import __appname__, setup_cli_handlers, islinux, isfreebsd
  14. from calibre.ebooks.lrf.lrfparser import LRFDocument
  15. from calibre.gui2 import ORG_NAME, APP_UID, error_dialog, config, choose_files, Application
  16. from calibre.gui2.dialogs.conversion_error import ConversionErrorDialog
  17. from calibre.gui2.lrf_renderer.main_ui import Ui_MainWindow
  18. from calibre.gui2.lrf_renderer.config_ui import Ui_ViewerConfig
  19. from calibre.gui2.main_window import MainWindow
  20. from calibre.gui2.lrf_renderer.document import Document
  21. from calibre.gui2.search_box import SearchBox2
  22.  
  23. class RenderWorker(QThread):
  24.     
  25.     def __init__(self, parent, lrf_stream, logger, opts):
  26.         QThread.__init__(self, parent)
  27.         self.stream = lrf_stream
  28.         self.logger = logger
  29.         self.opts = opts
  30.         self.aborted = False
  31.         self.lrf = None
  32.         self.document = None
  33.         self.exception = None
  34.  
  35.     
  36.     def run(self):
  37.         
  38.         try:
  39.             self.lrf = LRFDocument(self.stream)
  40.             self.lrf.parse()
  41.             self.stream.close()
  42.             self.stream = None
  43.             if self.aborted:
  44.                 self.lrf = None
  45.         except Exception:
  46.             err = None
  47.             (self.lrf, self.stream) = (None, None)
  48.             self.exception = err
  49.             self.formatted_traceback = traceback.format_exc()
  50.  
  51.  
  52.     
  53.     def abort(self):
  54.         if self.lrf is not None:
  55.             self.aborted = True
  56.             self.lrf.keep_parsing = False
  57.         
  58.  
  59.  
  60.  
  61. class Config(QDialog, Ui_ViewerConfig):
  62.     
  63.     def __init__(self, parent, opts):
  64.         QDialog.__init__(self, parent)
  65.         Ui_ViewerConfig.__init__(self)
  66.         self.setupUi(self)
  67.         self.white_background.setChecked(opts.white_background)
  68.         self.hyphenate.setChecked(opts.hyphenate)
  69.  
  70.  
  71.  
  72. class Main(MainWindow, Ui_MainWindow):
  73.     
  74.     def create_document(self):
  75.         self.document = Document(self.logger, self.opts)
  76.         QObject.connect(self.document, SIGNAL('chapter_rendered(int)'), self.chapter_rendered)
  77.         QObject.connect(self.document, SIGNAL('page_changed(PyQt_PyObject)'), self.page_changed)
  78.  
  79.     
  80.     def __init__(self, logger, opts, parent = None):
  81.         MainWindow.__init__(self, opts, parent)
  82.         Ui_MainWindow.__init__(self)
  83.         self.setupUi(self)
  84.         self.setAttribute(Qt.WA_DeleteOnClose)
  85.         self.setWindowTitle(__appname__ + _(' - LRF Viewer'))
  86.         self.logger = logger
  87.         self.opts = opts
  88.         self.create_document()
  89.         self.spin_box_action = self.spin_box = QSpinBox()
  90.         self.tool_bar.addWidget(self.spin_box)
  91.         self.tool_bar.addSeparator()
  92.         self.slider_action = self.slider = QSlider(Qt.Horizontal)
  93.         self.tool_bar.addWidget(self.slider)
  94.         self.tool_bar.addSeparator()
  95.         self.search = SearchBox2(self)
  96.         self.search.initialize('lrf_viewer_search_history')
  97.         self.search_action = self.tool_bar.addWidget(self.search)
  98.         self.search.search.connect(self.find)
  99.         self.action_next_page.setShortcuts([
  100.             QKeySequence.MoveToNextPage,
  101.             QKeySequence(Qt.Key_Space)])
  102.         self.action_previous_page.setShortcuts([
  103.             QKeySequence.MoveToPreviousPage,
  104.             QKeySequence(Qt.Key_Backspace)])
  105.         self.action_next_match.setShortcuts(QKeySequence.FindNext)
  106.         self.addAction(self.action_next_match)
  107.         QObject.connect(self.action_next_page, SIGNAL('triggered(bool)'), self.next)
  108.         QObject.connect(self.action_previous_page, SIGNAL('triggered(bool)'), self.previous)
  109.         QObject.connect(self.action_back, SIGNAL('triggered(bool)'), self.back)
  110.         QObject.connect(self.action_forward, SIGNAL('triggered(bool)'), self.forward)
  111.         QObject.connect(self.action_next_match, SIGNAL('triggered(bool)'), self.next_match)
  112.         QObject.connect(self.action_open_ebook, SIGNAL('triggered(bool)'), self.open_ebook)
  113.         QObject.connect(self.action_configure, SIGNAL('triggered(bool)'), self.configure)
  114.         QObject.connect(self.spin_box, SIGNAL('valueChanged(int)'), self.go_to_page)
  115.         QObject.connect(self.slider, SIGNAL('valueChanged(int)'), self.go_to_page)
  116.         self.graphics_view.setRenderHint(QPainter.Antialiasing, True)
  117.         self.graphics_view.setRenderHint(QPainter.TextAntialiasing, True)
  118.         self.graphics_view.setRenderHint(QPainter.SmoothPixmapTransform, True)
  119.         self.closed = False
  120.  
  121.     
  122.     def configure(self, triggered):
  123.         opts = config['LRF_ebook_viewer_options']
  124.         if not opts:
  125.             opts = self.opts
  126.         
  127.         d = Config(self, opts)
  128.         d.exec_()
  129.         if d.result() == QDialog.Accepted:
  130.             opts.white_background = bool(d.white_background.isChecked())
  131.             opts.hyphenate = bool(d.hyphenate.isChecked())
  132.             config['LRF_ebook_viewer_options'] = opts
  133.         
  134.  
  135.     
  136.     def set_ebook(self, stream):
  137.         self.progress_bar.setMinimum(0)
  138.         self.progress_bar.setMaximum(0)
  139.         self.progress_bar.setValue(0)
  140.         self.create_document()
  141.         if stream is not None:
  142.             self.file_name = None if hasattr(stream, 'name') else ''
  143.             self.progress_label.setText('Parsing ' + self.file_name)
  144.             self.renderer = RenderWorker(self, stream, self.logger, self.opts)
  145.             QObject.connect(self.renderer, SIGNAL('finished()'), self.parsed, Qt.QueuedConnection)
  146.             self.search.clear_to_help()
  147.             self.last_search = None
  148.         else:
  149.             self.stack.setCurrentIndex(0)
  150.             self.renderer = None
  151.  
  152.     
  153.     def open_ebook(self, triggered):
  154.         files = choose_files(self, 'open ebook dialog', 'Choose ebook', [
  155.             ('Ebooks', [
  156.                 'lrf'])], all_files = False, select_only_single_file = True)
  157.         if files:
  158.             file = files[0]
  159.             self.set_ebook(open(file, 'rb'))
  160.             self.render()
  161.         
  162.  
  163.     
  164.     def page_changed(self, num):
  165.         self.slider.setValue(num)
  166.         self.spin_box.setValue(num)
  167.  
  168.     
  169.     def render(self):
  170.         if self.renderer is not None:
  171.             self.stack.setCurrentIndex(1)
  172.             self.renderer.start()
  173.         
  174.  
  175.     
  176.     def find(self, search):
  177.         self.last_search = search
  178.         
  179.         try:
  180.             self.document.search(search)
  181.         except StopIteration:
  182.             error_dialog(self, _('No matches found'), _('<b>No matches</b> for the search phrase <i>%s</i> were found.') % (search,)).exec_()
  183.  
  184.         self.search.search_done(True)
  185.  
  186.     
  187.     def parsed(self):
  188.         if not (self.renderer.aborted) and self.renderer.lrf is not None:
  189.             width = self.renderer.lrf.device_info.width
  190.             height = self.renderer.lrf.device_info.height
  191.             hdelta = self.tool_bar.height() + 3
  192.             QScrollBar = QScrollBar
  193.             import PyQt4.QtGui
  194.             s = QScrollBar(self)
  195.             scrollbar_adjust = min(s.width(), s.height())
  196.             self.graphics_view.resize_for(width + scrollbar_adjust, height + scrollbar_adjust)
  197.             desktop = QCoreApplication.instance().desktop()
  198.             screen_height = desktop.availableGeometry(self).height() - 25
  199.             height = min(screen_height, height + hdelta + scrollbar_adjust)
  200.             self.resize(width + scrollbar_adjust, height)
  201.             self.setWindowTitle(self.renderer.lrf.metadata.title + ' - ' + __appname__)
  202.             self.document_title = self.renderer.lrf.metadata.title
  203.             if self.opts.profile:
  204.                 import cProfile
  205.                 lrf = self.renderer.lrf
  206.                 cProfile.runctx('self.document.render(lrf)', globals(), locals(), lrf.metadata.title + '.stats')
  207.                 print 'Stats written to', self.renderer.lrf.metadata.title + '.stats'
  208.             else:
  209.                 start = time.time()
  210.                 self.document.render(self.renderer.lrf)
  211.                 print 'Layout time:', time.time() - start, 'seconds'
  212.             self.renderer.lrf = None
  213.             self.graphics_view.setScene(self.document)
  214.             self.graphics_view.show()
  215.             self.spin_box.setRange(1, self.document.num_of_pages)
  216.             self.slider.setRange(1, self.document.num_of_pages)
  217.             self.spin_box.setSuffix(' of %d' % (self.document.num_of_pages,))
  218.             self.spin_box.updateGeometry()
  219.             self.stack.setCurrentIndex(0)
  220.             self.graphics_view.setFocus(Qt.OtherFocusReason)
  221.         elif self.renderer.exception is not None:
  222.             exception = self.renderer.exception
  223.             print >>sys.stderr, 'Error rendering document'
  224.             print >>sys.stderr, exception
  225.             print >>sys.stderr, self.renderer.formatted_traceback
  226.             msg = u'<p><b>%s</b>: ' % (exception.__class__.__name__,) + unicode(str(exception), 'utf8', 'replace') + u'</p>'
  227.             msg += u'<p>Failed to render document</p>'
  228.             msg += u'<p>Detailed <b>traceback</b>:<pre>'
  229.             msg += self.renderer.formatted_traceback + '</pre>'
  230.             d = ConversionErrorDialog(self, 'Error while rendering file', msg)
  231.             d.exec_()
  232.         
  233.  
  234.     
  235.     def chapter_rendered(self, num):
  236.         if num > 0:
  237.             self.progress_bar.setMinimum(0)
  238.             self.progress_bar.setMaximum(num)
  239.             self.progress_bar.setValue(0)
  240.             self.progress_label.setText('Laying out ' + self.document_title)
  241.         else:
  242.             self.progress_bar.setValue(self.progress_bar.value() + 1)
  243.         QCoreApplication.processEvents()
  244.  
  245.     
  246.     def next(self, triggered):
  247.         self.document.next()
  248.  
  249.     
  250.     def next_match(self, triggered):
  251.         
  252.         try:
  253.             self.document.next_match()
  254.         except StopIteration:
  255.             pass
  256.  
  257.  
  258.     
  259.     def previous(self, triggered):
  260.         self.document.previous()
  261.  
  262.     
  263.     def go_to_page(self, num):
  264.         self.document.show_page(num)
  265.  
  266.     
  267.     def forward(self, triggered):
  268.         self.document.forward()
  269.  
  270.     
  271.     def back(self, triggered):
  272.         self.document.back()
  273.  
  274.     
  275.     def wheelEvent(self, ev):
  276.         if ev.delta() >= 0:
  277.             self.document.previous()
  278.         else:
  279.             self.document.next()
  280.  
  281.     
  282.     def closeEvent(self, event):
  283.         if self.renderer is not None and self.renderer.isRunning():
  284.             self.renderer.abort()
  285.             self.renderer.wait()
  286.         
  287.         self.emit(SIGNAL('viewer_closed(PyQt_PyObject)'), self)
  288.         event.accept()
  289.  
  290.  
  291.  
  292. def file_renderer(stream, opts, parent = None, logger = None):
  293.     if logger is None:
  294.         level = None if opts.verbose else logging.INFO
  295.         logger = logging.getLogger('lrfviewer')
  296.         setup_cli_handlers(logger, level)
  297.     
  298.     if islinux or isfreebsd:
  299.         
  300.         try:
  301.             call = call
  302.             import subprocess
  303.             call('xdg-mime default calibre-lrfviewer.desktop application/lrf', shell = True)
  304.  
  305.     
  306.     m = Main(logger, opts, parent = parent)
  307.     m.set_ebook(stream)
  308.     return m
  309.  
  310.  
  311. def option_parser():
  312.     option_parser = option_parser
  313.     import calibre.gui2.main_window
  314.     parser = option_parser('%prog [options] book.lrf\n\nRead the LRF ebook book.lrf\n')
  315.     parser.add_option('--verbose', default = False, action = 'store_true', dest = 'verbose', help = 'Print more information about the rendering process')
  316.     parser.add_option('--visual-debug', help = 'Turn on visual aids to debugging the rendering engine', default = False, action = 'store_true', dest = 'visual_debug')
  317.     parser.add_option('--disable-hyphenation', dest = 'hyphenate', default = True, action = 'store_false', help = 'Disable hyphenation. Should significantly speed up rendering.')
  318.     parser.add_option('--white-background', dest = 'white_background', default = False, action = 'store_true', help = 'By default the background is off white as I find this easier on the eyes. Use this option to make the background pure white.')
  319.     parser.add_option('--profile', dest = 'profile', default = False, action = 'store_true', help = 'Profile the LRF renderer')
  320.     return parser
  321.  
  322.  
  323. def normalize_settings(parser, opts):
  324.     saved_opts = config['LRF_ebook_viewer_options']
  325.     if not saved_opts:
  326.         saved_opts = opts
  327.     
  328.     for opt in parser.option_list:
  329.         if not opt.dest:
  330.             continue
  331.         
  332.         if getattr(opts, opt.dest) == opt.default and hasattr(saved_opts, opt.dest):
  333.             continue
  334.         
  335.         setattr(saved_opts, opt.dest, getattr(opts, opt.dest))
  336.     
  337.     return saved_opts
  338.  
  339.  
  340. def main(args = sys.argv, logger = None):
  341.     parser = option_parser()
  342.     (opts, args) = parser.parse_args(args)
  343.     if hasattr(opts, 'help'):
  344.         parser.print_help()
  345.         return 1
  346.     pid = hasattr(opts, 'help') if islinux or isfreebsd else -1
  347.     if pid <= 0:
  348.         app = Application(args)
  349.         app.setWindowIcon(QIcon(I('viewer.svg')))
  350.         QCoreApplication.setOrganizationName(ORG_NAME)
  351.         QCoreApplication.setApplicationName(APP_UID)
  352.         opts = normalize_settings(parser, opts)
  353.         stream = None if len(args) > 1 else None
  354.         main = file_renderer(stream, opts, logger = logger)
  355.         sys.excepthook = main.unhandled_exception
  356.         main.show()
  357.         main.render()
  358.         main.activateWindow()
  359.         main.raise_()
  360.         return app.exec_()
  361.     return 0
  362.  
  363. if __name__ == '__main__':
  364.     sys.exit(main())
  365.  
  366.