✨Simulation view redesign with simulation run add, edit, import, export and execution functionality#522
Conversation
…it search controls and modified alignments for qubit value edit controls
… instead of model-view architecture of simulation run list
…uns instead of widget based design
…elegate overwrite
…ialog into separate files. Setup basic simulation run controls and layout
…runs execution controls
…urther model properties required for other Qt 'components'
…icking edit selected item in simulation run overview. However, dialog does not update internal model.
… completers to search controls of the latter
…run editor dialog
…lidation and automatic input field resizing
…s of remaining quantum registers as well as disabling the save button of the edit dialog
…and functionality to clear model as well as generate all possible input state combinations in model
…n dialog, fixed extraction of qubit values from n_bit_values_container and added dynamic column width to simulation run QStyledItemDelegate
…o base class and 'promoted' constants from class member variables to free variables
…s regarding simulation run tab widget as well as card headers in styled item delegates
…ead of executing operation on UI thread
… to the all input states generator dialog, however rendering is still laggy/sluggish
… Added artifically delay to input states generator to improve UI responsiveness
…ly resets dialog instance. Update closeEvent implementaiton in AllInputStatesGeneratorDialog. Fixed required height calculation in simulation run execution styled item delegate
…un instead of working directly on the latter.
…t to load simulation runs from file button
…es not being considered as ancillary qubits
There was a problem hiding this comment.
Actionable comments posted: 14
🤖 Fix all issues with AI agents
In `@python/mqt/syrec/logger_utils.py`:
- Around line 29-31: Fix the typo "can be advances further" → "can be advanced
further" in the comments above each of the four logging wrapper functions;
locate the comments next to the logger.* calls (e.g., the
logger.debug/info/warning/error calls that pass stacklevel with
num_additionally_skipped_stack_frames_starting_from_caller_function) and update
the wording to "can be advanced further".
- Around line 15-31: configure_default_console_logger currently calls
logging.basicConfig (configuring the root logger) while the code uses a named
logger DEFAULT_LOGGER_NAME; change configure_default_console_logger to configure
the named logger directly: obtain logger =
logging.getLogger(DEFAULT_LOGGER_NAME), remove/clear any existing handlers on
that logger, set logger.setLevel(logging.DEBUG), create a StreamHandler with the
same formatter (use the existing format and datefmt), add the handler to the
named logger and (optionally) set logger.propagate = False so messages aren't
duplicated; leave log_debug_to_console as-is using DEFAULT_LOGGER_NAME.
In `@python/mqt/syrec/quantum_circuit_simulation_dialog.py`:
- Around line 794-800: Remove the dead standalone cast call that discards its
result: delete the expression cast("QtWidgets.QTabWidget",
optional_curr_active_tab_widget). If the intent was to type the value, replace
it by assigning the casted value to a variable (e.g., curr_active_tab_widget:
Final[QtWidgets.QTabWidget] = cast("QtWidgets.QTabWidget",
optional_curr_active_tab_widget)); otherwise simply remove the unused cast to
avoid the no-op.
- Around line 1196-1220: The method _determine_num_non_ancillary_qubits
currently inverts the check and accumulates into num_ancillary_qubits; rename
the accumulator to num_non_ancillary_qubits, remove the negation so you
increment when
QuantumCircuitSimulationDialog._does_qubit_label_start_with_internal_qubit_label_prefix(fetched_qubit_label)
is True (i.e., label starts with "__q"), and return num_non_ancillary_qubits;
keep the early error handling for fetched_qubit_label unchanged.
In `@python/mqt/syrec/simulation_view/dialogs/base_progress_dialog.py`:
- Around line 173-178: BaseProgressDialog currently calls
self._handle_non_recoverable_error but doesn't define it, so add an abstract
method declaration to BaseProgressDialog to enforce implementation in
subclasses: make BaseProgressDialog inherit from abc.ABC (or typing.Protocol)
and declare def _handle_non_recoverable_error(self, message: str) -> None as an
`@abstractmethod` (or protocol method) so subclasses must implement it; reference
the BaseProgressDialog class and the _handle_non_recoverable_error method in
your changes.
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_dialog.py`:
- Around line 419-422: The code is passing result.sim_runtime_in_ms
(milliseconds) into methods that expect seconds; change the calls around
_update_total_model_runtime_and_label and _accumulate_and_update_total_runtime
to convert milliseconds to seconds (divide the sim_runtime_in_ms value by
1000.0) before passing it so the label and accumulators use seconds
consistently.
In
`@python/mqt/syrec/simulation_view/dialogs/simulation_run_json_import_dialog.py`:
- Around line 192-194: The code updates the progress bar using a non-existent
attribute self.num_generated_input_states which will raise AttributeError;
replace that reference with the dialog's tracked counter attribute used
elsewhere in this class (e.g. the internal counter like
self._num_generated_states or self._generated_input_states) when setting
self._progress_bar.setValue(...), and ensure you fall back to 0 if that
attribute is missing (or initialize the tracked counter in the dialog); update
the block that touches self._progress_bar and self._progress_info_text_lbl
accordingly so it uses the existing tracked counter instead of
self.num_generated_input_states.
In `@python/mqt/syrec/simulation_view/simulation_run_model.py`:
- Around line 363-364: The is_model_index_valid method currently redundantly
checks index.row() >= 0; simplify the condition by relying on index.isValid()
(which already implies a non-negative row) and only explicitly check the upper
bound against len(self._simulation_run_models); update the return to: return
index.isValid() and index.row() < len(self._simulation_run_models) (retain the
existing # type: ignore comment if needed).
In
`@python/mqt/syrec/simulation_view/styled_item_delegates/simulation_run_overview_styled_item_delegate.py`:
- Around line 314-357: Change the signature of _draw_card_border_and_header to
make draw_rect_corners a keyword-only parameter (e.g. introduce a
positional-only separator or a bare * before draw_rect_corners) so the boolean
default is not accepted positionally; update the function definition for
SimulationRunOverviewStyledItemDelegate._draw_card_border_and_header accordingly
and confirm any callers (e.g. places that call _draw_card_border_and_header or
the two internal calls to _paint_rect_edge_points) use the keyword form or rely
on the default—adjust any positional boolean usages to use draw_rect_corners=...
to satisfy Ruff FBT001/FBT002.
In
`@python/mqt/syrec/simulation_view/workers/all_input_states_generator_worker.py`:
- Around line 46-48: The comment about "32 bit integer overflow" is misleading
because Python integers are arbitrary-precision; update the comment around
n_states_to_generate (computed as 2**self._expected_input_state_size) to either
remove the overflow remark or replace it with a clear warning that the real
concern is exponential growth in memory/time for large
self._expected_input_state_size (and that the caller must validate/limit sizes
to avoid huge allocations or long runtimes).
In `@python/mqt/syrec/simulation_view/workers/cancellable_worker_variants.py`:
- Line 63: Remove the unnecessary noqa directives from the signal declarations
(e.g., the batchCompleted = QtCore.pyqtSignal(float) line in
cancellable_worker_variants.py and the other occurrence around line 141);
specifically delete the " # noqa: N815" suffix so the signal definitions read
simply as "batchCompleted = QtCore.pyqtSignal(float)" (and similarly for the
other signal), since N815 is not enabled and the noqa is redundant.
In
`@python/mqt/syrec/simulation_view/workers/simulation_run_json_import_worker.py`:
- Around line 19-30: Remove the import-time side effect by deleting the call to
configure_default_console_logger() inside the ImportError fallback in
simulation_run_json_import_worker.py; keep the ImportError handler but only call
log_error_to_console("yajl2 C-extension not available, falling back to
pure-Python parser!") and then import ijson, so logging configuration remains
the application's responsibility and no root logger reconfiguration happens
during module import.
In `@python/mqt/syrec/simulation_view/workers/simulation_run_worker.py`:
- Around line 82-84: The recv queue get call uses recv_queue.get(block=False,
timeout=0.2) where timeout is ignored; update the recv_queue.get invocations in
simulation_run_worker (function/method containing dequeued_sim_run_model) and
the similar call in simulation_run_json_export_worker to either remove the
timeout argument when using block=False or change to block=True if a timeout is
desired—i.e., locate the recv_queue.get(...) calls and either call
recv_queue.get(block=False) or recv_queue.get(block=True, timeout=0.2)
consistently.
…correctly considers currently selected simulation run execution mode
…itting batchCompleted signal
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Fix all issues with AI agents
In `@python/mqt/syrec/quantum_circuit_simulation_dialog.py`:
- Around line 169-174: Add a positional-only barrier (`*,`) to make the boolean
parameters keyword-only in the three methods:
initialize_simulation_runs_tab_widget (make create_load_from_file_controls
keyword-only),
set_enabled_state_of_simulation_run_execution_controls_in_tab_widget (make its
boolean param keyword-only), and
set_enabled_state_of_simulation_run_execution_controls_in_tab_widget_based_on_sim_run_selection_status
(make its boolean param keyword-only); then update all call sites that pass
literal True/False to these functions to pass the booleans by name (e.g.,
create_load_from_file_controls=True and enabled=True or the actual boolean
parameter name used in the callee) so the calls match the new signature.
In `@python/mqt/syrec/simulation_view/dialogs/base_progress_dialog.py`:
- Around line 58-66: Make all boolean parameters keyword-only by adding a
positional-only splitter (*) in the BaseProgressDialog.__init__ signature (so
booleans like create_default_layout and center_dialog cannot be passed
positionally) and similarly adjust any other functions in this file that take
boolean parameters to use the same pattern; then update every call site in the
subclasses SimulationRunJsonImportDialog, SimulationRunJsonExportDialog,
SimulationRunDialog, and AllInputStatesGeneratorDialog to pass those booleans by
name (e.g., create_default_layout=True, center_dialog=False) instead of as
positional arguments so the FBT001/FBT002/FBT003 violations are resolved.
In
`@python/mqt/syrec/simulation_view/dialogs/simulation_run_json_import_dialog.py`:
- Around line 185-195: The code clears _progress_info_text_lbl immediately after
calling _update_progress_text_with_batch_info, which erases the batch message;
instead, remove the unconditional self._progress_info_text_lbl.setText("") and
only clear the progress info when the import is finished (e.g., when
self._num_imported_simulation_runs >= the total import count or inside the
existing completion/cleanup path). Keep calling
QtCore.QTimer.singleShot(DEFAULT_WORKER_CONTINUE_DELAY_IN_MS,
self._allow_worker_to_continue) as before; ensure the clearing logic references
the same completion condition used elsewhere (total count or
_on_import_complete) so the last batch message remains visible until completion.
In `@python/mqt/syrec/simulation_view/simulation_run_model.py`:
- Around line 54-105: Change the positional boolean params to keyword-only by
inserting a * in the function signatures for __init__ (make
create_new_n_bit_values_container_instances keyword-only),
reset_result_of_execution (reset_actual_output_state),
update_input_state_qubit_value (new_qubit_value),
update_expected_output_state_qubit_value (new_qubit_value),
_update_n_bit_values_container_qubit_value (new_qubit_value), and
update_model_using_simulation_run_result
(do_expected_and_actual_output_states_match); then update all call sites to pass
those booleans as keywords (e.g.,
create_new_n_bit_values_container_instances=True,
reset_actual_output_state=False, new_qubit_value=True,
do_expected_and_actual_output_states_match=True) including the references in
simulation_run_editor_dialog.py and simulation_run_dialog.py and any internal
callers of _update_n_bit_values_container_qubit_value.
In
`@python/mqt/syrec/simulation_view/workers/simulation_run_json_export_worker.py`:
- Around line 61-166: The comma logic writes a delimiter when
has_exported_first_batch is set at batch end, causing a leading comma if that
batch exported zero items; change to track whether any element has actually been
written (e.g., introduce has_written_any_element or total_exported_sim_runs
counter) and only write "," if that flag/counter > 0 right before serializing an
element; update the write spot that currently calls
SimulationRunJsonExportWorker._should_sim_run_export_delimiter_be_serialized to
use the new flag/counter, set the flag to True immediately after successful
file.write(json.dumps(...)) (not at batch completion), and remove the now-unused
_should_sim_run_export_delimiter_be_serialized usage and the assignment
has_exported_first_batch = True.
In
`@python/mqt/syrec/simulation_view/workers/simulation_run_json_import_worker.py`:
- Around line 130-168: The _try_deserialize_simulation_run function currently
assumes parsed_json_elem_values_dict[INPUT_STATE_JSON_KEY] and
parsed_json_elem_values_dict.get(EXPECTED_OUTPUT_STATE_JSON_KEY) are strings and
may raise TypeError; add explicit type checks before using len(...) or
iterating: verify stringified_input_state is instance of str (raise ValueError
with a clear message referencing INPUT_STATE_JSON_KEY) and if
stringified_expected_output_state is not None verify it is a str (raise
ValueError referencing EXPECTED_OUTPUT_STATE_JSON_KEY); keep the existing size
and character validations and then proceed to create NBitValuesContainer and set
bits as before (references: _try_deserialize_simulation_run,
INPUT_STATE_JSON_KEY, EXPECTED_OUTPUT_STATE_JSON_KEY, stringified_input_state,
stringified_expected_output_state).
In `@python/mqt/syrec/simulation_view/workers/simulation_run_worker.py`:
- Around line 37-78: Make the boolean parameter
stop_at_first_output_state_mismatch keyword-only: change
SimulationRunWorker.__init__ to accept stop_at_first_output_state_mismatch as a
keyword-only argument (e.g., add a * before keyword-only params) and update the
_should_continue_processing signature so any boolean flags are keyword-only as
well (add * before those boolean parameters); then update the
SimulationRunWorker instantiation in simulation_run_dialog.py to pass
stop_at_first_output_state_mismatch=..., and update the two internal calls to
_should_continue_processing in start_simulations to call it with named arguments
(e.g., found_outputs_mismatch=..., has_reached_end_sentinel=...,
stop_at_first_output_state_mismatch=...) so no boolean is passed positionally.
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Fix all issues with AI agents
In `@python/mqt/syrec/quantum_circuit_simulation_dialog.py`:
- Around line 924-928: The code incorrectly casts the object returned by
QTabWidget.widget() to QtWidgets.QTabWidget (e.g., variables
selected_filename_lbl and curr_active_tab_widget and usages inside
_clear_simulation_run_list_and_backing_model), but widget() returns a
QtWidgets.QWidget; change those casts and any type annotations from
QtWidgets.QTabWidget to QtWidgets.QWidget (and adjust variable names/usages if
needed) so the types accurately reflect QWidget; apply the same change for the
other occurrence around the _clear_simulation_run_list_and_backing_model usage
(the block referenced also at lines 1176-1181).
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_dialog.py`:
- Line 142: Calls to _change_dialog_ok_button_enable_state use positional
boolean literals; change these to use a keyword argument (e.g., enabled=True or
the actual parameter name from _change_dialog_ok_button_enable_state) so the
boolean is passed by name at both call sites in simulation_run_dialog.py (the
current True/False calls around the shown line and the other occurrence).
- Around line 144-149: The parameter stop_at_first_output_state_mismatch in
start_simulations is a positional boolean and must be made keyword-only: change
the function signature of start_simulations to force keyword-only parameters
(e.g., insert a bare * before stop_at_first_output_state_mismatch) so callers
cannot pass that boolean positionally, then update all call sites (notably the
call from QuantumCircuitSimulationDialog) to pass
stop_at_first_output_state_mismatch=<value> as a named argument; keep the
existing default values for sim_run_model_queue_batch_size and
sim_run_result_queue_batch_size unchanged.
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_editor_dialog.py`:
- Around line 453-461: For the three PyQt slot handlers, make boolean parameters
keyword-only to satisfy FBT001: in
_handle_input_state_qubit_value_checkbox_state_change and
_handle_expected_output_state_qubit_value_checkbox_state_change add a
positional-only marker (*) immediately before
update_associated_state_input_field so its signature becomes ... , *,
update_associated_state_input_field: bool = False, and in
_handle_input_or_output_state_text_change add * before is_editing_input_state so
that is_editing_input_state is keyword-only; then update any call
sites/callbacks that invoke _handle_input_or_output_state_text_change
(specifically the lambdas referenced around the previous lines 676 and 683) to
pass is_editing_input_state=is_editing_input_state as a keyword argument. Ensure
you only change the function signatures and call sites—no behavioral logic
changes.
In
`@python/mqt/syrec/simulation_view/dialogs/simulation_run_json_import_dialog.py`:
- Around line 144-145: Replace positional boolean literals in calls to
_change_dialog_cancel_button_enable_state with a keyword argument (e.g.,
_change_dialog_cancel_button_enable_state(enabled=True) and
_change_dialog_cancel_button_enable_state(enabled=False)) so the boolean is
passed by name; update the occurrences at the shown call and the other
occurrences referenced (around lines 208–209) to use the same keyword form.
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In
`@python/mqt/syrec/simulation_view/dialogs/all_input_states_generator_dialog.py`:
- Around line 162-178: Add a Ruff suppression for FBT001 on the Qt slot boolean
parameter in the _handle_input_state_generator_finished method: update the
function definition for _handle_input_state_generator_finished(self,
was_cancellation_requested: bool) -> None to include an inline "# noqa: FBT001"
comment (so the positional bool parameter used by the Qt slot call is ignored by
Ruff) and leave the rest of the method unchanged; ensure the suppression is
placed on the def line (or immediately after the parameter) so the linter
recognizes it.
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_dialog.py`:
- Around line 254-268: Add a targeted noqa to suppress FBT001 for the Qt slot
boolean parameter: update the decorator line on
_handle_all_simulation_run_executions_done (the `@QtCore.pyqtSlot`(bool) # type:
ignore[untyped-decorator] line) to include "# noqa: FBT001" so linting ignores
the positional boolean Qt signal; do not change method signature or logic and
keep calls to _request_worker_cancellation and
_shutdown_worker_thread_and_await_completion intact.
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_editor_dialog.py`:
- Around line 1528-1535: The function _stringify_qubit_value should make
return_as_high_low_state a keyword-only parameter to satisfy FBT001; change its
signature to include a positional-only parameter for qubit_value and a
keyword-only marker (e.g., def _stringify_qubit_value(qubit_value: bool | None,
*, return_as_high_low_state: bool) -> str) and leave the body unchanged — all
current callers already pass return_as_high_low_state by name so no callsite
changes are needed.
In
`@python/mqt/syrec/simulation_view/styled_item_delegates/simulation_run_execution_styled_item_delegate.py`:
- Around line 457-468: Change the two helper methods
_stringify_outputs_match_result(...) and
_determine_color_for_outputs_match_result(...) to require their boolean argument
as keyword-only (e.g., def _stringify_outputs_match_result(*, outputs_match:
bool) -> str and def _determine_color_for_outputs_match_result(*, outputs_match:
bool) -> QColor), and update their call sites to pass the boolean by name (e.g.,
_stringify_outputs_match_result(outputs_match=associated_input_output_mapping.do_expected_and_actual_outputs_match)
and
_determine_color_for_outputs_match_result(outputs_match=associated_input_output_mapping.do_expected_and_actual_outputs_match));
ensure both the method definitions and both places that call them in
SimulationRunExecutionStyledItemDelegate are updated accordingly.
…d disabled FBT001 ruff rule due to its conflict with the PyQt6 signal/slot mechanism
…d disabled FBT001 ruff rule due to its conflict with the PyQt6 signal/slot mechanism
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_editor_dialog.py`:
- Around line 1487-1492: The two casts are wrong: change the cast target for
optional_not_edited_input_state_qubit_checkbox and
optional_not_edited_output_state_qubit_checkbox from "QtWidgets.QGroupBox" to
"QtWidgets.QCheckBox" so that not_edited_input_state_qubit_checkbox and
not_edited_output_state_qubit_checkbox are typed as QCheckBox (matching their
declarations and findChild usage); update the two cast(...) calls referencing
those variable names accordingly.
- Around line 934-1158: In _handle_qreg_qubit_values_edit_toggle_button_click
and _handle_init_expected_output_state_button_click replace invalid PyQt6 type
hints QtWidgets.QtWidget and QtWidgets.QtQWidget with QtWidgets.QWidget for
generic widget variables (e.g.
optional_expected_output_state_value_toggle_button,
optional_qreg_search_input_field, optional_qreg_search_trigger_btn,
optional_qubit_values_groupbox_qubit_search_field), change the incorrect cast of
optional_qubit_values_groupbox from QCheckBox to QtWidgets.QGroupBox (variable
qubit_values_groupbox), and change the cast of qreg_search_trigger_btn from the
non-existent QPushButtonLineEdit to QtWidgets.QPushButton (variable
qreg_search_trigger_btn); update any matching cast() string literals to use the
correct QtWidgets types and ensure QPushButton is used where a button widget is
expected.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_editor_dialog.py`:
- Around line 441-443: The condition uses qreg_name_search_input_field.text() is
None which is always False because QLineEdit.text() returns "" when empty;
update the should_control_be_visible expression in the
simulation_run_editor_dialog (the variable name should_control_be_visible near
qreg_name_search_input_field and qreg_name) to explicitly check for an empty
string (e.g., qreg_name_search_input_field.text() == "" or not
qreg_name_search_input_field.text()) or use .strip() if you want to treat
whitespace as empty, so the logic reads: empty search OR
qreg_name.startswith(search_text).
- Line 1359: The cast() call on the standalone line using
cast("QtWidgets.QGroupBox", optional_effected_qreg_qubit_values_groupbox)
produces no effect because its result is not assigned or used; either remove
this no-op statement or assign the cast result to a variable and use it (e.g.,
replace the line with an assignment like effected_qreg_qubit_values_groupbox =
cast(QtWidgets.QGroupBox, optional_effected_qreg_qubit_values_groupbox)) so the
typed value is actually available for subsequent code that references
optional_effected_qreg_qubit_values_groupbox/effected_qreg_qubit_values_groupbox.
…r and qubit name search
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@python/mqt/syrec/simulation_view/dialogs/simulation_run_editor_dialog.py`:
- Around line 62-69: The __init__ method in class LineEditWithDynamicWidth is
missing an explicit return annotation and should also use modern union syntax
for the optional parent parameter; update the signature of
LineEditWithDynamicWidth.__init__ to declare parent as QtWidgets.QWidget | None
and add a trailing -> None return type (keep the body unchanged and preserve the
existing attributes like _expected_max_num_characters and setMaxLength).
- Around line 485-513: Make the `_stringify_qubit_value` function require
`qubit_value` as a keyword-only argument and update all call sites to pass
`qubit_value=` explicitly; specifically, change the function signature of
`_stringify_qubit_value` so `qubit_value` is after a bare `*` (e.g. def
_stringify_qubit_value(*, qubit_value, return_as_high_low_state: bool | None =
None):) and then update every invocation (for example all uses of
SimulationRunEditorDialog._stringify_qubit_value(...)) to call
`_stringify_qubit_value(qubit_value=updated_qubit_value,
return_as_high_low_state=...)` (apply same change to all occurrences referenced
in the review: the calls around the shown block and the other ranges noted).
|
@burgholzer The scope of this PR could be reduced a bit by adding the import/export to json functionality in a separate PR. |
burgholzer
left a comment
There was a problem hiding this comment.
While I haven't reviewed this in detail it seems pretty clean. CI is happy, the rabbit is happy, so I am happy.
Thanks for the contribution!
Description
As defined in #499 with this PR the current simulation view, simulating all possible input combinations and displaying the input and associated output qubit values in a table, is redesigned by introducing a redesigned parent dialog that provides the following functionality:
jsonfile:{ "inputCircuit": "<SYREC_CIRCUIT>", "simulationRuns": [ { "in": "(0|1)+", "out": "(0|1)+" }] }.jsonfiles.jsonfile:.jsondata since serialization will be terminated in case of an error.This PR adds the following dependencies to the project:
.jsonparser) | License: BSD-3 and ISCpython < 3.11(catch unhandled new enum values with the help of assert_never() via static type checkers, support for override and abstractmethod decorators) | License: PSF 2.0Manual tests of the UI were performed with the following operating systems:
Checklist: