2015-05-22 17:05:15 +08:00
|
|
|
from quamash import QtCore
|
2015-08-17 23:03:18 +08:00
|
|
|
import numpy as np
|
2014-12-30 18:40:19 +08:00
|
|
|
|
|
|
|
|
2015-08-08 11:08:04 +08:00
|
|
|
def elide(s, maxlen):
|
|
|
|
elided = False
|
|
|
|
if len(s) > maxlen:
|
|
|
|
s = s[:maxlen]
|
|
|
|
elided = True
|
|
|
|
try:
|
|
|
|
idx = s.index("\n")
|
|
|
|
except ValueError:
|
|
|
|
pass
|
|
|
|
else:
|
|
|
|
s = s[:idx]
|
|
|
|
elided = True
|
|
|
|
if elided:
|
|
|
|
maxlen -= 3
|
|
|
|
if len(s) > maxlen:
|
|
|
|
s = s[:maxlen]
|
|
|
|
s += "..."
|
|
|
|
return s
|
2015-07-25 00:32:18 +08:00
|
|
|
|
|
|
|
|
2015-07-22 06:01:09 +08:00
|
|
|
def short_format(v):
|
2015-08-06 18:03:05 +08:00
|
|
|
if v is None:
|
|
|
|
return "None"
|
2015-07-22 06:01:09 +08:00
|
|
|
t = type(v)
|
2015-08-17 23:14:18 +08:00
|
|
|
if np.issubdtype(t, int) or np.issubdtype(t, float):
|
2015-07-22 06:01:09 +08:00
|
|
|
return str(v)
|
2015-07-25 14:37:19 +08:00
|
|
|
elif t is str:
|
2015-08-08 11:08:04 +08:00
|
|
|
return "\"" + elide(v, 15) + "\""
|
2015-07-22 06:01:09 +08:00
|
|
|
else:
|
|
|
|
r = t.__name__
|
|
|
|
if t is list or t is dict or t is set:
|
|
|
|
r += " ({})".format(len(v))
|
|
|
|
return r
|
|
|
|
|
|
|
|
|
2015-07-22 05:13:46 +08:00
|
|
|
class _SyncSubstruct:
|
2015-05-17 16:11:00 +08:00
|
|
|
def __init__(self, update_cb, ref):
|
|
|
|
self.update_cb = update_cb
|
|
|
|
self.ref = ref
|
|
|
|
|
2015-07-14 23:30:55 +08:00
|
|
|
def append(self, x):
|
|
|
|
self.ref.append(x)
|
|
|
|
self.update_cb()
|
|
|
|
|
|
|
|
def insert(self, i, x):
|
|
|
|
self.ref.insert(i, x)
|
|
|
|
self.update_cb()
|
|
|
|
|
|
|
|
def pop(self, i=-1):
|
|
|
|
self.ref.pop(i)
|
|
|
|
self.update_cb()
|
2015-05-17 16:11:00 +08:00
|
|
|
|
|
|
|
def __setitem__(self, key, value):
|
|
|
|
self.ref[key] = value
|
|
|
|
self.update_cb()
|
|
|
|
|
2015-07-14 23:30:55 +08:00
|
|
|
def __delitem__(self, key):
|
|
|
|
self.ref.__delitem__(key)
|
|
|
|
self.update_cb()
|
|
|
|
|
|
|
|
def __getitem__(self, key):
|
2015-07-22 05:13:46 +08:00
|
|
|
return _SyncSubstruct(self.update_cb, self.ref[key])
|
2015-07-14 23:30:55 +08:00
|
|
|
|
2015-05-17 16:11:00 +08:00
|
|
|
|
2015-05-22 17:05:15 +08:00
|
|
|
class DictSyncModel(QtCore.QAbstractTableModel):
|
|
|
|
def __init__(self, headers, parent, init):
|
|
|
|
self.headers = headers
|
2015-06-19 00:02:40 +08:00
|
|
|
self.backing_store = init
|
|
|
|
self.row_to_key = sorted(self.backing_store.keys(),
|
|
|
|
key=lambda k: self.sort_key(k, self.backing_store[k]))
|
2015-05-22 17:05:15 +08:00
|
|
|
QtCore.QAbstractTableModel.__init__(self, parent)
|
|
|
|
|
|
|
|
def rowCount(self, parent):
|
2015-06-19 00:02:40 +08:00
|
|
|
return len(self.backing_store)
|
2015-05-22 17:05:15 +08:00
|
|
|
|
|
|
|
def columnCount(self, parent):
|
|
|
|
return len(self.headers)
|
|
|
|
|
|
|
|
def data(self, index, role):
|
|
|
|
if not index.isValid():
|
|
|
|
return None
|
|
|
|
elif role != QtCore.Qt.DisplayRole:
|
|
|
|
return None
|
|
|
|
k = self.row_to_key[index.row()]
|
2015-06-19 00:02:40 +08:00
|
|
|
return self.convert(k, self.backing_store[k], index.column())
|
2015-05-22 17:05:15 +08:00
|
|
|
|
|
|
|
def headerData(self, col, orientation, role):
|
|
|
|
if (orientation == QtCore.Qt.Horizontal
|
|
|
|
and role == QtCore.Qt.DisplayRole):
|
|
|
|
return self.headers[col]
|
|
|
|
return None
|
|
|
|
|
|
|
|
def _find_row(self, k, v):
|
|
|
|
lo = 0
|
|
|
|
hi = len(self.row_to_key)
|
|
|
|
while lo < hi:
|
|
|
|
mid = (lo + hi)//2
|
|
|
|
if (self.sort_key(self.row_to_key[mid],
|
2015-06-19 00:02:40 +08:00
|
|
|
self.backing_store[self.row_to_key[mid]])
|
2015-05-22 17:05:15 +08:00
|
|
|
< self.sort_key(k, v)):
|
|
|
|
lo = mid + 1
|
|
|
|
else:
|
|
|
|
hi = mid
|
|
|
|
return lo
|
|
|
|
|
|
|
|
def __setitem__(self, k, v):
|
2015-06-19 00:02:40 +08:00
|
|
|
if k in self.backing_store:
|
2015-05-22 17:05:15 +08:00
|
|
|
old_row = self.row_to_key.index(k)
|
|
|
|
new_row = self._find_row(k, v)
|
|
|
|
if old_row == new_row:
|
|
|
|
self.dataChanged.emit(self.index(old_row, 0),
|
|
|
|
self.index(old_row, len(self.headers)))
|
|
|
|
else:
|
|
|
|
self.beginMoveRows(QtCore.QModelIndex(), old_row, old_row,
|
|
|
|
QtCore.QModelIndex(), new_row)
|
2015-06-19 00:02:40 +08:00
|
|
|
self.backing_store[k] = v
|
2015-05-22 17:05:15 +08:00
|
|
|
self.row_to_key[old_row], self.row_to_key[new_row] = \
|
|
|
|
self.row_to_key[new_row], self.row_to_key[old_row]
|
|
|
|
if old_row != new_row:
|
|
|
|
self.endMoveRows()
|
2015-01-02 22:09:02 +08:00
|
|
|
else:
|
2015-05-22 17:05:15 +08:00
|
|
|
row = self._find_row(k, v)
|
|
|
|
self.beginInsertRows(QtCore.QModelIndex(), row, row)
|
2015-06-19 00:02:40 +08:00
|
|
|
self.backing_store[k] = v
|
2015-05-22 17:05:15 +08:00
|
|
|
self.row_to_key.insert(row, k)
|
|
|
|
self.endInsertRows()
|
|
|
|
|
|
|
|
def __delitem__(self, k):
|
|
|
|
row = self.row_to_key.index(k)
|
|
|
|
self.beginRemoveRows(QtCore.QModelIndex(), row, row)
|
|
|
|
del self.row_to_key[row]
|
2015-06-19 00:02:40 +08:00
|
|
|
del self.backing_store[k]
|
2015-05-22 17:05:15 +08:00
|
|
|
self.endRemoveRows()
|
2015-05-17 16:11:00 +08:00
|
|
|
|
2015-07-22 05:13:46 +08:00
|
|
|
def __getitem__(self, k):
|
2015-05-17 16:11:00 +08:00
|
|
|
def update():
|
2015-07-22 05:13:46 +08:00
|
|
|
self[k] = self.backing_store[k]
|
|
|
|
return _SyncSubstruct(update, self.backing_store[k])
|
2015-01-02 22:09:02 +08:00
|
|
|
|
2015-05-22 17:05:15 +08:00
|
|
|
def sort_key(self, k, v):
|
2015-01-02 22:09:02 +08:00
|
|
|
raise NotImplementedError
|
|
|
|
|
2015-05-22 17:05:15 +08:00
|
|
|
def convert(self, k, v, column):
|
2015-01-02 22:09:02 +08:00
|
|
|
raise NotImplementedError
|
2015-07-22 05:13:46 +08:00
|
|
|
|
|
|
|
|
|
|
|
class ListSyncModel(QtCore.QAbstractTableModel):
|
|
|
|
def __init__(self, headers, parent, init):
|
|
|
|
self.headers = headers
|
|
|
|
self.backing_store = init
|
|
|
|
QtCore.QAbstractTableModel.__init__(self, parent)
|
|
|
|
|
|
|
|
def rowCount(self, parent):
|
|
|
|
return len(self.backing_store)
|
|
|
|
|
|
|
|
def columnCount(self, parent):
|
|
|
|
return len(self.headers)
|
|
|
|
|
|
|
|
def data(self, index, role):
|
|
|
|
if not index.isValid():
|
|
|
|
return None
|
|
|
|
elif role != QtCore.Qt.DisplayRole:
|
|
|
|
return None
|
|
|
|
return self.convert(self.backing_store[index.row()], index.column())
|
|
|
|
|
|
|
|
def headerData(self, col, orientation, role):
|
|
|
|
if (orientation == QtCore.Qt.Horizontal
|
|
|
|
and role == QtCore.Qt.DisplayRole):
|
|
|
|
return self.headers[col]
|
|
|
|
return None
|
|
|
|
|
|
|
|
def __setitem__(self, k, v):
|
|
|
|
self.dataChanged.emit(self.index(k, 0),
|
|
|
|
self.index(k, len(self.headers)))
|
|
|
|
self.backing_store[k] = v
|
|
|
|
|
|
|
|
def __delitem__(self, k):
|
|
|
|
self.beginRemoveRows(QtCore.QModelIndex(), k, k)
|
|
|
|
del self.backing_store[k]
|
|
|
|
self.endRemoveRows()
|
|
|
|
|
|
|
|
def __getitem__(self, k):
|
|
|
|
def update():
|
|
|
|
self[k] = self.backing_store[k]
|
|
|
|
return _SyncSubstruct(update, self.backing_store[k])
|
|
|
|
|
|
|
|
def append(self, v):
|
|
|
|
row = len(self.backing_store)
|
|
|
|
self.beginInsertRows(QtCore.QModelIndex(), row, row)
|
|
|
|
self.backing_store.append(v)
|
|
|
|
self.endInsertRows()
|
|
|
|
|
|
|
|
def convert(self, v, column):
|
|
|
|
raise NotImplementedError
|