Address Book example: Replace QPair by struct

Introduce Contact struct to store contact data and use it
instead of QPair<QString, QString>. Proper naming really
clarifies the code.

Task-number: QTBUG-60635
Change-Id: Ibfb421dfc854accc382212b0da46e7aafc0d528a
Reviewed-by: Jesus Fernandez <Jesus.Fernandez@qt.io>
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
This commit is contained in:
Alexander Volkov 2017-09-04 18:09:52 +03:00
parent 92d67b58b8
commit 66119a07e8
4 changed files with 64 additions and 54 deletions

View File

@ -60,8 +60,8 @@
the address book. the address book.
\c TableModel is a subclass of QAbstractTableModel that provides \c TableModel is a subclass of QAbstractTableModel that provides
the standard model/view API to access data. It also holds a the standard model/view API to access data. It holds a list of
QList of \l{QPair}s corresponding to the contacts added. added contacts.
However, this data is not all visible in a single tab. Instead, However, this data is not all visible in a single tab. Instead,
QTableView is used to provide 9 different views of the same QTableView is used to provide 9 different views of the same
data, according to the alphabet groups. data, according to the alphabet groups.
@ -80,7 +80,7 @@
\section1 TableModel Class Definition \section1 TableModel Class Definition
The \c TableModel class provides standard API to access data in The \c TableModel class provides standard API to access data in
its QList of \l{QPair}s by subclassing QAbstractTableModel. The its list of contacts by subclassing QAbstractTableModel. The
basic functions that must be implemented in order to do so are: basic functions that must be implemented in order to do so are:
\c rowCount(), \c columnCount(), \c data(), \c headerData(). \c rowCount(), \c columnCount(), \c data(), \c headerData().
For TableModel to be editable, it has to provide implementations For TableModel to be editable, it has to provide implementations
@ -90,15 +90,14 @@
\snippet itemviews/addressbook/tablemodel.h 0 \snippet itemviews/addressbook/tablemodel.h 0
Two constructors are used, a default constructor which uses Two constructors are used, a default constructor which uses
\c TableModel's own \c {QList<QPair<QString, QString>>} and one \c TableModel's own \c {QList<Contact>} and one that takes
that takes \c {QList<QPair<QString, QString>} as an argument, \c {QList<Contact>} as an argument, for convenience.
for convenience.
\section1 TableModel Class Implementation \section1 TableModel Class Implementation
We implement the two constructors as defined in the header file. We implement the two constructors as defined in the header file.
The second constructor initializes the list of pairs in the The second constructor initializes the list of contacts in the
model, with the parameter value. model, with the parameter value.
\snippet itemviews/addressbook/tablemodel.cpp 0 \snippet itemviews/addressbook/tablemodel.cpp 0
@ -117,7 +116,7 @@
The \c data() function returns either a \b Name or The \c data() function returns either a \b Name or
\b {Address}, based on the contents of the model index \b {Address}, based on the contents of the model index
supplied. The row number stored in the model index is used to supplied. The row number stored in the model index is used to
reference an item in the list of pairs. Selection is handled reference an item in the list of contacts. Selection is handled
by the QItemSelectionModel, which will be explained with by the QItemSelectionModel, which will be explained with
\c AddressWidget. \c AddressWidget.
@ -164,12 +163,11 @@
use the editing features of the QTableView object, we enable use the editing features of the QTableView object, we enable
them here so that we can reuse the model in other programs. them here so that we can reuse the model in other programs.
The last function in \c {TableModel}, \c getList() returns the The last function in \c {TableModel}, \c getContacts() returns the
QList<QPair<QString, QString>> object that holds all the QList<Contact> object that holds all the contacts in the address
contacts in the address book. We use this function later to book. We use this function later to obtain the list of contacts to
obtain the list of contacts to check for existing entries, write check for existing entries, write the contacts to a file and read
the contacts to a file and read them back. Further explanation is them back. Further explanation is given with \c AddressWidget.
given with \c AddressWidget.
\snippet itemviews/addressbook/tablemodel.cpp 8 \snippet itemviews/addressbook/tablemodel.cpp 8
@ -250,7 +248,7 @@
Basic validation is done in the second \c addEntry() function to Basic validation is done in the second \c addEntry() function to
prevent duplicate entries in the address book. As mentioned with prevent duplicate entries in the address book. As mentioned with
\c TableModel, this is part of the reason why we require the \c TableModel, this is part of the reason why we require the
getter method \c getList(). getter method \c getContacts().
\snippet itemviews/addressbook/addresswidget.cpp 3 \snippet itemviews/addressbook/addresswidget.cpp 3
@ -292,7 +290,7 @@
The \c writeToFile() function is used to save a file containing The \c writeToFile() function is used to save a file containing
all the contacts in the address book. The file is saved in a all the contacts in the address book. The file is saved in a
custom \c{.dat} format. The contents of the QList of \l{QPair}s custom \c{.dat} format. The contents of the list of contacts
are written to \c file using QDataStream. If the file cannot be are written to \c file using QDataStream. If the file cannot be
opened, a QMessageBox is displayed with the related error message. opened, a QMessageBox is displayed with the related error message.
@ -301,7 +299,7 @@
The \c readFromFile() function loads a file containing all the The \c readFromFile() function loads a file containing all the
contacts in the address book, previously saved using contacts in the address book, previously saved using
\c writeToFile(). QDataStream is used to read the contents of a \c writeToFile(). QDataStream is used to read the contents of a
\c{.dat} file into a list of pairs and each of these is added \c{.dat} file into a list of contacts and each of these is added
using \c addEntry(). using \c addEntry().
\snippet itemviews/addressbook/addresswidget.cpp 7 \snippet itemviews/addressbook/addresswidget.cpp 7

View File

@ -85,10 +85,7 @@ void AddressWidget::showAddEntryDialog()
//! [3] //! [3]
void AddressWidget::addEntry(QString name, QString address) void AddressWidget::addEntry(QString name, QString address)
{ {
QList<QPair<QString, QString> >list = table->getList(); if (!table->getContacts().contains({ name, address })) {
QPair<QString, QString> pair(name, address);
if (!list.contains(pair)) {
table->insertRows(0, 1, QModelIndex()); table->insertRows(0, 1, QModelIndex());
QModelIndex index = table->index(0, 0, QModelIndex()); QModelIndex index = table->index(0, 0, QModelIndex());
@ -211,18 +208,16 @@ void AddressWidget::readFromFile(const QString &fileName)
return; return;
} }
QList<QPair<QString, QString> > pairs = table->getList(); QList<Contact> contacts;
QDataStream in(&file); QDataStream in(&file);
in >> pairs; in >> contacts;
if (pairs.isEmpty()) { if (contacts.isEmpty()) {
QMessageBox::information(this, tr("No contacts in file"), QMessageBox::information(this, tr("No contacts in file"),
tr("The file you are attempting to open contains no contacts.")); tr("The file you are attempting to open contains no contacts."));
} else { } else {
for (int i=0; i<pairs.size(); ++i) { for (const auto &contact: qAsConst(contacts))
QPair<QString, QString> p = pairs.at(i); addEntry(contact.name, contact.address);
addEntry(p.first, p.second);
}
} }
} }
//! [7] //! [7]
@ -237,8 +232,7 @@ void AddressWidget::writeToFile(const QString &fileName)
return; return;
} }
QList<QPair<QString, QString> > pairs = table->getList();
QDataStream out(&file); QDataStream out(&file);
out << pairs; out << table->getContacts();
} }
//! [6] //! [6]

View File

@ -56,10 +56,10 @@ TableModel::TableModel(QObject *parent)
{ {
} }
TableModel::TableModel(QList<QPair<QString, QString> > pairs, QObject *parent) TableModel::TableModel(QList<Contact> contacts, QObject *parent)
: QAbstractTableModel(parent) : QAbstractTableModel(parent)
, contacts(contacts)
{ {
listOfPairs = pairs;
} }
//! [0] //! [0]
@ -67,7 +67,7 @@ TableModel::TableModel(QList<QPair<QString, QString> > pairs, QObject *parent)
int TableModel::rowCount(const QModelIndex &parent) const int TableModel::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
return listOfPairs.size(); return contacts.size();
} }
int TableModel::columnCount(const QModelIndex &parent) const int TableModel::columnCount(const QModelIndex &parent) const
@ -83,16 +83,16 @@ QVariant TableModel::data(const QModelIndex &index, int role) const
if (!index.isValid()) if (!index.isValid())
return QVariant(); return QVariant();
if (index.row() >= listOfPairs.size() || index.row() < 0) if (index.row() >= contacts.size() || index.row() < 0)
return QVariant(); return QVariant();
if (role == Qt::DisplayRole) { if (role == Qt::DisplayRole) {
QPair<QString, QString> pair = listOfPairs.at(index.row()); const auto &contact = contacts.at(index.row());
if (index.column() == 0) if (index.column() == 0)
return pair.first; return contact.name;
else if (index.column() == 1) else if (index.column() == 1)
return pair.second; return contact.address;
} }
return QVariant(); return QVariant();
} }
@ -126,10 +126,8 @@ bool TableModel::insertRows(int position, int rows, const QModelIndex &index)
Q_UNUSED(index); Q_UNUSED(index);
beginInsertRows(QModelIndex(), position, position + rows - 1); beginInsertRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row) { for (int row = 0; row < rows; ++row)
QPair<QString, QString> pair(" ", " "); contacts.insert(position, { QString(), QString() });
listOfPairs.insert(position, pair);
}
endInsertRows(); endInsertRows();
return true; return true;
@ -142,9 +140,8 @@ bool TableModel::removeRows(int position, int rows, const QModelIndex &index)
Q_UNUSED(index); Q_UNUSED(index);
beginRemoveRows(QModelIndex(), position, position + rows - 1); beginRemoveRows(QModelIndex(), position, position + rows - 1);
for (int row = 0; row < rows; ++row) { for (int row = 0; row < rows; ++row)
listOfPairs.removeAt(position); contacts.removeAt(position);
}
endRemoveRows(); endRemoveRows();
return true; return true;
@ -157,16 +154,16 @@ bool TableModel::setData(const QModelIndex &index, const QVariant &value, int ro
if (index.isValid() && role == Qt::EditRole) { if (index.isValid() && role == Qt::EditRole) {
int row = index.row(); int row = index.row();
QPair<QString, QString> p = listOfPairs.value(row); auto contact = contacts.value(row);
if (index.column() == 0) if (index.column() == 0)
p.first = value.toString(); contact.name = value.toString();
else if (index.column() == 1) else if (index.column() == 1)
p.second = value.toString(); contact.address = value.toString();
else else
return false; return false;
listOfPairs.replace(row, p); contacts.replace(row, contact);
emit(dataChanged(index, index)); emit(dataChanged(index, index));
return true; return true;
@ -187,8 +184,8 @@ Qt::ItemFlags TableModel::flags(const QModelIndex &index) const
//! [7] //! [7]
//! [8] //! [8]
QList< QPair<QString, QString> > TableModel::getList() QList<Contact> TableModel::getContacts() const
{ {
return listOfPairs; return contacts;
} }
//! [8] //! [8]

View File

@ -53,16 +53,37 @@
#include <QAbstractTableModel> #include <QAbstractTableModel>
#include <QList> #include <QList>
#include <QPair>
//! [0] //! [0]
struct Contact
{
QString name;
QString address;
bool operator==(const Contact &other) const
{
return name == other.name && address == other.address;
}
};
inline QDataStream &operator<<(QDataStream &stream, const Contact &contact)
{
return stream << contact.name << contact.address;
}
inline QDataStream &operator>>(QDataStream &stream, Contact &contact)
{
return stream >> contact.name >> contact.address;
}
class TableModel : public QAbstractTableModel class TableModel : public QAbstractTableModel
{ {
Q_OBJECT Q_OBJECT
public: public:
TableModel(QObject *parent = 0); TableModel(QObject *parent = 0);
TableModel(QList<QPair<QString, QString> > listofPairs, QObject *parent = 0); TableModel(QList<Contact> contacts, QObject *parent = 0);
int rowCount(const QModelIndex &parent) const override; int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override; int columnCount(const QModelIndex &parent) const override;
@ -72,10 +93,10 @@ public:
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; 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 insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override; bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
QList<QPair<QString, QString> > getList(); QList<Contact> getContacts() const;
private: private:
QList<QPair<QString, QString> > listOfPairs; QList<Contact> contacts;
}; };
//! [0] //! [0]