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>
{
public:
~KReportTableModelDataSource() override;
qint64
at()
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>
, m_currentRow(0)
, m_model(&model)
{}
KReportTableModelDataSource::~KReportTableModelDataSource() {}
bool KReportTableModelDataSource::open()
{
return true;
}
bool KReportTableModelDataSource::close()
{
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
{
for (int i = 0; i < m_model->columnCount(); i++) {
}
return names;
}
int KReportTableModelDataSource::fieldNumber(
const QString &field)
const
{
for (int i = 0; i < m_model->columnCount(); i++) {
return i;
}
}
return -1;
}
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));
}
{
return value(fieldNumber(field));
}
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
{
}
Our data source is now ready to be used to render reports.