Example #1
0
    def __init__(self, app):
        super(DialogEditMS, self).__init__()
        self.ui = Ui_editMSDialog()
        self.ui.setupUi(self)

        self.setFixedSize(self.size())  # no resize
        
        self.app =  app
        self.taxonomy = app.taxonomy

        # save mapping scheme dialog box        
        self.dlgSave = DialogSaveMS(self.app)
        self.dlgSave.setModal(True)
        
        # connect slots (ui events)
        self.ui.btn_apply.clicked.connect(self.updateWeights)
        self.ui.btn_add.clicked.connect(self.addValue)
        self.ui.btn_range.clicked.connect(self.editRanges)
        self.ui.btn_delete.clicked.connect(self.deleteValue)
        self.ui.cb_attributes.currentIndexChanged[str].connect(self.attributeUpdated)
        self.ui.btn_save.clicked.connect(self.saveMSBranch)
        self.ui.btn_close.clicked.connect(self.reject)
Example #2
0
class DialogEditMS(Ui_editMSDialog, QDialog):
    """
    dialog for editing mapping scheme branches
    """
    # constructor
    ###############################
    
    def __init__(self, app):
        super(DialogEditMS, self).__init__()
        self.ui = Ui_editMSDialog()
        self.ui.setupUi(self)

        self.setFixedSize(self.size())  # no resize
        
        self.app =  app
        self.taxonomy = app.taxonomy

        # save mapping scheme dialog box        
        self.dlgSave = DialogSaveMS(self.app)
        self.dlgSave.setModal(True)
        
        # connect slots (ui events)
        self.ui.btn_apply.clicked.connect(self.updateWeights)
        self.ui.btn_add.clicked.connect(self.addValue)
        self.ui.btn_range.clicked.connect(self.editRanges)
        self.ui.btn_delete.clicked.connect(self.deleteValue)
        self.ui.cb_attributes.currentIndexChanged[str].connect(self.attributeUpdated)
        self.ui.btn_save.clicked.connect(self.saveMSBranch)
        self.ui.btn_close.clicked.connect(self.reject)

    # public properties
    ###############################

    @property
    def current_attribute(self):
        return self.ui.cb_attributes.currentText()

    # ui event handler
    ###############################
    @pyqtSlot(QObject)
    def resizeEvent(self, event):
        return
    
    @logUICall
    @pyqtSlot()
    def updateWeights(self):
        """ 
        event handler for btn_apply
        - return new set of values/weights to be applied  
        """
        self.values = self.levelModel.values
        self.weights = self.levelModel.weights
        # TODO: performs checks before returning
        # 1. no empty values
        # 2. weights add up to 100
        self.accept()
    
    @logUICall
    @pyqtSlot()
    def addValue(self):
        """ 
        event handler for btn_add
        - add another pair of value/weights  
        """
        self.levelModel.addValues()
    
    @logUICall 
    @pyqtSlot() 
    def deleteValue(self):
        """ 
        event handler for btn_delete
        - delete currently selected row of value/weights from table table_ms_level  
        """    
        selected = self.getSelectedCell()
        if selected is not None:
            self.levelModel.deleteValue(selected.row())

    @logUICall 
    @pyqtSlot()     
    def editRanges(self):
        attribute_name = str(self.ui.cb_attributes.currentText())
        
        if self.app.setRange(self.ranges, attribute_name):
            self.attributeUpdated(self.ui.cb_attributes.currentText())

    @logUICall
    @pyqtSlot()
    def saveMSBranch(self):
        """ 
        event handler for btn_save
        - open "Save mapping scheme" dialog box to save current set of values/weights
          as a single level mapping scheme
        """
        ms = MappingScheme(self.taxonomy)
        stats = Statistics(self.taxonomy)
        root = stats.get_tree()
        for v, w in map(None, self.levelModel.values, self.levelModel.weights):
            node = StatisticNode(root, '', v)
            node.weight = w
            root.children.append(node)
        stats.finalized = True
        ms.assign(MappingSchemeZone('ALL'), stats)
        
        self.dlgSave.setMS(ms, True)
        self.dlgSave.exec_()

    @logUICall
    @pyqtSlot(str)
    def attributeUpdated(self, attribute_name):        
        """ 
        event handler for cb_attributes
        - update list of possible values according to attribute selected
        """
        if attribute_name=='':
            return
        attribute = self.taxonomy.get_attribute_by_name(attribute_name)
        if attribute is None:
            return
        
        self.valid_codes = {}
        if attribute.type == 2: # numeric type that can have ranges
            
            # retrieve range if exists
            if self.ranges.has_key(str(attribute_name)):
                ranges = self.ranges[str(attribute_name)]                

                # add all ranges to list of codes for drop-down
                for min_val, max_val in map(None, ranges['min_values'], ranges['max_values']):
                    value = attribute.make_string([min_val, max_val])
                    self.valid_codes[value] = value
    
                # test for range [0,0], which is the unknown case
                if ranges['min_values'] >0 and ranges['max_values']>0:
                    value = attribute.make_string([None, None])
                    self.valid_codes[value] = value                    
            #else:
                # allow user use default edit feature
                            
            # enable button for editing ranges 
            self.ui.btn_range.setEnabled(True)
        else:               # code only types that cannot have ranges 
            try:
                node = self.node
                taxonomy = self.taxonomy
                filter_code = taxonomy.get_code_by_name(str(node.value))
                while filter_code.attribute.order > 1 and not taxonomy.has_rule(filter_code.attribute.name):
                    node = node.parent
                    filter_code = taxonomy.get_code_by_name(str(node.value))                                        
                attribute = taxonomy.get_attribute_by_name(attribute_name)                
                if filter_code.attribute.group.name != attribute.group.name:
                    filter_code = None
            except:
                filter_code = None
            for code in self.taxonomy.get_code_by_attribute(attribute_name, filter_code):
                self.valid_codes[code.description]=code.code
            # disable button for editing ranges            
            self.ui.btn_range.setEnabled(False)
        
        # set list of values to table editor
        # do not allow add if there is no codes available
        allow_add = False 
        if len(self.valid_codes) > 1:
            attr_editor = MSAttributeItemDelegate(self.ui.table_ms_level, self.valid_codes, 0)
            self.ui.table_ms_level.setItemDelegateForColumn(0, attr_editor)
            allow_add = True            
        
        # adjust ui
        self.ui.btn_add.setEnabled(allow_add)
        self.ui.btn_apply.setEnabled(allow_add)
        self.ui.btn_delete.setEnabled(allow_add)
        self.ui.btn_range.setEnabled(allow_add)
        self.ui.btn_save.setEnabled(allow_add)            

    # public methods    
    #############################            
    @logUICall
    def setNode(self, node, ranges, addNew=False):
        """ 
        shows values/weights in table_ms_level for given node
        if addNew values/weights correspond to node's children (if any)
        otherwise, values/weights are from node's sibling (if any) 
        """        
        self.ui.cb_attributes.clear()
        
        # create copy of values to be shown and modified
        values = []
        weights = []
        
        self.ranges = ranges
        if not addNew:
            self.node = node.parent
            attribute_name = node.name
            has_know_attribute = True
        else:
            self.node = node        
            if len(self.node.children) > 0:
                attribute_name = self.node.children[0].name
                has_know_attribute = True
            else:
                attribute_name = ""
                has_know_attribute = False
        
        if has_know_attribute:
            self.ui.cb_attributes.addItem(attribute_name)
        else:
            existing_attributes = node.ancestor_names
            existing_attributes.append(node.name)            
            
            node_attr = self.taxonomy.get_attribute_by_name(node.name)
            if node_attr is None:
                node_group, node_order = '', 1
            else:
                node_group, node_order = node_attr.group.name, node_attr.order 
                        
            for attr in self.taxonomy.attributes:
                try:
                    # make sure it does not already exist
                    existing_attributes.index(attr.name)
                except:
                    # this step reached if attribute not found in existing_attributes list 
                    add_attribute = False
                    # add 1st attribute of group or in current group  
                    if (node_group != attr.group.name and attr.order == 1 ):    
                        add_attribute = True
                    
                    # add next attribute of current group
                    if (node_group == attr.group.name and attr.order == node_order+1):
                        add_attribute = True
                        
                    if (add_attribute):
                        self.ui.cb_attributes.addItem(attr.name)
        
        for child in self.node.children:
            values.append(str(child.value))
            weights.append(child.weight)
        
        self.levelModel = MSLevelTableModel(values, weights, self.taxonomy, self.taxonomy.codes,
                                            is_editable=[True, True])
        # initialize table view 
        tableUI = self.ui.table_ms_level                
        tableUI.setModel(self.levelModel)
        tableUI.setSelectionMode(QAbstractItemView.SingleSelection)
        table_width = tableUI.width()
        value_col_width = round(table_width*0.7, 0)
        tableUI.setColumnWidth(0, value_col_width)
        tableUI.setColumnWidth(1, table_width-value_col_width)
        tableUI.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

        # handle dataChanged event
        self.levelModel.dataChanged.connect(self.verifyWeights)
        
        # check total weights
        self.verifyWeights(None, None)

    def verifyWeights(self, startIndex, endIndex):
        sum_weights = sum(self.levelModel.weights)
        self.ui.txt_total_weights.setText('%.1f' % sum_weights)
        if (sum_weights == 100):
            self.ui.txt_total_weights.setStyleSheet('color:black')
            self.ui.btn_apply.setEnabled(True)
        else:
            self.ui.txt_total_weights.setStyleSheet('color:red')
            self.ui.btn_apply.setEnabled(False)

    # internal helper methods
    ###############################
    def getSelectedCell(self):
        """ return selected cell in table_ms_level """
        selectedIndexes = self.ui.table_ms_level.selectedIndexes()
        if (len(selectedIndexes) <= 0):
            logUICall.log('Please select node first.', logUICall.WARNING)            
            return None       
        if not selectedIndexes[0].isValid():
            logUICall.log('Select node does not support this function.', logUICall.WARNING)
            return None
        return selectedIndexes[0]