Revision control
++ // Copyright (C) 2016 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
++
++ #include "addresswidget.h"
++ #include "adddialog.h"
++ #include "newaddresstab.h"
++
++ #include <QHeaderView>
++ #include <QMessageBox>
++ #include <QTableView>
++
++ #include <QDataStream>
++ #include <QDir>
++ #include <QFile>
++ #include <QItemSelection>
++ #include <QItemSelectionModel>
++ #include <QModelIndex>
++ #include <QRegularExpression>
++ #include <QSortFilterProxyModel>
++ #include <QStandardPaths>
++
++ #include <algorithm>
++
++ using namespace Qt::StringLiterals;
++
++ QString AddressWidget::fileName()
++ {
++ static const QString result = QStandardPaths::standardLocations(QStandardPaths::TempLocation).value(0)
++ + "/addressbook.dat"_L1;
++ return result;
++ }
++
++ //! [0]
++ AddressWidget::AddressWidget(QWidget *parent)
++ : QTabWidget(parent),
++ newAddressTab(new NewAddressTab(this)),
++ adapter(std::ref(contacts))
++ {
++ connect(newAddressTab, &NewAddressTab::triggered, this, &AddressWidget::showAddEntryDialog);
++
++ addTab(newAddressTab, tr("Address Book"));
++
++ setupTabs();
++ }
++ //! [0]
++
++ //! [2]
++ void AddressWidget::showAddEntryDialog()
++ {
++ AddDialog aDialog(this);
++
++ if (aDialog.exec() == QDialog::Accepted)
++ addEntry(aDialog.contact());
++ }
++ //! [2]
++
++ //! [3]
++ void AddressWidget::addEntry(const Contact &contact)
++ {
++ if (contacts.contains(contact)) {
++ QMessageBox::information(this, tr("Duplicate Name"),
++ tr("The name \"%1\" already exists.").arg(contact.name));
++ return;
++ }
++
++ adapter.insertRow(adapter.rowCount(), contact);
++
++ removeTab(indexOf(newAddressTab));
++
++ const QChar firstChar = contact.name.at(0).toUpper();
++ for (int t = 0, tabCount = count(); t < tabCount; ++t) {
++ if (tabText(t).contains(firstChar)) {
++ setCurrentIndex(t);
++ break;
++ }
++ }
++ }
++ //! [3]
++
++ //! [4a]
++ void AddressWidget::editEntry()
++ {
++ auto *tableView = static_cast<QTableView *>(currentWidget());
++ auto *proxy = static_cast<QSortFilterProxyModel *>(tableView->model());
++ QItemSelectionModel *selectionModel = tableView->selectionModel();
++
++ const QModelIndexList indexes = selectionModel->selectedRows();
++ if (indexes.isEmpty())
++ return;
++
++ const int row = proxy->mapToSource(indexes.constFirst()).row();
++ const Contact contact = contacts.at(row);
++ //! [4a]
++
++ //! [4b]
++ AddDialog aDialog(this);
++ aDialog.setWindowTitle(tr("Edit a Contact"));
++ aDialog.editAddress(contact);
++
++ if (aDialog.exec() == QDialog::Accepted) {
++ const Contact newContact = aDialog.contact();
++ if (newContact != contact)
++ adapter[row] = newContact;
++ }
++ }
++ //! [4b]
++
++ //! [5]
++ void AddressWidget::removeEntry()
++ {
++ auto *tableView = static_cast<QTableView *>(currentWidget());
++ auto *proxy = static_cast<QSortFilterProxyModel *>(tableView->model());
++ QItemSelectionModel *selectionModel = tableView->selectionModel();
++
++ const QModelIndexList indexes = selectionModel->selectedRows();
++ if (indexes.isEmpty())
++ return;
++
++ const int row = proxy->mapToSource(indexes.constFirst()).row();
++ adapter.removeRow(row);
++
++ if (adapter.rowCount() == 0)
++ insertTab(0, newAddressTab, tr("Address Book"));
++ }
++ //! [5]
++
++ //! [1]
++ void AddressWidget::setupTabs()
++ {
++ const auto groups = { "ABC"_L1, "DEF"_L1, "GHI"_L1, "JKL"_L1, "MNO"_L1, "PQR"_L1,
++ "STU"_L1, "VW"_L1, "XYZ"_L1 };
++
++ for (QLatin1StringView str : groups) {
++ const auto regExp = QRegularExpression(QLatin1StringView("^[%1].*").arg(str),
++ QRegularExpression::CaseInsensitiveOption);
++
++ auto *proxyModel = new QSortFilterProxyModel(this);
++ proxyModel->setSourceModel(adapter.model());
++ proxyModel->setFilterRegularExpression(regExp);
++ proxyModel->setFilterKeyColumn(0);
++
++ auto *tableView = new QTableView;
++ tableView->setModel(proxyModel);
++ tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
++ tableView->horizontalHeader()->setStretchLastSection(true);
++ tableView->verticalHeader()->hide();
++ tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
++ tableView->setSelectionMode(QAbstractItemView::SingleSelection);
++ tableView->setSortingEnabled(true);
++
++ connect(tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
++ this, &AddressWidget::selectionChanged);
++
++ connect(this, &QTabWidget::currentChanged, this, [this, tableView](int tabIndex) {
++ if (widget(tabIndex) == tableView)
++ emit selectionChanged(tableView->selectionModel()->selection());
++ });
++
++ addTab(tableView, str);
++ }
++ }
++ //! [1]
++
++ //! [7]
++ bool AddressWidget::readFromFile()
++ {
++ QFile file(fileName());
++
++ if (!file.open(QIODevice::ReadOnly)) {
++ QMessageBox::information(this, tr("Unable to open file"),
++ tr("Cannot open %1: %2").arg(QDir::toNativeSeparators(fileName()),
++ file.errorString()));
++ return false;
++ }
++
++ QList<Contact> contactsIn;
++ QDataStream in(&file);
++ in >> contactsIn;
++
++ if (contactsIn.isEmpty()) {
++ QMessageBox::information(this, tr("No contacts in file"),
++ tr("The file you are attempting to open contains no contacts."));
++ }
++
++ for (const auto &contact : std::as_const(contactsIn))
++ addEntry(contact);
++
++ return true;
++ }
++ //! [7]
++
++ //! [6]
++ bool AddressWidget::writeToFile()
++ {
++ QFile file(fileName());
++
++ if (!file.open(QIODevice::WriteOnly)) {
++ QMessageBox::information(this, tr("Unable to open file"),
++ tr("Cannot write to %1: %2").arg(QDir::toNativeSeparators(fileName()),
++ file.errorString()));
++ return false;
++ }
++
++ auto sortedContacts = contacts;
++ std::sort(sortedContacts.begin(), sortedContacts.end());
++
++ QDataStream out(&file);
++ out << sortedContacts;
++ return true;
++ }
++ //! [6]