File indexing completed on 2024-05-19 15:01:18

0001 /***************************************************************************
0002     File                 : AbstractColumn.cpp
0003     Project              : LabPlot
0004     Description          : Interface definition for data with column logic
0005     --------------------------------------------------------------------
0006     Copyright            : (C) 2007,2008 Tilman Benkert (thzs@gmx.net)
0007     Copyright            : (C) 2017-2020 Stefan Gerlach (stefan.gerlach@uni.kn)
0008 
0009  ***************************************************************************/
0010 
0011 /***************************************************************************
0012  *                                                                         *
0013  *  This program is free software; you can redistribute it and/or modify   *
0014  *  it under the terms of the GNU General Public License as published by   *
0015  *  the Free Software Foundation; either version 2 of the License, or      *
0016  *  (at your option) any later version.                                    *
0017  *                                                                         *
0018  *  This program is distributed in the hope that it will be useful,        *
0019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
0020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
0021  *  GNU General Public License for more details.                           *
0022  *                                                                         *
0023  *   You should have received a copy of the GNU General Public License     *
0024  *   along with this program; if not, write to the Free Software           *
0025  *   Foundation, Inc., 51 Franklin Street, Fifth Floor,                    *
0026  *   Boston, MA  02110-1301  USA                                           *
0027  *                                                                         *
0028  ***************************************************************************/
0029 
0030 #include "backend/core/AbstractColumn.h"
0031 #include "backend/core/AbstractColumnPrivate.h"
0032 #include "backend/core/abstractcolumncommands.h"
0033 #include "backend/lib/XmlStreamReader.h"
0034 #include "backend/lib/SignallingUndoCommand.h"
0035 
0036 #include <QDateTime>
0037 #include <QIcon>
0038 #include <KLocalizedString>
0039 
0040 /**
0041  * \class AbstractColumn
0042  * \brief Interface definition for data with column logic
0043  *
0044  * This is an abstract base class for column-based data,
0045  * i.e. mathematically a vector or technically a 1D array or list.
0046  * It only defines the interface but has no data members itself.
0047  *
0048  * Classes derived from this are typically table columns or outputs
0049  * of filters which can be chained between table columns and plots.
0050  * From the point of view of the plot functions there will be no difference
0051  * between a table column and a filter output since both use this interface.
0052  *
0053  * Classes derived from this will either store a
0054  * vector with entries of one certain data type, e.g. double, QString,
0055  * QDateTime, or generate such values on demand. To determine the data
0056  * type of a class derived from this, use the columnMode() function.
0057  * AbstractColumn defines all access functions for all supported data
0058  * types but only those corresponding to the return value of columnMode()
0059  * will return a meaningful value. Calling functions not belonging to
0060  * the data type of the column is safe, but will do nothing (writing
0061  * function) or return some default value (reading functions).
0062  *
0063  * This class also defines all signals which indicate a data change.
0064  * Any class whose output values are subject to change over time must emit
0065  * the according signals. These signals notify any object working with the
0066  * column before and after a change of the column.
0067  * In some cases it will be necessary for a class using
0068  * the column to connect aboutToBeDestroyed(), to react
0069  * to a column's deletion, e.g. a filter's reaction to a
0070  * table deletion.
0071  *
0072  * All writing functions have a "do nothing" standard implementation to
0073  * make deriving a read-only class very easy without bothering about the
0074  * writing interface.
0075  */
0076 
0077 /**
0078  * \brief Ctor
0079  *
0080  * \param name the column name (= aspect name)
0081  */
0082 AbstractColumn::AbstractColumn(const QString &name, AspectType type)
0083     : AbstractAspect(name, type), d( new AbstractColumnPrivate(this) ) {
0084 }
0085 
0086 AbstractColumn::~AbstractColumn() {
0087     emit aboutToBeDestroyed(this);
0088     delete d;
0089 }
0090 
0091 QStringList AbstractColumn::dateFormats() {
0092     static const QStringList dates{"yyyy-MM-dd", "yyyy/MM/dd", "dd/MM/yyyy",
0093         "dd/MM/yy", "dd.MM.yyyy", "dd.MM.yy", "MM/yyyy", "dd.MM.", "yyyyMMdd"};
0094 
0095     return dates;
0096 }
0097 
0098 QStringList AbstractColumn::timeFormats() {
0099     static const QStringList times{"hh", "hh ap", "hh:mm", "hh:mm ap",
0100         "hh:mm:ss", "hh:mm:ss.zzz", "hh:mm:ss:zzz", "mm:ss.zzz", "hhmmss"};
0101 
0102     return times;
0103 }
0104 
0105 QStringList AbstractColumn::dateTimeFormats() {
0106     // any combination of date and times
0107     QStringList dateTimes = dateFormats();
0108     for (const auto& t : timeFormats())
0109         dateTimes << t;
0110     for (const auto& d : dateFormats())
0111         for (const auto& t : timeFormats())
0112             dateTimes << d + ' ' + t;
0113 
0114     return dateTimes;
0115 }
0116 
0117 /**
0118  * \brief Convenience method for mode-dependent icon
0119  */
0120 QIcon AbstractColumn::iconForMode(ColumnMode mode) {
0121     switch (mode) {
0122     case ColumnMode::Numeric:
0123     case ColumnMode::Integer:
0124     case ColumnMode::BigInt:
0125         break;
0126     case ColumnMode::Text:
0127         return QIcon::fromTheme("draw-text");
0128     case ColumnMode::DateTime:
0129     case ColumnMode::Month:
0130     case ColumnMode::Day:
0131         return QIcon::fromTheme("chronometer");
0132     }
0133 
0134     return QIcon::fromTheme("x-shape-text");
0135 }
0136 
0137 /**
0138  * \fn bool AbstractColumn::isReadOnly() const
0139  * \brief Return whether the object is read-only
0140  */
0141 
0142 /**
0143  * \fn AbstractColumn::ColumnMode AbstractColumn::columnMode() const
0144  * \brief Return the column mode
0145  *
0146  * This function is most used by tables but can also be used
0147  * by plots. The column mode specifies how to interpret
0148  * the values in the column additional to the data type.
0149  */
0150 
0151 /**
0152  * \brief Set the column mode
0153  *
0154  * This sets the column mode and, if
0155  * necessary, converts it to another datatype.
0156  */
0157 void AbstractColumn::setColumnMode(AbstractColumn::ColumnMode) {}
0158 
0159 /**
0160  * \brief Copy another column of the same type
0161  *
0162  * This function will return false if the data type
0163  * of 'other' is not the same as the type of 'this'.
0164  * Use a filter to convert a column to another type.
0165  */
0166 bool AbstractColumn::copy(const AbstractColumn *other) {
0167     Q_UNUSED(other)
0168     return false;
0169 }
0170 
0171 /**
0172  * \brief Copies part of another column of the same type
0173  *
0174  * This function will return false if the data type
0175  * of 'other' is not the same as the type of 'this'.
0176  * \param source pointer to the column to copy
0177  * \param source_start first row to copy in the column to copy
0178  * \param destination_start first row to copy in
0179  * \param num_rows the number of rows to copy
0180  */
0181 bool AbstractColumn::copy(const AbstractColumn *source, int source_start, int destination_start, int num_rows) {
0182     Q_UNUSED(source)
0183     Q_UNUSED(source_start)
0184     Q_UNUSED(destination_start)
0185     Q_UNUSED(num_rows)
0186     return false;
0187 }
0188 
0189 /**
0190  * \fn int AbstractColumn::rowCount() const
0191  * \brief Return the data vector size
0192  */
0193 
0194 /**
0195  * \fn int AbstractColumn::availableRowCount() const
0196  * \brief Return the number of available data rows
0197  */
0198 
0199 /**
0200  * \brief Insert some empty (or initialized with invalid values) rows
0201  */
0202 void AbstractColumn::insertRows(int before, int count) {
0203     beginMacro( i18np("%1: insert 1 row", "%1: insert %2 rows", name(), count) );
0204     exec(new SignallingUndoCommand("pre-signal", this, "rowsAboutToBeInserted", "rowsRemoved",
0205                                    Q_ARG(const AbstractColumn*,this), Q_ARG(int,before), Q_ARG(int,count)));
0206 
0207     handleRowInsertion(before, count);
0208 
0209     exec(new SignallingUndoCommand("post-signal", this, "rowsInserted", "rowsAboutToBeRemoved",
0210                                    Q_ARG(const AbstractColumn*,this), Q_ARG(int,before), Q_ARG(int,count)));
0211     endMacro();
0212 }
0213 
0214 void AbstractColumn::handleRowInsertion(int before, int count) {
0215     exec(new AbstractColumnInsertRowsCmd(this, before, count));
0216 }
0217 
0218 /**
0219  * \brief Remove 'count' rows starting from row 'first'
0220  */
0221 void AbstractColumn::removeRows(int first, int count) {
0222     beginMacro( i18np("%1: remove 1 row", "%1: remove %2 rows", name(), count) );
0223     exec(new SignallingUndoCommand("change signal", this, "rowsAboutToBeRemoved", "rowsInserted",
0224                                    Q_ARG(const AbstractColumn*,this), Q_ARG(int,first), Q_ARG(int,count)));
0225 
0226     handleRowRemoval(first, count);
0227 
0228     exec(new SignallingUndoCommand("change signal", this, "rowsRemoved", "rowsAboutToBeInserted",
0229                                    Q_ARG(const AbstractColumn*,this), Q_ARG(int,first), Q_ARG(int,count)));
0230     endMacro();
0231 }
0232 
0233 void AbstractColumn::handleRowRemoval(int first, int count) {
0234     exec(new AbstractColumnRemoveRowsCmd(this, first, count));
0235 }
0236 
0237 /**
0238  * \fn AbstractColumn::PlotDesignation AbstractColumn::plotDesignation() const
0239  * \brief Return the column plot designation
0240  */
0241 
0242 /**
0243  * \brief Set the column plot designation
0244  */
0245 void AbstractColumn::setPlotDesignation(AbstractColumn::PlotDesignation pd) {
0246     Q_UNUSED(pd)
0247 }
0248 
0249 bool AbstractColumn::isNumeric() const {
0250     const auto mode = columnMode();
0251     return (mode == ColumnMode::Numeric || mode == ColumnMode::Integer || mode == ColumnMode::BigInt);
0252 }
0253 
0254 bool AbstractColumn::isPlottable() const {
0255     const auto mode = columnMode();
0256     return (mode == ColumnMode::Numeric || mode == ColumnMode::Integer || mode == ColumnMode::BigInt || mode == ColumnMode::DateTime);
0257 }
0258 
0259 /**
0260  * \brief Clear the whole column
0261  */
0262 void AbstractColumn::clear() {}
0263 
0264 /**
0265  * \brief Convenience method for mode-independent testing of validity
0266  */
0267 bool AbstractColumn::isValid(int row) const {
0268     switch (columnMode()) {
0269     case ColumnMode::Numeric:
0270         return !(std::isnan(valueAt(row)) || std::isinf(valueAt(row)));
0271     case ColumnMode::Integer:   // there is no invalid integer
0272     case ColumnMode::BigInt:
0273         return true;
0274     case ColumnMode::Text:
0275         return !textAt(row).isNull();
0276     case ColumnMode::DateTime:
0277     case ColumnMode::Month:
0278     case ColumnMode::Day:
0279         return dateTimeAt(row).isValid();
0280     }
0281 
0282     return false;
0283 }
0284 
0285 ////////////////////////////////////////////////////////////////////////////////////////////////////
0286 //! \name IntervalAttribute related functions
0287 //@{
0288 ////////////////////////////////////////////////////////////////////////////////////////////////////
0289 
0290 /**
0291  * \brief Return whether a certain row is masked
0292  */
0293 bool AbstractColumn::isMasked(int row) const {
0294     return d->m_masking.isSet(row);
0295 }
0296 
0297 /**
0298  * \brief Return whether a certain interval of rows is fully masked
0299  */
0300 bool AbstractColumn::isMasked(const Interval<int>& i) const {
0301     return d->m_masking.isSet(i);
0302 }
0303 
0304 /**
0305  * \brief Return all intervals of masked rows
0306  */
0307 QVector< Interval<int> > AbstractColumn::maskedIntervals() const {
0308     return d->m_masking.intervals();
0309 }
0310 
0311 /**
0312  * \brief Clear all masking information
0313  */
0314 void AbstractColumn::clearMasks() {
0315     exec(new AbstractColumnClearMasksCmd(d),
0316          "maskingAboutToChange", "maskingChanged", Q_ARG(const AbstractColumn*,this));
0317 }
0318 
0319 /**
0320  * \brief Set an interval masked
0321  *
0322  * \param i the interval
0323  * \param mask true: mask, false: unmask
0324  */
0325 void AbstractColumn::setMasked(const Interval<int>& i, bool mask) {
0326     exec(new AbstractColumnSetMaskedCmd(d, i, mask),
0327          "maskingAboutToChange", "maskingChanged", Q_ARG(const AbstractColumn*,this));
0328 }
0329 
0330 /**
0331  * \brief Overloaded function for convenience
0332  */
0333 void AbstractColumn::setMasked(int row, bool mask) {
0334     setMasked(Interval<int>(row,row), mask);
0335 }
0336 
0337 ////////////////////////////////////////////////////////////////////////////////////////////////////
0338 //@}
0339 ////////////////////////////////////////////////////////////////////////////////////////////////////
0340 
0341 ////////////////////////////////////////////////////////////////////////////////////////////////////
0342 //! \name Formula related functions
0343 //@{
0344 ////////////////////////////////////////////////////////////////////////////////////////////////////
0345 
0346 /**
0347  * \brief Return the formula associated with row 'row'
0348  */
0349 QString AbstractColumn::formula(int row) const {
0350     Q_UNUSED(row);
0351     return QString();
0352 }
0353 
0354 /**
0355  * \brief Return the intervals that have associated formulas
0356  *
0357  * This can be used to make a list of formulas with their intervals.
0358  * Here is some example code:
0359  *
0360  * \code
0361  * QStringList list;
0362  * QVector< Interval<int> > intervals = my_column.formulaIntervals();
0363  * foreach(Interval<int> interval, intervals)
0364  *  list << QString(interval.toString() + ": " + my_column.formula(interval.start()));
0365  * \endcode
0366  */
0367 QVector< Interval<int> > AbstractColumn::formulaIntervals() const {
0368     return QVector< Interval<int> >();
0369 }
0370 
0371 /**
0372  * \brief Set a formula string for an interval of rows
0373  */
0374 void AbstractColumn::setFormula(const Interval<int>& i, const QString& formula) {
0375     Q_UNUSED(i) Q_UNUSED(formula)
0376 }
0377 
0378 /**
0379  * \brief Overloaded function for convenience
0380  */
0381 void AbstractColumn::setFormula(int row, const QString& formula) {
0382     Q_UNUSED(row) Q_UNUSED(formula)
0383 }
0384 
0385 /**
0386  * \brief Clear all formulas
0387  */
0388 void AbstractColumn::clearFormulas() {};
0389 
0390 ////////////////////////////////////////////////////////////////////////////////////////////////////
0391 //@}
0392 ////////////////////////////////////////////////////////////////////////////////////////////////////
0393 
0394 ////////////////////////////////////////////////////////////////////////////////////////////////////
0395 //! \name type specific functions
0396 //@{
0397 ////////////////////////////////////////////////////////////////////////////////////////////////////
0398 
0399 /**
0400  * \brief Return the content of row 'row'.
0401  *
0402  * Use this only when columnMode() is Text
0403  */
0404 QString AbstractColumn::textAt(int row) const {
0405     Q_UNUSED(row);
0406     return QString();
0407 }
0408 
0409 /**
0410  * \brief Set the content of row 'row'
0411  *
0412  * Use this only when columnMode() is Text
0413  */
0414 void AbstractColumn::setTextAt(int row, const QString& new_value) {
0415     Q_UNUSED(row) Q_UNUSED(new_value)
0416 }
0417 
0418 /**
0419  * \brief Replace a range of values
0420  *
0421  * Use this only when columnMode() is Text
0422  */
0423 void AbstractColumn::replaceTexts(int first, const QVector<QString>& new_values) {
0424     Q_UNUSED(first) Q_UNUSED(new_values)
0425 };
0426 
0427 /**
0428  * \brief Return the date part of row 'row'
0429  *
0430  * Use this only when columnMode() is DateTime, Month or Day
0431  */
0432 QDate AbstractColumn::dateAt(int row) const {
0433     Q_UNUSED(row);
0434     return QDate{};
0435 }
0436 
0437 /**
0438  * \brief Set the content of row 'row'
0439  *
0440  * Use this only when columnMode() is DateTime, Month or Day
0441  */
0442 void AbstractColumn::setDateAt(int row, QDate new_value) {
0443     Q_UNUSED(row) Q_UNUSED(new_value)
0444 };
0445 
0446 /**
0447  * \brief Return the time part of row 'row'
0448  *
0449  * Use this only when columnMode() is DateTime, Month or Day
0450  */
0451 QTime AbstractColumn::timeAt(int row) const {
0452     Q_UNUSED(row);
0453     return QTime{};
0454 }
0455 
0456 /**
0457  * \brief Set the content of row 'row'
0458  *
0459  * Use this only when columnMode() is DateTime, Month or Day
0460  */
0461 void AbstractColumn::setTimeAt(int row, QTime new_value) {
0462     Q_UNUSED(row) Q_UNUSED(new_value)
0463 }
0464 
0465 /**
0466  * \brief Return the QDateTime in row 'row'
0467  *
0468  * Use this only when columnMode() is DateTime, Month or Day
0469  */
0470 QDateTime AbstractColumn::dateTimeAt(int row) const {
0471     Q_UNUSED(row);
0472     return QDateTime();
0473 }
0474 
0475 /**
0476  * \brief Set the content of row 'row'
0477  *
0478  * Use this only when columnMode() is DateTime, Month or Day
0479  */
0480 void AbstractColumn::setDateTimeAt(int row, const QDateTime& new_value) {
0481     Q_UNUSED(row) Q_UNUSED(new_value)
0482 };
0483 
0484 /**
0485  * \brief Replace a range of values
0486  *
0487  * Use this only when columnMode() is DateTime, Month or Day
0488  */
0489 void AbstractColumn::replaceDateTimes(int first, const QVector<QDateTime>& new_values) {
0490     Q_UNUSED(first) Q_UNUSED(new_values)
0491 };
0492 
0493 /**
0494  * \brief Return the double value in row 'row'
0495  *
0496  * Use this only when columnMode() is Numeric
0497  */
0498 double AbstractColumn::valueAt(int row) const {
0499     Q_UNUSED(row);
0500     return NAN;
0501 }
0502 
0503 /**
0504  * \brief Set the content of row 'row'
0505  *
0506  * Use this only when columnMode() is Numeric
0507  */
0508 void AbstractColumn::setValueAt(int row, const double new_value) {
0509     Q_UNUSED(row) Q_UNUSED(new_value)
0510 };
0511 
0512 /**
0513  * \brief Replace a range of values
0514  *
0515  * Use this only when columnMode() is Numeric
0516  */
0517 void AbstractColumn::replaceValues(int first, const QVector<double>& new_values) {
0518     Q_UNUSED(first) Q_UNUSED(new_values)
0519 }
0520 
0521 /**
0522  * \brief Return the integer value in row 'row'
0523  *
0524  * Use this only when columnMode() is Integer
0525  */
0526 int AbstractColumn::integerAt(int row) const {
0527     Q_UNUSED(row);
0528     return 42;
0529 }
0530 
0531 /**
0532  * \brief Set the content of row 'row'
0533  *
0534  * Use this only when columnMode() is Integer
0535  */
0536 void AbstractColumn::setIntegerAt(int row, const int new_value) {
0537     Q_UNUSED(row) Q_UNUSED(new_value)
0538 };
0539 
0540 /**
0541  * \brief Replace a range of values
0542  *
0543  * Use this only when columnMode() is Integer
0544  */
0545 void AbstractColumn::replaceInteger(int first, const QVector<int>& new_values) {
0546     Q_UNUSED(first) Q_UNUSED(new_values)
0547 }
0548 
0549 /**
0550  * \brief Return the bigint value in row 'row'
0551  *
0552  * Use this only when columnMode() is BigInt
0553  */
0554 qint64 AbstractColumn::bigIntAt(int row) const {
0555     Q_UNUSED(row);
0556     return 42;
0557 }
0558 
0559 /**
0560  * \brief Set the content of row 'row'
0561  *
0562  * Use this only when columnMode() is BigInt
0563  */
0564 void AbstractColumn::setBigIntAt(int row, const qint64 new_value) {
0565     Q_UNUSED(row) Q_UNUSED(new_value)
0566 };
0567 
0568 /**
0569  * \brief Replace a range of values
0570  *
0571  * Use this only when columnMode() is BigInt
0572  */
0573 void AbstractColumn::replaceBigInt(int first, const QVector<qint64>& new_values) {
0574     Q_UNUSED(first) Q_UNUSED(new_values)
0575 }
0576 
0577 /**
0578  * Returns the properties hold by this column (no, constant, monotonic increasing, monotonic decreasing,...)
0579  * Is used in XYCurve to improve the search velocity for the y value for a specific x value
0580  */
0581 AbstractColumn::Properties AbstractColumn::properties() const {
0582     return AbstractColumn::Properties::No;
0583 }
0584 
0585 /**********************************************************************/
0586 double AbstractColumn::minimum(int count) const {
0587     Q_UNUSED(count);
0588     return -INFINITY;
0589 }
0590 
0591 double AbstractColumn::minimum(int startIndex, int endIndex) const {
0592     Q_UNUSED(startIndex);
0593     Q_UNUSED(endIndex);
0594     return -INFINITY;
0595 }
0596 
0597 double AbstractColumn::maximum(int count) const {
0598     Q_UNUSED(count);
0599     return INFINITY;
0600 }
0601 
0602 double AbstractColumn::maximum(int startIndex, int endIndex) const {
0603     Q_UNUSED(startIndex);
0604     Q_UNUSED(endIndex);
0605     return INFINITY;
0606 }
0607 
0608 bool AbstractColumn::indicesMinMax(double v1, double v2, int& start, int& end)  const {
0609     Q_UNUSED(v1)
0610     Q_UNUSED(v2)
0611     Q_UNUSED(start)
0612     Q_UNUSED(end)
0613     return false;
0614 }
0615 
0616 int AbstractColumn::indexForValue(double x) const {
0617     Q_UNUSED(x)
0618     return 0;
0619 }
0620 
0621 ////////////////////////////////////////////////////////////////////////////////////////////////////
0622 //@}
0623 ////////////////////////////////////////////////////////////////////////////////////////////////////
0624 
0625 /**
0626  * \fn void AbstractColumn::plotDesignationAboutToChange(const AbstractColumn *source)
0627  * \brief Column plot designation will be changed
0628  *
0629  * 'source' is always the this pointer of the column that
0630  * emitted this signal. This way it's easier to use
0631  * one handler for lots of columns.
0632  */
0633 
0634 /**
0635  * \fn void AbstractColumn::plotDesignationChanged(const AbstractColumn *source)
0636  * \brief Column plot designation changed
0637  *
0638  * 'source' is always the this pointer of the column that
0639  * emitted this signal. This way it's easier to use
0640  * one handler for lots of columns.
0641  */
0642 
0643 /**
0644  * \fn void AbstractColumn::modeAboutToChange(const AbstractColumn *source)
0645  * \brief Column mode (possibly also the data type) will be changed
0646  *
0647  * 'source' is always the this pointer of the column that
0648  * emitted this signal. This way it's easier to use
0649  * one handler for lots of columns.
0650  */
0651 
0652 /**
0653  * \fn void AbstractColumn::modeChanged(const AbstractColumn *source)
0654  * \brief Column mode (possibly also the data type) changed
0655  *
0656  * 'source' is always the this pointer of the column that
0657  * emitted this signal. This way it's easier to use
0658  * one handler for lots of columns.
0659  */
0660 
0661 /**
0662  * \fn void AbstractColumn::dataAboutToChange(const AbstractColumn *source)
0663  * \brief Data of the column will be changed
0664  *
0665  * 'source' is always the this pointer of the column that
0666  * emitted this signal. This way it's easier to use
0667  * one handler for lots of columns.
0668  */
0669 
0670 /**
0671  * \fn void AbstractColumn::dataChanged(const AbstractColumn *source)
0672  * \brief Data of the column has changed
0673  *
0674  * Important: When data has changed also the number
0675  * of rows in the column may have changed without
0676  * any other signal emission.
0677  * 'source' is always the this pointer of the column that
0678  * emitted this signal. This way it's easier to use
0679  * one handler for lots of columns.
0680  */
0681 
0682 /**
0683  * \fn void AbstractColumn::rowsAboutToBeInserted(const AbstractColumn *source, int before, int count)
0684  * \brief Rows will be inserted
0685  *
0686  *  \param source the column that emitted the signal
0687  *  \param before the row to insert before
0688  *  \param count the number of rows to be inserted
0689  */
0690 
0691 /**
0692  * \fn void AbstractColumn::rowsInserted(const AbstractColumn *source, int before, int count)
0693  * \brief Rows have been inserted
0694  *
0695  *  \param source the column that emitted the signal
0696  *  \param before the row to insert before
0697  *  \param count the number of rows to be inserted
0698  */
0699 
0700 /**
0701  * \fn void AbstractColumn::rowsAboutToBeRemoved(const AbstractColumn *source, int first, int count)
0702  * \brief Rows will be deleted
0703  *
0704  *  \param source the column that emitted the signal
0705  *  \param first the first row to be deleted
0706  *  \param count the number of rows to be deleted
0707  */
0708 
0709 /**
0710  * \fn void AbstractColumn::rowsRemoved(const AbstractColumn *source, int first, int count)
0711  * \brief Rows have been deleted
0712  *
0713  *  \param source the column that emitted the signal
0714  *  \param first the first row that was deleted
0715  *  \param count the number of deleted rows
0716  */
0717 
0718 /**
0719  * \fn void AbstractColumn::maskingAboutToChange(const AbstractColumn *source)
0720  * \brief Rows are about to be masked or unmasked
0721  */
0722 
0723 /**
0724  * \fn void AbstractColumn::maskingChanged(const AbstractColumn *source)
0725  * \brief Rows have been masked or unmasked
0726  */
0727 
0728 /**
0729  * \fn void AbstractColumn::aboutToBeDestroyed(const AbstractColumn *source)
0730  * \brief Emitted shortl before this column is deleted
0731  *
0732  * \param source the object emitting this signal
0733  *
0734  * This is needed by AbstractFilter.
0735  */
0736 
0737 /**
0738  * \brief Read XML mask element
0739  */
0740 bool AbstractColumn::XmlReadMask(XmlStreamReader *reader) {
0741     Q_ASSERT(reader->isStartElement() && reader->name() == "mask");
0742 
0743     bool ok1, ok2;
0744     int start, end;
0745     start = reader->readAttributeInt("start_row", &ok1);
0746     end = reader->readAttributeInt("end_row", &ok2);
0747     if (!ok1 || !ok2) {
0748         reader->raiseError(i18n("invalid or missing start or end row"));
0749         return false;
0750     }
0751     setMasked(Interval<int>(start,end));
0752     if (!reader->skipToEndElement()) return false;
0753 
0754     return true;
0755 }
0756 
0757 /**
0758  * \brief Write XML mask element
0759  */
0760 void AbstractColumn::XmlWriteMask(QXmlStreamWriter *writer) const {
0761     for (const auto& interval : maskedIntervals()) {
0762         writer->writeStartElement("mask");
0763         writer->writeAttribute("start_row", QString::number(interval.start()));
0764         writer->writeAttribute("end_row", QString::number(interval.end()));
0765         writer->writeEndElement();
0766     }
0767 }