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