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())
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
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)
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)
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())
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)