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()
Exemple #2
0
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)
Exemple #3
0
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)
Exemple #4
0
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
Exemple #5
0
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
Exemple #8
0
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()
Exemple #9
0
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
Exemple #10
0
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()
Exemple #11
0
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)