Exemple #1
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 #2
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