All the more obvious bugs have been ironed out of gui2

This commit is contained in:
Kovid Goyal 2007-08-05 22:36:55 +00:00
parent 65681cf015
commit 3b6141f135
9 changed files with 82 additions and 30 deletions

View File

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

View File

@ -905,7 +905,7 @@ class PRS500(Device):
space = self.free_space(end_session=False) space = self.free_space(end_session=False)
mspace = space[0] mspace = space[0]
cspace = space[1] if space[1] >= space[2] else space[2] cspace = space[1] if space[1] >= space[2] else space[2]
if oncard and size > cspace - 1024*1024: if oncard and size > cspace - 1024*1024:
raise FreeSpaceError("There is insufficient free space "+\ raise FreeSpaceError("There is insufficient free space "+\
"on the storage card") "on the storage card")
if not oncard and size > mspace - 1024*1024: if not oncard and size > mspace - 1024*1024:

View File

@ -12,9 +12,16 @@
## You should have received a copy of the GNU General Public License along ## 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., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
import sys
from PyQt4.QtCore import QThread, SIGNAL, QObject from PyQt4.QtCore import QThread, SIGNAL, QObject
from libprs500.devices.prs500.driver import PRS500 _libusb_available = False
try:
from libprs500.devices.prs500.driver import PRS500
_libusb_available = True
except OSError, err: #libusb not availabe
print >>sys.stderr, err
class DeviceDetector(QThread): class DeviceDetector(QThread):
''' '''
@ -27,14 +34,20 @@ class DeviceDetector(QThread):
@param sleep_time: Time to sleep between device probes in millisecs @param sleep_time: Time to sleep between device probes in millisecs
@type sleep_time: integer @type sleep_time: integer
''' '''
self.devices = ([PRS500, False],) self.devices = []
if _libusb_available:
for dclass in (PRS500,):
self.devices.append([dclass, False])
self.sleep_time = sleep_time self.sleep_time = sleep_time
QThread.__init__(self) QThread.__init__(self)
def run(self): def run(self):
while True: while True:
for device in self.devices: for device in self.devices:
connected = device[0].is_connected() try:
connected = device[0].is_connected()
except:
connected = False
if connected and not device[1]: if connected and not device[1]:
self.emit(SIGNAL('connected(PyQt_PyObject, PyQt_PyObject)'), device[0], True) self.emit(SIGNAL('connected(PyQt_PyObject, PyQt_PyObject)'), device[0], True)
device[1] ^= True device[1] ^= True

View File

@ -222,7 +222,11 @@ class JobManager(QAbstractTableModel):
def status_update(self, id, progress): def status_update(self, id, progress):
keys = self.jobs.keys() keys = self.jobs.keys()
keys.sort() keys.sort()
row = keys.index(id) try:
index = self.index(row, 2) row = keys.index(id)
self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), index, index) index = self.index(row, 2)
self.emit(SIGNAL('dataChanged(QModelIndex, QModelIndex)'), index, index)
except ValueError:
pass

View File

@ -12,8 +12,7 @@
## You should have received a copy of the GNU General Public License along ## 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., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
from libprs500.ptempfile import PersistentTemporaryFile import os, textwrap, traceback, time, re, sre_constants
import os, textwrap, traceback, time, re
from datetime import timedelta, datetime from datetime import timedelta, datetime
from operator import attrgetter from operator import attrgetter
from math import cos, sin, pi from math import cos, sin, pi
@ -24,6 +23,7 @@ from PyQt4.QtGui import QTableView, QProgressDialog, QAbstractItemView, QColor,
from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \ from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \
QCoreApplication, SIGNAL, QObject, QSize, QModelIndex QCoreApplication, SIGNAL, QObject, QSize, QModelIndex
from libprs500.ptempfile import PersistentTemporaryFile
from libprs500.library.database import LibraryDatabase from libprs500.library.database import LibraryDatabase
from libprs500.gui2 import NONE from libprs500.gui2 import NONE
@ -118,7 +118,15 @@ class BooksModel(QAbstractTableModel):
text = text.replace('"'+quot.group(1)+'"', '') text = text.replace('"'+quot.group(1)+'"', '')
quot = re.search('"(.*?)"', text) quot = re.search('"(.*?)"', text)
tokens += text.split(' ') tokens += text.split(' ')
return [re.compile(i, re.IGNORECASE) for i in tokens] ans = []
for i in tokens:
try:
ans.append(re.compile(i, re.IGNORECASE))
except sre_constants.error:
continue
return ans
def search(self, text, refinement): def search(self, text, refinement):
tokens = self.search_tokens(text) tokens = self.search_tokens(text)

View File

@ -12,15 +12,14 @@
## You should have received a copy of the GNU General Public License along ## 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., ## with this program; if not, write to the Free Software Foundation, Inc.,
## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning ## 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.Warning
from libprs500.ptempfile import PersistentTemporaryFile import os, sys, traceback, StringIO, textwrap
import os, tempfile, sys, traceback
from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \ from PyQt4.QtCore import Qt, SIGNAL, QObject, QCoreApplication, \
QSettings, QVariant, QSize, QThread QSettings, QVariant, QSize, QThread
from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox from PyQt4.QtGui import QPixmap, QColor, QPainter, QMenu, QIcon, QMessageBox
from PyQt4.QtSvg import QSvgRenderer from PyQt4.QtSvg import QSvgRenderer
from libprs500 import __version__, __appname__ from libprs500 import __version__, __appname__, iswindows, isosx
from libprs500.ebooks.metadata.meta import get_metadata from libprs500.ebooks.metadata.meta import get_metadata
from libprs500.devices.errors import FreeSpaceError from libprs500.devices.errors import FreeSpaceError
from libprs500.devices.interface import Device from libprs500.devices.interface import Device
@ -30,7 +29,7 @@ from libprs500.gui2 import APP_TITLE, warning_dialog, choose_files, error_dialog
from libprs500.gui2.main_ui import Ui_MainWindow from libprs500.gui2.main_ui import Ui_MainWindow
from libprs500.gui2.device import DeviceDetector, DeviceManager from libprs500.gui2.device import DeviceDetector, DeviceManager
from libprs500.gui2.status import StatusBar from libprs500.gui2.status import StatusBar
from libprs500.gui2.jobs import JobManager, JobException from libprs500.gui2.jobs import JobManager
from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog from libprs500.gui2.dialogs.metadata_single import MetadataSingleDialog
from libprs500.gui2.dialogs.metadata_bulk import MetadataBulkDialog from libprs500.gui2.dialogs.metadata_bulk import MetadataBulkDialog
from libprs500.gui2.dialogs.jobs import JobsDialog from libprs500.gui2.dialogs.jobs import JobsDialog
@ -61,6 +60,7 @@ class Main(QObject, Ui_MainWindow):
self.default_thumbnail = None self.default_thumbnail = None
self.device_error_dialog = error_dialog(self.window, 'Error communicating with device', ' ') self.device_error_dialog = error_dialog(self.window, 'Error communicating with device', ' ')
self.device_error_dialog.setModal(Qt.NonModal) self.device_error_dialog.setModal(Qt.NonModal)
self.tb_wrapper = textwrap.TextWrapper(width=40)
####################### Location View ######################## ####################### Location View ########################
QObject.connect(self.location_view, SIGNAL('location_selected(PyQt_PyObject)'), QObject.connect(self.location_view, SIGNAL('location_selected(PyQt_PyObject)'),
self.location_selected) self.location_selected)
@ -436,6 +436,12 @@ class Main(QObject, Ui_MainWindow):
self.current_view().setCurrentIndex(self.current_view().model().index(0, 0)) self.current_view().setCurrentIndex(self.current_view().model().index(0, 0))
def wrap_traceback(self, tb):
tb = unicode(tb, 'utf8', 'replace')
if iswindows or isosx:
tb = '\n'.join(self.tb_wrapper.wrap(tb))
return tb
def device_job_exception(self, id, description, exception, formatted_traceback): def device_job_exception(self, id, description, exception, formatted_traceback):
''' '''
Handle exceptions in threaded jobs. Handle exceptions in threaded jobs.
@ -444,10 +450,11 @@ class Main(QObject, Ui_MainWindow):
print >>sys.stderr, exception print >>sys.stderr, exception
print >>sys.stderr, formatted_traceback print >>sys.stderr, formatted_traceback
if not self.device_error_dialog.isVisible(): if not self.device_error_dialog.isVisible():
msg = '<p><b>%s</b>: '%(exception.__class__.__name__,) + str(exception) + '</p>' msg = u'<p><b>%s</b>: '%(exception.__class__.__name__,) + unicode(str(exception), 'utf8', 'replace') + u'</p>'
msg += '<p>Failed to perform <b>job</b>: '+description msg += u'<p>Failed to perform <b>job</b>: '+description
msg += '<p>Further device related error messages will not be shown while this message is visible.' msg += u'<p>Further device related error messages will not be shown while this message is visible.'
msg += '<p>Detailed <b>traceback</b>:<pre>'+formatted_traceback+'</pre>' msg += u'<p>Detailed <b>traceback</b>:<pre>'
msg += self.wrap_traceback(formatted_traceback)
self.device_error_dialog.setText(msg) self.device_error_dialog.setText(msg)
self.device_error_dialog.show() self.device_error_dialog.show()
@ -456,10 +463,10 @@ class Main(QObject, Ui_MainWindow):
def read_settings(self): def read_settings(self):
settings = QSettings() settings = QSettings()
settings.beginGroup("MainWindow") settings.beginGroup("MainWindow")
self.window.resize(settings.value("size", QVariant(QSize(1000, 700))).toSize()) self.window.resize(settings.value("size", QVariant(QSize(800, 600))).toSize())
settings.endGroup() settings.endGroup()
self.database_path = settings.value("database path", QVariant(os.path\ self.database_path = settings.value("database path",
.expanduser("~/library1.db"))).toString() QVariant(os.path.join(os.path.expanduser('~'),'library1.db'))).toString()
def write_settings(self): def write_settings(self):
settings = QSettings() settings = QSettings()
@ -485,13 +492,15 @@ class Main(QObject, Ui_MainWindow):
e.ignore() e.ignore()
def unhandled_exception(self, type, value, tb): def unhandled_exception(self, type, value, tb):
traceback.print_exception(type, value, tb, file=sys.stderr) sio = StringIO.StringIO()
traceback.print_exception(type, value, tb, file=sio)
fe = sio.getvalue()
print >>sys.stderr, fe
if type == KeyboardInterrupt: if type == KeyboardInterrupt:
self.window.close() self.window.close()
self.window.thread().exit(0) self.window.thread().exit(0)
fe = '\n'.join(traceback.format_exception(type, value, tb)) msg = '<p><b>' + unicode(str(value), 'utf8', 'replace') + '</b></p>'
msg = '<p><b>' + str(value) + '</b></p>' msg += '<p>Detailed <b>traceback</b>:<pre>'+self.wrap_traceback(fe)+'</pre>'
msg += '<p>Detailed <b>traceback</b>:<pre>'+fe+'</pre>'
d = error_dialog(self.window, 'ERROR: Unhandled exception', msg) d = error_dialog(self.window, 'ERROR: Unhandled exception', msg)
d.exec_() d.exec_()
@ -502,6 +511,7 @@ def main():
window.setWindowTitle(APP_TITLE) window.setWindowTitle(APP_TITLE)
QCoreApplication.setOrganizationName("KovidsBrain") QCoreApplication.setOrganizationName("KovidsBrain")
QCoreApplication.setApplicationName(APP_TITLE) QCoreApplication.setApplicationName(APP_TITLE)
initialize_file_icon_provider() initialize_file_icon_provider()
main = Main(window) main = Main(window)
sys.excepthook = main.unhandled_exception sys.excepthook = main.unhandled_exception

View File

@ -90,7 +90,10 @@ class LibraryDatabase(object):
obj = conn.execute('INSERT INTO books(title, timestamp) VALUES (?,?)', obj = conn.execute('INSERT INTO books(title, timestamp) VALUES (?,?)',
(book['title'], book['timestamp'])) (book['title'], book['timestamp']))
id = obj.lastrowid id = obj.lastrowid
authors = book['authors'].split('&') authors = book['authors']
if not authors:
authors = 'Unknown'
authors = authors.split('&')
for a in authors: for a in authors:
author = conn.execute('SELECT id from authors WHERE name=?', (a,)).fetchone() author = conn.execute('SELECT id from authors WHERE name=?', (a,)).fetchone()
if author: if author:
@ -644,7 +647,7 @@ class LibraryDatabase(object):
'''Cover as a data string or None''' '''Cover as a data string or None'''
id = self.id(index) id = self.id(index)
data = self.conn.execute('SELECT data FROM covers WHERE book=?', (id,)).fetchone() data = self.conn.execute('SELECT data FROM covers WHERE book=?', (id,)).fetchone()
if not data: if not data or not data[0]:
return None return None
return(decompress(data[0])) return(decompress(data[0]))

View File

@ -58,5 +58,5 @@ def PersistentTemporaryFile(suffix="", prefix="", dir=None):
prefix = "" prefix = ""
fd, name = tempfile.mkstemp(suffix, __appname__+"_"+ __version__+"_" + prefix, fd, name = tempfile.mkstemp(suffix, __appname__+"_"+ __version__+"_" + prefix,
dir=dir) dir=dir)
_file = os.fdopen(fd, "wb") _file = os.fdopen(fd, 'w+b')
return _TemporaryFileWrapper(_file, name) return _TemporaryFileWrapper(_file, name)

View File

@ -355,7 +355,8 @@ r'''<?xml version='1.0' encoding='windows-1252'?>
class BuildEXE(build_exe): class BuildEXE(build_exe):
manifest_resource_id = 0 manifest_resource_id = 0
QT_PREFIX = r'C:\\Qt\\4.3.0'
MANIFEST_TEMPLATE = ''' MANIFEST_TEMPLATE = '''
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
@ -393,7 +394,20 @@ class BuildEXE(build_exe):
print 'Adding', qtxmldll print 'Adding', qtxmldll
shutil.copyfile(qtxmldll, shutil.copyfile(qtxmldll,
os.path.join(self.dist_dir, os.path.basename(qtxmldll))) os.path.join(self.dist_dir, os.path.basename(qtxmldll)))
print 'Adding plugins...',
qt_prefix = self.QT_PREFIX
if qtsvgdll:
qt_prefix = os.path.dirname(os.path.dirname(qtsvgdll))
plugdir = os.path.join(qt_prefix, 'plugins')
for d in ('imageformats', 'codecs', 'iconengines'):
print d,
imfd = os.path.join(plugdir, d)
tg = os.path.join(self.dist_dir, d)
if os.path.exists(tg):
shutil.rmtree(tg)
shutil.copytree(imfd, tg)
print
print print
print 'Building Installer' print 'Building Installer'
installer = NSISInstaller(APPNAME, self.dist_dir, 'dist') installer = NSISInstaller(APPNAME, self.dist_dir, 'dist')