File indexing completed on 2024-05-12 03:47:26

0001 /*
0002     File                 : AbstractSimpleFilter.cpp
0003     Project              : AbstractColumn
0004     Description          : Simplified filter interface for filters with
0005     only one output port.
0006     --------------------------------------------------------------------
0007     SPDX-FileCopyrightText: 2007, 2008 Knut Franke <knut.franke*gmx.de (use @ for *)>
0008     SPDX-FileCopyrightText: 2007, 2008 Tilman Benkert <thzs@gmx.net>
0009     SPDX-FileCopyrightText: 2020 Stefan Gerlach <stefan.gerlach@uni.kn>
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 */
0012 
0013 #include "AbstractSimpleFilter.h"
0014 #include "backend/lib/XmlStreamReader.h"
0015 
0016 #include <QDate>
0017 #include <QDateTime>
0018 #include <QTime>
0019 
0020 #include <KLocalizedString>
0021 
0022 /**
0023  * \class AbstractSimpleFilter
0024  * \brief Simplified filter interface for filters with only one output port.
0025  *
0026  * This class is only meant to simplify implementation of a restricted subtype of filter.
0027  * It should not be instantiated directly. You should always either derive from
0028  * AbstractFilter or (if necessary) provide an actual (non-abstract) implementation.
0029  *
0030  * The trick here is that, in a sense, the filter is its own output port. This means you
0031  * can implement a complete filter in only one class and don't have to coordinate data
0032  * transfer between a filter class and a data source class.
0033  * Additionally, AbstractSimpleFilter offers some useful convenience methods which make writing
0034  * filters as painless as possible.
0035  *
0036  * For the data type of the output, all types supported by AbstractColumn (currently double, QString and
0037  * QDateTime) are supported.
0038  *
0039  * \section tutorial1 Tutorial, Step 1
0040  * The simplest filter you can write assumes there's also only one input port and rows on the
0041  * input correspond 1:1 to rows in the output. All you need to specify is what data type you
0042  * want to have (in this example double) on the input port and how to compute the output values:
0043  *
0044  * \code
0045  * 01 #include "AbstractSimpleFilter.h"
0046  * 02 class TutorialFilter1 : public AbstractSimpleFilter
0047  * 03 {
0048  * 04   protected:
0049  * 05       virtual bool inputAcceptable(int, AbstractColumn *source) {
0050  * 06           return (source->columnMode() == AbstractColumn::Numeric);
0051  * 07       }
0052  * 08   public:
0053  * 09       virtual AbstractColumn::ColumnMode columnMode() const { return AbstractColumn::Numeric; }
0054  * 10
0055  * 11       virtual double valueAt(int row) const {
0056  * 12           if (!m_inputs.value(0)) return 0.0;
0057  * 13           double input_value = m_inputs.value(0)->valueAt(row);
0058  * 14           return input_value * input_value;
0059  * 15       }
0060  * 16 };
0061  * \endcode
0062  *
0063  * This filter reads an input value (line 13) and returns its square (line 14).
0064  * Reimplementing inputAcceptable() makes sure that the data source really is of type
0065  * double (lines 5 to 7). Otherwise, the source will be rejected by AbstractFilter::input().
0066  * The output type is reported by reimplementing columnMode() (line 09).
0067  * Before you actually use m_inputs.value(0), make sure that the input port has
0068  * been connected to a data source (line 12).
0069  * Otherwise line 13 would result in a crash. That's it, we've already written a
0070  * fully-functional filter!
0071  *
0072  * Equivalently, you can write 1:1-filters for QString or QDateTime inputs by checking for
0073  * AbstractColumn::TypeQString or AbstractColumn::TypeQDateTime in line 6. You would then use
0074  * AbstractColumn::textAt(row) or AbstractColumn::dateTimeAt(row) in line 13 to access the input data.
0075  * For QString output, you need to implement AbstractColumn::textAt(row).
0076  * For QDateTime output, you have to implement three methods:
0077  * \code
0078  * virtual QDateTime dateTimeAt(int row) const;
0079  * virtual QDate dateAt(int row) const;
0080  * virtual QTime timeAt(int row) const;
0081  * \endcode
0082  *
0083  * \section tutorial2 Tutorial, Step 2
0084  * Now for something slightly more interesting: a filter that uses only every second row of its
0085  * input. We no longer have a 1:1 correspondence between input and output rows, so we'll have
0086  * to do a bit more work in order to have everything come out as expected.
0087  * We'll use double-typed input and output again:
0088  * \code
0089  * 01 #include "AbstractSimpleFilter.h"
0090  * 02 class TutorialFilter2 : public AbstractSimpleFilter
0091  * 03 {
0092  * 04   protected:
0093  * 05       virtual bool inputAcceptable(int, AbstractColumn *source) {
0094  * 06           return (source->columnMode() == AbstractColumn::Numeric);
0095  * 07       }
0096  * 08   public:
0097  * 09       virtual AbstractColumn::ColumnMode columnMode() const { return AbstractColumn::Numeric; }
0098  * \endcode
0099  * Even rows (including row 0) get dropped, odd rows are renumbered:
0100  * \code
0101  * 10   public:
0102  * 11   virtual double valueAt(int row) const {
0103  * 12       if (!m_inputs.value(0)) return 0.0;
0104  * 13       return m_inputs.value(0)->valueAt(2*row + 1);
0105  * 14   }
0106  * \endcode
0107  */
0108 
0109 // TODO: should simple filters have a name argument?
0110 /**
0111  * \brief Ctor
0112  */
0113 AbstractSimpleFilter::AbstractSimpleFilter()
0114     : AbstractFilter(QStringLiteral("SimpleFilter"))
0115     , m_output_column(new SimpleFilterColumn(this)) {
0116     addChildFast(m_output_column);
0117 }
0118 
0119 /**
0120  * \brief Default to one input port.
0121  */
0122 int AbstractSimpleFilter::inputCount() const {
0123     return 1;
0124 }
0125 
0126 /**
0127  * \brief We manage only one output port (don't override unless you really know what you are doing).
0128  */
0129 int AbstractSimpleFilter::outputCount() const {
0130     return 1;
0131 }
0132 
0133 /**
0134  * \brief Copy plot designation of input port 0.
0135  */
0136 AbstractColumn::PlotDesignation AbstractSimpleFilter::plotDesignation() const {
0137     return m_inputs.value(0) ? m_inputs.at(0)->plotDesignation() : AbstractColumn::PlotDesignation::NoDesignation;
0138 }
0139 
0140 /**
0141  * \brief Return the column mode
0142  *
0143  * This function is most used by tables but can also be used
0144  * by plots. The column mode specifies how to interpret
0145  * the values in the column additional to the data type.
0146  */
0147 AbstractColumn::ColumnMode AbstractSimpleFilter::columnMode() const {
0148     // calling this function while m_input is empty is a sign of very bad code
0149     // nevertheless it will return some rather meaningless value to
0150     // avoid crashes
0151     return m_inputs.value(0) ? m_inputs.at(0)->columnMode() : AbstractColumn::ColumnMode::Text;
0152 }
0153 
0154 /**
0155  * \brief Return the content of row 'row'.
0156  *
0157  * Use this only when columnMode() is Text
0158  */
0159 QString AbstractSimpleFilter::textAt(int row) const {
0160     return m_inputs.value(0) ? m_inputs.at(0)->textAt(row) : QString();
0161 }
0162 
0163 /**
0164  * \brief Return the date part of row 'row'
0165  *
0166  * Use this only when columnMode() is DateTime, Month or Day
0167  */
0168 QDate AbstractSimpleFilter::dateAt(int row) const {
0169     return m_inputs.value(0) ? m_inputs.at(0)->dateAt(row) : QDate();
0170 }
0171 
0172 /**
0173  * \brief Return the time part of row 'row'
0174  *
0175  * Use this only when columnMode() is DateTime, Month or Day
0176  */
0177 QTime AbstractSimpleFilter::timeAt(int row) const {
0178     return m_inputs.value(0) ? m_inputs.at(0)->timeAt(row) : QTime();
0179 }
0180 
0181 /**
0182  * \brief Set the content of row 'row'
0183  *
0184  * Use this only when columnMode() is DateTime, Month or Day
0185  */
0186 QDateTime AbstractSimpleFilter::dateTimeAt(int row) const {
0187     return m_inputs.value(0) ? m_inputs.at(0)->dateTimeAt(row) : QDateTime();
0188 }
0189 
0190 /**
0191  * \brief Return the double value in row 'row'
0192  *
0193  * Use this only when columnMode() is Numeric
0194  */
0195 double AbstractSimpleFilter::valueAt(int row) const {
0196     return m_inputs.value(0) ? m_inputs.at(0)->valueAt(row) : 0.0;
0197 }
0198 
0199 /**
0200  * \brief Return the integer value in row 'row'
0201  *
0202  * Use this only when columnMode() is Integer
0203  */
0204 int AbstractSimpleFilter::integerAt(int row) const {
0205     return m_inputs.value(0) ? m_inputs.at(0)->integerAt(row) : 0;
0206 }
0207 
0208 /**
0209  * \brief Return the bigint value in row 'row'
0210  *
0211  * Use this only when columnMode() is BigInt
0212  */
0213 qint64 AbstractSimpleFilter::bigIntAt(int row) const {
0214     return m_inputs.value(0) ? m_inputs.at(0)->bigIntAt(row) : 0;
0215 }
0216 
0217 /**
0218  * \brief Number of output rows == number of input rows
0219  *
0220  * ... unless overridden in a subclass.
0221  */
0222 int AbstractSimpleFilter::rowCount() const {
0223     return m_inputs.value(0) ? m_inputs.at(0)->rowCount() : 0;
0224 }
0225 
0226 int AbstractSimpleFilter::rowCount(double min, double max) const {
0227     return m_inputs.value(0) ? m_inputs.at(0)->rowCount(min, max) : 0;
0228 }
0229 
0230 /**
0231  * \brief Number of output rows == number of input rows
0232  *
0233  * ... unless overridden in a subclass.
0234  */
0235 int AbstractSimpleFilter::availableRowCount(int max) const {
0236     return m_inputs.value(0) ? m_inputs.at(0)->availableRowCount(max) : 0;
0237 }
0238 
0239 /**
0240  * \brief Rows that will change when the given input interval changes.
0241  *
0242  * This implementation assumes a 1:1 correspondence between input and output rows, but can be
0243  * overridden in subclasses.
0244  */
0245 QList<Interval<int>> AbstractSimpleFilter::dependentRows(const Interval<int>& inputRange) const {
0246     return QList<Interval<int>>() << inputRange;
0247 }
0248 
0249 ////////////////////////////////////////////////////////////////////////////////////////////////////
0250 //!\name signal handlers
0251 //@{
0252 ////////////////////////////////////////////////////////////////////////////////////////////////////
0253 
0254 void AbstractSimpleFilter::inputPlotDesignationAboutToChange(const AbstractColumn*) {
0255     Q_EMIT m_output_column->plotDesignationAboutToChange(m_output_column);
0256 }
0257 
0258 void AbstractSimpleFilter::inputPlotDesignationChanged(const AbstractColumn*) {
0259     Q_EMIT m_output_column->plotDesignationChanged(m_output_column);
0260 }
0261 
0262 void AbstractSimpleFilter::inputModeAboutToChange(const AbstractColumn*) {
0263     Q_EMIT m_output_column->dataAboutToChange(m_output_column);
0264 }
0265 
0266 void AbstractSimpleFilter::inputModeChanged(const AbstractColumn*) {
0267     Q_EMIT m_output_column->dataChanged(m_output_column);
0268 }
0269 
0270 void AbstractSimpleFilter::inputDataAboutToChange(const AbstractColumn*) {
0271     Q_EMIT m_output_column->dataAboutToChange(m_output_column);
0272 }
0273 
0274 void AbstractSimpleFilter::inputDataChanged(const AbstractColumn*) {
0275     Q_EMIT m_output_column->dataChanged(m_output_column);
0276 }
0277 
0278 void AbstractSimpleFilter::inputRowsAboutToBeInserted(const AbstractColumn* /*source*/, int before, int /*count*/) {
0279     for (const auto& output_range : dependentRows(Interval<int>(before, before)))
0280         Q_EMIT m_output_column->rowsAboutToBeInserted(m_output_column, output_range.start(), output_range.size());
0281 }
0282 
0283 void AbstractSimpleFilter::inputRowsInserted(const AbstractColumn* /*source*/, int before, int /*count*/) {
0284     for (const auto& output_range : dependentRows(Interval<int>(before, before)))
0285         Q_EMIT m_output_column->rowsInserted(m_output_column, output_range.start(), output_range.size());
0286 }
0287 
0288 void AbstractSimpleFilter::inputRowsAboutToBeRemoved(const AbstractColumn* /*source*/, int first, int count) {
0289     for (const auto& output_range : dependentRows(Interval<int>(first, first + count - 1)))
0290         Q_EMIT m_output_column->rowsAboutToBeRemoved(m_output_column, output_range.start(), output_range.size());
0291 }
0292 
0293 void AbstractSimpleFilter::inputRowsRemoved(const AbstractColumn* /*source*/, int first, int count) {
0294     for (const auto& output_range : dependentRows(Interval<int>(first, first + count - 1)))
0295         Q_EMIT m_output_column->rowsRemoved(m_output_column, output_range.start(), output_range.size());
0296 }
0297 
0298 ////////////////////////////////////////////////////////////////////////////////////////////////////
0299 //@}
0300 ////////////////////////////////////////////////////////////////////////////////////////////////////
0301 
0302 /**
0303  * \brief Return a pointer to #m_output_column on port 0 (don't override unless you really know what you are doing).
0304  */
0305 AbstractColumn* AbstractSimpleFilter::output(int port) {
0306     return port == 0 ? static_cast<AbstractColumn*>(m_output_column) : nullptr;
0307 }
0308 
0309 const AbstractColumn* AbstractSimpleFilter::output(int port) const {
0310     return port == 0 ? static_cast<const AbstractColumn*>(m_output_column) : nullptr;
0311 }
0312 
0313 ////////////////////////////////////////////////////////////////////////////////////////////////////
0314 //! \name serialize/deserialize
0315 //@{
0316 ////////////////////////////////////////////////////////////////////////////////////////////////////
0317 
0318 /**
0319  * \brief Save to XML
0320  */
0321 void AbstractSimpleFilter::save(QXmlStreamWriter* writer) const {
0322     writer->writeStartElement(QStringLiteral("simple_filter"));
0323     writeBasicAttributes(writer);
0324     writeExtraAttributes(writer);
0325     writer->writeAttribute(QStringLiteral("filter_name"), QLatin1String(metaObject()->className()));
0326     writeCommentElement(writer);
0327     writer->writeEndElement();
0328 }
0329 
0330 /**
0331  * \brief Override this in derived classes if they have other attributes than filter_name
0332  */
0333 void AbstractSimpleFilter::writeExtraAttributes(QXmlStreamWriter*) const {
0334 }
0335 
0336 ////////////////////////////////////////////////////////////////////////////////////////////////////
0337 //@}
0338 ////////////////////////////////////////////////////////////////////////////////////////////////////
0339 
0340 /**
0341  * \brief Load from XML
0342  */
0343 bool AbstractSimpleFilter::load(XmlStreamReader* reader, bool /*preview*/) {
0344     if (!readBasicAttributes(reader))
0345         return false;
0346 
0347     QXmlStreamAttributes attribs = reader->attributes();
0348     QString str = attribs.value(reader->namespaceUri().toString(), QStringLiteral("filter_name")).toString();
0349     if (str != QLatin1String(metaObject()->className())) {
0350         reader->raiseError(i18n("incompatible filter type"));
0351         return false;
0352     }
0353 
0354     // read child elements
0355     while (!reader->atEnd()) {
0356         reader->readNext();
0357 
0358         if (reader->isEndElement())
0359             break;
0360 
0361         if (reader->isStartElement()) {
0362             if (reader->name() == QLatin1String("comment")) {
0363                 if (!readCommentElement(reader))
0364                     return false;
0365             } else { // unknown element
0366                 reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
0367                 if (!reader->skipToEndElement())
0368                     return false;
0369             }
0370         }
0371     }
0372 
0373     return !reader->hasError();
0374 }
0375 
0376 ////////////////////////////////////////////////////////////////////////////////////////////////////
0377 //! \class SimpleFilterColumn
0378 ////////////////////////////////////////////////////////////////////////////////////////////////////
0379 
0380 AbstractColumn::ColumnMode SimpleFilterColumn::columnMode() const {
0381     return m_owner->columnMode();
0382 }
0383 
0384 QString SimpleFilterColumn::textAt(int row) const {
0385     return m_owner->textAt(row);
0386 }
0387 
0388 QDate SimpleFilterColumn::dateAt(int row) const {
0389     return m_owner->dateAt(row);
0390 }
0391 
0392 QTime SimpleFilterColumn::timeAt(int row) const {
0393     return m_owner->timeAt(row);
0394 }
0395 
0396 QDateTime SimpleFilterColumn::dateTimeAt(int row) const {
0397     return m_owner->dateTimeAt(row);
0398 }
0399 
0400 double SimpleFilterColumn::valueAt(int row) const {
0401     return m_owner->valueAt(row);
0402 }
0403 
0404 int SimpleFilterColumn::integerAt(int row) const {
0405     return m_owner->integerAt(row);
0406 }
0407 
0408 qint64 SimpleFilterColumn::bigIntAt(int row) const {
0409     return m_owner->bigIntAt(row);
0410 }