Source code for gui.modelwidget
# -*- coding: utf-8 -*-
# gui/modelwidget.py
from __future__ import absolute_import # PEP328
from builtins import str
from builtins import range
import sys
import logging
import imp
import os
from gui.qt import QtCore, QtGui
from gui.utils.signal import Signal, tryDisconnect
from QtGui import (QWidget, QVBoxLayout, QComboBox)
from gui.bases.mixins import TitleHandler, AppSettings
from utils import isString
from utils.findmodels import FindModels
from bases.model import ScatteringModel
from gui.scientrybox import SciEntryBox
from gui.algorithmwidget import AlgorithmWidget
from gui.utils.displayexception import DisplayException
from dataobj import DataObj
FIXEDWIDTH = 240
[docs]class ModelWidget(AlgorithmWidget):
_calculator = None
_statsWidget = None # RangeList for (re-)storing histogram settings
_models = None
def __init__(self, parent, calculator, *args):
super(ModelWidget, self).__init__(parent, None, *args)
self._calculator = calculator
self.title = TitleHandler.setup(self, "Model")
# get all loadable ScatteringModels from model directory
self._models = FindModels()
layout = QVBoxLayout(self)
layout.setObjectName("modelLayout")
self.setLayout(layout)
self.modelBox = QComboBox(self)
self.modelBox.setFixedWidth(FIXEDWIDTH)
layout.addWidget(self.modelBox)
self.modelWidget = QWidget(self)
paramLayout = QVBoxLayout(self.modelWidget)
self.modelWidget.setLayout(paramLayout)
layout.addWidget(self.modelWidget)
[docs] def setStatsWidget(self, statsWidget):
"""Sets the statistics widget to use for updating ranges."""
assert(isinstance(statsWidget, AppSettings))
self._statsWidget = statsWidget
[docs] def onDataSelected(self, dataobj):
"""Gets the data which is currently selected in the UI and rebuilds
the model selection box based on compatible models."""
if not isinstance(dataobj, DataObj):
return
try:
self.modelBox.currentIndexChanged[int].disconnect()
except:
pass
self.modelBox.clear()
# build selection list of available models
for modelid in self._models:
cls, dummy = self._models[modelid]
if cls is None or not issubclass(cls, dataobj.modelType):
continue
category = modelid.split('.')[0:-2]
if category[0] == self._models.rootName:
del category[0]
# set up the display name of the model, may contain category
displayName = " / ".join(category + [cls.name(),])
# store the unique model identifier alongside its title
self.modelBox.addItem(displayName, modelid)
self.modelBox.setCurrentIndex(-1) # select none first
self.modelBox.currentIndexChanged[int].connect(self._selectModelSlot)
# trigger signal by switching from none -> 0
self.modelBox.setCurrentIndex(0)
[docs] def storeSession(self, section = None):
if self.appSettings is None or self.model is None:
return
model = self.model.name()
self.setRootGroup()
self.appSettings.beginGroup(self.objectName())
self.appSettings.setValue("model", model)
super(ModelWidget, self).storeSession(model)
self.appSettings.endGroup()
self._statsWidget.storeSession()
[docs] def restoreSession(self, model = None):
"""Load last known user settings from persistent app settings."""
if self.appSettings is None:
return
if model is None:
# get the last model used and select it
self.appSettings.beginGroup(self.objectName())
model = self.appSettings.value("model")
self.appSettings.endGroup()
# calls restoreSession(model) and storeSession()
# mind the QSettings.group()
if not isString(model): # default model if none set
model = "Sphere"
self.selectModel(model)
else:
self.appSettings.beginGroup(self.objectName())
super(ModelWidget, self).restoreSession(model)
self.appSettings.endGroup()
self._statsWidget.restoreSession()
def _selectModelSlot(self, key = None):
# get the model by its unique name in the items data field
modelid = self.modelBox.itemData(key)
if modelid not in self._models:
return
model, dummy = self._models[modelid]
if model is None or not issubclass(model, ScatteringModel):
return
# store current settings before changing the model
self.storeSession()
self._calculator.model = model() # instantiate the model class
# remove parameter widgets from layout
layout = self.modelWidget.layout()
self.removeWidgets(self.modelWidget)
# create new parameter widget based on current selection
for p in self.model.params():
try:
widget = self.makeSetting(p, activeBtns = True)
layout.addWidget(widget)
except Exception as e:
DisplayException(e, fmt = u"An error occurred on building a "
"UI for parameter '{p}' in model '{m}'."
"<p><nobr>{e}</nobr></p>"
"Please see the log for a traceback."
.format(p = p.name(), m = self.model.name(), e = "{e}"))
self.removeWidgets(self.modelWidget)
self.modelBox.setCurrentIndex(0)
return
layout.addStretch()
# restore user settings for this model
self.restoreSession(self.model.name())
[docs] def selectModel(self, model):
"""*model*: string containing the name of the model to select.
Calls _selectModelSlot() via signal."""
if not isString(model):
return
index = 0
# search the model with the provided name
for i in range(0, self.modelBox.count()):
if self.modelBox.itemText(i).lower() == model.lower().strip():
index = i
break
# set the index found or the first one otherwise
self.modelBox.setCurrentIndex(index)
@AlgorithmWidget.algorithm.getter
def algorithm(self):
if self._calculator is None:
return None
return self._calculator.model
model = algorithm
[docs] def setSphericalSizeRange(self, minVal, maxVal):
key = "radius"
# get parameter display order of magnitude:
param = None
for p in self.model.params():
if key in p.name().lower():
param = p
break
if param is None:
logging.debug("No 'radius'-named parameter found, "
"not setting spherical size range!")
return False # nothing to do
keymin, keymax = key+"min", key+"max"
if self.get(keymin) is not None and self.get(keymax) is not None:
self.set(keymin, param.toDisplay(minVal))
self.set(keymax, param.toDisplay(maxVal))
return True
return False
# vim: set ts=4 sts=4 sw=4 tw=0: