"Fossies" - the Fresh Open Source Software Archive

Member "labplot-2.7.0/src/backend/core/AbstractSimpleFilter.cpp" (24 Oct 2019, 15315 Bytes) of package /linux/privat/labplot-2.7.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbstractSimpleFilter.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.6.0_vs_2.7.0.

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