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()
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_())
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
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)
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
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_())
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)
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())
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")
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 set_icon(self, on: str, off: str) -> None: self.icon = load_icon(normal=on, normal_off=off) self.setIcon(self.icon)