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