1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "addresswidget.h"
52#include "adddialog.h"
53
54#include <QtWidgets>
55
56//! [0]
57AddressWidget::AddressWidget(QWidget *parent)
58 : QTabWidget(parent),
59 table(new TableModel(this)),
60 newAddressTab(new NewAddressTab(this))
61{
62 connect(newAddressTab, &NewAddressTab::sendDetails,
63 this, &AddressWidget::addEntry);
64
65 addTab(newAddressTab, tr("Address Book"));
66
67 setupTabs();
68}
69//! [0]
70
71//! [2]
72void AddressWidget::showAddEntryDialog()
73{
74 AddDialog aDialog;
75
76 if (aDialog.exec())
77 addEntry(aDialog.name(), aDialog.address());
78}
79//! [2]
80
81//! [3]
82void AddressWidget::addEntry(const QString &name, const QString &address)
83{
84 if (!table->getContacts().contains({ name, address })) {
85 table->insertRows(0, 1, QModelIndex());
86
87 QModelIndex index = table->index(0, 0, QModelIndex());
88 table->setData(index, name, Qt::EditRole);
89 index = table->index(0, 1, QModelIndex());
90 table->setData(index, address, Qt::EditRole);
91 removeTab(indexOf(newAddressTab));
92 } else {
93 QMessageBox::information(this, tr("Duplicate Name"),
94 tr("The name \"%1\" already exists.").arg(name));
95 }
96}
97//! [3]
98
99//! [4a]
100void AddressWidget::editEntry()
101{
102 QTableView *temp = static_cast<QTableView*>(currentWidget());
103 QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model());
104 QItemSelectionModel *selectionModel = temp->selectionModel();
105
106 const QModelIndexList indexes = selectionModel->selectedRows();
107 QString name;
108 QString address;
109 int row = -1;
110
111 for (const QModelIndex &index : indexes) {
112 row = proxy->mapToSource(index).row();
113 QModelIndex nameIndex = table->index(row, 0, QModelIndex());
114 QVariant varName = table->data(nameIndex, Qt::DisplayRole);
115 name = varName.toString();
116
117 QModelIndex addressIndex = table->index(row, 1, QModelIndex());
118 QVariant varAddr = table->data(addressIndex, Qt::DisplayRole);
119 address = varAddr.toString();
120 }
121//! [4a]
122
123//! [4b]
124 AddDialog aDialog;
125 aDialog.setWindowTitle(tr("Edit a Contact"));
126 aDialog.editAddress(name, address);
127
128 if (aDialog.exec()) {
129 const QString newAddress = aDialog.address();
130 if (newAddress != address) {
131 const QModelIndex index = table->index(row, 1, QModelIndex());
132 table->setData(index, newAddress, Qt::EditRole);
133 }
134 }
135}
136//! [4b]
137
138//! [5]
139void AddressWidget::removeEntry()
140{
141 QTableView *temp = static_cast<QTableView*>(currentWidget());
142 QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model());
143 QItemSelectionModel *selectionModel = temp->selectionModel();
144
145 const QModelIndexList indexes = selectionModel->selectedRows();
146
147 for (QModelIndex index : indexes) {
148 int row = proxy->mapToSource(index).row();
149 table->removeRows(row, 1, QModelIndex());
150 }
151
152 if (table->rowCount(QModelIndex()) == 0)
153 insertTab(0, newAddressTab, tr("Address Book"));
154}
155//! [5]
156
157//! [1]
158void AddressWidget::setupTabs()
159{
160 const auto groups = { "ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ" };
161
162 for (const QString &str : groups) {
163 const auto regExp = QRegularExpression(QString("^[%1].*").arg(str),
164 QRegularExpression::CaseInsensitiveOption);
165
166 auto proxyModel = new QSortFilterProxyModel(this);
167 proxyModel->setSourceModel(table);
168 proxyModel->setFilterRegularExpression(regExp);
169 proxyModel->setFilterKeyColumn(0);
170
171 QTableView *tableView = new QTableView;
172 tableView->setModel(proxyModel);
173 tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
174 tableView->horizontalHeader()->setStretchLastSection(true);
175 tableView->verticalHeader()->hide();
176 tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
177 tableView->setSelectionMode(QAbstractItemView::SingleSelection);
178 tableView->setSortingEnabled(true);
179
180 connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
181 this, &AddressWidget::selectionChanged);
182
183 connect(this, &QTabWidget::currentChanged, this, [this, tableView](int tabIndex) {
184 if (widget(tabIndex) == tableView)
185 emit selectionChanged(tableView->selectionModel()->selection());
186 });
187
188 addTab(tableView, str);
189 }
190}
191//! [1]
192
193//! [7]
194void AddressWidget::readFromFile(const QString &fileName)
195{
196 QFile file(fileName);
197
198 if (!file.open(QIODevice::ReadOnly)) {
199 QMessageBox::information(this, tr("Unable to open file"),
200 file.errorString());
201 return;
202 }
203
204 QVector<Contact> contacts;
205 QDataStream in(&file);
206 in >> contacts;
207
208 if (contacts.isEmpty()) {
209 QMessageBox::information(this, tr("No contacts in file"),
210 tr("The file you are attempting to open contains no contacts."));
211 } else {
212 for (const auto &contact: qAsConst(contacts))
213 addEntry(contact.name, contact.address);
214 }
215}
216//! [7]
217
218//! [6]
219void AddressWidget::writeToFile(const QString &fileName)
220{
221 QFile file(fileName);
222
223 if (!file.open(QIODevice::WriteOnly)) {
224 QMessageBox::information(this, tr("Unable to open file"), file.errorString());
225 return;
226 }
227
228 QDataStream out(&file);
229 out << table->getContacts();
230}
231//! [6]
232