class LastDocumentsDocker(krita.DockWidget): def __init__(self): super(LastDocumentsDocker, self).__init__() self.baseWidget = QWidget() self.layout = QVBoxLayout() self.listView = QListView() self.loadButton = QPushButton("Refresh") self.listModel = lastdocumentslistmodel.LastDocumentsListModel() self.listView.setModel(self.listModel) self.listView.setFlow(QListView.LeftToRight) self.layout.addWidget(self.listView) self.layout.addWidget(self.loadButton) self.baseWidget.setLayout(self.layout) self.setWidget(self.baseWidget) self.loadButton.clicked.connect(self.refreshRecentDocuments) self.setWindowTitle("Last Documents Docker") def canvasChanged(self, canvas): pass def refreshRecentDocuments(self): self.listModel.loadRecentDocuments()
class PangoFileWidget(PangoDockWidget): def __init__(self, title, parent=None): super().__init__(title, parent) self.setFixedWidth(160) self.file_model = QFileSystemModel() self.file_model.setFilter(QDir.Files | QDir.NoDotAndDotDot) self.file_model.setNameFilters(["*.jpg", "*.png"]) self.file_model.setNameFilterDisables(False) self.th_provider = ThumbnailProvider() self.file_model.setIconProvider(self.th_provider) self.file_view = QListView() self.file_view.setModel(self.file_model) self.file_view.setViewMode(QListView.IconMode) self.file_view.setFlow(QListView.LeftToRight) self.file_view.setIconSize(QSize(150, 150)) self.setWidget(self.file_view) def select_next_image(self): c_idx = self.file_view.currentIndex() idx = c_idx.siblingAtRow(c_idx.row()+1) if idx.row() != -1: self.file_view.setCurrentIndex(idx) def select_prev_image(self): c_idx = self.file_view.currentIndex() idx = c_idx.siblingAtRow(c_idx.row()-1) if idx.row() != -1: self.file_view.setCurrentIndex(idx)
class QuickAccessWidget(QFrame): def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.Box | QFrame.Sunken) self.setStyleSheet("QListView {background: transparent; }") self.setLayout(QHBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.listView = QListView(self) self.layout().addWidget(self.listView) self.listView.setModel(self.window().quickAccessModel) self.listView.setMovement(QListView.Snap) self.listView.setFlow(QListView.LeftToRight) self.listView.setResizeMode(QListView.Adjust) gridSize = self.logicalDpiX() / 96 * 60 self.listView.setGridSize(QSize(gridSize, gridSize)) self.listView.setViewMode(QListView.IconMode) self.listView.activated.connect(self.listView.model().runShortcut)
class LastDocumentsDocker(krita.DockWidget): def __init__(self): super(LastDocumentsDocker, self).__init__() self.baseWidget = QWidget() self.layout = QVBoxLayout() self.listView = QListView() self.listView.setFlow(QListView.LeftToRight) self.layout.addWidget(self.listView) self.baseWidget.setLayout(self.layout) self.setWidget(self.baseWidget) self.listView.setModel(lastdocumentslistmodel.LastDocumentsListModel()) self.setWindowTitle("Last Documents Docker") def canvasChanged(self, canvas): pass
class FontViewWidget(QWidget): def __init__(self, statusBar, config, *args, **kwargs): super(FontViewWidget, self).__init__(*args, **kwargs) self.statusBar = statusBar layout = QVBoxLayout(self) self.retButton = QToolButton(self) self.retButton.setIconSize(QSize(60, 60)) self.retButton.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) self.retButton.setMinimumSize(200, 100) self.retButton.setMaximumSize(200, 100) layout.addWidget(self.retButton) # 过滤输入框 layout.addWidget( QLineEdit(self, textChanged=self.doFilter, placeholderText='过滤...')) # Material Font self.listView = QListView(self) self.listView.setMouseTracking(True) self.listView.setViewMode(QListView.IconMode) self.listView.setMovement(QListView.Static) self.listView.setFlow(QListView.LeftToRight) self.listView.setWrapping(True) self.listView.setEditTriggers(QListView.NoEditTriggers) self.listView.setResizeMode(QListView.Adjust) self.listView.doubleClicked.connect(self.onDoubleClicked) self.listView.entered.connect(self.onEntered) self.dmodel = QStandardItemModel(self.listView) self.fmodel = QSortFilterProxyModel(self.listView) self.fmodel.setSourceModel(self.dmodel) self.fmodel.setFilterRole(Qt.ToolTipRole) self.listView.setModel(self.fmodel) layout.addWidget(self.listView) # 字体加载器 loader = config[0] # 添加Item fontMap = json.loads(open(config[1], 'rb').read().decode(encoding='utf_8', errors='ignore'), encoding='utf_8') for name, _ in fontMap.items(): item = QStandardItem(loader.icon(name), '') item.setData(name, Qt.ToolTipRole) item.setData(name, Qt.StatusTipRole) item.setTextAlignment(Qt.AlignCenter) item.setFlags(item.flags()) self.dmodel.appendRow(item) def doFilter(self, _): self.fmodel.setFilterRegExp(self.sender().text()) def onEntered(self, index): index = self.fmodel.mapToSource(index) text = index.data(Qt.ToolTipRole) if text: self.retButton.setText(text) self.retButton.setIcon(self.dmodel.itemFromIndex(index).icon()) def onDoubleClicked(self, index): index = self.fmodel.mapToSource(index) text = index.data(Qt.ToolTipRole) if text: QApplication.clipboard().setText(text) self.statusBar.showMessage('已复制: %s' % text)
class RequestsOperations(QWidget): def __init__(self, parent): super().__init__(parent) self.initUI() self.__ops = [] def initUI(self): self.layout = QFormLayout() self.layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) self.layout.setLabelAlignment(Qt.AlignLeft) self.layout.setFormAlignment(Qt.AlignLeft | Qt.AlignTop) twoListsOfSets = QWidget() twoListsOfSets.setLayout(QHBoxLayout()) twoListsOfSets.layout().setContentsMargins(5, 10, 5, 5) twoListsOfSets.layout().setSpacing(0) effect = QGraphicsDropShadowEffect() effect.setBlurRadius(10) effect.setColor(QColor(0, 0, 0, 160)) effect.setOffset(0.0) self.requestList = QListView() self.requestList.setSpacing(3) self.requestList.setAutoFillBackground(True) self.requestList.setGraphicsEffect(effect) self.requestList.setFrameStyle(QFrame.NoFrame) self.requestList.viewport().setAutoFillBackground(False) self.requestList.setFlow(QListView.LeftToRight) self.requestList.setWrapping(True) self.requestList.setResizeMode(QListView.Adjust) self.requestList.setUniformItemSizes(True) self.requestsModel = QStandardItemModel() self.requestList.setModel(self.requestsModel) effect = QGraphicsDropShadowEffect() effect.setBlurRadius(10) effect.setColor(QColor(0, 0, 0, 160)) effect.setOffset(0.0) self.requestList2 = QListView() self.requestList2.setSpacing(3) self.requestList2.setAutoFillBackground(True) self.requestList2.setGraphicsEffect(effect) self.requestList2.setFrameStyle(QFrame.NoFrame) self.requestList2.viewport().setAutoFillBackground(False) self.requestList2.setFlow(QListView.LeftToRight) self.requestList2.setWrapping(True) self.requestList2.setResizeMode(QListView.Adjust) self.requestList2.setUniformItemSizes(True) self.requestsModel2 = QStandardItemModel() self.requestList2.setModel(self.requestsModel2) twoListsOfSets.layout().addWidget(self.requestList) twoListsOfSets.layout().addWidget(self.requestList2) self.layout.addRow("SETS", twoListsOfSets) self.layout.addRow(HorizontalLine(self)) self.operationSelection = QGroupBox() self.operationSelection.setFlat(True) self.operationSelection.setLayout(QVBoxLayout()) self.buttonIntersection = QRadioButton("Intersection") self.operationSelection.layout().addWidget(self.buttonIntersection) self.buttonIntersection.clicked.connect( self.__disableSecondRequestList) self.buttonIntersection.click() self.buttonUnion = QRadioButton("Union") self.operationSelection.layout().addWidget(self.buttonUnion) self.buttonUnion.clicked.connect(self.__disableSecondRequestList) self.buttonDiff = QRadioButton("Difference") self.operationSelection.layout().addWidget(self.buttonDiff) self.buttonDiff.clicked.connect(self.__enableSecondRequestList) self.layout.addRow("OPERATION", self.operationSelection) self.buttonApplyWidget = QWidget() self.buttonApplyWidget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.buttonApplyLayout = QHBoxLayout() self.buttonApplyLayout.setContentsMargins(0, 0, 0, 0) self.buttonApplyWidget.setLayout(self.buttonApplyLayout) self.buttonApply = QPushButton("Apply") self.buttonApply.clicked.connect(self.__applyOp) self.operationSelection.layout().addWidget(self.buttonApply) self.buttonApplyLayout.addWidget(self.buttonApply, alignment=Qt.AlignRight) self.layout.addRow("", self.buttonApplyWidget) self.layout.addRow(HorizontalLine(self)) self.layout.addRow("RESULTS", None) self.resultingSets = QTableView() self.resultingSets.horizontalHeader().setSectionResizeMode( QHeaderView.Stretch) self.resultingSets.verticalHeader().setSectionResizeMode( QHeaderView.ResizeToContents) self.resultingSets.setModel(OperationsTableModel()) self.layout.addRow(self.resultingSets) self.layout.addRow(HorizontalLine(self)) self.outputSetSelection = QComboBox() self.outputSetSelection.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) self.layout.addRow("OUTPUT SET", self.outputSetSelection) self.setLayout(self.layout) def outputSet(self): return self.outputSetSelection.currentText() def setOutputSet(self, outputSetName): self.outputSetSelection.setCurrentText(outputSetName) @property def ops(self): return copy.deepcopy(self.__ops) def __applyOp(self): includedSets = [ self.requestsModel.item(i).text() for i in range(self.requestsModel.rowCount()) if self.requestsModel.item(i).data(Qt.CheckStateRole) == QVariant( Qt.Checked) ] if self.buttonUnion.isChecked(): if len(includedSets) > 1: opName = SetNameManagement.getUniqueSetName() self.addOp(OverpassUnion(opName), includedSets) logging.info("Union created.") else: logging.error("The union must have at least two sets.") elif self.buttonIntersection.isChecked(): if len(includedSets) > 1: opName = SetNameManagement.getUniqueSetName() self.addOp(OverpassIntersection(opName), includedSets) logging.info("Intersection created.") else: logging.error("The intersection must have at least two sets.") elif self.buttonDiff.isChecked(): excludedSets = [ self.requestsModel2.item(i).text() for i in range(self.requestsModel2.rowCount()) if self.requestsModel2.item(i).data(Qt.CheckStateRole) == QVariant(Qt.Checked) ] if len(includedSets) == 1 and len(excludedSets) > 0: opName = SetNameManagement.getUniqueSetName() self.addOp(OverpassDiff(includedSets[0], opName), excludedSets) logging.info("Difference created.") else: logging.error( "The difference must have only one set selected in the first list and at least one in the other." ) logging.debug("LINE") def addOp(self, op, sets=None): SetNameManagement.assign(op.name) self.__ops.append(op) if sets is not None: op.addSets(sets) self.resultingSets.model().addOp(op.name, op) self.addRequest(op.name) self.cleanRequestList() def __enableSecondRequestList(self): self.requestList2.show() def __disableSecondRequestList(self): self.requestList2.hide() def addRequest(self, name): self.requestsModel.beginInsertRows(QModelIndex(), self.requestsModel.rowCount(), self.requestsModel.rowCount()) item = QStandardItem(name) item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) self.requestsModel.appendRow(item) self.requestsModel.endInsertRows() self.requestsModel2.beginInsertRows(QModelIndex(), self.requestsModel2.rowCount(), self.requestsModel2.rowCount()) item = QStandardItem(name) item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) self.requestsModel2.appendRow(item) self.requestsModel2.endInsertRows() self.outputSetSelection.addItem(name) def removeSetAndDependencies(self, setName): removeList = [setName] for set in removeList: logging.info("Removing set '{}'.".format(set)) removeList.extend( [i for i in self.__removeSet(set) if i not in removeList]) logging.debug("LINE") def __removeSet(self, setName): dependencies = [] for op in self.__ops: op.removeSet(setName) if not op.isValid(): dependencies.append(op.name) for i in range(self.requestsModel.rowCount()): if self.requestsModel.item(i).text() == setName: self.requestsModel.beginRemoveRows(QModelIndex(), i, i) self.requestsModel.removeRow(i) self.requestsModel.endInsertRows() self.requestsModel2.beginRemoveRows(QModelIndex(), i, i) self.requestsModel2.removeRow(i) self.requestsModel2.endInsertRows() self.outputSetSelection.removeItem(i) break for op in self.__ops: if op.name == setName: self.resultingSets.model().removeOp(setName) self.__ops.remove(op) break SetNameManagement.releaseName(setName) return dependencies def reset(self): while len(self.ops) > 0: self.removeSetAndDependencies(self.ops[0].name) def cleanRequestList(self): for i in range(self.requestsModel.rowCount()): self.requestsModel.item(i).setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) self.requestsModel2.item(i).setData(QVariant(Qt.Unchecked), Qt.CheckStateRole) def keyPressEvent(self, event): if event.key() == Qt.Key_Backspace and self.resultingSets.hasFocus(): advice = "Are you sure?\nAll sets containing this one will be deleted if they are no longer valid" reply = QMessageBox.question(self, "Remove request operation", advice) if reply == QMessageBox.Yes: select = self.resultingSets.selectionModel() while len(select.selectedRows()) > 0: self.removeSetAndDependencies( self.resultingSets.model().getOpByIndex( select.selectedRows()[0].row())) event.accept()
class DisambiguationWidget(QWidget): def __init__(self, getRequestFunction, setFiltersFunction, parent=None): super().__init__(parent) self.getRequestFunction = getRequestFunction self.setFiltersFunction = setFiltersFunction # LAYOUT self.layout = QFormLayout() self.layout.setContentsMargins(10, 10, 10, 10) self.layout.setFieldGrowthPolicy(QFormLayout.ExpandingFieldsGrow) self.layout.setLabelAlignment(Qt.AlignLeft) self.layout.setFormAlignment(Qt.AlignLeft | Qt.AlignTop) # TYPE self.onlyDisconnectedCB = QCheckBox() self.onlyDisconnectedCB.setText("Only disconnected ways") self.columnSelection = QListView() self.columnSelection.setSpacing(3) self.columnSelection.setAutoFillBackground(True) self.columnSelection.setFrameStyle(QFrame.NoFrame) self.columnSelection.viewport().setAutoFillBackground(False) self.columnSelection.setFlow(QListView.LeftToRight) self.columnSelection.setWrapping(True) self.columnSelection.setResizeMode(QListView.Adjust) self.columnSelectionModel = QStandardItemModel() self.columnSelection.setModel(self.columnSelectionModel) self.applyButton = QPushButton("Apply") self.applyButton.clicked.connect(self.showTable) self.tableView = QTableView() self.tableView.doubleClicked.connect( lambda signal: self.setFiltersFunction( self.setSelection.currentText(), self.tableView.model().getDictDataFromCell(signal))) horizontalHeader = self.tableView.horizontalHeader() horizontalHeader.setSectionResizeMode(QHeaderView.ResizeToContents) horizontalHeader.setStretchLastSection(True) verticalHeader = self.tableView.verticalHeader() verticalHeader.sectionDoubleClicked.connect( lambda i: self.setFiltersFunction( self.setSelection.currentText(), self.tableView.model().getDictData(i))) self.tableView.setMinimumHeight(300) self.tableButtons = QWidget() tableButtonsLayout = QHBoxLayout() tableButtonsLayout.setAlignment(Qt.AlignRight) self.tableButtons.setLayout(tableButtonsLayout) tableButtonsLayout.setSpacing(0) tableButtonsLayout.setContentsMargins(0, 0, 0, 0) buttonMore = IconButton( QIcon(os.path.join(picturesDir, "showMore.png")), self.tableButtons.windowHandle(), self.tableButtons.height()) buttonMore.setToolTip("Show more") buttonMore.setFlat(True) buttonMore.clicked.connect(self.showMore) tableButtonsLayout.addWidget(buttonMore) buttonLess = IconButton( QIcon(os.path.join(picturesDir, "showLess.png")), self.tableButtons.windowHandle(), self.tableButtons.height()) buttonLess.setToolTip("Show less") buttonLess.setFlat(True) buttonLess.clicked.connect(self.showLess) tableButtonsLayout.addWidget(buttonLess) self.setSelection = QComboBox() self.setSelection.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.layout.addRow("SET", self.setSelection) self.layout.addRow("TYPE", self.onlyDisconnectedCB) self.layout.addRow("KEYS", self.columnSelection) self.layout.addRow(self.applyButton) self.layout.addRow(self.tableView) self.layout.addRow(self.tableButtons) self.setLayout(self.layout) def showMore(self): if self.tableView.model() is not None: self.tableView.model().showMore() def showLess(self): if self.tableView.model() is not None: self.tableView.model().showLess() def addFilterFromCell(self, signal): key = self.tableView.model().headerData(signal.column(), Qt.Horizontal, Qt.DisplayRole) value = self.tableView.model().itemData(signal).get(0) return self.setFiltersFunction( self.setSelection.currentText(), ([OverpassFilter(key, TagComparison.EQUAL, value, False, True) ], [])) def showTable(self): request = self.getRequestFunction(self.setSelection.currentText()) if request is not None: query = OverpassQuery(request.name) query.addRequest(request) try: writeXMLResponse(query.getQL(), tableDir) except OverpassRequestException as e: logging.error(str(e)) return except OSError: logging.error( "There was a problem creating the file with the request response." ) return except RuntimeError as e: logging.error(str(e)) return except Exception: logging.error(traceback.format_exc()) return jsonResponse = ox.overpass_json_from_file(tableDir) if len(jsonResponse["elements"]) == 0: logging.warning("There are no elements to show in the table.") logging.debug("LINE") else: self.disconnectedWaysTable = DisconnectedWaysTable( jsonResponse) self.similarWaysTable = SimilarWaysTable(jsonResponse) self.showHideOnlyDisconnected() self.columnSelectionModel.clear() for key in self.similarWaysTable.getAllColumns(): self.columnSelectionModel.beginInsertRows( QModelIndex(), self.columnSelectionModel.rowCount(), self.columnSelectionModel.rowCount()) item = QStandardItem(key) self.columnSelectionModel.itemChanged.connect( self.updateColumns) item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) item.setData( QVariant(Qt.Checked if key in self.similarWaysTable. getSelectedColumns() else Qt.Unchecked), Qt.CheckStateRole) self.columnSelectionModel.appendRow(item) self.columnSelectionModel.endInsertRows() self.disconnectedWaysTable.updateColumns( self.similarWaysTable.getSelectedColumns()) self.onlyDisconnectedCB.stateChanged.connect( self.showHideOnlyDisconnected) logging.info("Showing table.") logging.debug("LINE") else: logging.warning( "There is no requests. It is not possible to show the table.") def updateColumns(self): self.disconnectedWaysTable.updateColumns(self.getSelectedKeys()) self.similarWaysTable.updateColumns(self.getSelectedKeys()) def getSelectedKeys(self): return [ self.columnSelectionModel.item(i).text() for i in range(self.columnSelectionModel.rowCount()) if self.columnSelectionModel.item(i).data(Qt.CheckStateRole) == QVariant(Qt.Checked) ] def getSelectedRowNetworkx(self): if self.tableView.model() is None: logging.warning("The table has not been created yet.") logging.debug("LINE") else: indexes = self.tableView.selectionModel().selectedRows() return self.tableView.model().getRowJson(indexes) def getHtmlFromSelectedRow(self): selectedRows = self.getSelectedRowNetworkx() if selectedRows: return buildHTMLWithNetworkx(selectedRows) else: raise RuntimeError("No row is selected") def showHideOnlyDisconnected(self): if self.onlyDisconnectedCB.isChecked(): self.tableView.setModel(self.disconnectedWaysTable) else: self.tableView.setModel(self.similarWaysTable) def showTableSelection(self): try: self.changePage( buildHTMLWithNetworkx(self.getSelectedRowNetworkx())) except (OverpassRequestException, OsmnxException) as e: logging.error(str(e)) logging.warning( "Before open NETEDIT you must run a query with the row filters applied." ) except ox.EmptyOverpassResponse: logging.error("There are no elements with the given row.") except OSError: logging.error( "There was a problem creating the file with the row selection." ) except Exception: logging.error(traceback.format_exc()) logging.debug("LINE") def addSet(self, setName): self.applyButton.setEnabled(True) self.setSelection.addItem(setName) def removeSet(self, setName): for i in range(self.setSelection.count()): if self.setSelection.itemText(i) == setName: self.setSelection.removeItem(i) break
class ConversationView(QFrame): """ View Displays an active conversation, including all previous messages and a text field for sending new messages to the recipient """ def __init__(self, parent: Optional[QWidget], client: Client, peer: Peer, friends_list: PeerList, conversation_list: PeerList): super().__init__(parent) self.setObjectName("conversation_view") self._peer = peer self._client = client self._friends_list = friends_list self._conversation_list = conversation_list self._conversation_model = self._client.conversation(self._peer) # Model containing messages self._layout_manager = QVBoxLayout(self) # Configure message list self._message_list = QListView() # View used to display conversation messages (the model) self._message_list.setWordWrap(True) self._message_list.setModel(self._conversation_model) # Set up custom delegate message_delegate = MessageItemDelegate(self._message_list) self._message_list.setItemDelegate(message_delegate) self._send_view = MessageSendView(self, self._conversation_model.peer().username() if self._conversation_model else None) self.setup_ui() def setup_ui(self): """ Builds UI for display """ self._layout_manager.setContentsMargins(0, 0, 0, 0) self._send_view.setContentsMargins(0, 0, 0, 0) self._message_list.setModel(self._conversation_model) # Connect model self._message_list.setLayoutMode(QListView.Batched) # Display as needed self._message_list.setBatchSize(10) # Number of messages to display self._message_list.setFlow(QListView.TopToBottom) # Display vertically self._message_list.setResizeMode(QListView.Adjust) # Items laid out every time view is resized # Layout widgets and views # self._layout_manager.addWidget(header) self._layout_manager.addWidget(self._message_list, 1) self._layout_manager.addWidget(self._send_view) # Connect to signals self._send_view.text_edit().keyPressEvent = self.send_view_did_change self._message_list.verticalScrollBar().rangeChanged.connect(self.scroll_to_message) # Listeners def send_view_did_change(self, event: QKeyEvent): """ As QPlainTextEdit doesn't natively support enter key response, this function prevents the user from typing the 'enter' key and sends a message on its press instead :param event: QKeyEvent raised by key press """ text_field = self._send_view.text_edit() if event.key() == Qt.Key_Return: message: str = text_field.toPlainText() if not message: # Don't want to allow sending of empty messages return # Clear message send view self._send_view.text_edit().clear() # Create message chat_msg = ChatMessage(message) # Send over network to peer self._client.send_chat(self._peer, chat_msg) else: QPlainTextEdit.keyPressEvent(text_field, event) def peer(self): """ Getter :return: this conversation's peer """ return self._peer @QtCore.pyqtSlot() def scroll_to_message(self): """ Event Listener connected to QListView's vertical scroll bar's range change Scrolls to a new message when view reflects a new message in the model """ self._message_list.scrollToBottom()
class PeerListView(QFrame): """" Abstract class, sets forth a basic list for viewing peers """ def __init__(self, parent: Optional[QWidget], search_placeholder: str, is_stateless: bool): super().__init__(parent) self.setProperty("class", "friends_list") self._layout_manager = QVBoxLayout(self) self._header_manager = QHBoxLayout() # Set up search bar self._search_bar = QLineEdit() self._search_bar.setPlaceholderText(search_placeholder) # Set up model self._peer_model = PeerList(self, is_stateless) self._peer_list_view = QListView(self) self._peer_list_view.setModel(self._peer_model) self._peer_list_view.setContextMenuPolicy(Qt.CustomContextMenu) # Connect events self._search_bar.returnPressed.connect(self._search_initiated) self._setup_ui() @QtCore.pyqtSlot() def _search_initiated(self): """ Slot connected to returnPressed signal, initiates a search """ print("Search!") def _setup_ui(self): """ Establishes UI for display """ # Set minimum width of search bar to length of placeholder text font_metrics = QFontMetrics(self._search_bar.font()) txt_width = font_metrics.width(self._search_bar.placeholderText()) self._search_bar.minimumSizeHint = QSize(txt_width, -1) self._search_bar.setFixedHeight(30) self._peer_list_view.setLayoutMode(QListView.Batched) # Display as needed self._peer_list_view.setBatchSize(10) # Number of messages to display self._peer_list_view.setFlow(QListView.TopToBottom) # Display vertically self._peer_list_view.setResizeMode(QListView.Adjust) # Items laid out every time view is resized # Set up header self._header_manager.addWidget(self._search_bar, 1) # Layout widgets self._layout_manager.addLayout(self._header_manager) self._layout_manager.addSpacing(10) self._layout_manager.addWidget(self._peer_list_view) self._layout_manager.setSpacing(0) def add_to_header(self, widget: QWidget): """ Adds the given widget to the header :param widget: Widget to be added """ self._header_manager.addSpacing(5) self._header_manager.addWidget(widget) def model(self) -> PeerList: """ :return: The peer list model """ return self._peer_model
class DesktopIconWidget(QFrame): def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.Box | QFrame.Sunken) self.setStyleSheet("QListView{background:transparent;}") self.listView = QListView(self) self.setLayout(QHBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.listView) self.listView.setContextMenuPolicy(Qt.CustomContextMenu) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listView.setMovement(QListView.Snap) self.listView.setFlow(QListView.LeftToRight) self.listView.setResizeMode(QListView.Adjust) self.listView.setGridSize(QSize(self.logicalDpiX() / 96 * 70, self.logicalDpiY() / 96 * 70)) self.listView.setViewMode(QListView.IconMode) self.quickDesktopModel = QuickDesktopModel(self.window().platform.databaseFile) self.listView.setModel(self.quickDesktopModel) self.createActions() self.makeConnections() def createActions(self): self.actionCreateComputer = QAction(self.tr("我的电脑(&C)"), self) self.actionCreateDocuments = QAction(self.tr("我的文档(&D)"), self) self.actionCreateMusic = QAction(self.tr("我的音乐(&M)"), self) self.actionCreatePictures = QAction(self.tr("我的图片(&P)"), self) self.actionCreateShortcut = QAction(self.tr("创建快捷方式(&C)"), self) self.actionCreateShortcut.setIcon(QIcon(":/images/new.png")) self.actionCreateBookmark = QAction(self.tr("创建网络链接(&B)"), self) self.actionCreateBookmark.setIcon(QIcon(":/images/insert-link.png")) self.actionRemoveShortcut = QAction(self.tr("删除快捷方式(&R)"), self) self.actionRemoveShortcut.setIcon(QIcon(":/images/delete.png")) self.actionRenameShortcut = QAction(self.tr("重命名(&N)"), self) self.actionRenameShortcut.setIcon(QIcon(":/images/edit-rename.png")) self.actionEditShortcut = QAction(self.tr("编辑快捷方式(&E)"), self) self.actionEditShortcut.setIcon(QIcon(":/images/edit.png")) def makeConnections(self): self.listView.customContextMenuRequested.connect(self.onQuickDesktopContextMenuRequest) self.listView.activated.connect(self.runQuickDesktopShortcut) self.actionCreateComputer.triggered.connect(self.createComputerShortcut) self.actionCreateDocuments.triggered.connect(self.createDocumentsShortcut) self.actionCreateMusic.triggered.connect(self.createMusicShortcut) self.actionCreatePictures.triggered.connect(self.createPicturesShortcut) self.actionCreateShortcut.triggered.connect(self.createShortcut) self.actionCreateBookmark.triggered.connect(self.createBookmark) self.actionEditShortcut.triggered.connect(self.editShortcut) self.actionRemoveShortcut.triggered.connect(self.removeShortcut) self.actionRenameShortcut.triggered.connect(self.renameShortcut) def onQuickDesktopContextMenuRequest(self, pos): index = self.listView.indexAt(pos) self.listView.setCurrentIndex(index) menu = QMenu() menu.addAction(self.actionCreateShortcut) menu.addAction(self.actionCreateBookmark) menu2 = menu.addMenu(self.tr("创建特殊快捷方式(&S)")) if os.name == "nt": menu2.addAction(self.actionCreateComputer) menu2.addAction(self.actionCreateDocuments) menu2.addAction(self.actionCreatePictures) menu2.addAction(self.actionCreateMusic) if index.isValid(): menu.addAction(self.actionRemoveShortcut) if not self.quickDesktopModel.isSpecialShortcut(index): menu.addAction(self.actionEditShortcut) menu.addAction(self.actionRenameShortcut) try: getattr(menu, "exec")(QCursor.pos()) except AttributeError: getattr(menu, "exec_")(QCursor.pos()) def createShortcut(self): d = ShortcutDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = d.getResult() shortcut["id"] = str(uuid.uuid4()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createBookmark(self): d = BookmarkDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = { "id": str(uuid.uuid4()), "icon": "", "openwith": "", "dir": "", } shortcut.update(d.getResult()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createComputerShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的电脑"), "path": COMPUTER_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createDocumentsShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的文档"), "path": DOCUMENTS_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createPicturesShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("图片收藏"), "path": PICTURES_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createMusicShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的音乐"), "path": MUSIC_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def renameShortcut(self): self.listView.edit(self.listView.currentIndex()) def removeShortcut(self): self.quickDesktopModel.removeShortcut(self.listView.currentIndex()) def editShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return shortcut = self.quickDesktopModel.shortcutAt(index) url = QUrl.fromUserInput(shortcut["path"]) if not url.isValid(): return if url.scheme() == "special": QMessageBox.information(self, self.tr("编辑快捷方式"), self.tr("不能编辑特殊图标。")) return elif url.scheme() == "file": d = ShortcutDialog(self) else: d = BookmarkDialog(self) if self.window().runDialog(d.edit, shortcut) == QDialog.Accepted: shortcut.update(d.getResult()) self.quickDesktopModel.updateShortcut(shortcut, index) d.deleteLater() def runQuickDesktopShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return if not self.quickDesktopModel.runShortcut(index): QMessageBox.information(self, self.tr("快捷面板"), \ self.tr("不能运行快捷方式。请检查文件是否存在或者程序是否正确。")) else: self.window().close()
class DesktopIconWidget(QFrame): def __init__(self, parent): QFrame.__init__(self, parent) self.setFrameStyle(QFrame.Box | QFrame.Sunken) self.setStyleSheet("QListView{background:transparent;}") self.listView = QListView(self) self.setLayout(QHBoxLayout()) self.layout().setContentsMargins(0, 0, 0, 0) self.layout().addWidget(self.listView) self.listView.setContextMenuPolicy(Qt.CustomContextMenu) self.listView.setEditTriggers(QAbstractItemView.NoEditTriggers) self.listView.setMovement(QListView.Snap) self.listView.setFlow(QListView.LeftToRight) self.listView.setResizeMode(QListView.Adjust) self.listView.setGridSize( QSize(self.logicalDpiX() / 96 * 70, self.logicalDpiY() / 96 * 70)) self.listView.setViewMode(QListView.IconMode) self.quickDesktopModel = QuickDesktopModel( self.window().platform.databaseFile) self.listView.setModel(self.quickDesktopModel) self.createActions() self.makeConnections() def createActions(self): self.actionCreateComputer = QAction(self.tr("我的电脑(&C)"), self) self.actionCreateDocuments = QAction(self.tr("我的文档(&D)"), self) self.actionCreateMusic = QAction(self.tr("我的音乐(&M)"), self) self.actionCreatePictures = QAction(self.tr("我的图片(&P)"), self) self.actionCreateShortcut = QAction(self.tr("创建快捷方式(&C)"), self) self.actionCreateShortcut.setIcon(QIcon(":/images/new.png")) self.actionCreateBookmark = QAction(self.tr("创建网络链接(&B)"), self) self.actionCreateBookmark.setIcon(QIcon(":/images/insert-link.png")) self.actionRemoveShortcut = QAction(self.tr("删除快捷方式(&R)"), self) self.actionRemoveShortcut.setIcon(QIcon(":/images/delete.png")) self.actionRenameShortcut = QAction(self.tr("重命名(&N)"), self) self.actionRenameShortcut.setIcon(QIcon(":/images/edit-rename.png")) self.actionEditShortcut = QAction(self.tr("编辑快捷方式(&E)"), self) self.actionEditShortcut.setIcon(QIcon(":/images/edit.png")) def makeConnections(self): self.listView.customContextMenuRequested.connect( self.onQuickDesktopContextMenuRequest) self.listView.activated.connect(self.runQuickDesktopShortcut) self.actionCreateComputer.triggered.connect( self.createComputerShortcut) self.actionCreateDocuments.triggered.connect( self.createDocumentsShortcut) self.actionCreateMusic.triggered.connect(self.createMusicShortcut) self.actionCreatePictures.triggered.connect( self.createPicturesShortcut) self.actionCreateShortcut.triggered.connect(self.createShortcut) self.actionCreateBookmark.triggered.connect(self.createBookmark) self.actionEditShortcut.triggered.connect(self.editShortcut) self.actionRemoveShortcut.triggered.connect(self.removeShortcut) self.actionRenameShortcut.triggered.connect(self.renameShortcut) def onQuickDesktopContextMenuRequest(self, pos): index = self.listView.indexAt(pos) self.listView.setCurrentIndex(index) menu = QMenu() menu.addAction(self.actionCreateShortcut) menu.addAction(self.actionCreateBookmark) menu2 = menu.addMenu(self.tr("创建特殊快捷方式(&S)")) if os.name == "nt": menu2.addAction(self.actionCreateComputer) menu2.addAction(self.actionCreateDocuments) menu2.addAction(self.actionCreatePictures) menu2.addAction(self.actionCreateMusic) if index.isValid(): menu.addAction(self.actionRemoveShortcut) if not self.quickDesktopModel.isSpecialShortcut(index): menu.addAction(self.actionEditShortcut) menu.addAction(self.actionRenameShortcut) try: getattr(menu, "exec")(QCursor.pos()) except AttributeError: getattr(menu, "exec_")(QCursor.pos()) def createShortcut(self): d = ShortcutDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = d.getResult() shortcut["id"] = str(uuid.uuid4()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createBookmark(self): d = BookmarkDialog(self) if self.window().runDialog(d.create) == QDialog.Accepted: shortcut = { "id": str(uuid.uuid4()), "icon": "", "openwith": "", "dir": "", } shortcut.update(d.getResult()) self.quickDesktopModel.addShortcut(shortcut) d.deleteLater() def createComputerShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的电脑"), "path": COMPUTER_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createDocumentsShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的文档"), "path": DOCUMENTS_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createPicturesShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("图片收藏"), "path": PICTURES_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def createMusicShortcut(self): shortcut = { "id": str(uuid.uuid4()), "name": self.tr("我的音乐"), "path": MUSIC_PATH, "icon": "", "dir": "", "openwith": "", } self.quickDesktopModel.addShortcut(shortcut) def renameShortcut(self): self.listView.edit(self.listView.currentIndex()) def removeShortcut(self): self.quickDesktopModel.removeShortcut(self.listView.currentIndex()) def editShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return shortcut = self.quickDesktopModel.shortcutAt(index) url = QUrl.fromUserInput(shortcut["path"]) if not url.isValid(): return if url.scheme() == "special": QMessageBox.information(self, self.tr("编辑快捷方式"), self.tr("不能编辑特殊图标。")) return elif url.scheme() == "file": d = ShortcutDialog(self) else: d = BookmarkDialog(self) if self.window().runDialog(d.edit, shortcut) == QDialog.Accepted: shortcut.update(d.getResult()) self.quickDesktopModel.updateShortcut(shortcut, index) d.deleteLater() def runQuickDesktopShortcut(self): index = self.listView.currentIndex() if not index.isValid(): return if not self.quickDesktopModel.runShortcut(index): QMessageBox.information(self, self.tr("快捷面板"), \ self.tr("不能运行快捷方式。请检查文件是否存在或者程序是否正确。")) else: self.window().close()
class PlaylistView(QFrame): """ Horizontal Scroll Area containing playlists that can be selected """ # Signals should_display_playlist = pyqtSignal( int) # Display playlist given playlist_id def __init__(self, parent: QObject, image_cache: ImageCache): super().__init__(parent) self.__item_delegate = PlaylistDelegate(self) self.__model = PlaylistModel(self, image_cache) self.__horizontal_list = QListView(self) self.__horizontal_list.setModel(self.__model) self.__horizontal_list.setItemDelegate(self.__item_delegate) self.__horizontal_list.verticalScrollBar().setEnabled(False) self.__horizontal_list.setContextMenuPolicy(Qt.CustomContextMenu) self.__layout_manager = QVBoxLayout(self) self.__layout_ui() # Connect signals to slots self.__horizontal_list.doubleClicked.connect( self.__playlist_double_clicked) self.__horizontal_list.customContextMenuRequested.connect( self.__show_context_menu) def __layout_ui(self): # Set up horizontal list self.__horizontal_list.setFlow(QListView.LeftToRight) self.__horizontal_list.setMinimumHeight(235) self.__horizontal_list.setSpacing(20) self.__layout_manager.addWidget(self.__horizontal_list) def model(self) -> PlaylistModel: return self.__model @QtCore.pyqtSlot(QModelIndex) def __playlist_double_clicked(self, index: QModelIndex): """ Slot that connects to the doubleClicked signal Should either display contents of the playlist or allow for playlist creation (index dependent) :index: Index that was clicked """ should_create_playlist = (index.row() != self.__model.rowCount() - 1) if should_create_playlist: # Didn't click last index (create playlist), should display contents self.should_display_playlist.emit( self.__model.at(index.row()).playlist_id) else: self.__model.create_new_playlist() @QtCore.pyqtSlot(QModelIndex) def __handle_playlist_rename(self, index: QModelIndex): """ Allows the user to rename the playlist at index """ playlist = self.__model.at(index.row()) rename_dialog = RenamePlaylistDialog(self, playlist) if rename_dialog.exec() == QDialog.Accepted: # Rename successfully requested new_playlist_name = rename_dialog.get_new_name() rename_playlist(cursor, connection, playlist.playlist_id, new_playlist_name) self.relayout() @QtCore.pyqtSlot(QPoint) def __show_context_menu(self, pos: QPoint): """ Displays a context menu of user choices on a right-click :param pos: Location where user clicked on the screen """ index = self.__horizontal_list.indexAt(pos) if index.row() != -1 and index.row() != self.__model.rowCount( ) - 1: # Must be a valid index and not create global_pos = self.__horizontal_list.mapToGlobal(pos) context_menu = QMenu(self) show_action = QAction("Show Playlist") show_action.triggered.connect( lambda: self.__playlist_double_clicked(index)) rename_action = QAction("Rename Playlist") rename_action.triggered.connect( lambda: self.__handle_playlist_rename(index)) del_action = QAction("Delete Playlist") del_action.triggered.connect( lambda: self.__horizontal_list.model().delete_playlist(index)) context_menu.addAction(show_action) context_menu.addSeparator() context_menu.addAction(rename_action) context_menu.addAction(del_action) context_menu.exec(global_pos) del context_menu def relayout(self): """ Refreshes the UI to reflect the state of the DB """ playlists = get_all_user_playlists(cursor) self.__model.update_playlist(playlists)