示例#1
0
def get_selected_recs_ids(selection_model: QItemSelectionModel,
                          ndx_col: int = 0) -> Optional[Tuple[int, ...]]:
    """
    Get integer ids from selected records.
    Unless explicitely defines, it assumes that id is stored in column 0.

    :param selection_model: the selection model.
    :type selection_model: QItemSelectionModel.
    :param ndx_col: the index of the searched columns.
    :type ndx_col: int.
    :return: the sequence of ids.
    :rtype: tuple of integers.
    """

    # get selected records attitudes

    selected_records_ids = selection_model.selectedRows(column=ndx_col)

    if selected_records_ids:
        return tuple(
            map(lambda qmodel_ndx: qmodel_ndx.data(), selected_records_ids))
    else:
        return None
示例#2
0
class ListModel(QAbstractTableModel):
    orderChanged = pyqtSignal()
    elementSelected = pyqtSignal(int)

    class ColumnID(object):
        """
        Define how many column the model holds and their type

        """

        ncols = 2
        Name = 0
        Delete = 1

    def __init__(self, elements=None, parent=None):
        """
        Common interface for the labelListModel, the boxListModel, and the cropListModel
        see concrete implementations for details

        :param elements:
        :param parent:
        """
        QAbstractTableModel.__init__(self, parent)

        if elements is None:
            elements = []
        self._elements = list(elements)
        self._selectionModel = QItemSelectionModel(self)

        def onSelectionChanged(selected, deselected):

            if selected:
                ind = selected[0].indexes()
                if len(ind) > 0:
                    self.elementSelected.emit(ind[0].row())

        self._selectionModel.selectionChanged.connect(onSelectionChanged)

        self._allowRemove = True
        self._toolTipSuffixes = {}

        self.unremovable_rows = [
        ]  # rows in this list cannot be removed from the gui,
        # to add to this list call self.makeRowPermanent(int)
        # to remove make the self.makeRowRemovable(int)

    def makeRowPermanent(self, rowIndex):
        """
        The rowindex cannot be removed from gui
        to remove this index use self.makeRowRemovable
        """

        self.unremovable_rows.append(rowIndex)

    def makeRowRemovable(self, rowIndex):
        """
        :param rowIndex: is the index for the label of interest in the current gui setting
        """
        self.unremovable_rows.remove(rowIndex)

    def __len__(self):
        return len(self._elements)

    def __getitem__(self, i):
        return self._elements[i]

    def selectedRow(self):
        selected = self._selectionModel.selectedRows()
        if len(selected) == 1:
            return selected[0].row()
        return -1

    def selectedIndex(self):
        row = self.selectedRow()
        if row >= 0:
            return self.index(self.selectedRow())
        else:
            return QModelIndex()

    def rowCount(self, parent=None):
        return len(self._elements)

    def columnCount(self, parent):
        return self.ColumnID.ncols

    def _getToolTipSuffix(self, row):
        """
        Get the middle column tooltip suffix
        """
        suffix = "; Click to select"
        if row in self._toolTipSuffixes:
            suffix = self._toolTipSuffixes[row]
        return suffix

    def _setToolTipSuffix(self, row, text):
        """
        Set the middle column tooltip suffix
        """
        self._toolTipSuffixes[row] = text
        index = self.createIndex(row, 1)
        self.dataChanged.emit(index, index)

    class EntryToolTipAdapter(object):
        """This class can be used to make each row look like a
        separate widget with its own tooltip.

        In this case, the "tooltip" is the suffix appended to the
        tooltip of the middle column.

        """
        def __init__(self, table, row):
            self._row = row
            self._table = table

        def toolTip(self):
            return self._table._getToolTipSuffix(self._row)

        def setToolTip(self, text):
            self._table._setToolTipSuffix(self._row, text)

    def insertRow(self, position, object, parent=QModelIndex()):
        self.beginInsertRows(parent, position, position)
        object.changed.connect(self.modelReset)
        self._elements.insert(position, object)
        self.endInsertRows()
        return True

    def removeRow(self, position, parent=QModelIndex()):
        if position in self.unremovable_rows:
            return False

        self.beginRemoveRows(parent, position, position)
        value = self._elements[position]
        logger.debug("removing row: " + str(value))
        self._elements.remove(value)
        self.endRemoveRows()
        return True

    def allowRemove(self, check):
        # Allow removing of rows. Needed to be able to disallow it
        # in interactive mode
        self._allowRemove = check
        self.dataChanged.emit(
            self.createIndex(0, self.ColumnID.Delete),
            self.createIndex(self.rowCount(), self.ColumnID.Delete))

    def data(self, index, role):
        """
        Reimplement, see labelListModel or boxListModel for concrete example
        :param index:
        :param role:
        """

        if role == Qt.EditRole and index.column() == self.ColumnID.Name:
            name = self._elements[index.row()].name
            return name

        elif role == Qt.ToolTipRole and index.column() == self.ColumnID.Delete:
            s = "Delete {}".format(self._elements[index.row()].name)
            return s

        elif role == Qt.ToolTipRole and index.column() == self.ColumnID.Name:
            suffix = self._getToolTipSuffix(index.row())
            s = "{}\nDouble click to rename {}".format(
                self._elements[index.row()].name, suffix)
            return s
        elif role == Qt.DisplayRole and index.column() == self.ColumnID.Name:
            name = self._elements[index.row()].name
            return name

        if role == Qt.DecorationRole and index.column(
        ) == self.ColumnID.Delete:
            if index.row() in self.unremovable_rows:
                return

            row = index.row()
            pixmap = QPixmap(_NPIXELS, _NPIXELS)
            pixmap.fill(Qt.transparent)
            painter = QPainter()
            painter.begin(pixmap)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setBrush(QColor("red"))
            painter.drawEllipse(1, 1, _NPIXELS - 2, _NPIXELS - 2)
            pen = QPen(QColor("black"))
            pen.setWidth(2)
            painter.setPen(pen)

            x = _XSTART
            y = _NPIXELS - x
            painter.drawLine(x, x, y, y)
            painter.drawLine(y, x, x, y)

            painter.end()
            icon = QIcon(pixmap)
            return icon

    def flags(self, index):
        """
        Reimplement, see labelListModel or boxListModel for concrete example
        :param index:
        """
        if index.column() == self.ColumnID.Delete:
            if self._allowRemove:
                return Qt.ItemIsEnabled | Qt.ItemIsSelectable
            else:
                return Qt.NoItemFlags
        elif index.column() == self.ColumnID.Name:
            return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
        else:
            return Qt.NoItemFlags

    def setData(self, index, value, role=Qt.EditRole):
        """
        Reimplement, see labelListModel or boxListModel for concrete example
        :param index:
        """
        if role == Qt.EditRole and index.column() == self.ColumnID.Name:
            row = index.row()
            self._elements[row].name = value
            self.dataChanged.emit(index, index)
            return True

        return False

    def select(self, row):
        """
        Reimplement, see labelListModel or boxListModel for concrete example
        :param row
        """
        self._selectionModel.clear()
        self._selectionModel.select(self.index(row, self.ColumnID.Name),
                                    QItemSelectionModel.Select)

    def clearSelectionModel(self):
        self._selectionModel.clear()
示例#3
0
class LayerStackModel(QAbstractListModel):
    canMoveSelectedUp = pyqtSignal("bool")
    canMoveSelectedDown = pyqtSignal("bool")
    canDeleteSelected = pyqtSignal("bool")

    orderChanged = pyqtSignal()
    layerAdded = pyqtSignal(Layer, int)  # is now in row
    layerRemoved = pyqtSignal(Layer, int)  # was in row
    stackCleared = pyqtSignal()

    def __init__(self, parent=None):
        QAbstractListModel.__init__(self, parent)
        self._layerStack = []
        self.selectionModel = QItemSelectionModel(self)
        self.selectionModel.selectionChanged.connect(self.updateGUI)
        self.selectionModel.selectionChanged.connect(self._onSelectionChanged)
        self._movingRows = False
        QTimer.singleShot(0, self.updateGUI)

        def _handleRemovedLayer(layer):
            # Layerstacks *own* the layers they hold, and thus are
            #  responsible for cleaning them up when they are removed:
            layer.clean_up()

        self.layerRemoved.connect(_handleRemovedLayer)

    ####
    ## High level API to manipulate the layerstack
    ###

    def __len__(self):
        return self.rowCount()

    def __repr__(self):
        return "<LayerStackModel: layerStack='%r'>" % (self._layerStack, )

    def __getitem__(self, i):
        return self._layerStack[i]

    def __iter__(self):
        return self._layerStack.__iter__()

    def layerIndex(self, layer):
        #note that the 'index' function already has a different implementation
        #from Qt side
        return self._layerStack.index(layer)

    def findMatchingIndex(self, func):
        """Call the given function with each layer and return the index of the first layer for which f is True."""
        for index, layer in enumerate(self._layerStack):
            if func(layer):
                return index
        raise ValueError("No matching layer in stack.")

    def append(self, data):
        self.insert(0, data)

    def clear(self):
        if len(self) > 0:
            self.removeRows(0, len(self))
            self.stackCleared.emit()

    def insert(self, index, data):
        """
        Insert a layer into this layer stack, which *takes ownership* of the layer.
        """
        assert isinstance(
            data, Layer), "Only Layers can be added to a LayerStackModel"
        self.insertRow(index)
        self.setData(self.index(index), data)
        if self.selectedRow() >= 0:
            self.selectionModel.select(self.index(self.selectedRow()),
                                       QItemSelectionModel.Deselect)
        self.selectionModel.select(self.index(index),
                                   QItemSelectionModel.Select)

        data.changed.connect(
            functools.partial(self._onLayerChanged, self.index(index)))
        index = self._layerStack.index(data)
        self.layerAdded.emit(data, index)

        self.updateGUI()

    def selectRow(self, row):
        already_selected_rows = self.selectionModel.selectedRows()
        if len(already_selected_rows) == 1 and row == already_selected_rows[0]:
            # Nothing to do if this row is already selected
            return
        self.selectionModel.clear()
        self.selectionModel.setCurrentIndex(self.index(row),
                                            QItemSelectionModel.SelectCurrent)

    def deleteSelected(self):
        num_rows = len(self.selectionModel.selectedRows())
        assert num_rows == 1, "Can't delete selected row: {} layers are currently selected.".format(
            num_rows)
        row = self.selectionModel.selectedRows()[0]
        layer = self._layerStack[row.row()]
        assert not layer._cleaned_up, "This layer ({}) has already been cleaned up.  Shouldn't it already be removed from the layerstack?".format(
            layer.name)
        self.removeRow(row.row())
        if self.rowCount() > 0:
            self.selectionModel.select(self.index(0),
                                       QItemSelectionModel.Select)
        self.layerRemoved.emit(layer, row.row())
        self.updateGUI()

    def moveSelectedUp(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != 0:
            oldRow = row.row()
            newRow = oldRow - 1
            self._moveToRow(oldRow, newRow)

    def moveSelectedDown(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != self.rowCount() - 1:
            oldRow = row.row()
            newRow = oldRow + 1
            self._moveToRow(oldRow, newRow)

    def moveSelectedToTop(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != 0:
            oldRow = row.row()
            newRow = 0
            self._moveToRow(oldRow, newRow)

    def moveSelectedToBottom(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != self.rowCount() - 1:
            oldRow = row.row()
            newRow = self.rowCount() - 1
            self._moveToRow(oldRow, newRow)

    def moveSelectedToRow(self, newRow):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != newRow:
            oldRow = row.row()
            self._moveToRow(oldRow, newRow)

    def _moveToRow(self, oldRow, newRow):
        d = self._layerStack[oldRow]
        self.removeRow(oldRow)
        self.insertRow(newRow)
        self.setData(self.index(newRow), d)
        self.selectionModel.select(self.index(newRow),
                                   QItemSelectionModel.Select)
        self.orderChanged.emit()
        self.updateGUI()

    ####
    ## Low level API. To add, remove etc. layers use the high level API from above.
    ####

    def updateGUI(self):
        self.canMoveSelectedUp.emit(self.selectedRow() > 0)
        self.canMoveSelectedDown.emit(self.selectedRow() < self.rowCount() - 1)
        self.canDeleteSelected.emit(self.rowCount() > 0)
        self.wantsUpdate()

    def selectedRow(self):
        selected = self.selectionModel.selectedRows()
        if len(selected) == 1:
            return selected[0].row()
        return -1

    def selectedIndex(self):
        row = self.selectedRow()
        if row >= 0:
            return self.index(self.selectedRow())
        else:
            return QModelIndex()

    def rowCount(self, parent=QModelIndex()):
        if not parent.isValid():
            return len(self._layerStack)
        return 0

    def insertRows(self, row, count, parent=QModelIndex()):
        '''Insert empty rows in the stack. 
        
        DO NOT USE THIS METHOD TO INSERT NEW LAYERS!
        Always use the insert() or append() method.
        
        '''
        if parent.isValid():
            return False
        oldRowCount = self.rowCount()
        #for some reason, row can be negative!
        beginRow = max(0, row)
        endRow = min(beginRow + count - 1, len(self._layerStack))
        self.beginInsertRows(parent, beginRow, endRow)
        while (beginRow <= endRow):
            self._layerStack.insert(row, Layer(datasources=[]))
            beginRow += 1
        self.endInsertRows()
        assert self.rowCount(
        ) == oldRowCount + 1, "oldRowCount = %d, self.rowCount() = %d" % (
            oldRowCount, self.rowCount())
        return True

    def removeRows(self, row, count, parent=QModelIndex()):
        '''Remove rows from the stack. 
        
        DO NOT USE THIS METHOD TO REMOVE LAYERS!
        Use the deleteSelected() method instead.
        
        '''

        if parent.isValid():
            return False
        if row + count <= 0 or row >= len(self._layerStack):
            return False
        oldRowCount = self.rowCount()
        beginRow = max(0, row)
        endRow = min(row + count - 1, len(self._layerStack) - 1)
        self.beginRemoveRows(parent, beginRow, endRow)
        while (beginRow <= endRow):
            del self._layerStack[row]
            beginRow += 1
        self.endRemoveRows()
        return True

    def flags(self, index):
        defaultFlags = Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled
        if index.isValid():
            return Qt.ItemIsDragEnabled | defaultFlags
        else:
            return Qt.ItemIsDropEnabled | defaultFlags

    def supportedDropActions(self):
        return Qt.MoveAction

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None
        if index.row() >= len(self._layerStack):
            return None

        if role == Qt.DisplayRole or role == Qt.EditRole:
            return self._layerStack[index.row()]
        elif role == Qt.ToolTipRole:
            return self._layerStack[index.row()].toolTip()
        else:
            return None

    def setData(self, index, value, role=Qt.EditRole):
        '''Replace one layer with another. 
        
        DO NOT USE THIS METHOD TO INSERT NEW LAYERS!
        Use deleteSelected() followed by insert() or append().
        
        '''
        if role == Qt.EditRole:
            layer = value
            if not isinstance(value, Layer):
                layer = value
            self._layerStack[index.row()] = layer
            self.dataChanged.emit(index, index)
            return True
        elif role == Qt.ToolTipRole:
            self._layerStack[index.row()].setToolTip()
            return True
        return False

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role != Qt.DisplayRole:
            return None
        if orientation == Qt.Horizontal:
            return "Column %r" % section
        else:
            return "Row %r" % section

    def wantsUpdate(self):
        self.layoutChanged.emit()

    def _onLayerChanged(self, idx):
        self.dataChanged.emit(idx, idx)
        self.updateGUI()

    def _onSelectionChanged(self, selected, deselected):
        for idx in deselected.indexes():
            self[idx.row()].setActive(False)
        for idx in selected.indexes():
            self[idx.row()].setActive(True)
示例#4
0
class Attributes():
    def __init__(self, treeManipulate, tabnumber):
        self.treeManipulate = treeManipulate
        self.tabnumber = tabnumber
        self.tvattributesview = None
        self.lenameattributes = None
        self.levalueattributes = None
        self.battributesinsert = None
        self.battributesdelete = None
        self.battributeshelp = None
        self.setUiInit()
        self.helptext = self.treeManipulate.main.attribhelp
        #build empty model for data and the selection
        self.attribmodel = AttribStandardItemModel(self.tvattributesview)
        self.attribmodel.setHorizontalHeaderLabels(["Name", "Value", "var/fun", "comment"])
        self.attribselectionmodel = QItemSelectionModel(self.attribmodel)
        #set model to tableview
        self.tvattributesview.setModel(self.attribmodel)
        self.tvattributesview.setSelectionModel(self.attribselectionmodel)
        #signals
        self.battributesinsert.clicked.connect(self.addAttrib)
        self.battributesdelete.clicked.connect(self.deleteAttrib)
        self.battributeshelp.clicked.connect(self.help)
        self.attribmodel.itemChanged.connect(self.changeAttrib)
        #resize
        self.resz()
        #variables
        self.changeOnce = True  #prevent the changeAttrib() function from being executed twice (the second time by the model change)

    def setUiInit(self):
        if self.tabnumber == 0:
            self.tvattributesview = self.treeManipulate.main.attributefieldst1[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst1[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst1[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst1[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst1[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst1[5]
        if self.tabnumber == 1:
            self.tvattributesview = self.treeManipulate.main.attributefieldst2[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst2[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst2[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst2[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst2[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst2[5]
        if self.tabnumber == 2:
            self.tvattributesview = self.treeManipulate.main.attributefieldst3[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst3[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst3[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst3[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst3[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst3[5]
        if self.tabnumber == 3:
            self.tvattributesview = self.treeManipulate.main.attributefieldst4[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst4[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst4[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst4[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst4[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst4[5]
        if self.tabnumber == 4:
            self.tvattributesview = self.treeManipulate.main.attributefieldst5[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst5[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst5[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst5[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst5[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst5[5]
        if self.tabnumber == 5:
            self.tvattributesview = self.treeManipulate.main.attributefieldst6[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst6[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst6[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst6[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst6[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst6[5]
        if self.tabnumber == 6:
            self.tvattributesview = self.treeManipulate.main.attributefieldst7[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst7[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst7[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst7[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst7[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst7[5]
        if self.tabnumber == 7:
            self.tvattributesview = self.treeManipulate.main.attributefieldst8[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst8[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst8[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst8[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst8[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst8[5]
        if self.tabnumber == 8:
            self.tvattributesview = self.treeManipulate.main.attributefieldst9[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst9[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst9[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst9[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst9[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst9[5]
        if self.tabnumber == 9:
            self.tvattributesview = self.treeManipulate.main.attributefieldst10[0]
            self.lenameattributes = self.treeManipulate.main.attributefieldst10[1]
            self.levalueattributes = self.treeManipulate.main.attributefieldst10[2]
            self.battributesinsert = self.treeManipulate.main.attributefieldst10[3]
            self.battributesdelete = self.treeManipulate.main.attributefieldst10[4]
            self.battributeshelp = self.treeManipulate.main.attributefieldst10[5]

    def setSesVarsFunsInAttributes(self):
        if self.tabnumber == 0:
            self.sesVariablest1 = self.treeManipulate.main.modellist[0][1]
            self.sesFunctionst1 = self.treeManipulate.main.modellist[0][2]
            self.sesVariablest1.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst1.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 1:
            self.sesVariablest2 = self.treeManipulate.main.modellist[1][1]
            self.sesFunctionst2 = self.treeManipulate.main.modellist[1][2]
            self.sesVariablest2.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst2.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 2:
            self.sesVariablest3 = self.treeManipulate.main.modellist[2][1]
            self.sesFunctionst3 = self.treeManipulate.main.modellist[2][2]
            self.sesVariablest3.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst3.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 3:
            self.sesVariablest4 = self.treeManipulate.main.modellist[3][1]
            self.sesFunctionst4 = self.treeManipulate.main.modellist[3][2]
            self.sesVariablest4.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst4.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 4:
            self.sesVariablest5 = self.treeManipulate.main.modellist[4][1]
            self.sesFunctionst5 = self.treeManipulate.main.modellist[4][2]
            self.sesVariablest5.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst5.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 5:
            self.sesVariablest6 = self.treeManipulate.main.modellist[5][1]
            self.sesFunctionst6 = self.treeManipulate.main.modellist[5][2]
            self.sesVariablest6.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst6.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 6:
            self.sesVariablest7 = self.treeManipulate.main.modellist[6][1]
            self.sesFunctionst7 = self.treeManipulate.main.modellist[6][2]
            self.sesVariablest7.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst7.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 7:
            self.sesVariablest8 = self.treeManipulate.main.modellist[7][1]
            self.sesFunctionst8 = self.treeManipulate.main.modellist[7][2]
            self.sesVariablest8.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst8.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 8:
            self.sesVariablest9 = self.treeManipulate.main.modellist[8][1]
            self.sesFunctionst9 = self.treeManipulate.main.modellist[8][2]
            self.sesVariablest9.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst9.sesfunChangedSignal.connect(self.validate)
        if self.tabnumber == 9:
            self.sesVariablest10 = self.treeManipulate.main.modellist[9][1]
            self.sesFunctionst10 = self.treeManipulate.main.modellist[9][2]
            self.sesVariablest10.sesvarChangedSignal.connect(self.validate)
            self.sesFunctionst10.sesfunChangedSignal.connect(self.validate)

    """read -> called from tree manipulate"""
    def readAttribList(self, lst):
        for row in range(len(lst)):
            itemnme = QStandardItem(lst[row][0])
            itemval = QStandardItem(lst[row][1])
            itemvarfun = QStandardItem(lst[row][2])
            itemcomment = QStandardItem(lst[row][3])
            self.attribmodel.appendRow([itemnme, itemval, itemvarfun, itemcomment])
        self.resz()
        self.validate()

    """write -> the entries of the list in the current node"""
    def writeAttribList(self):
        if not self.treeManipulate.isRestoringTree:  # only, if it is not called due to a selection change during reading the tree from save
            attribList = []
            # get current selected node
            nodeuid = self.treeManipulate.treeModel.getNode(self.treeManipulate.treeSelectionModel.currentIndex()).getUid()
            for row in range(self.attribmodel.rowCount()):
                indnme = self.attribmodel.item(row, 0)
                indval = self.attribmodel.item(row, 1)
                indvarfun = self.attribmodel.item(row, 2)
                indcomment = self.attribmodel.item(row, 3)
                var = [indnme.data(QtCore.Qt.DisplayRole), indval.data(QtCore.Qt.DisplayRole), indvarfun.data(QtCore.Qt.DisplayRole), indcomment.data(QtCore.Qt.DisplayRole)]
                attribList.append(var)
            self.treeManipulate.treeModel.insertNodeSpecProp(self.treeManipulate.treeSelectionModel.currentIndex(), attribList, "attriblist", nodeuid)  # write into the node

    """resize"""
    """
    def resz(self):
        self.tvattributesview.setColumnWidth(0, self.tvattributesview.width()*0.4)
        header = self.tvattributesview.horizontalHeader()
        header.setStretchLastSection(True)
    """
    def resz(self):
        i = 0
        while i < 2:
            self.tvattributesview.resizeColumnToContents(i)
            i += 1
        header = self.tvattributesview.horizontalHeader()
        header.setStretchLastSection(True)

    """add an attribute to the model"""
    def addAttrib(self):
        name = self.lenameattributes.text()
        value = self.levalueattributes.text()
        cname, cnameb, deleten = self.checkReturnName(name, False)
        cvalue, cvalueb, deletev, varfun = self.checkReturnValue(value, False)
        if cnameb and cvalueb:
            itemnm = QStandardItem(cname)
            itemval = QStandardItem(str(cvalue))
            itemvarfun = QStandardItem(varfun)
            itemcomment = QStandardItem("")
            self.attribmodel.appendRow([itemnm, itemval, itemvarfun, itemcomment])
            self.lenameattributes.setText("")
            self.levalueattributes.setText("")
        self.writeAttribList()
        self.resz()
        self.validate()

    """model changed via double click"""
    def changeAttrib(self):
        if self.changeOnce:
            self.changeOnce = False
            index = self.tvattributesview.currentIndex()
            #cloumn 0 -> name
            if index.column() == 0:
                namedic = self.attribmodel.itemData(index)
                name = namedic[0]
                cname, cnameb, deleten = self.checkReturnName(name, True)
                if cnameb:  # set data
                    dict = {0: cname}
                    self.attribmodel.setItemData(index, dict)
                if deleten:  # remove row
                    self.deleteAttrib(self.attribselectionmodel.currentIndex().row(), True)
            #column 1 -> value
            elif index.column() == 1:
                valuedic = self.attribmodel.itemData(index)
                value = valuedic[0]
                cvalue, cvalueb, deletev, varfun = self.checkReturnValue(value, True)
                if cvalueb:  # set data
                    dict = {0: str(cvalue)}
                    self.attribmodel.setItemData(index, dict)
                    #set the value for the varfun column
                    index2 = self.attribmodel.index(index.row(), 2)
                    dict2 = {0: varfun}
                    self.attribmodel.setItemData(index2, dict2)
                if deletev:  # remove row
                    self.deleteAttrib(self.attribselectionmodel.currentIndex().row(), True)
            self.writeAttribList()
            self.resz()
            self.validate()
            self.changeOnce = True

    """check the name"""
    def checkReturnName(self, name, edited):
        if name != "" and not name == "''" and not name == '""' and not name == '\n':
            name = name.strip() #remove whitespaces before and after

            # check for two words as name
            namesplit = name.split(" ")
            if not edited and len(namesplit) > 1:
                QMessageBox.information(None, "Inserting not possible", "The variable name contains spaces. Please remove them.", QtWidgets.QMessageBox.Ok)
                return("", False, False)
            elif edited and len(namesplit) > 1:
                QMessageBox.information(None, "Changing not possible", "The variable name contains spaces. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return("", False, True)

            # check for duplicates of variable name
            if not edited and len(self.attribmodel.findItems(name)) != 0:
                QMessageBox.information(None, "Inserting not possible", "The variable name already exists. Please enter another variable name.", QtWidgets.QMessageBox.Ok)
                return ("", False, False)
            elif edited and len(self.attribmodel.findItems(self.attribmodel.item(self.attribselectionmodel.currentIndex().row(), 0).data(QtCore.Qt.DisplayRole))) > 1:
                QMessageBox.information(None, "Changing not possible", "The variable name already exists. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True)

            # check that the variable name is no Python keyword
            if not edited and keyword.iskeyword(name):
                QMessageBox.information(None, "Inserting not possible", "The variable name denotes a Python keyword. Please enter another variable name.", QtWidgets.QMessageBox.Ok)
                return ("", False, False)
            elif edited and keyword.iskeyword(name):
                QMessageBox.information(None, "Changing not possible", "The variable name denotes a Python keyword. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True)

            # check that the variable name is not 'PARENT', 'CHILDREN' or 'NUMREP'
            if not edited and (name == 'PARENT' or name == 'CHILDREN' or name == 'NUMREP'):
                QMessageBox.information(None, "Inserting not possible", "The variable name is 'PARENT', 'CHILDREN' or 'NUMREP'. Please enter another variable name.", QtWidgets.QMessageBox.Ok)
                return ("", False, False)
            elif edited and (name == 'PARENT' or name == 'CHILDREN' or name == 'NUMREP'):
                QMessageBox.information(None, "Changing not possible", "The variable name is 'PARENT', 'CHILDREN' or 'NUMREP'. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True)

            #check if the variable name is in Python syntax
            attribregex = re.compile('^([a-z]|[A-Z])(\w+)?$')
            attribregexcorrect = attribregex.match(name)
            if not edited and attribregexcorrect is None:
                QMessageBox.information(None, "Inserting not possible", "Please enter correct Python syntax for the variable name.", QtWidgets.QMessageBox.Ok)
                return ("", False, False)
            elif edited and attribregexcorrect is None:
                QMessageBox.information(None, "Changing not possible", "Please enter correct Python syntax for the variable name. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True)

            return (name, True, False)

        else:   #empty name
            if not edited:
                QMessageBox.information(None, "The variable name is empty", "The variable name is empty. The variable can not be inserted.", QtWidgets.QMessageBox.Ok)
                return ("", False, False)
            else:
                QMessageBox.information(None, "The variable name is empty", "The variable name is empty. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True)

    """check the value"""
    def checkReturnValue(self, value, edited):
        if value != "" and not value == "''" and not value == '""' and not value == '\n':
            value = value.strip()  # remove whitespaces before and after
            isString = False
            if (ord(value[0]) == 39 and ord(value[-1]) == 39) or (ord(value[0]) == 34 and ord(value[-1]) == 34):    #check ascii code: ord() for getting the number and chr() for getting the character again, unichr() for getting the unicode character
                isString = True
            try:
                if not isString:    #a string shall stay a string, try to interprete if not entered as string
                    value = ast.literal_eval(value)
                return (value, True, False, "")
            except:
                #the value is no Python value so it could be the name of an SES variable or function
                #check if it can be the syntax of an SES variable or function
                attribregex = re.compile('^([a-z]|[A-Z])(\w+)?(\(([\"\']?\w+[\"\']?)?(,\s*?[\"\']?\w+[\"\']?)*\))?$')
                attribregexcorrect = attribregex.match(value)
                if attribregexcorrect is not None and not isString:
                    return (value, True, False, "x")
                QMessageBox.information(None, "Inserting not possible",
                                        "Please enter a variable using Python syntax or the possible name of an SES variable or function. SES variables and functions may not be part of a list or other Python datatype.\n"
                                        "If edited the variable will be deleted.", QtWidgets.QMessageBox.Ok)
                if not edited:
                    return ("", False, False, "")
                else:
                    return ("", False, True, "")

        else:  # empty value
            if not edited:
                QMessageBox.information(None, "The variable value is empty",
                                        "The variable value is empty. The variable can not be inserted.",
                                        QtWidgets.QMessageBox.Ok)
                return ("", False, False, "")
            else:
                QMessageBox.information(None, "The variable value is empty",
                                        "The variable value is empty. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True, "")

    """delete"""
    def deleteAttrib(self, rw=-1, rowsdelete=False):
        selectedrows = self.attribselectionmodel.selectedRows()
        if len(selectedrows) == 0 and rw == -1:
            QMessageBox.information(None, "Deleting not possible", "Please select at least one attribute to delete.", QtWidgets.QMessageBox.Ok)
        elif len(selectedrows) > 0 and not rowsdelete:
            deleteListRows = []
            for rowind in selectedrows:
                deleteListRows.append(rowind.row())
            deleteListRows.sort(reverse=True)
            for row in deleteListRows:
                self.attribmodel.removeRow(row, QtCore.QModelIndex())
        elif rw != -1 and rowsdelete:
            self.attribmodel.removeRow(rw, QtCore.QModelIndex())
        self.writeAttribList()
        self.resz()

    """color the value field if an SES variable or SES function can be interpreted"""
    def validate(self, sesvarl="", sesfunl="", nd=None):

        #sub function
        def validateAttr(nd, sviat, sesfunl):

            attrlist = nd.attributes

            #there can be several attributes, so we have to put the results of this sub function into lists
            attrlinel = []
            isVarFunl = []
            varFoundl = []
            funFoundl = []
            funVarFoundl = []
            resl = []
            for row in attrlist:
                data = row[1]
                datavarfun = row[2]

                attrline = row
                isVarFun = False
                varFound = False
                funFound = False
                funVarFound = True
                res = ""
                #check if it is an SES variable or function
                if datavarfun == "":
                    #if type(data) is str:  #it can only be a string
                    res = data
                elif datavarfun == "x":
                    isVarFun = True

                    # evaluate the SES variable
                    try:
                        res = eval(data, globals(), sviat.__dict__)
                        varFound = True
                    except:
                        pass

                    # check if the expression is an SES function
                    if isinstance(data, str) and "(" in data and ")" in data:
                        funname = data.split("(")
                        funname[1] = funname[1][0:-1]
                        vars = funname[1].split(",")
                        if vars[0] == '':
                            del vars[0]
                        for v in range(len(vars)):
                            vars[v] = vars[v].strip()
                        # check if the parameters are SES variables and get the values
                        varvalues = []
                        for v in vars:
                            try:
                                vv = ast.literal_eval(v)
                                varvalues.append(vv)
                            except:
                                # the value is no Python value so it could be the name of an SES variable or function
                                # check if the expression is an SES variable
                                try:
                                    ret = eval(v, globals(), sviat.__dict__)
                                    # replace the name with the value
                                    varvalues.append(ret)
                                except:
                                    varvalues.append("")

                        # now get the function from the sesFunctions and try to find a match with the entry
                        for sesfunvalue in sesfunl:
                            if sesfunvalue[0] == funname[0]:
                                # get the vars of the found function match since the parameters in the function definition do not have to match the SES variable names
                                funvarsfound = re.findall('def\s+' + re.escape(funname[0]) + '\(.*\)', sesfunvalue[1])
                                funvarsfound[0] = funvarsfound[0].replace("def", "")
                                funvarsfound[0] = funvarsfound[0].replace(funname[0] + "(", "")
                                funvarsfound[0] = funvarsfound[0].replace(")", "")
                                funvarsfound[0] = funvarsfound[0].strip()
                                vars2 = funvarsfound[0].split(",")
                                if vars2[0] == '':
                                    del vars2[0]
                                # remove existing default values
                                for i in range(len(vars2)):
                                    if i < len(vars):
                                        vars2[i] = vars2[i].split("=")[0]
                                # make variables to default variables by position
                                for i in range(len(vars2)):
                                    if i < len(vars):
                                        if varvalues[i] != "":
                                            if isinstance(varvalues[i], str):
                                                vars2[i] = vars2[i] + " = '" + varvalues[i] + "'"
                                            else:
                                                vars2[i] = vars2[i] + " = " + str(varvalues[i])
                                        else:
                                            funVarFound = False

                                # build a string from the variables to pass
                                for i in range(len(vars2)):
                                    vars2[i] = str(vars2[i])
                                varstring = ', '.join(vars2)

                                # replace parameters in the function with the varstring
                                sesfunvalue[1] = re.sub('def ' + re.escape(sesfunvalue[0]) + '\(.*\)', 'def ' + re.escape(sesfunvalue[0]) + '(' + varstring + ')', sesfunvalue[1])

                                # try to execute the function
                                try:
                                    exec(sesfunvalue[1])
                                    self.ret = None
                                    execute = "self.ret = " + sesfunvalue[0] + "()"
                                    if sesfunvalue[0] in locals():
                                        try:
                                            exec(execute)
                                            funFound = True
                                            res = self.ret
                                        except:
                                            pass
                                except:
                                    pass

                #always return a string
                res = str(res)

                attrlinel.append(attrline)
                isVarFunl.append(isVarFun)
                varFoundl.append(varFound)
                funFoundl.append(funFound)
                funVarFoundl.append(funVarFound)
                resl.append(res)

            return attrlinel, isVarFunl, varFoundl, funFoundl, funVarFoundl, resl

        #here the validate function begins

        # own class for SES variables
        class sesvarsinattr:
            pass

        # create an instance of the SES variables class
        sviat = sesvarsinattr

        #was the process started for coloring the lines or for pruning?
        if sesvarl == "" and sesfunl == "" and nd == None:  # the validate process was started from the editor for coloring the lines
            # fill the instance of the sesvar class
            for sesvarvalue in self.treeManipulate.main.modellist[self.treeManipulate.main.activeTab][1].outputSesVarList():
                try:
                    sesvarvalue[1] = ast.literal_eval(sesvarvalue[1])  # interprete the type of the value
                except:
                    pass  # do nothing, it stays a string
                setattr(sviat, sesvarvalue[0], sesvarvalue[1])

            #get the SES functions
            sesfunl = self.treeManipulate.main.modellist[self.treeManipulate.main.activeTab][2].outputSesFunList()

            #go through all nodes
            indices = self.treeManipulate.listAllIndices(self.treeManipulate.treeSelectionModel.currentIndex())
            for ind in indices:
                #get the node
                nd = self.treeManipulate.treeModel.getNode(ind[0])
                #only continue if the node has attributes
                if nd.typeInfo() == "Entity Node":

                    attrlinel, isVarFunl, varFoundl, funFoundl, funVarFoundl, resl = validateAttr(nd, sviat, sesfunl)

                    #update the model
                    self.updateModel(attrlinel, isVarFunl, varFoundl, funFoundl, funVarFoundl)

        else:   # the validate process was started for pruning
            # fill the instance of the sesvar class
            for sesvarvalue in sesvarl:
                try:
                    sesvarvalue[1] = ast.literal_eval(sesvarvalue[1])  # interprete the type of the value
                except:
                    pass  # do nothing, it stays a string
                setattr(sviat, sesvarvalue[0], sesvarvalue[1])

            #the SES functions are given in the pass list

            #only continue if the node has attributes
            if nd.typeInfo() == "Entity Node":

                attrlinel, isVarFunl, varFoundl, funFoundl, funVarFoundl, resl = validateAttr(nd, sviat, sesfunl)

                #return the evaluated results
                return resl



    def updateModel(self, attrlinel, isVarFunl, varFoundl, funFoundl, funVarFoundl):    #the information how to color the rows is not in the node (no True/False), so we have to pass the lists

        for row in range(self.attribmodel.rowCount()):
            index0 = self.attribmodel.index(row, 0)
            index1 = self.attribmodel.index(row, 1)
            index2 = self.attribmodel.index(row, 2)
            index3 = self.attribmodel.index(row, 3)

            #if the attribute the parameters were calculated for fits the attribute of the line
            attrname = index0.data(QtCore.Qt.DisplayRole)
            attrvalue = index1.data(QtCore.Qt.DisplayRole)
            attrvarfun = index2.data(QtCore.Qt.DisplayRole)
            attrcomment = index3.data(QtCore.Qt.DisplayRole)
            for i in range(len(attrlinel)):
                if attrlinel[i][0] == attrname and attrlinel[i][1] == attrvalue and attrlinel[i][2] == attrvarfun and attrlinel[i][3] == attrcomment:
                    if isVarFunl[i]:
                        #color the rows according to the found result
                        if varFoundl[i] or (funFoundl[i] and funVarFoundl[i]):
                            color1 = QtGui.QColor(195, 255, 195, 255)
                        else:
                            color1 = QtGui.QColor(255, 195, 195, 255)
                    else:
                        #get the alternating colors
                        if row % 2 == 0:
                            color1 = QtGui.QColor(QtCore.Qt.white)
                        else:
                            color1 = QtGui.QColor(239, 240, 241, 255)
                    self.attribmodel.setData(index1, color1, QtCore.Qt.BackgroundColorRole)
                    self.attribmodel.setData(index2, color1, QtCore.Qt.BackgroundColorRole)

    """empty the model"""
    def emptyAttribModel(self):
        self.attribmodel.clear()
        self.attribmodel.setHorizontalHeaderLabels(["Name", "Value", "var/fun", "comment"])

    """help"""
    def help(self):
        msgBox = QMessageBox(self.treeManipulate.main)
        msgBox.setIcon(QMessageBox.Information)
        msgBox.setWindowTitle("attributes: Help")
        msgBox.setText(self.helptext[0])
        msgBox.setDetailedText(self.helptext[1])
        msgBox.setWindowModality(Qt.NonModal)
        msgBox.setStandardButtons(QMessageBox.Ok)
        msgBox.setDefaultButton(QMessageBox.Ok)
        msgBox.setEscapeButton(QMessageBox.Ok)
        msgBox.show()

    #validate function where only the existence of the SES function and parameters is checked but not if it is interpretable
    """
    def validate(self):
        self.changeOnce = False
        for row in range(self.attribmodel.rowCount()):
            data = self.attribmodel.item(row, 1).data(QtCore.Qt.DisplayRole)
            datavarfun = self.attribmodel.item(row, 2).data(QtCore.Qt.DisplayRole)
            index1 = self.attribmodel.index(row, 1)
            index2 = self.attribmodel.index(row, 2)
            #if it is an SES variable or function
            if datavarfun == "x":
                varFound = False
                funFound = False
                parameterFound = []

                for sesvarvalue in self.treeManipulate.main.modellist[self.treeManipulate.main.activeTab][1].outputSesVarList():
                    if data == sesvarvalue[0]:
                        varFound = True

                attribregex = re.compile('^([a-z]|[A-Z])(\w+)?(\(([\"\']?\w+[\"\']?)?(,\s*?[\"\']?\w+[\"\']?)*\))$')
                attribregexfun = attribregex.match(data)
                if attribregexfun is not None:
                    funsplit = data.split("(")
                    funsplit[1] = funsplit[1][0:len(funsplit[1])-1]
                    for sesfunvalue in self.treeManipulate.main.modellist[self.treeManipulate.main.activeTab][2].outputSesFunList():
                        if funsplit[0] == sesfunvalue[0]:
                            funFound = True
                            #now interprete the parameters
                            parameters = funsplit[1].split(",")
                            for p in range(len(parameters)):
                                parameters[p] = parameters[p].strip()
                                if not parameters[p] == "":
                                    try:
                                        ast.literal_eval(parameters[p])
                                    except: #the parameter is maybe an SES variable
                                        found = False
                                        for sesvarvalue in self.treeManipulate.main.modellist[self.treeManipulate.main.activeTab][1].outputSesVarList():
                                            if parameters[p] == sesvarvalue[0]:
                                                found = True
                                        if found:
                                            parameterFound.append(True)
                                        else:
                                            parameterFound.append(False)

                #color the rows according to the found result
                parameterFoundRes = all(parameterFound)

                if varFound or (funFound and parameterFoundRes):
                    color1 = QtGui.QColor(195, 255, 195, 255)
                else:
                    color1 = QtGui.QColor(255, 195, 195, 255)
            else:
                #get the alternating colors
                if row % 2 == 0:
                    color1 = QtGui.QColor(QtCore.Qt.white)
                else:
                    color1 = QtGui.QColor(239, 240, 241, 255)
            self.attribmodel.setData(index1, color1, QtCore.Qt.BackgroundColorRole)
            self.attribmodel.setData(index2, color1, QtCore.Qt.BackgroundColorRole)
        self.changeOnce = True
    """

    #functions when the syntax var() and fun() is used------------------------------------------------------------------

    """check the value -> old function: with var as keyword for SES Variable and fun as keyword for SES function"""
    """
    def checkReturnValue(self, value, edited):
        def checkQuotes(val):  # it must be an even number of quotes and one type of quotes may only be twice in the string since it defines the string
            quote = val.count("'")
            doublequote = val.count('"')
            if quote % 2 == 1 or doublequote % 2 == 1:  # if one number of quotetype is odd -> return False
                return False
            elif quote == 0 or doublequote == 0:  # one number of quotetype must be 0 (since the string delimiters are not counted)
                return True
            else:
                return False

        if value != "":
            value = value.strip()  # remove whitespaces before and after
            try:
                value = ast.literal_eval(value)

                sesvarfunkeyexists = False
                sesvarkeyfound = None
                sesfunkeyfound = None
                sesvarregex = re.compile('^var\([\"\']([a-z]|[A-Z])(\w+)?[\"\']\)$')  # regular expression: var("abc") or var('abc'), not found: var("abc def") since SES variable names may not contain whitespaces
                sesfunregex = re.compile('^fun\([\"\']([a-z]|[A-Z])(\w+)?[\"\'](,\s?((\d+(\.\d+)?)|([\"\']var\([\"\']([a-z]|[A-Z])(\w+)?[\"\']\)[\"\'])))*\)$')  # regular expression: fun("abc"[...]) or fun('abc'[...]) with [...] optional containing: , 4 or , "var("a")" with whitespace optional between , and text
                checkquotes = False

                if isinstance(value, str) and ("var(" in value or "fun(" in value):
                    sesvarfunkeyexists = True
                    sesvarkeyfound = sesvarregex.match(value)
                    sesfunkeyfound = sesfunregex.match(value)
                    checkquotes = checkQuotes(value)
                # if isinstance(value, list) and (("var(" in v for v in value) or ("fun(" in v for v in value)):   #does not perfectly function
                if isinstance(value, list):
                    for v in value:
                        if isinstance(v, str) and ("var(" in v or "fun(" in v):
                            sesvarfunkeyexists = True
                            sesvarkeyfound = sesvarregex.match(v)
                            sesfunkeyfound = sesfunregex.match(v)
                            checkquotes = checkQuotes(v)
                # if isinstance(value, tuple) and (("var(" in v for v in value) or ("fun(" in v for v in value)):  #does not perfectly function
                if isinstance(value, tuple):
                    for v in value:
                        if isinstance(v, str) and ("var(" in v or "fun(" in v):
                            sesvarfunkeyexists = True
                            sesvarkeyfound = sesvarregex.match(v)
                            sesfunkeyfound = sesfunregex.match(v)
                            checkquotes = checkQuotes(v)
                # if isinstance(value, dict) and (("var(" in v for v in list(value.values())) or ("fun(" in v for v in list(value.values()))): #does not perfectly function
                if isinstance(value, dict):
                    for v in list(value.values()):
                        if isinstance(v, str) and ("var(" in v or "fun(" in v):
                            sesvarfunkeyexists = True
                            sesvarkeyfound = sesvarregex.match(v)
                            sesfunkeyfound = sesfunregex.match(v)
                            checkquotes = checkQuotes(v)

                if not sesvarfunkeyexists:  # all correct Python values which do not contain the keywords fun( or var(
                    return (value, True, False)
                elif sesvarfunkeyexists and sesvarkeyfound is not None and checkquotes:  # value contains var( keyword in correct syntax
                    return (value, True, False)
                elif sesvarfunkeyexists and sesfunkeyfound is not None and checkquotes:  # value contains fun( keyword in correct syntax
                    return (value, True, False)
                elif sesvarfunkeyexists and (sesvarkeyfound is not None or sesfunkeyfound is not None) and not checkquotes:
                    QMessageBox.information(None, "Inserting not possible",
                                            "It seems you want to reference an SES variable or function. Please watch your quotes. "
                                            "If edited the variable will be deleted.", QtWidgets.QMessageBox.Ok)
                    if not edited:
                        return (value, False, False)
                    else:
                        return (value, False, True)
                elif sesvarfunkeyexists and sesvarkeyfound is None and sesfunkeyfound is None:  # value contains var( or fun( keywords not in correct syntax
                    QMessageBox.information(None, "Inserting not possible",
                                            "It seems you want to reference an SES variable or function.\n"
                                            "Please use the syntax\n\"var('sesvarname')\" or\n\"fun('sesfunname'[, 4.5])\" or\n\"fun('sesfunname'[, 'var('sesvarname')'])\" .\n"
                                            "The expression in square brackets is optional, do not type the square brackets. Use it if you want to pass parameters.\n"
                                            "sesvarname and sesfunname must be alphanumeric not beginning with a number.\n"
                                            "If edited the variable will be deleted.", QtWidgets.QMessageBox.Ok)
                    if not edited:
                        return (value, False, False)
                    else:
                        return (value, False, True)
                else:
                    return (value, False, False)  # if it is none of the above cases -> do nothing
            except:
                QMessageBox.information(None, "Inserting not possible",
                                        "Please enter a variable using Python syntax.\n"
                                        "If edited the variable will be deleted.", QtWidgets.QMessageBox.Ok)
                if not edited:
                    return ("", False, False)
                else:
                    return ("", False, True)

        else:  # empty value
            if not edited:
                QMessageBox.information(None, "The variable value is empty",
                                        "The variable value is empty. The variable can not be inserted.",
                                        QtWidgets.QMessageBox.Ok)
                return ("", False, False)
            else:
                QMessageBox.information(None, "The variable value is empty",
                                        "The variable value is empty. The variable is deleted.", QtWidgets.QMessageBox.Ok)
                return ("", False, True)
    """

    """color the value field if a var() or fun() can be interpreted -> old function: with var as keyword for SES Variable and fun as keyword for SES function"""
    """
    def validate(self):
        self.changeOnce = False
        for row in range(self.attribmodel.rowCount()):
            data = self.attribmodel.item(row, 1).data(QtCore.Qt.DisplayRole)
            #find all occurences of var
            matches = re.findall('var\([\"\']([a-z]|[A-Z])(\w+)?[\"\']\)', data)
            sesvarfound = []
            for ma in matches:
                #connect the tuple of each resulting group
                m = ma[0] + ma[1]
                #check if SES variable with this found name exists
                nameexists = False
                for sesvarvalue in self.sesVariables.outputSesVarList():
                    if m == sesvarvalue[0]:
                        nameexists = True
                        break
                sesvarfound.append(nameexists)
            #find all occurrences of fun
            matches = re.findall('fun\([\"\']([a-z]|[A-Z])(\w+)?[\"\'].*\)', data)
            sesfunfound = []
            for ma in matches:
                #connect the tuple of each resulting group
                m = ma[0] + ma[1]
                #check if SES function with this found name exists
                nameexists = False
                for sesfunvalue in self.sesFunctions.outputSesFunList():
                    if m == sesfunvalue[0]:
                        nameexists = True
                        break
                sesfunfound.append(nameexists)

            #color the rows according to the found result
            if not (not sesvarfound and not sesfunfound):   #if both lists are empty -> line does not contain fun(...) or var(...) -> do not color
                sesvarallfound = all(sesvarfound)
                sesfunallfound = all(sesfunfound)
                index1 = self.attribmodel.index(row, 1)
                if sesvarallfound and sesfunallfound:
                    color1 = QtGui.QColor(195, 255, 195, 255)
                else:
                    color1 = QtGui.QColor(255, 195, 195, 255)
                self.attribmodel.setData(index1, color1, QtCore.Qt.BackgroundColorRole)
        self.changeOnce = True
    """

    """new function: validate (commented function above)"""
    """
示例#5
0
class ListModel(QAbstractTableModel):
    orderChanged = pyqtSignal()
    elementSelected = pyqtSignal(int)


    class ColumnID(object):
        '''
        Define how many column the model holds and their type

        '''
        ncols=2
        Name=0
        Delete=1

    def __init__(self, elements=None, parent=None):
        '''
        Common interface for the labelListModel, the boxListModel, and the cropListModel
        see concrete implementations for details

        :param elements:
        :param parent:
        '''
        QAbstractTableModel.__init__(self, parent)

        if elements is None:
            elements = []
        self._elements = list(elements)
        self._selectionModel = QItemSelectionModel(self)

        def onSelectionChanged(selected, deselected):


            if selected:
                ind = selected[0].indexes()
                if len(ind)>0:
                    self.elementSelected.emit(ind[0].row())

        self._selectionModel.selectionChanged.connect(onSelectionChanged)

        self._allowRemove = True
        self._toolTipSuffixes = {}

        self.unremovable_rows=[] #rows in this list cannot be removed from the gui,
                                 # to add to this list call self.makeRowPermanent(int)
                                 # to remove make the self.makeRowRemovable(int)
    def makeRowPermanent(self, rowIndex):
        """
        The rowindex cannot be removed from gui
        to remove this index use self.makeRowRemovable
        """

        self.unremovable_rows.append(rowIndex)

    def makeRowRemovable(self, rowIndex):
        """
        :param rowIndex: is the index for the label of interest in the current gui setting
        """
        self.unremovable_rows.remove(rowIndex)

    def __len__(self):
        return len(self._elements)

    def __getitem__(self, i):
        return self._elements[i]

    def selectedRow(self):
        selected = self._selectionModel.selectedRows()
        if len(selected) == 1:
            return selected[0].row()
        return -1

    def selectedIndex(self):
        row = self.selectedRow()
        if row >= 0:
            return self.index(self.selectedRow())
        else:
            return QModelIndex()

    def rowCount(self, parent=None):
        return len(self._elements)

    def columnCount(self, parent):
        return self.ColumnID.ncols

    def _getToolTipSuffix(self, row):
        """
        Get the middle column tooltip suffix
        """
        suffix = "; Click to select"
        if row in self._toolTipSuffixes:
            suffix = self._toolTipSuffixes[row]
        return suffix

    def _setToolTipSuffix(self, row, text):
        """
        Set the middle column tooltip suffix
        """
        self._toolTipSuffixes[row] = text
        index = self.createIndex(row, 1)
        self.dataChanged.emit(index, index)

    class EntryToolTipAdapter(object):
        """This class can be used to make each row look like a
        separate widget with its own tooltip.

        In this case, the "tooltip" is the suffix appended to the
        tooltip of the middle column.

        """
        def __init__(self, table, row):
            self._row = row
            self._table = table
        def toolTip(self):
            return self._table._getToolTipSuffix(self._row)
        def setToolTip(self, text):
            self._table._setToolTipSuffix(self._row, text)



    def insertRow(self, position, object, parent=QModelIndex()):
        self.beginInsertRows(parent, position, position)
        object.changed.connect(self.modelReset)
        self._elements.insert(position, object)
        self.endInsertRows()
        return True

    def removeRow(self, position, parent=QModelIndex()):
        if position in self.unremovable_rows:
            return False

        self.beginRemoveRows(parent, position, position)
        value = self._elements[position]
        logger.debug("removing row: " + str(value))
        self._elements.remove(value)
        self.endRemoveRows()
        return True

    def allowRemove(self, check):
        #Allow removing of rows. Needed to be able to disallow it
        #in interactive mode
        self._allowRemove = check
        self.dataChanged.emit(self.createIndex(0, self.ColumnID.Delete),
                              self.createIndex(self.rowCount(), self.ColumnID.Delete))
    def data(self, index, role):
        '''
        Reimplement, see labelListModel or boxListModel for concrete example
        :param index:
        :param role:
        '''

        if role == Qt.EditRole and index.column() == self.ColumnID.Name:
            name = self._elements[index.row()].name
            return name

        elif role == Qt.ToolTipRole and index.column() == self.ColumnID.Delete:
            s = "Delete {}".format(self._elements[index.row()].name)
            return s

        elif role == Qt.ToolTipRole and index.column() == self.ColumnID.Name:
            suffix = self._getToolTipSuffix(index.row())
            s = "{}\nDouble click to rename {}".format(
                self._elements[index.row()].name, suffix)
            return s
        elif role == Qt.DisplayRole and index.column() == self.ColumnID.Name:
            name = self._elements[index.row()].name
            return name

        if role == Qt.DecorationRole and index.column() == self.ColumnID.Delete:
            if index.row() in self.unremovable_rows: return

            row = index.row()
            pixmap = QPixmap(_NPIXELS, _NPIXELS)
            pixmap.fill(Qt.transparent)
            painter = QPainter()
            painter.begin(pixmap)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setBrush(QColor("red"))
            painter.drawEllipse(1, 1, _NPIXELS - 2, _NPIXELS - 2)
            pen = QPen(QColor("black"))
            pen.setWidth(2)
            painter.setPen(pen)

            x = _XSTART
            y = _NPIXELS - x
            painter.drawLine(x, x, y, y)
            painter.drawLine(y, x, x, y)

            painter.end()
            icon = QIcon(pixmap)
            return icon

    def flags(self, index):
        '''
        Reimplement, see labelListModel or boxListModel for concrete example
        :param index:
        '''
        if index.column() == self.ColumnID.Delete:
            if self._allowRemove:
                return Qt.ItemIsEnabled | Qt.ItemIsSelectable
            else:
                return Qt.NoItemFlags
        elif  index.column() == self.ColumnID.Name:
            return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
        else:
            return Qt.NoItemFlags

    def setData(self, index, value, role=Qt.EditRole):
        '''
        Reimplement, see labelListModel or boxListModel for concrete example
        :param index:
        '''
        if role == Qt.EditRole  and index.column() == self.ColumnID.Name:
            row = index.row()
            self._elements[row].name = value
            self.dataChanged.emit(index, index)
            return True

        return False

    def select(self, row):
        '''
        Reimplement, see labelListModel or boxListModel for concrete example
        :param row
        '''
        self._selectionModel.clear()
        self._selectionModel.select(self.index(row, self.ColumnID.Name),
                                    QItemSelectionModel.Select)

    def clearSelectionModel(self):
        self._selectionModel.clear()
示例#6
0
class LayerStackModel(QAbstractListModel):
    canMoveSelectedUp = pyqtSignal("bool")
    canMoveSelectedDown = pyqtSignal("bool")
    canDeleteSelected = pyqtSignal("bool")

    orderChanged = pyqtSignal()
    layerAdded = pyqtSignal(Layer, int)  # is now in row
    layerRemoved = pyqtSignal(Layer, int)  # was in row
    stackCleared = pyqtSignal()

    def __init__(self, parent=None):
        QAbstractListModel.__init__(self, parent)
        self._layerStack = []
        self.selectionModel = QItemSelectionModel(self)
        self.selectionModel.selectionChanged.connect(self.updateGUI)
        self.selectionModel.selectionChanged.connect(self._onSelectionChanged)
        self._movingRows = False
        QTimer.singleShot(0, self.updateGUI)

        def _handleRemovedLayer(layer):
            # Layerstacks *own* the layers they hold, and thus are
            #  responsible for cleaning them up when they are removed:
            layer.clean_up()

        self.layerRemoved.connect(_handleRemovedLayer)

    ####
    ## High level API to manipulate the layerstack
    ###

    def __len__(self):
        return self.rowCount()

    def __repr__(self):
        return "<LayerStackModel: layerStack='%r'>" % (self._layerStack,)

    def __getitem__(self, i):
        return self._layerStack[i]

    def __iter__(self):
        return self._layerStack.__iter__()

    def layerIndex(self, layer):
        # note that the 'index' function already has a different implementation
        # from Qt side
        return self._layerStack.index(layer)

    def findMatchingIndex(self, func):
        """Call the given function with each layer and return the index of the first layer for which f is True."""
        for index, layer in enumerate(self._layerStack):
            if func(layer):
                return index
        raise ValueError("No matching layer in stack.")

    def append(self, data):
        self.insert(0, data)

    def clear(self):
        if len(self) > 0:
            self.removeRows(0, len(self))
            self.stackCleared.emit()

    def insert(self, index, data):
        """
        Insert a layer into this layer stack, which *takes ownership* of the layer.
        """
        assert isinstance(data, Layer), "Only Layers can be added to a LayerStackModel"
        self.insertRow(index)
        self.setData(self.index(index), data)
        if self.selectedRow() >= 0:
            self.selectionModel.select(self.index(self.selectedRow()), QItemSelectionModel.Deselect)
        self.selectionModel.select(self.index(index), QItemSelectionModel.Select)

        data.changed.connect(functools.partial(self._onLayerChanged, self.index(index)))
        index = self._layerStack.index(data)
        self.layerAdded.emit(data, index)

        self.updateGUI()

    def selectRow(self, row):
        already_selected_rows = self.selectionModel.selectedRows()
        if len(already_selected_rows) == 1 and row == already_selected_rows[0]:
            # Nothing to do if this row is already selected
            return
        self.selectionModel.clear()
        self.selectionModel.setCurrentIndex(self.index(row), QItemSelectionModel.SelectCurrent)

    def deleteSelected(self):
        num_rows = len(self.selectionModel.selectedRows())
        assert num_rows == 1, "Can't delete selected row: {} layers are currently selected.".format(num_rows)
        row = self.selectionModel.selectedRows()[0]
        layer = self._layerStack[row.row()]
        assert (
            not layer._cleaned_up
        ), "This layer ({}) has already been cleaned up.  Shouldn't it already be removed from the layerstack?".format(
            layer.name
        )
        self.removeRow(row.row())
        if self.rowCount() > 0:
            self.selectionModel.select(self.index(0), QItemSelectionModel.Select)
        self.layerRemoved.emit(layer, row.row())
        self.updateGUI()

    def moveSelectedUp(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != 0:
            oldRow = row.row()
            newRow = oldRow - 1
            self._moveToRow(oldRow, newRow)

    def moveSelectedDown(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != self.rowCount() - 1:
            oldRow = row.row()
            newRow = oldRow + 1
            self._moveToRow(oldRow, newRow)

    def moveSelectedToTop(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != 0:
            oldRow = row.row()
            newRow = 0
            self._moveToRow(oldRow, newRow)

    def moveSelectedToBottom(self):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != self.rowCount() - 1:
            oldRow = row.row()
            newRow = self.rowCount() - 1
            self._moveToRow(oldRow, newRow)

    def moveSelectedToRow(self, newRow):
        assert len(self.selectionModel.selectedRows()) == 1
        row = self.selectionModel.selectedRows()[0]
        if row.row() != newRow:
            oldRow = row.row()
            self._moveToRow(oldRow, newRow)

    def _moveToRow(self, oldRow, newRow):
        d = self._layerStack[oldRow]
        self.removeRow(oldRow)
        self.insertRow(newRow)
        self.setData(self.index(newRow), d)
        self.selectionModel.select(self.index(newRow), QItemSelectionModel.Select)
        self.orderChanged.emit()
        self.updateGUI()

    ####
    ## Low level API. To add, remove etc. layers use the high level API from above.
    ####

    def updateGUI(self):
        self.canMoveSelectedUp.emit(self.selectedRow() > 0)
        self.canMoveSelectedDown.emit(self.selectedRow() < self.rowCount() - 1)
        self.canDeleteSelected.emit(self.rowCount() > 0)
        self.wantsUpdate()

    def selectedRow(self):
        selected = self.selectionModel.selectedRows()
        if len(selected) == 1:
            return selected[0].row()
        return -1

    def selectedIndex(self):
        row = self.selectedRow()
        if row >= 0:
            return self.index(self.selectedRow())
        else:
            return QModelIndex()

    def rowCount(self, parent=QModelIndex()):
        if not parent.isValid():
            return len(self._layerStack)
        return 0

    def insertRows(self, row, count, parent=QModelIndex()):
        """Insert empty rows in the stack.

        DO NOT USE THIS METHOD TO INSERT NEW LAYERS!
        Always use the insert() or append() method.

        """
        if parent.isValid():
            return False
        oldRowCount = self.rowCount()
        # for some reason, row can be negative!
        beginRow = max(0, row)
        endRow = min(beginRow + count - 1, len(self._layerStack))
        self.beginInsertRows(parent, beginRow, endRow)
        while beginRow <= endRow:
            self._layerStack.insert(row, Layer(datasources=[]))
            beginRow += 1
        self.endInsertRows()
        assert self.rowCount() == oldRowCount + 1, "oldRowCount = %d, self.rowCount() = %d" % (
            oldRowCount,
            self.rowCount(),
        )
        return True

    def removeRows(self, row, count, parent=QModelIndex()):
        """Remove rows from the stack.

        DO NOT USE THIS METHOD TO REMOVE LAYERS!
        Use the deleteSelected() method instead.

        """

        if parent.isValid():
            return False
        if row + count <= 0 or row >= len(self._layerStack):
            return False
        oldRowCount = self.rowCount()
        beginRow = max(0, row)
        endRow = min(row + count - 1, len(self._layerStack) - 1)
        self.beginRemoveRows(parent, beginRow, endRow)
        while beginRow <= endRow:
            del self._layerStack[row]
            beginRow += 1
        self.endRemoveRows()
        return True

    def flags(self, index):
        defaultFlags = Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsEnabled
        if index.isValid():
            return Qt.ItemIsDragEnabled | defaultFlags
        else:
            return Qt.ItemIsDropEnabled | defaultFlags

    def supportedDropActions(self):
        return Qt.MoveAction

    def data(self, index, role=Qt.DisplayRole):
        if not index.isValid():
            return None
        if index.row() >= len(self._layerStack):
            return None

        if role == Qt.DisplayRole or role == Qt.EditRole:
            return self._layerStack[index.row()]
        elif role == Qt.ToolTipRole:
            return self._layerStack[index.row()].toolTip()
        else:
            return None

    def setData(self, index, value, role=Qt.EditRole):
        """Replace one layer with another.

        DO NOT USE THIS METHOD TO INSERT NEW LAYERS!
        Use deleteSelected() followed by insert() or append().

        """
        if role == Qt.EditRole:
            layer = value
            if not isinstance(value, Layer):
                layer = value
            self._layerStack[index.row()] = layer
            self.dataChanged.emit(index, index)
            return True
        elif role == Qt.ToolTipRole:
            self._layerStack[index.row()].setToolTip()
            return True
        return False

    def headerData(self, section, orientation, role=Qt.DisplayRole):
        if role != Qt.DisplayRole:
            return None
        if orientation == Qt.Horizontal:
            return "Column %r" % section
        else:
            return "Row %r" % section

    def wantsUpdate(self):
        self.layoutChanged.emit()

    def _onLayerChanged(self, idx):
        self.dataChanged.emit(idx, idx)
        self.updateGUI()

    def _onSelectionChanged(self, selected, deselected):
        for idx in deselected.indexes():
            self[idx.row()].setActive(False)
        for idx in selected.indexes():
            self[idx.row()].setActive(True)