Changeset be8f4b0 in sasview for src/sas/qtgui


Ignore:
Timestamp:
Jan 16, 2018 4:50:31 AM (7 years ago)
Author:
Piotr Rozyczko <rozyczko@…>
Branches:
ESS_GUI, ESS_GUI_Docs, ESS_GUI_batch_fitting, ESS_GUI_bumps_abstraction, ESS_GUI_iss1116, ESS_GUI_iss879, ESS_GUI_iss959, ESS_GUI_opencl, ESS_GUI_ordering, ESS_GUI_sync_sascalc
Children:
47d7d2d
Parents:
676f137
Message:

Context menus for tab and constraint list widgets.
Dynamic bindings of add/remove for FPs and the C&S widget

Location:
src/sas/qtgui
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • src/sas/qtgui/Perspectives/Fitting/ConstraintWidget.py

    r676f137 rbe8f4b0  
    88 
    99from sas.qtgui.Perspectives.Fitting.UI.ConstraintWidgetUI import Ui_ConstraintWidgetUI 
     10from sas.qtgui.Perspectives.Fitting.FittingWidget import FittingWidget 
    1011 
    1112class ConstraintWidget(QtWidgets.QWidget, Ui_ConstraintWidgetUI): 
    1213    """ 
    13     Constraints Dialog to select the desired parameter/model constraints 
     14    Constraints Dialog to select the desired parameter/model constraints. 
    1415    """ 
    1516 
     
    2021        self.currentType = "FitPage" 
    2122 
     23        # Set up the widgets 
     24        self.initializeWidgets() 
     25 
    2226        # Set up signals/slots 
    2327        self.initializeSignals() 
    2428 
    2529        # Create the list of tabs 
    26         self.updateFitList() 
     30        self.initializeFitList() 
     31 
     32    def acceptsData(self): 
     33        """ Tells the caller this widget doesn't accept data """ 
     34        return False 
     35 
     36    def initializeWidgets(self): 
     37        """ 
     38        Set up various widget states 
     39        """ 
     40        labels = ['FitPage', 'Model', 'Data', 'Mnemonics'] 
     41        # tab widget - headers 
     42        self.tblTabList.setColumnCount(len(labels)) 
     43        self.tblTabList.setHorizontalHeaderLabels(labels) 
     44        self.tblTabList.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) 
     45 
     46        self.tblTabList.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) 
     47        self.tblTabList.customContextMenuRequested.connect(self.showModelContextMenu) 
     48 
     49        # disabled constraint  
     50        labels = ['Constraint'] 
     51        self.tblConstraints.setColumnCount(len(labels)) 
     52        self.tblConstraints.setHorizontalHeaderLabels(labels) 
     53        self.tblConstraints.horizontalHeader().setSectionResizeMode(QtWidgets.QHeaderView.Stretch) 
     54        self.tblConstraints.setEnabled(False) 
     55 
     56        self.tblConstraints.setContextMenuPolicy(QtCore.Qt.CustomContextMenu) 
     57        self.tblConstraints.customContextMenuRequested.connect(self.showConstrContextMenu) 
    2758 
    2859    def initializeSignals(self): 
     
    3263        self.btnSingle.toggled.connect(self.onFitTypeChange) 
    3364        self.btnBatch.toggled.connect(self.onFitTypeChange) 
    34         self.cbSeries.indexChanged.connect(self.onSpecialCaseChange) 
     65        self.cbCases.currentIndexChanged.connect(self.onSpecialCaseChange) 
    3566        self.cmdFit.clicked.connect(self.onFit) 
    3667        self.cmdHelp.clicked.connect(self.onHelp) 
     68        self.parent.tabsModifiedSignal.connect(self.initializeFitList) 
     69 
     70    def updateSignalsFromTab(self, tab=None): 
     71        """ 
     72        Intercept update signals from fitting tabs 
     73        """ 
     74        if tab is not None: 
     75            ObjectLibrary.getObject(tab).constraintAddedSignal.connect(self.initializeFitList) 
     76            ObjectLibrary.getObject(tab).newModelSignal.connect(self.initializeFitList) 
    3777 
    3878    def onFitTypeChange(self, checked): 
     
    61101        pass 
    62102 
    63     def updateFitList(self): 
     103    def isTabImportable(self, tab): 
     104        """ 
     105        Determines if the tab can be imported and included in the widget 
     106        """ 
     107        if not self.currentType in tab: return False 
     108        object = ObjectLibrary.getObject(tab) 
     109        if not isinstance(object, FittingWidget): return False 
     110        if object.data is None: return False 
     111        return True 
     112 
     113    def showModelContextMenu(self, position): 
     114        """ 
     115        Show context specific menu in the tab table widget. 
     116        """ 
     117        menu = QtWidgets.QMenu() 
     118        rows = [s.row() for s in self.tblTabList.selectionModel().selectedRows()] 
     119        num_rows = len(rows) 
     120        if num_rows <= 0: 
     121            return 
     122        # Select for fitting 
     123        param_string = "Fit Page " if num_rows==1 else "Fit Pages " 
     124        to_string = "to its current value" if num_rows==1 else "to their current values" 
     125 
     126        self.actionSelect = QtWidgets.QAction(self) 
     127        self.actionSelect.setObjectName("actionSelect") 
     128        self.actionSelect.setText(QtCore.QCoreApplication.translate("self", "Select "+param_string+" for fitting")) 
     129        # Unselect from fitting 
     130        self.actionDeselect = QtWidgets.QAction(self) 
     131        self.actionDeselect.setObjectName("actionDeselect") 
     132        self.actionDeselect.setText(QtCore.QCoreApplication.translate("self", "De-select "+param_string+" from fitting")) 
     133 
     134        self.actionRemoveConstraint = QtWidgets.QAction(self) 
     135        self.actionRemoveConstraint.setObjectName("actionRemoveConstrain") 
     136        self.actionRemoveConstraint.setText(QtCore.QCoreApplication.translate("self", "Remove all constraints on selected models")) 
     137 
     138        self.actionMutualMultiConstrain = QtWidgets.QAction(self) 
     139        self.actionMutualMultiConstrain.setObjectName("actionMutualMultiConstrain") 
     140        self.actionMutualMultiConstrain.setText(QtCore.QCoreApplication.translate("self", "Mutual constrain of parameters in selected models...")) 
     141 
     142        menu.addAction(self.actionSelect) 
     143        menu.addAction(self.actionDeselect) 
     144        menu.addSeparator() 
     145 
     146        #menu.addAction(self.actionRemoveConstraint) 
     147        if num_rows >= 2: 
     148            menu.addAction(self.actionMutualMultiConstrain) 
     149 
     150        # Define the callbacks 
     151        #self.actionConstrain.triggered.connect(self.addSimpleConstraint) 
     152        #self.actionRemoveConstraint.triggered.connect(self.deleteConstraint) 
     153        #self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstraint) 
     154        self.actionSelect.triggered.connect(self.selectModels) 
     155        self.actionDeselect.triggered.connect(self.deselectModels) 
     156        try: 
     157            menu.exec_(self.tblTabList.viewport().mapToGlobal(position)) 
     158        except AttributeError as ex: 
     159            logging.error("Error generating context menu: %s" % ex) 
     160        return 
     161 
     162    def showConstrContextMenu(self, position): 
     163        """ 
     164        Show context specific menu in the tab table widget. 
     165        """ 
     166        menu = QtWidgets.QMenu() 
     167        rows = [s.row() for s in self.tblConstraints.selectionModel().selectedRows()] 
     168        num_rows = len(rows) 
     169        if num_rows <= 0: 
     170            return 
     171        # Select for fitting 
     172        param_string = "constraint " if num_rows==1 else "constraints " 
     173        to_string = "to its current value" if num_rows==1 else "to their current values" 
     174 
     175        self.actionSelect = QtWidgets.QAction(self) 
     176        self.actionSelect.setObjectName("actionSelect") 
     177        self.actionSelect.setText(QtCore.QCoreApplication.translate("self", "Select "+param_string+" for fitting")) 
     178        # Unselect from fitting 
     179        self.actionDeselect = QtWidgets.QAction(self) 
     180        self.actionDeselect.setObjectName("actionDeselect") 
     181        self.actionDeselect.setText(QtCore.QCoreApplication.translate("self", "De-select "+param_string+" from fitting")) 
     182 
     183        self.actionRemoveConstraint = QtWidgets.QAction(self) 
     184        self.actionRemoveConstraint.setObjectName("actionRemoveConstrain") 
     185        self.actionRemoveConstraint.setText(QtCore.QCoreApplication.translate("self", "Remove "+param_string)) 
     186 
     187        menu.addAction(self.actionSelect) 
     188        menu.addAction(self.actionDeselect) 
     189        menu.addSeparator() 
     190        menu.addAction(self.actionRemoveConstraint) 
     191 
     192        # Define the callbacks 
     193        #self.actionConstrain.triggered.connect(self.addSimpleConstraint) 
     194        self.actionRemoveConstraint.triggered.connect(self.deleteConstraint) 
     195        #self.actionMutualMultiConstrain.triggered.connect(self.showMultiConstraint) 
     196        self.actionSelect.triggered.connect(self.selectConstraints) 
     197        self.actionDeselect.triggered.connect(self.deselectConstraints) 
     198        try: 
     199            menu.exec_(self.tblConstraints.viewport().mapToGlobal(position)) 
     200        except AttributeError as ex: 
     201            logging.error("Error generating context menu: %s" % ex) 
     202        return 
     203 
     204    def selectConstraints(self): 
     205        """ 
     206        Selected constraints are chosen for fitting 
     207        """ 
     208        status = QtCore.Qt.Checked 
     209        self.setRowSelection(self.tblConstraints, status) 
     210 
     211    def deselectConstraints(self): 
     212        """ 
     213        Selected constraints are removed for fitting 
     214        """ 
     215        status = QtCore.Qt.Unchecked 
     216        self.setRowSelection(self.tblConstraints, status) 
     217 
     218    def selectModels(self): 
     219        """ 
     220        Selected models are chosen for fitting 
     221        """ 
     222        status = QtCore.Qt.Checked 
     223        self.setRowSelection(self.tblTabList, status) 
     224 
     225    def deselectModels(self): 
     226        """ 
     227        Selected models are removed for fitting 
     228        """ 
     229        status = QtCore.Qt.Unchecked 
     230        self.setRowSelection(self.tblTabList, status) 
     231 
     232    def selectedParameters(self, widget): 
     233        """ Returns list of selected (highlighted) parameters """ 
     234        return [s.row() for s in widget.selectionModel().selectedRows()] 
     235 
     236    def setRowSelection(self, widget, status=QtCore.Qt.Unchecked): 
     237        """ 
     238        Selected models are chosen for fitting 
     239        """ 
     240        # Convert to proper indices and set requested enablement 
     241        for row in self.selectedParameters(widget): 
     242            widget.item(row, 0).setCheckState(status) 
     243 
     244    def deleteConstraint(self):#, row): 
     245        """ 
     246        Delete all selected constraints. 
     247        """ 
     248        constraints_to_delete = [] 
     249        for row in self.selectedParameters(self.tblConstraints): 
     250            constraints_to_delete.append(self.tblConstraints.item(row, 0).data(0)) 
     251        for constraint in constraints_to_delete: 
     252            moniker = constraint[:constraint.index(':')] 
     253            param = constraint[constraint.index(':')+1:constraint.index('=')].strip() 
     254            tab = self.available_tabs[moniker] 
     255            tab.deleteConstraintOnParameter(param) 
     256        # Constraints removed - refresh the table widget 
     257        self.initializeFitList() 
     258 
     259    def updateFitLine(self, tab): 
     260        """ 
     261        Update a single line of the table widget with tab info 
     262        """ 
     263        model = ObjectLibrary.getObject(tab).kernel_module 
     264        if model is None: 
     265            return 
     266        tab_name = tab 
     267        model_name = model.id 
     268        moniker = model.name 
     269        model_data = ObjectLibrary.getObject(tab).data 
     270        model_filename = model_data.filename 
     271        self.available_tabs[moniker] = ObjectLibrary.getObject(tab) 
     272 
     273        # Update the model table widget 
     274        item = QtWidgets.QTableWidgetItem(tab_name) 
     275        item.setCheckState(QtCore.Qt.Checked) 
     276        pos = self.tblTabList.rowCount() 
     277        self.tblTabList.insertRow(pos) 
     278        self.tblTabList.setItem(pos, 0, item) 
     279        self.tblTabList.setItem(pos, 1, QtWidgets.QTableWidgetItem(model_name)) 
     280        self.tblTabList.setItem(pos, 2, QtWidgets.QTableWidgetItem(model_filename)) 
     281        self.tblTabList.setItem(pos, 3, QtWidgets.QTableWidgetItem(moniker)) 
     282 
     283        #self.available_tabs[pos] = (model, model_data) 
     284        #self.available_tabs[moniker] = tab 
     285 
     286        # Check if any constraints present in tab 
     287        constraints = ObjectLibrary.getObject(tab).getConstraintsForModel() 
     288        if not constraints:  
     289            return 
     290        self.tblConstraints.setEnabled(True) 
     291        for constraint in constraints: 
     292            # Create the text for widget item 
     293            label = moniker + ":"+ constraint[0] + " = " + constraint[1] 
     294 
     295            # Show the text in the constraint table 
     296            item = QtWidgets.QTableWidgetItem(label) 
     297            item.setCheckState(QtCore.Qt.Checked) 
     298            pos = self.tblConstraints.rowCount() 
     299            self.tblConstraints.insertRow(pos) 
     300            self.tblConstraints.setItem(pos, 0, item) 
     301            self.available_constraints[pos] = constraints 
     302 
     303    def initializeFitList(self): 
    64304        """ 
    65305        Fill the list of model/data sets for fitting/constraining 
    66306        """ 
    67307        # look at the object library to find all fit tabs 
     308        # Show the content of the current "model" 
    68309        objects = ObjectLibrary.listObjects() 
     310 
     311        # Tab dict 
     312        # moniker -> (kernel_module, data) 
     313        self.available_tabs = {} 
     314        # Constraint dict 
     315        # moniker -> [constraints] 
     316        self.available_constraints = {} 
     317 
     318        # Reset the table widgets 
     319        self.tblTabList.setRowCount(0) 
     320        self.tblConstraints.setRowCount(0) 
     321 
     322        # Fit disabled 
     323        self.cmdFit.setEnabled(False) 
     324 
    69325        if not objects: 
    70326            return 
    71         tabs = [tab for tab in ObjectLibrary.listObjects() if self.currentType in tab] 
    72  
    73         pass 
    74  
    75     def updateConstraintList(self): 
    76         """ 
    77         Fill the list of constraints for the current selection of model/data sets 
    78         """ 
    79         pass 
    80  
    81  
     327 
     328        tabs = [tab for tab in ObjectLibrary.listObjects() if self.isTabImportable(tab)] 
     329        for tab in tabs: 
     330            self.updateFitLine(tab) 
     331            self.updateSignalsFromTab(tab) 
     332            # We have at least 1 fit page, allow fitting 
     333            self.cmdFit.setEnabled(True) 
  • src/sas/qtgui/Perspectives/Fitting/FittingPerspective.py

    r676f137 rbe8f4b0  
    1818    """ 
    1919    """ 
     20    tabsModifiedSignal = QtCore.pyqtSignal() 
    2021    name = "Fitting" # For displaying in the combo box in DataExplorer 
    2122    def __init__(self, parent=None, data=None): 
     
    117118        self.maxIndex += 1 
    118119        self.addTab(tab, tab_name) 
     120        self.tabsModifiedSignal.emit() 
    119121 
    120122    def addConstraintTab(self): 
     
    122124        Add a new C&S fitting tab 
    123125        """ 
    124         tab     = ConstraintWidget(parent=self.parent) 
     126        tab     = ConstraintWidget(parent=self) 
    125127        # Add this tab to the object library so it can be retrieved by scripting/jupyter 
    126128        tab_name = self.getCSTabName() # TODO update the tab name scheme 
     
    182184            self.removeTab(index) 
    183185            del self.tabs[index] 
     186            self.tabsModifiedSignal.emit() 
    184187        except IndexError: 
    185188            # The tab might have already been deleted previously 
  • src/sas/qtgui/Perspectives/Fitting/FittingWidget.py

    r676f137 rbe8f4b0  
    8282    Main widget for selecting form and structure factor models 
    8383    """ 
    84     #constraintAddedSignal = QtCore.pyqtSignal(list) 
     84    constraintAddedSignal = QtCore.pyqtSignal(list) 
     85    newModelSignal = QtCore.pyqtSignal() 
    8586    def __init__(self, parent=None, data=None, tab_id=1): 
    8687 
     
    574575        row = self.rowFromName(constraint.param) 
    575576        self._model_model.item(row, 1).setChild(0, item) 
    576         #self.constraintAddedSignal.emit([row]) 
     577        self.constraintAddedSignal.emit([row]) 
    577578 
    578579        # Show visual hints for the constraint 
     
    626627            max = self._model_model.item(row, max_col).text() 
    627628            # Create a Constraint object 
    628             constraint = Constraint(param=param, value=value, min=min, max=max) 
     629            constraint = Constraint(param=param, value=value, min=min, max=max, func=value) 
    629630            # Create a new item and add the Constraint object as a child 
    630631            item = QtGui.QStandardItem() 
     
    634635            self._model_model.item(row, min_col).setText(value) 
    635636            self._model_model.item(row, max_col).setText(value) 
    636             #self.constraintAddedSignal.emit([row]) 
     637            self.constraintAddedSignal.emit([row]) 
    637638            # Show visual hints for the constraint 
    638639            font = QtGui.QFont() 
     
    647648        Delete constraints from selected parameters. 
    648649        """ 
     650        self.deleteConstraintOnParameter(param=None) 
     651 
     652    def deleteConstraintOnParameter(self, param=None): 
     653        """ 
     654        Delete the constraint on model parameter 'param' 
     655        """ 
    649656        min_col = self.lstParams.itemDelegate().param_min 
    650657        max_col = self.lstParams.itemDelegate().param_max 
    651         for row in self.selectedParameters(): 
     658        for row in range(self._model_model.rowCount()): 
    652659            # Get the Constraint object from of the model item 
    653660            item = self._model_model.item(row, 1) 
     
    659666            if not isinstance(constraint, Constraint): 
    660667                continue 
     668            if param and constraint.param != param: 
     669                continue 
     670            # Now we got the right row. Delete the constraint and clean up 
    661671            # Retrieve old values and put them on the model 
    662672            if constraint.min is not None: 
     
    666676            # Remove constraint item 
    667677            item.removeRow(0) 
    668             #self.constraintAddedSignal.emit([row]) 
     678            self.constraintAddedSignal.emit([row]) 
    669679            self.modifyViewOnRow(row) 
     680            break 
     681 
    670682        self.communicate.statusBarUpdateSignal.emit('Constraint removed') 
    671683        pass 
     684 
    672685 
    673686    def getConstraintForRow(self, row): 
     
    687700        """ 
    688701        item = self._model_model.item(row,1) 
    689         return True if (item.hasChildren() and isinstance(item.child(0).data(), Constraint)) else False 
     702        if item.hasChildren(): 
     703            c = item.child(0).data() 
     704            if isinstance(c, Constraint) and c.func: 
     705                return True 
     706        return False 
     707        #return True if (item.hasChildren() and isinstance(item.child(0).data(), Constraint)) else False 
    690708 
    691709    def selectParameters(self): 
     
    726744        self.kernel_module.name = model_name 
    727745        param_number = self._model_model.rowCount() 
     746        def preamble(s): 
     747            func = self._model_model.item(s, 1).child(0).data().func 
     748            value = self._model_model.item(s, 1).child(0).data().value 
     749            if func == value: 
     750                return "" 
     751            return model_name + "." 
    728752        params = [(self._model_model.item(s, 0).text(), 
    729                     model_name+"."+self._model_model.item(s, 1).child(0).data().func) 
     753                    preamble(s) +self._model_model.item(s, 1).child(0).data().func) 
    730754                    for s in range(param_number) if self.rowHasConstraint(s)] 
    731755        return params 
     
    806830        # Update state stack 
    807831        self.updateUndo() 
     832 
     833        # Let others know 
     834        self.newModelSignal.emit() 
    808835 
    809836    def onSelectCategory(self): 
     
    15231550        # Now we claim the model has been loaded 
    15241551        self.model_is_loaded = True 
     1552        # Change the model name to a monicker 
     1553        self.kernel_module.name = self.modelName() 
    15251554 
    15261555        # (Re)-create headers 
  • src/sas/qtgui/Perspectives/Fitting/UI/ConstraintWidgetUI.ui

    r676f137 rbe8f4b0  
    6363         </sizepolicy> 
    6464        </property> 
     65        <property name="contextMenuPolicy"> 
     66         <enum>Qt::ActionsContextMenu</enum> 
     67        </property> 
    6568        <property name="alternatingRowColors"> 
    6669         <bool>true</bool> 
     
    6972         <enum>QAbstractItemView::SelectRows</enum> 
    7073        </property> 
    71         <row> 
    72          <property name="text"> 
    73           <string/> 
    74          </property> 
    75         </row> 
    76         <row> 
    77          <property name="text"> 
    78           <string/> 
    79          </property> 
    80         </row> 
    81         <row> 
    82          <property name="text"> 
    83           <string/> 
    84          </property> 
    85         </row> 
    8674       </widget> 
    8775      </item> 
     
    122110          <verstretch>0</verstretch> 
    123111         </sizepolicy> 
     112        </property> 
     113        <property name="contextMenuPolicy"> 
     114         <enum>Qt::ActionsContextMenu</enum> 
    124115        </property> 
    125116        <column> 
  • src/sas/qtgui/Utilities/ObjectLibrary.py

    • Property mode changed from 100755 to 100644
Note: See TracChangeset for help on using the changeset viewer.