class SearchDialog(QDialog):
    """
    SearchDialog class for the Financeager application.
    """
    def __init__(self, parent=None):
        """
        Loads the ui layout file. 
        Populates the model and does some layout adjustments. 
        
        :param      parent | FinanceagerWindow 
        """
        super(SearchDialog, self).__init__(parent)
        loadUi(__file__, self)

        self.__model = QStandardItemModel(self.tableView)
        # sorts model according to Item.data, Item.text
        self.__model.setSortRole(Qt.UserRole + 1)
        self.__model.setHorizontalHeaderLabels(
            ['Name', 'Value', 'Date', 'Category'])
        self.tableView.setModel(self.__model)
        self.__sortOrder = 1  #Descending order

        self.tableView.horizontalHeader().setResizeMode(QHeaderView.Stretch)
        self.tableView.adjustSize()
        self.setFixedSize(self.size())
        self.buttonBox.button(QDialogButtonBox.Ok).setDefault(False)
        # CONNECTIONS
        self.lineEdit.textEdited.connect(self.displaySearchResult)
        self.expendituresButton.clicked.connect(self.displaySearchResult)
        self.receiptsButton.clicked.connect(self.displaySearchResult)
        self.bothButton.clicked.connect(self.displaySearchResult)
        self.tableView.horizontalHeader().sectionClicked.connect(
            self.sortByColumn)
        self.buttonBox.button(QDialogButtonBox.Ok).clicked.connect(self.close)

    def keyPressEvent(self, event):
        """
        Reimplementation. 
        Avoids triggering the OK button when pressing Enter. Considered a
        common reaction when searching for stuff.
        Unchecks the action_Search of the MainWindow if Esc pressed.
        """
        if event.key() == Qt.Key_Enter:
            return
        elif event.key() == Qt.Key_Escape:
            self.parentWidget().action_Search.setChecked(False)
        super(SearchDialog, self).keyPressEvent(event)

    def closeEvent(self, event):
        """ Reimplementation. Unchecks the action_Search of the MainWindow. """
        self.parentWidget().action_Search.setChecked(False)
        event.accept()

    def displaySearchResult(self, pattern=None):
        """
        Searches for the pattern given by the user in all months of the current
        year. If specified, only the respective expenditures or receipts are
        scanned. 
        If a match is found, new items are cloned and appended to the table.

        :param      pattern | QString emitted by QLineEdit.textChanged signal
                              or bool emitted by QRadioButton.clicked signal
                              or None if called from a BalanceModel (resp.
                              FinanceagerWindow.updateSearchDialog())
        """
        if type(pattern) is bool or pattern is None:
            pattern = self.lineEdit.text()
        pattern = unicode(pattern)
        self.__model.clear()
        self.__model.setHorizontalHeaderLabels(
            ['Name', 'Value', 'Date', 'Category'])
        self.setWindowTitle('Search for \'%s\'' % pattern)
        if not len(pattern):
            self.__model.setItem(0, 0, ResultItem('No pattern specified.'))
            return
        pattern = pattern.upper()
        monthsTabWidget = self.parent().monthsTabWidget
        for m in range(12):
            if self.expendituresButton.isChecked():
                modelList = [monthsTabWidget.widget(m).expendituresModel()]
            elif self.receiptsButton.isChecked():
                modelList = [monthsTabWidget.widget(m).receiptsModel()]
            elif self.bothButton.isChecked():
                modelList = [
                    monthsTabWidget.widget(m).expendituresModel(),
                    monthsTabWidget.widget(m).receiptsModel()
                ]
            for model in modelList:
                for r in range(model.rowCount()):
                    category = model.item(r)
                    for e in range(category.rowCount()):
                        entry = category.child(e)
                        name = unicode(entry.text())
                        if name.upper().find(pattern) > -1:
                            value = category.child(e, 1).value()
                            date = category.child(e, 2).data()
                            self.__model.appendRow([
                                ResultItem(name),
                                ResultItem(value),
                                ResultItem(date),
                                ResultItem(category.text())
                            ])
        if not self.__model.hasChildren():
            self.__model.setItem(0, 0, ResultItem('No match found.'))

    def sortByColumn(self, col):
        """
        Called when a section of the horizontalHeader of the model is clicked.
        Toggles the sortOrder from descending to ascending and vice versa. 
        Finally the respective column is sorted. 

        :param      col | int 
        """
        self.__sortOrder = not self.__sortOrder
        self.__model.sort(col, self.__sortOrder)
class ModelAtrributesView(QListView):
    """
    Custom QListView implementation that displays checkable model attributes.
    """
    def __init__(self,parent=None,dataModel = None):
        QListView.__init__(self, parent)
        
        self._dataModel = dataModel
        self._selectedDisplayMapping = OrderedDict()
        self._modelDisplayMapping = OrderedDict()
        self._attrModel = QStandardItemModel(self)
        
    def dataModel(self):
        """
        Returns the data model instance.
        """
        return self._dataModel
    
    def setDataModel(self,dataModel):
        """
        Sets the data model. Should be a callable class rather than the class.
        instance.
        """
        if callable(dataModel):
            self._dataModel = dataModel
            
        else:
            self._dataModel = dataModel.__class__
    
    def modelDisplayMapping(self):
        """
        Returns the column name and display name collection.
        """
        return self._modelDisplayMapping
    
    def setModelDisplayMapping(self, dataMapping):
        """
        Sets the mapping dictionary for the table object
        """
        if dataMapping != None:
            self._modelDisplayMapping=dataMapping

    def load(self, sort=False):
        """
        Load the model's attributes into the list view.
        """
        if self._dataModel == None:
            return
        
        try:
            self._loadAttrs(self._dataModel.displayMapping(), sort)
        except AttributeError:
            #Ignore error if model does not contain the displayMapping static method
            pass

    def load_mapping(self, mapping, sort=False):
        """
        Load collection containing column name and corresponding display name.
        """
        self._modelDisplayMapping = mapping

        self._loadAttrs(mapping, sort)

    def sort(self):
        """
        Sorts display name in ascending order.
        """
        self._attrModel.sort(0)
        
    def _loadAttrs(self, attrMapping, sort=False):
        """
        Loads display mapping into the list view.
        Specify to sort display names in ascending order once items have been
        added to the model.
        """
        self._attrModel.clear()
        self._attrModel.setColumnCount(2)
        
        for attrName,displayName in attrMapping.iteritems():
            #Exclude row ID in the list, other unique identifier attributes in the model can be used
            if attrName != "id":
                displayNameItem = QStandardItem(displayName)
                displayNameItem.setCheckable(True)
                attrNameItem = QStandardItem(attrName)
                
                self._attrModel.appendRow([displayNameItem,attrNameItem])
            
        self.setModel(self._attrModel)

        if sort:
            self._attrModel.sort(0)
        
    def selectedMappings(self):
        """
        Return a dictionary of field names and their corresponding display values.
        """
        selectedAttrs = {}
        
        for i in range(self._attrModel.rowCount()):
            displayNameItem = self._attrModel.item(i,0)
            
            if displayNameItem.checkState() == Qt.Checked:
                attrNameItem = self._attrModel.item(i,1)  
                selectedAttrs[attrNameItem.text()] = displayNameItem.text()
        
        return selectedAttrs
Exemple #3
0
class ModelAtrributesView(QListView):
    """
    Custom QListView implementation that displays checkable model attributes.
    """
    def __init__(self,parent=None,dataModel = None):
        QListView.__init__(self, parent)
        
        self._dataModel = dataModel
        self._selectedDisplayMapping = OrderedDict()
        self._modelDisplayMapping = OrderedDict()
        self._attrModel = QStandardItemModel(self)
        
    def dataModel(self):
        """
        Returns the data model instance.
        """
        return self._dataModel
    
    def setDataModel(self,dataModel):
        """
        Sets the data model. Should be a callable class rather than the class.
        instance.
        """
        if callable(dataModel):
            self._dataModel = dataModel
            
        else:
            self._dataModel = dataModel.__class__
    
    def modelDisplayMapping(self):
        """
        Returns the column name and display name collection.
        """
        return self._modelDisplayMapping
    
    def setModelDisplayMapping(self, dataMapping):
        """
        Sets the mapping dictionary for the table object
        """
        if dataMapping != None:
            self._modelDisplayMapping=dataMapping

    def load(self, sort=False):
        """
        Load the model's attributes into the list view.
        """
        if self._dataModel == None:
            return
        
        try:
            self._loadAttrs(self._dataModel.displayMapping(), sort)
        except AttributeError:
            # Ignore error if model does not contain
            # the displayMapping static method
            pass

    def load_mapping(self, mapping, sort=False):
        """
        Load collection containing column name and corresponding display name.
        """
        self._modelDisplayMapping = mapping

        self._loadAttrs(mapping, sort)

    def sort(self):
        """
        Sorts display name in ascending order.
        """
        self._attrModel.sort(0)
        
    def _loadAttrs(self, attrMapping, sort=False):
        """
        Loads display mapping into the list view.
        Specify to sort display names in ascending order once items have been
        added to the model.
        """
        self._attrModel.clear()
        self._attrModel.setColumnCount(2)
        
        for attrName,displayName in attrMapping.iteritems():
            #Exclude row ID in the list, other unique identifier attributes in the model can be used
            if attrName != "id":
                displayNameItem = QStandardItem(displayName)
                displayNameItem.setCheckable(True)
                attrNameItem = QStandardItem(attrName)
                
                self._attrModel.appendRow([displayNameItem,attrNameItem])
            
        self.setModel(self._attrModel)

        if sort:
            self._attrModel.sort(0)
        
    def selectedMappings(self):
        """
        Return a dictionary of field names and their corresponding display values.
        """
        selectedAttrs = OrderedDict()
        
        for i in range(self._attrModel.rowCount()):
            displayNameItem = self._attrModel.item(i,0)

            if displayNameItem.checkState() == Qt.Checked:

                attrNameItem = self._attrModel.item(i,1)

                selectedAttrs[attrNameItem.text()] = displayNameItem.text()

        return selectedAttrs