-
Allen, Bruce (CIV) authoredAllen, Bruce (CIV) authored
gui_manager.py 35.19 KiB
import os
from glob import glob
import signal
import json
import webbrowser
from PySide6.QtWidgets import QStyle # for PM_ScrollBarExtent
from PySide6.QtWidgets import QLabel
from PySide6.QtWidgets import QMenu
from PySide6.QtWidgets import QWidget, QSizePolicy
from PySide6.QtWidgets import QPlainTextEdit
from PySide6.QtCore import Qt
from PySide6.QtCore import QObject
from PySide6.QtCore import Slot
from PySide6.QtGui import QIcon
from PySide6.QtGui import QAction
from PySide6.QtGui import QGuiApplication
from mp_main_window import MPMainWindow
from version_file import VERSION
import resources_rc
from main_splitter import MainSplitter
from mp_code_column import MPCodeColumn
from navigation_column import NavigationColumn
from graph_list_selection_spinner import GraphListSelectionSpinner
from main_graph_scene import MainGraphScene
from main_graph_view import MainGraphView
from graph_list_view import GraphListView
from navigation_column_width_manager import NavigationColumnWidthManager
from scope_spinner import ScopeSpinner
from graph_metadata_label import GraphMetadataLabel
from graphs_manager import GraphsManager
from mp_code_manager import MPCodeManager
from mp_code_view import MPCodeView
from edit_menu import EditMenu
from code_editor_menu import make_code_editor_menu
from gry_manager import GryManager
from settings_themes_menu import SettingsThemesMenu
from socket_client_endpoint_menu import SocketClientEndpointMenu
from graph_pane_menu import GraphPaneMenu
from export_trace_manager import ExportTraceManager
from mp_logger import set_logger_targets, log, log_to_pane, log_to_statusbar, \
clear_log, begin_timestamps, timestamp, show_timestamps
from mp_style import mp_menu_button, MenuBarStatusTipEventRemover
import mp_json_io_manager
from trace_generator_manager import TraceGeneratorManager, \
TraceGeneratorCallback
from preferences import preferences
from preferences_manager import PreferencesManager
from settings import settings
from settings_manager import SettingsManager
from spellcheck_manager import SpellcheckManager
from session_persistence import SessionPersistence
from session_snapshots import SessionSnapshots
from session_snapshots_dialog_wrapper import snapshot_files
from keyboard_shortcuts_dialog import KeyboardShortcutsDialog
from about_mp_dialog_wrapper import AboutMPDialogWrapper
from search_mp_files_dialog_wrapper import SearchMPFilesDialogWrapper
from model_statistics_dialog import ModelStatisticsDialog
from tg_to_gry import tg_to_gry_graphs
from empty_graph import empty_graph
from paths_trace_generator import trace_generator_paths
from paths_trace_generator_manager import change_trace_generator_paths
from paths_examples import is_bundled, \
examples_paths, \
change_examples_paths, \
schedule_validate_examples_paths
from paths_gryphon import TRACE_GENERATED_OUTFILE_GRY
from examples_menu import fill_examples_menu
from message_popup import message_popup
from discard_existing_mp import DiscardExistingMP
from startup_options import parse_startup_options
from mp_file_dialog import get_open_file_name, get_save_file_name, \
get_existing_directory
from mp_code_event_dict import mp_code_schema
from verbose import verbose
class GUIManager(QObject):
"""MP main window containing menu, toolbar, statusbar, and central widget.
Central widget contains split pane areas, ref. http://firebird.nps.edu/:
code_area
console_area
graph_area
navigation_column
"""
def __init__(self, application):
super(GUIManager, self).__init__()
self.application = application
# the main window
self.w = MPMainWindow(self)
self.w.setWindowTitle("Monterey Phoenix v4 - Gryphon GUI %s"%VERSION)
self.w.setWindowIcon(QIcon(":/icons/mp_logo"))
# user preferences manager
self.preferences_manager = PreferencesManager(self)
# graph settings manager
self.settings_manager = SettingsManager(self.w,
self.preferences_manager.signal_preferences_changed)
# session persistence
self.session_persistence = SessionPersistence(self)
# session snapshots
self.session_snapshots = SessionSnapshots(self)
# spellcheck manager
self.spellcheck_manager = SpellcheckManager(self.w)
# the graphs manager
self.graphs_manager = GraphsManager(self.settings_manager)
# the graph list width manager
self.navigation_column_width_manager = NavigationColumnWidthManager(
self.w.style().pixelMetric(
QStyle.PixelMetric.PM_ScrollBarExtent))
# the main splitter which emits size_changed
self.main_splitter = MainSplitter(self.navigation_column_width_manager)
# the graph list view
self.graph_list_view = GraphListView(
self.main_splitter,
self.graphs_manager,
self.navigation_column_width_manager,
self.settings_manager.signal_settings_changed,
self.preferences_manager)
# the main graph scene and view
self.main_graph_view = MainGraphView(
self.graphs_manager.signal_graphs_loaded)
self.graph_pane_menu = GraphPaneMenu(self)
self.main_graph_scene = MainGraphScene(self.graphs_manager,
self.graph_list_view,
self.settings_manager,
self.graph_pane_menu)
self.main_graph_view.setScene(self.main_graph_scene)
self.main_graph_view.scale_view(preferences["graph_pane_scale"])
# the schema name and scope metadata label
self.graph_metadata_label = GraphMetadataLabel(self.graphs_manager)
# the statusbar
self.statusbar = self.w.statusBar()
self.statusbar.addPermanentWidget(self.graph_metadata_label.status_text)
self.statusbar.showMessage("Open, Import, or Compose MP Code to begin.")
# the log pane and the logger
self.log_pane = QPlainTextEdit()
self.log_pane.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
self.log_pane.setReadOnly(True)
set_logger_targets(self.statusbar, self.log_pane)
# the trace generator manager which runs the compiler asynchronously
self.trace_generator_callback = TraceGeneratorCallback()
self.trace_generator_manager = TraceGeneratorManager(
self.trace_generator_callback.send_signal)
self.trace_generator_callback.signal_compile_response.connect(
self.response_compile_mp_code)
# the MP Code manager
self.mp_code_manager = MPCodeManager(
self.preferences_manager.signal_preferences_changed,
self.settings_manager.signal_settings_changed,
self.spellcheck_manager.signal_spellcheck_changed,
self.statusbar)
# persistent dialogs
self.search_mp_files_dialog_wrapper = SearchMPFilesDialogWrapper(
self.w,
self.preferences_manager.signal_preferences_changed,
self.settings_manager.signal_settings_changed,
self.spellcheck_manager.signal_spellcheck_changed,
self.open_mp_code)
self.model_statistics_dialog = ModelStatisticsDialog(
self.w, self.graphs_manager,
self.mp_code_manager.signal_mp_code_loaded,
self.preferences_manager.signal_preferences_changed)
self.discard_existing_mp = DiscardExistingMP(self)
# the two MP Code editor view windows
self.mp_code_view_1 = MPCodeView(self.mp_code_manager,
self.preferences_manager,
self.spellcheck_manager,
self.search_mp_files_dialog_wrapper.action_search_mp_files,
self.application,
1)
self.mp_code_view_2 = MPCodeView(self.mp_code_manager,
self.preferences_manager,
self.spellcheck_manager,
self.search_mp_files_dialog_wrapper.action_search_mp_files,
self.application,
2)
# .gry manager
self.gry_manager = GryManager(self.w, self.graphs_manager,
self.mp_code_manager,
self.graph_list_view,
self.settings_manager,
self.discard_existing_mp)
# the scope spinner containing spinner=QSpinBox
self.scope_spinner = ScopeSpinner(
self.mp_code_manager.signal_mp_code_loaded)
# export trace manager
self.export_trace_manager = ExportTraceManager(self.w,
self.graphs_manager,
self.graph_list_view,
application)
# graph list selection spinner
self.graph_list_selection_spinner = GraphListSelectionSpinner(
self.graph_list_view)
# the central widget containing the main split pane
self.mp_code_column = MPCodeColumn(self)
self.mp_code_column.set_splitter_sizes(
preferences["code_column_splitter_sizes"])
self.navigation_column = NavigationColumn(self)
self.main_splitter.addWidget(self.mp_code_column)
self.main_splitter.addWidget(self.main_graph_view)
self.main_splitter.addWidget(self.navigation_column)
self.main_splitter.setSizes(preferences["main_splitter_sizes"])
self.w.setCentralWidget(self.main_splitter)
# actions and menus
self.define_actions()
self.define_menus()
# the toolbar
self.add_toolbar()
# current compile state for buttons
self.set_is_compiling(False)
# state for preference actions
self.preferences_manager.set_action_states()
# do these before shutdown
application.aboutToQuit.connect(
self.trace_generator_manager.mp_clean_shutdown)
application.aboutToQuit.connect(
self.preferences_manager.save_preferences)
application.aboutToQuit.connect(
self.session_persistence.save_this_session)
application.aboutToQuit.connect(self._clear_clipboard)
# get command line options
parse_startup_options(self)
# enqueue actions to start on Qt event loop
if not is_bundled():
schedule_validate_examples_paths(self.w)
self.w.show()
# accept Ctrl C
signal.signal(signal.SIGINT, self.make_ctrl_c_closure_function())
@Slot()
def _clear_clipboard(self):
# Qt crashes with:
# QFontDatabase: Must construct a QGuiApplication before accessing
# QFontDatabase
# Aborted (core dumped)
# so we clear it when Gryphon closes to avoid this crash.
QGuiApplication.clipboard().clear()
# enable graceful exit by Ctrl C
def make_ctrl_c_closure_function(self):
# signal handler for signal.signal
def ctrl_c_closure_function(_signal, _frame):
print("Ctrl C exit")
self.w.close()
return ctrl_c_closure_function
# actions
def define_actions(self):
# action exit
self.action_exit = QAction(QIcon(":/icons/exit"), "&Exit", self.w)
self.action_exit.setShortcut('Ctrl+Q')
self.action_exit.setToolTip("Exit MP")
self.action_exit.triggered.connect(self.w.close)
# action keyboard_shortcuts
self.action_keyboard_shortcuts = QAction("&Keyboard Shortcuts", self.w)
self.action_keyboard_shortcuts.setToolTip(
"Keyboard shorcuts for MP controls")
self.action_keyboard_shortcuts.triggered.connect(
self.keyboard_shortcuts)
# action about
self.action_about = QAction(QIcon(":/icons/about_mp"),
"&About MP", self)
self.action_about.setToolTip("about MP")
self.action_about.triggered.connect(self.about_mp)
# action report an issue
self.action_report_an_issue = QAction("Report an issue...", self)
self.action_report_an_issue.setToolTip("Report an issue about MP")
self.action_report_an_issue.triggered.connect(self.report_an_issue)
# action run/cancel
self.action_run_cancel = QAction(self)
self.action_run_cancel.setToolTip("Generate traces from MP Code")
self.action_run_cancel.triggered.connect(
self._run_cancel_compile_mp_code)
# action show model statistics
self.action_show_model_statistics = QAction(
QIcon(":/icons/show_model_statistics"),
"&Show model statistics...", self)
self.action_show_model_statistics.setToolTip(
"Show statistics about models")
self.action_show_model_statistics.triggered.connect(
self._show_model_statistics)
# action clear log
self.action_clear_log = QAction(QIcon(":/icons/clear_log"),
"&Clear status log", self)
self.action_clear_log.setToolTip("Clear the status log pane")
self.action_clear_log.triggered.connect(clear_log)
# action open MP Code file
self.action_open_mp_code_file = QAction(QIcon(":/icons/open"),
"&Open .mp...", self)
self.action_open_mp_code_file.setToolTip("Open MP Code File")
self.action_open_mp_code_file.triggered.connect(
self.select_and_open_mp_code_file)
# action close MP Code file
self.action_close_mp_code_file = QAction(QIcon(":/icons/close"),
"Close .mp", self)
self.action_close_mp_code_file.setToolTip("Close MP Code File")
self.action_close_mp_code_file.triggered.connect(self.close_mp_code)
# action save MP Code file
self.action_save_mp_code_file = QAction(QIcon(":/icons/save"),
"&Save .mp...", self)
self.action_save_mp_code_file.setShortcut('Ctrl+S')
self.action_save_mp_code_file.setToolTip("Save MP Code file")
self.action_save_mp_code_file.triggered.connect(
self.save_mp_code_file)
# action settings trace generator path...
self.action_trace_generator_path = QAction(
"Trace Generator Path...", self)
self.action_trace_generator_path.setToolTip(
"Set the path to the trace-generator")
self.action_trace_generator_path.triggered.connect(
self.select_trace_generator_path)
# action settings preloaded examples path...
self.action_examples_path = QAction(
"Preloaded Examples Path...", self)
self.action_examples_path.setToolTip(
"Set the path to preloaded examples")
self.action_examples_path.triggered.connect(
self.select_examples_path)
self.action_examples_path.setDisabled(is_bundled())
def _configure_settings_menu(self):
self.settings_manager.action_show_type_1_probability.setChecked(
settings["trace_show_type_1_probability"])
def _fill_examples_menu(self):
if os.path.exists(examples_paths["models"]):
fill_examples_menu(self.open_examples_menu,
examples_paths["models"],
self.open_mp_code)
else:
print("Examples path is not configured.")
def _enable_manage_snapshots(self):
has_snapshots = bool(len(snapshot_files()))
self.session_snapshots.action_manage_snapshots.setDisabled(
not has_snapshots)
# menus
def define_menus(self):
menubar = self.w.menuBar()
menubar.setNativeMenuBar(False)
menubar.installEventFilter(MenuBarStatusTipEventRemover(self.w))
# menu | file
self.file_menu = QMenu("&File")
menubar.addMenu(self.file_menu)
self.file_menu.aboutToShow.connect(
self._enable_manage_snapshots)
# menu | file | open
self.file_menu.addAction(self.action_open_mp_code_file)
# menu | file | open examples
self.open_examples_menu = QMenu("Open Example")
self.open_examples_menu.setToolTip("Open MP Code Example")
self.open_examples_menu.aboutToShow.connect(
self._fill_examples_menu)
# menu | file | save MP Code
self.file_menu.addAction(self.action_save_mp_code_file)
# menu | file | close
self.file_menu.addAction(self.action_close_mp_code_file)
# menu | file | separator
self.file_menu.addSeparator()
# menu | file | open examples
self.file_menu.addMenu(self.open_examples_menu)
# menu | file | search .mp files
self.file_menu.addAction(
self.search_mp_files_dialog_wrapper.action_search_mp_files)
# menu | file | separator
self.file_menu.addSeparator()
# menu | file | Save snapshot
self.file_menu.addAction(self.session_snapshots.action_take_snapshot)
# menu | file | Manage snapshots
self.file_menu.addAction(self.session_snapshots.action_manage_snapshots)
# menu | file | session persistence
self.file_menu.addAction(
self.session_persistence.action_restore_previous_session)
# menu | file | separator
self.file_menu.addSeparator()
# menu | file | import Gryphon Graph file
self.file_menu.addAction(self.gry_manager.action_import_gry_file)
# menu | file | export Gryphon Graph file
self.file_menu.addAction(self.gry_manager.action_export_gry_file)
# menu | file | separator
self.file_menu.addSeparator()
# menu | file | export trace
self.file_menu.addAction(self.export_trace_manager.action_export_trace)
# menu | file | export all traces
self.file_menu.addAction(
self.export_trace_manager.action_export_all_traces)
# menu | file | separator
self.file_menu.addSeparator()
# menu | file | exit
self.file_menu.addAction(self.action_exit)
# menu | edit
self.edit_menu = menubar.addMenu(EditMenu(self))
# menu | actions
actions_menu = menubar.addMenu('&Actions')
# menu | actions | run
actions_menu.addAction(self.action_run_cancel)
# menu | actions | show model statistics
actions_menu.addAction(self.action_show_model_statistics)
# menu | actions | clear log
actions_menu.addAction(self.action_clear_log)
# menu | settings
self.settings_menu = menubar.addMenu('&Settings')
self.settings_menu.aboutToShow.connect(self._configure_settings_menu)
# menu | settings | use dark mode
self.settings_menu.addAction(
self.preferences_manager.action_use_dark_mode)
# menu | settings | show type 1 probability
self.settings_menu.addAction(
self.settings_manager.action_show_type_1_probability)
# menu | settings | separator
self.settings_menu.addSeparator()
# menu | settings | themes
self.settings_themes_menu = SettingsThemesMenu(self.w,
self.settings_manager, self.graphs_manager)
self.settings_menu.addMenu(self.settings_themes_menu)
# menu | settings | code editor preferences
self._code_editor_menu = make_code_editor_menu(
self.preferences_manager, self.spellcheck_manager)
self.settings_menu.addMenu(self._code_editor_menu)
# menu | settings | graph pane preferences
self.settings_menu.addMenu(self.graph_pane_menu)
# menu | settings | graph list navigation pane preferences
self.settings_menu.addMenu(self.preferences_manager.graph_list_menu)
# menu | settings | reset GUI preferences
self.settings_menu.addAction(
self.preferences_manager.action_reset_preferences)
# menu | settings | separator
self.settings_menu.addSeparator()
# menu | settings | ignore model statistics warnings
self.settings_menu.addAction(self.model_statistics_dialog
.action_ignore_model_statistics_warnings)
# menu | settings | separator
self.settings_menu.addSeparator()
# menu | settings | Gryphon configuration
gryphon_configuration_menu = self.settings_menu.addMenu(
'Gryphon configuration')
gryphon_configuration_menu.addAction(self.action_trace_generator_path)
gryphon_configuration_menu.addAction(self.action_examples_path)
self.socket_client_endpoint_menu = SocketClientEndpointMenu()
gryphon_configuration_menu.addMenu(self.socket_client_endpoint_menu)
# menu | help
help_menu = menubar.addMenu('&Help')
help_menu.addAction(self.action_about)
help_menu.addAction(self.action_keyboard_shortcuts)
help_menu.addAction(self.action_report_an_issue)
# the toolbar
def add_toolbar(self):
toolbar = self.w.addToolBar("MP_Py Toolbar")
toolbar.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
self.open_menu = QMenu()
self.open_menu.addAction(self.action_open_mp_code_file)
self.open_menu.addMenu(self.open_examples_menu)
self.open_menu.addAction(
self.search_mp_files_dialog_wrapper.action_search_mp_files)
self.open_menu_button = mp_menu_button(self.open_menu,
QIcon(":/icons/open"),
"Open",
"Open MP schema file")
toolbar.addWidget(self.open_menu_button)
toolbar.addSeparator()
toolbar.addAction(self.action_run_cancel)
toolbar.addSeparator()
toolbar.addWidget(QLabel("Scope"))
toolbar.addWidget(self.scope_spinner.spinner)
toolbar.addSeparator()
toolbar.addWidget(self.main_graph_scene.trace_event_menu \
.trace_event_menu_button)
toolbar.addSeparator()
toolbar.addAction(self.graph_pane_menu.action_zoom_in)
toolbar.addAction(self.graph_pane_menu.action_zoom_out)
toolbar.addAction(self.graph_pane_menu.action_zoom_reset)
# far right side
spacer = QWidget()
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
toolbar.addWidget(spacer)
toolbar.addAction(self.preferences_manager.action_use_dark_mode)
############################################################
# action handlers
############################################################
# Keyboard Shortcuts...
@Slot()
def keyboard_shortcuts(self):
dialog = KeyboardShortcutsDialog(self.w)
dialog.show()
# About MP...
@Slot()
def about_mp(self):
wrapper = AboutMPDialogWrapper(self.w)
wrapper.show()
# Report an issue...
@Slot()
def report_an_issue(self):
text = "To report an issue please open the Monterey Phoenix Gryphon " \
"issue tracker at " \
"https://gitlab.nps.edu/monterey-phoenix/user-interfaces" \
'/gryphon/-/issues and click the "New issue" button.\n\n' \
"Please include the version of the Operating System you are " \
"using and that you are using Gryphon %s. " \
"If possible, please include a screen capture.\n\n" \
"Please de-identify screen capture and other " \
"submitted information as issues and related comments are " \
"public."%VERSION
message_popup(self.w, text)
# Open MP Code file
@Slot()
def select_and_open_mp_code_file(self):
filename = get_open_file_name(self.w,
"Open MP Code file",
preferences["preferred_mp_code_dir"],
"MP Code files (*.mp);;All Files (*)")
if filename:
# remember the preferred path
head, _tail = os.path.split(filename)
preferences["preferred_mp_code_dir"] = head
# open the file
self.open_mp_code(filename)
else:
status = "Open filename not selected."
log(status)
# Save MP Code file
@Slot()
def save_mp_code_file(self):
# suggested filename
mp_code_text = self.mp_code_manager.text()
schema_name = mp_code_schema(mp_code_text)
suggested_filename = "%s.mp" % schema_name
mp_code_filename = get_save_file_name(self.w,
"Save MP Code file",
os.path.join(preferences["preferred_mp_code_dir"],
suggested_filename),
"MP Code files (*.mp);;All Files (*)")
if mp_code_filename:
# remember the preferred path
head, _tail = os.path.split(mp_code_filename)
preferences["preferred_mp_code_dir"] = head
# save the file
status = mp_json_io_manager.save_mp_code_file(
mp_code_text, mp_code_filename)
if status:
# log failure
log(status)
else:
# great, exported.
log("Saved to file %s" % mp_code_filename)
# callers don't usually care about status
return status
else:
status = "Save filename not selected."
log(status)
return status
# Find MP code file
@Slot()
def find_mp_code_file(self):
wrapper = FindMPFileDialogWrapper(self.w)
wrapper.show()
@Slot()
def select_trace_generator_path(self):
path = get_existing_directory(self.w,
"Select the path to the MP trace-generator",
trace_generator_paths["trace_generator_root"])
if path:
change_trace_generator_paths(self.w, path)
@Slot()
def select_examples_path(self):
path = get_existing_directory(self.w,
"Select the path to the preloaded examples",
examples_paths["examples_root"])
if path:
change_examples_paths(self.w, path)
############################################################
# primary interfaces
############################################################
# open MP Code file
def open_mp_code(self, mp_code_filename):
# maybe abort request
status = self.discard_existing_mp.check()
if status:
log(status)
return
status, mp_code_text = mp_json_io_manager.read_mp_code_file(
mp_code_filename)
if status:
# log failure
log(status)
else:
# accept request
log("Opened MP Code file %s" % mp_code_filename)
# set mp code
self.mp_code_manager.set_text(mp_code_text)
# clear the selection
self.graph_list_view.select_graph_index(-1)
# clear the graph
self.graphs_manager.clear_graphs()
# Close MP Code file
@Slot()
def close_mp_code(self):
# maybe abort request
status = self.discard_existing_mp.check()
if status:
log(status)
return
# set mp code
self.mp_code_manager.set_text("")
# clear the selection
self.graph_list_view.select_graph_index(-1)
# clear the graph
self.graphs_manager.clear_graphs()
# compile MP Code
def _request_compile_mp_code(self):
# state at start of compilation
self._proposed_mp_code = self.mp_code_manager.text()
self._proposed_scope = self.scope_spinner.scope()
self._proposed_schema_name = mp_code_schema(self._proposed_mp_code)
self._proposed_settings = settings.copy()
self._existing_mp_code = self.graphs_manager.mp_code
self._existing_graphs = self.graphs_manager.graphs
self._existing_scope = self.graphs_manager.scope
self._existing_selected_graph_index \
= self.graph_list_view.selected_graph_index()
# set visual state
self.set_is_compiling(True)
# begin compilation
action = "Compiling %s scope %d..."%(self._proposed_schema_name,
self._proposed_scope)
log_to_statusbar(action)
begin_timestamps(action)
self.trace_generator_manager.mp_compile(
self._proposed_schema_name,
self._proposed_scope,
self._proposed_mp_code)
# clear the selected graph and the graphs
self.graph_list_view.select_graph_index(-1)
self.graphs_manager.clear_graphs()
# receive trace-generated json from the compiled MP Code
@Slot(str, dict, str)
def response_compile_mp_code(self, status, tg_data, _log):
# restore visual state
self.set_is_compiling(False)
# disable run button while initializing response
self.action_run_cancel.setDisabled(True)
# log the compilation log
log_to_pane(_log)
timestamp("Received compilation response")
# compensate for invalid empty JSON that the trace generator
# returns when no traces are generated
if status == "Error running trace-generator: Expecting" \
" value: line 1 column 1 (char 0)":
if verbose():
log(status)
status = ""
if status:
# log failure
log(status)
else:
# accept graphs
gry_graphs = tg_to_gry_graphs(tg_data)
timestamp("Created gry from tg")
log("Compiled %s"%self._proposed_schema_name)
# gry data
self.graphs_manager.set_graphs(
self._proposed_mp_code,
gry_graphs,
self._proposed_scope,
)
timestamp("Created graphs from gry")
# the default selected graph index is 1 else 0
if "traces" in tg_data and len(tg_data["traces"]) > 0:
selected_graph_index = 1
else:
selected_graph_index = 0
self.graph_list_view.select_graph_index(selected_graph_index)
# for diagnostics only, and only if it is not large,
# maybe write the generated .gry JSON, indented with sorted keys
with open(TRACE_GENERATED_OUTFILE_GRY, "w", encoding='utf-8') as f:
if len(gry_graphs) < 1000:
# prepare the generated .gry JSON, indented with sorted keys
gry_data = {
"mp_code":self._proposed_mp_code,
"graphs":gry_graphs,
"scope":self._proposed_scope,
"selected_graph_index":selected_graph_index,
"settings":self._proposed_settings,
}
else:
# too many graphs so prepare .gry without graphs
print("Note: Large graph size %d, graphs not written"
%len(gry_graphs))
gry_data = {
"mp_code":self._proposed_mp_code,
"graphs":[empty_graph()],
"scope":self._proposed_scope,
"selected_graph_index":-1,
"settings":self._proposed_settings,
}
json.dump(gry_data, f, indent=4, sort_keys=True)
# reenable run button after initializing response
self.action_run_cancel.setDisabled(False)
# set visual state
self.set_is_compiling(False)
show_timestamps()
# cancel compile MP Code
def _cancel_compile_mp_code(self):
# cancel compilation
log("Canceling compiling %s" % self._proposed_schema_name)
self.trace_generator_manager.mp_cancel_compile()
# restore graph data and the selected graph
self.graphs_manager.restore_graphs(self._existing_mp_code,
self._existing_graphs,
self._existing_scope)
self.graph_list_view.select_graph_index(
self._existing_selected_graph_index)
def _run_cancel_compile_mp_code(self):
if self._is_compiling:
self._cancel_compile_mp_code()
else:
self._request_compile_mp_code()
def _show_model_statistics(self):
self.model_statistics_dialog.show()
def _set_run_cancel_button_state(self):
if self._is_compiling:
self.action_run_cancel.setIcon(QIcon(":/icons/cancel"))
self.action_run_cancel.setText("Stop")
else:
self.action_run_cancel.setIcon(QIcon(":/icons/run"))
self.action_run_cancel.setText("Run")
# run and cancel widget state
def set_is_compiling(self, is_compiling):
self._is_compiling = is_compiling
# run/cancel
self._set_run_cancel_button_state()
# other actions and menus
self.action_open_mp_code_file.setDisabled(is_compiling)
self.action_close_mp_code_file.setDisabled(is_compiling)
self.open_examples_menu.setDisabled(is_compiling)
self.gry_manager.action_import_gry_file.setDisabled(is_compiling)
self.gry_manager.action_export_gry_file.setDisabled(is_compiling)
self.export_trace_manager.action_export_trace.setDisabled(is_compiling)
self.export_trace_manager.action_export_all_traces.setDisabled(
is_compiling)
self.open_menu_button.setDisabled(is_compiling)
self.main_graph_scene.trace_event_menu.trace_event_menu_button \
.setDisabled(is_compiling)
self.scope_spinner.spinner.setDisabled(is_compiling)