示例#1
0
def test_MainView_show_conversation(mocker):
    """
    Ensure the passed-in widget is added to the layout of the main view holder
    (i.e. that area of the screen on the right hand side).
    """
    mv = MainView(None)
    mv.view_layout = mocker.MagicMock()

    mock_widget = mocker.MagicMock()
    mv.set_conversation(mock_widget)

    mv.view_layout.takeAt.assert_called_once_with(0)
    mv.view_layout.addWidget.assert_called_once_with(mock_widget)
示例#2
0
class Window(QMainWindow):
    """
    Represents the application's main window that will contain the UI widgets.
    All interactions with the UI go through the object created by this class.
    """

    icon = 'icon.png'

    def __init__(self, sdc_home: str):
        """
        Create the default start state. The window contains a root widget into
        which is placed:

        * A status bar widget at the top, containing curent user / status
          information.
        * A main-view widget, itself containing a list view for sources and a
          place for details / message contents / forms.
        """
        super().__init__()
        self.sdc_home = sdc_home
        self.setWindowTitle(_("SecureDrop Client {}").format(__version__))
        self.setWindowIcon(load_icon(self.icon))

        self.widget = QWidget()
        widget_layout = QVBoxLayout()
        self.widget.setLayout(widget_layout)
        self.setCentralWidget(self.widget)

        self.tool_bar = ToolBar(self.widget)

        self.main_view = MainView(self.widget)
        self.main_view.source_list.itemSelectionChanged.connect(
            self.on_source_changed)

        widget_layout.addWidget(self.tool_bar, 1)
        widget_layout.addWidget(self.main_view, 6)

        # Cache a dict of source.uuid -> SourceConversationWrapper
        # We do this to not create/destroy widgets constantly (because it causes UI "flicker")
        self.conversations = {}

        # Tracks which source is shown
        self.current_source = None

        self.autosize_window()
        self.show()

    def setup(self, controller):
        """
        Create references to the controller logic and instantiate the various
        views used in the UI.
        """
        self.controller = controller  # Reference the Client logic instance.
        self.tool_bar.setup(self, controller)

        self.status_bar = QStatusBar(self)
        self.setStatusBar(self.status_bar)
        self.set_status('Started SecureDrop Client. Please sign in.', 20000)

        self.login_dialog = LoginDialog(self)
        self.main_view.setup(self.controller)

    def autosize_window(self):
        """
        Ensure the application window takes up 100% of the available screen
        (i.e. the whole of the virtualised desktop in Qubes dom)
        """
        screen = QDesktopWidget().screenGeometry()
        self.resize(screen.width(), screen.height())

    def show_login(self):
        """
        Show the login form.
        """
        self.login_dialog = LoginDialog(self)
        self.login_dialog.setup(self.controller)
        self.login_dialog.reset()
        self.login_dialog.exec()

    def show_login_error(self, error):
        """
        Display an error in the login dialog.
        """
        if self.login_dialog and error:
            self.login_dialog.error(error)

    def hide_login(self):
        """
        Kill the login dialog.
        """
        self.login_dialog.accept()
        self.login_dialog = None

    def update_error_status(self, error=None):
        """
        Show an error message on the sidebar.
        """
        self.main_view.update_error_status(error)

    def show_sources(self, sources):
        """
        Update the left hand sources list in the UI with the passed in list of
        sources.
        """
        self.main_view.source_list.update(sources)

    def show_sync(self, updated_on):
        """
        Display a message indicating the data-sync state.
        """
        if updated_on:
            self.main_view.status.setText('Last refresh: ' +
                                          updated_on.humanize())
        else:
            self.main_view.status.setText(_('Waiting to refresh...'))

    def set_logged_in_as(self, username):
        """
        Update the UI to show user logged in with username.
        """
        self.tool_bar.set_logged_in_as(username)

    def logout(self):
        """
        Update the UI to show the user is logged out.
        """
        self.tool_bar.set_logged_out()

    def on_source_changed(self):
        """
        React to when the selected source has changed.
        """
        source_item = self.main_view.source_list.currentItem()
        source_widget = self.main_view.source_list.itemWidget(source_item)
        if source_widget:
            self.current_source = source_widget.source
            self.show_conversation_for(self.current_source)

    def show_conversation_for(self, source):
        """
        Show conversation of messages and replies between a source and
        journalists.
        """

        conversation_container = self.conversations.get(source.uuid, None)

        if conversation_container is None:
            conversation_container = SourceConversationWrapper(
                source, self.sdc_home, self.controller)
            self.conversations[source.uuid] = conversation_container

        self.main_view.set_conversation(conversation_container)

    def set_status(self, message, duration=5000):
        """
        Display a status message to the user. Optionally, supply a duration
        (in milliseconds), the default value being a duration of 5 seconds.
        """
        self.status_bar.showMessage(message, duration)