168 lines
6.9 KiB
Python
168 lines
6.9 KiB
Python
# Copyright 2014-2020 Free Software Foundation, Inc.
|
|
# This file is part of GNU Radio
|
|
#
|
|
# GNU Radio Companion is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# GNU Radio Companion is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
from __future__ import absolute_import, print_function
|
|
|
|
# Standard modules
|
|
import logging
|
|
import textwrap
|
|
import os
|
|
|
|
from qtpy import QtCore, QtWidgets, QtGui, PYQT_VERSION, PYSIDE_VERSION
|
|
|
|
# Custom modules
|
|
from . import components
|
|
from .helpers.profiling import StopWatch
|
|
|
|
# Logging
|
|
# Setup the logger to use a different name than the file name
|
|
log = logging.getLogger("grc.application")
|
|
|
|
|
|
class Application(QtWidgets.QApplication):
|
|
"""
|
|
This is the main QT application for GRC.
|
|
It handles setting up the application components and actions and handles communication between different components in the system.
|
|
"""
|
|
|
|
def __init__(self, settings, platform, file_path):
|
|
# Note. Logger must have the correct naming convention to share handlers
|
|
log.debug("__init__")
|
|
self.settings = settings
|
|
self.platform = platform
|
|
config = platform.config
|
|
|
|
self.qsettings = QtCore.QSettings(config.gui_prefs_file, QtCore.QSettings.IniFormat)
|
|
log.debug(f"Using QSettings from {config.gui_prefs_file}")
|
|
os.environ["QT_SCALE_FACTOR"] = self.qsettings.value('appearance/qt_scale_factor', "1.0", type=str)
|
|
|
|
log.debug("Creating QApplication instance")
|
|
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts, True)
|
|
QtWidgets.QApplication.__init__(self, settings.argv)
|
|
|
|
self.theme = "light"
|
|
if self.qsettings.value("appearance/theme", "dark") == "dark":
|
|
try:
|
|
import qdarkstyle
|
|
|
|
self.setStyleSheet(qdarkstyle.load_stylesheet())
|
|
self.theme = "dark"
|
|
except ImportError:
|
|
log.warning("Did not find QDarkstyle. Dark mode disabled")
|
|
|
|
# Load the main view class and initialize QMainWindow
|
|
log.debug("ARGV - {0}".format(settings.argv))
|
|
log.debug("INSTALL_DIR - {0}".format(settings.path.INSTALL))
|
|
|
|
# Global signals
|
|
self.signals = {}
|
|
|
|
# Setup the main application window
|
|
log.debug("Creating main application window")
|
|
stopwatch = StopWatch()
|
|
self.MainWindow = components.MainWindow(file_path)
|
|
stopwatch.lap("mainwindow")
|
|
level_str = self.qsettings.value('grc/console_log_level', "info", type=str)
|
|
if level_str == "info":
|
|
self.Console = components.Console(logging.INFO)
|
|
else: # level_str == "debug"
|
|
self.Console = components.Console(logging.DEBUG)
|
|
stopwatch.lap("console")
|
|
self.BlockLibrary = components.BlockLibrary()
|
|
stopwatch.lap("blocklibrary")
|
|
# self.DocumentationTab = components.DocumentationTab()
|
|
# stopwatch.lap('documentationtab')
|
|
self.WikiTab = components.WikiTab()
|
|
stopwatch.lap("wikitab")
|
|
self.VariableEditor = components.VariableEditor()
|
|
stopwatch.lap("variable_editor")
|
|
self.VariableEditor.set_scene(self.MainWindow.currentFlowgraphScene)
|
|
self.VariableEditor.all_editor_actions.connect(self.MainWindow.handle_editor_action)
|
|
self.MainWindow.ExampleBrowser.set_library(self.BlockLibrary)
|
|
|
|
# Debug times
|
|
log.debug(
|
|
"Loaded MainWindow controller - {:.4f}s".format(
|
|
stopwatch.elapsed("mainwindow")
|
|
)
|
|
)
|
|
log.debug(
|
|
"Loaded Console component - {:.4f}s".format(stopwatch.elapsed("console"))
|
|
)
|
|
log.debug(
|
|
"Loaded BlockLibrary component - {:.4}s".format(
|
|
stopwatch.elapsed("blocklibrary")
|
|
)
|
|
)
|
|
# log.debug("Loaded DocumentationTab component - {:.4}s".format(stopwatch.elapsed("documentationtab")))
|
|
|
|
# Print Startup information once everything has loaded
|
|
self.Console.enable()
|
|
|
|
paths = "\n\t".join(config.block_paths)
|
|
welcome = (
|
|
f"<<< Welcome to {config.name} {config.version} >>>\n\n"
|
|
f"{('PyQt ' + PYQT_VERSION) if PYQT_VERSION else ('PySide ' + PYSIDE_VERSION)}\n"
|
|
f"GUI preferences file: {self.qsettings.fileName()}\n"
|
|
f"Block paths:\n\t{paths}\n"
|
|
f"Using {QtGui.QIcon.themeName()} icon theme\n"
|
|
)
|
|
log.info(textwrap.dedent(welcome))
|
|
|
|
log.debug(f'devicePixelRatio {self.MainWindow.screen().devicePixelRatio()}')
|
|
|
|
if (self.qsettings.value("appearance/theme", "dark") == "dark") and (self.theme == "light"):
|
|
log.warning("Could not apply dark theme. Is QDarkStyle installed?")
|
|
|
|
# Global registration functions
|
|
# - Handles the majority of child controller interaciton
|
|
|
|
def registerSignal(self, signal):
|
|
pass
|
|
|
|
def registerDockWidget(self, widget, location=0):
|
|
"""Allows child controllers to register a widget that can be docked in the main window"""
|
|
# TODO: Setup the system to automatically add new "Show <View Name>" menu items when a new
|
|
# dock widget is added.
|
|
log.debug(
|
|
"Registering widget ({0}, {1})".format(widget.__class__.__name__, location)
|
|
)
|
|
self.MainWindow.registerDockWidget(location, widget)
|
|
|
|
def registerMenu(self, menu):
|
|
"""Allows child controllers to register an a menu rather than just a single action"""
|
|
# TODO: Need to have several capabilities:
|
|
# - Menu's need the ability to have a priority for ordering
|
|
# - When registering, the controller needs to specific target menu
|
|
# - Automatically add seporators (unless it is the first or last items)
|
|
# - Have the ability to add it as a sub menu
|
|
# - MainWindow does not need to call register in the app controller. It can call directly
|
|
# - Possibly view sidebars and toolbars as submenu
|
|
# - Have the ability to create an entirely new menu
|
|
log.debug("Registering menu ({0})".format(menu.title()))
|
|
self.MainWindow.registerMenu(menu)
|
|
|
|
def registerAction(self, action, menu):
|
|
"""Allows child controllers to register a global action shown in the main window"""
|
|
pass
|
|
|
|
def run(self):
|
|
"""Launches the main QT event loop"""
|
|
# Show the main window after everything is initialized.
|
|
self.MainWindow.show()
|
|
return self.exec_()
|