1#!/usr/bin/env python 2 3 4############################################################################# 5## 6## Copyright (C) 2013 Riverbank Computing Limited. 7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 8## All rights reserved. 9## 10## This file is part of the examples of PyQt. 11## 12## $QT_BEGIN_LICENSE:BSD$ 13## You may use this file under the terms of the BSD license as follows: 14## 15## "Redistribution and use in source and binary forms, with or without 16## modification, are permitted provided that the following conditions are 17## met: 18## * Redistributions of source code must retain the above copyright 19## notice, this list of conditions and the following disclaimer. 20## * Redistributions in binary form must reproduce the above copyright 21## notice, this list of conditions and the following disclaimer in 22## the documentation and/or other materials provided with the 23## distribution. 24## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 25## the names of its contributors may be used to endorse or promote 26## products derived from this software without specific prior written 27## permission. 28## 29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 40## $QT_END_LICENSE$ 41## 42############################################################################# 43 44 45from PyQt5.QtCore import (QDate, QDateTime, QRegExp, QSortFilterProxyModel, Qt, 46 QTime) 47from PyQt5.QtGui import QStandardItemModel 48from PyQt5.QtWidgets import (QApplication, QCheckBox, QComboBox, QGridLayout, 49 QGroupBox, QHBoxLayout, QLabel, QLineEdit, QTreeView, QVBoxLayout, 50 QWidget) 51 52 53SUBJECT, SENDER, DATE = range(3) 54 55# Work around the fact that QSortFilterProxyModel always filters datetime 56# values in QtCore.Qt.ISODate format, but the tree views display using 57# QtCore.Qt.DefaultLocaleShortDate format. 58class SortFilterProxyModel(QSortFilterProxyModel): 59 def filterAcceptsRow(self, sourceRow, sourceParent): 60 # Do we filter for the date column? 61 if self.filterKeyColumn() == DATE: 62 # Fetch datetime value. 63 index = self.sourceModel().index(sourceRow, DATE, sourceParent) 64 data = self.sourceModel().data(index) 65 66 # Return, if regExp match in displayed format. 67 return (self.filterRegExp().indexIn(data.toString(Qt.DefaultLocaleShortDate)) >= 0) 68 69 # Not our business. 70 return super(SortFilterProxyModel, self).filterAcceptsRow(sourceRow, sourceParent) 71 72 73class Window(QWidget): 74 def __init__(self): 75 super(Window, self).__init__() 76 77 self.proxyModel = SortFilterProxyModel() 78 self.proxyModel.setDynamicSortFilter(True) 79 80 self.sourceGroupBox = QGroupBox("Original Model") 81 self.proxyGroupBox = QGroupBox("Sorted/Filtered Model") 82 83 self.sourceView = QTreeView() 84 self.sourceView.setRootIsDecorated(False) 85 self.sourceView.setAlternatingRowColors(True) 86 87 self.proxyView = QTreeView() 88 self.proxyView.setRootIsDecorated(False) 89 self.proxyView.setAlternatingRowColors(True) 90 self.proxyView.setModel(self.proxyModel) 91 self.proxyView.setSortingEnabled(True) 92 93 self.sortCaseSensitivityCheckBox = QCheckBox("Case sensitive sorting") 94 self.filterCaseSensitivityCheckBox = QCheckBox("Case sensitive filter") 95 96 self.filterPatternLineEdit = QLineEdit() 97 self.filterPatternLabel = QLabel("&Filter pattern:") 98 self.filterPatternLabel.setBuddy(self.filterPatternLineEdit) 99 100 self.filterSyntaxComboBox = QComboBox() 101 self.filterSyntaxComboBox.addItem("Regular expression", QRegExp.RegExp) 102 self.filterSyntaxComboBox.addItem("Wildcard", QRegExp.Wildcard) 103 self.filterSyntaxComboBox.addItem("Fixed string", QRegExp.FixedString) 104 self.filterSyntaxLabel = QLabel("Filter &syntax:") 105 self.filterSyntaxLabel.setBuddy(self.filterSyntaxComboBox) 106 107 self.filterColumnComboBox = QComboBox() 108 self.filterColumnComboBox.addItem("Subject") 109 self.filterColumnComboBox.addItem("Sender") 110 self.filterColumnComboBox.addItem("Date") 111 self.filterColumnLabel = QLabel("Filter &column:") 112 self.filterColumnLabel.setBuddy(self.filterColumnComboBox) 113 114 self.filterPatternLineEdit.textChanged.connect(self.filterRegExpChanged) 115 self.filterSyntaxComboBox.currentIndexChanged.connect(self.filterRegExpChanged) 116 self.filterColumnComboBox.currentIndexChanged.connect(self.filterColumnChanged) 117 self.filterCaseSensitivityCheckBox.toggled.connect(self.filterRegExpChanged) 118 self.sortCaseSensitivityCheckBox.toggled.connect(self.sortChanged) 119 120 sourceLayout = QHBoxLayout() 121 sourceLayout.addWidget(self.sourceView) 122 self.sourceGroupBox.setLayout(sourceLayout) 123 124 proxyLayout = QGridLayout() 125 proxyLayout.addWidget(self.proxyView, 0, 0, 1, 3) 126 proxyLayout.addWidget(self.filterPatternLabel, 1, 0) 127 proxyLayout.addWidget(self.filterPatternLineEdit, 1, 1, 1, 2) 128 proxyLayout.addWidget(self.filterSyntaxLabel, 2, 0) 129 proxyLayout.addWidget(self.filterSyntaxComboBox, 2, 1, 1, 2) 130 proxyLayout.addWidget(self.filterColumnLabel, 3, 0) 131 proxyLayout.addWidget(self.filterColumnComboBox, 3, 1, 1, 2) 132 proxyLayout.addWidget(self.filterCaseSensitivityCheckBox, 4, 0, 1, 2) 133 proxyLayout.addWidget(self.sortCaseSensitivityCheckBox, 4, 2) 134 self.proxyGroupBox.setLayout(proxyLayout) 135 136 mainLayout = QVBoxLayout() 137 mainLayout.addWidget(self.sourceGroupBox) 138 mainLayout.addWidget(self.proxyGroupBox) 139 self.setLayout(mainLayout) 140 141 self.setWindowTitle("Basic Sort/Filter Model") 142 self.resize(500, 450) 143 144 self.proxyView.sortByColumn(SENDER, Qt.AscendingOrder) 145 self.filterColumnComboBox.setCurrentIndex(SENDER) 146 147 self.filterPatternLineEdit.setText("Andy|Grace") 148 self.filterCaseSensitivityCheckBox.setChecked(True) 149 self.sortCaseSensitivityCheckBox.setChecked(True) 150 151 def setSourceModel(self, model): 152 self.proxyModel.setSourceModel(model) 153 self.sourceView.setModel(model) 154 155 def filterRegExpChanged(self): 156 syntax_nr = self.filterSyntaxComboBox.itemData(self.filterSyntaxComboBox.currentIndex()) 157 syntax = QRegExp.PatternSyntax(syntax_nr) 158 159 if self.filterCaseSensitivityCheckBox.isChecked(): 160 caseSensitivity = Qt.CaseSensitive 161 else: 162 caseSensitivity = Qt.CaseInsensitive 163 164 regExp = QRegExp(self.filterPatternLineEdit.text(), 165 caseSensitivity, syntax) 166 self.proxyModel.setFilterRegExp(regExp) 167 168 def filterColumnChanged(self): 169 self.proxyModel.setFilterKeyColumn(self.filterColumnComboBox.currentIndex()) 170 171 def sortChanged(self): 172 if self.sortCaseSensitivityCheckBox.isChecked(): 173 caseSensitivity = Qt.CaseSensitive 174 else: 175 caseSensitivity = Qt.CaseInsensitive 176 177 self.proxyModel.setSortCaseSensitivity(caseSensitivity) 178 179 180def addMail(model, subject, sender, date): 181 model.insertRow(0) 182 model.setData(model.index(0, SUBJECT), subject) 183 model.setData(model.index(0, SENDER), sender) 184 model.setData(model.index(0, DATE), date) 185 186 187def createMailModel(parent): 188 model = QStandardItemModel(0, 3, parent) 189 190 model.setHeaderData(SUBJECT, Qt.Horizontal, "Subject") 191 model.setHeaderData(SENDER, Qt.Horizontal, "Sender") 192 model.setHeaderData(DATE, Qt.Horizontal, "Date") 193 194 addMail(model, "Happy New Year!", "Grace K. <grace@software-inc.com>", 195 QDateTime(QDate(2006, 12, 31), QTime(17, 3))) 196 addMail(model, "Radically new concept", "Grace K. <grace@software-inc.com>", 197 QDateTime(QDate(2006, 12, 22), QTime(9, 44))) 198 addMail(model, "Accounts", "pascale@nospam.com", 199 QDateTime(QDate(2006, 12, 31), QTime(12, 50))) 200 addMail(model, "Expenses", "Joe Bloggs <joe@bloggs.com>", 201 QDateTime(QDate(2006, 12, 25), QTime(11, 39))) 202 addMail(model, "Re: Expenses", "Andy <andy@nospam.com>", 203 QDateTime(QDate(2007, 1, 2), QTime(16, 5))) 204 addMail(model, "Re: Accounts", "Joe Bloggs <joe@bloggs.com>", 205 QDateTime(QDate(2007, 1, 3), QTime(14, 18))) 206 addMail(model, "Re: Accounts", "Andy <andy@nospam.com>", 207 QDateTime(QDate(2007, 1, 3), QTime(14, 26))) 208 addMail(model, "Sports", "Linda Smith <linda.smith@nospam.com>", 209 QDateTime(QDate(2007, 1, 5), QTime(11, 33))) 210 addMail(model, "AW: Sports", "Rolf Newschweinstein <rolfn@nospam.com>", 211 QDateTime(QDate(2007, 1, 5), QTime(12, 0))) 212 addMail(model, "RE: Sports", "Petra Schmidt <petras@nospam.com>", 213 QDateTime(QDate(2007, 1, 5), QTime(12, 1))) 214 215 return model 216 217 218if __name__ == '__main__': 219 220 import sys 221 222 app = QApplication(sys.argv) 223 window = Window() 224 window.setSourceModel(createMailModel(window)) 225 window.show() 226 sys.exit(app.exec_()) 227