labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

AbstractSimpleFilter.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : AbstractSimpleFilter.cpp
3  Project : AbstractColumn
4  --------------------------------------------------------------------
5  Copyright : (C) 2007,2008 by Knut Franke, Tilman Benkert
6  Email (use @ for *) : knut.franke*gmx.de, thzs*gmx.net
7  Copyright : (C) 2020 Stefan Gerlach (stefan.gerlach@uni.kn)
8  Description : Simplified filter interface for filters with
9  only one output port.
10 
11  ***************************************************************************/
12 
13 /***************************************************************************
14  * *
15  * This program is free software; you can redistribute it and/or modify *
16  * it under the terms of the GNU General Public License as published by *
17  * the Free Software Foundation; either version 2 of the License, or *
18  * (at your option) any later version. *
19  * *
20  * This program is distributed in the hope that it will be useful, *
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
23  * GNU General Public License for more details. *
24  * *
25  * You should have received a copy of the GNU General Public License *
26  * along with this program; if not, write to the Free Software *
27  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
28  * Boston, MA 02110-1301 USA *
29  * *
30  ***************************************************************************/
31 
32 #include "AbstractSimpleFilter.h"
34 
35 #include <QDateTime>
36 #include <QDate>
37 #include <QTime>
38 
39 #include <KLocalizedString>
40 
41 /**
42  * \class AbstractSimpleFilter
43  * \brief Simplified filter interface for filters with only one output port.
44  *
45  * This class is only meant to simplify implementation of a restricted subtype of filter.
46  * It should not be instantiated directly. You should always either derive from
47  * AbstractFilter or (if necessary) provide an actual (non-abstract) implementation.
48  *
49  * The trick here is that, in a sense, the filter is its own output port. This means you
50  * can implement a complete filter in only one class and don't have to coordinate data
51  * transfer between a filter class and a data source class.
52  * Additionally, AbstractSimpleFilter offers some useful convenience methods which make writing
53  * filters as painless as possible.
54  *
55  * For the data type of the output, all types supported by AbstractColumn (currently double, QString and
56  * QDateTime) are supported.
57  *
58  * \section tutorial1 Tutorial, Step 1
59  * The simplest filter you can write assumes there's also only one input port and rows on the
60  * input correspond 1:1 to rows in the output. All you need to specify is what data type you
61  * want to have (in this example double) on the input port and how to compute the output values:
62  *
63  * \code
64  * 01 #include "AbstractSimpleFilter.h"
65  * 02 class TutorialFilter1 : public AbstractSimpleFilter
66  * 03 {
67  * 04 protected:
68  * 05 virtual bool inputAcceptable(int, AbstractColumn *source) {
69  * 06 return (source->columnMode() == AbstractColumn::Numeric);
70  * 07 }
71  * 08 public:
72  * 09 virtual AbstractColumn::ColumnMode columnMode() const { return AbstractColumn::Numeric; }
73  * 10
74  * 11 virtual double valueAt(int row) const {
75  * 12 if (!m_inputs.value(0)) return 0.0;
76  * 13 double input_value = m_inputs.value(0)->valueAt(row);
77  * 14 return input_value * input_value;
78  * 15 }
79  * 16 };
80  * \endcode
81  *
82  * This filter reads an input value (line 13) and returns its square (line 14).
83  * Reimplementing inputAcceptable() makes sure that the data source really is of type
84  * double (lines 5 to 7). Otherwise, the source will be rejected by AbstractFilter::input().
85  * The output type is reported by reimplementing columnMode() (line 09).
86  * Before you actually use m_inputs.value(0), make sure that the input port has
87  * been connected to a data source (line 12).
88  * Otherwise line 13 would result in a crash. That's it, we've already written a
89  * fully-functional filter!
90  *
91  * Equivalently, you can write 1:1-filters for QString or QDateTime inputs by checking for
92  * AbstractColumn::TypeQString or AbstractColumn::TypeQDateTime in line 6. You would then use
93  * AbstractColumn::textAt(row) or AbstractColumn::dateTimeAt(row) in line 13 to access the input data.
94  * For QString output, you need to implement AbstractColumn::textAt(row).
95  * For QDateTime output, you have to implement three methods:
96  * \code
97  * virtual QDateTime dateTimeAt(int row) const;
98  * virtual QDate dateAt(int row) const;
99  * virtual QTime timeAt(int row) const;
100  * \endcode
101  *
102  * \section tutorial2 Tutorial, Step 2
103  * Now for something slightly more interesting: a filter that uses only every second row of its
104  * input. We no longer have a 1:1 correspondence between input and output rows, so we'll have
105  * to do a bit more work in order to have everything come out as expected.
106  * We'll use double-typed input and output again:
107  * \code
108  * 01 #include "AbstractSimpleFilter.h"
109  * 02 class TutorialFilter2 : public AbstractSimpleFilter
110  * 03 {
111  * 04 protected:
112  * 05 virtual bool inputAcceptable(int, AbstractColumn *source) {
113  * 06 return (source->columnMode() == AbstractColumn::Numeric);
114  * 07 }
115  * 08 public:
116  * 09 virtual AbstractColumn::ColumnMode columnMode() const { return AbstractColumn::Numeric; }
117  * \endcode
118  * Even rows (including row 0) get dropped, odd rows are renumbered:
119  * \code
120  * 10 public:
121  * 11 virtual double valueAt(int row) const {
122  * 12 if (!m_inputs.value(0)) return 0.0;
123  * 13 return m_inputs.value(0)->valueAt(2*row + 1);
124  * 14 }
125  * \endcode
126  */
127 
128 // TODO: should simple filters have a name argument?
129 /**
130  * \brief Ctor
131  */
133  : AbstractFilter("SimpleFilter"), m_output_column(new SimpleFilterColumn(this)) {
135 }
136 
137 /**
138  * \brief Default to one input port.
139  */
141  return 1;
142 }
143 
144 /**
145  * \brief We manage only one output port (don't override unless you really know what you are doing).
146  */
148  return 1;
149 }
150 
151 /**
152  * \brief Copy plot designation of input port 0.
153  */
155  return m_inputs.value(0) ? m_inputs.at(0)->plotDesignation() : AbstractColumn::PlotDesignation::NoDesignation;
156 }
157 
158 /**
159  * \brief Copy plot designation string of input port 0.
160  */
162  return m_inputs.value(0) ? m_inputs.at(0)->plotDesignationString() : QString("");
163 }
164 
165 /**
166  * \brief Return the column mode
167  *
168  * This function is most used by tables but can also be used
169  * by plots. The column mode specifies how to interpret
170  * the values in the column additional to the data type.
171  */
173  // calling this function while m_input is empty is a sign of very bad code
174  // nevertheless it will return some rather meaningless value to
175  // avoid crashes
176  return m_inputs.value(0) ? m_inputs.at(0)->columnMode() : AbstractColumn::ColumnMode::Text;
177 }
178 
179 /**
180  * \brief Return the content of row 'row'.
181  *
182  * Use this only when columnMode() is Text
183  */
184 QString AbstractSimpleFilter::textAt(int row) const {
185  return m_inputs.value(0) ? m_inputs.at(0)->textAt(row) : QString();
186 }
187 
188 /**
189  * \brief Return the date part of row 'row'
190  *
191  * Use this only when columnMode() is DateTime, Month or Day
192  */
193 QDate AbstractSimpleFilter::dateAt(int row) const {
194  return m_inputs.value(0) ? m_inputs.at(0)->dateAt(row) : QDate();
195 }
196 
197 /**
198  * \brief Return the time part of row 'row'
199  *
200  * Use this only when columnMode() is DateTime, Month or Day
201  */
202 QTime AbstractSimpleFilter::timeAt(int row) const {
203  return m_inputs.value(0) ? m_inputs.at(0)->timeAt(row) : QTime();
204 }
205 
206 /**
207  * \brief Set the content of row 'row'
208  *
209  * Use this only when columnMode() is DateTime, Month or Day
210  */
211 QDateTime AbstractSimpleFilter::dateTimeAt(int row) const {
212  return m_inputs.value(0) ? m_inputs.at(0)->dateTimeAt(row) : QDateTime();
213 }
214 
215 /**
216  * \brief Return the double value in row 'row'
217  *
218  * Use this only when columnMode() is Numeric
219  */
220 double AbstractSimpleFilter::valueAt(int row) const {
221  return m_inputs.value(0) ? m_inputs.at(0)->valueAt(row) : 0.0;
222 }
223 
224 /**
225  * \brief Return the integer value in row 'row'
226  *
227  * Use this only when columnMode() is Integer
228  */
230  return m_inputs.value(0) ? m_inputs.at(0)->integerAt(row) : 0;
231 }
232 
233 /**
234  * \brief Return the bigint value in row 'row'
235  *
236  * Use this only when columnMode() is BigInt
237  */
238 qint64 AbstractSimpleFilter::bigIntAt(int row) const {
239  return m_inputs.value(0) ? m_inputs.at(0)->bigIntAt(row) : 0;
240 }
241 
242 /**
243  * \brief Number of output rows == number of input rows
244  *
245  * ... unless overridden in a subclass.
246  */
248  return m_inputs.value(0) ? m_inputs.at(0)->rowCount() : 0;
249 }
250 
251 /**
252  * \brief Number of output rows == number of input rows
253  *
254  * ... unless overridden in a subclass.
255  */
257  return m_inputs.value(0) ? m_inputs.at(0)->availableRowCount() : 0;
258 }
259 
260 /**
261  * \brief Rows that will change when the given input interval changes.
262  *
263  * This implementation assumes a 1:1 correspondence between input and output rows, but can be
264  * overridden in subclasses.
265  */
267  return QList< Interval<int> >() << inputRange;
268 }
269 
270 ////////////////////////////////////////////////////////////////////////////////////////////////////
271 //!\name signal handlers
272 //@{
273 ////////////////////////////////////////////////////////////////////////////////////////////////////
274 
277 }
278 
281 }
282 
285 }
286 
289 }
290 
293 }
294 
297 }
298 
299 void AbstractSimpleFilter::inputRowsAboutToBeInserted(const AbstractColumn * source, int before, int count) {
300  Q_UNUSED(source);
301  Q_UNUSED(count);
302  foreach (const Interval<int>& output_range, dependentRows(Interval<int>(before, before)))
303  emit m_output_column->rowsAboutToBeInserted(m_output_column, output_range.start(), output_range.size());
304 }
305 
306 void AbstractSimpleFilter::inputRowsInserted(const AbstractColumn * source, int before, int count) {
307  Q_UNUSED(source);
308  Q_UNUSED(count);
309  foreach (const Interval<int>& output_range, dependentRows(Interval<int>(before, before)))
310  emit m_output_column->rowsInserted(m_output_column, output_range.start(), output_range.size());
311 }
312 
313 void AbstractSimpleFilter::inputRowsAboutToBeRemoved(const AbstractColumn * source, int first, int count) {
314  Q_UNUSED(source);
315  foreach (const Interval<int>& output_range, dependentRows(Interval<int>(first, first+count-1)))
316  emit m_output_column->rowsAboutToBeRemoved(m_output_column, output_range.start(), output_range.size());
317 }
318 
319 void AbstractSimpleFilter::inputRowsRemoved(const AbstractColumn * source, int first, int count) {
320  Q_UNUSED(source);
321  foreach (const Interval<int>& output_range, dependentRows(Interval<int>(first, first+count-1)))
322  emit m_output_column->rowsRemoved(m_output_column, output_range.start(), output_range.size());
323 }
324 
325 ////////////////////////////////////////////////////////////////////////////////////////////////////
326 //@}
327 ////////////////////////////////////////////////////////////////////////////////////////////////////
328 
329 /**
330  * \brief Return a pointer to #m_output_column on port 0 (don't override unless you really know what you are doing).
331  */
333  return port == 0 ? static_cast<AbstractColumn*>(m_output_column) : nullptr;
334 }
335 
337  return port == 0 ? static_cast<const AbstractColumn*>(m_output_column) : nullptr;
338 }
339 
340 ////////////////////////////////////////////////////////////////////////////////////////////////////
341 //! \name serialize/deserialize
342 //@{
343 ////////////////////////////////////////////////////////////////////////////////////////////////////
344 
345 /**
346  * \brief Save to XML
347  */
348 void AbstractSimpleFilter::save(QXmlStreamWriter * writer) const {
349  writer->writeStartElement("simple_filter");
350  writeBasicAttributes(writer);
351  writeExtraAttributes(writer);
352  writer->writeAttribute("filter_name", metaObject()->className());
353  writeCommentElement(writer);
354  writer->writeEndElement();
355 }
356 
357 /**
358  * \brief Override this in derived classes if they have other attributes than filter_name
359  */
360 void AbstractSimpleFilter::writeExtraAttributes(QXmlStreamWriter * writer) const {
361  Q_UNUSED(writer)
362 }
363 
364 ////////////////////////////////////////////////////////////////////////////////////////////////////
365 //@}
366 ////////////////////////////////////////////////////////////////////////////////////////////////////
367 
368 /**
369  * \brief Load from XML
370  */
371 bool AbstractSimpleFilter::load(XmlStreamReader* reader, bool preview) {
372  Q_UNUSED(preview); //TODO
373 
374  if (!readBasicAttributes(reader))
375  return false;
376 
377  QXmlStreamAttributes attribs = reader->attributes();
378  QString str = attribs.value(reader->namespaceUri().toString(), "filter_name").toString();
379  if (str != metaObject()->className()) {
380  reader->raiseError(i18n("incompatible filter type"));
381  return false;
382  }
383 
384  // read child elements
385  while (!reader->atEnd()) {
386  reader->readNext();
387 
388  if (reader->isEndElement()) break;
389 
390  if (reader->isStartElement()) {
391  if (reader->name() == "comment") {
392  if (!readCommentElement(reader)) return false;
393  } else { // unknown element
394  reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
395  if (!reader->skipToEndElement()) return false;
396  }
397  }
398  }
399 
400  return !reader->hasError();
401 }
402 
403 ////////////////////////////////////////////////////////////////////////////////////////////////////
404 //! \class SimpleFilterColumn
405 ////////////////////////////////////////////////////////////////////////////////////////////////////
406 
408  return m_owner->columnMode();
409 }
410 
411 QString SimpleFilterColumn::textAt(int row) const {
412  return m_owner->textAt(row);
413 }
414 
415 QDate SimpleFilterColumn::dateAt(int row) const {
416  return m_owner->dateAt(row);
417 }
418 
419 QTime SimpleFilterColumn::timeAt(int row) const {
420  return m_owner->timeAt(row);
421 }
422 
423 QDateTime SimpleFilterColumn::dateTimeAt(int row) const {
424  return m_owner->dateTimeAt(row);
425 }
426 
427 double SimpleFilterColumn::valueAt(int row) const {
428  return m_owner->valueAt(row);
429 }
430 
431 int SimpleFilterColumn::integerAt(int row) const {
432  return m_owner->integerAt(row);
433 }
434 
435 qint64 SimpleFilterColumn::bigIntAt(int row) const {
436  return m_owner->bigIntAt(row);
437 }
bool readCommentElement(XmlStreamReader *)
Load comment from an XML element.
void addChildFast(AbstractAspect *)
Add the given Aspect to my list of children without any checks and without putting this step onto the...
void writeBasicAttributes(QXmlStreamWriter *) const
Save name and creation time to XML.
bool readBasicAttributes(XmlStreamReader *)
Load name and creation time from XML.
void writeCommentElement(QXmlStreamWriter *) const
Save the comment to XML.
Interface definition for data with column logic.
void plotDesignationAboutToChange(const AbstractColumn *source)
Column plot designation will be changed.
void rowsRemoved(const AbstractColumn *source, int first, int count)
Rows have been deleted.
void plotDesignationChanged(const AbstractColumn *source)
Column plot designation changed.
void rowsInserted(const AbstractColumn *source, int before, int count)
Rows have been inserted.
void dataChanged(const AbstractColumn *source)
Data of the column has changed.
void rowsAboutToBeRemoved(const AbstractColumn *source, int first, int count)
Rows will be deleted.
void dataAboutToChange(const AbstractColumn *source)
Data of the column will be changed.
void rowsAboutToBeInserted(const AbstractColumn *source, int before, int count)
Rows will be inserted.
Base class for all analysis operations.
QVector< const AbstractColumn * > m_inputs
The data sources connected to my input ports.
virtual QString textAt(int row) const
Return the content of row 'row'.
int outputCount() const override
We manage only one output port (don't override unless you really know what you are doing).
virtual AbstractColumn::ColumnMode columnMode() const
Return the column mode.
void inputDataChanged(const AbstractColumn *) override
The data of an input has changed.
void inputRowsRemoved(const AbstractColumn *source, int first, int count) override
virtual void writeExtraAttributes(QXmlStreamWriter *) const
Override this in derived classes if they have other attributes than filter_name.
int inputCount() const override
Default to one input port.
virtual QString plotDesignationString() const
Copy plot designation string of input port 0.
void inputPlotDesignationChanged(const AbstractColumn *) override
The plot designation of an input changed.
virtual qint64 bigIntAt(int row) const
Return the bigint value in row 'row'.
void inputRowsAboutToBeRemoved(const AbstractColumn *source, int first, int count) override
void inputRowsAboutToBeInserted(const AbstractColumn *source, int before, int count) override
void inputModeChanged(const AbstractColumn *) override
The display mode and possibly the data type has changed.
SimpleFilterColumn * m_output_column
virtual QDateTime dateTimeAt(int row) const
Set the content of row 'row'.
void inputDataAboutToChange(const AbstractColumn *) override
The data of an input is about to change.
virtual int integerAt(int row) const
Return the integer value in row 'row'.
virtual int rowCount() const
Number of output rows == number of input rows.
void save(QXmlStreamWriter *) const override
Save to XML.
virtual QTime timeAt(int row) const
Return the time part of row 'row'.
virtual int availableRowCount() const
Number of output rows == number of input rows.
bool load(XmlStreamReader *, bool preview) override
Load from XML.
void inputPlotDesignationAboutToChange(const AbstractColumn *) override
The plot designation of an input is about to change.
virtual double valueAt(int row) const
Return the double value in row 'row'.
virtual QList< Interval< int > > dependentRows(const Interval< int > &inputRange) const
Rows that will change when the given input interval changes.
AbstractColumn * output(int port) override
Return a pointer to m_output_column on port 0 (don't override unless you really know what you are doi...
virtual AbstractColumn::PlotDesignation plotDesignation() const
Copy plot designation of input port 0.
void inputRowsInserted(const AbstractColumn *source, int before, int count) override
void inputModeAboutToChange(const AbstractColumn *) override
The display mode and possibly the data type of an input is about to change.
virtual QDate dateAt(int row) const
Return the date part of row 'row'.
T start() const
Definition: Interval.h:50
Auxiliary class for interval based data.
Definition: Interval.h:212
T size() const
Definition: Interval.h:217
QDateTime dateTimeAt(int row) const override
Return the QDateTime in row 'row'.
AbstractColumn::ColumnMode columnMode() const override
Return the column mode.
QTime timeAt(int row) const override
Return the time part of row 'row'.
AbstractSimpleFilter * m_owner
double valueAt(int row) const override
Return the double value in row 'row'.
QDate dateAt(int row) const override
Return the date part of row 'row'.
int integerAt(int row) const override
Return the integer value in row 'row'.
qint64 bigIntAt(int row) const override
Return the bigint value in row 'row'.
QString textAt(int row) const override
Return the content of row 'row'.
XML stream parser that supports errors as well as warnings. This class also adds line and column numb...
void raiseWarning(const QString &)
void raiseError(const QString &)
#define i18n(m)
Definition: nsl_common.h:38