Logo Search packages:      
Sourcecode: scidavis version File versions  Download package

AbstractSimpleFilter.h

/***************************************************************************
    File                 : AbstractSimpleFilter.h
    Project              : SciDAVis
    --------------------------------------------------------------------
    Copyright            : (C) 2007 by Knut Franke, Tilman Benkert
    Email (use @ for *)  : knut.franke*gmx.de, thzs*gmx.net
    Description          : Simplified filter interface for filters with
                           only one output port.

 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *  This program is free software; you can redistribute it and/or modify   *
 *  it under the terms of the GNU General Public License as published by   *
 *  the Free Software Foundation; either version 2 of the License, or      *
 *  (at your option) any later version.                                    *
 *                                                                         *
 *  This program is distributed in the hope that it will be useful,        *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *  GNU General Public License for more details.                           *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the Free Software           *
 *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
 *   Boston, MA  02110-1301  USA                                           *
 *                                                                         *
 ***************************************************************************/
#ifndef ABSTRACT_SIMPLE_FILTER
#define ABSTRACT_SIMPLE_FILTER

#include "core/AbstractFilter.h"
#include "core/AbstractColumn.h"
#include "lib/IntervalAttribute.h"
#include "lib/XmlStreamReader.h"
#include <QUndoCommand>
#include <QXmlStreamWriter>

// forward declaration - class follows
class SimpleFilterColumn;

/**
 * \brief Simplified filter interface for filters with only one output port.
 *
 * This class is only meant to simplify implementation of a restricted subtype of filter.
 * It should not be instantiated directly. You should always either derive from
 * AbstractFilter or (if necessary) provide an actual (non-abstract) implementation.
 *
 * The trick here is that, in a sense, the filter is its own output port. This means you
 * can implement a complete filter in only one class and don't have to coordinate data
 * transfer between a filter class and a data source class.
 * Additionaly, AbstractSimpleFilter offers some useful convenience methods which make writing
 * filters as painless as possible.
 *
 * For the data type of the output, all types supported by AbstractColumn (currently double, QString and
 * QDateTime) are supported.
 *
 * \section tutorial1 Tutorial, Step 1
 * The simplest filter you can write assumes there's also only one input port and rows on the
 * input correspond 1:1 to rows in the output. All you need to specify is what data type you
 * want to have (in this example double) on the input port and how to compute the output values:
 *
 * \code
 * 01 #include "AbstractSimpleFilter.h"
 * 02 class TutorialFilter1 : public AbstractSimpleFilter
 * 03 {
 * 04 protected:
 * 05       virtual bool inputAcceptable(int, AbstractColumn *source) {
 * 06             return (source->dataType() == SciDAVis::TypeDouble);
 * 07       }
 * 08 public:
 * 09       virtual SciDAVis::ColumnDataType dataType() const { return SciDAVis::TypeDouble; }
 * 10
 * 11       virtual double valueAt(int row) const {
 * 12             if (!d_inputs.value(0)) return 0.0;
 * 13             double input_value = d_inputs.value(0)->valueAt(row);
 * 14             return input_value * input_value;
 * 15       }
 * 16 };
 * \endcode
 *
 * This filter reads an input value (line 13) and returns its square (line 14).
 * Reimplementing inputAcceptable() makes sure that the data source really is of type
 * double (lines 5 to 7). Otherwise, the source will be rejected by AbstractFilter::input().
 * The output type is repoted by reimplementing dataType() (line 09).
 * Before you actually use d_inputs.value(0), make sure that the input port has
 * been connected to a data source (line 12).
 * Otherwise line 13 would result in a crash. That's it, we've already written a
 * fully-functional filter!
 *
 * Equivalently, you can write 1:1-filters for QString or QDateTime inputs by checking for
 * SciDAVis::TypeQString or SciDAVis::TypeQDateTime in line 6. You would then use
 * AbstractColumn::textAt(row) or AbstractColumn::dateTimeAt(row) in line 13 to access the input data.
 * For QString output, you need to implement AbstractColumn::textAt(row). 
 * For QDateTime output, you have to implement three methods:
 * \code
 * virtual QDateTime dateTimeAt(int row) const;
 * virtual QDate dateAt(int row) const;
 * virtual QTime timeAt(int row) const;
 * \endcode
 *
 * \section tutorial2 Tutorial, Step 2
 * Now for something slightly more interesting: a filter that uses only every second row of its
 * input. We no longer have a 1:1 correspondence between input and output rows, so we'll have
 * to do a bit more work in order to have everything come out as expected.
 * We'll use double-typed input and output again:
 * \code
 * 01 #include "AbstractSimpleFilter.h"
 * 02 class TutorialFilter2 : public AbstractSimpleFilter
 * 03 {
 * 04 protected:
 * 05       virtual bool inputAcceptable(int, AbstractColumn *source) {
 * 06             return (source->dataType() == SciDAVis::TypeDouble);
 * 07       }
 * 08 public:
 * 09       virtual SciDAVis::ColumnDataType dataType() const { return SciDAVis::TypeDouble; }
 * \endcode
 * Even rows (including row 0) get dropped, odd rows are renumbered:
 * \code
 * 10 public:
 * 11       virtual double valueAt(int row) const {
 * 12       if (!d_inputs.value(0)) return 0.0;
 * 13       return d_inputs.value(0)->valueAt(2*row + 1);
 * 14       }
 * \endcode
 */
00128 class AbstractSimpleFilter : public AbstractFilter
{
      Q_OBJECT

      public:
            //! Ctor
            AbstractSimpleFilter();
            //! Default to one input port.
00136             virtual int inputCount() const { return 1; }
            //! We manage only one output port (don't override unless you really know what you are doing).
00138             virtual int outputCount() const { return 1; }
            //! Return a pointer to #d_output_column on port 0 (don't override unless you really know what you are doing).
            virtual AbstractColumn* output(int port);
            virtual const AbstractColumn * output(int port) const;
            //! Copy plot designation of input port 0.
00143             virtual SciDAVis::PlotDesignation plotDesignation() const {
                  return d_inputs.value(0) ?
                        d_inputs.at(0)->plotDesignation() :
                        SciDAVis::noDesignation;
            }
            //! Return the data type of the input
00149             virtual SciDAVis::ColumnDataType dataType() const
            {
                  // calling this function while d_input is empty is a sign of very bad code
                  // nevertheless it will return some rather meaningless value to
                  // avoid crashes
                  return d_inputs.value(0) ? d_inputs.at(0)->dataType() : SciDAVis::TypeQString;
            }
            //! Return the column mode
            /**
             * This function is most used by tables but can also be used
             * by plots. The column mode specifies how to interpret 
             * the values in the column additional to the data type.
             */ 
00162             virtual SciDAVis::ColumnMode columnMode() const
            {
                  // calling this function while d_input is empty is a sign of very bad code
                  // nevertheless it will return some rather meaningless value to
                  // avoid crashes
                  return d_inputs.value(0) ? d_inputs.at(0)->columnMode() : SciDAVis::Text;
            }
            //! Return the content of row 'row'.
            /**
             * Use this only when dataType() is QString
             */
00173             virtual QString textAt(int row) const
            {
                  return d_inputs.value(0) ? d_inputs.at(0)->textAt(row) : QString();
            }
            //! Return the date part of row 'row'
            /**
             * Use this only when dataType() is QDateTime
             */
00181             virtual QDate dateAt(int row) const
            {
                  return d_inputs.value(0) ? d_inputs.at(0)->dateAt(row) : QDate();
            }
            //! Return the time part of row 'row'
            /**
             * Use this only when dataType() is QDateTime
             */
00189             virtual QTime timeAt(int row) const
            {
                  return d_inputs.value(0) ? d_inputs.at(0)->timeAt(row) : QTime();
            }
            //! Set the content of row 'row'
            /**
             * Use this only when dataType() is QDateTime
             */
00197             virtual QDateTime dateTimeAt(int row) const
            {
                  return d_inputs.value(0) ? d_inputs.at(0)->dateTimeAt(row) : QDateTime();
            }
            //! Return the double value in row 'row'
            /**
             * Use this only when dataType() is double
             */
00205             virtual double valueAt(int row) const
            {
                  return d_inputs.value(0) ? d_inputs.at(0)->valueAt(row) : 0.0;
            }

            //!\name assuming a 1:1 correspondence between input and output rows
            //@{
            virtual int rowCount() const {
                  return d_inputs.value(0) ? d_inputs.at(0)->rowCount() : 0;
            }
            virtual QList< Interval<int> > dependentRows(Interval<int> input_range) const { return QList< Interval<int> >() << input_range; }
            //@}

            //!\name Masking
            //@{
            //! Return whether a certain row is masked
00221             virtual bool isMasked(int row) const { return d_masking.isSet(row); }
            //! Return whether a certain interval of rows rows is fully masked
00223             virtual bool isMasked(Interval<int> i) const { return d_masking.isSet(i); }
            //! Return all intervals of masked rows
00225             virtual QList< Interval<int> > maskedIntervals() const { return d_masking.intervals(); }
            //! Clear all masking information
            virtual void clearMasks();
            //! Set an interval masked
            /**
             * \param i the interval
             * \param mask true: mask, false: unmask
             */ 
            virtual void setMasked(Interval<int> i, bool mask = true);
            //! Overloaded function for convenience
00235             virtual void setMasked(int row, bool mask = true) { setMasked(Interval<int>(row,row), mask); }
            //@}

            //! Return whether a certain row contains an invalid value   
00239             virtual bool isInvalid(int row) const { return d_inputs.value(0) ? d_inputs.at(0)->isInvalid(row) : false; }
            //! Return whether a certain interval of rows contains only invalid values     
00241             virtual bool isInvalid(Interval<int> i) const { return d_inputs.value(0) ? d_inputs.at(0)->isInvalid(i) : false; }
            //! Return all intervals of invalid rows
00243             virtual QList< Interval<int> > invalidIntervals() const 
            {
                  return d_inputs.value(0) ? d_inputs.at(0)->invalidIntervals() : QList< Interval<int> >(); 
            }

            //! \name XML related functions
            //@{
            //! Save to XML
            virtual void save(QXmlStreamWriter * writer) const;
            //! Load from XML
            virtual bool load(XmlStreamReader * reader);
            //! Override this in derived classes if they have other attributes than filter_name
00255             virtual void writeExtraAttributes(QXmlStreamWriter * writer) const { Q_UNUSED(writer) }
            //@}

      protected:
            IntervalAttribute<bool> d_masking;

            //!\name signal handlers
            //@{
            virtual void inputPlotDesignationAboutToChange(const AbstractColumn*);
            virtual void inputPlotDesignationChanged(const AbstractColumn*);
            virtual void inputModeAboutToChange(const AbstractColumn*);
            virtual void inputModeChanged(const AbstractColumn*);
            virtual void inputDataAboutToChange(const AbstractColumn*);
            virtual void inputDataChanged(const AbstractColumn*);

            virtual void inputRowsAboutToBeInserted(const AbstractColumn * source, int before, int count);
            virtual void inputRowsInserted(const AbstractColumn * source, int before, int count);
            virtual void inputRowsAboutToBeRemoved(const AbstractColumn * source, int first, int count);
            virtual void inputRowsRemoved(const AbstractColumn * source, int first, int count);
            //@}
            
            SimpleFilterColumn *d_output_column;
};

class SimpleFilterColumn : public AbstractColumn
{
      Q_OBJECT

      public:
            SimpleFilterColumn(AbstractSimpleFilter *owner) : AbstractColumn(owner->name()), d_owner(owner) {}

            virtual SciDAVis::ColumnDataType dataType() const { return d_owner->dataType(); }
            virtual SciDAVis::ColumnMode columnMode() const { return d_owner->columnMode(); }
            virtual int rowCount() const { return d_owner->rowCount(); }
            virtual SciDAVis::PlotDesignation plotDesignation() const { return d_owner->plotDesignation(); }
            virtual bool isInvalid(int row) const { return d_owner->isInvalid(row); }
            virtual bool isInvalid(Interval<int> i) const { return d_owner->isInvalid(i); }
            virtual QList< Interval<int> > invalidIntervals() const { return d_owner->invalidIntervals(); }
            virtual bool isMasked(int row) const { return d_owner->isMasked(row); }
            virtual bool isMasked(Interval<int> i) const { return d_owner->isMasked(i); }
            virtual QList< Interval<int> > maskedIntervals() const { return d_owner->maskedIntervals(); }
            virtual void clearMasks() { d_owner->clearMasks(); }
            virtual QString textAt(int row) const { return d_owner->textAt(row); }
            virtual QDate dateAt(int row) const { return d_owner->dateAt(row); }
            virtual QTime timeAt(int row) const { return d_owner->timeAt(row); }
            virtual QDateTime dateTimeAt(int row) const { return d_owner->dateTimeAt(row); }
            virtual double valueAt(int row) const { return d_owner->valueAt(row); }

      private:
            AbstractSimpleFilter *d_owner;

      friend class AbstractSimpleFilter;
};

#endif // ifndef ABSTRACT_SIMPLE_FILTER


Generated by  Doxygen 1.6.0   Back to index