grc: formatting for qt-gui

Signed-off-by: Jeff Long <willcode4@gmail.com>
This commit is contained in:
Jeff Long 2024-03-14 05:45:07 -04:00
parent 9d8e381ccc
commit 5b5234d519
25 changed files with 108 additions and 83 deletions

View File

@ -618,7 +618,6 @@ class Block(Element):
block_connections = block_connections + list(port.connections())
return block_connections
##############################################
# Access
##############################################

View File

@ -51,7 +51,7 @@ class Cache(object):
else:
if self.log:
logger.info(f"Outdated cache {self.cache_file} found, "
"will be overwritten.")
"will be overwritten.")
raise ValueError()
except (IOError, ValueError):
self.need_cache_write = True

View File

@ -16,4 +16,4 @@ class Config(CoreConfig):
@property
def wiki_block_docs_url_prefix(self):
return self._gr_prefs.get_string('grc-docs', 'wiki_block_docs_url_prefix', '')
return self._gr_prefs.get_string('grc-docs', 'wiki_block_docs_url_prefix', '')

View File

@ -1,4 +1,4 @@
#TODO: This file is a modified copy of the old gui/Platform.py
# TODO: This file is a modified copy of the old gui/Platform.py
"""
Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio

View File

@ -1,4 +1,4 @@
#TODO: This file is a modified copy of the old gui/Platform.py
# TODO: This file is a modified copy of the old gui/Platform.py
"""
Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio
@ -65,5 +65,5 @@ class Platform(CorePlatform):
port_classes = {key: Port.make_cls_with_base(cls)
for key, cls in CorePlatform.port_classes.items()}
#param_classes = {key: Param.make_cls_with_base(cls)
# param_classes = {key: Param.make_cls_with_base(cls)
# for key, cls in CorePlatform.param_classes.items()}

View File

@ -60,7 +60,7 @@ class Component(object):
log.debug("Connecting signals")
self.connectSlots()
### Properties
# Properties
@property
def app(self):
@ -74,7 +74,7 @@ class Component(object):
def platform(self):
return self._app().platform
### Required methods
# Required methods
@abc.abstractmethod
def createActions(self, actions):
@ -91,7 +91,7 @@ class Component(object):
''' Add toolbars to the component. '''
raise NotImplementedError()
### Base methods
# Base methods
def connectSlots(self, useToggled=True, toggledHandler='_toggled',
triggeredHandler="_triggered"):

View File

@ -113,7 +113,7 @@ class BlockLibrary(QDockWidget, base.Component):
self.resize(400, 300)
self.setFloating(False)
### GUI Widgets
# GUI Widgets
# Create the layout widget
container = QWidget(self)
@ -156,13 +156,13 @@ class BlockLibrary(QDockWidget, base.Component):
container.setLayout(layout)
self.setWidget(container)
### Translation support
# Translation support
# self.setWindowTitle(_translate("blockLibraryDock", "Library", None))
# library.headerItem().setText(0, _translate("blockLibraryDock", "Blocks", None))
# QMetaObject.connectSlotsByName(blockLibraryDock)
### Loading blocks
# Loading blocks
# Keep as a separate function so it can be called at a later point (Reloading blocks)
self._block_tree_flat = {}

View File

@ -68,6 +68,7 @@ class GUIBlock(QGraphicsItem):
"""
The graphical representation of a block. Accesses the actual block with self.core.
"""
def __init__(self, core, parent, **n):
super(GUIBlock, self).__init__()
self.core = core

View File

@ -1,4 +1,4 @@
#TODO: This file is a modified copy of the old gui/Platform.py
# TODO: This file is a modified copy of the old gui/Platform.py
"""
Copyright 2008,2013 Free Software Foundation, Inc.
This file is part of GNU Radio

View File

@ -15,6 +15,7 @@ class DummyConnection(QGraphicsPathItem):
Dummy connection used for when the user drags a connection
between two ports.
"""
def __init__(self, parent, start_point, end_point):
super(DummyConnection, self).__init__()
@ -113,8 +114,10 @@ class GUIConnection(QGraphicsPathItem):
self._arrowhead.clear()
self._arrowhead.moveTo(self.sink.gui.connection_point + QPointF(10.0, 0))
self._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0) + QPointF(-CONNECTOR_ARROW_HEIGHT, - CONNECTOR_ARROW_BASE / 2))
self._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0) + QPointF(-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE / 2))
self._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0) +
QPointF(-CONNECTOR_ARROW_HEIGHT, - CONNECTOR_ARROW_BASE / 2))
self._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0) +
QPointF(-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE / 2))
self._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0))
self._path.clear()

View File

@ -32,6 +32,7 @@ class GUIPort(QGraphicsItem):
Note that this constructor is called before its parent GUIBlock is instantiated,
which is why we call setParentItem() in create_shapes_and_labels().
"""
def __init__(self, core, direction, **n):
self.core = core
QGraphicsItem.__init__(self)
@ -80,7 +81,8 @@ class GUIPort(QGraphicsItem):
return QGraphicsItem.itemChange(self, change, value)
def create_shapes_and_labels(self):
self.auto_hide_port_labels = self.core.parent.parent.gui.app.qsettings.value('grc/auto_hide_port_labels', type=bool)
self.auto_hide_port_labels = self.core.parent.parent.gui.app.qsettings.value(
'grc/auto_hide_port_labels', type=bool)
if not self.parentItem():
self.setParentItem(self.core.parent_block.gui)
@ -125,7 +127,8 @@ class GUIPort(QGraphicsItem):
painter.setPen(QPen(1))
painter.setFont(self.font)
if self.core._dir == "sink":
painter.drawText(QRectF(-max(0, self.width - 15), 0, self.width, self.height), Qt.AlignCenter, self.core.name)
painter.drawText(QRectF(-max(0, self.width - 15), 0, self.width,
self.height), Qt.AlignCenter, self.core.name)
else:
painter.drawText(QRectF(0, 0, self.width, self.height), Qt.AlignCenter, self.core.name)

View File

@ -86,7 +86,7 @@ class Console(QtWidgets.QDockWidget, base.Component):
self.setWindowTitle('Console')
self.level = level
### GUI Widgets
# GUI Widgets
# Create the layout widget
container = QtWidgets.QWidget(self)
@ -114,13 +114,13 @@ class Console(QtWidgets.QDockWidget, base.Component):
container.setLayout(layout)
self.setWidget(container)
### Translation support
# Translation support
#self.setWindowTitle(_translate("", "Library", None))
#library.headerItem().setText(0, _translate("", "Blocks", None))
#QtCore.QMetaObject.connectSlotsByName(blockLibraryDock)
# QtCore.QMetaObject.connectSlotsByName(blockLibraryDock)
### Setup actions
# Setup actions
# TODO: Move to the base controller and set actions as class attributes
# Automatically create the actions, menus and toolbars.
@ -157,7 +157,7 @@ class Console(QtWidgets.QDockWidget, base.Component):
def enable(self):
self.enabled = True
### Actions
# Actions
def createActions(self, actions):
''' Defines all actions for this view. '''
@ -169,7 +169,8 @@ class Console(QtWidgets.QDockWidget, base.Component):
actions['clear'] = Action(Icons("document-close"), _("clear"), self, statusTip=_("clear-tooltip"))
actions['show_level'] = Action(_("show-level"), self, statusTip=_("show-level"), checkable=True, checked=True)
actions['auto_scroll'] = Action(_("auto-scroll"), self, statusTip=_("auto-scroll"), checkable=True, checked=True)
actions['auto_scroll'] = Action(
_("auto-scroll"), self, statusTip=_("auto-scroll"), checkable=True, checked=True)
def createMenus(self, actions, menus):
''' Setup the view's menus '''
@ -180,7 +181,7 @@ class Console(QtWidgets.QDockWidget, base.Component):
console_menu.setObjectName("console::menu")
# Not needed, we have FileHandler logging in main.py
#console_menu.addAction(actions["save"])
# console_menu.addAction(actions["save"])
console_menu.addAction(actions["clear"])
console_menu.addAction(actions["show_level"])

View File

@ -122,6 +122,7 @@ class PropsDialog(QDialog):
self.edit_params.append(line_edit)
elif param.dtype == "_multiline_python_external":
ext_param = copy(param)
def open_editor(widget=None):
self._block.parent_flowgraph.gui.install_external_editor(
ext_param)
@ -143,7 +144,7 @@ class PropsDialog(QDialog):
line_edit = QPlainTextEdit(param.value)
line_edit.param = param
qvb.addWidget(editor_widget, i, 1)
#self.edit_params.append(line_edit)
# self.edit_params.append(line_edit)
else:
line_edit = QLineEdit(param.value)
line_edit.param = param

View File

@ -26,6 +26,7 @@ class Worker(QRunnable):
"""
This is the Worker that will gather/parse examples as a background task
"""
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
@ -111,7 +112,7 @@ class ExampleBrowser(QWidget, base.Component):
def connect_dialog(self, dialog: QDialog):
if self.dialog:
pass # disconnect?
pass # disconnect?
self.dialog = dialog
if isinstance(dialog, ExampleBrowserDialog):
@ -142,7 +143,7 @@ class ExampleBrowser(QWidget, base.Component):
except KeyError:
i = 0
while i <= len(split_rel_path):
partial_path = "/".join(split_rel_path[0:i+1])
partial_path = "/".join(split_rel_path[0:i + 1])
split_partial_path = os.path.normpath(partial_path).split(os.path.sep)
if not partial_path in self.dir_items:
if i == 0: # Top level
@ -176,7 +177,8 @@ class ExampleBrowser(QWidget, base.Component):
self.title_label.setText(f"<b>Title:</b> {ex['title'] if ex else ''}")
self.author_label.setText(f"<b>Author:</b> {ex['author'] if ex else ''}")
try:
self.language_label.setText(f"<b>Output language:</b> {self.lang_dict[ex['output_language']] if ex else ''}")
self.language_label.setText(
f"<b>Output language:</b> {self.lang_dict[ex['output_language']] if ex else ''}")
self.gen_opts_label.setText(f"<b>Type:</b> {self.gen_opts_dict[ex['generate_options']] if ex else ''}")
except KeyError:
self.language_label.setText(f"<b>Output language:</b> ")
@ -197,7 +199,6 @@ class ExampleBrowser(QWidget, base.Component):
else:
self.image_label.setPixmap(QPixmap())
def open_file(self):
ex = self.tree_widget.currentItem().data(0, self.data_role)
self.file_to_open.emit(ex["path"])
@ -217,7 +218,6 @@ class ExampleBrowser(QWidget, base.Component):
found = True
return found
def show_selective(self, item, path):
item.setHidden(True)
if item.childCount(): # is a directory
@ -247,7 +247,6 @@ class ExampleBrowser(QWidget, base.Component):
top = self.tree_widget.topLevelItem(i)
self.show_all(top)
def find_examples(self, progress_callback, ext="grc"):
"""Iterate through the example flowgraph directories and parse them."""
examples_dict = {}
@ -272,8 +271,10 @@ class ExampleBrowser(QWidget, base.Component):
data = cache.get_or_load(file_path)
example = {}
example["name"] = os.path.basename(file_path)
example["generate_options"] = data["options"]["parameters"].get("generate_options") or "no_gui"
example["output_language"] = data["options"]["parameters"].get("output_language") or "python"
example["generate_options"] = data["options"]["parameters"].get(
"generate_options") or "no_gui"
example["output_language"] = data["options"]["parameters"].get(
"output_language") or "python"
example["example_filter"] = data["metadata"].get("example_filter") or []
example["title"] = data["options"]["parameters"]["title"] or ""
example["desc"] = data["options"]["parameters"]["description"] or ""

View File

@ -66,7 +66,8 @@ class OOTBrowser(QtWidgets.QDialog, base.Component):
for key, val in type_dict.items():
if key in module:
if not type(module.get(key)) == val:
log.error(f"OOT module {module.get('title')} has field {key}, but it's not the correct type. Expected {val}, got {type(module.get(key))}. Ignoring")
log.error(
f"OOT module {module.get('title')} has field {key}, but it's not the correct type. Expected {val}, got {type(module.get(key))}. Ignoring")
valid = False
else:
log.error(f"OOT module {module.get('title')} is missing field {key}. Ignoring")
@ -97,7 +98,8 @@ class OOTBrowser(QtWidgets.QDialog, base.Component):
else:
self.copyright_label.setText("<b>Copyright Owner:</b> None")
if type(module.get('gr_supported_version')) == list:
self.supp_ver_label.setText(f"<b>Supported GNU Radio Versions:</b> {', '.join(module.get('gr_supported_version'))}")
self.supp_ver_label.setText(
f"<b>Supported GNU Radio Versions:</b> {', '.join(module.get('gr_supported_version'))}")
else:
self.supp_ver_label.setText("<b>Supported GNU Radio Versions:</b> N/A")
log.error(f"module {module.get('title')} has invalid manifest field gr_supported_version")

View File

@ -58,6 +58,7 @@ class RotateAction(QUndoCommand):
def undo(self):
self.scene.rotate_selected(-self.delta_angle)
class MoveAction(QUndoCommand):
def __init__(self, scene: FlowgraphScene, diff: QPointF):
QUndoCommand.__init__(self)
@ -87,6 +88,7 @@ class MoveAction(QUndoCommand):
g_block.move(-self.x, -self.y)
self.scene.update()
class EnableAction(ChangeStateAction):
def __init__(self, scene: FlowgraphScene):
ChangeStateAction.__init__(self, scene)

View File

@ -41,7 +41,7 @@ class VariableEditor(QDockWidget, base.Component):
self.right_click_menu = VariableEditorContextMenu(self)
self.scene = None
### GUI Widgets
# GUI Widgets
self._tree = QTreeWidget()
self._model = self._tree.model()
self._tree.setObjectName('variable_editor::tree_widget')
@ -75,7 +75,7 @@ class VariableEditor(QDockWidget, base.Component):
self.app.registerDockWidget(self, location=self.settings.window.VARIABLE_EDITOR_DOCK_LOCATION)
self.currently_rebuilding = False
### Actions
# Actions
def createActions(self, actions):
log.debug("Creating actions")
@ -149,7 +149,6 @@ class VariableEditor(QDockWidget, base.Component):
variable_.setFlags(Qt.ItemIsSelectable)
variable_.setIcon(2, QtGui.QIcon.fromTheme("list-remove"))
self.currently_rebuilding = False
def update_gui(self, blocks):
@ -159,6 +158,7 @@ class VariableEditor(QDockWidget, base.Component):
self._tree.expandAll()
Slot(VariableEditorAction)
def handle_action(self, action):
log.debug(f"{action} triggered!")
"""
@ -180,7 +180,7 @@ class VariableEditor(QDockWidget, base.Component):
self._block.state = 'enabled'
elif action == VariableEditorAction.DISABLE_BLOCK:
self._block.state = 'disabled'
#Actions.VARIABLE_EDITOR_UPDATE() # TODO: Fix this
# Actions.VARIABLE_EDITOR_UPDATE() # TODO: Fix this
class VariableEditorContextMenu(QMenu):

View File

@ -63,7 +63,7 @@ class WikiTab(QtWidgets.QDockWidget, base.Component):
self.hidden = True
return
### GUI Widgets
# GUI Widgets
# Create the layout widget
container = QtWidgets.QWidget(self)
@ -103,7 +103,7 @@ class WikiTab(QtWidgets.QDockWidget, base.Component):
self._text.load(url)
self._text.show()
### Actions
# Actions
def createActions(self, actions):
pass

View File

@ -22,7 +22,8 @@ import logging
import os
import sys
import subprocess
import cProfile, pstats
import cProfile
import pstats
from typing import Union
@ -1050,7 +1051,6 @@ class MainWindow(QtWidgets.QMainWindow, base.Component):
QtWidgets.QMessageBox.Save,
)
if response == QtWidgets.QMessageBox.Discard:
file_path = self.currentFlowgraphScene.filename
self.tabWidget.removeTab(tab_index)
@ -1320,14 +1320,14 @@ class MainWindow(QtWidgets.QMainWindow, base.Component):
if self.currentView.process_is_done():
self.generate_triggered()
if self.currentView.generator:
xterm = self.app.qsettings.value("grc/xterm_executable","")
xterm = self.app.qsettings.value("grc/xterm_executable", "")
'''if self.config.xterm_missing() != xterm:
if not os.path.exists(xterm):
Dialogs.show_missing_xterm(main, xterm)
self.config.xterm_missing(xterm)'''
if self.currentFlowgraphScene.saved and self.currentFlowgraphScene.filename:
# Save config before execution
#self.config.save()
# self.config.save()
ExecFlowGraphThread(
view=self.currentView,
flowgraph=self.currentFlowgraph,
@ -1519,4 +1519,3 @@ class MainWindow(QtWidgets.QMainWindow, base.Component):
log.info("Stopping profiler")
stats = pstats.Stats(self.profiler)
stats.dump_stats('stats.prof')

View File

@ -71,4 +71,4 @@ if __name__ == '__main__':
e.start()
time.sleep(15)
e.stop()
e.join()
e.join()

View File

@ -84,6 +84,7 @@ class ConsoleFormatter(logging.Formatter):
return output.format(level, message, record.name, record.filename, record.lineno)
''' Verbose formatter '''
def verbose(self, record):
# TODO: Still need to implement this
pass

View File

@ -23,4 +23,3 @@ class StopWatch(object):
# Don't worry about catching it here
start, stop = self._laps[name]
return stop - start

View File

@ -226,30 +226,30 @@ class Types(object):
''' Setup types then map them to the conversion dictionaries '''
CORE_TYPES = { # Key: (Size, Color, Name)
'fc64': (16, Colors.COMPLEX_FLOAT_64, 'Complex Float 64'),
'fc32': (8, Colors.COMPLEX_FLOAT_32, 'Complex Float 32'),
'sc64': (16, Colors.COMPLEX_INTEGER_64, 'Complex Integer 64'),
'sc32': (8, Colors.COMPLEX_INTEGER_32, 'Complex Integer 32'),
'sc16': (4, Colors.COMPLEX_INTEGER_16, 'Complex Integer 16'),
'sc8': (2, Colors.COMPLEX_INTEGER_8, 'Complex Integer 8',),
'f64': (8, Colors.FLOAT_64, 'Float 64'),
'f32': (4, Colors.FLOAT_32, 'Float 32'),
's64': (8, Colors.INTEGER_64, 'Integer 64'),
's32': (4, Colors.INTEGER_32, 'Integer 32'),
's16': (2, Colors.INTEGER_16, 'Integer 16'),
's8': (1, Colors.INTEGER_8, 'Integer 8'),
'msg': (0, Colors.MESSAGE_QUEUE, 'Message Queue'),
'message': (0, Colors.ASYNC_MESSAGE, 'Async Message'),
'bus': (0, Colors.BUS_CONNECTION, 'Bus Connection'),
'': (0, Colors.WILDCARD, 'Wildcard')
'fc64': (16, Colors.COMPLEX_FLOAT_64, 'Complex Float 64'),
'fc32': (8, Colors.COMPLEX_FLOAT_32, 'Complex Float 32'),
'sc64': (16, Colors.COMPLEX_INTEGER_64, 'Complex Integer 64'),
'sc32': (8, Colors.COMPLEX_INTEGER_32, 'Complex Integer 32'),
'sc16': (4, Colors.COMPLEX_INTEGER_16, 'Complex Integer 16'),
'sc8': (2, Colors.COMPLEX_INTEGER_8, 'Complex Integer 8',),
'f64': (8, Colors.FLOAT_64, 'Float 64'),
'f32': (4, Colors.FLOAT_32, 'Float 32'),
's64': (8, Colors.INTEGER_64, 'Integer 64'),
's32': (4, Colors.INTEGER_32, 'Integer 32'),
's16': (2, Colors.INTEGER_16, 'Integer 16'),
's8': (1, Colors.INTEGER_8, 'Integer 8'),
'msg': (0, Colors.MESSAGE_QUEUE, 'Message Queue'),
'message': (0, Colors.ASYNC_MESSAGE, 'Async Message'),
'bus': (0, Colors.BUS_CONNECTION, 'Bus Connection'),
'': (0, Colors.WILDCARD, 'Wildcard')
}
ALIAS_TYPES = {
'complex': (8, Colors.COMPLEX),
'float': (4, Colors.FLOAT),
'int': (4, Colors.INT),
'short': (2, Colors.SHORT),
'byte': (1, Colors.BYTE),
'float': (4, Colors.FLOAT),
'int': (4, Colors.INT),
'short': (2, Colors.SHORT),
'byte': (1, Colors.BYTE),
}
# Setup conversion dictionaries

15
main.py
View File

@ -31,13 +31,13 @@ LOG_LEVELS = {
'critical': logging.CRITICAL,
}
### Load GNU Radio
# Load GNU Radio
# Do this globally so it is available for both run_gtk() and run_qt()
try:
from gnuradio import gr
except ImportError as ex:
# Throw a new exception with more information
print ("Cannot find GNU Radio! (Have you sourced the environment file?)", file=sys.stderr)
print("Cannot find GNU Radio! (Have you sourced the environment file?)", file=sys.stderr)
# If this is a background session (not launched through a script), show a Tkinter error dialog.
# Tkinter should already be installed default with Python, so this shouldn't add new dependencies
@ -55,7 +55,7 @@ except ImportError as ex:
raise Exception("Cannot find GNU Radio!") from None
### Enable Logging
# Enable Logging
# Do this globally so it is available for both run_gtk() and run_qt()
# TODO: Advanced logging - https://docs.python.org/3/howto/logging-cookbook.html#formatting-styles
# Note: All other modules need to use the 'grc.<module>' convention
@ -137,7 +137,6 @@ def run_qt(args, log):
# Still need to install null translation to let the system handle calls to _()
language.install()
''' OS Platform '''
# Figure out system specific properties and setup defaults.
# Some properties can be overridden by preferences
@ -168,7 +167,6 @@ def run_qt(args, log):
else:
log.warning("Unknown operating system")
''' Preferences '''
# TODO: Move earlier? Need to load user preferences and override the default properties/settings
@ -201,9 +199,7 @@ def main():
log.warning("main.py could not read grc_qt.conf")
log.warning(e)
### Argument parsing
# Argument parsing
parser = argparse.ArgumentParser(
description=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version())
parser.add_argument('flow_graphs', nargs='*')
@ -249,8 +245,7 @@ def main():
except (PermissionError, FileNotFoundError) as e:
log.error(f'Cannot write to {log_file} - {e}')
### GUI Framework
# GUI Framework
if args.framework == 'qt':
run_qt(args, log)
elif args.framework == 'gtk':

View File

@ -23,10 +23,11 @@ from grc.gui_qt.Platform import Platform
log = logging.getLogger("grc")
@pytest.fixture(scope="session")
def qapp_cls_():
settings = properties.Properties([])
settings.argv = [""]
settings.argv = [""]
""" Translation Support """
# Try to get the current locale. Always add English
@ -153,6 +154,8 @@ def menu_shortcut(qtbot, app, menu_name, menu_key, shortcut_key):
qtbot.wait(100)
# Start by closing the flowgraph that pops up on start
def test_file_close_init(qtbot, qapp_cls_, monkeypatch):
win = qapp_cls_.MainWindow
monkeypatch.setattr(
@ -167,6 +170,7 @@ def test_file_close_init(qtbot, qapp_cls_, monkeypatch):
menu_shortcut(qtbot, qapp_cls_, "file", QtCore.Qt.Key_F, QtCore.Qt.Key_L)
assert win.tabWidget.count() == 1
def test_delete_block(qtbot, qapp_cls_):
qtbot.wait(100)
var = find_blocks(qapp_cls_.MainWindow.currentFlowgraph, "variable")
@ -209,6 +213,7 @@ def test_add_throttle(qtbot, qapp_cls_):
delete_block(qtbot, qapp_cls_, throttle)
def test_right_click(qtbot, qapp_cls_):
qtbot.wait(100)
add_block_from_query(qtbot, qapp_cls_, "throttle")
@ -226,6 +231,7 @@ def test_right_click(qtbot, qapp_cls_):
delete_block(qtbot, qapp_cls_, throttle)
def test_errors(qtbot, qapp_cls_):
menu = qapp_cls_.MainWindow.menus["build"]
@ -239,7 +245,7 @@ def test_errors(qtbot, qapp_cls_):
qtbot.keyClick(qapp_cls_.focusWidget(), QtCore.Qt.Key_B, QtCore.Qt.AltModifier)
qtbot.wait(100)
QtCore.QTimer.singleShot(200, assert_and_close)
#qtbot.keyClick(menu, QtCore.Qt.Key_E) # Not necessary since it's already selected (it's the first item)
# qtbot.keyClick(menu, QtCore.Qt.Key_E) # Not necessary since it's already selected (it's the first item)
qtbot.keyClick(menu, QtCore.Qt.Key_Enter)
qtbot.wait(300)
@ -248,14 +254,15 @@ def test_errors(qtbot, qapp_cls_):
delete_block(qtbot, qapp_cls_, throttle)
def test_open_properties(qtbot, qapp_cls_):
qtbot.wait(100)
qtbot.mouseDClick(
qapp_cls_.MainWindow.currentView.viewport(),
QtCore.Qt.LeftButton,
pos=qapp_cls_.MainWindow.currentView.mapFromScene(
qapp_cls_.MainWindow.currentFlowgraph.options_block.gui.pos()
+ QtCore.QPointF(15.0, 15.0)
qapp_cls_.MainWindow.currentFlowgraph.options_block.gui.pos() +
QtCore.QPointF(15.0, 15.0)
),
)
qtbot.wait(100)
@ -481,13 +488,14 @@ def test_num_inputs(qtbot, qapp_cls_):
# I think loses focus makes delete_fail the first time. This makes it work, but is a hack
#click_on(qtbot, qapp_cls_, n_src)
pag.click(click_pos.x()+50, click_pos.y()+50, button="left")
pag.click(click_pos.x() + 50, click_pos.y() + 50, button="left")
for block in [n_src, n_sink]:
delete_block(qtbot, qapp_cls_, block)
qtbot.wait(100)
assert len(fg.blocks) == 2
def test_bus(qtbot, qapp_cls_):
fg = qapp_cls_.MainWindow.currentFlowgraph
view = qapp_cls_.MainWindow.currentView
@ -550,6 +558,7 @@ def test_bus(qtbot, qapp_cls_):
delete_block(qtbot, qapp_cls_, n_sink)
qtbot.wait(100)
def test_bypass(qtbot, qapp_cls_):
scaling = qapp_cls_.MainWindow.screen().devicePixelRatio()
@ -583,6 +592,7 @@ def test_bypass(qtbot, qapp_cls_):
for block in [throttle, n_src]:
delete_block(qtbot, qapp_cls_, block)
def test_file_save(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg_path = tmp_path / "test_save.grc"
monkeypatch.setattr(
@ -593,6 +603,7 @@ def test_file_save(qtbot, qapp_cls_, monkeypatch, tmp_path):
ctrl_keystroke(qtbot, qapp_cls_, QtCore.Qt.Key_S)
assert fg_path.exists(), "File/Save: Could not save file"
def test_file_save_as(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg_path = tmp_path / "test.grc"
monkeypatch.setattr(
@ -604,6 +615,7 @@ def test_file_save_as(qtbot, qapp_cls_, monkeypatch, tmp_path):
menu_shortcut(qtbot, qapp_cls_, "file", QtCore.Qt.Key_F, QtCore.Qt.Key_A)
assert fg_path.exists()
def test_file_save_copy(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg_path = tmp_path / "test_copy.grc"
monkeypatch.setattr(
@ -672,6 +684,7 @@ def test_file_preferences(qtbot, qapp_cls_):
assert qapp_cls_.activeWindow() == qapp_cls_.MainWindow
qtbot.wait(100)
def test_file_examples(qtbot, qapp_cls_):
menu = qapp_cls_.MainWindow.menus["file"]
items = gather_menu_items(menu)
@ -688,9 +701,11 @@ def test_file_examples(qtbot, qapp_cls_):
assert qapp_cls_.activeWindow() == qapp_cls_.MainWindow
qtbot.wait(100)
def test_edit_actions(qtbot, qapp_cls_):
pass
def test_edit_select_all(qtbot, qapp_cls_):
qtbot.keyClick(qapp_cls_.focusWidget(), QtCore.Qt.Key_A, QtCore.Qt.ControlModifier)
qtbot.wait(100)
@ -821,6 +836,7 @@ def test_file_new_close(qtbot, qapp_cls_, monkeypatch):
ctrl_keystroke(qtbot, qapp_cls_, QtCore.Qt.Key_W)
assert win.tabWidget.count() == 4 - i, "File/Close"
def test_generate(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg = qapp_cls_.MainWindow.currentFlowgraph
view = qapp_cls_.MainWindow.currentView
@ -863,6 +879,7 @@ def test_generate(qtbot, qapp_cls_, monkeypatch, tmp_path):
assert fg_path.exists(), "File/Save: Could not save .grc file"
assert py_path.exists(), "File/Save: Could not save Python file"
def test_file_close_all(qtbot, qapp_cls_, monkeypatch):
win = qapp_cls_.MainWindow
monkeypatch.setattr(
@ -880,6 +897,7 @@ def test_file_close_all(qtbot, qapp_cls_, monkeypatch):
menu_shortcut(qtbot, qapp_cls_, "file", QtCore.Qt.Key_F, QtCore.Qt.Key_L)
assert win.tabWidget.count() == 1, "File/Close All"
def test_quit(qtbot, qapp_cls_, monkeypatch):
monkeypatch.setattr(
QtWidgets.QMessageBox,