def test_styles(mocker, main_window):
    wrapper = main_window.main_view.view_layout.itemAt(0).widget()
    conversation_scrollarea = wrapper.conversation_view.scroll
    file_widget = conversation_scrollarea.widget().layout().itemAt(0).widget()
    download_button = file_widget.download_button

    expected_image = load_icon("download_file.svg").pixmap(20, 20).toImage()
    assert download_button.icon().pixmap(20, 20).toImage() == expected_image
    assert "Source Sans Pro" == download_button.font().family()
    assert QFont.Bold == download_button.font().weight()
    assert 13 == download_button.font().pixelSize()
    assert "#2a319d" == download_button.palette().color(QPalette.Foreground).name()
    # assert 'border: none;' for download_button

    file_widget.eventFilter(download_button, QEvent(QEvent.HoverEnter))
    expected_image = load_icon("download_file_hover.svg").pixmap(20, 20).toImage()
    assert download_button.icon().pixmap(20, 20).toImage() == expected_image
    # assert '#05a6fe' == download_button.palette().color(QPalette.Foreground).name()

    file_widget.eventFilter(download_button, QEvent(QEvent.HoverLeave))
    expected_image = load_icon("download_file.svg").pixmap(20, 20).toImage()
    assert download_button.icon().pixmap(20, 20).toImage() == expected_image
    assert "#2a319d" == download_button.palette().color(QPalette.Foreground).name()
示例#2
0
def start_app(args, qt_args) -> None:
    """
    Create all the top-level assets for the application, set things up and
    run the application. Specific tasks include:

    - set up locale and language.
    - set up logging.
    - create an application object.
    - create a window for the app.
    - create an API connection to the SecureDrop proxy.
    - create a SqlAlchemy session to local storage.
    - configure the client (logic) object.
    - ensure the application is setup in the default safe starting state.
    """
    configure_locale_and_language()
    init(args.sdc_home)
    configure_logging(args.sdc_home)
    logging.info('Starting SecureDrop Client {}'.format(__version__))

    app = QApplication(qt_args)
    app.setApplicationName('SecureDrop Client')
    app.setDesktopFileName('org.freedomofthepress.securedrop.client')
    app.setApplicationVersion(__version__)
    app.setAttribute(Qt.AA_UseHighDpiPixmaps)

    load_font('Montserrat')
    load_font('Source_Sans_Pro')

    prevent_second_instance(app, args.sdc_home)

    session_maker = make_session_maker(args.sdc_home)

    gui = Window()

    app.setWindowIcon(load_icon(gui.icon))
    app.setStyleSheet(load_css('sdclient.css'))

    controller = Controller("http://localhost:8081/", gui, session_maker,
                            args.sdc_home, not args.no_proxy,
                            not args.no_qubes)
    controller.setup()

    configure_signal_handlers(app)
    timer = QTimer()
    timer.start(500)
    timer.timeout.connect(lambda: None)

    sys.exit(app.exec_())
示例#3
0
def test_init():
    """
    Ensure the Window instance is setup in the expected manner.
    """
    mock_li = mock.MagicMock(return_value=load_icon('icon.png'))
    mock_lo = mock.MagicMock(return_value=QVBoxLayout())
    mock_lo().addWidget = mock.MagicMock()
    with mock.patch('securedrop_client.gui.main.load_icon', mock_li), \
            mock.patch('securedrop_client.gui.main.ToolBar') as mock_tb, \
            mock.patch('securedrop_client.gui.main.MainView') as mock_mv, \
            mock.patch('securedrop_client.gui.main.QVBoxLayout', mock_lo), \
            mock.patch('securedrop_client.gui.main.QMainWindow') as mock_qmw:
        w = Window()
        mock_li.assert_called_once_with(w.icon)
        mock_tb.assert_called_once_with(w.widget)
        mock_mv.assert_called_once_with(w.widget)
        assert mock_lo().addWidget.call_count == 2
示例#4
0
    def __init__(self, on: str, off: str, svg_size: str = None):
        super().__init__()

        # Set layout
        layout = QHBoxLayout(self)
        self.setLayout(layout)

        # Remove margins and spacing
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        # Add SVG icon and set its size
        self.icon = load_icon(normal=on, normal_off=off)
        self.setIcon(self.icon)
        self.setIconSize(svg_size) if svg_size else self.setIconSize(QSize())

        # Make this a toggle button
        self.setCheckable(True)
示例#5
0
def test_init(mocker):
    """
    Ensure the Window instance is setup in the expected manner.
    """
    mock_li = mocker.MagicMock(return_value=load_icon('icon.png'))
    mock_lo = mocker.MagicMock(return_value=QHBoxLayout())
    mock_lo().addWidget = mocker.MagicMock()
    mocker.patch('securedrop_client.gui.main.load_icon', mock_li)
    mock_lp = mocker.patch('securedrop_client.gui.main.LeftPane')
    mock_mv = mocker.patch('securedrop_client.gui.main.MainView')
    mocker.patch('securedrop_client.gui.main.QHBoxLayout', mock_lo)
    mocker.patch('securedrop_client.gui.main.QMainWindow')

    w = Window()

    mock_li.assert_called_once_with(w.icon)
    mock_lp.assert_called_once_with()
    mock_mv.assert_called_once_with(w.main_pane)
    assert mock_lo().addWidget.call_count == 2
示例#6
0
def run():
    """
    Create all the top-level assets for the application, set things up and
    run the application. Specific tasks include:

    - set up logging.
    - create an application object.
    - create a window for the app.
    - create an API connection to the SecureDrop proxy.
    - create a SqlAlchemy session to local storage.
    - configure the client (logic) object.
    - ensure the application is setup in the default safe starting state.
    """
    configure_logging()
    logging.info('Starting SecureDrop Client {}'.format(__version__))

    app = QApplication(sys.argv)
    app.setApplicationName('SecureDrop Client')
    app.setDesktopFileName('org.freedomofthepress.securedrop.client')
    app.setApplicationVersion(__version__)
    app.setAttribute(Qt.AA_UseHighDpiPixmaps)

    gui = Window()
    app.setWindowIcon(load_icon(gui.icon))
    app.setStyleSheet(load_css('sdclient.css'))

    Session = sessionmaker(bind=engine)
    session = Session()

    client = Client("http://localhost:8081/", gui, session)
    client.setup()

    def signal_handler(*nargs) -> None:
        app.quit()

    for sig in [signal.SIGINT, signal.SIGTERM]:
        signal.signal(sig, signal_handler)
    timer = QTimer()
    timer.start(500)
    timer.timeout.connect(lambda: None)

    sys.exit(app.exec_())
示例#7
0
    def __init__(self) -> None:
        """
        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__()

        load_font("Montserrat")
        load_font("Source_Sans_Pro")
        self.setStyleSheet(load_css("sdclient.css"))
        self.setWindowTitle(_("SecureDrop Client {}").format(__version__))
        self.setWindowIcon(load_icon(self.icon))

        # Top Pane to display activity and error messages
        self.top_pane = TopPane()

        # Main Pane to display everything else
        self.main_pane = QWidget()
        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        self.main_pane.setLayout(layout)
        self.left_pane = LeftPane()
        self.main_view = MainView(self.main_pane)
        layout.addWidget(self.left_pane)
        layout.addWidget(self.main_view)

        # Set the main window's central widget to show Top Pane and Main Pane
        self.central_widget = QWidget()
        central_widget_layout = QVBoxLayout()
        central_widget_layout.setContentsMargins(0, 0, 0, 0)
        central_widget_layout.setSpacing(0)
        self.central_widget.setLayout(central_widget_layout)
        self.setCentralWidget(self.central_widget)
        central_widget_layout.addWidget(self.top_pane)
        central_widget_layout.addWidget(self.main_pane)
示例#8
0
    def __init__(
        self,
        normal: str,
        disabled: str = None,
        active: str = None,
        selected: str = None,
        svg_size: str = None,
    ) -> None:
        super().__init__()

        # Set layout
        layout = QHBoxLayout(self)
        self.setLayout(layout)

        # Remove margins and spacing
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        # Add SVG icon and set its size
        self.icon = load_icon(normal=normal, disabled=disabled, active=active, selected=selected)
        self.setIcon(self.icon)
        self.setIconSize(svg_size) if svg_size else self.setIconSize(QSize())
示例#9
0
def test_init(mocker):
    """
    Ensure the Window instance is setup in the expected manner.
    """
    mock_li = mocker.MagicMock(return_value=load_icon("icon.png"))
    mock_lo = mocker.MagicMock(return_value=QHBoxLayout())
    mock_lo().addWidget = mocker.MagicMock()
    mocker.patch("securedrop_client.gui.main.load_icon", mock_li)
    mock_lp = mocker.patch("securedrop_client.gui.main.LeftPane")
    mock_mv = mocker.patch("securedrop_client.gui.main.MainView")
    mocker.patch("securedrop_client.gui.main.QHBoxLayout", mock_lo)
    mocker.patch("securedrop_client.gui.main.QMainWindow")
    mocker.patch("securedrop_client.gui.main.Window.setStyleSheet")
    load_css = mocker.patch("securedrop_client.gui.main.load_css")

    w = Window()

    mock_li.assert_called_once_with(w.icon)
    mock_lp.assert_called_once_with()
    mock_mv.assert_called_once_with(w.main_pane)
    assert mock_lo().addWidget.call_count == 2
    load_css.assert_called_once_with("sdclient.css")
示例#10
0
    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()
示例#11
0
 def set_icon(self, on: str, off: str) -> None:
     self.icon = load_icon(normal=on, normal_off=off)
     self.setIcon(self.icon)