예제 #1
0
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
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 UI:
    """
    WSL2 端口自动转发
    """
    def __init__(self, qt_application=None):
        self.qt_application = qt_application
        # 实例化配置管理类
        self.settings_manage = SettingsManage()
        self.__setting = self.settings_manage.get()

        # 实例化windows命令处理类
        self.wsl2 = WinCmd()

        # 初始化启动脚本
        if not isfile(self.wsl2.WSL_VBS_PATH):
            copyfile(self.wsl2.WSL_VBS_PATH_TEMP, self.wsl2.WSL_VBS_PATH)
        if not isfile(self.wsl2.WSL_BAT_PATH):
            self.settings_manage.save_file_content(
                self.wsl2.WSL_BAT_PATH,
                self.__setting.get('wsl_bat_content', ''))
        # 加载UI文件
        self.ui = QUiLoader().load(ResourcePath.resource_path('lib/wsl2.ui'))

        # 设置界面图标
        app_icon = QIcon(ResourcePath.resource_path("lib/logo.ico"))
        self.ui.setWindowIcon(app_icon)

        # 设置选中状态
        self.ui.auto_start_wsl.setChecked(
            self.__setting.get('auto_start_wsl', False))
        self.ui.fire_wall_open.setChecked(
            self.__setting.get('fire_wall_open', False))
        self.ui.fire_wall_close.setChecked(
            self.__setting.get('fire_wall_close', False))

        # 设置文本框的值
        self.ui.port_text.appendPlainText('\n'.join(
            self.__setting.get('ports', [])))
        self.ui.bat_text.appendPlainText(self.wsl2.get_bat_script())

        # 按钮监听
        self.ui.get_wsl2_ip.clicked.connect(self.__get_wsl2_ip)
        self.ui.port_add.clicked.connect(self.__port_add)
        self.ui.port_del.clicked.connect(self.__port_del)
        self.ui.port_info.clicked.connect(self.__port_info)
        self.ui.wsl_l_v.clicked.connect(self.__wsl_l_v)
        self.ui.port_reset.clicked.connect(self.__port_reset)
        self.ui.end_wsl.clicked.connect(self.__end_wsl)
        self.ui.start_wsl.clicked.connect(self.__start_wsl)
        self.ui.start_wsl_all.clicked.connect(self.start_wsl_all)
        self.ui.save_settings.clicked.connect(self.__save_settings)
        self.ui.save_settings_ports.clicked.connect(self.__save_settings)

        # 设置系统托盘图标的菜单
        tp_icon = QIcon(ResourcePath.resource_path("lib/logo.ico"))
        self.tp = QSystemTrayIcon(self.ui)
        self.tp.setIcon(tp_icon)

        self.ui_hide = QAction(icon=tp_icon,
                               text='隐藏(Hide)',
                               triggered=self.ui.hide)
        self.ui_show = QAction(icon=tp_icon,
                               text='显示(Show)',
                               triggered=self.ui.show)
        self.ui_exit = QAction(icon=tp_icon,
                               text='退出(Exit)',
                               triggered=self.__quit_app)
        self.tp_menu = QMenu()
        self.tp_menu.addAction(self.ui_hide)
        self.tp_menu.addAction(self.ui_show)
        self.tp_menu.addAction(self.ui_exit)
        self.tp.setContextMenu(self.tp_menu)
        self.tp.activated.connect(self.__tp_connect_action)
        self.tp.show()
        self.tp.showMessage('WSL2AutoPortForward', 'WSL2端口自动转发工具已启动',
                            QSystemTrayIcon.MessageIcon.Information)

    def __tp_connect_action(self, activation_reason):
        """
        监听托盘图标点击
        :param activation_reason: 点击类型
        :return:
        """
        if activation_reason == QSystemTrayIcon.ActivationReason.Trigger:
            # 左单击
            if self.ui.isHidden():
                self.ui.show()
            else:
                self.ui.hide()
        elif activation_reason == QSystemTrayIcon.ActivationReason.Context:
            # 右单击
            self.tp_menu.show()
        elif activation_reason == QSystemTrayIcon.ActivationReason.DoubleClick:
            # 双击
            self.ui.show()

    def __quit_app(self):
        """
        退出APP
        :return:
        """
        re = QMessageBox.question(self.ui, "提示", "退出系统",
                                  QMessageBox.Yes | QMessageBox.No,
                                  QMessageBox.No)
        if re == QMessageBox.Yes:
            # 关闭窗体程序
            self.qt_application.quit()
            # 在应用程序全部关闭后,TrayIcon其实还不会自动消失,
            # 直到你的鼠标移动到上面去后,才会消失,
            # 这是个问题,(如同你terminate一些带TrayIcon的应用程序时出现的状况),
            # 这种问题的解决我是通过在程序退出前将其setVisible(False)来完成的。
            self.tp.setVisible(False)

    def __wsl_l_v(self):
        """
        获取wsl信息
        :return:
        """
        wsl_l_v_txt = '  ' + self.wsl2.wsl_l_v(exec_run=True).replace(
            '\x00', '').strip()
        if not wsl_l_v_txt:
            # 未查询到wsl信息提示
            wsl_l_v_txt = '未查询到wsl信息!'
            QMessageBox.information(self.ui, '系统提示', wsl_l_v_txt)
        self.ui.wsl_l_v_text.setPlainText(wsl_l_v_txt)

    def __get_wsl2_ip(self):
        wsl2_ip_info = self.wsl2.get_wsl2_ip()
        if not wsl2_ip_info:
            # 未查询到端口转发信息提示
            QMessageBox.information(self.ui, '系统提示', '未查询到IP信息!')
        else:
            wsl2_ip_info = 'WSL2当前IP为:' + wsl2_ip_info
            self.ui.wsl_l_v_text.setPlainText(wsl2_ip_info)

    def __port_add(self):
        wsl2_ip_info = self.wsl2.get_wsl2_ip()
        if not wsl2_ip_info:
            # 未查询到端口转发信息提示
            QMessageBox.information(self.ui, '系统提示', '未查询到IP信息!')
        else:
            self.ui.result_text.clear()
            ports = self.ui.port_text.toPlainText()
            port_str = ''
            for port in ports.splitlines():
                if not port.strip():
                    continue
                self.__port_add_one(port, wsl2_ip_info)
                port_str += (',' + port if port_str else port)
            self.__fire_wall_rule_add(port_str)
            self.ui.result_text.appendPlainText('Succeed!')

    def __port_del(self, del_port=True, del_fire=True):
        self.ui.result_text.clear()
        ports = self.ui.port_text.toPlainText()
        if del_port:
            for port in ports.splitlines():
                if not port.strip():
                    continue
                self.__port_del_one(port)
        if del_fire:
            self.__fire_wall_rule_del()
        self.ui.result_text.appendPlainText('Succeed!')

    def __port_reset(self):
        port_info = self.wsl2.port_info()
        self.ui.result_text.clear()
        for port in port_info:
            self.__port_del_one(port['port'])
        self.__fire_wall_rule_del()
        self.ui.result_text.appendPlainText('Succeed!')

    def __port_info(self):
        """
        获取端口转发信息
        :return:
        """
        info_str = self.wsl2.port_info(True).strip()
        if not info_str:
            # 未查询到端口转发信息提示
            info_str = '未查询到端口转发信息!'
            QMessageBox.information(self.ui, '系统提示', info_str)
        self.ui.result_text.setPlainText(info_str)

    def __wsl2_auto_port_forward(self):
        """
        一键自动转发
        @return:
        """

        self.__port_del(del_port=False, del_fire=True)
        self.__port_add()

    def __end_wsl(self):
        """
        停止wsl
        :return:
        """
        self.start_qt_process(self.wsl2.end_wsl(exec_run=False))
        info_str = 'wsl 已全部停止'
        QMessageBox.information(self.ui, '系统提示', info_str)

    def __start_wsl(self):
        """
        启动wsl
        :return:
        """
        self.start_qt_process(self.wsl2.start_wsl(exec_run=False))

    def start_wsl_all(self):
        """
        启动wsl并转发端口
        :return:
        """
        self.__start_wsl()
        self.__wsl2_auto_port_forward()

    def __save_settings(self):
        """
        保存全部配置
        :return:
        """
        # 保存脚本
        self.__save_bat_script()

        # 保存配置信息
        self.settings_manage.set('fire_wall_open',
                                 self.ui.fire_wall_open.isChecked())
        self.settings_manage.set('fire_wall_close',
                                 self.ui.fire_wall_close.isChecked())
        self.settings_manage.set('auto_start_wsl',
                                 self.ui.auto_start_wsl.isChecked())
        self.settings_manage.set('ports',
                                 self.ui.port_text.toPlainText().splitlines())

        # 保存成功提示
        QMessageBox.information(self.ui, '系统提示', '配置保存成功!')

    def __save_bat_script(self):
        """
        保存启动脚本
        :return:
        """
        content = self.ui.bat_text.toPlainText()
        self.settings_manage.set('wsl_bat_content', content)
        self.wsl2.save_bat_script(content)

    def __fire_wall_rule_add(self, port):
        """
        添加防火墙
        :param port: 端口号,多个端口逗号隔开
        :return:
        """
        if self.ui.fire_wall_open.isChecked():
            self.start_qt_process(
                self.wsl2.fire_wall_rule_add(
                    wsl_port=port,
                    wall_type=self.wsl2.FireWallRuleIn,
                    exec_run=False))
            self.ui.result_text.appendPlainText('>>> 添加防火墙:【' +
                                                self.wsl2.FireWallRuleIn +
                                                '】...')
            self.start_qt_process(
                self.wsl2.fire_wall_rule_add(
                    wsl_port=port,
                    wall_type=self.wsl2.FireWallRuleOut,
                    exec_run=False))
            self.ui.result_text.appendPlainText('>>> 添加防火墙:【' +
                                                self.wsl2.FireWallRuleOut +
                                                '】...')

    def __fire_wall_rule_del(self):
        """
        删除防火墙
        :return:
        """
        if self.ui.fire_wall_close.isChecked():
            self.start_qt_process(
                self.wsl2.fire_wall_rule_del(
                    wall_type=self.wsl2.FireWallRuleIn, exec_run=False))
            self.ui.result_text.appendPlainText('>>> 删除防火墙:【' +
                                                self.wsl2.FireWallRuleIn +
                                                '】...')
            self.start_qt_process(
                self.wsl2.fire_wall_rule_del(
                    wall_type=self.wsl2.FireWallRuleOut, exec_run=False))
            self.ui.result_text.appendPlainText('>>> 删除防火墙:【' +
                                                self.wsl2.FireWallRuleOut +
                                                '】...')

    def __port_add_one(self, port, wsl2_ip_info):
        """
        添加单个端口
        :param port: 端口号
        :param wsl2_ip_info: 转发的IP
        :return:
        """
        self.start_qt_process(
            self.wsl2.port_add(wsl_ip=wsl2_ip_info,
                               wsl_port=port,
                               exec_run=False))
        self.ui.result_text.appendPlainText('>>> 添加端口:【' + port + '】...')

    def __port_del_one(self, port):
        """
        删除单个端口
        :param port: 端口号
        :return:
        """
        self.start_qt_process(self.wsl2.port_del(wsl_port=port,
                                                 exec_run=False))
        self.ui.result_text.appendPlainText('>>> 删除端口:【' + port + '】...')

    def start_qt_process(self, cmd):
        """
        启动子进程执行耗时命令
        :param cmd:
        :return:
        """
        process = QProcess(self.ui)
        process.start(cmd)
        result = process.waitForStarted()
        return result
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)
예제 #6
0
class STATCardPanel(QWidget):
    def __init__(self, parent=None, cardList=None, cardlistcomboBox=None):
        super(STATCardPanel, self).__init__(parent)
        self.cardList = cardList
        self.cardlistcomboBox = cardlistcomboBox
        self.gridLayout = QGridLayout(self)

        self.nicknamelabel = QLabel(self)
        self.nicknamelabel.setText("卡片别名")

        self.nicknamelineedit = QLineEdit(self)

        self.cardtypelabel = QLabel(self)
        self.cardtypelabel.setText("卡片类型")

        self.cardtypecomboBox = cardCharacterComboBox(self)

        self.wishpanel = wishPanel()
        self.amuletpanel = amuletPanel()

        # gridLayout1__________________________

        self.gridLayout1 = QGridLayout()

        self.ADlabel = QLabel(self)
        self.ADlabel.setText("物攻")
        self.gridLayout1.addWidget(self.ADlabel, 0, 0, 1, 1)

        self.ADLineEdit = intLineEdit(self)
        self.gridLayout1.addWidget(self.ADLineEdit, 0, 1, 1, 1)

        self.APlabel = QLabel(self)
        self.APlabel.setText("魔攻")
        self.gridLayout1.addWidget(self.APlabel, 1, 0, 1, 1)

        self.APLineEdit = intLineEdit(self)
        self.gridLayout1.addWidget(self.APLineEdit, 1, 1, 1, 1)

        self.ADClabel = QLabel(self)
        self.ADClabel.setText("物穿")
        self.gridLayout1.addWidget(self.ADClabel, 2, 0, 1, 1)

        self.ADCLineEdit = intLineEdit(self)
        self.gridLayout1.addWidget(self.ADCLineEdit, 2, 1, 1, 1)

        self.ADCALineEdit = intLineEdit(self)
        self.gridLayout1.addWidget(self.ADCALineEdit, 2, 2, 1, 1)

        self.APClabel = QLabel(self)
        self.APClabel.setText("魔穿")
        self.gridLayout1.addWidget(self.APClabel, 3, 0, 1, 1)

        self.APCLineEdit = intLineEdit(self)
        self.gridLayout1.addWidget(self.APCLineEdit, 3, 1, 1, 1)

        self.APCALineEdit = intLineEdit(self)
        self.gridLayout1.addWidget(self.APCALineEdit, 3, 2, 1, 1)

        # gridLayout2__________________________

        self.gridLayout2 = QGridLayout()

        self.RTKlabel = QLabel(self)
        self.RTKlabel.setText("绝对攻击")
        self.gridLayout2.addWidget(self.RTKlabel, 0, 0, 1, 1)

        self.RTKLineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.RTKLineEdit, 0, 1, 1, 1)

        self.CRITClabel = QLabel(self)
        self.CRITClabel.setText("暴击穿透")
        self.gridLayout2.addWidget(self.CRITClabel, 1, 0, 1, 1)

        self.CRITCLineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.CRITCLineEdit, 1, 1, 1, 1)

        self.SPEEDlabel = QLabel(self)
        self.SPEEDlabel.setText("速度")
        self.gridLayout2.addWidget(self.SPEEDlabel, 2, 0, 1, 1)

        self.SPEEDLineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.SPEEDLineEdit, 2, 1, 1, 1)

        self.WDEFlabel = QLabel(self)
        self.WDEFlabel.setText("物防")
        self.gridLayout2.addWidget(self.WDEFlabel, 3, 0, 1, 1)

        self.WDEFLineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.WDEFLineEdit, 3, 1, 1, 1)

        self.WDEFALineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.WDEFALineEdit, 3, 2, 1, 1)

        self.MDEFlabel = QLabel(self)
        self.MDEFlabel.setText("魔防")
        self.gridLayout2.addWidget(self.MDEFlabel, 4, 0, 1, 1)

        self.MDEFLineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.MDEFLineEdit, 4, 1, 1, 1)

        self.MDEFALineEdit = intLineEdit(self)
        self.gridLayout2.addWidget(self.MDEFALineEdit, 4, 2, 1, 1)

        # gridLayout3__________________________

        self.gridLayout3 = QGridLayout()

        self.HEALTHlabel = QLabel(self)
        self.HEALTHlabel.setText("生命")
        self.gridLayout3.addWidget(self.HEALTHlabel, 0, 0, 1, 1)

        self.HEALTHLineEdit = intLineEdit(self)
        self.gridLayout3.addWidget(self.HEALTHLineEdit, 0, 1, 1, 1)

        self.RECOVERlabel = QLabel(self)
        self.RECOVERlabel.setText("回血")
        self.gridLayout3.addWidget(self.RECOVERlabel, 1, 0, 1, 1)

        self.RECOVERLineEdit = intLineEdit(self)
        self.gridLayout3.addWidget(self.RECOVERLineEdit, 1, 1, 1, 1)

        self.RECOVERALineEdit = intLineEdit(self)
        self.gridLayout3.addWidget(self.RECOVERALineEdit, 1, 2, 1, 1)

        self.SHIELDlabel = QLabel(self)
        self.SHIELDlabel.setText("护盾")
        self.gridLayout3.addWidget(self.SHIELDlabel, 2, 0, 1, 1)

        self.SHIELDLineEdit = intLineEdit(self)
        self.gridLayout3.addWidget(self.SHIELDLineEdit, 2, 1, 1, 1)

        self.SHIELDRECOVERlabel = QLabel(self)
        self.SHIELDRECOVERlabel.setText("回盾")
        self.gridLayout3.addWidget(self.SHIELDRECOVERlabel, 3, 0, 1, 1)

        self.SHIELDRECOVERLineEdit = intLineEdit(self)
        self.gridLayout3.addWidget(self.SHIELDRECOVERLineEdit, 3, 1, 1, 1)

        self.SHIELDRECOVERALineEdit = intLineEdit(self)
        self.gridLayout3.addWidget(self.SHIELDRECOVERALineEdit, 3, 2, 1, 1)

        # gridLayout4__________________________

        self.gridLayout4 = QGridLayout()

        self.CRITlabel = QLabel(self)
        self.CRITlabel.setText("暴击")
        self.gridLayout4.addWidget(self.CRITlabel, 0, 0, 1, 1)

        self.CRITLineEdit = intLineEdit(self)
        self.gridLayout4.addWidget(self.CRITLineEdit, 0, 1, 1, 1)

        self.SKILLlabel = QLabel(self)
        self.SKILLlabel.setText("技能")
        self.gridLayout4.addWidget(self.SKILLlabel, 1, 0, 1, 1)

        self.SKILLLineEdit = intLineEdit(self)
        self.gridLayout4.addWidget(self.SKILLLineEdit, 1, 1, 1, 1)

        self.REFLECTlabel = QLabel(self)
        self.REFLECTlabel.setText("反弹")
        self.gridLayout4.addWidget(self.REFLECTlabel, 2, 0, 1, 1)

        self.REFLECTLineEdit = intLineEdit(self)
        self.gridLayout4.addWidget(self.REFLECTLineEdit, 2, 1, 1, 1)

        self.VAMPIRElabel = QLabel(self)
        self.VAMPIRElabel.setText("吸血")
        self.gridLayout4.addWidget(self.VAMPIRElabel, 3, 0, 1, 1)

        self.VAMPIRELineEdit = intLineEdit(self)
        self.gridLayout4.addWidget(self.VAMPIRELineEdit, 3, 1, 1, 1)

        # gridLayout5__________________________

        self.gridLayout5 = QGridLayout()

        self.comboBoxList = []
        for i in range(5, len(all_skill["name"])):
            name = all_skill["name"][i]
            attr = all_skill["data"][i]
            if attr == "XUE":
                continue
            thisCombobox = STATSkillCheckBox(name, attr, self)
            self.comboBoxList.append(thisCombobox)

        thisCombobox = STATSkillCheckBox("荣誉之刃", "BLADE", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("刺杀弓", "ASSBOW", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("手环", "BRACELET", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("秃鹫手套", "VULTURE", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("发饰", "TIARA", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("幽梦匕首", "DAGGER", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("光辉法杖", "WAND", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("荆棘剑盾", "SHIELD", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("天使缎带", "RIBBON", self)
        self.comboBoxList.append(thisCombobox)
        thisCombobox = STATSkillCheckBox("陨铁重剑", "CLAYMORE", self)
        self.comboBoxList.append(thisCombobox)

        try:
            for i in range(5):
                for j in range(5):
                    self.gridLayout5.addWidget(self.comboBoxList[i * 5 + j], i, j, 1, 1)
        except:
            pass

        # gridLayout6__________________________

        self.gridLayout6 = QGridLayout()

        self.savepushButton = QPushButton()
        self.savepushButton.clicked.connect(self.saveMyCard)
        self.savepushButton.setText(u"保存卡片")
        self.gridLayout6.addWidget(self.savepushButton, 0, 0, 1, 1)

        self.editpushButton = QPushButton()
        self.editpushButton.clicked.connect(self.editMyCard)
        self.editpushButton.setText(u"修改卡片")
        self.gridLayout6.addWidget(self.editpushButton, 0, 1, 1, 1)

        self.deletepushButton = QPushButton()
        self.deletepushButton.clicked.connect(self.delMyCard)
        self.deletepushButton.setText(u"删除卡片")
        self.gridLayout6.addWidget(self.deletepushButton, 0, 2, 1, 1)

        # final

        self.rightMenuCreat()
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.rightMenuShow)

        self.gridLayout.addWidget(self.nicknamelabel, 0, 0, 1, 1)  # 卡片别名
        self.gridLayout.addWidget(self.nicknamelineedit, 0, 1, 1, 1)  # 卡片别名QLineEdit
        self.gridLayout.addWidget(self.cardtypelabel, 1, 0, 1, 1)  # 卡片类型
        self.gridLayout.addWidget(self.cardtypecomboBox, 1, 1, 1, 1)  # 卡片类型comboBox
        self.gridLayout.addWidget(self.wishpanel, 2, 0, 1, 1)
        self.gridLayout.addWidget(self.amuletpanel, 2, 1, 1, 1)
        self.gridLayout.addLayout(self.gridLayout1, 3, 0, 2, 1)  # 物攻
        self.gridLayout.addLayout(self.gridLayout2, 3, 1, 2, 1)  # 绝对攻击
        self.gridLayout.addLayout(self.gridLayout3, 5, 0, 2, 1)  # 生命
        self.gridLayout.addLayout(self.gridLayout4, 5, 1, 2, 1)  # 暴击
        self.gridLayout.addLayout(self.gridLayout5, 7, 0, 2, 2)  # 神秘
        self.gridLayout.addLayout(self.gridLayout6, 9, 0, 1, 2)  # 按钮

    def makeMyCard(self):
        nickname = self.nicknamelineedit.text()
        cardType = self.cardtypecomboBox.currentIndex()

        wishSet = WishSet(self.wishpanel.getWishLevelList())
        amuletclass = amuletClass(self.amuletpanel.getAmuletLevelList())

        attrs1 = []
        attrs1.append(self.ADLineEdit.getValue())
        attrs1.append(self.APLineEdit.getValue())
        attrs1.append(self.RTKLineEdit.getValue())
        attrs1.append(self.ADCLineEdit.getValue())
        attrs1.append(self.ADCALineEdit.getValue())
        attrs1.append(self.APCLineEdit.getValue())
        attrs1.append(self.APCALineEdit.getValue())
        attrs1.append(self.CRITCLineEdit.getValue())

        attrs2 = []
        attrs2.append(self.SPEEDLineEdit.getValue())
        attrs2.append(self.WDEFLineEdit.getValue())
        attrs2.append(self.WDEFALineEdit.getValue())
        attrs2.append(self.MDEFLineEdit.getValue())
        attrs2.append(self.MDEFALineEdit.getValue())

        attrs3 = []
        attrs3.append(self.HEALTHLineEdit.getValue())
        attrs3.append(self.RECOVERLineEdit.getValue())
        attrs3.append(self.RECOVERALineEdit.getValue())
        attrs3.append(self.SHIELDLineEdit.getValue())
        attrs3.append(self.SHIELDRECOVERLineEdit.getValue())
        attrs3.append(self.SHIELDRECOVERALineEdit.getValue())

        attrs4 = []
        attrs4.append(self.CRITLineEdit.getValue())
        attrs4.append(self.SKILLLineEdit.getValue())
        attrs4.append(self.REFLECTLineEdit.getValue())
        attrs4.append(self.VAMPIRELineEdit.getValue())

        attrs5 = [0]
        for i in self.comboBoxList:
            if i.isChecked():
                attrs5[0] += 1
                attrs5.append(i.currentValue())

        return STATCard(cardType, attrs1, attrs2, attrs3, attrs4, attrs5, nickname, wishSet, amuletclass)

    def ableCheck(self):
        return True, ""

    def saveMyCard(self):
        (result, message) = self.ableCheck()
        if not result:
            QMessageBox.critical(self, "错误", message, QMessageBox.Yes)
            return
        try:
            newCard = self.makeMyCard()
            text, ok = QInputDialog.getText(self, '设置卡片显示名', '输入名称:', text=newCard.tostring())
            if ok and text:
                if text in self.cardList.keys():
                    QMessageBox.critical(self, "错误", "保存失败,与已有配置重名", QMessageBox.Yes)
                    return
                self.cardList[text] = newCard
                self.cardlistcomboBox.setCurrentText(text)
        except Exception as err:
            print(err)
            QMessageBox.critical(self, "错误", err.__str__(), QMessageBox.Yes)

    def editMyCard(self):
        (result, message) = self.ableCheck()
        if not result:
            QMessageBox.critical(self, "错误", message, QMessageBox.Yes)
            return
        newCard = self.makeMyCard()
        # index = self.comboBox.currentIndex()
        text = self.cardlistcomboBox.currentText()
        if text == "":
            QMessageBox.critical(self, "错误", "修改失败,空名称", QMessageBox.Yes)
            return
        if text == "新卡片":
            QMessageBox.critical(self, "错误", "模板不可修改", QMessageBox.Yes)
            return
        yes = QMessageBox.question(self, "提问对话框", "确认修改?", QMessageBox.Yes | QMessageBox.No)
        if yes == QMessageBox.Yes:
            self.cardList[text] = newCard

    def delMyCard(self):
        text = self.cardlistcomboBox.currentText()
        if text == "新卡片":
            QMessageBox.critical(self, "错误", "模板不可删除", QMessageBox.Yes)
            return
        yes = QMessageBox.question(self, "提问对话框", "确认删除?", QMessageBox.Yes | QMessageBox.No)
        if yes == QMessageBox.Yes:
            del (self.cardList[text])

    def newMyCard(self):
        self.nicknamelineedit.setText("")
        self.cardtypecomboBox.setCurrentIndex(0)

        wishLevelList = [0, 0, 0, 0, 0, 0, 0]
        self.wishpanel.wishLevelList = wishLevelList
        self.amuletpanel.resetList()

        self.ADLineEdit.setText("")
        self.APLineEdit.setText("")
        self.RTKLineEdit.setText("")
        self.ADCLineEdit.setText("")
        self.ADCALineEdit.setText("")
        self.APCLineEdit.setText("")
        self.APCALineEdit.setText("")
        self.CRITCLineEdit.setText("")

        self.SPEEDLineEdit.setText("")
        self.WDEFLineEdit.setText("")
        self.WDEFALineEdit.setText("")
        self.MDEFLineEdit.setText("")
        self.MDEFALineEdit.setText("")

        self.HEALTHLineEdit.setText("")
        self.RECOVERLineEdit.setText("")
        self.RECOVERALineEdit.setText("")
        self.SHIELDLineEdit.setText("")
        self.SHIELDRECOVERLineEdit.setText("")
        self.SHIELDRECOVERALineEdit.setText("")

        self.CRITLineEdit.setText("")
        self.SKILLLineEdit.setText("")
        self.REFLECTLineEdit.setText("")
        self.VAMPIRELineEdit.setText("")

        for i in self.comboBoxList:
            i.setChecked(False)

    def setMyCard(self, card):
        cardtype = card.cardType
        attrs1 = card.attrs1
        attrs2 = card.attrs2
        attrs3 = card.attrs3
        attrs4 = card.attrs4
        attrs5 = card.attrs5
        if hasattr(card, "nickname"):
            nickname = card.nickname
            self.nicknamelineedit.setText(nickname)
        else:
            self.nicknamelineedit.setText("")

        self.cardtypecomboBox.setCurrentIndex(cardtype)

        if hasattr(card, "wishSet"):
            wishSet = card.wishSet
        else:
            wishSet = WishSet([0, 0, 0, 0, 0, 0, 0])

        if hasattr(card, "amuletclass"):
            amuletclass = card.amuletclass
        else:
            amuletclass = amuletClass([])

        self.wishpanel.wishLevelList = wishSet.getWishLevelList()
        self.amuletpanel.amuletLevelList = amuletclass.getAmuletLevelList()

        self.ADLineEdit.setText(attrs1[0])
        self.APLineEdit.setText(attrs1[1])
        self.RTKLineEdit.setText(attrs1[2])
        self.ADCLineEdit.setText(attrs1[3])
        self.ADCALineEdit.setText(attrs1[4])
        self.APCLineEdit.setText(attrs1[5])
        self.APCALineEdit.setText(attrs1[6])
        self.CRITCLineEdit.setText(attrs1[7])

        self.SPEEDLineEdit.setText(attrs2[0])
        self.WDEFLineEdit.setText(attrs2[1])
        self.WDEFALineEdit.setText(attrs2[2])
        self.MDEFLineEdit.setText(attrs2[3])
        self.MDEFALineEdit.setText(attrs2[4])

        self.HEALTHLineEdit.setText(attrs3[0])
        self.RECOVERLineEdit.setText(attrs3[1])
        self.RECOVERALineEdit.setText(attrs3[2])
        self.SHIELDLineEdit.setText(attrs3[3])
        self.SHIELDRECOVERLineEdit.setText(attrs3[4])
        self.SHIELDRECOVERALineEdit.setText(attrs3[5])

        self.CRITLineEdit.setText(attrs4[0])
        self.SKILLLineEdit.setText(attrs4[1])
        self.REFLECTLineEdit.setText(attrs4[2])
        self.VAMPIRELineEdit.setText(attrs4[3])

        for i in self.comboBoxList:
            if i.ATTR in attrs5:
                i.setChecked(True)
            else:
                i.setChecked(False)

    def rightMenuCreat(self):
        self.contextMenu = QMenu(self)
        self.cardImport = self.contextMenu.addAction(u'全部导入')
        self.cardImport.triggered.connect(lambda: self.cardImportFun())

        self.cardOutput = self.contextMenu.addAction(u'全部导出')
        self.cardOutput.triggered.connect(lambda: self.cardOutputFun())

    def rightMenuShow(self):
        self.contextMenu.popup(QCursor.pos())  # 2菜单显示的位置
        self.contextMenu.show()

    def wishImportFun(self, text=None):
        if text is None:
            text, ok = QInputDialog.getMultiLineText(self, '导入祝福', 'WISH 开头')
            if not (ok and text):
                return

        text = text.split(" ")
        if text[0] != "WISH":
            return
        else:
            wishLevelList = []
            for i in range(len(text) - 1):
                try:
                    wishLevelList.append(int(text[i + 1]))
                except:
                    pass
            self.wishpanel.wishLevelList = wishLevelList.copy()

    def amuletImportFun(self, text=None):
        if text is None:
            text, ok = QInputDialog.getMultiLineText(self, '导入护符', 'AMULET 开头,ENDAMULET结束')
            if not (ok and text):
                return

        text = text.split(" ")
        if text[0] != "AMULET":
            return
        else:
            amuletLevelList = [0] * len(all_amulet["data"])
            for i in range(1, len(text) - 2, 2):
                try:
                    name = text[i]
                    level = text[i + 1]
                    for j in range(len(all_amulet["data"])):
                        if all_amulet["data"][j] == name:
                            amuletLevelList[j] = int(level)
                except:
                    pass
            self.amuletpanel.amuletLevelList = amuletLevelList.copy()

    def cardImportFun(self, text=None):
        if text is None:
            text, ok = QInputDialog.getMultiLineText(self, '导入卡片', '计算器格式')
            if not (ok and text):
                return

        text = re.sub(r"\n\n", "\n", text)
        text = text.split("\n")

        attrs1 = text[0].split()
        if (len(attrs1) == 2):
            cardtype, nickname = attrs1[0].split("_")
            for i in range(len(all_character['data'])):
                if cardtype == all_character['data'][i]:
                    self.cardtypecomboBox.setCurrentIndex(i)
                    break
            self.nicknamelineedit.setText(nickname)
            text.pop(0)
            attrs1 = text[0].split()

        if attrs1[0] == "WISH":
            self.wishImportFun(text[0])
            text.pop(0)
            attrs1 = text[0].split()

        if attrs1[0] == "AMULET":
            self.amuletImportFun(text[0])
            text.pop(0)
            attrs1 = text[0].split()

        self.ADLineEdit.setText(attrs1[0])
        self.APLineEdit.setText(attrs1[1])
        self.RTKLineEdit.setText(attrs1[2])
        self.ADCLineEdit.setText(attrs1[3])
        self.ADCALineEdit.setText(attrs1[4])
        self.APCLineEdit.setText(attrs1[5])
        self.APCALineEdit.setText(attrs1[6])
        self.CRITCLineEdit.setText(attrs1[7])

        attrs2 = text[1].split()
        self.SPEEDLineEdit.setText(attrs2[0])
        self.WDEFLineEdit.setText(attrs2[1])
        self.WDEFALineEdit.setText(attrs2[2])
        self.MDEFLineEdit.setText(attrs2[3])
        self.MDEFALineEdit.setText(attrs2[4])

        attrs3 = text[2].split()
        self.HEALTHLineEdit.setText(attrs3[0])
        self.RECOVERLineEdit.setText(attrs3[1])
        self.RECOVERALineEdit.setText(attrs3[2])
        self.SHIELDLineEdit.setText(attrs3[3])
        self.SHIELDRECOVERLineEdit.setText(attrs3[4])
        self.SHIELDRECOVERALineEdit.setText(attrs3[5])

        attrs4 = text[3].split()
        self.CRITLineEdit.setText(attrs4[0])
        self.SKILLLineEdit.setText(attrs4[1])
        self.REFLECTLineEdit.setText(attrs4[2])
        self.VAMPIRELineEdit.setText(attrs4[3])

        others = text[4].split()
        for i in range(len(self.comboBoxList)):
            self.comboBoxList[i].setChecked(False)
            for j in range(1,len(others)):
                if others[j] == self.comboBoxList[i].ATTR:
                    self.comboBoxList[i].setChecked(True)

    def cardOutputFun(self, text=None):
        if not self.ableCheck():
            return

        thiscard = self.makeMyCard()
        thistext = thiscard.make_gu_text()
        QInputDialog.getMultiLineText(self, '请复制', "", thistext)
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())
예제 #8
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)