mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
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:
parent
7491a8d20e
commit
49d70e0f9e
@ -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 = {
|
||||
|
@ -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>
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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():
|
||||
|
Loading…
x
Reference in New Issue
Block a user