version 0.4.4

1) Add support for Sup, Sub and Space
2) Fix laying out of ImageBlocks in a Canvas
3) Integrate lrfviewer into main GUI
This commit is contained in:
Kovid Goyal 2007-09-24 19:51:12 +00:00
parent a050a683c1
commit 4815ecf0ae
10 changed files with 2254 additions and 85 deletions

View File

@ -13,7 +13,7 @@
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
''' E-book management software'''
__version__ = "0.4.3"
__version__ = "0.4.4"
__docformat__ = "epytext"
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
__appname__ = 'libprs500'

View File

@ -32,6 +32,9 @@ class LRFDocument(LRFMetaFile):
self.page_trees = []
self.font_map = {}
self.image_map = {}
self.keep_parsing = True
def parse(self):
self._parse_objects()
self.toc = None
self.metadata = LRFDocument.temp()
@ -53,9 +56,13 @@ class LRFDocument(LRFMetaFile):
if ord(array.array("i",[1]).tostring()[0])==0: #big-endian
obj_array.byteswap()
for i in range(self.number_of_objects):
if not self.keep_parsing:
break
objid, objoff, objsize = obj_array[i*4:i*4+3]
self._parse_object(objid, objoff, objsize)
for obj in self.objects.values():
if not self.keep_parsing:
break
if hasattr(obj, 'initialize'):
obj.initialize()
@ -155,6 +162,7 @@ def main(args=sys.argv, logger=None):
o.write(u'<?xml version="1.0" encoding="UTF-8"?>\n')
logger.info('Parsing LRF...')
d = LRFDocument(open(args[1], 'rb'))
d.parse()
logger.info('Creating XML...')
o.write(d.to_xml())
logger.info('LRS written to '+opts.out)

View File

@ -47,5 +47,6 @@
<file>images/sd.svg</file>
<file>images/sync.svg</file>
<file>images/trash.svg</file>
<file>images/view.svg</file>
</qresource>
</RCC>

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -108,11 +108,8 @@ class _Canvas(QGraphicsRectItem):
canvas.setParentItem(self)
canvas.setPos(x, y)
canvas.has_content = False
oy = self.current_y
for block, x, y in canvas.items:
self.layout_block(block, x, oy+y)
self.current_y = oy + canvas.max_y
canvas.put_objects()
self.current_y += canvas.max_y
def layout_text_block(self, block, x, y):
textwidth = block.bs.blockwidth - block.bs.sidemargin
@ -148,7 +145,11 @@ class _Canvas(QGraphicsRectItem):
rl.has_content = False
def layout_image_block(self, ib, x, y):
if self.current_y + ib.height > self.max_y-y and self.current_y < 5:
mw, mh = self.max_x - x, self.max_y - y
print self, mw, mh
if ib.width > mw or ib.height > mh:
ib.resize(mw, mh)
if self.current_y + ib.height > self.max_y-y and self.current_y > 5:
self.is_full = True
else:
br = ib.boundingRect()
@ -201,6 +202,10 @@ class Canvas(_Canvas, ContentObject):
if item:
self.items.append((item, po.x, po.y))
def put_objects(self):
for block, x, y in self.items:
self.layout_block(block, x, y)
def layout_block(self, block, x, y):
block.reset()
_Canvas.layout_block(self, block, x, y)

View File

@ -33,6 +33,7 @@ class RenderWorker(QThread):
def __init__(self, parent, lrf_stream, logger, opts):
QThread.__init__(self, parent)
self.stream, self.logger, self.opts = lrf_stream, logger, opts
self.aborted = False
self.lrf = None
self.document = None
self.exception = None
@ -40,25 +41,36 @@ class RenderWorker(QThread):
def run(self):
try:
self.lrf = LRFDocument(self.stream)
self.lrf.parse()
self.stream.close()
self.stream = None
if self.aborted:
self.lrf = None
except Exception, err:
self.lrf, self.stream = None, None
self.exception = err
self.formatted_traceback = traceback.format_exc()
self.emit(SIGNAL('parsed()'))
class Main(QObject, Ui_MainWindow, MainWindow):
def __init__(self, window, stream, logger, opts):
QObject.__init__(self)
def abort(self):
if self.lrf is not None:
self.aborted = True
self.lrf.keep_parsing = False
class Main(MainWindow, Ui_MainWindow):
def __init__(self, stream, logger, opts, parent=None):
MainWindow.__init__(self, parent)
Ui_MainWindow.__init__(self)
self.setupUi(window)
self.window = window
self.setupUi(self)
self.setAttribute(Qt.WA_DeleteOnClose)
self.setWindowTitle(__appname__ + ' - LRF Viewer')
self.logger = logger
self.file_name = os.path.basename(stream.name) if hasattr(stream, 'name') else ''
self.opts = opts
self.document = None
self.renderer = RenderWorker(self, stream, logger, opts)
QObject.connect(self.renderer, SIGNAL('parsed()'), self.parsed, Qt.QueuedConnection)
QObject.connect(self.renderer, SIGNAL('finished()'), self.parsed, Qt.QueuedConnection)
self.document = Document(self.logger, self.opts)
QObject.connect(self.document, SIGNAL('chapter_rendered(int)'), self.chapter_rendered)
QObject.connect(self.document, SIGNAL('page_changed(PyQt_PyObject)'), self.page_changed)
@ -85,6 +97,9 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.graphics_view.setRenderHint(QPainter.TextAntialiasing, True)
self.graphics_view.setRenderHint(QPainter.SmoothPixmapTransform, True)
self.closed = False
def page_changed(self, num):
self.slider.setValue(num)
self.spin_box.setValue(num)
@ -98,13 +113,13 @@ class Main(QObject, Ui_MainWindow, MainWindow):
try:
self.document.search(search)
except StopIteration:
error_dialog(self.window, 'No matches found', '<b>No matches</b> for the search phrase <i>%s</i> were found.'%(search,)).exec_()
error_dialog(self, 'No matches found', '<b>No matches</b> for the search phrase <i>%s</i> were found.'%(search,)).exec_()
def parsed(self, *args):
if self.renderer.lrf is not None:
def parsed(self):
if not self.renderer.aborted and self.renderer.lrf is not None:
self.graphics_view.setMinimumSize(self.renderer.lrf.device_info.width+5,
self.renderer.lrf.device_info.height)
self.window.setWindowTitle(self.renderer.lrf.metadata.title + ' - ' + __appname__)
self.setWindowTitle(self.renderer.lrf.metadata.title + ' - ' + __appname__)
self.document_title = self.renderer.lrf.metadata.title
if self.opts.profile:
import cProfile
@ -123,7 +138,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.spin_box.setSuffix(' of %d'%(self.document.num_of_pages,))
self.spin_box.updateGeometry()
self.stack.setCurrentIndex(0)
else:
elif self.renderer.exception is not None:
exception = self.renderer.exception
print >>sys.stderr, 'Error rendering document'
print >>sys.stderr, exception
@ -132,7 +147,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
msg += u'<p>Failed to render document</p>'
msg += u'<p>Detailed <b>traceback</b>:<pre>'
msg += self.renderer.formatted_traceback + '</pre>'
d = ConversionErrorDialog(self.window, 'Error while rendering file', msg)
d = ConversionErrorDialog(self, 'Error while rendering file', msg)
d.exec_()
def chapter_rendered(self, num):
@ -160,13 +175,21 @@ class Main(QObject, Ui_MainWindow, MainWindow):
def back(self, triggered):
self.document.back()
def closeEvent(self, event):
if self.renderer.isRunning():
self.renderer.abort()
self.renderer.wait()
self.emit(SIGNAL('viewer_closed(PyQt_PyObject)'), self)
event.accept()
def file_renderer(stream, logger, opts):
from PyQt4.Qt import QMainWindow
window = QMainWindow()
window.setAttribute(Qt.WA_DeleteOnClose)
window.setWindowTitle(__appname__ + ' - LRF Viewer')
return Main(window, stream, logger, opts)
def file_renderer(stream, opts, parent=None, logger=None):
if logger is None:
level = logging.DEBUG if opts.verbose else logging.INFO
logger = logging.getLogger('lrfviewer')
setup_cli_handlers(logger, level)
return Main(stream, logger, opts, parent=parent)
def option_parser():
@ -191,18 +214,14 @@ def main(args=sys.argv, logger=None):
if len(args) != 2:
parser.print_help()
return 1
if logger is None:
level = logging.DEBUG if opts.verbose else logging.INFO
logger = logging.getLogger('lrf2lrs')
setup_cli_handlers(logger, level)
pid = os.fork() if False and islinux else -1
pid = os.fork() if islinux else -1
if pid <= 0:
app = QApplication(args)
QCoreApplication.setOrganizationName(ORG_NAME)
QCoreApplication.setApplicationName(APP_UID)
main = file_renderer(open(args[1], 'rb'), logger, opts)
main = file_renderer(open(args[1], 'rb'), opts, logger=logger)
sys.excepthook = main.unhandled_exception
main.window.show()
main.show()
main.render()
return app.exec_()
return 0

View File

@ -43,6 +43,11 @@ class PixmapItem(QGraphicsPixmapItem):
self.setTransformationMode(Qt.SmoothTransformation)
self.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)
def resize(self, width, height):
p = self.pixmap()
self.setPixmap(p.scaled(width, height, Qt.IgnoreAspectRatio, Qt.SmoothTransformation))
self.width, self.height = width, height
class Plot(PixmapItem):
@ -214,6 +219,9 @@ class TextBlock(object):
if self.current_line is not None:
self.current_line.end_link()
def close_valign(self):
if self.current_line is not None:
self.current_line.valign = None
def populate(self, tb):
self.create_line()
@ -260,10 +268,13 @@ class TextBlock(object):
self.end_line()
self.create_line()
self.current_line.add_plot(plot)
elif i.name == 'Sup':
open_containers.append((('current_style', self.current_style.copy()),))
elif i.name == 'Sub':
open_containers.append((('current_style', self.current_style.copy()),))
elif i.name in ['Sup', 'Sub']:
if self.current_line is None:
self.create_line()
self.current_line.valign = i.name
open_containers.append(((self.close_valign, []),))
elif i.name == 'Space':
self.current_line.add_space(i.attrs['xsize'])
elif i.name == 'EmpLine':
if i.attrs:
open_containers.append((('current_style', self.current_style.copy()),))
@ -356,6 +367,7 @@ class Line(QGraphicsItem):
self.height, self.descent = 0, 0
self.links = collections.deque()
self.current_link = None
self.valign = None
def start_link(self, refobj, slot):
self.current_link = [self.current_width, sys.maxint, refobj, slot]
@ -380,6 +392,8 @@ class Line(QGraphicsItem):
processed = False
matches = self.__class__.whitespace.finditer(phrase)
font = QFont(ts.font)
if self.valign is not None:
font.setPixelSize(font.pixelSize()/1.5)
fm = QFontMetrics(font)
single_space_width = fm.width(' ')
height, descent = fm.height(), fm.descent()
@ -423,7 +437,7 @@ class Line(QGraphicsItem):
return phrase_pos, False
def commit(self, word, width, height, descent, ts, font):
self.tokens.append(Word(word, width, height, ts, font))
self.tokens.append(Word(word, width, height, ts, font, self.valign))
self.current_width += width
self.height = max(self.height, height)
self.descent = max(self.descent, descent)
@ -483,7 +497,6 @@ class Line(QGraphicsItem):
x += tok
elif isinstance(tok, Word):
painter.setFont(tok.font)
p = painter.pen()
if tok.highlight:
painter.save()
painter.setPen(QPen(Qt.NoPen))
@ -491,8 +504,12 @@ class Line(QGraphicsItem):
painter.drawRect(x, 0, tok.width, tok.height)
painter.restore()
painter.setPen(QPen(tok.text_color))
if tok.valign is None:
painter.drawText(x, y, tok.string)
painter.setPen(p)
elif tok.valign == 'Sub':
painter.drawText(x+1, y+self.descent/1.5, tok.string)
elif tok.valign == 'Sup':
painter.drawText(x+1, y-2.*self.descent, tok.string)
x += tok.width
else:
painter.drawPixmap(x, 0, tok.pixmap())
@ -546,11 +563,12 @@ class Line(QGraphicsItem):
class Word(object):
def __init__(self, string, width, height, ts, font):
def __init__(self, string, width, height, ts, font, valign):
self.string, self.width, self.height = QString(string), width, height
self.font = font
self.text_color = ts.textcolor
self.highlight = False
self.valign = valign
def main(args=sys.argv):
return 0

View File

@ -12,7 +12,7 @@
## You should have received a copy of the GNU General Public License along
## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
import os, sys, textwrap
import os, sys, textwrap, cStringIO, collections
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
QSettings, QVariant, QSize, QThread
@ -41,8 +41,10 @@ from libprs500.gui2.dialogs.jobs import JobsDialog
from libprs500.gui2.dialogs.conversion_error import ConversionErrorDialog
from libprs500.gui2.dialogs.lrf_single import LRFSingleDialog
from libprs500.gui2.dialogs.password import PasswordDialog
from libprs500.gui2.lrf_renderer.main import file_renderer
from libprs500.gui2.lrf_renderer.main import option_parser as lrfviewerop
class Main(QObject, Ui_MainWindow, MainWindow):
class Main(MainWindow, Ui_MainWindow):
def set_default_thumbnail(self, height):
r = QSvgRenderer(':/images/book.svg')
@ -53,24 +55,25 @@ class Main(QObject, Ui_MainWindow, MainWindow):
p.end()
self.default_thumbnail = (pixmap.width(), pixmap.height(), pixmap_to_data(pixmap))
def __init__(self, window):
QObject.__init__(self)
def __init__(self, parent=None):
MainWindow.__init__(self, parent)
Ui_MainWindow.__init__(self)
self.window = window
self.setupUi(window)
self.setupUi(self)
self.setWindowTitle(__appname__)
self.read_settings()
self.job_manager = JobManager()
self.jobs_dialog = JobsDialog(self.window, self.job_manager)
self.jobs_dialog = JobsDialog(self, self.job_manager)
self.device_manager = None
self.upload_memory = {}
self.delete_memory = {}
self.conversion_jobs = {}
self.persistent_files = []
self.default_thumbnail = None
self.device_error_dialog = ConversionErrorDialog(self.window, 'Error communicating with device', ' ')
self.device_error_dialog = ConversionErrorDialog(self, 'Error communicating with device', ' ')
self.device_error_dialog.setModal(Qt.NonModal)
self.tb_wrapper = textwrap.TextWrapper(width=40)
self.device_connected = False
self.viewers = collections.deque()
####################### Location View ########################
QObject.connect(self.location_view, SIGNAL('location_selected(PyQt_PyObject)'),
self.location_selected)
@ -83,7 +86,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
####################### Status Bar #####################
self.status_bar = StatusBar(self.jobs_dialog)
self.window.setStatusBar(self.status_bar)
self.setStatusBar(self.status_bar)
QObject.connect(self.job_manager, SIGNAL('job_added(int)'), self.status_bar.job_added)
QObject.connect(self.job_manager, SIGNAL('job_done(int)'), self.status_bar.job_done)
@ -105,6 +108,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
QObject.connect(sm.actions()[0], SIGNAL('triggered(bool)'), self.sync_to_main_memory)
QObject.connect(sm.actions()[1], SIGNAL('triggered(bool)'), self.sync_to_card)
QObject.connect(self.action_save, SIGNAL("triggered(bool)"), self.save_to_disk)
QObject.connect(self.action_view, SIGNAL("triggered(bool)"), self.view_book)
self.action_sync.setMenu(sm)
self.action_edit.setMenu(md)
nm = QMenu()
@ -141,8 +145,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.memory_view.connect_dirtied_signal(self.upload_booklists)
self.card_view.connect_dirtied_signal(self.upload_booklists)
window.closeEvent = self.close_event
window.show()
self.show()
self.stack.setCurrentIndex(0)
self.library_view.migrate_database()
self.library_view.sortByColumn(3, Qt.DescendingOrder)
@ -254,7 +257,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
'''
Add books from the local filesystem to either the library or the device.
'''
books = choose_files(self.window, 'add books dialog dir', 'Select books',
books = choose_files(self, 'add books dialog dir', 'Select books',
filters=[('Books', BOOK_EXTENSIONS)])
if not books:
return
@ -312,7 +315,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
if isinstance(exception, FreeSpaceError):
where = 'in main memory.' if 'memory' in str(exception) else 'on the storage card.'
titles = '\n'.join(['<li>'+mi['title']+'</li>' for mi in metadata])
d = error_dialog(self.window, 'No space on device',
d = error_dialog(self, 'No space on device',
'<p>Cannot upload books to device there is no more free space available '+where+
'</p>\n<ul>%s</ul>'%(titles,))
d.exec_()
@ -380,12 +383,12 @@ class Main(QObject, Ui_MainWindow, MainWindow):
'''
rows = self.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
d = error_dialog(self.window, 'Cannot edit metadata', 'No books selected')
d = error_dialog(self, 'Cannot edit metadata', 'No books selected')
d.exec_()
return
changed = False
for row in rows:
if MetadataSingleDialog(self.window, row.row(),
if MetadataSingleDialog(self, row.row(),
self.library_view.model().db).changed:
changed = True
@ -399,10 +402,10 @@ class Main(QObject, Ui_MainWindow, MainWindow):
'''
rows = [r.row() for r in self.library_view.selectionModel().selectedRows()]
if not rows or len(rows) == 0:
d = error_dialog(self.window, 'Cannot edit metadata', 'No books selected')
d = error_dialog(self, 'Cannot edit metadata', 'No books selected')
d.exec_()
return
if MetadataBulkDialog(self.window, rows, self.library_view.model().db).changed:
if MetadataBulkDialog(self, rows, self.library_view.model().db).changed:
self.library_view.model().resort(reset=False)
self.library_view.model().research()
@ -451,7 +454,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.status_bar.showMessage('Sending books to device.', 5000)
if bad:
bad = '\n'.join('<li>%s</li>'%(i,) for i in bad)
d = warning_dialog(self.window, 'No suitable formats',
d = warning_dialog(self, 'No suitable formats',
'Could not upload the following books to the device, as no suitable formats were found:<br><ul>%s</ul>'%(bad,))
d.exec_()
@ -462,10 +465,10 @@ class Main(QObject, Ui_MainWindow, MainWindow):
def save_to_disk(self, checked):
rows = self.current_view().selectionModel().selectedRows()
if not rows or len(rows) == 0:
d = error_dialog(self.window, 'Cannot save to disk', 'No books selected')
d = error_dialog(self, 'Cannot save to disk', 'No books selected')
d.exec_()
return
dir = choose_dir(self.window, 'save to disk dialog', 'Choose destination directory')
dir = choose_dir(self, 'save to disk dialog', 'Choose destination directory')
if not dir:
return
if self.current_view() == self.library_view:
@ -515,7 +518,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.fetch_news('newsweek', 'Newsweek')
def fetch_news_nytimes(self, checked):
d = PasswordDialog(self.window, 'nytimes info dialog',
d = PasswordDialog(self, 'nytimes info dialog',
'<p>Please enter your username and password for nytimes.com<br>If you do not have, you can <a href="http://www.nytimes.com/gst/regi.html">register</a> for free.<br>Without a registration, some articles will not be downloaded correctly. Click OK to proceed.')
d.exec_()
if d.result() == QDialog.Accepted:
@ -526,18 +529,18 @@ class Main(QObject, Ui_MainWindow, MainWindow):
############################### Convert ####################################
def convert_bulk(self, checked):
d = error_dialog(self.window, 'Cannot convert', 'Not yet implemented.')
d = error_dialog(self, 'Cannot convert', 'Not yet implemented.')
d.exec_()
def convert_single(self, checked):
rows = self.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
d = error_dialog(self.window, 'Cannot convert', 'No books selected')
d = error_dialog(self, 'Cannot convert', 'No books selected')
d.exec_()
changed = False
for row in [r.row() for r in rows]:
d = LRFSingleDialog(self.window, self.library_view.model().db, row)
d = LRFSingleDialog(self, self.library_view.model().db, row)
if d.selected_format:
d.exec_()
if d.result() == QDialog.Accepted:
@ -573,6 +576,40 @@ class Main(QObject, Ui_MainWindow, MainWindow):
data.close()
self.status_bar.showMessage(description + ' completed', 2000)
#############################View book######################################
def view_book(self, triggered):
rows = self.library_view.selectionModel().selectedRows()
if not rows or len(rows) == 0:
d = error_dialog(self, 'Cannot view', 'No book selected')
d.exec_()
return
row = rows[0].row()
formats = self.library_view.model().db.formats(row)
title = self.library_view.model().db.title(row)
id = self.library_view.model().db.id(row)
if 'LRF' not in formats.upper():
d = error_dialog(self, 'Cannot view', '%s is not available in LRF format. Please convert it first.'%(title,))
d.exec_()
return
data = cStringIO.StringIO(self.library_view.model().db.format(row, 'LRF'))
parser = lrfviewerop()
opts = parser.parse_args(['lrfviewer'])[0]
viewer = file_renderer(data, opts)
viewer.libprs500_db_id = id
viewer.show()
viewer.render()
self.viewers.append(viewer)
QObject.connect(viewer, SIGNAL('viewer_closed(PyQt_PyObject)'), self.viewer_closed)
def viewer_closed(self, viewer):
self.viewers.remove(viewer)
############################################################################
############################################################################
def location_selected(self, location):
'''
@ -626,13 +663,13 @@ class Main(QObject, Ui_MainWindow, MainWindow):
msg += formatted_traceback + '</pre>'
msg += '<p><b>Log:</b></p><pre>'
msg += log
ConversionErrorDialog(self.window, 'Conversion Error', msg, show=True)
ConversionErrorDialog(self, 'Conversion Error', msg, show=True)
def read_settings(self):
settings = QSettings()
settings.beginGroup("Main Window")
self.window.resize(settings.value("size", QVariant(QSize(800, 600))).toSize())
self.resize(settings.value("size", QVariant(QSize(800, 600))).toSize())
settings.endGroup()
self.database_path = settings.value("database path",
QVariant(os.path.join(os.path.expanduser('~'),'library1.db'))).toString()
@ -640,7 +677,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
def write_settings(self):
settings = QSettings()
settings.beginGroup("Main Window")
settings.setValue("size", QVariant(self.window.size()))
settings.setValue("size", QVariant(self.size()))
settings.endGroup()
settings.beginGroup('Book Views')
self.library_view.write_settings()
@ -648,7 +685,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
self.memory_view.write_settings()
settings.endGroup()
def close_event(self, e):
def closeEvent(self, e):
msg = 'There are active jobs. Are you sure you want to quit?'
if self.job_manager.has_device_jobs():
msg = '<p>'+__appname__ + ' is communicating with the device!<br>'+\
@ -656,7 +693,7 @@ class Main(QObject, Ui_MainWindow, MainWindow):
'Are you sure you want to quit?'
if self.job_manager.has_jobs():
d = QMessageBox(QMessageBox.Warning, 'WARNING: Active jobs', msg,
QMessageBox.Yes|QMessageBox.No, self.window)
QMessageBox.Yes|QMessageBox.No, self)
d.setIconPixmap(QPixmap(':/images/dialog_warning.svg'))
d.setDefaultButton(QMessageBox.No)
if d.exec_() != QMessageBox.Yes:
@ -669,18 +706,15 @@ class Main(QObject, Ui_MainWindow, MainWindow):
def main(args=sys.argv):
from PyQt4.Qt import QApplication, QMainWindow
from PyQt4.Qt import QApplication
pid = os.fork() if islinux else -1
if pid <= 0:
app = QApplication(args)
window = QMainWindow()
window.setWindowTitle(__appname__)
QCoreApplication.setOrganizationName(ORG_NAME)
QCoreApplication.setApplicationName(APP_UID)
initialize_file_icon_provider()
main = Main(window)
main = Main()
sys.excepthook = main.unhandled_exception
QObject.connect(app, SIGNAL('lastWindowClosed()'), app.quit)
return app.exec_()
return 0

View File

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>787</width>
<width>865</width>
<height>822</height>
</rect>
</property>
@ -316,8 +316,8 @@
</property>
<property name="iconSize" >
<size>
<width>64</width>
<height>64</height>
<width>48</width>
<height>48</height>
</size>
</property>
<property name="toolButtonStyle" >
@ -338,6 +338,7 @@
<addaction name="separator" />
<addaction name="action_news" />
<addaction name="action_convert" />
<addaction name="action_view" />
</widget>
<widget class="QStatusBar" name="statusBar" >
<property name="mouseTracking" >
@ -421,6 +422,14 @@
<string>Convert E-books</string>
</property>
</action>
<action name="action_view" >
<property name="icon" >
<iconset resource="images.qrc" >:/images/view.svg</iconset>
</property>
<property name="text" >
<string>View</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -15,9 +15,13 @@
import StringIO, traceback, sys
from PyQt4.QtGui import QMainWindow
from libprs500.gui2.dialogs.conversion_error import ConversionErrorDialog
class MainWindow(object):
class MainWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
def unhandled_exception(self, type, value, tb):
sio = StringIO.StringIO()
@ -26,5 +30,5 @@ class MainWindow(object):
print >>sys.stderr, fe
msg = '<p><b>' + unicode(str(value), 'utf8', 'replace') + '</b></p>'
msg += '<p>Detailed <b>traceback</b>:<pre>'+fe+'</pre>'
d = ConversionErrorDialog(self.window, 'ERROR: Unhandled exception', msg)
d = ConversionErrorDialog(self, 'ERROR: Unhandled exception', msg)
d.exec_()