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:
parent
92d67b58b8
commit
66119a07e8
@ -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
|
||||||
|
@ -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]
|
||||||
|
@ -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]
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user