Exemple #1
0
 def __init__(self, device, probe=False):
     QAbstractItemModel.__init__(self)
     # map ob.name -> GuiItem instance
     self.probe = probe
     self.device_items = {}
     if probe:
         self.root_items = self.populate_items(device)
     else:
         self.root_items = []
         if hasattr(device, "stateMachine"):
             self.root_items.append(self.populate_stateMachine(device))
         self.method_items = self.populate_methods(device)
         self.root_items += self.method_items
         self.root_items.append(self.populate_attributes(device))
     self.device = device
     self.sub = ServerSubscription(device, "", self.on_change)
     self.sub.loop_run()
Exemple #2
0
class GuiModel(QAbstractItemModel):

    def __init__(self, device, probe=False):
        QAbstractItemModel.__init__(self)
        # map ob.name -> GuiItem instance
        self.probe = probe
        self.device_items = {}
        if probe:
            self.root_items = self.populate_items(device)
        else:
            self.root_items = []
            if hasattr(device, "stateMachine"):
                self.root_items.append(self.populate_stateMachine(device))
            self.method_items = self.populate_methods(device)
            self.root_items += self.method_items
            self.root_items.append(self.populate_attributes(device))
        self.device = device
        self.sub = ServerSubscription(device, "", self.on_change)
        self.sub.loop_run()

    def populate_methods(self, device):
        off = len(self.root_items)
        ret = []
        for mname, mval in device.methods.items():
            if not self.probe and mname in ("exit", "validate"):
                continue
            row = len(ret)
            # make an item for each method
            parent_item = self.make_item(row + off, mname, mval)
            # now make a child item for each argument
            for aname, aval in mval.arguments.items():
                if aname != "block":
                    row = len(parent_item.children)
                    name_list = ["methods", mname, "arguments", aname]
                    item = self.make_item(
                        row, aname, aval, ".".join(name_list), parent_item)
                    parent_item.children.append(item)
                    self.populate_items(aval, name_list, item)
            ret.append(parent_item)
        return ret

    def populate_stateMachine(self, device):
        row = len(self.root_items)
        stateMachine_item = self.make_item(row, "stateMachine",
                                           device.stateMachine)
        self.populate_items(device.stateMachine, ["stateMachine"],
                            stateMachine_item)
        return stateMachine_item

    def populate_attributes(self, device):
        row = len(self.root_items)
        attributes_item = self.make_item(row, "attributes")
        self.populate_items(device.attributes, ["attributes"], attributes_item)
        return attributes_item

    def make_item(self, row, name, val="", fullname=None, parent_item=None):
        # create value index
        item = GuiItem(name, val, parent_item, row)
        item.index = self.createIndex(row, 1, item)
        # add self into map
        if fullname:
            self.device_items[fullname] = item
        return item

    def populate_items(self, ob, parent_name=[], parent_item=None):
        if hasattr(ob, "to_dict"):
            ob = ob.to_dict()
        # If we have children
        ret = []
        if hasattr(ob, "keys"):
            # items we have created
            for row, (cname, cval) in enumerate(ob.items()):
                name_list = parent_name + [cname]
                item = self.make_item(row, cname, cval, ".".join(name_list),
                                      parent_item)
                if parent_item is not None:
                    parent_item.children.append(item)
                # add any children
                self.populate_items(cval, name_list, item)
                self.update_parents(item)
                ret.append(item)
        return ret

    def on_change(self, typ, value, changes):
        for c, val in changes.items():
            if c in self.device_items:
                item = self.device_items[c]
                item.data = val
                self.dataChanged.emit(item.index, item.index)
                self.update_parents(item)
            if c == "stateMachine.state":
                # redraw method buttons
                for item in self.method_items:
                    self.dataChanged.emit(item.index, item.index)

    def update_parents(self, item):
        # keep traversing up until we find something we should regenerate
        if item.parent_item and item.parent_item.name == "attributes":
            self.dataChanged.emit(item.index, item.index)
        elif item.name == "stateMachine":
            self.dataChanged.emit(item.index, item.index)
        elif item.parent_item:
            self.update_parents(item.parent_item)

    def index(self, row, column, parent=QModelIndex()):
        # Check row and column in range
        if row < 0 or row >= self.rowCount(parent) or \
                column < 0 or column >= self.columnCount(parent):
            return QModelIndex()
        if not parent.isValid():
            # If parent isn't valid, we're being asked for our root item
            child_item = self.root_items[row]
        else:
            # Otherwise fetch it from the index
            parent_item = parent.internalPointer()
            child_item = parent_item.children[row]
        # Now make an index
        index = self.createIndex(row, column, child_item)
        return index

    def parent(self, index):
        # Check valid index
        if not index.isValid():
            return QModelIndex()
        child_item = index.internalPointer()
        # Check child's parent exists
        if child_item.parent_item is None:
            return QModelIndex()
        # Return an index for us
        index = self.createIndex(child_item.parent_row, 0,
                                 child_item.parent_item)
        return index

    def rowCount(self, parent):
        if parent.column() > 0:
            return 0
        if not parent.isValid():
            return len(self.root_items)
        else:
            parent_item = parent.internalPointer()
            rows = len(parent_item.children)
            return rows

    def columnCount(self, parent):
        return 2

    def data(self, index, role):
        if not index.isValid():
            return None
        # Get item
        item = index.internalPointer()
        if index.column() == 0:
            # name
            if role == Qt.DisplayRole:
                if item.dirty:
                    return QVariant(item.name + " *")
                else:
                    return QVariant(item.name)
        else:
            # value
            if role == Qt.DisplayRole:
                return self.format_data(item)
            elif role == Qt.EditRole:
                return self.format_data(item)
            elif role == Qt.BackgroundRole:
                if self.isArgument(item) or self.isWriteable(item):
                    # alternating background as specified by stylesheet
                    return None
                else:
                    # and a bit darker
                    return QBrush(QColor(0, 0, 0, 176))
            elif role == Qt.ToolTipRole:
                txts = ["value: {}".format(self.format_data(item))]
                for attr in ("descriptor", "type", "alarm", "timeStamp"):
                    if hasattr(item.data, attr):
                        txts.append("{}: {}".format(attr, getattr(item.data, attr)))
                return "\n\n".join(txts)
            elif role == Qt.ForegroundRole:
                alarm = getattr(item.data, "alarm", None)
                severity = getattr(alarm, "severity", AlarmSeverity.noAlarm)
                if self.isArgument(item) or self.isWriteable(item):
                    return QBrush(QColor(0, 0, 196))
                elif severity == AlarmSeverity.noAlarm:
                    return QBrush(QColor(96, 255, 96))
                elif severity == AlarmSeverity.minorAlarm:
                    return QBrush(QColor(255, 241, 0))
                elif severity == AlarmSeverity.majorAlarm:
                    return QBrush(QColor(255, 0, 0))
                else:
                    return QBrush(QColor(255, 240, 255))

    def isArgument(self, item):
        if self.probe:
            # method.argument.value
            isargument = item.parent_item and item.parent_item.parent_item and isinstance(
                item.parent_item.parent_item.data, Method)
        else:
            # method.argument
            isargument = item.parent_item and isinstance(
                item.parent_item.data, Method)
        return isargument

    def isWriteable(self, item):
        if self.probe:
            # attribute.value
            iswriteable = item.parent_item and isinstance(
                item.parent_item.data, Attribute) and item.parent_item.data.put_method_name()
        else:
            # attribute
            iswriteable = isinstance(item.data, Attribute) and item.data.put_method_name()
        return iswriteable

    def setData(self, index, value, role=Qt.EditRole):
        if role == Qt.EditRole:
            if index.isValid():
                item = index.internalPointer()
                if self.isArgument(item):
                    newvalue = str(value.toString())
                    if isinstance(item.data.typ, VBool):
                        newvalue = newvalue.lower() != "false"
                    if newvalue != str(item.argvalue):
                        item.argvalue = newvalue
                        item.dirty = True
                        label = index.sibling(index.row(), 0)
                        self.dataChanged.emit(label, index)
                        return True
                elif self.isWriteable(item):
                    newvalue = str(value.toString())
                    if isinstance(item.data.typ, VBool):
                        newvalue = newvalue.lower() != "false"
                    import cothread
                    cothread.Spawn(self.do_put, index, newvalue)
                    return True
                elif isinstance(item.data, Method):
                    args = {}
                    for child_item in item.children:
                        child_item.dirty = False
                        args[child_item.name] = child_item.argvalue
                    childleft = self.index(0, 0, index)
                    childright = self.index(1, len(item.children) - 1, index)
                    self.dataChanged.emit(childleft, childright)
                    item.argvalue = "Running"
                    self.dataChanged.emit(index, index)
                    import cothread
                    cothread.Spawn(self.run_method, index, **args)
                    return True
        return False

    def run_method(self, index, **args):
        item = index.internalPointer()
        method = item.data
        try:
            # TODO: something with ret here
            ret = method(**args)
        except:
            method.log_exception("Exception raised from gui")
        finally:
            item.argvalue = None
            self.dataChanged.emit(index, index)

    def do_put(self, index, value):
        item = index.internalPointer()
        if self.probe:
            item = item.parent_item
        attr = item.data
        try:
            # TODO: something with ret here
            ret = attr.update(value)
        except:
            attr.log_exception("Exception raised from gui")

    def flags(self, index):
        flags = QAbstractItemModel.flags(self, index)
        if index.isValid() and index.column() == 1:
            item = index.internalPointer()
            if self.isArgument(item) or self.isWriteable(item) or isinstance(item.data, Method):
                flags |= Qt.ItemIsEditable
        return flags

    def format_data(self, item):
        ob = item.data
        if self.isArgument(item):
            return str(item.argvalue)
        elif isinstance(ob, Attribute):
            # Report value
            return str(ob.value)
        elif isinstance(ob, StateMachine):
            # Report state, message
            return "{}: {}".format(ob.state.name, ob.message)
        elif isinstance(ob, list):
            return "\n".join(str(o) for o in ob)
        else:
            return str(ob)

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if orientation == Qt.Horizontal and role == Qt.DisplayRole:
            label = ["name", "value"][section]
            return label
        return QVariant()