def loadElements(self, rows): """ elemplist - a list of (elem obj, field). *field=None* means separator. """ self.beginResetModel() self.clear() for i, (elem, fld) in enumerate(rows): pvsp = elem.pv(field=fld, handle="setpoint") for j, pv in enumerate(pvsp): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i, C_VAL_SP, j)) pvrb = elem.pv(field=fld, handle="readback") for j, pv in enumerate(pvrb): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i, C_VAL_RB, j)) # one data record, pvs are all list rec = [elem, fld, [None] * len(pvsp), [None] * len(pvrb)] for j, s in enumerate(self._unitsys): rec.append([None] * len(pvrb)) self._data.append(tuple(rec)) self._pvlst.append(pvsp + pvrb) self._block = [0] k = 0 for i in range(1, len(rows)): elem, fld = rows[i] if elem != rows[i - 1][0]: k += 1 self._block.append(k) self._cadata = CaDataMonitor(wait=0.0) for pv in self._pvidx.keys(): #self._cadata.addHook(pv, self._ca_update) self._cadata.addHook(pv, self._ca_update) self._cadata.addPv(self._pvidx.keys()) self.endResetModel() self._cadata.start()
def loadElements(self, rows): """ elemplist - a list of (elem obj, field). *field=None* means separator. """ self.beginResetModel() self.clear() for i, (elem, fld) in enumerate(rows): pvsp = elem.pv(field=fld, handle="setpoint") for j,pv in enumerate(pvsp): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i,C_VAL_SP,j)) pvrb = elem.pv(field=fld, handle="readback") for j,pv in enumerate(pvrb): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i,C_VAL_RB,j)) # one data record, pvs are all list rec = [elem, fld, [None] * len(pvsp), [None] * len(pvrb)] for j,s in enumerate(self._unitsys): rec.append([None] * len(pvrb)) self._data.append(tuple(rec)) self._pvlst.append(pvsp + pvrb) self._block = [0] k = 0 for i in range(1, len(rows)): elem, fld = rows[i] if elem != rows[i-1][0]: k += 1 self._block.append(k) self._cadata = CaDataMonitor(wait=0.0) for pv in self._pvidx.keys(): #self._cadata.addHook(pv, self._ca_update) self._cadata.addHook(pv, self._ca_update) self._cadata.addPv(self._pvidx.keys()) self.endResetModel() self._cadata.start()
class ElementPropertyTableModel(QAbstractTableModel): def __init__(self, **kwargs): super(ElementPropertyTableModel, self).__init__() # elem obj, idx, name/fld self._unitsys = ['phy'] self._unitsymb = [] self._data = [] self._block = [] # block of fields for one element self._inactive = [] self._pvidx = {} # map pv to row,column,idx self._pvlst = [] # map row to pv list self._cadata = None self._t0 = datetime.now() def clear(self): if self._cadata: self._cadata.close() idx0 = self.index(0, 0) idx1 = self.index(len(self._data) - 1, self.columnCount() - 1) self._data = [] self._pvidx = {} self._pvlst = [] self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx0, idx1) def loadElements(self, rows): """ elemplist - a list of (elem obj, field). *field=None* means separator. """ self.beginResetModel() self.clear() for i, (elem, fld) in enumerate(rows): pvsp = elem.pv(field=fld, handle="setpoint") for j, pv in enumerate(pvsp): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i, C_VAL_SP, j)) pvrb = elem.pv(field=fld, handle="readback") for j, pv in enumerate(pvrb): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i, C_VAL_RB, j)) # one data record, pvs are all list rec = [elem, fld, [None] * len(pvsp), [None] * len(pvrb)] for j, s in enumerate(self._unitsys): rec.append([None] * len(pvrb)) self._data.append(tuple(rec)) self._pvlst.append(pvsp + pvrb) self._block = [0] k = 0 for i in range(1, len(rows)): elem, fld = rows[i] if elem != rows[i - 1][0]: k += 1 self._block.append(k) self._cadata = CaDataMonitor(wait=0.0) for pv in self._pvidx.keys(): #self._cadata.addHook(pv, self._ca_update) self._cadata.addHook(pv, self._ca_update) self._cadata.addPv(self._pvidx.keys()) self.endResetModel() self._cadata.start() def _ca_update(self, val, idx=None): #print val.name, val for i, j, k in self._pvidx[val.name]: self._data[i][j][k] = val t1 = datetime.now() if (t1 - self._t0).total_seconds() > 1: idx0 = self.index(0, C_VAL_SP) idx1 = self.index(len(self._data) - 1, self.columnCount() - 1) self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx0, idx1) self._t0 = datetime.now() def getElementField(self, row): return self._data[row][:2] def checkDeadPvs(self): if len(self._deadpvs) == 0: return pvs = list(self._deadpvs) vals = aphla.catools.caget(pvs, timeout=2) for i, val in enumerate(vals): if val.ok: self._deadpvs.remove(pvs[i]) def updateData(self, row0, row1): pvs = reduce(lambda a, b: a + b, [self._pvlst[i] for i in range(row0, row1)]) pvs = [pv for pv in pvs if pv not in self._deadpvs] vals = aphla.catools.caget(pvs) for ipv, pv in enumerate(pvs): if not vals[ipv].ok: self._deadpvs.add(pv) continue for i, j, k in self._pvidx[pv]: self._data[i][j][k] = vals[ipv] if j == C_VAL_RB: elem, fld = self._data[i][:2] for isys, usys in enumerate(self._unitsys): if usys not in elem.getUnitSystems(field=fld): self._data[i][j + isys + 1][k] = '' continue self._data[i][j+isys+1][k] = \ elem.convertUnit(fld, val, None, usys) print("Updated") idx0 = self.index(row0, C_VAL_SP) idx1 = self.index(row1 - 1, self.columnCount() - 1) self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx0, idx1) #QtGui.qApp.processEvents() def _cadata_to_qv(self, vals): """ this is cadata, it is a list even for scalar """ # assume it is a cadata, must be a list if len(vals) == 0: return QVariant() elif len(vals) > 1: return QVariant("...") # size 1 val = vals[0] if val is None: return QVariant() elif isinstance(val, (float, np.float32)): return QVariant(float(val)) elif isinstance(val, str): return QVariant(QString(val)) elif isinstance(val, int): return QVariant(int(val)) elif isinstance(val, (list, tuple)): return [self._cadata_to_qvariant(v) for v in val] elif isinstance(val, cothread.dbr.ca_array): return [self._cadata_to_qvariant(v) for v in val] elif not val.ok: return QVariant(QString("Disconnected")) else: raise RuntimeError("Unknow data type: {0} ({1})".format( type(val), val)) def isSubHeader(self, i): return self._data[i][1] is None def data(self, index, role=Qt.DisplayRole): """return data as a QVariant""" #print "data model=",role if not index.isValid() or index.row() >= len(self._data): return QVariant() r, col = index.row(), index.column() elem, fld = self._data[r][:2] if role == Qt.DisplayRole: #if r == 0: print r, col, elem.name, fld, self._data[r][col], "//" if col == C_ELEM: return QVariant(QString(elem.name)) elif col == C_FIELD: return QVariant(QString(fld)) elif col == C_VAL_SP or col == C_VAL_RB: return self._cadata_to_qv(self._data[r][col]) # other unit system unitsys = self._unitsys[col - C_VAL_RB - 1] try: vals = elem.convertUnit(fld, self._data[r][C_VAL_RB], None, unitsys) return self._cadata_to_qv(vals) except: return QVariant() #elif role == Qt.EditRole: # if col == C_FIELD: # raise RuntimeError("what is this ?") # return QVariant(self._field[r]+self._fieldpfx[r]) # #print r, col, self._field[r], self._value[r] # if vals is None: return QVariant() # if isinstance(vals[col-1], (tuple, list)): # return QVariant.fromList([QVariant(v) for v in vals[col-1]]) # elif vals[col-1] is not None: # return QVariant(vals[col-1]) elif role == Qt.TextAlignmentRole: if col == C_FIELD: return QVariant(Qt.AlignLeft | Qt.AlignVCenter) else: return QVariant(Qt.AlignRight | Qt.AlignBottom) elif role == Qt.ToolTipRole: if col == C_ELEM or col == C_FIELD: return QVariant("{0}, sb={1}, L={2}".format( elem.family, elem.sb, elem.length)) elif col == C_VAL_SP: pv = elem.pv(field=fld, handle="setpoint") return QVariant(", ".join(pv)) elif col == C_VAL_RB: pv = elem.pv(field=fld, handle="readback") return QVariant(", ".join(pv)) elif col > C_VAL_RB: unitsys = self._unitsys[col - C_VAL_RB - 1] #print "Checking the unit:", unitsys, elem.getUnit(fld, unitsys) return QVariant(str(elem.getUnit(fld, unitsys))) elif role == Qt.ForegroundRole: #if idx == 0: return QColor(Qt.darkGray) #if r in self._inactive and self.isHeadIndex(r): # return QColor(Qt.darkGray) #elif r in self._inactive: # return QColor(Qt.lightGray) #else: return QColor(Qt.black) return QVariant() elif role == Qt.BackgroundRole: if self._block[r] % 2 == 0: return QVariant() else: return QColor(0xE0, 0xE0, 0xE0) elif role == Qt.CheckStateRole: #if vals is not None: return QVariant() #elif r in self._inactive: return Qt.Unchecked #else: return Qt.Checked #if idx == 0 and col == C_FIELD: return Qt.Checked return QVariant() else: return QVariant() #print "Asking data role=", role return QVariant() def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: return QVariant(int(Qt.AlignLeft | Qt.AlignVCenter)) return QVariant(int(Qt.AlignRight | Qt.AlignVCenter)) if role != Qt.DisplayRole: return QVariant() if orientation == Qt.Horizontal: #print "Section:", section, C_VAL_RB if section == C_FIELD: return QVariant("Field") elif section == C_VAL_SP: return QVariant("Setpoint") elif section == C_VAL_RB: return QVariant("Readback") elif section > C_VAL_RB and section < C_VAL_RB + len( self._unitsys): return QVariant(self._unitsys[section - 1 - C_VAL_RB]) else: return QVariant() elif orientation == Qt.Vertical: #if self._value[section] is not None: return QVariant() #idx = [k for k in range(section+1) if self._value[k] is None] #return QVariant(len(idx)) return QVariant(section) #return QVariant(int(section+1)) return QVariant() def flags(self, index): #print "flags:", if not index.isValid(): return Qt.ItemIsEnabled row, col = index.row(), index.column() elem, fld = self._data[row][:2] if col == C_VAL_SP and fld is not None: return Qt.ItemFlags( QAbstractTableModel.flags(self, index) | Qt.ItemIsSelectable) #return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | # Qt.ItemIsEditable) return Qt.ItemIsEnabled def rowCount(self, index=QModelIndex()): return len(self._data) def columnCount(self, index=QModelIndex()): return C_VAL_RB + len(self._unitsys) + 1 def setElementActive(self, irow, active=True): rows = self._element_block(irow) if active: for i in rows: if i not in self._inactive: continue self._inactive.remove(i) else: for i in rows: if i in self._inactive: continue self._inactive.add(i) def isActive(self, irow): return irow not in self._inactive
class ElementPropertyTableModel(QAbstractTableModel): def __init__(self, **kwargs): super(ElementPropertyTableModel, self).__init__() # elem obj, idx, name/fld self._unitsys = ['phy'] self._unitsymb = [] self._data = [] self._block = [] # block of fields for one element self._inactive = [] self._pvidx = {} # map pv to row,column,idx self._pvlst = [] # map row to pv list self._cadata = None self._t0 = datetime.now() def clear(self): if self._cadata: self._cadata.close() idx0 = self.index(0, 0) idx1 = self.index(len(self._data) - 1, self.columnCount()-1) self._data = [] self._pvidx = {} self._pvlst = [] self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx0, idx1) def loadElements(self, rows): """ elemplist - a list of (elem obj, field). *field=None* means separator. """ self.beginResetModel() self.clear() for i, (elem, fld) in enumerate(rows): pvsp = elem.pv(field=fld, handle="setpoint") for j,pv in enumerate(pvsp): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i,C_VAL_SP,j)) pvrb = elem.pv(field=fld, handle="readback") for j,pv in enumerate(pvrb): self._pvidx.setdefault(pv, []) self._pvidx[pv].append((i,C_VAL_RB,j)) # one data record, pvs are all list rec = [elem, fld, [None] * len(pvsp), [None] * len(pvrb)] for j,s in enumerate(self._unitsys): rec.append([None] * len(pvrb)) self._data.append(tuple(rec)) self._pvlst.append(pvsp + pvrb) self._block = [0] k = 0 for i in range(1, len(rows)): elem, fld = rows[i] if elem != rows[i-1][0]: k += 1 self._block.append(k) self._cadata = CaDataMonitor(wait=0.0) for pv in self._pvidx.keys(): #self._cadata.addHook(pv, self._ca_update) self._cadata.addHook(pv, self._ca_update) self._cadata.addPv(self._pvidx.keys()) self.endResetModel() self._cadata.start() def _ca_update(self, val, idx = None): #print val.name, val for i,j,k in self._pvidx[val.name]: self._data[i][j][k] = val t1 = datetime.now() if (t1-self._t0).total_seconds() > 1: idx0 = self.index(0, C_VAL_SP) idx1 = self.index(len(self._data)-1, self.columnCount()-1) self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx0, idx1) self._t0 = datetime.now() def getElementField(self, row): return self._data[row][:2] def checkDeadPvs(self): if len(self._deadpvs) == 0: return pvs = list(self._deadpvs) vals = aphla.catools.caget(pvs, timeout=2) for i,val in enumerate(vals): if val.ok: self._deadpvs.remove(pvs[i]) def updateData(self, row0, row1): pvs = reduce(lambda a,b: a + b, [self._pvlst[i] for i in range(row0, row1)]) pvs = [pv for pv in pvs if pv not in self._deadpvs] vals = aphla.catools.caget(pvs) for ipv,pv in enumerate(pvs): if not vals[ipv].ok: self._deadpvs.add(pv) continue for i,j,k in self._pvidx[pv]: self._data[i][j][k] = vals[ipv] if j == C_VAL_RB: elem, fld = self._data[i][:2] for isys, usys in enumerate(self._unitsys): if usys not in elem.getUnitSystems(field=fld): self._data[i][j+isys+1][k] = '' continue self._data[i][j+isys+1][k] = \ elem.convertUnit(fld, val, None, usys) print "Updated" idx0 = self.index(row0, C_VAL_SP) idx1 = self.index(row1-1, self.columnCount()-1) self.emit(SIGNAL("dataChanged(QModelIndex,QModelIndex)"), idx0, idx1) #QtGui.qApp.processEvents() def _cadata_to_qv(self, vals): """ this is cadata, it is a list even for scalar """ # assume it is a cadata, must be a list if len(vals) == 0: return QVariant() elif len(vals) > 1: return QVariant("...") # size 1 val = vals[0] if val is None: return QVariant() elif isinstance(val, (float, np.float32)): return QVariant(float(val)) elif isinstance(val, str): return QVariant(QString(val)) elif isinstance(val, int): return QVariant(int(val)) elif isinstance(val, (list, tuple)): return [self._cadata_to_qvariant(v) for v in val] elif isinstance(val, cothread.dbr.ca_array): return [self._cadata_to_qvariant(v) for v in val] elif not val.ok: return QVariant(QString("Disconnected")) else: raise RuntimeError("Unknow data type: {0} ({1})".format( type(val), val)) def isSubHeader(self, i): return self._data[i][1] is None def data(self, index, role=Qt.DisplayRole): """return data as a QVariant""" #print "data model=",role if not index.isValid() or index.row() >= len(self._data): return QVariant() r, col = index.row(), index.column() elem, fld = self._data[r][:2] if role == Qt.DisplayRole: #if r == 0: print r, col, elem.name, fld, self._data[r][col], "//" if col == C_ELEM: return QVariant(QString(elem.name)) elif col == C_FIELD: return QVariant(QString(fld)) elif col == C_VAL_SP or col == C_VAL_RB: return self._cadata_to_qv(self._data[r][col]) # other unit system unitsys = self._unitsys[col - C_VAL_RB - 1] try: vals = elem.convertUnit(fld, self._data[r][C_VAL_RB], None, unitsys) return self._cadata_to_qv(vals) except: return QVariant() #elif role == Qt.EditRole: # if col == C_FIELD: # raise RuntimeError("what is this ?") # return QVariant(self._field[r]+self._fieldpfx[r]) # #print r, col, self._field[r], self._value[r] # if vals is None: return QVariant() # if isinstance(vals[col-1], (tuple, list)): # return QVariant.fromList([QVariant(v) for v in vals[col-1]]) # elif vals[col-1] is not None: # return QVariant(vals[col-1]) elif role == Qt.TextAlignmentRole: if col == C_FIELD: return QVariant(Qt.AlignLeft | Qt.AlignVCenter) else: return QVariant(Qt.AlignRight | Qt.AlignBottom) elif role == Qt.ToolTipRole: if col == C_ELEM or col == C_FIELD: return QVariant("{0}, sb={1}, L={2}".format( elem.family, elem.sb, elem.length)) elif col == C_VAL_SP: pv = elem.pv(field=fld, handle="setpoint") return QVariant(", ".join(pv)) elif col == C_VAL_RB: pv = elem.pv(field=fld, handle="readback") return QVariant(", ".join(pv)) elif col > C_VAL_RB: unitsys = self._unitsys[col - C_VAL_RB - 1] #print "Checking the unit:", unitsys, elem.getUnit(fld, unitsys) return QVariant(str(elem.getUnit(fld, unitsys))) elif role == Qt.ForegroundRole: #if idx == 0: return QColor(Qt.darkGray) #if r in self._inactive and self.isHeadIndex(r): # return QColor(Qt.darkGray) #elif r in self._inactive: # return QColor(Qt.lightGray) #else: return QColor(Qt.black) return QVariant() elif role == Qt.BackgroundRole: if self._block[r] % 2 == 0: return QVariant() else: return QColor(0xE0, 0xE0, 0xE0) elif role == Qt.CheckStateRole: #if vals is not None: return QVariant() #elif r in self._inactive: return Qt.Unchecked #else: return Qt.Checked #if idx == 0 and col == C_FIELD: return Qt.Checked return QVariant() else: return QVariant() #print "Asking data role=", role return QVariant() def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.TextAlignmentRole: if orientation == Qt.Horizontal: return QVariant(int(Qt.AlignLeft|Qt.AlignVCenter)) return QVariant(int(Qt.AlignRight|Qt.AlignVCenter)) if role != Qt.DisplayRole: return QVariant() if orientation == Qt.Horizontal: #print "Section:", section, C_VAL_RB if section == C_FIELD: return QVariant("Field") elif section == C_VAL_SP: return QVariant("Setpoint") elif section == C_VAL_RB: return QVariant("Readback") elif section > C_VAL_RB and section < C_VAL_RB + len(self._unitsys): return QVariant(self._unitsys[section-1-C_VAL_RB]) else: return QVariant() elif orientation == Qt.Vertical: #if self._value[section] is not None: return QVariant() #idx = [k for k in range(section+1) if self._value[k] is None] #return QVariant(len(idx)) return QVariant(section) #return QVariant(int(section+1)) return QVariant() def flags(self, index): #print "flags:", if not index.isValid(): return Qt.ItemIsEnabled row, col = index.row(), index.column() elem, fld = self._data[row][:2] if col == C_VAL_SP and fld is not None: return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | Qt.ItemIsSelectable) #return Qt.ItemFlags(QAbstractTableModel.flags(self, index) | # Qt.ItemIsEditable) return Qt.ItemIsEnabled def rowCount(self, index=QModelIndex()): return len(self._data) def columnCount(self, index=QModelIndex()): return C_VAL_RB + len(self._unitsys) + 1 def setElementActive(self, irow, active = True): rows = self._element_block(irow) if active: for i in rows: if i not in self._inactive: continue self._inactive.remove(i) else: for i in rows: if i in self._inactive: continue self._inactive.add(i) def isActive(self, irow): return irow not in self._inactive