Cleanup Addressbook example

Cleanup the Addressbook example:
 - use nullptr
 - use for instead foreach
 - don't use public members but setters/getters
 - use QVector instead QList
 - make user-visible translatable

Change-Id: Ie7bdad8a2799c8fa6f634659b51c3064cc8a04ce
Reviewed-by: Samuel Gaist <samuel.gaist@idiap.ch>
Reviewed-by: Sze Howe Koh <szehowe.koh@gmail.com>
Reviewed-by: Paul Wicking <paul.wicking@qt.io>
Reviewed-by: Luca Beldi <v.ronin@yahoo.it>
This commit is contained in:
Christian Ehrlicher 2018-11-12 21:20:34 +01:00
parent 8c38b08343
commit 51f6d5d8c2
11 changed files with 120 additions and 134 deletions

View File

@ -90,8 +90,8 @@
\snippet itemviews/addressbook/tablemodel.h 0
Two constructors are used, a default constructor which uses
\c TableModel's own \c {QList<Contact>} and one that takes
\c {QList<Contact>} as an argument, for convenience.
\c TableModel's own \c {QVector<Contact>} and one that takes
\c {QVector<Contact>} as an argument, for convenience.
\section1 TableModel Class Implementation
@ -108,9 +108,6 @@
\c columnCount()'s value is always 2 because we only need space
for the \b Name and \b Address columns.
\note The \c Q_UNUSED() macro prevents the compiler from
generating warnings regarding unused parameters.
\snippet itemviews/addressbook/tablemodel.cpp 1
The \c data() function returns either a \b Name or
@ -164,7 +161,7 @@
them here so that we can reuse the model in other programs.
The last function in \c {TableModel}, \c getContacts() returns the
QList<Contact> object that holds all the contacts in the address
QVector<Contact> object that holds all the contacts in the address
book. We use this function later to obtain the list of contacts to
check for existing entries, write the contacts to a file and read
them back. Further explanation is given with \c AddressWidget.
@ -233,7 +230,7 @@
\image addressbook-signals.png Signals and Slots Connections
We provide 2 \c addEntry() functions: 1 which is intended to be
We provide two \c addEntry() functions: One which is intended to be
used to accept user input, and the other which performs the actual
task of adding new entries to the address book. We divide the
responsibility of adding entries into two parts to allow

View File

@ -54,17 +54,16 @@
//! [0]
AddDialog::AddDialog(QWidget *parent)
: QDialog(parent)
: QDialog(parent),
nameText(new QLineEdit),
addressText(new QTextEdit)
{
nameLabel = new QLabel("Name");
addressLabel = new QLabel("Address");
okButton = new QPushButton("OK");
cancelButton = new QPushButton("Cancel");
auto nameLabel = new QLabel(tr("Name"));
auto addressLabel = new QLabel(tr("Address"));
auto okButton = new QPushButton(tr("OK"));
auto cancelButton = new QPushButton(tr("Cancel"));
nameText = new QLineEdit;
addressText = new QTextEdit;
QGridLayout *gLayout = new QGridLayout;
auto gLayout = new QGridLayout;
gLayout->setColumnStretch(1, 2);
gLayout->addWidget(nameLabel, 0, 0);
gLayout->addWidget(nameText, 0, 1);
@ -72,13 +71,13 @@ AddDialog::AddDialog(QWidget *parent)
gLayout->addWidget(addressLabel, 1, 0, Qt::AlignLeft|Qt::AlignTop);
gLayout->addWidget(addressText, 1, 1, Qt::AlignLeft);
QHBoxLayout *buttonLayout = new QHBoxLayout;
auto buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
gLayout->addLayout(buttonLayout, 2, 1, Qt::AlignRight);
QVBoxLayout *mainLayout = new QVBoxLayout;
auto mainLayout = new QVBoxLayout;
mainLayout->addLayout(gLayout);
setLayout(mainLayout);
@ -87,4 +86,21 @@ AddDialog::AddDialog(QWidget *parent)
setWindowTitle(tr("Add a Contact"));
}
QString AddDialog::name() const
{
return nameText->text();
}
QString AddDialog::address() const
{
return addressText->toPlainText();
}
void AddDialog::editAddress(const QString &name, const QString &address)
{
nameText->setReadOnly(true);
nameText->setText(name);
addressText->setPlainText(address);
}
//! [0]

View File

@ -66,15 +66,15 @@ class AddDialog : public QDialog
Q_OBJECT
public:
AddDialog(QWidget *parent = 0);
QLineEdit *nameText;
QTextEdit *addressText;
AddDialog(QWidget *parent = nullptr);
QString name() const;
QString address() const;
void editAddress(const QString &name, const QString &address);
private:
QLabel *nameLabel;
QLabel *addressLabel;
QPushButton *okButton;
QPushButton *cancelButton;
QLineEdit *nameText;
QTextEdit *addressText;
};
//! [0]

View File

@ -48,21 +48,21 @@
**
****************************************************************************/
#include "adddialog.h"
#include "addresswidget.h"
#include "adddialog.h"
#include <QtWidgets>
//! [0]
AddressWidget::AddressWidget(QWidget *parent)
: QTabWidget(parent)
: QTabWidget(parent),
table(new TableModel(this)),
newAddressTab(new NewAddressTab(this))
{
table = new TableModel(this);
newAddressTab = new NewAddressTab(this);
connect(newAddressTab, &NewAddressTab::sendDetails,
this, &AddressWidget::addEntry);
addTab(newAddressTab, "Address Book");
addTab(newAddressTab, tr("Address Book"));
setupTabs();
}
@ -73,17 +73,13 @@ void AddressWidget::showAddEntryDialog()
{
AddDialog aDialog;
if (aDialog.exec()) {
QString name = aDialog.nameText->text();
QString address = aDialog.addressText->toPlainText();
addEntry(name, address);
}
if (aDialog.exec())
addEntry(aDialog.name(), aDialog.address());
}
//! [2]
//! [3]
void AddressWidget::addEntry(QString name, QString address)
void AddressWidget::addEntry(const QString &name, const QString &address)
{
if (!table->getContacts().contains({ name, address })) {
table->insertRows(0, 1, QModelIndex());
@ -107,12 +103,12 @@ void AddressWidget::editEntry()
QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model());
QItemSelectionModel *selectionModel = temp->selectionModel();
QModelIndexList indexes = selectionModel->selectedRows();
const QModelIndexList indexes = selectionModel->selectedRows();
QString name;
QString address;
int row = -1;
foreach (QModelIndex index, indexes) {
for (const QModelIndex &index : indexes) {
row = proxy->mapToSource(index).row();
QModelIndex nameIndex = table->index(row, 0, QModelIndex());
QVariant varName = table->data(nameIndex, Qt::DisplayRole);
@ -127,15 +123,12 @@ void AddressWidget::editEntry()
//! [4b]
AddDialog aDialog;
aDialog.setWindowTitle(tr("Edit a Contact"));
aDialog.nameText->setReadOnly(true);
aDialog.nameText->setText(name);
aDialog.addressText->setText(address);
aDialog.editAddress(name, address);
if (aDialog.exec()) {
QString newAddress = aDialog.addressText->toPlainText();
const QString newAddress = aDialog.address();
if (newAddress != address) {
QModelIndex index = table->index(row, 1, QModelIndex());
const QModelIndex index = table->index(row, 1, QModelIndex());
table->setData(index, newAddress, Qt::EditRole);
}
}
@ -149,52 +142,46 @@ void AddressWidget::removeEntry()
QSortFilterProxyModel *proxy = static_cast<QSortFilterProxyModel*>(temp->model());
QItemSelectionModel *selectionModel = temp->selectionModel();
QModelIndexList indexes = selectionModel->selectedRows();
const QModelIndexList indexes = selectionModel->selectedRows();
foreach (QModelIndex index, indexes) {
for (QModelIndex index : indexes) {
int row = proxy->mapToSource(index).row();
table->removeRows(row, 1, QModelIndex());
}
if (table->rowCount(QModelIndex()) == 0) {
insertTab(0, newAddressTab, "Address Book");
}
if (table->rowCount(QModelIndex()) == 0)
insertTab(0, newAddressTab, tr("Address Book"));
}
//! [5]
//! [1]
void AddressWidget::setupTabs()
{
QStringList groups;
groups << "ABC" << "DEF" << "GHI" << "JKL" << "MNO" << "PQR" << "STU" << "VW" << "XYZ";
const auto groups = { "ABC", "DEF", "GHI", "JKL", "MNO", "PQR", "STU", "VW", "XYZ" };
for (int i = 0; i < groups.size(); ++i) {
QString str = groups.at(i);
QString regExp = QString("^[%1].*").arg(str);
for (const QString &str : groups) {
const auto regExp = QRegularExpression(QString("^[%1].*").arg(str),
QRegularExpression::CaseInsensitiveOption);
proxyModel = new QSortFilterProxyModel(this);
auto proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(table);
proxyModel->setFilterRegExp(QRegExp(regExp, Qt::CaseInsensitive));
proxyModel->setFilterRegularExpression(regExp);
proxyModel->setFilterKeyColumn(0);
QTableView *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(tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
this, &AddressWidget::selectionChanged);
connect(this, &QTabWidget::currentChanged, this, [this](int tabIndex) {
auto *tableView = qobject_cast<QTableView *>(widget(tabIndex));
if (tableView)
connect(this, &QTabWidget::currentChanged, this, [this, tableView](int tabIndex) {
if (widget(tabIndex) == tableView)
emit selectionChanged(tableView->selectionModel()->selection());
});
@ -214,7 +201,7 @@ void AddressWidget::readFromFile(const QString &fileName)
return;
}
QList<Contact> contacts;
QVector<Contact> contacts;
QDataStream in(&file);
in >> contacts;

View File

@ -68,13 +68,13 @@ class AddressWidget : public QTabWidget
Q_OBJECT
public:
AddressWidget(QWidget *parent = 0);
AddressWidget(QWidget *parent = nullptr);
void readFromFile(const QString &fileName);
void writeToFile(const QString &fileName);
public slots:
void showAddEntryDialog();
void addEntry(QString name, QString address);
void addEntry(const QString &name, const QString &address);
void editEntry();
void removeEntry();
@ -86,7 +86,6 @@ private:
TableModel *table;
NewAddressTab *newAddressTab;
QSortFilterProxyModel *proxyModel;
};
//! [0]

View File

@ -56,8 +56,9 @@
//! [0]
MainWindow::MainWindow()
: QMainWindow(),
addressWidget(new AddressWidget)
{
addressWidget = new AddressWidget;
setCentralWidget(addressWidget);
createMenus();
setWindowTitle(tr("Address Book"));
@ -67,28 +68,29 @@ MainWindow::MainWindow()
//! [1a]
void MainWindow::createMenus()
{
fileMenu = menuBar()->addMenu(tr("&File"));
QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
openAct = new QAction(tr("&Open..."), this);
QAction *openAct = new QAction(tr("&Open..."), this);
fileMenu->addAction(openAct);
connect(openAct, &QAction::triggered, this, &MainWindow::openFile);
//! [1a]
saveAct = new QAction(tr("&Save As..."), this);
QAction *saveAct = new QAction(tr("&Save As..."), this);
fileMenu->addAction(saveAct);
connect(saveAct, &QAction::triggered, this, &MainWindow::saveFile);
fileMenu->addSeparator();
exitAct = new QAction(tr("E&xit"), this);
QAction *exitAct = new QAction(tr("E&xit"), this);
fileMenu->addAction(exitAct);
connect(exitAct, &QAction::triggered, this, &QWidget::close);
toolMenu = menuBar()->addMenu(tr("&Tools"));
QMenu *toolMenu = menuBar()->addMenu(tr("&Tools"));
addAct = new QAction(tr("&Add Entry..."), this);
QAction *addAct = new QAction(tr("&Add Entry..."), this);
toolMenu->addAction(addAct);
connect(addAct, &QAction::triggered, addressWidget, &AddressWidget::showAddEntryDialog);
connect(addAct, &QAction::triggered,
addressWidget, &AddressWidget::showAddEntryDialog);
//! [1b]
editAct = new QAction(tr("&Edit Entry..."), this);

View File

@ -72,12 +72,6 @@ private:
void createMenus();
AddressWidget *addressWidget;
QMenu *fileMenu;
QMenu *toolMenu;
QAction *openAct;
QAction *saveAct;
QAction *exitAct;
QAction *addAct;
QAction *editAct;
QAction *removeAct;
};

View File

@ -48,24 +48,23 @@
**
****************************************************************************/
#include "adddialog.h"
#include "newaddresstab.h"
#include "adddialog.h"
#include <QtWidgets>
//! [0]
NewAddressTab::NewAddressTab(QWidget *parent)
: QWidget(parent)
{
Q_UNUSED(parent);
auto descriptionLabel = new QLabel(tr("There are currently no contacts in your address book. "
"\nClick Add to add new contacts."));
descriptionLabel = new QLabel(tr("There are currently no contacts in your address book. "
"\nClick Add to add new contacts."));
addButton = new QPushButton(tr("Add"));
auto addButton = new QPushButton(tr("Add"));
connect(addButton, &QAbstractButton::clicked, this, &NewAddressTab::addEntry);
mainLayout = new QVBoxLayout;
auto mainLayout = new QVBoxLayout;
mainLayout->addWidget(descriptionLabel);
mainLayout->addWidget(addButton, 0, Qt::AlignCenter);
@ -78,11 +77,7 @@ void NewAddressTab::addEntry()
{
AddDialog aDialog;
if (aDialog.exec()) {
QString name = aDialog.nameText->text();
QString address = aDialog.addressText->toPlainText();
emit sendDetails(name, address);
}
if (aDialog.exec())
emit sendDetails(aDialog.name(), aDialog.address());
}
//! [1]

View File

@ -65,19 +65,13 @@ class NewAddressTab : public QWidget
Q_OBJECT
public:
NewAddressTab(QWidget *parent = 0);
NewAddressTab(QWidget *parent = nullptr);
public slots:
void addEntry();
signals:
void sendDetails(QString name, QString address);
private:
QLabel *descriptionLabel;
QPushButton *addButton;
QVBoxLayout *mainLayout;
void sendDetails(const QString &name, const QString &address);
};
//! [0]

View File

@ -56,9 +56,9 @@ TableModel::TableModel(QObject *parent)
{
}
TableModel::TableModel(QList<Contact> contacts, QObject *parent)
: QAbstractTableModel(parent)
, contacts(contacts)
TableModel::TableModel(const QVector<Contact> &contacts, QObject *parent)
: QAbstractTableModel(parent),
contacts(contacts)
{
}
//! [0]
@ -66,14 +66,12 @@ TableModel::TableModel(QList<Contact> contacts, QObject *parent)
//! [1]
int TableModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return contacts.size();
return parent.isValid() ? 0 : contacts.size();
}
int TableModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 2;
return parent.isValid() ? 0 : 2;
}
//! [1]
@ -89,10 +87,14 @@ QVariant TableModel::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
const auto &contact = contacts.at(index.row());
if (index.column() == 0)
return contact.name;
else if (index.column() == 1)
return contact.address;
switch (index.column()) {
case 0:
return contact.name;
case 1:
return contact.address;
default:
break;
}
}
return QVariant();
}
@ -108,12 +110,10 @@ QVariant TableModel::headerData(int section, Qt::Orientation orientation, int ro
switch (section) {
case 0:
return tr("Name");
case 1:
return tr("Address");
default:
return QVariant();
break;
}
}
return QVariant();
@ -152,19 +152,21 @@ bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
bool TableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && role == Qt::EditRole) {
int row = index.row();
const int row = index.row();
auto contact = contacts.value(row);
if (index.column() == 0)
contact.name = value.toString();
else if (index.column() == 1)
contact.address = value.toString();
else
return false;
switch (index.column()) {
case 0:
contact.name = value.toString();
break;
case 1:
contact.address = value.toString();
break;
default:
return false;
}
contacts.replace(row, contact);
emit dataChanged(index, index, {role});
emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole});
return true;
}
@ -184,7 +186,7 @@ Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
//! [7]
//! [8]
QList<Contact> TableModel::getContacts() const
const QVector<Contact> &TableModel::getContacts() const
{
return contacts;
}

View File

@ -52,7 +52,7 @@
#define TABLEMODEL_H
#include <QAbstractTableModel>
#include <QList>
#include <QVector>
//! [0]
@ -82,8 +82,8 @@ class TableModel : public QAbstractTableModel
Q_OBJECT
public:
TableModel(QObject *parent = 0);
TableModel(QList<Contact> contacts, QObject *parent = 0);
TableModel(QObject *parent = nullptr);
TableModel(const QVector<Contact> &contacts, QObject *parent = nullptr);
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
@ -93,10 +93,10 @@ public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
QList<Contact> getContacts() const;
const QVector<Contact> &getContacts() const;
private:
QList<Contact> contacts;
QVector<Contact> contacts;
};
//! [0]