JSONConfig: Fix encoding of top level str objects. Add support for encoding bytearray objects. Remove pointless TableView class and have jobs view remember its column layout

This commit is contained in:
Kovid Goyal 2010-05-18 15:04:20 -06:00
parent 7491a8d20e
commit 49d70e0f9e
6 changed files with 76 additions and 88 deletions

View File

@ -8,7 +8,7 @@ from PyQt4.QtCore import QVariant, QFileInfo, QObject, SIGNAL, QBuffer, Qt, QSiz
QByteArray, QTranslator, QCoreApplication, QThread, \
QEvent, QTimer, pyqtSignal, QDate
from PyQt4.QtGui import QFileDialog, QMessageBox, QPixmap, QFileIconProvider, \
QIcon, QTableView, QApplication, QDialog, QPushButton
QIcon, QApplication, QDialog, QPushButton
ORG_NAME = 'KovidsBrain'
APP_UID = 'libprs500'
@ -294,34 +294,6 @@ class GetMetadata(QObject):
mi = MetaInformation('', [_('Unknown')])
self.emit(SIGNAL('metadata(PyQt_PyObject, PyQt_PyObject)'), id, mi)
class TableView(QTableView):
def __init__(self, parent):
QTableView.__init__(self, parent)
self.read_settings()
def read_settings(self):
self.cw = dynamic[self.__class__.__name__+'column width map']
def write_settings(self):
m = dynamic[self.__class__.__name__+'column width map']
if m is None:
m = {}
cmap = getattr(self.model(), 'column_map', None)
if cmap is not None:
for i,c in enumerate(cmap):
m[c] = self.columnWidth(i)
dynamic[self.__class__.__name__+'column width map'] = m
self.cw = m
def restore_column_widths(self):
if self.cw and len(self.cw):
for i,c in enumerate(self.model().column_map):
if c in self.cw:
self.setColumnWidth(i, self.cw[c])
return True
return False
class FileIconProvider(QFileIconProvider):
ICONS = {

View File

@ -14,12 +14,12 @@
<string>Active Jobs</string>
</property>
<property name="windowIcon">
<iconset resource="../../../work/calibre/resources/images.qrc">
<iconset resource="../../../../resources/images.qrc">
<normaloff>:/images/jobs.svg</normaloff>:/images/jobs.svg</iconset>
</property>
<layout class="QVBoxLayout">
<item>
<widget class="JobsView" name="jobs_view">
<widget class="QTableView" name="jobs_view">
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
@ -66,15 +66,8 @@
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>JobsView</class>
<extends>QTableView</extends>
<header>widgets.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../../../work/calibre/resources/images.qrc"/>
<include location="../../../../resources/images.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -15,10 +15,11 @@ from PyQt4.Qt import QAbstractTableModel, QVariant, QModelIndex, Qt, \
from calibre.utils.ipc.server import Server
from calibre.utils.ipc.job import ParallelJob
from calibre.gui2 import Dispatcher, error_dialog, NONE, config
from calibre.gui2 import Dispatcher, error_dialog, NONE, config, gprefs
from calibre.gui2.device import DeviceJob
from calibre.gui2.dialogs.jobs_ui import Ui_JobsDialog
from calibre import __appname__
from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
class JobManager(QAbstractTableModel):
@ -243,7 +244,32 @@ class ProgressBarDelegate(QAbstractItemDelegate):
opts.text = QString(_('Unavailable') if percent == 0 else '%d%%'%percent)
QApplication.style().drawControl(QStyle.CE_ProgressBar, opts, painter)
class DetailView(QDialog, Ui_Dialog):
def __init__(self, parent, job):
QDialog.__init__(self, parent)
self.setupUi(self)
self.setWindowTitle(job.description)
self.job = job
self.next_pos = 0
self.update()
self.timer = QTimer(self)
self.timer.timeout.connect(self.update)
self.timer.start(1000)
def update(self):
f = self.job.log_file
f.seek(self.next_pos)
more = f.read()
self.next_pos = f.tell()
if more:
self.log.appendPlainText(more.decode('utf-8', 'replace'))
class JobsDialog(QDialog, Ui_JobsDialog):
def __init__(self, window, model):
QDialog.__init__(self, window)
Ui_JobsDialog.__init__(self)
@ -252,8 +278,6 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.model = model
self.setWindowModality(Qt.NonModal)
self.setWindowTitle(__appname__ + _(' - Jobs'))
self.connect(self.jobs_view.model(), SIGNAL('modelReset()'),
self.jobs_view.resizeColumnsToContents)
self.connect(self.kill_button, SIGNAL('clicked()'),
self.kill_job)
self.connect(self.details_button, SIGNAL('clicked()'),
@ -264,7 +288,21 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.jobs_view.model().kill_job)
self.pb_delegate = ProgressBarDelegate(self)
self.jobs_view.setItemDelegateForColumn(2, self.pb_delegate)
self.jobs_view.doubleClicked.connect(self.show_job_details)
self.jobs_view.horizontalHeader().setMovable(True)
state = gprefs.get('jobs view column layout', None)
if state is not None:
try:
self.jobs_view.horizontalHeader().restoreState(bytes(state))
except:
pass
def show_job_details(self, index):
row = index.row()
job = self.jobs_view.model().row_to_job(row)
d = DetailView(self, job)
d.exec_()
d.timer.stop()
def kill_job(self):
for index in self.jobs_view.selectedIndexes():
@ -281,5 +319,9 @@ class JobsDialog(QDialog, Ui_JobsDialog):
self.model.kill_all_jobs()
def closeEvent(self, e):
self.jobs_view.write_settings()
try:
state = bytearray(self.jobs_view.horizontalHeader().saveState())
gprefs['jobs view column layout'] = state
except:
pass
e.accept()

View File

@ -33,16 +33,12 @@ class JobsButton(QFrame):
def initialize(self, jobs_dialog):
self.jobs_dialog = jobs_dialog
self.jobs_dialog.jobs_view.restore_column_widths()
def mouseReleaseEvent(self, event):
if self.jobs_dialog.isVisible():
self.jobs_dialog.jobs_view.write_settings()
self.jobs_dialog.hide()
else:
self.jobs_dialog.jobs_view.read_settings()
self.jobs_dialog.show()
self.jobs_dialog.jobs_view.restore_column_widths()
@property
def is_running(self):

View File

@ -7,15 +7,15 @@ import re, os, traceback
from PyQt4.Qt import QListView, QIcon, QFont, QLabel, QListWidget, \
QListWidgetItem, QTextCharFormat, QApplication, \
QSyntaxHighlighter, QCursor, QColor, QWidget, \
QPixmap, QPalette, QTimer, QDialog, QSplitterHandle, \
QPixmap, QPalette, QSplitterHandle, \
QAbstractListModel, QVariant, Qt, SIGNAL, pyqtSignal, \
QRegExp, QSettings, QSize, QModelIndex, QSplitter, \
QAbstractButton, QPainter, QLineEdit, QComboBox, \
QMenu, QStringListModel, QCompleter, QStringList
from calibre.gui2 import human_readable, NONE, TableView, \
from calibre.gui2 import human_readable, NONE, \
error_dialog, pixmap_to_data, dynamic
from calibre.gui2.dialogs.job_view_ui import Ui_Dialog
from calibre.gui2.filename_pattern_ui import Ui_Form
from calibre import fit_image
from calibre.utils.fonts import fontconfig
@ -399,41 +399,6 @@ class EjectButton(QAbstractButton):
painter.drawPixmap(0, 0, image)
class DetailView(QDialog, Ui_Dialog):
def __init__(self, parent, job):
QDialog.__init__(self, parent)
self.setupUi(self)
self.setWindowTitle(job.description)
self.job = job
self.next_pos = 0
self.update()
self.timer = QTimer(self)
self.connect(self.timer, SIGNAL('timeout()'), self.update)
self.timer.start(1000)
def update(self):
f = self.job.log_file
f.seek(self.next_pos)
more = f.read()
self.next_pos = f.tell()
if more:
self.log.appendPlainText(more.decode('utf-8', 'replace'))
class JobsView(TableView):
def __init__(self, parent):
TableView.__init__(self, parent)
self.connect(self, SIGNAL('doubleClicked(QModelIndex)'), self.show_details)
def show_details(self, index):
row = index.row()
job = self.model().row_to_job(row)
d = DetailView(self, job)
d.exec_()
d.timer.stop()
class FontFamilyModel(QAbstractListModel):

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
'''
Manage application-wide preferences.
'''
import os, re, cPickle, textwrap, traceback, plistlib, json
import os, re, cPickle, textwrap, traceback, plistlib, json, base64
from copy import deepcopy
from functools import partial
from optparse import OptionParser as _OptionParser
@ -636,11 +636,31 @@ class JSONConfig(XMLConfig):
EXTENSION = '.json'
def to_json(self, obj):
if isinstance(obj, bytearray):
return {'__class__': 'bytearray',
'__value__': base64.standard_b64encode(bytes(obj))}
raise TypeError(repr(obj) + ' is not JSON serializable')
def from_json(self, obj):
if '__class__' in obj:
if obj['__class__'] == 'bytearray':
return bytearray(base64.standard_b64decode(obj['__value__']))
return obj
def raw_to_object(self, raw):
return json.loads(raw.decode('utf-8'))
return json.loads(raw.decode('utf-8'), object_hook=self.from_json)
def to_raw(self):
return json.dumps(self, indent=2)
return json.dumps(self, indent=2, default=self.to_json)
def __getitem__(self, key):
return dict.__getitem__(self, key)
def __setitem__(self, key, val):
dict.__setitem__(self, key, val)
self.commit()
def _prefs():