chemunited 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chemunited/__init__.py +3 -0
- chemunited/__main__.py +53 -0
- chemunited/connectivity/__init__.py +0 -0
- chemunited/connectivity/graph.py +77 -0
- chemunited/connectivity/online_list.py +364 -0
- chemunited/connectivity/openapi_commands.py +248 -0
- chemunited/draw/__init__.py +0 -0
- chemunited/draw/graph.py +376 -0
- chemunited/draw/tree_add.py +287 -0
- chemunited/elements/__init__.py +3 -0
- chemunited/elements/access.py +176 -0
- chemunited/elements/component/__init__.py +13 -0
- chemunited/elements/component/__test_component.py +64 -0
- chemunited/elements/component/component_factory.py +159 -0
- chemunited/elements/component/component_parts/__init__.py +24 -0
- chemunited/elements/component/component_parts/connection_point.py +157 -0
- chemunited/elements/component/component_parts/flow_channel.py +0 -0
- chemunited/elements/component/component_parts/scene_item.py +379 -0
- chemunited/elements/component/component_parts/svg_layer.py +90 -0
- chemunited/elements/component/component_parts/text_element.py +22 -0
- chemunited/elements/component/connectivity.py +56 -0
- chemunited/elements/component/glossary/__init__.py +61 -0
- chemunited/elements/component/glossary/analytics/__init__.py +0 -0
- chemunited/elements/component/glossary/analytics/hplccontrol_graph.py +28 -0
- chemunited/elements/component/glossary/analytics/ircontrol_graph.py +26 -0
- chemunited/elements/component/glossary/analytics/mscontrol_graph.py +28 -0
- chemunited/elements/component/glossary/analytics/nmrcontrol_graph.py +28 -0
- chemunited/elements/component/glossary/analytics/spectrum.py +50 -0
- chemunited/elements/component/glossary/assembly/__init__.py +0 -0
- chemunited/elements/component/glossary/pipes/__init__.py +0 -0
- chemunited/elements/component/glossary/pipes/distributor_graph.py +44 -0
- chemunited/elements/component/glossary/pipes/mfc_graph.py +21 -0
- chemunited/elements/component/glossary/pumps/__init__.py +0 -0
- chemunited/elements/component/glossary/pumps/syringepump_graph.py +92 -0
- chemunited/elements/component/glossary/sensors/__init__.py +0 -0
- chemunited/elements/component/glossary/technical/__init__.py +0 -0
- chemunited/elements/component/glossary/technical/multichannel_graph.py +56 -0
- chemunited/elements/component/glossary/thermal/__init__.py +0 -0
- chemunited/elements/component/glossary/valve/__init__.py +0 -0
- chemunited/elements/component/glossary/valve/rotary_valve_graph.py +92 -0
- chemunited/elements/component/glossary/valve/solenoid_valve_graph.py +164 -0
- chemunited/elements/component/glossary/vessels/__init__.py +0 -0
- chemunited/elements/component/glossary/vessels/common.py +45 -0
- chemunited/elements/component/glossary/vessels/customflask_graph.py +93 -0
- chemunited/elements/component/glossary/vessels/flowreactor_graph.py +99 -0
- chemunited/elements/component/glossary/vessels/glassbottle_graph.py +92 -0
- chemunited/elements/component/glossary/vessels/loop_graph.py +75 -0
- chemunited/elements/component/glossary/vessels/vial_graph.py +211 -0
- chemunited/elements/component/graph_item.py +625 -0
- chemunited/elements/component/protocols/__init__.py +30 -0
- chemunited/elements/component/widgets/__init__.py +5 -0
- chemunited/elements/component/widgets/connectivity.py +35 -0
- chemunited/elements/component/widgets/main.py +67 -0
- chemunited/elements/component/widgets/properties.py +34 -0
- chemunited/elements/compounds/__init__.py +5 -0
- chemunited/elements/compounds/compound_dialog.py +117 -0
- chemunited/elements/compounds/compound_list.py +285 -0
- chemunited/elements/compounds/compounds_widget.py +44 -0
- chemunited/elements/compounds/coolprop_lookup.py +179 -0
- chemunited/elements/connection/__connection_test.py +128 -0
- chemunited/elements/connection/__init__.py +17 -0
- chemunited/elements/connection/connection.py +404 -0
- chemunited/elements/inventory/__init__.py +5 -0
- chemunited/elements/inventory/workspace.py +1251 -0
- chemunited/elements/pool_commands.py +71 -0
- chemunited/elements/reactions/__init__.py +11 -0
- chemunited/elements/reactions/model.py +33 -0
- chemunited/elements/reactions/reaction_dialog.py +108 -0
- chemunited/elements/reactions/reaction_list.py +132 -0
- chemunited/elements/reactions/reactions_widget.py +28 -0
- chemunited/mcp/MCP_CLIENT_CONFIG.md +99 -0
- chemunited/mcp/__init__.py +6 -0
- chemunited/mcp/instructions.md +287 -0
- chemunited/mcp/project_files.py +122 -0
- chemunited/mcp/qt_bridge.py +46 -0
- chemunited/mcp/server.py +226 -0
- chemunited/monitor.py +237 -0
- chemunited/monitoring/__init__.py +0 -0
- chemunited/monitoring/execution_api_process.py +387 -0
- chemunited/monitoring/graph.py +14 -0
- chemunited/monitoring/pool_log_tailer.py +106 -0
- chemunited/monitoring/process_list.py +100 -0
- chemunited/monitoring/status_animated.py +90 -0
- chemunited/monitoring/summary.py +728 -0
- chemunited/orchestrator/__init__.py +5 -0
- chemunited/orchestrator/connectivity.py +154 -0
- chemunited/orchestrator/core.py +118 -0
- chemunited/orchestrator/draw.py +468 -0
- chemunited/orchestrator/execution.py +1020 -0
- chemunited/orchestrator/inventory_state.py +158 -0
- chemunited/orchestrator/main.py +5 -0
- chemunited/orchestrator/orchestrator.py +5 -0
- chemunited/orchestrator/project_file.py +1283 -0
- chemunited/orchestrator/protocols.py +163 -0
- chemunited/pre_run/__init__.py +0 -0
- chemunited/pre_run/dashboard_launcher.py +695 -0
- chemunited/pre_run/pre_run_frame.py +69 -0
- chemunited/pre_run/process_list.py +448 -0
- chemunited/pre_run/protocols_historic.py +231 -0
- chemunited/pre_run/summary_window.py +235 -0
- chemunited/project/__init__.py +0 -0
- chemunited/project/git_manager.py +225 -0
- chemunited/project/manifest.py +35 -0
- chemunited/project/platform_svg.py +139 -0
- chemunited/project/recent.py +104 -0
- chemunited/project/session.py +217 -0
- chemunited/project/storage.py +958 -0
- chemunited/project/writer.py +92 -0
- chemunited/protocols/__init__.py +0 -0
- chemunited/protocols/graph.py +6 -0
- chemunited/protocols/process_list.py +94 -0
- chemunited/protocols/workflows/__init__.py +12 -0
- chemunited/protocols/workflows/controller.py +192 -0
- chemunited/protocols/workflows/design.py +39 -0
- chemunited/protocols/workflows/editor.py +529 -0
- chemunited/protocols/workflows/elements/__init__.py +7 -0
- chemunited/protocols/workflows/elements/access_point.py +168 -0
- chemunited/protocols/workflows/elements/status_bar.py +136 -0
- chemunited/protocols/workflows/elements/style.py +44 -0
- chemunited/protocols/workflows/elements/work_connection.py +606 -0
- chemunited/protocols/workflows/elements/work_node.py +443 -0
- chemunited/protocols/workflows/exceptions.py +6 -0
- chemunited/protocols/workflows/naming.py +12 -0
- chemunited/protocols/workflows/node_parameters_dialog.py +236 -0
- chemunited/protocols/workflows/process_workflow.py +406 -0
- chemunited/protocols/workflows/workflow_frames.py +1598 -0
- chemunited/protocols/workflows/workflow_rules.py +140 -0
- chemunited/protocols/workflows/workflow_widget.py +169 -0
- chemunited/setup.py +529 -0
- chemunited/shared/editor/__init__.py +0 -0
- chemunited/shared/editor/base.py +181 -0
- chemunited/shared/editor/editor.py +0 -0
- chemunited/shared/editor/lexer.py +108 -0
- chemunited/shared/editor/parameters/cards.py +703 -0
- chemunited/shared/editor/parameters/drag_list.py +155 -0
- chemunited/shared/editor/parameters/example.py +121 -0
- chemunited/shared/editor/parameters/list.py +117 -0
- chemunited/shared/editor/parameters/main.py +528 -0
- chemunited/shared/editor/protocols/command.py +296 -0
- chemunited/shared/editor/protocols/command_list.py +462 -0
- chemunited/shared/editor/protocols/example.py +246 -0
- chemunited/shared/editor/protocols/node_metadata.py +36 -0
- chemunited/shared/editor/protocols/param_ref_card.py +165 -0
- chemunited/shared/editor/protocols/script.py +419 -0
- chemunited/shared/enums/__init__.py +10 -0
- chemunited/shared/enums/elements_scene.py +8 -0
- chemunited/shared/enums/protocols_enum.py +10 -0
- chemunited/shared/enums/windows_enum.py +17 -0
- chemunited/shared/graph/__init__.py +7 -0
- chemunited/shared/graph/graph_core.py +190 -0
- chemunited/shared/graph/scene_core.py +37 -0
- chemunited/shared/graph_objects/__init__.py +6 -0
- chemunited/shared/graph_objects/custom_path.py +184 -0
- chemunited/shared/icon.py +78 -0
- chemunited/shared/logger_queue.py +132 -0
- chemunited/shared/prcess_list/__init__.py +5 -0
- chemunited/shared/prcess_list/item.py +261 -0
- chemunited/shared/prcess_list/list.py +154 -0
- chemunited/shared/prcess_list/widget.py +107 -0
- chemunited/shared/resources/README.md +177 -0
- chemunited/shared/resources/__init__.py +0 -0
- chemunited/shared/resources/components/ADC.svg +32 -0
- chemunited/shared/resources/components/BackPressureRegulator.svg +48 -0
- chemunited/shared/resources/components/BottleAccess.svg +34 -0
- chemunited/shared/resources/components/BottlePressureAccess.svg +34 -0
- chemunited/shared/resources/components/BubbleSensor.svg +46 -0
- chemunited/shared/resources/components/Chiller.svg +106 -0
- chemunited/shared/resources/components/CustomFlask.svg +54 -0
- chemunited/shared/resources/components/DAC.svg +32 -0
- chemunited/shared/resources/components/Distributor.svg +20 -0
- chemunited/shared/resources/components/FlaskJacket.svg +20 -0
- chemunited/shared/resources/components/FlowMeter.svg +49 -0
- chemunited/shared/resources/components/FlowReactor.svg +131 -0
- chemunited/shared/resources/components/FlowReactorBase.svg +20 -0
- chemunited/shared/resources/components/FourPortDistributionValve.svg +308 -0
- chemunited/shared/resources/components/FourPortFivePositionValve.svg +282 -0
- chemunited/shared/resources/components/Gantry3D.svg +199 -0
- chemunited/shared/resources/components/GlassBottle.svg +75 -0
- chemunited/shared/resources/components/HPLC.svg +116 -0
- chemunited/shared/resources/components/HPLCControl.svg +1023 -0
- chemunited/shared/resources/components/HPLCPump.svg +79 -0
- chemunited/shared/resources/components/IRControl.svg +36 -0
- chemunited/shared/resources/components/LengthControl.svg +66 -0
- chemunited/shared/resources/components/Loop.svg +128 -0
- chemunited/shared/resources/components/LoopBase.svg +23 -0
- chemunited/shared/resources/components/MFCComponent.svg +226 -0
- chemunited/shared/resources/components/MSControl.svg +79 -0
- chemunited/shared/resources/components/MassFlowControl.svg +40 -0
- chemunited/shared/resources/components/MultiChannelADC.svg +238 -0
- chemunited/shared/resources/components/MultiChannelDAC.svg +238 -0
- chemunited/shared/resources/components/MultiChannelRelay.svg +220 -0
- chemunited/shared/resources/components/NMRControl.svg +48 -0
- chemunited/shared/resources/components/Peltier.svg +76 -0
- chemunited/shared/resources/components/PeltierCoolerTemperatureControl.svg +553 -0
- chemunited/shared/resources/components/PhidgetBubbleSensorComponent.svg +256 -0
- chemunited/shared/resources/components/PhidgetBubbleSensorPowerComponent.svg +59 -0
- chemunited/shared/resources/components/PhotoLeds.svg +57 -0
- chemunited/shared/resources/components/PhotoSensor.svg +144 -0
- chemunited/shared/resources/components/Photoreactor.svg +296 -0
- chemunited/shared/resources/components/PoolDARK.svg +91 -0
- chemunited/shared/resources/components/PoolLIGHT.svg +91 -0
- chemunited/shared/resources/components/Power.svg +27 -0
- chemunited/shared/resources/components/PowerControl.svg +59 -0
- chemunited/shared/resources/components/PowerSwitch.svg +59 -0
- chemunited/shared/resources/components/PressureControl.svg +294 -0
- chemunited/shared/resources/components/PressureSensor.svg +287 -0
- chemunited/shared/resources/components/Relay.svg +26 -0
- chemunited/shared/resources/components/RotaryValve.svg +37 -0
- chemunited/shared/resources/components/Separator.svg +53 -0
- chemunited/shared/resources/components/Sink.svg +77 -0
- chemunited/shared/resources/components/SixPortDistributionValve.svg +364 -0
- chemunited/shared/resources/components/SixPortTwoPositionValve.svg +352 -0
- chemunited/shared/resources/components/SixteenPortDistributionValve.svg +644 -0
- chemunited/shared/resources/components/SolenoidValve.svg +33 -0
- chemunited/shared/resources/components/SolenoidValve2Way.svg +39 -0
- chemunited/shared/resources/components/Source.svg +77 -0
- chemunited/shared/resources/components/SourceSink.svg +22 -0
- chemunited/shared/resources/components/SyringeBarrel.svg +101 -0
- chemunited/shared/resources/components/SyringePlunger.svg +24 -0
- chemunited/shared/resources/components/SyringePump.svg +704 -0
- chemunited/shared/resources/components/TemperatureControl.svg +1089 -0
- chemunited/shared/resources/components/ThreePortFourPositionValve.svg +283 -0
- chemunited/shared/resources/components/ThreePortTwoPositionValve.svg +264 -0
- chemunited/shared/resources/components/TwelvePortDistributionValve.svg +532 -0
- chemunited/shared/resources/components/TwoPortDistributionValve.svg +252 -0
- chemunited/shared/resources/components/Vial.svg +301 -0
- chemunited/shared/resources/icons/add_folder_black.svg +14 -0
- chemunited/shared/resources/icons/add_folder_white.svg +14 -0
- chemunited/shared/resources/icons/air.svg +4 -0
- chemunited/shared/resources/icons/block_for_black.svg +4 -0
- chemunited/shared/resources/icons/block_for_white.svg +4 -0
- chemunited/shared/resources/icons/block_if_black.svg +7 -0
- chemunited/shared/resources/icons/block_if_white.svg +11 -0
- chemunited/shared/resources/icons/boolean_black.svg +13 -0
- chemunited/shared/resources/icons/boolean_white.svg +13 -0
- chemunited/shared/resources/icons/build.svg +12 -0
- chemunited/shared/resources/icons/chemical_black.svg +11 -0
- chemunited/shared/resources/icons/chemical_white.svg +7 -0
- chemunited/shared/resources/icons/chemunited.ico +0 -0
- chemunited/shared/resources/icons/chemunited.svg +346 -0
- chemunited/shared/resources/icons/chemunited_simu.svg +689 -0
- chemunited/shared/resources/icons/choices_black.svg +11 -0
- chemunited/shared/resources/icons/choices_white.svg +11 -0
- chemunited/shared/resources/icons/color_select_black.svg +6 -0
- chemunited/shared/resources/icons/color_select_white.svg +6 -0
- chemunited/shared/resources/icons/complete.svg +1 -0
- chemunited/shared/resources/icons/component_icon.svg +1 -0
- chemunited/shared/resources/icons/connection_black.svg +13 -0
- chemunited/shared/resources/icons/connection_white.svg +15 -0
- chemunited/shared/resources/icons/csv.svg +10 -0
- chemunited/shared/resources/icons/database_black.svg +1 -0
- chemunited/shared/resources/icons/database_white.svg +1 -0
- chemunited/shared/resources/icons/device_hierarchy.svg +1 -0
- chemunited/shared/resources/icons/flowchem_logo.svg +33 -0
- chemunited/shared/resources/icons/home.svg +13 -0
- chemunited/shared/resources/icons/inspect_black.svg +9 -0
- chemunited/shared/resources/icons/inspect_white.svg +9 -0
- chemunited/shared/resources/icons/integer_black.svg +15 -0
- chemunited/shared/resources/icons/integer_white.svg +15 -0
- chemunited/shared/resources/icons/json.svg +7 -0
- chemunited/shared/resources/icons/line_pressure_black.svg +23 -0
- chemunited/shared/resources/icons/line_pressure_white.svg +23 -0
- chemunited/shared/resources/icons/link_black.svg +4 -0
- chemunited/shared/resources/icons/link_white.svg +4 -0
- chemunited/shared/resources/icons/list_black.svg +1 -0
- chemunited/shared/resources/icons/list_white.svg +6 -0
- chemunited/shared/resources/icons/log.svg +12 -0
- chemunited/shared/resources/icons/logo.svg +389 -0
- chemunited/shared/resources/icons/manual_black.svg +12 -0
- chemunited/shared/resources/icons/manual_white.svg +12 -0
- chemunited/shared/resources/icons/measure_black.svg +38 -0
- chemunited/shared/resources/icons/measure_white.svg +38 -0
- chemunited/shared/resources/icons/module.svg +1 -0
- chemunited/shared/resources/icons/molecule_black.svg +48 -0
- chemunited/shared/resources/icons/molecule_white.svg +48 -0
- chemunited/shared/resources/icons/move_black.svg +4 -0
- chemunited/shared/resources/icons/move_white.svg +4 -0
- chemunited/shared/resources/icons/offline.svg +28 -0
- chemunited/shared/resources/icons/online.svg +25 -0
- chemunited/shared/resources/icons/onlineA.svg +22 -0
- chemunited/shared/resources/icons/onlineB.svg +23 -0
- chemunited/shared/resources/icons/onlineC.svg +24 -0
- chemunited/shared/resources/icons/open_folder_black.svg +7 -0
- chemunited/shared/resources/icons/open_folder_white.svg +7 -0
- chemunited/shared/resources/icons/orchestrator_black.svg +2 -0
- chemunited/shared/resources/icons/orchestrator_white.svg +2 -0
- chemunited/shared/resources/icons/pause_black.svg +5 -0
- chemunited/shared/resources/icons/pause_white.svg +5 -0
- chemunited/shared/resources/icons/play_black.svg +14 -0
- chemunited/shared/resources/icons/play_white.svg +14 -0
- chemunited/shared/resources/icons/process_black.svg +14 -0
- chemunited/shared/resources/icons/process_white.svg +14 -0
- chemunited/shared/resources/icons/python.svg +1 -0
- chemunited/shared/resources/icons/router.svg +28 -0
- chemunited/shared/resources/icons/scissor_black.svg +2 -0
- chemunited/shared/resources/icons/scissor_white.svg +14 -0
- chemunited/shared/resources/icons/select_black.svg +12 -0
- chemunited/shared/resources/icons/select_white.svg +12 -0
- chemunited/shared/resources/icons/simulation.svg +27 -0
- chemunited/shared/resources/icons/slow_black.svg +9 -0
- chemunited/shared/resources/icons/slow_white.svg +9 -0
- chemunited/shared/resources/icons/speed_black.svg +10 -0
- chemunited/shared/resources/icons/speed_white.svg +10 -0
- chemunited/shared/resources/icons/status_black.svg +5 -0
- chemunited/shared/resources/icons/status_white.svg +5 -0
- chemunited/shared/resources/icons/stop_black.svg +10 -0
- chemunited/shared/resources/icons/stop_white.svg +10 -0
- chemunited/shared/resources/icons/string_black.svg +6 -0
- chemunited/shared/resources/icons/string_white.svg +6 -0
- chemunited/shared/resources/icons/toml.svg +1 -0
- chemunited/shared/resources/icons/trash_black.svg +1 -0
- chemunited/shared/resources/icons/trash_white.svg +1 -0
- chemunited/shared/resources/icons/update_black.svg +2 -0
- chemunited/shared/resources/icons/update_white.svg +2 -0
- chemunited/shared/resources/icons/upload_black.svg +7 -0
- chemunited/shared/resources/icons/upload_white.svg +7 -0
- chemunited/shared/resources/icons/variable_black.svg +12 -0
- chemunited/shared/resources/icons/variable_white.svg +12 -0
- chemunited/shared/resources/icons/waiting_icon.svg +1 -0
- chemunited/shared/resources/icons/water.svg +5 -0
- chemunited/shared/resources/icons/wifi_black.svg +6 -0
- chemunited/shared/resources/icons/wifi_white.svg +6 -0
- chemunited/shared/resources/lexer/theme_dark.json +62 -0
- chemunited/shared/resources/lexer/theme_light.json +62 -0
- chemunited/shared/resources/qss/dark/loggings_widget.qss +6 -0
- chemunited/shared/resources/qss/dark/main_window.qss +21 -0
- chemunited/shared/resources/qss/light/loggings_widget.qss +6 -0
- chemunited/shared/resources/qss/light/main_window.qss +21 -0
- chemunited/shared/resources/resources_rc.py +31195 -0
- chemunited/shared/resources/resources_rc.qrc +183 -0
- chemunited/shared/resources/scripts/parameter.txt +12 -0
- chemunited/shared/resources/scripts/process.txt +139 -0
- chemunited/shared/resources/scripts/project.txt +43 -0
- chemunited/shared/widgets/__init__.py +0 -0
- chemunited/shared/widgets/base_mode_editor/__init__.py +4 -0
- chemunited/shared/widgets/base_mode_editor/card_factory.py +95 -0
- chemunited/shared/widgets/base_mode_editor/cards/__init__.py +0 -0
- chemunited/shared/widgets/base_mode_editor/cards/base_card.py +111 -0
- chemunited/shared/widgets/base_mode_editor/cards/bool_card.py +58 -0
- chemunited/shared/widgets/base_mode_editor/cards/builder_models.py +251 -0
- chemunited/shared/widgets/base_mode_editor/cards/choice_card.py +74 -0
- chemunited/shared/widgets/base_mode_editor/cards/float_card.py +73 -0
- chemunited/shared/widgets/base_mode_editor/cards/int_card.py +65 -0
- chemunited/shared/widgets/base_mode_editor/cards/list_card.py +121 -0
- chemunited/shared/widgets/base_mode_editor/cards/quantity_card.py +152 -0
- chemunited/shared/widgets/base_mode_editor/cards/str_card.py +50 -0
- chemunited/shared/widgets/base_mode_editor/dialog.py +53 -0
- chemunited/shared/widgets/base_mode_editor/editor_widget.py +211 -0
- chemunited/shared/widgets/base_mode_editor/example.py +251 -0
- chemunited/shared/widgets/busy_status.py +79 -0
- chemunited/shared/widgets/frame_base.py +293 -0
- chemunited/shared/widgets/loggings_widget.py +360 -0
- chemunited/shared/widgets/logo_window.py +106 -0
- chemunited/shared/widgets/main_window.py +192 -0
- chemunited/shared/widgets/segment_widget.py +49 -0
- chemunited/simulation/__init__.py +4 -0
- chemunited/simulation/final_state.py +297 -0
- chemunited/simulation/graph_simulation.py +10 -0
- chemunited/simulation/playback.py +61 -0
- chemunited/simulation/simulate_report.py +1024 -0
- chemunited/utils/files.py +39 -0
- chemunited/utils/flowchem_listener.py +176 -0
- chemunited/utils/math_functions.py +154 -0
- chemunited/utils/update_dialog.py +82 -0
- chemunited/utils/version_check.py +45 -0
- chemunited-0.0.1.dist-info/METADATA +36 -0
- chemunited-0.0.1.dist-info/RECORD +371 -0
- chemunited-0.0.1.dist-info/WHEEL +5 -0
- chemunited-0.0.1.dist-info/entry_points.txt +2 -0
- chemunited-0.0.1.dist-info/licenses/LICENSE +21 -0
- chemunited-0.0.1.dist-info/top_level.txt +1 -0
chemunited/__init__.py
ADDED
chemunited/__main__.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import rich_click as click
|
|
5
|
+
from PyQt5.QtCore import Qt, QTimer
|
|
6
|
+
from PyQt5.QtGui import QIcon
|
|
7
|
+
from PyQt5.QtWidgets import QApplication
|
|
8
|
+
|
|
9
|
+
from chemunited.setup import SetupWindow
|
|
10
|
+
|
|
11
|
+
_APP_ID = "org.chemunited.orchestrator"
|
|
12
|
+
_ICON_PATH = ":/icons/icons/chemunited.ico"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@click.command()
|
|
16
|
+
@click.argument("project_file", type=click.Path(exists=True), required=False)
|
|
17
|
+
@click.option(
|
|
18
|
+
"--overwrite",
|
|
19
|
+
is_flag=True,
|
|
20
|
+
default=False,
|
|
21
|
+
help="Overwrite an existing project directory when importing a .chemunited file.",
|
|
22
|
+
)
|
|
23
|
+
def main(project_file: str | None = None, overwrite: bool = False) -> None:
|
|
24
|
+
"""Entry point for launching the ChemUnited GUI."""
|
|
25
|
+
if sys.platform == "win32":
|
|
26
|
+
import ctypes
|
|
27
|
+
|
|
28
|
+
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(_APP_ID)
|
|
29
|
+
|
|
30
|
+
# Set high DPI settings for better display scaling
|
|
31
|
+
QApplication.setHighDpiScaleFactorRoundingPolicy(
|
|
32
|
+
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough # type: ignore[attr-defined]
|
|
33
|
+
)
|
|
34
|
+
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) # type: ignore[attr-defined]
|
|
35
|
+
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) # type: ignore[attr-defined]
|
|
36
|
+
|
|
37
|
+
app = QApplication(sys.argv)
|
|
38
|
+
|
|
39
|
+
app.setWindowIcon(QIcon(_ICON_PATH))
|
|
40
|
+
|
|
41
|
+
window = SetupWindow()
|
|
42
|
+
window.show()
|
|
43
|
+
if project_file:
|
|
44
|
+
_path = Path(project_file).resolve()
|
|
45
|
+
_overwrite = overwrite
|
|
46
|
+
QTimer.singleShot(
|
|
47
|
+
0, lambda: window.orchestrator.open_project(_path, overwrite=_overwrite)
|
|
48
|
+
)
|
|
49
|
+
sys.exit(app.exec_())
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, override
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
|
|
5
|
+
from chemunited.elements.component.graph_item import GraphComponent
|
|
6
|
+
from chemunited.shared.enums import SetupStepMode
|
|
7
|
+
from chemunited.shared.graph import GraphCore, SceneCore
|
|
8
|
+
|
|
9
|
+
from .online_list import OnlineList
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from ..setup import SetupWindow
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ConnectivityGraphicView(GraphCore):
|
|
16
|
+
MODE = SetupStepMode.CONNECTIVITY
|
|
17
|
+
|
|
18
|
+
def __init__(self, scene: SceneCore | None = None, parent=None):
|
|
19
|
+
super().__init__(scene, parent)
|
|
20
|
+
self.setObjectName("ConnectivityGraphicView")
|
|
21
|
+
if parent is not None:
|
|
22
|
+
self.parent_ref: SetupWindow = parent
|
|
23
|
+
|
|
24
|
+
@override
|
|
25
|
+
def dragEnterEvent(self, event):
|
|
26
|
+
if event.mimeData().hasFormat(OnlineList.MIME):
|
|
27
|
+
event.acceptProposedAction()
|
|
28
|
+
else:
|
|
29
|
+
event.ignore()
|
|
30
|
+
|
|
31
|
+
@override
|
|
32
|
+
def dragMoveEvent(self, event):
|
|
33
|
+
if event.mimeData().hasFormat(OnlineList.MIME):
|
|
34
|
+
event.acceptProposedAction()
|
|
35
|
+
else:
|
|
36
|
+
event.ignore()
|
|
37
|
+
|
|
38
|
+
def _component_at_drop_position(self, event) -> GraphComponent | None:
|
|
39
|
+
scene_pos = self.mapToScene(event.pos())
|
|
40
|
+
scene = self.scene()
|
|
41
|
+
if scene is None:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
for item in scene.items(scene_pos):
|
|
45
|
+
current = item
|
|
46
|
+
while current is not None:
|
|
47
|
+
if isinstance(current, GraphComponent):
|
|
48
|
+
return current
|
|
49
|
+
current = current.parentItem() # type: ignore[assignment]
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
@override
|
|
53
|
+
def dropEvent(self, event):
|
|
54
|
+
if not event.mimeData().hasFormat(OnlineList.MIME):
|
|
55
|
+
event.ignore()
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
url_component = event.mimeData().data(OnlineList.MIME).data().decode("utf-8")
|
|
59
|
+
event.acceptProposedAction()
|
|
60
|
+
|
|
61
|
+
component = self._component_at_drop_position(event)
|
|
62
|
+
if component is None:
|
|
63
|
+
logger.warning(
|
|
64
|
+
f"No component found at position {self.mapToScene(event.pos())}"
|
|
65
|
+
)
|
|
66
|
+
return
|
|
67
|
+
if not component.inf.is_electronic:
|
|
68
|
+
logger.warning(f"Component {component.inf.name} is not electronic.")
|
|
69
|
+
return
|
|
70
|
+
|
|
71
|
+
if hasattr(self, "parent_ref"):
|
|
72
|
+
self.parent_ref.orchestrator.associate_component(
|
|
73
|
+
name=component.inf.name,
|
|
74
|
+
urlc=url_component,
|
|
75
|
+
)
|
|
76
|
+
else:
|
|
77
|
+
print(url_component, component.inf.name)
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING, Optional
|
|
2
|
+
from urllib.parse import urlsplit, urlunsplit
|
|
3
|
+
|
|
4
|
+
from loguru import logger
|
|
5
|
+
from PyQt5.QtCore import QMimeData, Qt
|
|
6
|
+
from PyQt5.QtGui import QColor, QDrag, QFont, QIcon, QPainter, QPixmap
|
|
7
|
+
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QListWidgetItem, QVBoxLayout, QWidget
|
|
8
|
+
from qfluentwidgets import (
|
|
9
|
+
EditableComboBox,
|
|
10
|
+
FluentIcon,
|
|
11
|
+
ListWidget,
|
|
12
|
+
PushButton,
|
|
13
|
+
StrongBodyLabel,
|
|
14
|
+
TransparentToolButton,
|
|
15
|
+
isDarkTheme,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from chemunited.shared.icon import OrchestratorIcon
|
|
19
|
+
from chemunited.utils.flowchem_listener import (
|
|
20
|
+
FLOWCHEM_SERVERS,
|
|
21
|
+
access_url,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from chemunited.setup import SetupWindow
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class OnlineList(ListWidget):
|
|
29
|
+
MIME = "application/x-chemunited-online-list"
|
|
30
|
+
|
|
31
|
+
def __init__(self, api_obj, parent=None):
|
|
32
|
+
super().__init__(parent)
|
|
33
|
+
self.api_obj = api_obj
|
|
34
|
+
self.setDragEnabled(True)
|
|
35
|
+
# Important: allow dragging outside the widget
|
|
36
|
+
self.setDefaultDropAction(Qt.MoveAction) # type: ignore[attr-defined]
|
|
37
|
+
|
|
38
|
+
def startDrag(self, supportedActions):
|
|
39
|
+
item = self.currentItem()
|
|
40
|
+
if item:
|
|
41
|
+
url_c = self.api_obj.currentText() + "/" + item.text()
|
|
42
|
+
mime = QMimeData()
|
|
43
|
+
mime.setData(self.MIME, url_c.encode("utf-8"))
|
|
44
|
+
mime.setText(url_c)
|
|
45
|
+
|
|
46
|
+
drag = QDrag(self)
|
|
47
|
+
drag.setMimeData(mime)
|
|
48
|
+
|
|
49
|
+
# === Create a custom pixmap that shows icon + text ===
|
|
50
|
+
icon = item.icon()
|
|
51
|
+
text = item.text()
|
|
52
|
+
|
|
53
|
+
# Define pixmap size (width can adapt to text length)
|
|
54
|
+
width = max(140, len(text) * 8 + 40)
|
|
55
|
+
height = 36
|
|
56
|
+
pixmap = QPixmap(width, height)
|
|
57
|
+
pixmap.fill(Qt.transparent) # type: ignore[attr-defined]
|
|
58
|
+
|
|
59
|
+
painter = QPainter(pixmap)
|
|
60
|
+
|
|
61
|
+
# Rounded background (light or dark depending on theme)
|
|
62
|
+
bg_color = (
|
|
63
|
+
QColor(40, 40, 40, 180) if isDarkTheme() else QColor(240, 240, 240, 200)
|
|
64
|
+
)
|
|
65
|
+
painter.setRenderHint(QPainter.Antialiasing)
|
|
66
|
+
painter.setBrush(bg_color)
|
|
67
|
+
painter.setPen(Qt.NoPen) # type: ignore[attr-defined]
|
|
68
|
+
painter.drawRoundedRect(0, 0, width, height, 8, 8)
|
|
69
|
+
|
|
70
|
+
# Draw icon
|
|
71
|
+
if not icon.isNull():
|
|
72
|
+
icon_pix = icon.pixmap(24, 24)
|
|
73
|
+
painter.drawPixmap(6, (height - 24) // 2, icon_pix)
|
|
74
|
+
|
|
75
|
+
# Draw text
|
|
76
|
+
painter.setFont(QFont("Segoe UI", 9))
|
|
77
|
+
painter.setPen(
|
|
78
|
+
Qt.white if isDarkTheme() else Qt.black # type: ignore[attr-defined]
|
|
79
|
+
)
|
|
80
|
+
painter.drawText(36, 22, text)
|
|
81
|
+
|
|
82
|
+
painter.end()
|
|
83
|
+
|
|
84
|
+
# Set this custom pixmap as the drag image
|
|
85
|
+
drag.setPixmap(pixmap)
|
|
86
|
+
drag.setHotSpot(pixmap.rect().center())
|
|
87
|
+
|
|
88
|
+
drag.exec_(Qt.CopyAction) # type: ignore[attr-defined]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class OnlineComponent(QWidget):
|
|
92
|
+
def __init__(self, parent):
|
|
93
|
+
super().__init__()
|
|
94
|
+
self._parent: Optional["SetupWindow"] = parent
|
|
95
|
+
layout = QVBoxLayout(self)
|
|
96
|
+
|
|
97
|
+
self.api = EditableComboBox(self)
|
|
98
|
+
self.api.setPlaceholderText("-")
|
|
99
|
+
self.api.currentTextChanged.connect(self.select_api)
|
|
100
|
+
self.api.textEdited.connect(self._on_manual_api_edited)
|
|
101
|
+
self.api.returnPressed.connect(self.submit_manual_api)
|
|
102
|
+
layout.addWidget(StrongBodyLabel("Available Flowchem servers", parent=self))
|
|
103
|
+
layout.addWidget(self.api)
|
|
104
|
+
|
|
105
|
+
self.OnlineList = OnlineList(api_obj=self.api)
|
|
106
|
+
widget = QWidget()
|
|
107
|
+
icon = TransparentToolButton(OrchestratorIcon.MOVE, self)
|
|
108
|
+
icon.setToolTip("Item in the list is movable to the graphic")
|
|
109
|
+
label_text = StrongBodyLabel("Available Online Components", parent=self)
|
|
110
|
+
label_text.setToolTip("Item in the list is movable to the graphic")
|
|
111
|
+
label_layout = QHBoxLayout(widget)
|
|
112
|
+
label_layout.setContentsMargins(0, 0, 0, 0)
|
|
113
|
+
label_layout.addWidget(icon)
|
|
114
|
+
label_layout.addWidget(label_text)
|
|
115
|
+
layout.addWidget(widget)
|
|
116
|
+
layout.addWidget(self.OnlineList)
|
|
117
|
+
|
|
118
|
+
self.LockList = ListWidget()
|
|
119
|
+
layout.addWidget(StrongBodyLabel("Lock Online Components", parent=self))
|
|
120
|
+
layout.addWidget(self.LockList)
|
|
121
|
+
|
|
122
|
+
self.update_button = PushButton(OrchestratorIcon.UPDATE, "Update List", self)
|
|
123
|
+
self.update_button.clicked.connect(self.update_list)
|
|
124
|
+
layout.addWidget(self.update_button)
|
|
125
|
+
|
|
126
|
+
def update_list(self):
|
|
127
|
+
self.update_button.setEnabled(True)
|
|
128
|
+
self.api.clear()
|
|
129
|
+
self.api.setText("")
|
|
130
|
+
FLOWCHEM_SERVERS.update()
|
|
131
|
+
for item in FLOWCHEM_SERVERS.servers:
|
|
132
|
+
self.api.addItem(item)
|
|
133
|
+
|
|
134
|
+
def _on_manual_api_edited(self, _text: str):
|
|
135
|
+
self.update_button.setEnabled(False)
|
|
136
|
+
|
|
137
|
+
def submit_manual_api(self):
|
|
138
|
+
raw_url = self.api.text()
|
|
139
|
+
normalized_url = self._normalize_api_url(raw_url)
|
|
140
|
+
if not normalized_url:
|
|
141
|
+
self._reject_manual_api(
|
|
142
|
+
raw_url,
|
|
143
|
+
normalized_url,
|
|
144
|
+
"Flowchem API address is empty or invalid.",
|
|
145
|
+
)
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
self._show_busy_status(
|
|
149
|
+
"Inspecting FlowChem API",
|
|
150
|
+
f"Reading {normalized_url}/openapi.json...",
|
|
151
|
+
)
|
|
152
|
+
ok, data = access_url(f"{normalized_url}/openapi.json", timeout=1)
|
|
153
|
+
if not ok:
|
|
154
|
+
self._reject_manual_api(
|
|
155
|
+
raw_url,
|
|
156
|
+
normalized_url,
|
|
157
|
+
"Flowchem API is not reachable at {}.",
|
|
158
|
+
normalized_url,
|
|
159
|
+
)
|
|
160
|
+
return
|
|
161
|
+
|
|
162
|
+
if not isinstance(data, dict) or not isinstance(data.get("paths"), dict):
|
|
163
|
+
self._reject_manual_api(
|
|
164
|
+
raw_url,
|
|
165
|
+
normalized_url,
|
|
166
|
+
"Flowchem API at {} does not expose a valid openapi paths object.",
|
|
167
|
+
normalized_url,
|
|
168
|
+
)
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
if "/startup_config" not in data["paths"]:
|
|
172
|
+
self._reject_manual_api(
|
|
173
|
+
raw_url,
|
|
174
|
+
normalized_url,
|
|
175
|
+
"Flowchem API at {} does not expose startup_config. "
|
|
176
|
+
"Update Flowchem for smooth connection with chemunited.",
|
|
177
|
+
normalized_url,
|
|
178
|
+
)
|
|
179
|
+
return
|
|
180
|
+
|
|
181
|
+
FLOWCHEM_SERVERS.register_openapi(normalized_url, data)
|
|
182
|
+
self._select_registered_api(raw_url=raw_url, normalized_url=normalized_url)
|
|
183
|
+
self.update_button.setEnabled(True)
|
|
184
|
+
component_count = sum(
|
|
185
|
+
len(components)
|
|
186
|
+
for components in FLOWCHEM_SERVERS.servers[normalized_url].values()
|
|
187
|
+
)
|
|
188
|
+
self._finish_busy_status(f"Registered {component_count} FlowChem component(s).")
|
|
189
|
+
|
|
190
|
+
@staticmethod
|
|
191
|
+
def _normalize_api_url(raw_url: str) -> str:
|
|
192
|
+
url = raw_url.strip().rstrip("/")
|
|
193
|
+
if not url:
|
|
194
|
+
return ""
|
|
195
|
+
|
|
196
|
+
if "://" not in url:
|
|
197
|
+
url = f"http://{url}"
|
|
198
|
+
|
|
199
|
+
parsed = urlsplit(url)
|
|
200
|
+
if parsed.scheme not in {"http", "https"} or not parsed.netloc:
|
|
201
|
+
return ""
|
|
202
|
+
|
|
203
|
+
path = parsed.path.rstrip("/")
|
|
204
|
+
return urlunsplit((parsed.scheme, parsed.netloc, path, "", ""))
|
|
205
|
+
|
|
206
|
+
def _select_registered_api(self, raw_url: str, normalized_url: str):
|
|
207
|
+
signals_blocked = self.api.blockSignals(True)
|
|
208
|
+
try:
|
|
209
|
+
if raw_url != normalized_url:
|
|
210
|
+
raw_index = self.api.findText(raw_url)
|
|
211
|
+
if raw_index >= 0:
|
|
212
|
+
self.api.removeItem(raw_index)
|
|
213
|
+
|
|
214
|
+
index = self.api.findText(normalized_url)
|
|
215
|
+
if index < 0:
|
|
216
|
+
self.api.addItem(normalized_url)
|
|
217
|
+
index = self.api.findText(normalized_url)
|
|
218
|
+
|
|
219
|
+
self.api.setCurrentIndex(index)
|
|
220
|
+
self.api.setText(normalized_url)
|
|
221
|
+
finally:
|
|
222
|
+
self.api.blockSignals(signals_blocked)
|
|
223
|
+
|
|
224
|
+
self.select_api(normalized_url)
|
|
225
|
+
|
|
226
|
+
def _reject_manual_api(
|
|
227
|
+
self, raw_url: str, normalized_url: str, message: str, *args
|
|
228
|
+
):
|
|
229
|
+
self.OnlineList.clear()
|
|
230
|
+
self._remove_unregistered_api_items(raw_url, normalized_url)
|
|
231
|
+
self.api.setText(raw_url)
|
|
232
|
+
self.update_button.setEnabled(True)
|
|
233
|
+
formatted = message.format(*args) if args else message
|
|
234
|
+
self._fail_busy_status(formatted)
|
|
235
|
+
logger.warning(message, *args)
|
|
236
|
+
|
|
237
|
+
def _show_busy_status(self, title: str, message: str) -> None:
|
|
238
|
+
if self._parent is None:
|
|
239
|
+
return
|
|
240
|
+
show_busy_status = getattr(self._parent, "show_busy_status", None)
|
|
241
|
+
if callable(show_busy_status):
|
|
242
|
+
show_busy_status(title, message)
|
|
243
|
+
|
|
244
|
+
def _finish_busy_status(self, message: str) -> None:
|
|
245
|
+
if self._parent is None:
|
|
246
|
+
return
|
|
247
|
+
finish_busy_status = getattr(self._parent, "finish_busy_status", None)
|
|
248
|
+
if callable(finish_busy_status):
|
|
249
|
+
finish_busy_status(message)
|
|
250
|
+
|
|
251
|
+
def _fail_busy_status(self, message: str) -> None:
|
|
252
|
+
if self._parent is None:
|
|
253
|
+
return
|
|
254
|
+
fail_busy_status = getattr(self._parent, "fail_busy_status", None)
|
|
255
|
+
if callable(fail_busy_status):
|
|
256
|
+
fail_busy_status(message)
|
|
257
|
+
|
|
258
|
+
def _remove_unregistered_api_items(self, *urls: str):
|
|
259
|
+
for url in dict.fromkeys(urls):
|
|
260
|
+
if not url or url in FLOWCHEM_SERVERS.servers:
|
|
261
|
+
continue
|
|
262
|
+
|
|
263
|
+
index = self.api.findText(url)
|
|
264
|
+
if index >= 0:
|
|
265
|
+
self.api.removeItem(index)
|
|
266
|
+
|
|
267
|
+
def select_api(self, item):
|
|
268
|
+
url = item.rstrip("/")
|
|
269
|
+
self.OnlineList.clear()
|
|
270
|
+
|
|
271
|
+
if url in FLOWCHEM_SERVERS.servers:
|
|
272
|
+
for device in FLOWCHEM_SERVERS.servers[url]:
|
|
273
|
+
for component in FLOWCHEM_SERVERS.servers[url][device]:
|
|
274
|
+
urlc = f"{url}/{device}/{component}"
|
|
275
|
+
figure = OrchestratorIcon.COMPONENT_ICON.path()
|
|
276
|
+
|
|
277
|
+
# Create the list item with icon + text
|
|
278
|
+
text = f"{device}/{component}"
|
|
279
|
+
list_item = QListWidgetItem(QIcon(figure), text)
|
|
280
|
+
self.OnlineList.addItem(list_item)
|
|
281
|
+
|
|
282
|
+
list_item.setToolTip(f"{text}\nDiscovered from openapi.json")
|
|
283
|
+
|
|
284
|
+
used_by = self._component_using_url(urlc)
|
|
285
|
+
if used_by is not None:
|
|
286
|
+
self.add_to_lock(text, QIcon(figure), used_by)
|
|
287
|
+
self.OnlineList.takeItem(self.OnlineList.row(list_item))
|
|
288
|
+
|
|
289
|
+
def associate_item(self, component: str, text: str | None = None):
|
|
290
|
+
"""Move selected items from OnlineList to LockList."""
|
|
291
|
+
if text:
|
|
292
|
+
for i in range(self.OnlineList.count()):
|
|
293
|
+
item = self.OnlineList.item(i)
|
|
294
|
+
if item.text() == text:
|
|
295
|
+
self.add_to_lock(item.text(), item.icon(), component)
|
|
296
|
+
self.OnlineList.takeItem(i)
|
|
297
|
+
return
|
|
298
|
+
else:
|
|
299
|
+
for item in self.OnlineList.selectedItems():
|
|
300
|
+
self.add_to_lock(item.text(), item.icon(), component)
|
|
301
|
+
self.OnlineList.takeItem(self.OnlineList.row(item))
|
|
302
|
+
|
|
303
|
+
def add_to_lock(self, text, icon, component):
|
|
304
|
+
"""Add QListWidgetItem to B, with icon + button."""
|
|
305
|
+
item = QListWidgetItem(icon, text)
|
|
306
|
+
self.LockList.addItem(item)
|
|
307
|
+
|
|
308
|
+
# Create small widget with label + button
|
|
309
|
+
widget = QWidget()
|
|
310
|
+
layout = QHBoxLayout(widget)
|
|
311
|
+
layout.setContentsMargins(4, 0, 4, 0)
|
|
312
|
+
|
|
313
|
+
label = QLabel(text)
|
|
314
|
+
label.setVisible(False)
|
|
315
|
+
button = TransparentToolButton(FluentIcon.CANCEL_MEDIUM, self)
|
|
316
|
+
button.setToolTip("Disconnect component")
|
|
317
|
+
button.clicked.connect(
|
|
318
|
+
lambda _, t=text, ic=icon: self.move_back_to_online(t, ic, component)
|
|
319
|
+
)
|
|
320
|
+
|
|
321
|
+
layout.addWidget(label)
|
|
322
|
+
layout.addStretch()
|
|
323
|
+
layout.addWidget(button)
|
|
324
|
+
|
|
325
|
+
item.setSizeHint(widget.sizeHint())
|
|
326
|
+
self.LockList.setItemWidget(item, widget)
|
|
327
|
+
|
|
328
|
+
def move_back_to_online(self, text, icon, component):
|
|
329
|
+
"""Move the item back from LockList to OnlineList."""
|
|
330
|
+
for i in range(self.LockList.count()):
|
|
331
|
+
item = self.LockList.item(i)
|
|
332
|
+
widget = self.LockList.itemWidget(item)
|
|
333
|
+
if widget:
|
|
334
|
+
label = widget.findChild(QLabel)
|
|
335
|
+
if label and label.text() == text:
|
|
336
|
+
if self._parent:
|
|
337
|
+
self._parent.orchestrator.disassociate_component(component)
|
|
338
|
+
self.LockList.takeItem(i)
|
|
339
|
+
break
|
|
340
|
+
self.OnlineList.addItem(QListWidgetItem(icon, text))
|
|
341
|
+
|
|
342
|
+
def _component_using_url(self, urlc: str) -> str | None:
|
|
343
|
+
if not self._parent:
|
|
344
|
+
return None
|
|
345
|
+
|
|
346
|
+
target_url = urlc.rstrip("/")
|
|
347
|
+
for component in self._parent.orchestrator.components.values():
|
|
348
|
+
if not component.inf.is_electronic:
|
|
349
|
+
continue
|
|
350
|
+
if str(component.url).rstrip("/") == target_url:
|
|
351
|
+
return component.name
|
|
352
|
+
return None
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
if __name__ == "__main__":
|
|
356
|
+
import sys
|
|
357
|
+
|
|
358
|
+
from PyQt5.QtWidgets import QApplication
|
|
359
|
+
|
|
360
|
+
app = QApplication(sys.argv)
|
|
361
|
+
w = OnlineComponent(parent=None)
|
|
362
|
+
w.update_list()
|
|
363
|
+
w.show()
|
|
364
|
+
sys.exit(app.exec_())
|