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()) block_connections = block_connections + list(port.connections())
return block_connections return block_connections
############################################## ##############################################
# Access # Access
############################################## ##############################################

View File

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

View File

@ -16,4 +16,4 @@ class Config(CoreConfig):
@property @property
def wiki_block_docs_url_prefix(self): 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. Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio 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. Copyright 2008, 2009 Free Software Foundation, Inc.
This file is part of GNU Radio This file is part of GNU Radio
@ -65,5 +65,5 @@ class Platform(CorePlatform):
port_classes = {key: Port.make_cls_with_base(cls) port_classes = {key: Port.make_cls_with_base(cls)
for key, cls in CorePlatform.port_classes.items()} 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()} # for key, cls in CorePlatform.param_classes.items()}

View File

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

View File

@ -113,7 +113,7 @@ class BlockLibrary(QDockWidget, base.Component):
self.resize(400, 300) self.resize(400, 300)
self.setFloating(False) self.setFloating(False)
### GUI Widgets # GUI Widgets
# Create the layout widget # Create the layout widget
container = QWidget(self) container = QWidget(self)
@ -156,13 +156,13 @@ class BlockLibrary(QDockWidget, base.Component):
container.setLayout(layout) container.setLayout(layout)
self.setWidget(container) self.setWidget(container)
### Translation support # Translation support
# self.setWindowTitle(_translate("blockLibraryDock", "Library", None)) # self.setWindowTitle(_translate("blockLibraryDock", "Library", None))
# library.headerItem().setText(0, _translate("blockLibraryDock", "Blocks", None)) # library.headerItem().setText(0, _translate("blockLibraryDock", "Blocks", None))
# QMetaObject.connectSlotsByName(blockLibraryDock) # QMetaObject.connectSlotsByName(blockLibraryDock)
### Loading blocks # Loading blocks
# Keep as a separate function so it can be called at a later point (Reloading blocks) # Keep as a separate function so it can be called at a later point (Reloading blocks)
self._block_tree_flat = {} 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. The graphical representation of a block. Accesses the actual block with self.core.
""" """
def __init__(self, core, parent, **n): def __init__(self, core, parent, **n):
super(GUIBlock, self).__init__() super(GUIBlock, self).__init__()
self.core = core 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. Copyright 2008,2013 Free Software Foundation, Inc.
This file is part of GNU Radio 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 Dummy connection used for when the user drags a connection
between two ports. between two ports.
""" """
def __init__(self, parent, start_point, end_point): def __init__(self, parent, start_point, end_point):
super(DummyConnection, self).__init__() super(DummyConnection, self).__init__()
@ -113,8 +114,10 @@ class GUIConnection(QGraphicsPathItem):
self._arrowhead.clear() self._arrowhead.clear()
self._arrowhead.moveTo(self.sink.gui.connection_point + QPointF(10.0, 0)) 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) +
self._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0) + QPointF(-CONNECTOR_ARROW_HEIGHT, CONNECTOR_ARROW_BASE / 2)) 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._arrowhead.lineTo(self.sink.gui.connection_point + QPointF(10.0, 0))
self._path.clear() self._path.clear()

View File

@ -32,6 +32,7 @@ class GUIPort(QGraphicsItem):
Note that this constructor is called before its parent GUIBlock is instantiated, Note that this constructor is called before its parent GUIBlock is instantiated,
which is why we call setParentItem() in create_shapes_and_labels(). which is why we call setParentItem() in create_shapes_and_labels().
""" """
def __init__(self, core, direction, **n): def __init__(self, core, direction, **n):
self.core = core self.core = core
QGraphicsItem.__init__(self) QGraphicsItem.__init__(self)
@ -80,7 +81,8 @@ class GUIPort(QGraphicsItem):
return QGraphicsItem.itemChange(self, change, value) return QGraphicsItem.itemChange(self, change, value)
def create_shapes_and_labels(self): 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(): if not self.parentItem():
self.setParentItem(self.core.parent_block.gui) self.setParentItem(self.core.parent_block.gui)
@ -125,7 +127,8 @@ class GUIPort(QGraphicsItem):
painter.setPen(QPen(1)) painter.setPen(QPen(1))
painter.setFont(self.font) painter.setFont(self.font)
if self.core._dir == "sink": 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: else:
painter.drawText(QRectF(0, 0, self.width, self.height), Qt.AlignCenter, self.core.name) 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.setWindowTitle('Console')
self.level = level self.level = level
### GUI Widgets # GUI Widgets
# Create the layout widget # Create the layout widget
container = QtWidgets.QWidget(self) container = QtWidgets.QWidget(self)
@ -114,13 +114,13 @@ class Console(QtWidgets.QDockWidget, base.Component):
container.setLayout(layout) container.setLayout(layout)
self.setWidget(container) self.setWidget(container)
### Translation support # Translation support
#self.setWindowTitle(_translate("", "Library", None)) #self.setWindowTitle(_translate("", "Library", None))
#library.headerItem().setText(0, _translate("", "Blocks", 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 # TODO: Move to the base controller and set actions as class attributes
# Automatically create the actions, menus and toolbars. # Automatically create the actions, menus and toolbars.
@ -157,7 +157,7 @@ class Console(QtWidgets.QDockWidget, base.Component):
def enable(self): def enable(self):
self.enabled = True self.enabled = True
### Actions # Actions
def createActions(self, actions): def createActions(self, actions):
''' Defines all actions for this view. ''' ''' 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['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['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): def createMenus(self, actions, menus):
''' Setup the view's menus ''' ''' Setup the view's menus '''
@ -180,7 +181,7 @@ class Console(QtWidgets.QDockWidget, base.Component):
console_menu.setObjectName("console::menu") console_menu.setObjectName("console::menu")
# Not needed, we have FileHandler logging in main.py # 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["clear"])
console_menu.addAction(actions["show_level"]) console_menu.addAction(actions["show_level"])

View File

@ -122,6 +122,7 @@ class PropsDialog(QDialog):
self.edit_params.append(line_edit) self.edit_params.append(line_edit)
elif param.dtype == "_multiline_python_external": elif param.dtype == "_multiline_python_external":
ext_param = copy(param) ext_param = copy(param)
def open_editor(widget=None): def open_editor(widget=None):
self._block.parent_flowgraph.gui.install_external_editor( self._block.parent_flowgraph.gui.install_external_editor(
ext_param) ext_param)
@ -143,7 +144,7 @@ class PropsDialog(QDialog):
line_edit = QPlainTextEdit(param.value) line_edit = QPlainTextEdit(param.value)
line_edit.param = param line_edit.param = param
qvb.addWidget(editor_widget, i, 1) qvb.addWidget(editor_widget, i, 1)
#self.edit_params.append(line_edit) # self.edit_params.append(line_edit)
else: else:
line_edit = QLineEdit(param.value) line_edit = QLineEdit(param.value)
line_edit.param = param 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 This is the Worker that will gather/parse examples as a background task
""" """
def __init__(self, fn, *args, **kwargs): def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__() super(Worker, self).__init__()
@ -111,7 +112,7 @@ class ExampleBrowser(QWidget, base.Component):
def connect_dialog(self, dialog: QDialog): def connect_dialog(self, dialog: QDialog):
if self.dialog: if self.dialog:
pass # disconnect? pass # disconnect?
self.dialog = dialog self.dialog = dialog
if isinstance(dialog, ExampleBrowserDialog): if isinstance(dialog, ExampleBrowserDialog):
@ -142,7 +143,7 @@ class ExampleBrowser(QWidget, base.Component):
except KeyError: except KeyError:
i = 0 i = 0
while i <= len(split_rel_path): 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) split_partial_path = os.path.normpath(partial_path).split(os.path.sep)
if not partial_path in self.dir_items: if not partial_path in self.dir_items:
if i == 0: # Top level 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.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 ''}") self.author_label.setText(f"<b>Author:</b> {ex['author'] if ex else ''}")
try: 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 ''}") self.gen_opts_label.setText(f"<b>Type:</b> {self.gen_opts_dict[ex['generate_options']] if ex else ''}")
except KeyError: except KeyError:
self.language_label.setText(f"<b>Output language:</b> ") self.language_label.setText(f"<b>Output language:</b> ")
@ -197,7 +199,6 @@ class ExampleBrowser(QWidget, base.Component):
else: else:
self.image_label.setPixmap(QPixmap()) self.image_label.setPixmap(QPixmap())
def open_file(self): def open_file(self):
ex = self.tree_widget.currentItem().data(0, self.data_role) ex = self.tree_widget.currentItem().data(0, self.data_role)
self.file_to_open.emit(ex["path"]) self.file_to_open.emit(ex["path"])
@ -217,7 +218,6 @@ class ExampleBrowser(QWidget, base.Component):
found = True found = True
return found return found
def show_selective(self, item, path): def show_selective(self, item, path):
item.setHidden(True) item.setHidden(True)
if item.childCount(): # is a directory if item.childCount(): # is a directory
@ -247,7 +247,6 @@ class ExampleBrowser(QWidget, base.Component):
top = self.tree_widget.topLevelItem(i) top = self.tree_widget.topLevelItem(i)
self.show_all(top) self.show_all(top)
def find_examples(self, progress_callback, ext="grc"): def find_examples(self, progress_callback, ext="grc"):
"""Iterate through the example flowgraph directories and parse them.""" """Iterate through the example flowgraph directories and parse them."""
examples_dict = {} examples_dict = {}
@ -272,8 +271,10 @@ class ExampleBrowser(QWidget, base.Component):
data = cache.get_or_load(file_path) data = cache.get_or_load(file_path)
example = {} example = {}
example["name"] = os.path.basename(file_path) example["name"] = os.path.basename(file_path)
example["generate_options"] = data["options"]["parameters"].get("generate_options") or "no_gui" example["generate_options"] = data["options"]["parameters"].get(
example["output_language"] = data["options"]["parameters"].get("output_language") or "python" "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["example_filter"] = data["metadata"].get("example_filter") or []
example["title"] = data["options"]["parameters"]["title"] or "" example["title"] = data["options"]["parameters"]["title"] or ""
example["desc"] = data["options"]["parameters"]["description"] 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(): for key, val in type_dict.items():
if key in module: if key in module:
if not type(module.get(key)) == val: 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 valid = False
else: else:
log.error(f"OOT module {module.get('title')} is missing field {key}. Ignoring") log.error(f"OOT module {module.get('title')} is missing field {key}. Ignoring")
@ -97,7 +98,8 @@ class OOTBrowser(QtWidgets.QDialog, base.Component):
else: else:
self.copyright_label.setText("<b>Copyright Owner:</b> None") self.copyright_label.setText("<b>Copyright Owner:</b> None")
if type(module.get('gr_supported_version')) == list: 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: else:
self.supp_ver_label.setText("<b>Supported GNU Radio Versions:</b> N/A") 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") 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): def undo(self):
self.scene.rotate_selected(-self.delta_angle) self.scene.rotate_selected(-self.delta_angle)
class MoveAction(QUndoCommand): class MoveAction(QUndoCommand):
def __init__(self, scene: FlowgraphScene, diff: QPointF): def __init__(self, scene: FlowgraphScene, diff: QPointF):
QUndoCommand.__init__(self) QUndoCommand.__init__(self)
@ -87,6 +88,7 @@ class MoveAction(QUndoCommand):
g_block.move(-self.x, -self.y) g_block.move(-self.x, -self.y)
self.scene.update() self.scene.update()
class EnableAction(ChangeStateAction): class EnableAction(ChangeStateAction):
def __init__(self, scene: FlowgraphScene): def __init__(self, scene: FlowgraphScene):
ChangeStateAction.__init__(self, scene) ChangeStateAction.__init__(self, scene)

View File

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

View File

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

View File

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

View File

@ -71,4 +71,4 @@ if __name__ == '__main__':
e.start() e.start()
time.sleep(15) time.sleep(15)
e.stop() 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) return output.format(level, message, record.name, record.filename, record.lineno)
''' Verbose formatter ''' ''' Verbose formatter '''
def verbose(self, record): def verbose(self, record):
# TODO: Still need to implement this # TODO: Still need to implement this
pass pass

View File

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

View File

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

15
main.py
View File

@ -31,13 +31,13 @@ LOG_LEVELS = {
'critical': logging.CRITICAL, 'critical': logging.CRITICAL,
} }
### Load GNU Radio # Load GNU Radio
# Do this globally so it is available for both run_gtk() and run_qt() # Do this globally so it is available for both run_gtk() and run_qt()
try: try:
from gnuradio import gr from gnuradio import gr
except ImportError as ex: except ImportError as ex:
# Throw a new exception with more information # 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. # 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 # 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 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() # 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 # 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 # 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 _() # Still need to install null translation to let the system handle calls to _()
language.install() language.install()
''' OS Platform ''' ''' OS Platform '''
# Figure out system specific properties and setup defaults. # Figure out system specific properties and setup defaults.
# Some properties can be overridden by preferences # Some properties can be overridden by preferences
@ -168,7 +167,6 @@ def run_qt(args, log):
else: else:
log.warning("Unknown operating system") log.warning("Unknown operating system")
''' Preferences ''' ''' Preferences '''
# TODO: Move earlier? Need to load user preferences and override the default properties/settings # 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("main.py could not read grc_qt.conf")
log.warning(e) log.warning(e)
# Argument parsing
### Argument parsing
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version()) description=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version())
parser.add_argument('flow_graphs', nargs='*') parser.add_argument('flow_graphs', nargs='*')
@ -249,8 +245,7 @@ def main():
except (PermissionError, FileNotFoundError) as e: except (PermissionError, FileNotFoundError) as e:
log.error(f'Cannot write to {log_file} - {e}') log.error(f'Cannot write to {log_file} - {e}')
# GUI Framework
### GUI Framework
if args.framework == 'qt': if args.framework == 'qt':
run_qt(args, log) run_qt(args, log)
elif args.framework == 'gtk': elif args.framework == 'gtk':

View File

@ -23,10 +23,11 @@ from grc.gui_qt.Platform import Platform
log = logging.getLogger("grc") log = logging.getLogger("grc")
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def qapp_cls_(): def qapp_cls_():
settings = properties.Properties([]) settings = properties.Properties([])
settings.argv = [""] settings.argv = [""]
""" Translation Support """ """ Translation Support """
# Try to get the current locale. Always add English # 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) qtbot.wait(100)
# Start by closing the flowgraph that pops up on start # Start by closing the flowgraph that pops up on start
def test_file_close_init(qtbot, qapp_cls_, monkeypatch): def test_file_close_init(qtbot, qapp_cls_, monkeypatch):
win = qapp_cls_.MainWindow win = qapp_cls_.MainWindow
monkeypatch.setattr( 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) menu_shortcut(qtbot, qapp_cls_, "file", QtCore.Qt.Key_F, QtCore.Qt.Key_L)
assert win.tabWidget.count() == 1 assert win.tabWidget.count() == 1
def test_delete_block(qtbot, qapp_cls_): def test_delete_block(qtbot, qapp_cls_):
qtbot.wait(100) qtbot.wait(100)
var = find_blocks(qapp_cls_.MainWindow.currentFlowgraph, "variable") 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) delete_block(qtbot, qapp_cls_, throttle)
def test_right_click(qtbot, qapp_cls_): def test_right_click(qtbot, qapp_cls_):
qtbot.wait(100) qtbot.wait(100)
add_block_from_query(qtbot, qapp_cls_, "throttle") 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) delete_block(qtbot, qapp_cls_, throttle)
def test_errors(qtbot, qapp_cls_): def test_errors(qtbot, qapp_cls_):
menu = qapp_cls_.MainWindow.menus["build"] 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.keyClick(qapp_cls_.focusWidget(), QtCore.Qt.Key_B, QtCore.Qt.AltModifier)
qtbot.wait(100) qtbot.wait(100)
QtCore.QTimer.singleShot(200, assert_and_close) 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.keyClick(menu, QtCore.Qt.Key_Enter)
qtbot.wait(300) qtbot.wait(300)
@ -248,14 +254,15 @@ def test_errors(qtbot, qapp_cls_):
delete_block(qtbot, qapp_cls_, throttle) delete_block(qtbot, qapp_cls_, throttle)
def test_open_properties(qtbot, qapp_cls_): def test_open_properties(qtbot, qapp_cls_):
qtbot.wait(100) qtbot.wait(100)
qtbot.mouseDClick( qtbot.mouseDClick(
qapp_cls_.MainWindow.currentView.viewport(), qapp_cls_.MainWindow.currentView.viewport(),
QtCore.Qt.LeftButton, QtCore.Qt.LeftButton,
pos=qapp_cls_.MainWindow.currentView.mapFromScene( pos=qapp_cls_.MainWindow.currentView.mapFromScene(
qapp_cls_.MainWindow.currentFlowgraph.options_block.gui.pos() qapp_cls_.MainWindow.currentFlowgraph.options_block.gui.pos() +
+ QtCore.QPointF(15.0, 15.0) QtCore.QPointF(15.0, 15.0)
), ),
) )
qtbot.wait(100) 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 # 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) #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]: for block in [n_src, n_sink]:
delete_block(qtbot, qapp_cls_, block) delete_block(qtbot, qapp_cls_, block)
qtbot.wait(100) qtbot.wait(100)
assert len(fg.blocks) == 2 assert len(fg.blocks) == 2
def test_bus(qtbot, qapp_cls_): def test_bus(qtbot, qapp_cls_):
fg = qapp_cls_.MainWindow.currentFlowgraph fg = qapp_cls_.MainWindow.currentFlowgraph
view = qapp_cls_.MainWindow.currentView view = qapp_cls_.MainWindow.currentView
@ -550,6 +558,7 @@ def test_bus(qtbot, qapp_cls_):
delete_block(qtbot, qapp_cls_, n_sink) delete_block(qtbot, qapp_cls_, n_sink)
qtbot.wait(100) qtbot.wait(100)
def test_bypass(qtbot, qapp_cls_): def test_bypass(qtbot, qapp_cls_):
scaling = qapp_cls_.MainWindow.screen().devicePixelRatio() scaling = qapp_cls_.MainWindow.screen().devicePixelRatio()
@ -583,6 +592,7 @@ def test_bypass(qtbot, qapp_cls_):
for block in [throttle, n_src]: for block in [throttle, n_src]:
delete_block(qtbot, qapp_cls_, block) delete_block(qtbot, qapp_cls_, block)
def test_file_save(qtbot, qapp_cls_, monkeypatch, tmp_path): def test_file_save(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg_path = tmp_path / "test_save.grc" fg_path = tmp_path / "test_save.grc"
monkeypatch.setattr( 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) ctrl_keystroke(qtbot, qapp_cls_, QtCore.Qt.Key_S)
assert fg_path.exists(), "File/Save: Could not save file" assert fg_path.exists(), "File/Save: Could not save file"
def test_file_save_as(qtbot, qapp_cls_, monkeypatch, tmp_path): def test_file_save_as(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg_path = tmp_path / "test.grc" fg_path = tmp_path / "test.grc"
monkeypatch.setattr( 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) menu_shortcut(qtbot, qapp_cls_, "file", QtCore.Qt.Key_F, QtCore.Qt.Key_A)
assert fg_path.exists() assert fg_path.exists()
def test_file_save_copy(qtbot, qapp_cls_, monkeypatch, tmp_path): def test_file_save_copy(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg_path = tmp_path / "test_copy.grc" fg_path = tmp_path / "test_copy.grc"
monkeypatch.setattr( monkeypatch.setattr(
@ -672,6 +684,7 @@ def test_file_preferences(qtbot, qapp_cls_):
assert qapp_cls_.activeWindow() == qapp_cls_.MainWindow assert qapp_cls_.activeWindow() == qapp_cls_.MainWindow
qtbot.wait(100) qtbot.wait(100)
def test_file_examples(qtbot, qapp_cls_): def test_file_examples(qtbot, qapp_cls_):
menu = qapp_cls_.MainWindow.menus["file"] menu = qapp_cls_.MainWindow.menus["file"]
items = gather_menu_items(menu) items = gather_menu_items(menu)
@ -688,9 +701,11 @@ def test_file_examples(qtbot, qapp_cls_):
assert qapp_cls_.activeWindow() == qapp_cls_.MainWindow assert qapp_cls_.activeWindow() == qapp_cls_.MainWindow
qtbot.wait(100) qtbot.wait(100)
def test_edit_actions(qtbot, qapp_cls_): def test_edit_actions(qtbot, qapp_cls_):
pass pass
def test_edit_select_all(qtbot, qapp_cls_): def test_edit_select_all(qtbot, qapp_cls_):
qtbot.keyClick(qapp_cls_.focusWidget(), QtCore.Qt.Key_A, QtCore.Qt.ControlModifier) qtbot.keyClick(qapp_cls_.focusWidget(), QtCore.Qt.Key_A, QtCore.Qt.ControlModifier)
qtbot.wait(100) 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) ctrl_keystroke(qtbot, qapp_cls_, QtCore.Qt.Key_W)
assert win.tabWidget.count() == 4 - i, "File/Close" assert win.tabWidget.count() == 4 - i, "File/Close"
def test_generate(qtbot, qapp_cls_, monkeypatch, tmp_path): def test_generate(qtbot, qapp_cls_, monkeypatch, tmp_path):
fg = qapp_cls_.MainWindow.currentFlowgraph fg = qapp_cls_.MainWindow.currentFlowgraph
view = qapp_cls_.MainWindow.currentView 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 fg_path.exists(), "File/Save: Could not save .grc file"
assert py_path.exists(), "File/Save: Could not save Python file" assert py_path.exists(), "File/Save: Could not save Python file"
def test_file_close_all(qtbot, qapp_cls_, monkeypatch): def test_file_close_all(qtbot, qapp_cls_, monkeypatch):
win = qapp_cls_.MainWindow win = qapp_cls_.MainWindow
monkeypatch.setattr( 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) menu_shortcut(qtbot, qapp_cls_, "file", QtCore.Qt.Key_F, QtCore.Qt.Key_L)
assert win.tabWidget.count() == 1, "File/Close All" assert win.tabWidget.count() == 1, "File/Close All"
def test_quit(qtbot, qapp_cls_, monkeypatch): def test_quit(qtbot, qapp_cls_, monkeypatch):
monkeypatch.setattr( monkeypatch.setattr(
QtWidgets.QMessageBox, QtWidgets.QMessageBox,