Index: src/sas/qtgui/Perspectives/Fitting/AssociatedComboBox.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/AssociatedComboBox.py (revision 04f775db13543cbc91b64834af6068a163b77f8b)
+++ src/sas/qtgui/Perspectives/Fitting/AssociatedComboBox.py (revision 04f775db13543cbc91b64834af6068a163b77f8b)
@@ -0,0 +1,38 @@
+from PyQt5 import QtGui, QtWidgets
+
+
+class AssociatedComboBox(QtWidgets.QComboBox):
+ """Just a regular combo box, but associated with a particular QStandardItem so that it can be used to display and
+ select an item's current text and a restricted list of other possible text.
+
+ When the combo box's current text is changed, the change is immediately reflected in the associated item; either
+ the text itself is set as the item's data, or the current index is used; see constructor."""
+ item = None # type: QtGui.QStandardItem
+
+ def __init__(self, item, idx_as_value=False, parent=None):
+ # type: (QtGui.QStandardItem, bool, QtWidgets.QWidget) -> None
+ """
+ Initialize widget. idx_as_value indicates whether to use the combo box's current index (otherwise, current text)
+ as the associated item's new data.
+ """
+ super(AssociatedComboBox, self).__init__(parent)
+ self.item = item
+
+ if idx_as_value:
+ self.currentIndexChanged[int].connect(self._onIndexChanged)
+ else:
+ self.currentTextChanged.connect(self._onTextChanged)
+
+ def _onTextChanged(self, text):
+ # type: (str) -> None
+ """
+ Callback for combo box's currentTextChanged. Set associated item's data to the new text.
+ """
+ self.item.setText(text)
+
+ def _onIndexChanged(self, idx):
+ # type: (int) -> None
+ """
+ Callback for combo box's currentIndexChanged. Set associated item's data to the new index.
+ """
+ self.item.setText(str(idx))
Index: src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py (revision b764ae5882f084a8b74c7cf664276c13fb07c29e)
+++ src/sas/qtgui/Perspectives/Fitting/FittingUtilities.py (revision 04f775db13543cbc91b64834af6068a163b77f8b)
@@ -8,4 +8,6 @@
from sas.qtgui.Plotting.PlotterData import Data1D
from sas.qtgui.Plotting.PlotterData import Data2D
+
+from sas.qtgui.Perspectives.Fitting.AssociatedComboBox import AssociatedComboBox
model_header_captions = ['Parameter', 'Value', 'Min', 'Max', 'Units']
@@ -61,5 +63,33 @@
return (param_name, param_length)
-def addParametersToModel(parameters, kernel_module, is2D):
+def createFixedChoiceComboBox(param, item_row):
+ """
+ Determines whether param is a fixed-choice parameter, modifies items in item_row appropriately and returns a combo
+ box containing the fixed choices. Returns None if param is not fixed-choice.
+
+ item_row is a list of QStandardItem objects for insertion into the parameter table.
+ """
+
+ # Determine whether this is a fixed-choice parameter. There are lots of conditionals, simply because the
+ # implementation is not yet concrete; there are several possible indicators that the parameter is fixed-choice.
+ # TODO: (when the sasmodels implementation is concrete, clean this up)
+ choices = None
+ if type(param.choices) is list and len(param.choices) > 0:
+ # The choices property is concrete in sasmodels, probably will use this
+ choices = param.choices
+ elif type(param.units) is list:
+ choices = param.units
+
+ cbox = None
+ if choices is not None:
+ # Use combo box for input, if it is fixed-choice
+ cbox = AssociatedComboBox(item_row[1], idx_as_value=True)
+ cbox.addItems(choices)
+ item_row[2].setEditable(False)
+ item_row[3].setEditable(False)
+
+ return cbox
+
+def addParametersToModel(model, view, parameters, kernel_module, is2D):
"""
Update local ModelModel with sasmodel parameters
@@ -72,19 +102,19 @@
else:
params = parameters.iq_parameters
- item = []
+
for param in params:
# don't include shell parameters
if param.name == multishell_param_name:
continue
+
# Modify parameter name from [n] to 1
item_name = param.name
if param in multishell_parameters:
continue
- # item_name = replaceShellName(param.name, 1)
item1 = QtGui.QStandardItem(item_name)
item1.setCheckable(True)
item1.setEditable(False)
- # item_err = QtGui.QStandardItem()
+
# check for polydisp params
if param.polydisperse:
@@ -93,4 +123,5 @@
item1_1 = QtGui.QStandardItem("Distribution")
item1_1.setEditable(False)
+
# Find param in volume_params
for p in parameters.form_volume_parameters:
@@ -99,5 +130,4 @@
width = kernel_module.getParam(p.name+'.width')
ptype = kernel_module.getParam(p.name+'.type')
-
item1_2 = QtGui.QStandardItem(str(width))
item1_2.setEditable(False)
@@ -110,21 +140,27 @@
poly_item.appendRow([item1_1, item1_2, item1_3, item1_4, item1_5])
break
+
# Add the polydisp item as a child
item1.appendRow([poly_item])
+
# Param values
item2 = QtGui.QStandardItem(str(param.default))
- # TODO: the error column.
- # Either add a proxy model or a custom view delegate
- #item_err = QtGui.QStandardItem()
item3 = QtGui.QStandardItem(str(param.limits[0]))
item4 = QtGui.QStandardItem(str(param.limits[1]))
- item5 = QtGui.QStandardItem(param.units)
+ item5 = QtGui.QStandardItem(str(param.units))
item5.setEditable(False)
- item.append([item1, item2, item3, item4, item5])
- return item
-
-def addSimpleParametersToModel(parameters, is2D):
- """
- Update local ModelModel with sasmodel parameters
+
+ # Check if fixed-choice (returns combobox, if so, also makes some items uneditable)
+ row = [item1, item2, item3, item4, item5]
+ cbox = createFixedChoiceComboBox(param, row)
+
+ # Append to the model and use the combobox, if required
+ model.appendRow(row)
+ if cbox is not None:
+ view.setIndexWidget(item2.index(), cbox)
+
+def addSimpleParametersToModel(model, view, parameters, is2D):
+ """
+ Update local ModelModel with sasmodel parameters (non-dispersed, non-magnetic)
"""
if is2D:
@@ -132,5 +168,5 @@
else:
params = parameters.iq_parameters
- item = []
+
for param in params:
# Create the top level, checkable item
@@ -139,13 +175,21 @@
item1.setCheckable(True)
item1.setEditable(False)
+
# Param values
# TODO: add delegate for validation of cells
item2 = QtGui.QStandardItem(str(param.default))
- item4 = QtGui.QStandardItem(str(param.limits[0]))
- item5 = QtGui.QStandardItem(str(param.limits[1]))
- item6 = QtGui.QStandardItem(param.units)
- item6.setEditable(False)
- item.append([item1, item2, item4, item5, item6])
- return item
+ item3 = QtGui.QStandardItem(str(param.limits[0]))
+ item4 = QtGui.QStandardItem(str(param.limits[1]))
+ item5 = QtGui.QStandardItem(str(param.units))
+ item5.setEditable(False)
+
+ # Check if fixed-choice (returns combobox, if so, also makes some items uneditable)
+ row = [item1, item2, item3, item4, item5]
+ cbox = createFixedChoiceComboBox(param, row)
+
+ # Append to the model and use the combobox, if required
+ model.appendRow(row)
+ if cbox is not None:
+ view.setIndexWidget(item2.index(), cbox)
def markParameterDisabled(model, row):
Index: src/sas/qtgui/Perspectives/Fitting/FittingWidget.py
===================================================================
--- src/sas/qtgui/Perspectives/Fitting/FittingWidget.py (revision f84d793343c420fd47b44c3b601e90f9e82ea451)
+++ src/sas/qtgui/Perspectives/Fitting/FittingWidget.py (revision 04f775db13543cbc91b64834af6068a163b77f8b)
@@ -2050,8 +2050,11 @@
# Update the QModel
- new_rows = FittingUtilities.addParametersToModel(self.model_parameters, self.kernel_module, self.is2D)
-
- for row in new_rows:
- self._model_model.appendRow(row)
+ FittingUtilities.addParametersToModel(
+ self._model_model,
+ self.lstParams,
+ self.model_parameters,
+ self.kernel_module,
+ self.is2D)
+
# Update the counter used for multishell display
self._last_model_row = self._model_model.rowCount()
@@ -2071,11 +2074,17 @@
self.kernel_module = MultiplicationModel(form_kernel, structure_kernel)
- new_rows = FittingUtilities.addSimpleParametersToModel(structure_parameters, self.is2D)
- for row in new_rows:
- self._model_model.appendRow(row)
- # disable fitting of parameters not listed in self.kernel_module (probably radius_effective)
- if row[0].text() not in self.kernel_module.params.keys():
- row_num = self._model_model.rowCount() - 1
- FittingUtilities.markParameterDisabled(self._model_model, row_num)
+ # Update the QModel
+ FittingUtilities.addSimpleParametersToModel(
+ self._model_model,
+ self.lstParams,
+ structure_parameters,
+ self.is2D)
+
+ # Any parameters removed from the structure factor when producing the product model, e.g. radius_effective, must
+ # be disabled (greyed out, etc.)
+ for r in range(self._last_model_row, self._model_model.rowCount()):
+ param_name = self._model_model.item(r, 0).text()
+ if param_name not in self.kernel_module.params.keys():
+ FittingUtilities.markParameterDisabled(self._model_model, r)
# Update the counter used for multishell display