Commit 0fe68852 authored by Valentin Valls's avatar Valentin Valls
Browse files

Create a table to manage stored scans

parent 5713ec6f
......@@ -119,9 +119,13 @@ class CurvePlotWidget(plot_helper.PlotWidget):
plotItemSelected = qt.Signal(object)
"""Emitted when a flint plot item was selected by the plot"""
scanListUpdated = qt.Signal(object)
"""Emitted when the list of scans is changed"""
def __init__(self, parent=None):
super(CurvePlotWidget, self).__init__(parent=parent)
self.__scan: Optional[scan_model.Scan] = None
self.__scans: List[scan_model.Scan] = []
self.__maxScans = 3
self.__flintModel: Optional[flint_model.FlintState] = None
self.__plotModel: plot_model.Plot = None
......@@ -369,6 +373,7 @@ class CurvePlotWidget(plot_helper.PlotWidget):
self.__aggregator.callbackTo(self.__transactionFinished)
)
self.__plotModel = plotModel
self.__syncStyleStrategy()
if self.__plotModel is not None:
self.__plotModel.structureChanged.connect(
self.__aggregator.callbackTo(self.__structureChanged)
......@@ -535,6 +540,27 @@ class CurvePlotWidget(plot_helper.PlotWidget):
self.__boundingY2.setRange(xMin, xMax)
self.__boundingY2.setVisible(True)
def scanList(self):
return self.__scans
def removeScan(self, scan):
if scan is None:
return
if scan is self.__scan:
_logger.warning("Removing the current scan is not available")
return
self.__scans.remove(scan)
self.__syncStyleStrategy()
self.scanListUpdated.emit(self.__scans)
self.__redrawAllScans()
@property
def __scan(self):
if len(self.__scans) == 0:
return None
else:
return self.__scans[0]
def scan(self) -> Optional[scan_model.Scan]:
return self.__scan
......@@ -551,7 +577,12 @@ class CurvePlotWidget(plot_helper.PlotWidget):
self.__scan.scanFinished.disconnect(
self.__aggregator.callbackTo(self.__scanFinished)
)
self.__scan = scan
if scan is not None:
self.__scans.insert(0, scan)
while len(self.__scans) > self.__maxScans:
del self.__scans[-1]
self.__syncStyleStrategy()
self.scanListUpdated.emit(self.__scans)
if self.__scan is not None:
self.__scan.scanDataUpdated[object].connect(
self.__aggregator.callbackTo(self.__scanDataUpdated)
......@@ -569,6 +600,12 @@ class CurvePlotWidget(plot_helper.PlotWidget):
self.__redrawAllScans()
self.__syncAxisTitle.trigger()
def __syncStyleStrategy(self):
if self.__plotModel is not None:
styleStrategy = self.__plotModel.styleStrategy()
if styleStrategy is not None:
styleStrategy.setScans(self.__scans)
def __cleanScanIfNeeded(self, scan):
plotModel = self.__plotModel
if plotModel is None:
......@@ -648,9 +685,10 @@ class CurvePlotWidget(plot_helper.PlotWidget):
for scan in scanItems:
self.__redrawScan(scan.scan())
else:
currentScan = self.__scan
if currentScan is not None:
self.__redrawScan(currentScan)
for s in self.__scans:
if s is None:
continue
self.__redrawScan(s)
def __cleanScan(self, scan: scan_model.Scan):
items = self.__items.pop(scan, {})
......@@ -714,10 +752,10 @@ class CurvePlotWidget(plot_helper.PlotWidget):
for scan in scanItems:
self.__updatePlotItem(item, scan.scan())
else:
currentScan = self.__scan
if currentScan is None:
return
self.__updatePlotItem(item, currentScan)
for s in self.__scans:
if s is None:
continue
self.__updatePlotItem(item, s)
if reselect is not None:
self.selectPlotItem(reselect)
......
......@@ -10,6 +10,7 @@ from typing import Union
from typing import List
from typing import Dict
from typing import Optional
from typing import NamedTuple
import logging
import functools
......@@ -29,6 +30,7 @@ from bliss.flint.helper.style_helper import DefaultStyleStrategy
from bliss.flint.utils import qmodelutils
from bliss.flint.widgets.select_channel_dialog import SelectChannelDialog
from . import delegates
from . import data_views
from . import _property_tree_helper
......@@ -637,6 +639,60 @@ class _DataItem(_property_tree_helper.ScanRowItem):
self.updateError()
class ScanItem(NamedTuple):
scan: scan_model.Scan
plotModel: plot_model.Plot
curveWidget: qt.QWidget
class ScanTableView(data_views.VDataTableView):
ScanNbColumn = 0
ScanTitleColumn = 1
ScanStartTimeColumn = 2
ScanStyleColumn = 3
ScanRemoveColumn = 4
def initLayout(self):
"""Called after the model was set"""
self.setColumn(
self.ScanNbColumn,
title="Nb",
delegate=delegates.ScanNumberDelegate,
resizeMode=qt.QHeaderView.ResizeToContents,
)
self.setColumn(
self.ScanTitleColumn,
title="Title",
delegate=delegates.ScanTitleDelegate,
resizeMode=qt.QHeaderView.Stretch,
)
self.setColumn(
self.ScanStartTimeColumn,
title="Time",
delegate=delegates.ScanStartTimeDelegate,
resizeMode=qt.QHeaderView.ResizeToContents,
)
self.setColumn(
self.ScanStyleColumn,
title="Style",
delegate=delegates.StyleScanDelegate,
resizeMode=qt.QHeaderView.ResizeToContents,
)
self.setColumn(
self.ScanRemoveColumn,
title="Remove",
delegate=delegates.RemoveScanDelegate,
resizeMode=qt.QHeaderView.ResizeToContents,
)
self.setShowGrid(False)
self.verticalHeader().setVisible(False)
vheader = self.verticalHeader()
vheader.setDefaultSectionSize(30)
vheader.sectionResizeMode(qt.QHeaderView.Fixed)
class CurvePlotPropertyWidget(qt.QWidget):
NameColumn = 0
......@@ -680,12 +736,18 @@ class CurvePlotPropertyWidget(qt.QWidget):
line.setFrameShape(qt.QFrame.HLine)
line.setFrameShadow(qt.QFrame.Sunken)
self.__scanListView = ScanTableView(self)
self.__scanListModel = data_views.ObjectListModel(self)
self.__scanListView.setModel(self.__scanListModel)
self.__scanListView.initLayout()
layout = qt.QVBoxLayout(self)
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(0)
layout.addWidget(toolBar)
layout.addWidget(line)
layout.addWidget(self.__tree)
layout.addWidget(self.__scanListView)
def __removeAllItems(self):
if self.__plotModel is None:
......@@ -892,21 +954,26 @@ class CurvePlotPropertyWidget(qt.QWidget):
widget.plotModelUpdated.disconnect(self.__plotModelUpdated)
widget.plotItemSelected.disconnect(self.__selectionChangedFromPlot)
widget.scanModelUpdated.disconnect(self.__currentScanChanged)
widget.scanListUpdated.disconnect(self.__currentScanListChanged)
self.__focusWidget = widget
if self.__focusWidget is not None:
widget.plotModelUpdated.connect(self.__plotModelUpdated)
widget.plotItemSelected.connect(self.__selectionChangedFromPlot)
widget.scanModelUpdated.connect(self.__currentScanChanged)
widget.scanListUpdated.connect(self.__currentScanListChanged)
plotModel = widget.plotModel()
scanModel = widget.scan()
else:
plotModel = None
scanModel = None
self.__currentScanChanged(scanModel)
self.__currentScanListChanged(widget.scanList())
self.__plotModelUpdated(plotModel)
self.__syncScanModel()
def __plotModelUpdated(self, plotModel):
self.setPlotModel(plotModel)
self.__syncScanModel()
def setPlotModel(self, plotModel: plot_model.Plot):
if self.__plotModel is not None:
......@@ -923,6 +990,20 @@ class CurvePlotPropertyWidget(qt.QWidget):
def __currentScanChanged(self, scanModel):
self.__setScan(scanModel)
def __currentScanListChanged(self, scanList):
self.__syncScanModel()
def __syncScanModel(self):
widget = self.__focusWidget
if widget is None:
return
plotModel = self.__plotModel
if plotModel is None:
return
scans = widget.scanList()
scanList = [ScanItem(s, plotModel, widget) for s in scans]
self.__scanListModel.setObjectList(scanList)
def __structureChanged(self):
if self.__plotModel.isInTransaction():
self.__structureInvalidated = True
......
......@@ -181,6 +181,86 @@ class StyleItemDelegate(qt.QStyledItemDelegate):
editor.move(pos)
class RemovePropertyItemDelegate(qt.QStyledItemDelegate):
def __init__(self, parent):
qt.QStyledItemDelegate.__init__(self, parent=parent)
def createEditor(self, parent, option, index):
if not index.isValid():
return super(RemovePropertyItemDelegate, self).createEditor(
parent, option, index
)
editor = RemovePlotItemButton(parent=parent)
plotItem = self.getPlotItem(index)
editor.setVisible(plotItem is not None)
return editor
def getPlotItem(self, index) -> Union[None, plot_model.Item]:
plotItem = index.data(PlotItemRole)
if not isinstance(plotItem, plot_model.Item):
return None
return plotItem
def setEditorData(self, editor, index):
plotItem = self.getPlotItem(index)
editor.setVisible(plotItem is not None)
editor.setPlotItem(plotItem)
def setModelData(self, editor, model, index):
pass
class StyleScanDelegate(qt.QStyledItemDelegate):
"""Style delegate to display scan style.
"""
def __init__(self, parent=None, editable=False):
qt.QStyledItemDelegate.__init__(self, parent=parent)
self.__editable = editable
def createEditor(self, parent, option, index):
if not index.isValid():
return super(StyleScanDelegate, self).createEditor(parent, option, index)
editor = StylePropertyWidget(parent)
editor.setEditable(self.__editable)
editor.setMinimumSize(editor.sizeHint())
self.__updateEditor(editor, index)
return editor
def __getFirstItem(self, plotModel: plot_model.Plot):
if plotModel is None:
return None
for item in plotModel.items():
if isinstance(item, plot_item_model.ScanItem):
pass
elif isinstance(item, plot_model.ComputableMixIn):
pass
else:
return item
return None
def __updateEditor(self, editor: qt.QWidget, index: qt.QModelIndex):
scanItem = index.data(ObjectRole)
plotItem = self.__getFirstItem(scanItem.plotModel)
editor.setScan(scanItem.scan)
editor.setPlotItem(plotItem)
def setEditorData(self, editor, index):
self.__updateEditor(editor, index)
def setModelData(self, editor, model, index):
pass
def updateEditorGeometry(self, editor, option, index):
# Center the widget to the cell
size = editor.sizeHint()
half = size / 2
halfPoint = qt.QPoint(half.width(), half.height() - 1)
pos = option.rect.center() - halfPoint
editor.move(pos)
class RemovePlotItemButton(qt.QToolButton):
def __init__(self, parent: qt.QWidget = None):
super(RemovePlotItemButton, self).__init__(parent=parent)
......@@ -202,30 +282,112 @@ class RemovePlotItemButton(qt.QToolButton):
self.__plotItem = plotItem
class RemovePropertyItemDelegate(qt.QStyledItemDelegate):
def __init__(self, parent):
qt.QStyledItemDelegate.__init__(self, parent=parent)
class RemoveScanButton(qt.QToolButton):
def __init__(self, parent: qt.QWidget = None):
super(RemoveScanButton, self).__init__(parent=parent)
self.__scan: Optional[scan_model.Scan] = None
self.__plotWidget: Optional[qt.QWidget] = None
self.clicked.connect(self.__requestRemoveScan)
icon = icons.getQIcon("flint:icons/remove-item")
self.setIcon(icon)
self.setAutoRaise(True)
def __requestRemoveScan(self):
widget = self.__plotWidget
widget.removeScan(self.__scan)
def setScan(self, scan: scan_model.Scan):
self.__scan = scan
def setPlotWidget(self, plotWidget: qt.QWidget):
self.__plotWidget = plotWidget
class RemoveScanDelegate(qt.QStyledItemDelegate):
def createEditor(self, parent, option, index):
if not index.isValid():
return super(RemovePropertyItemDelegate, self).createEditor(
parent, option, index
)
editor = RemovePlotItemButton(parent=parent)
plotItem = self.getPlotItem(index)
editor.setVisible(plotItem is not None)
return super(RemoveScanDelegate, self).createEditor(parent, option, index)
editor = RemoveScanButton(parent=parent)
self.setEditorData(editor, index)
return editor
def getPlotItem(self, index) -> Union[None, plot_model.Item]:
plotItem = index.data(PlotItemRole)
if not isinstance(plotItem, plot_model.Item):
return None
return plotItem
def setEditorData(self, editor, index):
scanItem = index.data(ObjectRole)
editor.setScan(scanItem.scan)
editor.setPlotWidget(scanItem.curveWidget)
isRemovable = True
if scanItem.scan is None or scanItem.curveWidget is None:
isRemovable = False
else:
if scanItem.scan is scanItem.curveWidget.scan():
isRemovable = False
editor.setToolTip("The active scan can't be removed")
editor.setEnabled(isRemovable)
def setModelData(self, editor, model, index):
pass
class ScanNumberDelegate(qt.QStyledItemDelegate):
def createEditor(self, parent, option, index):
if not index.isValid():
return super().createEditor(parent, option, index)
editor = qt.QLabel(parent=parent)
return editor
def setEditorData(self, editor, index):
plotItem = self.getPlotItem(index)
editor.setVisible(plotItem is not None)
editor.setPlotItem(plotItem)
scanItem = index.data(ObjectRole)
scanInfo = scanItem.scan.scanInfo()
scanNb = scanInfo.get("scan_nb", None)
if scanNb is None:
scanNb = ""
else:
scanNb = f"#{scanNb}"
editor.setText(scanNb)
def setModelData(self, editor, model, index):
pass
class ScanTitleDelegate(qt.QStyledItemDelegate):
def createEditor(self, parent, option, index):
if not index.isValid():
return super().createEditor(parent, option, index)
editor = qt.QLabel(parent=parent)
return editor
def setEditorData(self, editor, index):
scanItem = index.data(ObjectRole)
scanInfo = scanItem.scan.scanInfo()
scanTitle = scanInfo.get("title", None)
if scanTitle is None:
scanTitle = scanInfo.get("type", None)
if scanTitle is None:
scanTitle = ""
editor.setText(scanTitle)
def setModelData(self, editor, model, index):
pass
class ScanStartTimeDelegate(qt.QStyledItemDelegate):
def createEditor(self, parent, option, index):
if not index.isValid():
return super().createEditor(parent, option, index)
editor = qt.QLabel(parent=parent)
return editor
def __toStartTimeText(self, scan: scan_model.Scan) -> str:
scanInfo = scan.scanInfo()
value = scanInfo.get("start_time", None)
if value is None:
return ""
return value.strftime("%H:%M")
def setEditorData(self, editor, index):
scanItem = index.data(ObjectRole)
text = self.__toStartTimeText(scanItem.scan)
editor.setText(text)
def setModelData(self, editor, model, index):
pass
......@@ -365,6 +527,10 @@ class StylePropertyWidget(qt.QWidget):
def __currentScanChanged(self):
self.__setScan(self.__flintModel.currentScan())
def setScan(self, scan: Union[None, scan_model.Scan]):
self.__scan = scan
self.__update()
def __setScan(self, scan: Union[None, scan_model.Scan]):
self.__scan = scan
self.__update()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment