コード例 #1
0
ファイル: view_str.py プロジェクト: ollawone/stdm
class STRViewEntityWidget(WIDGET2, BASE2, EntitySearchItem):
    """
    A widget that represents options for searching through an entity.
    """
    asyncStarted = pyqtSignal()
    asyncFinished = pyqtSignal()

    def __init__(self, config, formatter=None, parent=None):
        QWidget.__init__(self, parent)
        EntitySearchItem.__init__(self, formatter)
        self.setupUi(self)

        self.tbSTRViewEntity.setTabIcon(0, GuiUtils.get_icon('filter.png'))
        self.tbSTRViewEntity.setTabIcon(1,
                                        GuiUtils.get_icon('period_blue.png'))

        self.config = config
        self.setConfigOptions()
        self.curr_profile = current_profile()
        self.social_tenure = self.curr_profile.social_tenure
        self.str_model = entity_model(self.social_tenure)
        # Model for storing display and actual mapping values
        self._completer_model = None
        self._proxy_completer_model = None

        # Hook up signals
        self.cboFilterCol.currentIndexChanged.connect(
            self._on_column_index_changed)
        self.init_validity_dates()
        self.validity_from_date.dateChanged.connect(self.set_minimum_to_date)
        self.validity.setDisabled(True)
        self.init_validity_checkbox()

    def init_validity_checkbox(self):
        self.check_box_list = []
        self.validity_checkbox = QCheckBox()

        self.check_box_list.append(self.validity_checkbox)
        self.tbSTRViewEntity.tabBar().setTabButton(
            self.tbSTRViewEntity.tabBar().count() - 1, QTabBar.LeftSide,
            self.validity_checkbox)
        self.validity_checkbox.stateChanged.connect(
            self.toggle_validity_period)

    def toggle_validity_period(self, state):
        if state == Qt.Checked:
            self.validity.setDisabled(False)
        else:
            self.validity.setDisabled(True)

    def set_minimum_to_date(self):
        """
        Set the minimum to date based on the
        change in value of from date.
        :return:
        :rtype:
        """
        self.validity_to_date.setMinimumDate(self.validity_from_date.date())

    def init_validity_dates(self):
        """
        Initialize the dates by setting the current date.
        :return:
        :rtype:
        """
        self.validity_from_date.setDate(date.today())
        self.validity_to_date.setDate(date.today())

    def setConfigOptions(self):
        """
        Apply configuration options.
        """
        # Set filter columns and remove id column
        for col_name, display_name in self.config.filterColumns.items():
            if col_name != "id":
                self.cboFilterCol.addItem(display_name, col_name)

    def loadAsync(self):
        """
        Asynchronously loads an entity's attribute values.
        """
        self.asyncStarted.emit()

        # Create model worker
        workerThread = QThread(self)
        modelWorker = ModelWorker()
        modelWorker.moveToThread(workerThread)

        # Connect signals
        modelWorker.error.connect(self.errorHandler)
        workerThread.started.connect(lambda: modelWorker.fetch(
            self.config.STRModel, self.currentFieldName()))
        modelWorker.retrieved.connect(self._asyncFinished)
        modelWorker.retrieved.connect(workerThread.quit)
        workerThread.finished.connect(modelWorker.deleteLater)
        workerThread.finished.connect(workerThread.deleteLater)

        # Start thread
        workerThread.start()

    def validate(self):
        """
        Validate entity search widget
        """
        is_valid = True
        message = ""

        if self.txtFilterPattern.text() == "":
            message = QApplication.translate("ViewSTR",
                                             "Search word cannot be empty.")
            is_valid = False

        return is_valid, message

    def executeSearch(self):
        """
        Base class override.
        Search for matching items for the specified entity and column.
        """
        model_root_node = None

        prog_dialog = QProgressDialog(self)
        prog_dialog.setFixedWidth(380)
        prog_dialog.setWindowTitle(
            QApplication.translate("STRViewEntityWidget",
                                   "Searching for STR..."))
        prog_dialog.show()
        prog_dialog.setRange(0, 10)
        search_term = self._searchTerm()

        prog_dialog.setValue(2)
        # Try to get the corresponding search term value from the completer model
        if not self._completer_model is None:
            reg_exp = QRegExp("^%s$" % (search_term), Qt.CaseInsensitive,
                              QRegExp.RegExp2)
            self._proxy_completer_model.setFilterRegExp(reg_exp)

            if self._proxy_completer_model.rowCount() > 0:
                # Get corresponding actual value from the first matching item
                value_model_idx = self._proxy_completer_model.index(0, 1)
                source_model_idx = self._proxy_completer_model.mapToSource(
                    value_model_idx)
                prog_dialog.setValue(4)
                search_term = self._completer_model.data(
                    source_model_idx, Qt.DisplayRole)

        modelInstance = self.config.STRModel()

        modelQueryObj = modelInstance.queryObject()

        queryObjProperty = getattr(self.config.STRModel,
                                   self.currentFieldName())

        entity_name = modelQueryObj._primary_entity._label_name

        entity = self.curr_profile.entity_by_name(entity_name)

        prog_dialog.setValue(6)
        # Get property type so that the filter can
        # be applied according to the appropriate type
        propType = queryObjProperty.property.columns[0].type
        results = []
        try:
            if not isinstance(propType, String):

                col_name = self.currentFieldName()
                col = entity.columns[self.currentFieldName()]

                if col.TYPE_INFO == 'LOOKUP':
                    lookup_entity = lookup_parent_entity(
                        self.curr_profile, col_name)
                    lkp_model = entity_model(lookup_entity)
                    lkp_obj = lkp_model()
                    value_obj = getattr(lkp_model, 'value')

                    result = lkp_obj.queryObject().filter(
                        func.lower(value_obj) == func.lower(
                            search_term)).first()
                    if result is None:
                        result = lkp_obj.queryObject().filter(
                            func.lower(value_obj).like(search_term +
                                                       '%')).first()

                    if not result is None:
                        results = modelQueryObj.filter(
                            queryObjProperty == result.id).all()

                    else:
                        results = []

            else:
                results = modelQueryObj.filter(
                    func.lower(queryObjProperty) == func.lower(
                        search_term)).all()

            if self.validity.isEnabled():
                valid_str_ids = self.str_validity_period_filter(results)
            else:
                valid_str_ids = None

            prog_dialog.setValue(7)
        except exc.StatementError:
            return model_root_node, [], search_term

        # if self.formatter is not None:
        # self.formatter.setData(results)
        # model_root_node = self.formatter.root(valid_str_ids)
        prog_dialog.setValue(10)
        prog_dialog.hide()

        return results, search_term

    def str_validity_period_filter(self, results):
        """
        Filter the entity results using validity period in STR table.
        :param results: Entity result
        :type results: SQLAlchemy result proxy
        :return: Valid list of STR ids
        :rtype: List
        """
        self.str_model_obj = self.str_model()
        valid_str_ids = []
        for result in results:
            from_date = self.validity_from_date.date().toPyDate()
            to_date = self.validity_to_date.date().toPyDate()
            entity_id = '{}_id'.format(result.__table__.name[3:])
            str_column_obj = getattr(self.str_model, entity_id)
            str_result = self.str_model_obj.queryObject().filter(
                self.str_model.validity_start >= from_date).filter(
                    self.str_model.validity_end <= to_date).filter(
                        str_column_obj == result.id).all()

            for res in str_result:
                valid_str_ids.append(res.id)

        return valid_str_ids

    def reset(self):
        """
        Clear search input parameters.
        """
        self.txtFilterPattern.clear()
        if self.cboFilterCol.count() > 0:
            self.cboFilterCol.setCurrentIndex(0)

    def currentFieldName(self):
        """
        Returns the name of the database field
        from the current item in the combo box.
        """
        curr_index = self.cboFilterCol.currentIndex()
        field_name = self.cboFilterCol.itemData(curr_index)

        if field_name is None:
            return
        else:
            return field_name

    def _searchTerm(self):
        """
        Returns the search term specified by the user.
        """
        return self.txtFilterPattern.text()

    def _asyncFinished(self, model_values):
        """
        Slot raised when worker has finished retrieving items.
        """
        # Create QCompleter and add values to it.
        self._update_completer(model_values)
        self.asyncFinished.emit()

    def _update_completer(self, values):
        # Get the items in a tuple and put them in a list

        # Store display and actual values in a
        # model for easier mapping and
        # retrieval when carrying out searches

        model_attr_mapping = []

        # Check if there are formaters specified
        # for the current field name
        for mv in values:
            f_model_values = []

            m_val = mv[0]

            if m_val is not None:
                col_label = self.currentFieldName()
                if col_label in self.config.LookupFormatters:
                    formatter = self.config.LookupFormatters[col_label]
                    if formatter.column.TYPE_INFO == 'LOOKUP':
                        m_val = formatter.code_value(m_val)[0]
                    else:
                        m_val = formatter.format_column_value(m_val)
            f_model_values.extend([m_val, m_val])

            model_attr_mapping.append(f_model_values)

        self._completer_model = BaseSTDMTableModel(model_attr_mapping,
                                                   ["", ""], self)

        # We will use the QSortFilterProxyModel for filtering purposes
        self._proxy_completer_model = QSortFilterProxyModel()
        self._proxy_completer_model.setDynamicSortFilter(True)
        self._proxy_completer_model.setSourceModel(self._completer_model)
        self._proxy_completer_model.setSortCaseSensitivity(Qt.CaseInsensitive)
        self._proxy_completer_model.setFilterKeyColumn(0)

        # Configure completer
        mod_completer = QCompleter(self._completer_model, self)
        mod_completer.setCaseSensitivity(Qt.CaseInsensitive)
        mod_completer.setCompletionMode(QCompleter.PopupCompletion)
        mod_completer.setCompletionColumn(0)
        mod_completer.setCompletionRole(Qt.DisplayRole)

        self.txtFilterPattern.setCompleter(mod_completer)

    def _on_column_index_changed(self, int):
        """
        Slot raised when the user selects a different filter column.
        """
        self.txtFilterPattern.clear()
        self.loadAsync()
コード例 #2
0
 def makeProxyModel(self, model):
     proxyModel = QSortFilterProxyModel()
     proxyModel.setDynamicSortFilter(True)
     proxyModel.setSortCaseSensitivity(Qt.CaseInsensitive)
     proxyModel.setSourceModel(model)
     return proxyModel