mirror of
https://github.com/bec-project/bec_widgets.git
synced 2026-06-13 16:40:56 +02:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d4ff0bfac4 |
@@ -1,5 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -304,6 +306,49 @@ class BECWidget(BECConnector):
|
||||
buf.close()
|
||||
return ba
|
||||
|
||||
@SafeSlot(popup_error=True)
|
||||
@rpc_timeout(None)
|
||||
def screenshot_to_scilog(self) -> None:
|
||||
"""
|
||||
Take a screenshot of the widget and send it to SciLog through BEC messaging services.
|
||||
"""
|
||||
if not isinstance(self, QWidget):
|
||||
raise RuntimeError("Cannot take screenshot of non-QWidget instance")
|
||||
|
||||
messaging = getattr(self.client, "messaging", None)
|
||||
if messaging is None:
|
||||
raise RuntimeError("BEC messaging services are not available on the current client.")
|
||||
|
||||
scilog = messaging.scilog
|
||||
if not getattr(scilog, "_enabled", False):
|
||||
# We currently don't expose a public method to check if SciLog is enabled,
|
||||
# so we play defensive and check for an internal _enabled attribute that
|
||||
# should be True when SciLog is enabled.
|
||||
raise RuntimeError(
|
||||
"SciLog is not enabled for the current client, cannot send screenshot."
|
||||
)
|
||||
|
||||
pixmap: QPixmap = self.grab()
|
||||
if pixmap.isNull():
|
||||
raise RuntimeError("Failed to capture screenshot.")
|
||||
|
||||
tmp_name: str | None = None
|
||||
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_file:
|
||||
tmp_name = tmp_file.name
|
||||
|
||||
if not pixmap.save(tmp_name, "PNG"):
|
||||
raise RuntimeError("Failed to save screenshot to a temporary file.")
|
||||
|
||||
msg = messaging.scilog.new()
|
||||
msg.add_attachment(tmp_name, width="80%")
|
||||
msg.send()
|
||||
logger.info("Screenshot sent to SciLog")
|
||||
finally:
|
||||
if tmp_name and os.path.exists(tmp_name):
|
||||
os.unlink(tmp_name)
|
||||
|
||||
def attach(self):
|
||||
dock = WidgetHierarchy.find_ancestor(self, QtAds.CDockWidget)
|
||||
if dock is None:
|
||||
|
||||
@@ -32,6 +32,7 @@ from bec_widgets.utils.rpc_widget_handler import widget_handler
|
||||
from bec_widgets.utils.toolbars.actions import (
|
||||
ExpandableMenuAction,
|
||||
MaterialIconAction,
|
||||
SwitchableToolBarAction,
|
||||
WidgetAction,
|
||||
)
|
||||
from bec_widgets.utils.toolbars.bundles import ToolbarBundle
|
||||
@@ -470,10 +471,34 @@ class BECDockArea(DockAreaWidget):
|
||||
self._profile_management_enabled
|
||||
)
|
||||
self.toolbar.components.add_safe(
|
||||
"screenshot",
|
||||
"screenshot_save",
|
||||
MaterialIconAction(icon_name="photo_camera", tooltip="Take Screenshot", parent=self),
|
||||
)
|
||||
self.toolbar.components.get_action("screenshot").action.setVisible(
|
||||
self.toolbar.components.add_safe(
|
||||
"screenshot_to_scilog",
|
||||
MaterialIconAction(
|
||||
icon_name="add_a_photo", tooltip="Send Screenshot to SciLog", parent=self
|
||||
),
|
||||
)
|
||||
self.toolbar.components.add_safe(
|
||||
"screenshot",
|
||||
SwitchableToolBarAction(
|
||||
actions={
|
||||
"save": self.toolbar.components.get_action_reference("screenshot_save")(),
|
||||
"scilog": self.toolbar.components.get_action_reference(
|
||||
"screenshot_to_scilog"
|
||||
)(),
|
||||
},
|
||||
initial_action="save",
|
||||
tooltip="Screenshot Actions",
|
||||
checkable=False,
|
||||
parent=self.toolbar,
|
||||
),
|
||||
)
|
||||
self.toolbar.components.get_action("screenshot_save").action.setVisible(
|
||||
self._profile_management_enabled
|
||||
)
|
||||
self.toolbar.components.get_action("screenshot_to_scilog").action.setVisible(
|
||||
self._profile_management_enabled
|
||||
)
|
||||
dark_mode_action = WidgetAction(
|
||||
@@ -542,7 +567,12 @@ class BECDockArea(DockAreaWidget):
|
||||
_connect_flat_actions(self._ACTION_MAPPINGS["menu_utils"])
|
||||
|
||||
self.toolbar.components.get_action("attach_all").action.triggered.connect(self.attach_all)
|
||||
self.toolbar.components.get_action("screenshot").action.triggered.connect(self.screenshot)
|
||||
self.toolbar.components.get_action("screenshot_save").action.triggered.connect(
|
||||
self.screenshot
|
||||
)
|
||||
self.toolbar.components.get_action("screenshot_to_scilog").action.triggered.connect(
|
||||
self.screenshot_to_scilog
|
||||
)
|
||||
|
||||
def _new_plugin_widget(self, widget_type: str, toolbar_action: MaterialIconAction) -> None:
|
||||
# Created as helper method for simple tests
|
||||
|
||||
@@ -8,7 +8,7 @@ from unittest.mock import MagicMock, patch
|
||||
import pytest
|
||||
from qtpy.QtCore import QSettings, Qt, QTimer
|
||||
from qtpy.QtGui import QPixmap
|
||||
from qtpy.QtWidgets import QDialog, QMessageBox, QWidget
|
||||
from qtpy.QtWidgets import QDialog, QMessageBox, QToolButton, QWidget
|
||||
|
||||
import bec_widgets.widgets.containers.dock_area.basic_dock_area as basic_dock_module
|
||||
import bec_widgets.widgets.containers.dock_area.dock_area as dock_area_module
|
||||
@@ -987,9 +987,9 @@ class TestToolbarFunctionality:
|
||||
mock_screenshot = mock.MagicMock()
|
||||
mock_grab.return_value = mock_screenshot
|
||||
|
||||
# Trigger the screenshot action
|
||||
action = advanced_dock_area.toolbar.components.get_action("screenshot").action
|
||||
action.trigger()
|
||||
# Trigger the screenshot main button
|
||||
action = advanced_dock_area.toolbar.components.get_action("screenshot")
|
||||
action.main_button.click()
|
||||
|
||||
# Verify the dialog was called
|
||||
mock_dialog.assert_called_once()
|
||||
@@ -1000,6 +1000,41 @@ class TestToolbarFunctionality:
|
||||
# Verify save was called with the filename
|
||||
mock_screenshot.save.assert_called_once_with(str(screenshot_path))
|
||||
|
||||
def test_screenshot_button_has_scilog_dropdown(self, advanced_dock_area):
|
||||
"""Test screenshot toolbar button exposes a SciLog dropdown option."""
|
||||
action = advanced_dock_area.toolbar.components.get_action("screenshot")
|
||||
button = action.main_button
|
||||
|
||||
assert isinstance(button, QToolButton)
|
||||
assert button.popupMode() == QToolButton.ToolButtonPopupMode.MenuButtonPopup
|
||||
assert button.menu() is not None
|
||||
assert [menu_action.text() for menu_action in button.menu().actions()] == [
|
||||
"Take Screenshot",
|
||||
"Send Screenshot to SciLog",
|
||||
]
|
||||
|
||||
def test_screenshot_to_scilog_action(self, advanced_dock_area):
|
||||
"""Test sending a screenshot through the BEC SciLog messaging service."""
|
||||
mock_message = mock.MagicMock()
|
||||
mock_message.add_attachment.return_value = mock_message
|
||||
advanced_dock_area.client.messaging.scilog.new = mock.MagicMock(return_value=mock_message)
|
||||
advanced_dock_area.client.messaging.scilog._enabled = True
|
||||
|
||||
with mock.patch.object(advanced_dock_area, "grab") as mock_grab:
|
||||
mock_screenshot = mock.MagicMock()
|
||||
mock_screenshot.isNull.return_value = False
|
||||
mock_screenshot.save.return_value = True
|
||||
mock_grab.return_value = mock_screenshot
|
||||
|
||||
action = advanced_dock_area.toolbar.components.get_action("screenshot")
|
||||
assert action.main_button is not None
|
||||
scilog_menu_action = action.main_button.menu().actions()[1]
|
||||
scilog_menu_action.trigger()
|
||||
|
||||
advanced_dock_area.client.messaging.scilog.new.assert_called_once_with()
|
||||
mock_message.add_attachment.assert_called_once()
|
||||
mock_message.send.assert_called_once_with()
|
||||
|
||||
def test_plugin_toolbar_actions_empty_when_no_plugins(self, clear_plugin_toolbar_actions_cache):
|
||||
"""Test that no plugin toolbar actions are produced when no plugin widgets exist."""
|
||||
with patch(
|
||||
|
||||
Reference in New Issue
Block a user