Rebuild NodeWidget when the description changes

+ add descriptionChanged signal
* track detached of TabWidgetStorage correctly
* build new NodeWidget when the nodes description changes. the old one
  is replaced

Change-Id: I61e60c61b7c2c975819730cb98562657a66f16af
Reviewed-on: https://forge.frm2.tum.de/review/c/secop/frappy/+/30910
Tested-by: Jenkins Automated Tests <pedersen+jenkins@frm2.tum.de>
Reviewed-by: Enrico Faulhaber <enrico.faulhaber@frm2.tum.de>
Reviewed-by: Alexander Zaft <a.zaft@fz-juelich.de>
This commit is contained in:
Alexander Zaft 2023-04-18 09:29:46 +02:00 committed by Markus Zolliker
parent f069b31d5a
commit 42c5e97122
4 changed files with 56 additions and 1 deletions

View File

@ -30,6 +30,7 @@ class QSECNode(QObject):
newData = pyqtSignal(str, str, object) # module, parameter, data
stateChange = pyqtSignal(str, bool, str) # node name, online, connection state
unhandledMsg = pyqtSignal(str) # message
descriptionChanged = pyqtSignal(str, object) # contactpoint, self
logEntry = pyqtSignal(str)
def __init__(self, uri, parent_logger, parent=None):
@ -48,7 +49,7 @@ class QSECNode(QObject):
self.protocolVersion = conn.secop_version
self.log.debug('SECoP Version: %s', conn.secop_version)
conn.register_callback(None, self.updateItem, self.nodeStateChange,
self.unhandledMessage)
self.unhandledMessage, self.descriptiveDataChange)
# provide methods from old baseclient for making other gui code work
def reconnect(self):
@ -106,5 +107,10 @@ class QSECNode(QObject):
def unhandledMessage(self, action, specifier, data):
self.unhandledMsg.emit(f'{action} {specifier} {data!r}')
def descriptiveDataChange(self, _module, conn):
self.modules = conn.modules
self.properties = conn.properties
self.descriptionChanged.emit(self.contactPoint, self)
def terminate_connection(self):
self.conn.disconnect()

View File

@ -229,6 +229,7 @@ class MainWindow(QMainWindow):
self.tab.addTab(nodeWidget, node.equipmentId)
self._nodeWidgets[host] = nodeWidget
self.tab.setCurrentWidget(nodeWidget)
node.descriptionChanged.connect(self._descriptiveDataChange)
# add to recent nodes
settings = QSettings()
@ -275,6 +276,16 @@ class MainWindow(QMainWindow):
self.log.debug("Closing tab with node %s", node.nodename)
self.tab.removeTab(index)
def _descriptiveDataChange(self, host, node):
old_widget = self._nodeWidgets[host]
new_widget = NodeWidget(node)
curr_idx = self.tab.currentIndex()
index = self.tab.indexOf(old_widget)
self._nodeWidgets[host] = new_widget
self.tab.replace_widget(old_widget, new_widget, title=node.equipmentId)
if curr_idx == index:
self.tab.setCurrentIndex(curr_idx)
def _rebuildAdvanced(self, advanced):
if advanced:
pass

View File

@ -170,7 +170,18 @@ class ModuleOverview(QTreeWidget):
module.disconnected()
def setToReconnected(self):
"""set status after connection is reestablished.
If the node-description has changed during the reconnection, the nodewidget
this overview is a part of gets replaced. However, the reconnect-event
gets through before the descriptionChanged-event. So if a module is no
longer present we return early in order to avoid KeyErrors on node.modules
For the case of additional modules or changed module contents we do not care.
"""
nodemods = self._node.modules.keys()
for mname, module in self._modules.items():
if mname not in nodemods:
return # description changed and we will be replaced, return early
cache = self._node.queryCache(mname)
if not 'status' in cache:
module.setClearIcon()

View File

@ -296,6 +296,7 @@ class TearOffTabWidget(QTabWidget):
for i in self.tabIdx.values():
if i.widget == w:
detachWindow.tabIdx = self.tabIdx[i.index].index
self.tabIdx[i.index].detached = detachWindow
break
detachWindow.closed.connect(self.attachTab)
@ -383,6 +384,9 @@ class TearOffTabWidget(QTabWidget):
if newIndex != -1:
self.setCurrentIndex(newIndex)
idx = self.find_widget(tearOffWidget)
self.tabIdx[idx].detached = None
def tabChangedTab(self, index):
# for i in range(self.count()):
# for p in self.widget(i).panels:
@ -463,6 +467,29 @@ class TearOffTabWidget(QTabWidget):
# # QByteArray))
# detachWindow.show()
def find_widget(self, widget):
for idx, tab in self.tabIdx.items():
if tab.widget == widget:
return idx
return None
def replace_widget(self, old_widget, new_widget, title=None):
"""If old_widget is a child of either a tab or a detached window, it will
be replaced by new_widget"""
idx = self.find_widget(old_widget)
if not idx:
return
wstore = self.tabIdx[idx]
if title:
wstore.title = title
if wstore.detached:
wstore.detached.setWidget(new_widget)
else:
tabi = self._tabWidgetIndex(old_widget)
self.removeTab(tabi)
self.insertTab(tabi, new_widget, wstore.title)
wstore.widget = new_widget
def topLevelWidget(self, w):
widget = w
while True: