Source code for siriushla.as_ps_control.control_widget.BasePSControlWidget
"""Base class for controlling a power supply."""
import re
from qtpy.QtCore import Qt, Slot, QLocale
from qtpy.QtWidgets import QWidget, QVBoxLayout, QGroupBox, \
QGridLayout, QLabel, QHBoxLayout, QScrollArea, QLineEdit, QAction, \
QMenu, QInputDialog, QFrame, QPushButton, QSplitter, \
QSizePolicy as QSzPlcy
import qtawesome as qta
from pydm.connection_inspector import ConnectionInspector
from siriuspy.search import PSSearch
from siriuspy.namesys import SiriusPVName as PVName
from siriushla.util import connect_window, connect_newprocess
from ..PSDetailWindow import PSDetailWindow
from ..SummaryWidgets import SummaryWidget, SummaryHeader, \
get_prop2label, sort_propties
[docs]
class PSContainer(QWidget):
"""PSContainer."""
def __init__(self, widget, parent=None):
super().__init__(parent)
self._widget = widget
self.name = widget.devname
self.bbbname = widget.bbbname
self.udcname = widget.udcname
self.dclinks = list()
self.dclinks_type = ''
self.dclink_widgets = list()
self.dclinksbbbname = set()
self.dclinksudcname = set()
dclinks = PSSearch.conv_psname_2_dclink(self.name)
if dclinks:
self.dclinks = dclinks
self.dclinks_type = PSSearch.conv_psname_2_psmodel(dclinks[0])
if self.dclinks_type != 'REGATRON_DCLink':
for dc in dclinks:
self.dclinksbbbname.add(PSSearch.conv_psname_2_bbbname(dc))
self.dclinksudcname.add(PSSearch.conv_psname_2_udc(dc))
self.all_props = get_prop2label(PVName(dclinks[0]))
self.visible_props = sort_propties([
'detail', 'state', 'intlk', 'setpoint', 'monitor'])
self._setup_ui()
self._create_actions()
self._enable_actions()
self.setStyleSheet("""
#HideButton {
min-width: 10px;
max-width: 10px;
}
#DCLinkContainer {
background-color: lightgrey;
}
""")
def _setup_ui(self):
"""Setup widget UI."""
self._layout = QGridLayout()
self._layout.setSpacing(10)
self._layout.setContentsMargins(0, 0, 0, 0)
self.setLayout(self._layout)
self._dclink_container = QWidget(self)
self._dclink_container.setObjectName('DCLinkContainer')
self._dclink_container.setLayout(QVBoxLayout())
self._dclink_is_filled = False
if self.dclinks:
self._hide = QPushButton(qta.icon('mdi.plus'), '', self)
else:
self._hide = QPushButton('', self)
self._hide.setEnabled(False)
self._hide.setObjectName('HideButton')
self._hide.setSizePolicy(QSzPlcy.Maximum, QSzPlcy.Maximum)
self._hide.setFlat(True)
self._layout.addWidget(self._hide, 0, 0, Qt.AlignCenter)
self._layout.addWidget(self._widget, 0, 1)
self._layout.addWidget(self._dclink_container, 1, 1)
# Configure
self._dclink_container.setHidden(True)
self._hide.clicked.connect(self._toggle_dclink)
def _toggle_dclink(self):
if self._dclink_container.isHidden():
if not self._dclink_is_filled:
self._fill_dclink_container()
self._enable_actions()
self._hide.setIcon(qta.icon('mdi.minus'))
self._dclink_container.setHidden(False)
else:
self._hide.setIcon(qta.icon('mdi.plus'))
self._dclink_container.setHidden(True)
def _fill_dclink_container(self):
self._dclink_is_filled = True
self._dclink_container.layout().addWidget(
SummaryHeader(self.dclinks[0], self.visible_props, self))
for dclink_name in self.dclinks:
w = SummaryWidget(dclink_name, self.visible_props, self)
if self.dclinks_type == 'REGATRON_DCLink':
connect_newprocess(
w.detail_bt,
['sirius-hla-as-ps-regatron-individual',
'-dev', dclink_name],
parent=self, is_pydm=True)
else:
connect_window(w.detail_bt, PSDetailWindow,
self, psname=dclink_name)
self._dclink_container.layout().addWidget(w)
self.dclink_widgets.append(w)
[docs]
def update_visible_props(self, new_value):
self.visible_props = sort_propties(new_value)
self._enable_actions()
# Action methods
def _create_actions(self):
self._turn_on_action = QAction('Turn DCLinks On', self)
self._turn_on_action.triggered.connect(
lambda: self._set_dclink_pwrstate(True))
self._turn_on_action.setEnabled(False)
self._turn_off_action = QAction('Turn DCLinks Off', self)
self._turn_off_action.triggered.connect(
lambda: self._set_dclink_pwrstate(False))
self._turn_off_action.setEnabled(False)
self._open_loop_action = QAction('Open DCLinks Control Loop', self)
self._open_loop_action.triggered.connect(
lambda: self._set_dclink_control_loop(False))
self._open_loop_action.setEnabled(False)
self._close_loop_action = QAction('Close DCLinks Control Loop', self)
self._close_loop_action.triggered.connect(
lambda: self._set_dclink_control_loop(True))
self._close_loop_action.setEnabled(False)
self._set_setpoint_action = QAction('Set DCLinks Voltage', self)
self._set_setpoint_action.triggered.connect(self._set_setpoint)
self._set_setpoint_action.setEnabled(False)
self._reset_intlk_action = QAction('Reset DCLinks Interlocks', self)
self._reset_intlk_action.triggered.connect(self._reset_intlk)
self._reset_intlk_action.setEnabled(False)
def _enable_actions(self):
if 'state' in self.visible_props and \
not self._turn_on_action.isEnabled():
self._turn_on_action.setEnabled(True)
self._turn_off_action.setEnabled(True)
if 'ctrlloop' in self.visible_props and \
not self._open_loop_action.isEnabled():
self._open_loop_action.setEnabled(True)
self._close_loop_action.setEnabled(True)
if 'setpoint' in self.visible_props and \
not self._set_setpoint_action.isEnabled():
self._set_setpoint_action.setEnabled(True)
if 'reset' in self.visible_props and \
not self._reset_intlk_action.isEnabled():
self._reset_intlk_action.setEnabled(True)
def _set_dclink_pwrstate(self, value):
for dclink in self.dclink_widgets:
if value:
dclink.turn_on()
else:
dclink.turn_off()
def _set_dclink_control_loop(self, value):
for dclink in self.dclink_widgets:
btn = dclink.ctrlloop_bt
if value:
if btn._bit_val:
btn.send_value()
else:
if not btn._bit_val:
btn.send_value()
def _set_setpoint(self):
"""Set current setpoint for every visible widget."""
dlg = QInputDialog(self)
dlg.setLocale(QLocale(QLocale.English))
new_value, ok = dlg.getDouble(self, "New setpoint", "Value")
if ok:
for dclink in self.dclink_widgets:
sp = dclink.setpoint.spinbox
sp.value_changed(new_value)
try:
sp.send_value()
except TypeError:
pass
def _reset_intlk(self):
for dclink in self.dclink_widgets:
dclink.reset()
# Overloaded method
[docs]
def contextMenuEvent(self, event):
"""Overload to create a custom context menu."""
widget = self.childAt(event.pos())
if not widget:
return
parent = widget.parent()
grand_parent = parent.parent()
if widget.objectName() == 'DCLinkContainer' or \
parent.objectName() == 'DCLinkContainer' or \
grand_parent.objectName() == 'DCLinkContainer':
menu = QMenu(self)
menu.addAction(self._turn_on_action)
menu.addAction(self._turn_off_action)
menu.addSeparator()
menu.addAction(self._close_loop_action)
menu.addAction(self._open_loop_action)
menu.addSeparator()
menu.addAction(self._set_setpoint_action)
menu.addSeparator()
menu.addAction(self._reset_intlk_action)
menu.addSeparator()
action = menu.addAction('Show Connections...')
action.triggered.connect(self.show_connections)
menu.popup(event.globalPos())
else:
super().contextMenuEvent(event)
[docs]
def show_connections(self, checked):
"""."""
_ = checked
c = ConnectionInspector(self)
c.show()
[docs]
class BasePSControlWidget(QWidget):
"""Base widget class to control power supply."""
HORIZONTAL = 0
VERTICAL = 1
def __init__(self, subsection=None, orientation=0, parent=None):
"""Class constructor.
Parameters:
subsection
Default to None. To be used in filters defined in subclass.
orientation
Default to HORIZONTAL. Define how the different groups
(defined in subclasses) will be laid out.
"""
super(BasePSControlWidget, self).__init__(parent)
self._orientation = orientation
self._subsection = subsection
self._dev_list = PSSearch.get_psnames(self._getFilter(subsection))
dev0 = PVName(self._dev_list[0])
if dev0.sec == 'LI':
if dev0.dev == 'Slnd':
idcs = [int(PVName(dev).idx) for dev in self._dev_list]
self._dev_list = [
x for _, x in sorted(zip(idcs, self._dev_list))]
if 'Q' in dev0.dev:
all_props = dict()
for dev in self._dev_list:
all_props.update(get_prop2label(dev))
self.all_props = sort_propties(all_props)
else:
self.all_props = get_prop2label(self._dev_list[0])
else:
self.all_props = get_prop2label(self._dev_list[0])
self.visible_props = self._getVisibleProps()
if 'trim' in self.all_props:
self.visible_props.append('trim')
self.visible_props = sort_propties(self.visible_props)
# Data used to filter the widgets
self.ps_widgets_dict = dict()
self.containers_dict = dict()
self.filtered_widgets = set() # Set with key of visible widgets
# Get groups and respective power supplies
self.groups, self.groups2devs = list(), dict()
for group in self._getGroups():
pwrsupplies = list()
pattern = re.compile(group[1])
for el in self._dev_list:
if pattern.search(el):
pwrsupplies.append(el)
if not pwrsupplies:
continue
self.groups.append(group)
self.groups2devs[group[0]] = pwrsupplies
# Setup the UI
self._setup_ui()
self._create_actions()
self._enable_actions()
if len(self.groups) in [1, 3]:
self.setObjectName('cw')
self.setStyleSheet('#cw{min-height: 40em;}')
def _setup_ui(self):
self.layout = QVBoxLayout()
# Create filters
self.search_le = QLineEdit(parent=self)
self.search_le.setObjectName("search_lineedit")
self.search_le.setPlaceholderText("Search for a power supply...")
self.search_le.textEdited.connect(self._filter_pwrsupplies)
self.filter_pb = QPushButton(qta.icon('mdi.view-column'), '', self)
self.search_menu = QMenu(self.filter_pb)
self.filter_pb.setMenu(self.search_menu)
for prop, label in self.all_props.items():
act = self.search_menu.addAction(label)
act.setObjectName(prop)
act.setCheckable(True)
act.setChecked(prop in self.visible_props)
act.toggled.connect(self._set_widgets_visibility)
hlay_filter = QHBoxLayout()
hlay_filter.addWidget(self.search_le)
hlay_filter.addWidget(self.filter_pb)
self.layout.addLayout(hlay_filter)
self.count_label = QLabel(parent=self)
self.count_label.setSizePolicy(QSzPlcy.Maximum, QSzPlcy.Maximum)
self.layout.addWidget(self.count_label)
self.pwrsupplies_layout = self._getSplitter()
self.layout.addWidget(self.pwrsupplies_layout)
if len(self.groups) == 3:
splitt_v = QSplitter(Qt.Vertical)
# Build power supply Layout
# Create group boxes and pop. layout
for idx, group in enumerate(self.groups):
pwrsupplies = self.groups2devs[group[0]]
# Create header
header = SummaryHeader(pwrsupplies[0],
visible_props=self.visible_props,
parent=self)
self.containers_dict['header '+group[0]] = header
self.filtered_widgets.add('header '+group[0])
# Loop power supply to create all the widgets of a groupbox
group_widgets = list()
for psname in pwrsupplies:
ps_widget = SummaryWidget(
name=psname, visible_props=self.visible_props, parent=self)
pscontainer = PSContainer(ps_widget, self)
group_widgets.append(pscontainer)
self.containers_dict[psname] = pscontainer
self.filtered_widgets.add(psname)
self.ps_widgets_dict[psname] = ps_widget
# Create group
wid_type = 'groupbox' if group[0] else 'widget'
group_wid = self._createGroupWidget(
group[0], header, group_widgets, wid_type=wid_type)
# Add group box to grid layout
if len(self.groups) == 3:
if idx in [0, 1]:
splitt_v.addWidget(group_wid)
else:
self.pwrsupplies_layout.addWidget(splitt_v)
self.pwrsupplies_layout.addWidget(group_wid)
else:
self.pwrsupplies_layout.addWidget(group_wid)
self.count_label.setText(
"Showing {} power supplies.".format(
len(self.filtered_widgets)-len(self.groups)))
self.setLayout(self.layout)
def _createGroupWidget(self, title, header, widget_group,
wid_type='groupbox'):
scr_area_wid = QWidget(self)
scr_area_wid.setObjectName('scr_ar_wid')
scr_area_wid.setStyleSheet(
'#scr_ar_wid {background-color: transparent;}')
w_lay = QVBoxLayout(scr_area_wid)
w_lay.setSpacing(0)
w_lay.setContentsMargins(0, 0, 0, 0)
for widget in widget_group:
w_lay.addWidget(widget, alignment=Qt.AlignLeft)
w_lay.addStretch()
scr_area = QScrollArea(self)
scr_area.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scr_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scr_area.setWidgetResizable(True)
scr_area.setFrameShape(QFrame.NoFrame)
scr_area.setWidget(scr_area_wid)
wid = QGroupBox(title, self) if wid_type == 'groupbox' \
else QWidget(self)
gb_lay = QVBoxLayout(wid)
gb_lay.addWidget(header, alignment=Qt.AlignLeft)
gb_lay.addWidget(scr_area)
return wid
def _getSplitter(self):
if self._orientation == self.HORIZONTAL:
return QSplitter(Qt.Horizontal)
return QSplitter(Qt.Vertical)
def _getVisibleProps(self):
"""Default visible properties."""
return ['detail', 'state', 'intlk', 'setpoint', 'monitor',
'strength_sp', 'strength_mon']
def _filter_pwrsupplies(self, text):
"""Filter power supply widgets based on text inserted at line edit."""
try:
pattern = re.compile(text, re.I)
except Exception: # Ignore malformed patterns?
pattern = re.compile("malformed")
# Clear filtered widgets and add the ones that match the new pattern
self.filtered_widgets.clear()
for name, container in self.containers_dict.items():
cond = 'header' in name
if not cond:
cond |= bool(pattern.search(name))
cond |= bool(pattern.search(container.bbbname))
cond |= bool(pattern.search(container.udcname))
for dc in container.dclinks:
cond |= bool(pattern.search(dc))
for dc in container.dclinksbbbname:
cond |= bool(pattern.search(dc))
for dc in container.dclinksudcname:
cond |= bool(pattern.search(dc))
if cond:
self.filtered_widgets.add(name)
# Set widgets visibility and the number of widgets matched
self._set_widgets_visibility()
self.count_label.setText(
"Showing {} power supplies".format(
len(self.filtered_widgets)-len(self.groups)))
# Scroll to top
for scroll_area in self.findChildren(QScrollArea):
scroll_area.verticalScrollBar().setValue(0)
def _set_widgets_visibility(self):
"""Set visibility of the widgets."""
props = [act.objectName() for act in self.search_menu.actions()
if act.isChecked()]
self.visible_props = sort_propties(props)
self._enable_actions()
for key, wid in self.containers_dict.items():
wid.update_visible_props(props)
if 'header' in key:
for ob in wid.findChildren(QWidget):
name = ob.objectName()
ob.setVisible(name in props or 'Hidden' in name)
else:
vis = key in self.filtered_widgets
wid.setVisible(vis)
if not vis:
continue
objs = wid.findChildren(SummaryWidget)
objs.extend(wid.findChildren(SummaryHeader))
for ob in objs:
chil = ob.findChildren(
QWidget, options=Qt.FindDirectChildrenOnly)
for c in chil:
name = c.objectName()
if isinstance(ob, SummaryWidget) and name in props:
ob.fillWidget(name)
c.setVisible(name in props)
# Actions methods
def _create_actions(self):
self.turn_on_act = QAction("Turn On", self)
self.turn_on_act.triggered.connect(lambda: self._set_pwrstate(True))
self.turn_on_act.setEnabled(False)
self.turn_off_act = QAction("Turn Off", self)
self.turn_off_act.triggered.connect(lambda: self._set_pwrstate(False))
self.turn_off_act.setEnabled(False)
self.ctrlloop_close_act = QAction("Close Control Loop", self)
self.ctrlloop_close_act.triggered.connect(
lambda: self._set_ctrlloop(True))
self.ctrlloop_close_act.setEnabled(False)
self.ctrlloop_open_act = QAction("Open Control Loop", self)
self.ctrlloop_open_act.triggered.connect(
lambda: self._set_ctrlloop(False))
self.ctrlloop_open_act.setEnabled(False)
self.set_slowref_act = QAction("Set OpMode to SlowRef", self)
self.set_slowref_act.triggered.connect(self._set_slowref)
self.set_slowref_act.setEnabled(False)
self.set_current_sp_act = QAction("Set Current SP", self)
self.set_current_sp_act.triggered.connect(self._set_current_sp)
self.set_current_sp_act.setEnabled(False)
self.reset_act = QAction("Reset Interlocks", self)
self.reset_act.triggered.connect(self._reset_interlocks)
self.reset_act.setEnabled(False)
self.wfmupdate_on_act = QAction("Wfm Update Auto Enable", self)
self.wfmupdate_on_act.triggered.connect(
lambda: self._set_wfmupdate(True))
self.wfmupdate_on_act.setEnabled(False)
self.wfmupdate_off_act = QAction("Wfm Update Auto Disable", self)
self.wfmupdate_off_act.triggered.connect(
lambda: self._set_wfmupdate(False))
self.wfmupdate_off_act.setEnabled(False)
self.updparms_act = QAction("Update Parameters", self)
self.updparms_act.triggered.connect(self._update_params)
self.updparms_act.setEnabled(False)
self.idffmode_on_act = QAction("Set IDFFMode On", self)
self.idffmode_on_act.triggered.connect(
lambda: self._set_idffmode(True))
self.idffmode_on_act.setEnabled(False)
self.idffmode_off_act = QAction("Set IDFFMode Off", self)
self.idffmode_off_act.triggered.connect(
lambda: self._set_idffmode(False))
self.idffmode_off_act.setEnabled(False)
self.set_accfreeze_frozen_act = QAction(
"Set AccFreeze to frozen", self)
self.set_accfreeze_frozen_act.triggered.connect(
lambda: self._set_acc_freeze(True))
self.set_accfreeze_frozen_act.setEnabled(False)
self.set_accfreeze_unfrozen_act = QAction(
"Set AccFreeze to unfrozen", self)
self.set_accfreeze_unfrozen_act.triggered.connect(
lambda: self._set_acc_freeze(False))
self.set_accfreeze_unfrozen_act.setEnabled(False)
self.acc_clear_act = QAction("Clear Acc", self)
self.acc_clear_act.triggered.connect(self._acc_clear_cmd)
self.acc_clear_act.setEnabled(False)
def _enable_actions(self):
if 'state' in self.visible_props and \
not self.turn_on_act.isEnabled():
self.turn_on_act.setEnabled(True)
self.turn_off_act.setEnabled(True)
if 'ctrlloop' in self.visible_props and \
not self.ctrlloop_close_act.isEnabled():
self.ctrlloop_close_act.setEnabled(True)
self.ctrlloop_open_act.setEnabled(True)
if 'opmode' in self.visible_props and \
not self.set_slowref_act.isEnabled():
self.set_slowref_act.setEnabled(True)
if 'setpoint' in self.visible_props and \
not self.set_current_sp_act.isEnabled():
self.set_current_sp_act.setEnabled(True)
if 'reset' in self.visible_props and \
not self.reset_act.isEnabled():
self.reset_act.setEnabled(True)
if 'wfmupdate' in self.visible_props and \
not self.wfmupdate_on_act.isEnabled():
self.wfmupdate_on_act.setEnabled(True)
self.wfmupdate_off_act.setEnabled(True)
if 'updparms' in self.visible_props and \
not self.updparms_act.isEnabled():
self.updparms_act.setEnabled(True)
if 'idffmode' in self.visible_props and \
not self.idffmode_on_act.isEnabled():
self.idffmode_on_act.setEnabled(True)
self.idffmode_off_act.setEnabled(True)
if 'accfreeze' in self.visible_props and \
not self.set_accfreeze_frozen_act.isEnabled():
self.set_accfreeze_frozen_act.setEnabled(True)
self.set_accfreeze_unfrozen_act.setEnabled(True)
if 'accclear' in self.visible_props and \
not self.acc_clear_act.isEnabled():
self.acc_clear_act.setEnabled(True)
@Slot(bool)
def _set_pwrstate(self, state):
"""Execute turn on/off actions."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
if state:
widget.turn_on()
else:
widget.turn_off()
except TypeError:
pass
@Slot(bool)
def _set_ctrlloop(self, state):
"""Execute close/open control loop actions."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
if state:
widget.ctrlloop_close()
else:
widget.ctrlloop_open()
except TypeError:
pass
@Slot()
def _set_slowref(self):
"""Set opmode to SlowRef for every visible widget."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
widget.set_opmode_slowref()
except TypeError:
pass
@Slot()
def _set_current_sp(self):
"""Set current setpoint for every visible widget."""
dlg = QInputDialog(self)
dlg.setLocale(QLocale(QLocale.English))
new_value, ok = dlg.getDouble(self, "Insert current setpoint", "Value")
if ok:
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
sp = widget.setpoint.spinbox
sp.value_changed(new_value)
try:
sp.send_value()
except TypeError:
pass
@Slot()
def _reset_interlocks(self):
"""Reset interlocks."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
widget.reset()
except TypeError:
pass
@Slot(bool)
def _set_wfmupdate(self, state):
"""Execute turn WfmUpdateAuto on/off actions."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
if state:
widget.wfmupdate_on()
else:
widget.wfmupdate_off()
except TypeError:
pass
@Slot()
def _update_params(self):
"""Update parameters."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
widget.update_params()
except TypeError:
pass
@Slot(bool)
def _set_idffmode(self, state):
"""Execute turn IDFFMode on/off actions."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
if state:
widget.idffmode_on()
else:
widget.idffmode_off()
except TypeError:
pass
@Slot(bool)
def _set_acc_freeze(self, state):
"""Execute turn AccFreeze frozen/unfrozen actions."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
if state:
widget.set_accfreeze_frozen()
else:
widget.set_accfreeze_unfrozen()
except TypeError:
pass
@Slot()
def _acc_clear_cmd(self):
"""Reset interlocks."""
for key, widget in self.ps_widgets_dict.items():
if key in self.filtered_widgets:
try:
widget.acc_clear()
except TypeError:
pass
# Overloaded method
[docs]
def contextMenuEvent(self, event):
"""Show a custom context menu."""
point = event.pos()
menu = QMenu("Actions", self)
menu.addAction(self.turn_on_act)
menu.addAction(self.turn_off_act)
menu.addAction(self.set_current_sp_act)
menu.addAction(self.reset_act)
if not self._dev_list[0].dev in ('FCH', 'FCV'):
menu.addAction(self.ctrlloop_close_act)
menu.addAction(self.ctrlloop_open_act)
menu.addAction(self.set_slowref_act)
menu.addAction(self.wfmupdate_on_act)
menu.addAction(self.wfmupdate_off_act)
menu.addAction(self.updparms_act)
else:
menu.addAction(self.set_accfreeze_frozen_act)
menu.addAction(self.set_accfreeze_unfrozen_act)
menu.addAction(self.acc_clear_act)
if PSSearch.conv_psname_2_psmodel(self._dev_list[0]) == 'FBP':
menu.addAction(self.idffmode_on_act)
menu.addAction(self.idffmode_off_act)
menu.addSeparator()
action = menu.addAction('Show Connections...')
action.triggered.connect(self.show_connections)
menu.popup(self.mapToGlobal(point))
[docs]
def show_connections(self, checked):
"""."""
_ = checked
conn = ConnectionInspector(self)
conn.show()
[docs]
def get_summary_widgets(self):
"""Return Summary Widgets."""
return self.findChildren(SummaryWidget)