KReport

How to Implement a Data Source

This section describes how to implement a data source for KReport. As an example, this data source will simply wrap a QAbstractTableModel and will keep the current row in an attribute. It is the most simple data source that does not sort its data.

#include <KReportDataSource>
#include <QPointer>
class KReportTableModelDataSource : public KReportDataSource
{
public:
explicit KReportTableModelDataSource(QAbstractTableModel *model);
~KReportTableModelDataSource() override;
bool open() override;
bool close() override;
bool moveNext() override;
bool movePrevious() override;
bool moveFirst() override;
bool moveLast() override;
qint64 at() const override;
qint64 recordCount() const override;
int fieldNumber(const QString &field) const override;
QStringList fieldNames() const override;
QVariant value(int pos) const override;
QVariant value(const QString &field) const override;
QStringList dataSourceNames() const override;
private:
qint64 m_currentRow;
};
Abstraction of report data source.
virtual bool close()=0
Close the dataset.
virtual bool moveNext()=0
Move to the next record.
virtual bool moveLast()=0
Move to the last record.
virtual int fieldNumber(const QString &field) const =0
Return the index number of the field given by nane field.
virtual qint64 recordCount() const =0
Return the total number of records.
virtual bool movePrevious()=0
Move to the previous record.
virtual QStringList dataSourceNames() const =0
Return a list of data source names available for this data source Works after the source is opened.
virtual qint64 at() const =0
Return the current position in the dataset.
virtual bool open()=0
Open the dataset.
virtual bool moveFirst()=0
Move to the first record.
virtual QStringList fieldNames() const =0
Return the list of field names.
virtual QVariant value(int pos) const =0
Return the value of the field at the given position for the current record.

The constructor already receives the model with all the data that we need to extract, therefore in this case there is nothing to open or close.

#include "kreporttablemodeldatasource.h"
#include <QAbstractTableModel>
KReportTableModelDataSource::KReportTableModelDataSource(QAbstractTableModel *model)
, m_currentRow(0)
, m_model(&model)
{}
KReportTableModelDataSource::~KReportTableModelDataSource() {}
bool KReportTableModelDataSource::open()
{
// Nothing to do.
return true;
}
bool KReportTableModelDataSource::close()
{
// Nothing to do.
return true;
}

Next we will manage the current row by implementing the next, previous, first, and last methods. Those methods are called by KReport when traversing the data source within a report’s section.

bool KReportTableModelDataSource::moveNext()
{
if (m_currentRow >= recordCount() - 1) {
return false;
}
m_currentRow++;
return true;
}
bool KReportTableModelDataSource::movePrevious()
{
if (m_currentRow <= 0) {
return false;
}
m_currentRow--;
return true;
}
bool KReportTableModelDataSource::moveFirst()
{
m_currentRow = 0;
return true;
}
bool KReportTableModelDataSource::moveLast()
{
m_currentRow = recordCount() - 1;
return true;
}
qint64 KReportTableModelDataSource::at() const
{
return m_currentRow;
}

KReport needs to know how many rows there are in the data source.

qint64 KReportTableModelDataSource::recordCount() const
{
return m_model->rowCount();
}

It also needs to know the field count for each record, their names, and a way to reference them. All records need to have the same number of fields, exactly like the rows of a QAbstractTableModel. In this case, the field names will correspond to column’s names, and will use them as keys; the default behaviour of KReportDataSource::fieldKeys() is to return the output of KReportDataSource::fieldNames().

QStringList KReportTableModelDataSource::fieldNames() const
{
QStringList names;
for (int i = 0; i < m_model->columnCount(); i++) {
names << m_model->headerData(i, Qt::Horizontal).toString();
}
return names;
}
int KReportTableModelDataSource::fieldNumber(const QString &field) const
{
for (int i = 0; i < m_model->columnCount(); i++) {
if (m_model->headerData(i, Qt::Horizontal).toString() == field) {
return i;
}
}
return -1;
}
Horizontal

KReport will need to be able to read the value of a given field. The field is always in the current record and can be referenced by the key — the column’s name in this case — or by its position. Therefore we need to handle both cases.

QVariant KReportTableModelDataSource::value(int pos) const
{
return m_model->data(m_model->index(m_currentRow, pos));
}
QVariant KReportTableModelDataSource::value(const QString &field) const
{
return value(fieldNumber(field));
}
void * data()

The last remaining method to implement is for data sources that can retrieve data from multiple sources. In this case there is one possible source, the QAbstractTableModel, and have nothing to return.

QStringList KReportTableModelDataSource::dataSourceNames() const
{
return QStringList();
}

Our data source is now ready to be used to render reports.

This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:21:31 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.