コード例 #1
0
ファイル: helpers.py プロジェクト: lihj1311/cctbx_project
class MillerArrayTableView(QTableView):
    def __init__(self, *args, **kwargs):
        QTableView.__init__(self, *args, **kwargs)
        myqa = QAction("Copy selected cells...", self)
        myqa.setData(("Copying selection"))
        self.tablemenu = QMenu(self)
        self.tablemenu.addAction(myqa)
        self.tablemenu.triggered.connect(self.onTableMenuAction)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.onRightClick)
        self.doubleClicked.connect(self.onDoubleClick)
        self.setSelectionMode(QAbstractItemView.MultiSelection)
        #self.setSelectionMode(QAbstractItemView.ExtendedSelection)
    def onDoubleClick(self, index):
        hkl = (int(index.siblingAtColumn(0).data()),
               int(index.siblingAtColumn(1).data()),
               int(index.siblingAtColumn(2).data()))
        self.parent().parent().parent().parent.HighlightReflection(hkl)

    def onRightClick(self, QPos=None):
        parent = self.sender()
        self.tablemenu.move(QCursor.pos())
        self.tablemenu.show()

    def onTableMenuAction(self, action):
        data = action.data()
        if data == "Copying selection":
            self.copySelection()

    def copySelection(self):
        # from https://stackoverflow.com/questions/40225270/copy-paste-multiple-items-from-qtableview-in-pyqt4
        selection = self.selectedIndexes()
        if selection:
            rows = sorted(index.row() for index in selection)
            columns = sorted(index.column() for index in selection)
            rowcount = rows[-1] - rows[0] + 1
            colcount = columns[-1] - columns[0] + 1
            table = [[''] * colcount for _ in range(rowcount)]
            for index in selection:
                row = index.row() - rows[0]
                column = index.column() - columns[0]
                table[row][column] = index.data()
            stream = StringIO()
            csv.writer(stream, delimiter='\t').writerows(table)
            self.parent().parent().parent().parent.app.clipboard().setText(
                stream.getvalue())
コード例 #2
0
ファイル: QCanvas.py プロジェクト: Bernardrouhi/PuppetMaster
class CanvasGraphicsView(QGraphicsView):
    onSelection = Signal(PickNode)
    requestEditMode = Signal(bool)

    def __init__(self, parent=None):
        super(CanvasGraphicsView, self).__init__(parent)

        self.setFocusPolicy(Qt.StrongFocus)
        # Scene properties
        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.setRenderHint(QPainter.Antialiasing)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setBackgroundBrush(QBrush(QColor(51, 51, 51)))
        self.setFrameShape(QFrame.NoFrame)
        self.setDragMode(QGraphicsView.RubberBandDrag)
        self.ViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)

        self.init()

    def init(self):
        self.piiPath = str()
        self._model = {'background': str()}
        self._isPanning = False
        self._isZooming = False
        self._mousePressed = False
        self._scene = QGraphicsScene()
        self._scene.selectionChanged.connect(self.update_node_settings)
        self._backgroundNode = QGraphicsPixmapItem()
        self._scene.addItem(self._backgroundNode)
        self._orderSelected = list()
        self._lastPos = QPoint(0, 0)
        self.editMode = False
        self._namespace = str()
        self._dragMulti = list()

        self._defaultColor = QColor(255, 255, 255)
        self._defaultTextColor = QColor(0, 0, 0)
        self._defaultTextSize = 20
        self._defaultText = "New Node"

        self.workHight = 2160
        self.workWidth = 4096

        self.setScene(self._scene)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.setBackgroundImage(str())

    def update_node_settings(self):
        if self._orderSelected:
            node = self._orderSelected[-1]
            self._defaultText = node.toPlainText()
            self._defaultColor = node.Background
            self._defaultTextColor = node.defaultTextColor()
            self._defaultTextSize = node.font().pointSize()

    def update_maya_selection(self):
        '''
        Update Maya Scene base on active selection.
        '''
        clearSelection()
        selection = list()
        for each in self._orderSelected:
            selection += each.Items
        if selection:
            selectObjects(selection)

    def setBackgroundImage(self, path=str()):
        '''
        Set background image

        Parameters
        ----------
        path: (str)
            Path to background image.
        '''
        self._model['background'] = path
        self.setStatusTip(self._model['background'])
        pixmap = QPixmap(self._model['background'])
        self._backgroundNode.setPixmap(pixmap)

    def getBackgroundImage(self):
        '''
        Get background image
        '''
        return self._model['background']

    BackgroundImage = property(getBackgroundImage, setBackgroundImage)

    def actionMenu(self, QPos):
        '''
        Show action menu.

        Parameters
        ----------
        QPos: (list)
            list of x and y location.
        '''
        self.mainMenu = QMenu()

        add_action = self.mainMenu.addAction('Add A Button')
        add_action.setEnabled(self.editMode)
        add_action.triggered.connect(self.add_node)

        addMany_action = self.mainMenu.addAction('Add Many Buttons')
        addMany_action.setEnabled(self.editMode)
        addMany_action.triggered.connect(self.add_multiple_nodes)

        activeNode = self.mouse_on_node()
        if activeNode:
            update_action = self.mainMenu.addAction('Update Button')
            update_action.setEnabled(self.editMode)
            update_action.triggered.connect(
                lambda: self.update_node(activeNode))

        delete_action = self.mainMenu.addAction('Delete Button')
        delete_action.setEnabled(self.editMode)
        delete_action.setShortcut('Backspace')
        delete_action.triggered.connect(self.removeSelected)

        self.mainMenu.addSeparator()

        # search for selected ButtonNode
        btnStatus = [
            isinstance(n, ButtonNode) for n in self._scene.selectedItems()
        ]
        if True in btnStatus:
            # first ButtonNode
            activeNode = self._scene.selectedItems()[btnStatus.index(True)]
            command_action = self.mainMenu.addAction('Edit Command Button...')
            command_action.setEnabled(self.editMode)
            command_action.triggered.connect(
                lambda: self.update_ButtonNode(activeNode))
        else:
            command_action = self.mainMenu.addAction('add Command Button...')
            command_action.setEnabled(self.editMode)
            command_action.triggered.connect(self.add_commands)

        self.mainMenu.addSeparator()

        reset_action = self.mainMenu.addAction('Reset View')
        reset_action.setShortcut('H')
        reset_action.triggered.connect(self.reset_view)

        frame_action = self.mainMenu.addAction('Frame View')
        frame_action.setShortcut('F')
        frame_action.triggered.connect(self.frame_view)

        self.mainMenu.addSeparator()

        alignGrp = QMenu('Align')
        self.mainMenu.addMenu(alignGrp)

        hac_action = alignGrp.addAction('Horizontal Align Center')
        hac_action.setIcon(QIconSVG('h_align-01'))
        hac_action.setEnabled(self.editMode)
        hac_action.triggered.connect(self.align_horizontal)

        vac_action = alignGrp.addAction('Vertical Align Center')
        vac_action.setIcon(QIconSVG('v_align-01'))
        vac_action.setEnabled(self.editMode)
        vac_action.triggered.connect(self.align_vertical)

        hd_action = alignGrp.addAction('Horizontal Distribute')
        hd_action.setIcon(QIconSVG('h_d_align-01'))
        hd_action.setEnabled(self.editMode)
        hd_action.triggered.connect(self.align_horizontal_distribute)

        vd_action = alignGrp.addAction('Vertical Distribute')
        vd_action.setIcon(QIconSVG('v_d_align-01'))
        vd_action.setEnabled(self.editMode)
        vd_action.triggered.connect(self.align_vertical_distribute)

        alignGrp.addSeparator()

        ins_action = alignGrp.addAction('Increase Size')
        ins_action.setShortcut('+')
        ins_action.setEnabled(self.editMode)
        ins_action.triggered.connect(self.increase_size)

        dis_action = alignGrp.addAction('Decrease Size')
        dis_action.setShortcut('-')
        dis_action.setEnabled(self.editMode)
        dis_action.triggered.connect(self.decrease_size)

        self.mainMenu.addSeparator()

        edit_mode = self.mainMenu.addAction('Edit Mode')
        edit_mode.setCheckable(True)
        edit_mode.setChecked(self.editMode)
        edit_mode.triggered.connect(
            lambda: self.request_edit(not self.editMode))

        pos = self.mapToGlobal(QPoint(0, 0))
        self.mainMenu.move(pos + QPos)
        self.mainMenu.show()

    def mouse_on_node(self):
        globPosition = self.mapFromGlobal(QCursor.pos())
        scenePosition = self.mapToScene(globPosition)
        for node in self._scene.items():
            if isinstance(node, PickNode):
                if node.mapRectToScene(
                        node.boundingRect()).contains(scenePosition):
                    return node
        return None

    def update_node(self, node=PickNode):
        '''
        Update the Node selection base on selection in maya.
        '''
        mayaScene = getActiveItems()
        # for each in self._scene.selectedItems():
        node.Items = mayaScene

    def update_ButtonNode(self, node=ButtonNode):
        '''
        Update the ButtonNode commands.

        Parameters
        ----------
        node: (ButtonNode)
            ButtonNode Node.
        '''
        self.newCommand = CommandDialog(text=node.toPlainText(),
                                        cmd=node.Command,
                                        cmdType=node.CommandsType)
        if self.newCommand.exec_() == QDialog.Accepted:
            data = self.newCommand.Raw
            node.setPlainText(data[PIIButton.TEXT])
            node.Command = data[PIIButton.COMMAND]
            node.CommandsType = data[PIIButton.COMMANDTYPE]

    def add_commands(self):
        '''
        Create a new ButtonNode with Commands.
        '''
        globPosition = self.mapFromGlobal(QCursor.pos())
        scenePosition = self.mapToScene(globPosition)
        self.newCommand = CommandDialog()
        if self.newCommand.exec_() == QDialog.Accepted:
            data = self.newCommand.Raw
            self.create_button(position=scenePosition,
                               text=data[PIIButton.TEXT],
                               size=self._defaultTextSize,
                               textColor=self._defaultTextColor,
                               bgColor=self._defaultColor,
                               cmd=data[PIIButton.COMMAND],
                               cmdType=data[PIIButton.COMMANDTYPE])

    def align_horizontal(self):
        '''
        Align the selection to center horizontally.
        '''
        selected = self._scene.selectedItems()
        if len(selected) > 1:
            minValue = selected[0].y()
            maxValue = selected[0].y()
            whole = None
            for each in selected:
                y = each.y()
                value = y + each.boundingRect().height()
                # finding lowest value
                minValue = y if y < minValue else minValue
                minValue = value if value < minValue else minValue
                # finding highest value
                maxValue = y if y > maxValue else maxValue
                maxValue = value if value > maxValue else maxValue

            total = maxValue - minValue
            if total != 0:
                middle = (maxValue + minValue) / 2
                for each in selected:
                    center = each.shape().boundingRect().center()
                    start_y = each.y()
                    offset = start_y + center.y() - middle
                    each.setY(each.y() - offset)

    def align_vertical(self):
        '''
        Align the selection to center vertically.
        '''
        selected = self._scene.selectedItems()
        if len(selected) > 1:
            # sort it based on x position + width
            selected = sorted(selected,
                              key=lambda x: x.x() + x.boundingRect().width())
            leftNode = selected[0]
            rightNode = selected[-1]
            # total length of x axis
            total = rightNode.boundingRect().width() + rightNode.x(
            ) - leftNode.x()
            if total != 0:
                middle = (total / 2) + leftNode.x()
                for each in selected:
                    center = each.shape().boundingRect().center()
                    start_x = each.x()
                    offset = start_x + center.x() - middle
                    each.setX(each.x() - offset)

    def align_horizontal_distribute(self):
        '''
        Disturbute the selected nodes evenly between first node on the left and last 
        node on the right horizontally.
        '''
        selected = self._scene.selectedItems()
        if len(selected) > 2:
            # sort it based on x position + width
            selected = sorted(selected,
                              key=lambda x: x.x() + x.boundingRect().width())
            startItem = selected.pop(0)
            endItem = selected.pop(-1)

            # total length of items
            itemsLength = int()
            for each in selected:
                itemsLength += each.boundingRect().width()

            startPoint = startItem.x() + startItem.boundingRect().width()
            total = endItem.x() - startPoint
            section_num = len(selected) + 1
            extraSpace = total - itemsLength
            # nicly divide
            if extraSpace > 0:
                gap = extraSpace / section_num
                nextPlace = startPoint
                for each in selected:
                    newLoc = nextPlace + gap
                    nextPlace += gap + each.boundingRect().width()
                    each.setX(newLoc)
            else:
                total = endItem.x() - startPoint
                gap = total / section_num
                nextPlace = startPoint
                for each in selected:
                    nextPlace += gap
                    each.setX(nextPlace)
        else:
            errorMes("PUPPETMASTER-INFO: Select more than 2 nodes.")

    def align_vertical_distribute(self):
        '''
        Disturbute the selected nodes evenly between first node on the top and last 
        node on the bottom vertically.
        '''
        selected = self._scene.selectedItems()
        if len(selected) > 2:
            # sort it based on y position + width
            selected = sorted(
                selected,
                key=lambda node: node.y() + node.boundingRect().height())
            startItem = selected.pop(0)
            endItem = selected.pop(-1)

            # total length of items
            itemsLength = int()
            for each in selected:
                itemsLength += each.boundingRect().height()

            startPoint = startItem.y() + startItem.boundingRect().height()
            total = endItem.y() - startPoint
            section_num = len(selected) + 1
            extraSpace = total - itemsLength
            # nicly divide
            if extraSpace > 0:
                gap = extraSpace / section_num
                nextPlace = startPoint
                for each in selected:
                    newLoc = nextPlace + gap
                    nextPlace += gap + each.boundingRect().height()
                    each.setY(newLoc)
            else:
                total = endItem.y() - startPoint
                gap = total / section_num
                nextPlace = startPoint
                for each in selected:
                    nextPlace += gap
                    each.setY(nextPlace)
        else:
            errorMes("PUPPETMASTER-INFO: Select more than 2 nodes.")

    def reset_view(self):
        '''
        Fit all the items to the view.
        '''
        items = self._scene.items()
        if items:
            rects = [
                item.mapToScene(item.boundingRect()).boundingRect()
                for item in items
            ]
            rect = self.min_bounding_rect(rects)
            self._scene.setSceneRect(rect)
            self.fitInView(rect, Qt.KeepAspectRatio)

    def frame_view(self):
        '''
        Fit selected items to the view.
        '''
        items = self._scene.selectedItems()
        if items:
            rects = [
                item.mapToScene(item.boundingRect()).boundingRect()
                for item in items
            ]
            rect = self.min_bounding_rect(rects)
            self.fitInView(rect, Qt.KeepAspectRatio)

    def fit_contents(self):
        '''
        Update the scene boundery.
        '''
        items = self._scene.items()
        if items:
            rects = [
                item.mapToScene(item.boundingRect()).boundingRect()
                for item in items
            ]
            rect = self.min_bounding_rect(rects)
            self._scene.setSceneRect(rect)

    def request_edit(self, value=bool):
        self.requestEditMode.emit(value)

    def min_bounding_rect(self, rectList=list()):
        '''
        Get the minimum boundry based on objects in the scene.

        Parameters
        ----------
        rectList: (list)
            List of QRectF (boundry of objects)

        Return
        ------
        out: (QRectF)
            Get the minimum boundry
        '''
        minX = rectList[0].left()
        minY = rectList[0].top()
        maxX = rectList[0].right()
        maxY = rectList[0].bottom()

        for k in range(1, len(rectList)):
            minX = min(minX, rectList[k].left())
            minY = min(minY, rectList[k].top())
            maxX = max(maxX, rectList[k].right())
            maxY = max(maxY, rectList[k].bottom())

        return QRectF(minX, minY, maxX - minX, maxY - minY)

    def increase_size(self):
        '''
        Increase the size of selected items by 1 unit.
        '''
        selected = self._scene.selectedItems()
        for each in selected:
            font = each.font()
            fontSize = font.pointSize()
            if fontSize < 99:
                fontSize += 1
                font.setPointSize(fontSize)
                each.setFont(font)

    def decrease_size(self):
        '''
        Decrease the size of selected items by 1 unit.
        '''
        selected = self._scene.selectedItems()
        for each in selected:
            font = each.font()
            fontSize = font.pointSize()
            if fontSize > 1:
                fontSize -= 1
                font.setPointSize(fontSize)
                each.setFont(font)

    def is_texture(self, path=str):
        '''
        Check if the texture path is valid.

        Return
        ------
        out: (bool)
            True if texture is valide, otherwise False.
        '''
        if path.lower().endswith(IMAGE_FORMATS):
            return True
        return False

    def _QMimeDataToFile(self, data=QMimeData):
        '''
        Get all the filepath from drag file.

        Parameters
        ----------
        data: (QMimeData)
            QMimeData of dragged file.
        '''
        files = list()
        if data.hasUrls:
            for each in data.urls():
                files.append(each.toLocalFile())
        return files

    def _is_dragValid(self, event):
        '''
        Check for draged file validation
        '''
        dragedItems = self._QMimeDataToFile(event.mimeData())
        if dragedItems:
            first_path = dragedItems[0]
            if self.is_texture(first_path) and self.editMode:
                return True
        return False

    def dragEnterEvent(self, event):
        event.accept() if self._is_dragValid(event) else event.ignore()

    def dragMoveEvent(self, event):
        event.accept() if self._is_dragValid(event) else event.ignore()

    def dropEvent(self, event):
        dragedItems = self._QMimeDataToFile(event.mimeData())
        if dragedItems:
            first_path = dragedItems[0]
            if self.is_texture(first_path):
                self.setBackgroundImage(path=first_path)
                event.accept()
        else:
            event.ignore()

    def mousePressEvent(self, event):
        self._lastPos = event.pos()
        self._lastScenePos = self.mapToScene(event.pos())
        if self._dragMulti:
            for each in self._dragMulti:
                each.setSelected(True)
            self._dragMulti = list()
        if event.button() == Qt.MiddleButton:
            self._isPanning = True
            self.setCursor(QPixmap(iconSVG('nav-pan-02')))
            self._dragPos = event.pos()
            event.accept()
        elif event.button() == Qt.RightButton:
            if event.modifiers() == Qt.AltModifier:
                self._isZooming = True
                self.setCursor(QPixmap(iconSVG('nav-zoom-02')))
                self._dragPos = event.pos()
                self._dragPos2 = self.mapToScene(event.pos())
            else:
                self.actionMenu(event.pos())
            event.accept()
        else:
            super(CanvasGraphicsView, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if self._dragMulti and len(self._dragMulti) > 1:
            start = self._lastScenePos
            end = self.mapToScene(event.pos())

            total = len(self._dragMulti) - 1
            xLength = start.x() - end.x()
            yLength = start.y() - end.y()
            xStep = 0 if xLength == 0 else -(xLength / total)
            yStep = 0 if yLength == 0 else -(yLength / total)
            num = 0
            for each in self._dragMulti:
                position = QPointF(start.x() + (num * xStep),
                                   start.y() + (num * yStep))
                each.setPos(position)
                num += 1

        if self._isPanning:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            self.horizontalScrollBar().setValue(
                self.horizontalScrollBar().value() - diff.x())
            self.verticalScrollBar().setValue(
                self.verticalScrollBar().value() - diff.y())
            event.accept()
        elif self._isZooming:
            newPos = event.pos()
            diff = newPos - self._dragPos
            self._dragPos = newPos
            factor = 1.000
            if diff.x() < 0:
                factor = 0.98
            else:
                factor = 1.02

            self.scale(factor, factor)
            event.accept()
        else:
            if event.modifiers() == Qt.ShiftModifier:
                diff = event.pos() - self._lastPos
                x = event.x() if abs(diff.x()) > abs(
                    diff.y()) else self._lastPos.x()
                y = event.y() if abs(diff.y()) > abs(
                    diff.x()) else self._lastPos.y()
                event = QMouseEvent(QEvent.MouseMove, QPoint(x, y),
                                    self.mapToGlobal(QPoint(x,
                                                            y)), Qt.LeftButton,
                                    Qt.LeftButton, Qt.NoModifier)
            super(CanvasGraphicsView, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        self._isPanning = False
        self._isZooming = False
        self.setCursor(Qt.ArrowCursor)
        super(CanvasGraphicsView, self).mouseReleaseEvent(event)
        self.fit_contents()
        self.update_maya_selection()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Backspace or event.key() == Qt.Key_Delete:
            if self.editMode:
                self.removeSelected()
        elif event.key() == Qt.Key_Plus:
            if self.editMode:
                self.increase_size()
        elif event.key() == Qt.Key_Minus:
            if self.editMode:
                self.decrease_size()
        elif event.key() == Qt.Key_H:
            self.reset_view()
        elif event.key() == Qt.Key_F:
            self.frame_view()
        else:
            super(CanvasGraphicsView, self).keyPressEvent(event)

    def removeSelected(self):
        '''
        Remove selected Items.
        '''
        for each in self._scene.selectedItems():
            self._scene.removeItem(each)
            self.remove_stack(each)

    def wheelEvent(self, event):
        factor = 1.05
        if event.delta() < 0:
            # factor = .2 / factor
            factor = 0.95
        self.scale(factor, factor)
        self.update()

    def add_node(self):
        '''
        Add a new PickNode to the scene.
        '''
        # Cursor Position on Scene
        globPosition = self.mapFromGlobal(QCursor.pos())
        scenePosition = self.mapToScene(globPosition)

        self.create_node(text=self._defaultText,
                         size=self._defaultTextSize,
                         textColor=self._defaultTextColor,
                         bgColor=self._defaultColor,
                         position=scenePosition,
                         items=getActiveItems(),
                         shape=PickShape.SQUARE)

    def add_multiple_nodes(self):
        '''
        Add group of PickNode bellow each other to the scene.
        '''
        # Cursor Position on Scene
        globPosition = self.mapFromGlobal(QCursor.pos())
        scenePosition = self.mapToScene(globPosition)

        self._dragMulti = list()
        for each in getActiveItems():
            node = self.create_node(text=self._defaultText,
                                    size=self._defaultTextSize,
                                    textColor=self._defaultTextColor,
                                    bgColor=self._defaultColor,
                                    position=scenePosition,
                                    items=[each],
                                    shape=PickShape.SQUARE)
            self._dragMulti.append(node)
            # scenePosition = QPointF(scenePosition.x(), node.y() + node.boundingRect().height() + 5)

    def create_node(self,
                    position=list,
                    text=str,
                    size=int,
                    textColor=QColor,
                    bgColor=QColor,
                    items=list,
                    shape=PickShape.SQUARE):
        '''
        Create a new PickNode.

        Parameters
        ----------
        position: (list)
            List of x and y location.
        text: (str)
            Name of the text.
        size: (int)
            Size of the text.
        textColor: (QColor)
            Color of the text.
        bgColor: (QColor)
            Background Color of the node.
        items: (list)
            List of selected Maya object.

        Return
        ------
        out: (PickNode)
            Reference of created Node.
        '''
        textNode = PickNode()
        font = QFont("SansSerif", size)
        font.setStyleHint(QFont.Helvetica)
        textNode.setFont(font)
        textNode.setDefaultTextColor(textColor)
        textNode.setFlag(QGraphicsItem.ItemIsMovable, self.editMode)
        textNode.setFlag(QGraphicsItem.ItemIsSelectable)
        # textNode.setFlag(QGraphicsItem.ItemIsFocusable, self.editMode)
        textNode.Background = bgColor
        textNode.Items = items
        textNode.Shape = shape

        textNode.onSelected.connect(lambda: self.onSelection.emit(textNode))
        textNode.onAddToStack.connect(lambda: self.add_stack(textNode))
        textNode.onRemoveFromStack.connect(lambda: self.remove_stack(textNode))

        textNode.setPos(position)
        textNode.setPlainText(text)

        self._scene.addItem(textNode)
        return textNode

    def create_button(self,
                      position=list,
                      text=str,
                      size=int,
                      textColor=QColor,
                      bgColor=QColor,
                      cmd=str,
                      cmdType=str):
        '''
        Create a new ButtonNode.

        Parameters
        ----------
        position: (list)
            List of x and y location.
        text: (str)
            Name of the text.
        size: (int)
            Size of the text.
        textColor: (QColor)
            Color of the text.
        bgColor: (QColor)
            Background Color of the node.
        cmd: (str)
            Command to run when it's pressed.
        cmdType: (str)
            Type of command.("python"/"mel")
        '''
        btnNode = ButtonNode()
        font = QFont("SansSerif", size)
        font.setStyleHint(QFont.Helvetica)
        btnNode.setFont(font)
        btnNode.setDefaultTextColor(textColor)
        btnNode.setFlag(QGraphicsItem.ItemIsMovable, self.editMode)
        btnNode.setFlag(QGraphicsItem.ItemIsSelectable)
        btnNode.Background = bgColor
        btnNode.CommandsType = cmdType
        btnNode.Command = cmd

        # btnNode.onSelected.connect(lambda: self.onSelection.emit(textNode))
        btnNode.onSelected.connect(lambda: self.onSelection.emit(btnNode))
        btnNode.onClicked.connect(self.scriptJob)

        btnNode.setPos(position)
        btnNode.setPlainText(text)

        self._scene.addItem(btnNode)

    def scriptJob(self, cmdType=str, cmd=str):
        '''
        Run a command.

        Parameters
        ----------
        cmd: (str)
            Command to run.
        cmdType: (str)
            Type of command.("python"/"mel")
        '''
        if not self.editMode:
            if cmdType == CommandType.PYTHON:
                runPython(cmd)
            elif cmdType == CommandType.MEL:
                runMel(cmd)

    def add_stack(self, node=PickNode):
        '''
        Add a node selection in right order into the stack.

        Parameters
        ----------
        node: (PickNode)
            Selected node.
        '''
        self._orderSelected.append(node)

    def remove_stack(self, node=PickNode):
        '''
        Remove a node from the stack.

        Parameters
        ----------
        node: (PickNode)
            Selected node.
        '''
        if node in self._orderSelected:
            index = self._orderSelected.index(node)
            self._orderSelected.pop(index)

    def get_edit(self):
        return self.editMode

    def set_edit(self, value=bool):
        self.editMode = value
        for each in self._scene.items():
            if type(each) == PickNode:
                each.setFlag(QGraphicsItem.ItemIsMovable, self.editMode)
            elif type(each) == ButtonNode:
                each.setFlag(QGraphicsItem.ItemIsMovable, self.editMode)

    Edit = property(get_edit, set_edit)

    def get_path(self):
        return self.piiPath

    def set_path(self, path=str):
        self.piiPath = path

    Path = property(get_path, set_path)

    def get_raw(self):
        '''
        Get the scene information. (can be be save in .pii)

        Return
        ------
        out: (dict)
            Dictionary of scene date to be save in .pii file.
        '''
        image_data = str()
        pixmap = self._backgroundNode.pixmap()
        # Extract Image Data
        if not pixmap.isNull():
            buffer = QBuffer()
            buffer.open(QIODevice.WriteOnly)
            pixmap.save(buffer, "PNG")
            # Image Data
            image_data = bytes(buffer.data().toBase64()).decode('ascii')

        nodeList = []
        for each in self._scene.items():
            if type(each) == PickNode:
                textColor = each.defaultTextColor()
                bgColor = each.Background
                item = {
                    PIIPick.TYPE:
                    PIINode.PICK,
                    PIIPick.TEXT:
                    each.toPlainText(),
                    PIIPick.SIZE:
                    each.font().pointSize(),
                    PIIPick.POSITION: (each.pos().x(), each.pos().y()),
                    PIIPick.COLOR:
                    (textColor.red(), textColor.green(), textColor.blue()),
                    PIIPick.BACKGROUND:
                    (bgColor.red(), bgColor.green(), bgColor.blue()),
                    PIIPick.SELECTION:
                    each.Items,
                    PIIPick.SHAPE:
                    each.Shape
                }
                nodeList.append(item)
            elif type(each) == ButtonNode:
                textColor = each.defaultTextColor()
                bgColor = each.Background
                item = {
                    PIIButton.TYPE:
                    PIINode.BUTTON,
                    PIIButton.TEXT:
                    each.toPlainText(),
                    PIIButton.SIZE:
                    each.font().pointSize(),
                    PIIButton.POSITION: (each.pos().x(), each.pos().y()),
                    PIIButton.COLOR:
                    (textColor.red(), textColor.green(), textColor.blue()),
                    PIIButton.BACKGROUND:
                    (bgColor.red(), bgColor.green(), bgColor.blue()),
                    PIIButton.COMMAND:
                    each.Command,
                    PIIButton.COMMANDTYPE:
                    each.CommandsType
                }
                nodeList.append(item)

        rawData = {
            PII.VERSION: "1.0.0",
            PII.BACKGROUND: image_data,
            PII.NODES: nodeList
        }
        return rawData

    def set_raw(self, data=dict):
        '''
        set the scene information. (information from .pii)

        Parameters
        ----------
        data: (dict)
            Dictionary of date from .pii file.
        '''
        if data:
            if data[PII.VERSION] == "1.0.0":
                self.load_1_0_0(data)

    Raw = property(get_raw, set_raw)

    def get_namespace(self):
        '''
        Get namespace of all PickNode.

        Return
        ------
        out: (list)
            List of namespaces.
        '''
        namespaceList = []
        for each in self._scene.items():
            if type(each) == PickNode:
                valueList = each.Items
                for sObj in valueList:
                    if ":" in sObj:
                        group = sObj.split(":")[:-1]
                        for index in range(len(group)):
                            namespaceList.append(":".join(group[:index + 1]))
        return list(set(namespaceList))

    def set_namespace(self, data=dict):
        '''
        Set namespace of all PickNode.

        Parameters
        ----------
        data: (dict)
            Dictionary of namespace with value of new namespace.
        '''
        for each in self._scene.items():
            if type(each) == PickNode:
                valueList = each.Items
                newValue = list()
                for sObj in valueList:
                    if ":" in sObj:
                        # namesapce
                        nameS = ":".join(sObj.split(":")[:-1])
                        # object name
                        object_name = sObj.split(":")[-1]
                        keys = data.keys()
                        keys.sort(reverse=True)
                        for key in keys:
                            if key in nameS:
                                nameS = nameS.replace(key, data[key], 1)
                        # making sure doesn't start with ':'
                        nameS = nameS[1:] if nameS.startswith(":") else nameS
                        # add the object to namespace
                        nameS = ":".join([nameS, object_name
                                          ]) if nameS else object_name
                        newValue.append(nameS)
                    else:
                        newValue.append(sObj)
                each.Items = newValue

    Namespace = property(get_namespace, set_namespace)

    def get_NSHistory(self):
        return self._namespace

    def set_NSHistory(self, name=str):
        self._namespace = name

    NamespaceHistory = property(get_NSHistory, set_NSHistory)

    def get_highlight(self):
        return

    def set_highlight(self, data=list):
        if data:
            for each in self._scene.items():
                # QApplication.processEvents()
                if type(each) == PickNode:
                    for item in data:
                        if item in each.Items:
                            each.Highlight = True
                            break
                        else:
                            each.Highlight = False
        else:
            for each in self._scene.items():
                if type(each) == PickNode:
                    each.Highlight = False

    Highlight = property(get_highlight, set_highlight)

    def clear_scene(self):
        '''
        Clear the scene.
        '''
        self._orderSelected = list()
        self._scene.clear()
        self._backgroundNode = QGraphicsPixmapItem()
        self._scene.addItem(self._backgroundNode)
        self.reset_view()

    def is_changed(self):
        '''
        Check for the scene changes.
        '''
        if self._backgroundNode.pixmap():
            return True
        elif len(self._scene.items()) > 1:
            return True
        return False

    def load_1_0_0(self, data=dict):
        '''
        Load v1.0.0 of .pii version file.

        Parameters
        ----------
        data: (dict)
            Dictionary of date from .pii file.
        '''
        if data[PII.BACKGROUND]:
            # Import Image Data
            newPix = QPixmap()
            newPix.loadFromData(
                QByteArray.fromBase64(data[PII.BACKGROUND].encode('ascii')),
                "PNG")
            self._backgroundNode.setPixmap(newPix)

        for each in data[PII.NODES]:
            if each["type"] == PIINode.PICK:
                self.create_node(text=each[PIIPick.TEXT],
                                 size=each[PIIPick.SIZE],
                                 textColor=QColor(*each[PIIPick.COLOR]),
                                 bgColor=QColor(*each[PIIPick.BACKGROUND]),
                                 position=QPointF(*each[PIIPick.POSITION]),
                                 items=each[PIIPick.SELECTION],
                                 shape=each[PIIPick.SHAPE])
            elif each["type"] == PIINode.BUTTON:
                self.create_button(position=QPointF(*each[PIIButton.POSITION]),
                                   text=each[PIIButton.TEXT],
                                   size=each[PIIButton.SIZE],
                                   textColor=QColor(*each[PIIButton.COLOR]),
                                   bgColor=QColor(*each[PIIButton.BACKGROUND]),
                                   cmd=each[PIIButton.COMMAND],
                                   cmdType=each[PIIButton.COMMANDTYPE])

    def set_nodes_bg_color(self, color=QColor):
        '''
        Set background color of selected nodes.

        Parameters
        ----------
        color: (QColor)
            QColor value.
        '''
        self._defaultColor = color
        for each in self._scene.selectedItems():
            each.Background = color
        self.update()

    def set_nodes_font_color(self, color=QColor):
        '''
        Set font color of selected nodes.

        Parameters
        ----------
        color: (QColor)
            QColor value.
        '''
        self._defaultTextColor = color
        for each in self._scene.selectedItems():
            each.setDefaultTextColor(color)

    def set_nodes_font_size(self, size=int):
        '''
        Set font size of selected nodes.

        Parameters
        ----------
        size: (int)
            font size.
        '''
        self._defaultTextSize = size
        for each in self._scene.selectedItems():
            font = each.font()
            font.setPointSize(size)
            each.setFont(font)

    def set_nodes_text(self, text=str):
        '''
        Set text for selected nodes.

        Parameters
        ----------
        text: (str)
            text for the node.
        '''
        self._defaultText = text
        for each in self._scene.selectedItems():
            each.setPlainText(text)

    def set_nodes_shape(self, shape=str):
        '''
        Set shape for selected nodes.

        Parameters
        ----------
        shape: (str)
            name for the shape.
        '''
        for each in self._scene.selectedItems():
            if isinstance(each, PickNode):
                each.Shape = shape
コード例 #3
0
class PivotTableView(CopyPasteTableView):
    """Custom QTableView class with pivot capabilities.
    """

    _REMOVE_OBJECT = "Remove selected objects"
    _REMOVE_RELATIONSHIP = "Remove selected relationships"
    _REMOVE_PARAMETER = "Remove selected parameter definitions"

    def __init__(self, parent=None):
        """Initialize the class."""
        super().__init__(parent)
        self._data_store_form = None
        self._menu = QMenu(self)
        self._selected_value_indexes = list()
        self._selected_entity_indexes = list()
        self._selected_parameter_indexes = list()
        self.open_in_editor_action = None
        self.plot_action = None
        self._plot_in_window_menu = None
        self.remove_values_action = None
        self.remove_objects_action = None
        self.remove_relationships_action = None
        self.remove_parameters_action = None

    @property
    def source_model(self):
        return self.model().sourceModel()

    @property
    def db_mngr(self):
        return self.source_model.db_mngr

    @property
    def db_map(self):
        return self._data_store_form.db_map

    def connect_data_store_form(self, data_store_form):
        self._data_store_form = data_store_form
        self.create_context_menu()
        h_header = PivotTableHeaderView(Qt.Horizontal, "columns", self)
        h_header.setContextMenuPolicy(Qt.DefaultContextMenu)
        h_header.setResizeContentsPrecision(data_store_form.visible_rows)
        v_header = PivotTableHeaderView(Qt.Vertical, "rows", self)
        v_header.setContextMenuPolicy(Qt.NoContextMenu)
        v_header.setDefaultSectionSize(data_store_form.default_row_height)
        self.setHorizontalHeader(h_header)
        self.setVerticalHeader(v_header)

    def create_context_menu(self):
        self.open_in_editor_action = self._menu.addAction(
            "Open in editor...", self.open_in_editor)
        self._menu.addSeparator()
        self.plot_action = self._menu.addAction("Plot", self.plot)
        self._plot_in_window_menu = self._menu.addMenu("Plot in window")
        self._plot_in_window_menu.triggered.connect(self._plot_in_window)
        self._menu.addSeparator()
        self.remove_values_action = self._menu.addAction(
            "Remove selected parameter values", self.remove_values)
        self.remove_objects_action = self._menu.addAction(
            self._REMOVE_OBJECT, self.remove_objects)
        self.remove_relationships_action = self._menu.addAction(
            self._REMOVE_RELATIONSHIP, self.remove_relationships)
        self.remove_parameters_action = self._menu.addAction(
            self._REMOVE_PARAMETER, self.remove_parameters)

    def remove_selected(self):
        self._find_selected_indexes()
        self.remove_values()
        self.remove_relationships()
        self.remove_objects()
        self.remove_parameters()

    def remove_values(self):
        row_mask = set()
        column_mask = set()
        for index in self._selected_value_indexes:
            row, column = self.source_model.map_to_pivot(index)
            row_mask.add(row)
            column_mask.add(column)
        data = self.source_model.model.get_pivoted_data(row_mask, column_mask)
        ids = {item for row in data for item in row if item is not None}
        parameter_values = [
            self.db_mngr.get_item(self.db_map, "parameter value", id_)
            for id_ in ids
        ]
        db_map_typed_data = {
            self.db_map: {
                "parameter value": parameter_values
            }
        }
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_objects(self):
        ids = {
            self.source_model._header_id(index)
            for index in self._selected_entity_indexes
        }
        objects = [
            self.db_mngr.get_item(self.db_map, "object", id_) for id_ in ids
        ]
        db_map_typed_data = {self.db_map: {"object": objects}}
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_relationships(self):
        if self.model().sourceModel().item_type != "relationship":
            return
        rels_by_object_ids = {
            rel["object_id_list"]: rel
            for rel in self._data_store_form._get_entities()
        }
        relationships = []
        for index in self._selected_entity_indexes:
            object_ids, _ = self.source_model.object_and_parameter_ids(index)
            object_ids = ",".join([str(id_) for id_ in object_ids])
            relationships.append(rels_by_object_ids[object_ids])
        db_map_typed_data = {self.db_map: {"relationship": relationships}}
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_parameters(self):
        ids = {
            self.source_model._header_id(index)
            for index in self._selected_parameter_indexes
        }
        parameters = [
            self.db_mngr.get_item(self.db_map, "parameter definition", id_)
            for id_ in ids
        ]
        db_map_typed_data = {self.db_map: {"parameter definition": parameters}}
        self.db_mngr.remove_items(db_map_typed_data)

    def open_in_editor(self):
        """Opens the parameter value editor for the first selected cell."""
        index = self._selected_value_indexes[0]
        self._data_store_form.show_parameter_value_editor(index)

    def plot(self):
        """Plots the selected cells in the pivot table."""
        selected_indexes = self.selectedIndexes()
        hints = PivotTablePlottingHints()
        try:
            plot_window = plot_selection(self.model(), selected_indexes, hints)
        except PlottingError as error:
            report_plotting_failure(error, self)
            return
        plotted_column_names = {
            hints.column_label(self.model(), index.column())
            for index in selected_indexes
            if hints.is_index_in_data(self.model(), index)
        }
        plot_window.use_as_window(self.parentWidget(),
                                  ", ".join(plotted_column_names))
        plot_window.show()

    def contextMenuEvent(self, event):
        """Shows context menu.

        Args:
            event (QContextMenuEvent)
        """
        self._find_selected_indexes()
        self._update_actions_availability()
        self._update_actions_text()
        pos = event.globalPos()
        self._menu.move(pos)
        _prepare_plot_in_window_menu(self._plot_in_window_menu)
        self._menu.show()

    def _find_selected_indexes(self):
        indexes = [
            self.model().mapToSource(ind) for ind in self.selectedIndexes()
        ]
        self._selected_value_indexes = list()
        self._selected_entity_indexes = list()
        self._selected_parameter_indexes = list()
        for index in indexes:
            if self.source_model.index_in_data(index):
                self._selected_value_indexes.append(index)
            elif self.source_model.index_in_headers(index):
                top_left_id = self.source_model._top_left_id(index)
                header_type = self.source_model.top_left_headers[
                    top_left_id].header_type
                if header_type == "parameter":
                    self._selected_parameter_indexes.append(index)
                elif header_type == "object":
                    self._selected_entity_indexes.append(index)

    def _update_actions_availability(self):
        self.open_in_editor_action.setEnabled(
            len(self._selected_value_indexes) == 1)
        self.plot_action.setEnabled(len(self._selected_value_indexes) > 0)
        self.remove_values_action.setEnabled(bool(
            self._selected_value_indexes))
        self.remove_objects_action.setEnabled(
            bool(self._selected_entity_indexes))
        self.remove_relationships_action.setEnabled(
            bool(self._selected_entity_indexes)
            and self.model().sourceModel().item_type != "relationship")
        self.remove_parameters_action.setEnabled(
            bool(self._selected_parameter_indexes))

    def _update_actions_text(self):
        self.remove_objects_action.setText(self._REMOVE_OBJECT)
        self.remove_relationships_action.setText(self._REMOVE_RELATIONSHIP)
        self.remove_parameters_action.setText(self._REMOVE_PARAMETER)
        if len(self._selected_entity_indexes) == 1:
            index = self._selected_entity_indexes[0]
            object_name = self.source_model.header_name(index)
            self.remove_objects_action.setText(
                "Remove object: {}".format(object_name))
            if self.remove_relationships_action.isEnabled():
                object_names, _ = self.source_model.object_and_parameter_names(
                    index)
                relationship_name = self.db_mngr._GROUP_SEP.join(object_names)
                self.remove_relationships_action.setText(
                    "Remove relationship: {}".format(relationship_name))
        if len(self._selected_parameter_indexes) == 1:
            index = self._selected_parameter_indexes[0]
            parameter_name = self.source_model.header_name(index)
            self.remove_parameters_action.setText(
                "Remove parameter definition: {}".format(parameter_name))

    @Slot("QAction")
    def _plot_in_window(self, action):
        window_id = action.text()
        plot_window = PlotWidget.plot_windows.get(window_id)
        if plot_window is None:
            self.plot()
            return
        selected_indexes = self.selectedIndexes()
        hints = PivotTablePlottingHints()
        try:
            plot_selection(self.model(), selected_indexes, hints, plot_window)
            plot_window.raise_()
        except PlottingError as error:
            report_plotting_failure(error, self)
コード例 #4
0
class PivotTableView(CopyPasteTableView):
    """Custom QTableView class with pivot capabilities.
    """

    _REMOVE_OBJECT = "Remove selected objects"
    _REMOVE_RELATIONSHIP = "Remove selected relationships"
    _REMOVE_PARAMETER = "Remove selected parameter definitions"
    _REMOVE_ALTERNATIVE = "Remove selected alternatives"
    _REMOVE_SCENARIO = "Remove selected scenarios"

    def __init__(self, parent=None):
        """Initialize the class."""
        super().__init__(parent)
        self._spine_db_editor = None
        self._menu = QMenu(self)
        self._selected_value_indexes = list()
        self._selected_entity_indexes = list()
        self._selected_parameter_indexes = list()
        self._selected_alternative_indexes = list()
        self._selected_scenario_indexes = list()
        self.open_in_editor_action = None
        self.plot_action = None
        self._plot_in_window_menu = None
        self.remove_values_action = None
        self.remove_objects_action = None
        self.remove_relationships_action = None
        self.remove_parameters_action = None
        self.remove_alternatives_action = None
        self.remove_scenarios_action = None

    @property
    def source_model(self):
        return self.model().sourceModel()

    @property
    def db_mngr(self):
        return self.source_model.db_mngr

    def connect_spine_db_editor(self, spine_db_editor):
        self._spine_db_editor = spine_db_editor
        self.create_context_menu()
        h_header = PivotTableHeaderView(Qt.Horizontal, "columns", self)
        h_header.setContextMenuPolicy(Qt.DefaultContextMenu)
        h_header.setResizeContentsPrecision(spine_db_editor.visible_rows)
        v_header = PivotTableHeaderView(Qt.Vertical, "rows", self)
        v_header.setContextMenuPolicy(Qt.NoContextMenu)
        v_header.setDefaultSectionSize(spine_db_editor.default_row_height)
        self.setHorizontalHeader(h_header)
        self.setVerticalHeader(v_header)

    def create_context_menu(self):
        self.open_in_editor_action = self._menu.addAction("Open in editor...", self.open_in_editor)
        self._menu.addSeparator()
        self.plot_action = self._menu.addAction("Plot", self.plot)
        self._plot_in_window_menu = self._menu.addMenu("Plot in window")
        self._plot_in_window_menu.triggered.connect(self._plot_in_window)
        self._menu.addSeparator()
        self.remove_values_action = self._menu.addAction("Remove selected parameter values", self.remove_values)
        self.remove_objects_action = self._menu.addAction(self._REMOVE_OBJECT, self.remove_objects)
        self.remove_relationships_action = self._menu.addAction(self._REMOVE_RELATIONSHIP, self.remove_relationships)
        self.remove_parameters_action = self._menu.addAction(self._REMOVE_PARAMETER, self.remove_parameters)
        self.remove_alternatives_action = self._menu.addAction(self._REMOVE_ALTERNATIVE, self.remove_alternatives)
        self.remove_scenarios_action = self._menu.addAction(self._REMOVE_SCENARIO, self.remove_scenarios)

    def remove_selected(self):
        self._find_selected_indexes()
        self.remove_values()
        if self._can_remove_relationships():
            self.remove_relationships()
        self.remove_objects()
        self.remove_parameters()
        self.remove_alternatives()
        self.remove_scenarios()

    def remove_values(self):
        row_mask = set()
        column_mask = set()
        for index in self._selected_value_indexes:
            row, column = self.source_model.map_to_pivot(index)
            row_mask.add(row)
            column_mask.add(column)
        data = self.source_model.model.get_pivoted_data(row_mask, column_mask)
        items = (item for row in data for item in row)
        db_map_typed_data = {}
        for item in items:
            if item is None:
                continue
            db_map, id_ = item
            db_map_typed_data.setdefault(db_map, {}).setdefault("parameter_value", set()).add(id_)
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_objects(self):
        db_map_typed_data = {}
        for index in self._selected_entity_indexes:
            db_map, id_ = self.source_model._header_id(index)
            db_map_typed_data.setdefault(db_map, {}).setdefault("object", set()).add(id_)
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_relationships(self):
        db_map_relationship_lookup = {
            db_map: {rel["object_id_list"]: rel["id"] for rel in rels}
            for db_map, rels in self._spine_db_editor._get_db_map_entities().items()
        }
        db_map_typed_data = {}
        for index in self._selected_entity_indexes:
            db_map, object_ids = self.source_model.db_map_object_ids(index)
            object_id_list = ",".join([str(id_) for id_ in object_ids])
            id_ = db_map_relationship_lookup.get(db_map, {}).get(object_id_list)
            if id_:
                db_map_typed_data.setdefault(db_map, {}).setdefault("relationship", set()).add(id_)
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_parameters(self):
        db_map_typed_data = {}
        for index in self._selected_parameter_indexes:
            db_map, id_ = self.source_model._header_id(index)
            db_map_typed_data.setdefault(db_map, {}).setdefault("parameter_definition", set()).add(id_)
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_alternatives(self):
        db_map_typed_data = {}
        for index in self._selected_alternative_indexes:
            db_map, id_ = self.source_model._header_id(index)
            db_map_typed_data.setdefault(db_map, {}).setdefault("alternative", set()).add(id_)
        self.db_mngr.remove_items(db_map_typed_data)

    def remove_scenarios(self):
        db_map_typed_data = {}
        for index in self._selected_scenario_indexes:
            db_map, id_ = self.source_model._header_id(index)
            db_map_typed_data.setdefault(db_map, {}).setdefault("scenario", set()).add(id_)
        self.db_mngr.remove_items(db_map_typed_data)

    def open_in_editor(self):
        """Opens the parameter_value editor for the first selected cell."""
        index = self._selected_value_indexes[0]
        self._spine_db_editor.show_parameter_value_editor(index)

    def plot(self):
        """Plots the selected cells in the pivot table."""
        selected_indexes = self.selectedIndexes()
        hints = PivotTablePlottingHints()
        try:
            plot_window = plot_selection(self.model(), selected_indexes, hints)
        except PlottingError as error:
            report_plotting_failure(error, self)
            return
        plotted_column_names = {
            hints.column_label(self.model(), index.column())
            for index in selected_indexes
            if hints.is_index_in_data(self.model(), index)
        }
        plot_window.use_as_window(self.parentWidget(), ", ".join(plotted_column_names))
        plot_window.show()

    def contextMenuEvent(self, event):
        """Shows context menu.

        Args:
            event (QContextMenuEvent)
        """
        self._find_selected_indexes()
        self._update_actions_availability()
        pos = event.globalPos()
        self._menu.move(pos)
        _prepare_plot_in_window_menu(self._plot_in_window_menu)
        self._menu.show()

    def _find_selected_indexes(self):
        indexes = [self.model().mapToSource(ind) for ind in self.selectedIndexes()]
        self._selected_value_indexes = list()
        self._selected_entity_indexes = list()
        self._selected_parameter_indexes = list()
        self._selected_alternative_indexes = list()
        self._selected_scenario_indexes = list()
        for index in indexes:
            if self.source_model.index_in_data(index):
                self._selected_value_indexes.append(index)
            elif self.source_model.index_in_headers(index):
                top_left_id = self.source_model._top_left_id(index)
                header_type = self.source_model.top_left_headers[top_left_id].header_type
                if header_type == "parameter":
                    self._selected_parameter_indexes.append(index)
                elif header_type == "object":
                    self._selected_entity_indexes.append(index)
                elif header_type == "alternative":
                    self._selected_alternative_indexes.append(index)
                elif header_type == "scenario":
                    self._selected_scenario_indexes.append(index)

    def _update_actions_availability(self):
        self.open_in_editor_action.setEnabled(len(self._selected_value_indexes) == 1)
        self.plot_action.setEnabled(len(self._selected_value_indexes) > 0)
        self.remove_values_action.setEnabled(bool(self._selected_value_indexes))
        self.remove_objects_action.setEnabled(bool(self._selected_entity_indexes))
        self.remove_relationships_action.setEnabled(
            bool(self._selected_entity_indexes) and self._can_remove_relationships()
        )
        self.remove_parameters_action.setEnabled(bool(self._selected_parameter_indexes))
        self.remove_alternatives_action.setEnabled(bool(self._selected_alternative_indexes))
        self.remove_scenarios_action.setEnabled(bool(self._selected_scenario_indexes))

    def _can_remove_relationships(self):
        return (
            self.model().sourceModel().item_type == "parameter_value"
            and self._spine_db_editor.current_class_type == "relationship_class"
        )

    @Slot(QAction)
    def _plot_in_window(self, action):
        window_id = action.text()
        plot_window = PlotWidget.plot_windows.get(window_id)
        if plot_window is None:
            self.plot()
            return
        selected_indexes = self.selectedIndexes()
        hints = PivotTablePlottingHints()
        try:
            plot_selection(self.model(), selected_indexes, hints, plot_window)
            plot_window.raise_()
        except PlottingError as error:
            report_plotting_failure(error, self)
コード例 #5
0
class PivotTableHeaderView(QHeaderView):

    header_dropped = Signal(object, object)

    def __init__(self, orientation, area, pivot_table_view):
        super().__init__(orientation, parent=pivot_table_view)
        self._area = area
        self._proxy_model = pivot_table_view.model()
        self._model_index = None
        self._menu = QMenu(self)
        self._plot_action = self._menu.addAction("Plot single column",
                                                 self._plot_column)
        self._add_to_plot_menu = self._menu.addMenu("Plot in window")
        self._add_to_plot_menu.triggered.connect(self._add_column_to_plot)
        self._set_as_x_action = self._menu.addAction("Use as X",
                                                     self._set_x_flag)
        self._set_as_x_action.setCheckable(True)
        self.setAcceptDrops(True)
        self.setStyleSheet("QHeaderView::section {background-color: " +
                           PIVOT_TABLE_HEADER_COLOR + ";}")

    @property
    def area(self):
        return self._area

    def dragEnterEvent(self, event):
        if isinstance(event.source(), TabularViewHeaderWidget):
            event.accept()

    def dragMoveEvent(self, event):
        if isinstance(event.source(), TabularViewHeaderWidget):
            event.accept()

    def dropEvent(self, event):
        self.header_dropped.emit(event.source(), self)

    def contextMenuEvent(self, event):
        """Shows context menu.

        Args:
            event (QContextMenuEvent)
        """
        self._menu.move(event.globalPos())
        self._model_index = self.parent().indexAt(event.pos())
        source_index = self._proxy_model.mapToSource(self._model_index)
        if self._proxy_model.sourceModel().column_is_index_column(
                self._model_index.column()):
            self._plot_action.setEnabled(False)
            self._set_as_x_action.setEnabled(True)
            self._set_as_x_action.setChecked(source_index.column(
            ) == self._proxy_model.sourceModel().plot_x_column)
        elif self._model_index.column() < self._proxy_model.sourceModel(
        ).headerColumnCount():
            self._plot_action.setEnabled(False)
            self._set_as_x_action.setEnabled(False)
            self._set_as_x_action.setChecked(False)
        else:
            self._plot_action.setEnabled(True)
            self._set_as_x_action.setEnabled(True)
            self._set_as_x_action.setChecked(source_index.column(
            ) == self._proxy_model.sourceModel().plot_x_column)
        _prepare_plot_in_window_menu(self._add_to_plot_menu)
        self._menu.show()

    @Slot("QAction")
    def _add_column_to_plot(self, action):
        """Adds a single column to existing plot window."""
        window_id = action.text()
        plot_window = PlotWidget.plot_windows.get(window_id)
        if plot_window is None:
            self._plot_column()
            return
        try:
            support = PivotTablePlottingHints()
            plot_pivot_column(self._proxy_model, self._model_index.column(),
                              support, plot_window)
        except PlottingError as error:
            report_plotting_failure(error, self)

    @Slot()
    def _plot_column(self):
        """Plots a single column not the selection."""
        try:
            support = PivotTablePlottingHints()
            plot_window = plot_pivot_column(self._proxy_model,
                                            self._model_index.column(),
                                            support)
        except PlottingError as error:
            report_plotting_failure(error, self)
            return
        plot_window.use_as_window(
            self.parentWidget(),
            support.column_label(self._proxy_model,
                                 self._model_index.column()))
        plot_window.show()

    @Slot()
    def _set_x_flag(self):
        """Sets the X flag for a column."""
        index = self._proxy_model.mapToSource(self._model_index)
        self._proxy_model.sourceModel().set_plot_x_column(
            index.column(), self._set_as_x_action.isChecked())
コード例 #6
0
class QPushColorButton(QPushButton):
    colorSelected = Signal(QColor)
    def __init__(self, parent=None, columns=int(0), rows=int(0), palette=list):
        super(QPushColorButton, self).__init__(parent, "")
        self.setMaximumWidth(25)
        self.setMaximumHeight(25)
        self.currentColor = QColor(255,255,255)
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.palette = palette
        self._columns = columns
        self._rows = rows

    def paintEvent(self,event):
        super(QPushColorButton, self).paintEvent(event)
        size = 13
        height = (self.height() - size)/2
        width = (self.width() - size)/2
        qp = QPainter(self)
        # qp.begin(self)
        qp.setPen(Qt.NoPen)
        qp.setBrush(self.currentColor)
        qp.drawRect(width, height, size, size)

    def color_menu(self, QPos=list):
        '''
        Show color menu.

        Parameters
        ----------
        QPos: (list)
            list of x and y location.
        '''
        self.mainMenu = QMenu()
        self.mainMenu.setStyleSheet("QMenu {background-color: #222222;}")
        colorAction = ColorAction(self.mainMenu, self._columns, self._rows, self.palette)
        colorAction.colorSelected.connect(self.handleColorSelected)
        self.mainMenu.addAction(colorAction)

        pos = self.mapToGlobal(QPoint(0,0))
        self.mainMenu.move(pos + QPos)
        self.mainMenu.show()

    def get_palette(self):
        return self.palette
    def set_palette(self, value=list):
        self.palette = value
    Palette= property(get_palette, set_palette)

    def get_columns(self):
        return self._columns
    def set_columns(self, value=int):
        self._columns = value
    Columns = property(get_columns,set_columns)

    def get_rows(self):
        return self._rows
    def set_rows(self, value=int):
        self._rows = value
    Rows = property(get_rows,set_rows)

    def handleColorSelected(self, color=QColor):
        self.currentColor = color
        self.colorSelected.emit(color)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.color_menu(event.pos())
        super(QPushColorButton, self).mousePressEvent(event)

    def get_current_color(self):
        return self.currentColor
    def set_current_color(self, color=QColor):
        self.currentColor = color
        self.update()
    CurrentColor = property(get_current_color,set_current_color)