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 <QtWidgets>
52#include "addressbook.h"
53
54AddressBook::AddressBook(QWidget *parent)
55 : QWidget(parent)
56{
57 QLabel *nameLabel = new QLabel(tr("Name:"));
58 nameLine = new QLineEdit;
59 nameLine->setReadOnly(true);
60
61 QLabel *addressLabel = new QLabel(tr("Address:"));
62 addressText = new QTextEdit;
63 addressText->setReadOnly(true);
64
65 addButton = new QPushButton(tr("&Add"));
66
67 editButton = new QPushButton(tr("&Edit"));
68 editButton->setEnabled(false);
69 removeButton = new QPushButton(tr("&Remove"));
70 removeButton->setEnabled(false);
71 findButton = new QPushButton(tr("&Find"));
72 findButton->setEnabled(false);
73 submitButton = new QPushButton(tr("&Submit"));
74 submitButton->hide();
75 cancelButton = new QPushButton(tr("&Cancel"));
76 cancelButton->hide();
77
78 nextButton = new QPushButton(tr("&Next"));
79 nextButton->setEnabled(false);
80 previousButton = new QPushButton(tr("&Previous"));
81 previousButton->setEnabled(false);
82
83 loadButton = new QPushButton(tr("&Load..."));
84 loadButton->setToolTip(tr("Load contacts from a file"));
85 saveButton = new QPushButton(tr("&Save..."));
86 saveButton->setToolTip(tr("Save contacts to a file"));
87 saveButton->setEnabled(false);
88
89 exportButton = new QPushButton(tr("E&xport"));
90 exportButton->setToolTip(tr("Export as vCard"));
91 exportButton->setEnabled(false);
92
93 dialog = new FindDialog(this);
94
95 connect(addButton, &QPushButton::clicked,
96 this, &AddressBook::addContact);
97 connect(submitButton, &QPushButton::clicked,
98 this, &AddressBook::submitContact);
99 connect(editButton, &QPushButton::clicked,
100 this, &AddressBook::editContact);
101 connect(removeButton, &QPushButton::clicked,
102 this, &AddressBook::removeContact);
103 connect(cancelButton, &QPushButton::clicked,
104 this, &AddressBook::cancel);
105 connect(findButton, &QPushButton::clicked,
106 this, &AddressBook::findContact);
107 connect(nextButton, &QPushButton::clicked,
108 this, &AddressBook::next);
109 connect(previousButton, &QPushButton::clicked,
110 this, &AddressBook::previous);
111 connect(loadButton, &QPushButton::clicked,
112 this, &AddressBook::loadFromFile);
113 connect(saveButton, &QPushButton::clicked,
114 this, &AddressBook::saveToFile);
115 connect(exportButton, &QPushButton::clicked,
116 this, &AddressBook::exportAsVCard);
117
118 QVBoxLayout *buttonLayout1 = new QVBoxLayout;
119 buttonLayout1->addWidget(addButton);
120 buttonLayout1->addWidget(editButton);
121 buttonLayout1->addWidget(removeButton);
122 buttonLayout1->addWidget(findButton);
123 buttonLayout1->addWidget(submitButton);
124 buttonLayout1->addWidget(cancelButton);
125 buttonLayout1->addWidget(loadButton);
126 buttonLayout1->addWidget(saveButton);
127 buttonLayout1->addWidget(exportButton);
128 buttonLayout1->addStretch();
129
130 QHBoxLayout *buttonLayout2 = new QHBoxLayout;
131 buttonLayout2->addWidget(previousButton);
132 buttonLayout2->addWidget(nextButton);
133
134 QGridLayout *mainLayout = new QGridLayout;
135 mainLayout->addWidget(nameLabel, 0, 0);
136 mainLayout->addWidget(nameLine, 0, 1);
137 mainLayout->addWidget(addressLabel, 1, 0, Qt::AlignTop);
138 mainLayout->addWidget(addressText, 1, 1);
139 mainLayout->addLayout(buttonLayout1, 1, 2);
140 mainLayout->addLayout(buttonLayout2, 2, 1);
141
142 setLayout(mainLayout);
143 setWindowTitle(tr("Simple Address Book"));
144}
145
146void AddressBook::addContact()
147{
148 oldName = nameLine->text();
149 oldAddress = addressText->toPlainText();
150
151 nameLine->clear();
152 addressText->clear();
153
154 updateInterface(AddingMode);
155}
156
157void AddressBook::editContact()
158{
159 oldName = nameLine->text();
160 oldAddress = addressText->toPlainText();
161
162 updateInterface(EditingMode);
163}
164
165void AddressBook::submitContact()
166{
167 QString name = nameLine->text();
168 QString address = addressText->toPlainText();
169
170 if (name.isEmpty() || address.isEmpty()) {
171 QMessageBox::information(this, tr("Empty Field"),
172 tr("Please enter a name and address."));
173 return;
174 }
175
176 if (currentMode == AddingMode) {
177
178 if (!contacts.contains(name)) {
179 contacts.insert(name, address);
180 QMessageBox::information(this, tr("Add Successful"),
181 tr("\"%1\" has been added to your address book.").arg(name));
182 } else {
183 QMessageBox::information(this, tr("Add Unsuccessful"),
184 tr("Sorry, \"%1\" is already in your address book.").arg(name));
185 }
186 } else if (currentMode == EditingMode) {
187
188 if (oldName != name) {
189 if (!contacts.contains(name)) {
190 QMessageBox::information(this, tr("Edit Successful"),
191 tr("\"%1\" has been edited in your address book.").arg(oldName));
192 contacts.remove(oldName);
193 contacts.insert(name, address);
194 } else {
195 QMessageBox::information(this, tr("Edit Unsuccessful"),
196 tr("Sorry, \"%1\" is already in your address book.").arg(name));
197 }
198 } else if (oldAddress != address) {
199 QMessageBox::information(this, tr("Edit Successful"),
200 tr("\"%1\" has been edited in your address book.").arg(name));
201 contacts[name] = address;
202 }
203 }
204
205 updateInterface(NavigationMode);
206}
207
208void AddressBook::cancel()
209{
210 nameLine->setText(oldName);
211 addressText->setText(oldAddress);
212 updateInterface(NavigationMode);
213}
214
215void AddressBook::removeContact()
216{
217 QString name = nameLine->text();
218 QString address = addressText->toPlainText();
219
220 if (contacts.contains(name)) {
221
222 int button = QMessageBox::question(this,
223 tr("Confirm Remove"),
224 tr("Are you sure you want to remove \"%1\"?").arg(name),
225 QMessageBox::Yes | QMessageBox::No);
226
227 if (button == QMessageBox::Yes) {
228
229 previous();
230 contacts.remove(name);
231
232 QMessageBox::information(this, tr("Remove Successful"),
233 tr("\"%1\" has been removed from your address book.").arg(name));
234 }
235 }
236
237 updateInterface(NavigationMode);
238}
239
240void AddressBook::next()
241{
242 QString name = nameLine->text();
243 QMap<QString, QString>::iterator i = contacts.find(name);
244
245 if (i != contacts.end())
246 i++;
247
248 if (i == contacts.end())
249 i = contacts.begin();
250
251 nameLine->setText(i.key());
252 addressText->setText(i.value());
253}
254
255void AddressBook::previous()
256{
257 QString name = nameLine->text();
258 QMap<QString, QString>::iterator i = contacts.find(name);
259
260 if (i == contacts.end()) {
261 nameLine->clear();
262 addressText->clear();
263 return;
264 }
265
266 if (i == contacts.begin())
267 i = contacts.end();
268
269 i--;
270 nameLine->setText(i.key());
271 addressText->setText(i.value());
272}
273
274void AddressBook::findContact()
275{
276 dialog->show();
277
278 if (dialog->exec() == 1) {
279 QString contactName = dialog->getFindText();
280
281 if (contacts.contains(contactName)) {
282 nameLine->setText(contactName);
283 addressText->setText(contacts.value(contactName));
284 } else {
285 QMessageBox::information(this, tr("Contact Not Found"),
286 tr("Sorry, \"%1\" is not in your address book.").arg(contactName));
287 return;
288 }
289 }
290
291 updateInterface(NavigationMode);
292}
293void AddressBook::updateInterface(Mode mode)
294{
295 currentMode = mode;
296
297 switch (currentMode) {
298
299 case AddingMode:
300 case EditingMode:
301
302 nameLine->setReadOnly(false);
303 nameLine->setFocus(Qt::OtherFocusReason);
304 addressText->setReadOnly(false);
305
306 addButton->setEnabled(false);
307 editButton->setEnabled(false);
308 removeButton->setEnabled(false);
309
310 nextButton->setEnabled(false);
311 previousButton->setEnabled(false);
312
313 submitButton->show();
314 cancelButton->show();
315
316 loadButton->setEnabled(false);
317 saveButton->setEnabled(false);
318 exportButton->setEnabled(false);
319 break;
320
321 case NavigationMode:
322
323 if (contacts.isEmpty()) {
324 nameLine->clear();
325 addressText->clear();
326 }
327
328 nameLine->setReadOnly(true);
329 addressText->setReadOnly(true);
330 addButton->setEnabled(true);
331
332 int number = contacts.size();
333 editButton->setEnabled(number >= 1);
334 removeButton->setEnabled(number >= 1);
335 findButton->setEnabled(number > 2);
336 nextButton->setEnabled(number > 1);
337 previousButton->setEnabled(number > 1);
338
339 submitButton->hide();
340 cancelButton->hide();
341
342 exportButton->setEnabled(number >= 1);
343
344 loadButton->setEnabled(true);
345 saveButton->setEnabled(number >= 1);
346 break;
347 }
348}
349
350void AddressBook::saveToFile()
351{
352 QString fileName = QFileDialog::getSaveFileName(this,
353 tr("Save Address Book"), "",
354 tr("Address Book (*.abk);;All Files (*)"));
355
356 if (fileName.isEmpty())
357 return;
358 else {
359 QFile file(fileName);
360
361 if (!file.open(QIODevice::WriteOnly)) {
362 QMessageBox::information(this, tr("Unable to open file"),
363 file.errorString());
364 return;
365 }
366
367 QDataStream out(&file);
368 out.setVersion(QDataStream::Qt_4_3);
369 out << contacts;
370 }
371
372 updateInterface(NavigationMode);
373}
374
375void AddressBook::loadFromFile()
376{
377 QString fileName = QFileDialog::getOpenFileName(this,
378 tr("Open Address Book"), "",
379 tr("Address Book (*.abk);;All Files (*)"));
380
381 if (fileName.isEmpty())
382 return;
383 else {
384 QFile file(fileName);
385
386 if (!file.open(QIODevice::ReadOnly)) {
387 QMessageBox::information(this, tr("Unable to open file"),
388 file.errorString());
389 return;
390 }
391
392 QDataStream in(&file);
393 in.setVersion(QDataStream::Qt_4_3);
394 in >> contacts;
395
396 QMap<QString, QString>::iterator i = contacts.begin();
397 nameLine->setText(i.key());
398 addressText->setText(i.value());
399 }
400
401 updateInterface(NavigationMode);
402}
403
404//! [export function part1]
405void AddressBook::exportAsVCard()
406{
407 QString name = nameLine->text();
408 QString address = addressText->toPlainText();
409 QString firstName;
410 QString lastName;
411 QStringList nameList;
412
413 int index = name.indexOf(" ");
414
415 if (index != -1) {
416 nameList = name.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts);
417 firstName = nameList.first();
418 lastName = nameList.last();
419 } else {
420 firstName = name;
421 lastName = "";
422 }
423
424 QString fileName = QFileDialog::getSaveFileName(this,
425 tr("Export Contact"), "",
426 tr("vCard Files (*.vcf);;All Files (*)"));
427
428 if (fileName.isEmpty())
429 return;
430
431 QFile file(fileName);
432//! [export function part1]
433
434//! [export function part2]
435 if (!file.open(QIODevice::WriteOnly)) {
436 QMessageBox::information(this, tr("Unable to open file"),
437 file.errorString());
438 return;
439 }
440
441 QTextStream out(&file);
442//! [export function part2]
443
444//! [export function part3]
445 out << "BEGIN:VCARD" << '\n';
446 out << "VERSION:2.1" << '\n';
447 out << "N:" << lastName << ';' << firstName << '\n';
448
449 if (!nameList.isEmpty())
450 out << "FN:" << nameList.join(' ') << '\n';
451 else
452 out << "FN:" << firstName << '\n';
453//! [export function part3]
454
455//! [export function part4]
456 address.replace(";", "\\;", Qt::CaseInsensitive);
457 address.replace('\n', ";", Qt::CaseInsensitive);
458 address.replace(",", " ", Qt::CaseInsensitive);
459
460 out << "ADR;HOME:;" << address << '\n';
461 out << "END:VCARD" << '\n';
462
463 QMessageBox::information(this, tr("Export Successful"),
464 tr("\"%1\" has been exported as a vCard.").arg(name));
465}
466//! [export function part4]
467