lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #ifndef _SPARSE_MODEL_H_ lbajardsilogic@0: #define _SPARSE_MODEL_H_ lbajardsilogic@0: lbajardsilogic@0: #include "Model.h" lbajardsilogic@0: #include "base/Command.h" lbajardsilogic@0: #include "base/CommandHistory.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Model containing sparse data (points with some properties). The lbajardsilogic@0: * properties depend on the point type. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: class SparseModel : public Model lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: SparseModel(size_t sampleRate, size_t resolution, lbajardsilogic@0: bool notifyOnAdd = true); lbajardsilogic@0: virtual ~SparseModel() { } lbajardsilogic@0: lbajardsilogic@0: virtual bool isOK() const { return true; } lbajardsilogic@0: virtual size_t getStartFrame() const; lbajardsilogic@0: virtual size_t getEndFrame() const; lbajardsilogic@0: virtual size_t getSampleRate() const { return m_sampleRate; } lbajardsilogic@0: lbajardsilogic@0: virtual Model *clone() const; lbajardsilogic@0: lbajardsilogic@0: // Number of frames of the underlying sample rate that this model lbajardsilogic@0: // is capable of resolving to. For example, if m_resolution == 10 lbajardsilogic@0: // then every point in this model will be at a multiple of 10 lbajardsilogic@0: // sample frames and should be considered to cover a window ending lbajardsilogic@0: // 10 sample frames later. lbajardsilogic@0: virtual size_t getResolution() const { lbajardsilogic@0: return m_resolution ? m_resolution : 1; lbajardsilogic@0: } lbajardsilogic@0: virtual void setResolution(size_t resolution); lbajardsilogic@0: lbajardsilogic@0: typedef PointType Point; lbajardsilogic@0: typedef std::multiset PointList; lbajardsilogic@0: typedef typename PointList::iterator PointListIterator; lbajardsilogic@0: typedef typename PointList::const_iterator PointListConstIterator; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return whether the model is empty or not. lbajardsilogic@0: */ lbajardsilogic@0: virtual bool isEmpty() const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get the total number of points in the model. lbajardsilogic@0: */ lbajardsilogic@0: virtual size_t getPointCount() const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get all of the points in this model between the given lbajardsilogic@0: * boundaries (in frames), as well as up to two points before and lbajardsilogic@0: * after the boundaries. If you need exact boundaries, check the lbajardsilogic@0: * point coordinates in the returned list. lbajardsilogic@0: */ lbajardsilogic@0: virtual PointList getPoints(long start, long end) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Get all points that cover the given frame number, taking the lbajardsilogic@0: * resolution of the model into account. lbajardsilogic@0: */ lbajardsilogic@0: virtual PointList getPoints(long frame) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return all points that share the nearest frame number prior to lbajardsilogic@0: * the given one at which there are any points. lbajardsilogic@0: */ lbajardsilogic@0: virtual PointList getPreviousPoints(long frame) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Return all points that share the nearest frame number lbajardsilogic@0: * subsequent to the given one at which there are any points. lbajardsilogic@0: */ lbajardsilogic@0: virtual PointList getNextPoints(long frame) const; lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Remove all points. lbajardsilogic@0: */ lbajardsilogic@0: virtual void clear(); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Add a point. lbajardsilogic@0: */ lbajardsilogic@0: virtual void addPoint(const PointType &point); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Remove a point. Points are not necessarily unique, so this lbajardsilogic@0: * function will remove the first point that compares equal to the lbajardsilogic@0: * supplied one using Point::Comparator. Other identical points lbajardsilogic@0: * may remain in the model. lbajardsilogic@0: */ lbajardsilogic@0: virtual void deletePoint(const PointType &point); lbajardsilogic@0: lbajardsilogic@0: virtual void setCompletion(int completion); lbajardsilogic@0: virtual int getCompletion() const { return m_completion; } lbajardsilogic@0: lbajardsilogic@0: virtual bool hasTextLabels() const { return m_hasTextLabels; } lbajardsilogic@0: lbajardsilogic@0: virtual void toXml(QTextStream &out, lbajardsilogic@0: QString indent = "", lbajardsilogic@0: QString extraAttributes = "") const; lbajardsilogic@0: lbajardsilogic@0: virtual QString toXmlString(QString indent = "", lbajardsilogic@0: QString extraAttributes = "") const; lbajardsilogic@0: lbajardsilogic@0: virtual QString toDelimitedDataString(QString delimiter) const lbajardsilogic@0: { lbajardsilogic@0: QString s; lbajardsilogic@0: for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { lbajardsilogic@0: s += i->toDelimitedDataString(delimiter, m_sampleRate) + "\n"; lbajardsilogic@0: } lbajardsilogic@0: return s; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Command to add a point, with undo. lbajardsilogic@0: */ lbajardsilogic@0: class AddPointCommand : public Command lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: AddPointCommand(SparseModel *model, lbajardsilogic@0: const PointType &point, lbajardsilogic@0: QString name = "") : lbajardsilogic@0: m_model(model), m_point(point), m_name(name) { } lbajardsilogic@0: lbajardsilogic@0: virtual QString getName() const { lbajardsilogic@0: return (m_name == "" ? tr("Add Point") : m_name); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: virtual void execute() { m_model->addPoint(m_point); } lbajardsilogic@0: virtual void unexecute() { m_model->deletePoint(m_point); } lbajardsilogic@0: lbajardsilogic@0: const PointType &getPoint() const { return m_point; } lbajardsilogic@0: lbajardsilogic@0: private: lbajardsilogic@0: SparseModel *m_model; lbajardsilogic@0: PointType m_point; lbajardsilogic@0: QString m_name; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Command to remove a point, with undo. lbajardsilogic@0: */ lbajardsilogic@0: class DeletePointCommand : public Command lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: DeletePointCommand(SparseModel *model, lbajardsilogic@0: const PointType &point) : lbajardsilogic@0: m_model(model), m_point(point) { } lbajardsilogic@0: lbajardsilogic@0: virtual QString getName() const { return tr("Delete Point"); } lbajardsilogic@0: lbajardsilogic@0: virtual void execute() { m_model->deletePoint(m_point); } lbajardsilogic@0: virtual void unexecute() { m_model->addPoint(m_point); } lbajardsilogic@0: lbajardsilogic@0: const PointType &getPoint() const { return m_point; } lbajardsilogic@0: lbajardsilogic@0: private: lbajardsilogic@0: SparseModel *m_model; lbajardsilogic@0: PointType m_point; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Command to add or remove a series of points, with undo. lbajardsilogic@0: * Consecutive add/remove pairs for the same point are collapsed. lbajardsilogic@0: */ lbajardsilogic@0: class EditCommand : public MacroCommand lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: EditCommand(SparseModel *model, QString commandName); lbajardsilogic@0: lbajardsilogic@0: virtual void addPoint(const PointType &point); lbajardsilogic@0: virtual void deletePoint(const PointType &point); lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Stack an arbitrary other command in the same sequence. lbajardsilogic@0: */ lbajardsilogic@0: virtual void addCommand(Command *command) { addCommand(command, true); } lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * If any points have been added or deleted, add this command lbajardsilogic@0: * to the command history. Otherwise delete the command. lbajardsilogic@0: */ lbajardsilogic@0: virtual void finish(); lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: virtual void addCommand(Command *command, bool executeFirst); lbajardsilogic@0: lbajardsilogic@0: SparseModel *m_model; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: /** lbajardsilogic@0: * Command to relabel a point. lbajardsilogic@0: */ lbajardsilogic@0: class RelabelCommand : public Command lbajardsilogic@0: { lbajardsilogic@0: public: lbajardsilogic@0: RelabelCommand(SparseModel *model, lbajardsilogic@0: const PointType &point, lbajardsilogic@0: QString newLabel) : lbajardsilogic@0: m_model(model), m_oldPoint(point), m_newPoint(point) { lbajardsilogic@0: m_newPoint.label = newLabel; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: virtual QString getName() const { return tr("Re-Label Point"); } lbajardsilogic@0: lbajardsilogic@0: virtual void execute() { lbajardsilogic@0: m_model->deletePoint(m_oldPoint); lbajardsilogic@0: m_model->addPoint(m_newPoint); lbajardsilogic@0: std::swap(m_oldPoint, m_newPoint); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: virtual void unexecute() { execute(); } lbajardsilogic@0: lbajardsilogic@0: private: lbajardsilogic@0: SparseModel *m_model; lbajardsilogic@0: PointType m_oldPoint; lbajardsilogic@0: PointType m_newPoint; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: protected: lbajardsilogic@0: size_t m_sampleRate; lbajardsilogic@0: size_t m_resolution; lbajardsilogic@0: bool m_notifyOnAdd; lbajardsilogic@0: long m_sinceLastNotifyMin; lbajardsilogic@0: long m_sinceLastNotifyMax; lbajardsilogic@0: bool m_hasTextLabels; lbajardsilogic@0: lbajardsilogic@0: PointList m_points; lbajardsilogic@0: size_t m_pointCount; lbajardsilogic@0: mutable QMutex m_mutex; lbajardsilogic@0: int m_completion; lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: SparseModel::SparseModel(size_t sampleRate, lbajardsilogic@0: size_t resolution, lbajardsilogic@0: bool notifyOnAdd) : lbajardsilogic@0: m_sampleRate(sampleRate), lbajardsilogic@0: m_resolution(resolution), lbajardsilogic@0: m_notifyOnAdd(notifyOnAdd), lbajardsilogic@0: m_sinceLastNotifyMin(-1), lbajardsilogic@0: m_sinceLastNotifyMax(-1), lbajardsilogic@0: m_hasTextLabels(false), lbajardsilogic@0: m_pointCount(0), lbajardsilogic@0: m_completion(100) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: size_t lbajardsilogic@0: SparseModel::getStartFrame() const lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: size_t f = 0; lbajardsilogic@0: if (!m_points.empty()) { lbajardsilogic@0: f = m_points.begin()->frame; lbajardsilogic@0: } lbajardsilogic@0: return f; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: size_t lbajardsilogic@0: SparseModel::getEndFrame() const lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: size_t f = 0; lbajardsilogic@0: if (!m_points.empty()) { lbajardsilogic@0: PointListConstIterator i(m_points.end()); lbajardsilogic@0: f = (--i)->frame; lbajardsilogic@0: } lbajardsilogic@0: return f; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: Model * lbajardsilogic@0: SparseModel::clone() const lbajardsilogic@0: { lbajardsilogic@0: SparseModel *model = lbajardsilogic@0: new SparseModel(m_sampleRate, m_resolution, m_notifyOnAdd); lbajardsilogic@0: model->m_points = m_points; lbajardsilogic@0: model->m_pointCount = m_pointCount; lbajardsilogic@0: return model; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: bool lbajardsilogic@0: SparseModel::isEmpty() const lbajardsilogic@0: { lbajardsilogic@0: return m_pointCount == 0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: size_t lbajardsilogic@0: SparseModel::getPointCount() const lbajardsilogic@0: { lbajardsilogic@0: return m_pointCount; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: typename SparseModel::PointList lbajardsilogic@0: SparseModel::getPoints(long start, long end) const lbajardsilogic@0: { lbajardsilogic@0: if (start > end) return PointList(); lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: lbajardsilogic@0: PointType startPoint(start), endPoint(end); lbajardsilogic@0: lbajardsilogic@0: PointListConstIterator startItr = m_points.lower_bound(startPoint); lbajardsilogic@0: PointListConstIterator endItr = m_points.upper_bound(endPoint); lbajardsilogic@0: lbajardsilogic@0: if (startItr != m_points.begin()) --startItr; lbajardsilogic@0: if (startItr != m_points.begin()) --startItr; lbajardsilogic@0: if (endItr != m_points.end()) ++endItr; lbajardsilogic@0: if (endItr != m_points.end()) ++endItr; lbajardsilogic@0: lbajardsilogic@0: PointList rv; lbajardsilogic@0: lbajardsilogic@0: for (PointListConstIterator i = startItr; i != endItr; ++i) { lbajardsilogic@0: rv.insert(*i); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: typename SparseModel::PointList lbajardsilogic@0: SparseModel::getPoints(long frame) const lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: lbajardsilogic@0: if (m_resolution == 0) return PointList(); lbajardsilogic@0: lbajardsilogic@0: long start = (frame / m_resolution) * m_resolution; lbajardsilogic@0: long end = start + m_resolution; lbajardsilogic@0: lbajardsilogic@0: PointType startPoint(start), endPoint(end); lbajardsilogic@0: lbajardsilogic@0: PointListConstIterator startItr = m_points.lower_bound(startPoint); lbajardsilogic@0: PointListConstIterator endItr = m_points.upper_bound(endPoint); lbajardsilogic@0: lbajardsilogic@0: PointList rv; lbajardsilogic@0: lbajardsilogic@0: for (PointListConstIterator i = startItr; i != endItr; ++i) { lbajardsilogic@0: rv.insert(*i); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: typename SparseModel::PointList lbajardsilogic@0: SparseModel::getPreviousPoints(long originFrame) const lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: lbajardsilogic@0: PointType lookupPoint(originFrame); lbajardsilogic@0: PointList rv; lbajardsilogic@0: lbajardsilogic@0: PointListConstIterator i = m_points.lower_bound(lookupPoint); lbajardsilogic@0: if (i == m_points.begin()) return rv; lbajardsilogic@0: lbajardsilogic@0: --i; lbajardsilogic@0: long frame = i->frame; lbajardsilogic@0: while (i->frame == frame) { lbajardsilogic@0: rv.insert(*i); lbajardsilogic@0: if (i == m_points.begin()) break; lbajardsilogic@0: --i; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: typename SparseModel::PointList lbajardsilogic@0: SparseModel::getNextPoints(long originFrame) const lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: lbajardsilogic@0: PointType lookupPoint(originFrame); lbajardsilogic@0: PointList rv; lbajardsilogic@0: lbajardsilogic@0: PointListConstIterator i = m_points.upper_bound(lookupPoint); lbajardsilogic@0: if (i == m_points.end()) return rv; lbajardsilogic@0: lbajardsilogic@0: long frame = i->frame; lbajardsilogic@0: while (i != m_points.end() && i->frame == frame) { lbajardsilogic@0: rv.insert(*i); lbajardsilogic@0: ++i; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return rv; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::setResolution(size_t resolution) lbajardsilogic@0: { lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: m_resolution = resolution; lbajardsilogic@0: } lbajardsilogic@0: emit modelChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::clear() lbajardsilogic@0: { lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: m_points.clear(); lbajardsilogic@0: m_pointCount = 0; lbajardsilogic@0: } lbajardsilogic@0: emit modelChanged(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::addPoint(const PointType &point) lbajardsilogic@0: { lbajardsilogic@0: // std::cout << "SparseModel::addPoint(" << point.frame << ", " lbajardsilogic@0: // << point.value << ")" << std::endl; lbajardsilogic@0: lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: m_points.insert(point); lbajardsilogic@0: m_pointCount++; lbajardsilogic@0: if (point.label != "") m_hasTextLabels = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: // Even though this model is nominally sparse, there may still be lbajardsilogic@0: // too many signals going on here (especially as they'll probably lbajardsilogic@0: // be queued from one thread to another), which is why we need the lbajardsilogic@0: // notifyOnAdd as an option rather than a necessity (the lbajardsilogic@0: // alternative is to notify on setCompletion). lbajardsilogic@0: lbajardsilogic@0: if (m_notifyOnAdd) { lbajardsilogic@0: emit modelChanged(point.frame, point.frame + m_resolution); lbajardsilogic@0: } else { lbajardsilogic@0: if (m_sinceLastNotifyMin == -1 || lbajardsilogic@0: point.frame < m_sinceLastNotifyMin) { lbajardsilogic@0: m_sinceLastNotifyMin = point.frame; lbajardsilogic@0: } lbajardsilogic@0: if (m_sinceLastNotifyMax == -1 || lbajardsilogic@0: point.frame > m_sinceLastNotifyMax) { lbajardsilogic@0: m_sinceLastNotifyMax = point.frame; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::deletePoint(const PointType &point) lbajardsilogic@0: { lbajardsilogic@0: { lbajardsilogic@0: QMutexLocker locker(&m_mutex); lbajardsilogic@0: lbajardsilogic@0: PointListIterator i = m_points.lower_bound(point); lbajardsilogic@0: typename PointType::Comparator comparator; lbajardsilogic@0: while (i != m_points.end()) { lbajardsilogic@0: if (i->frame > point.frame) break; lbajardsilogic@0: if (!comparator(*i, point) && !comparator(point, *i)) { lbajardsilogic@0: m_points.erase(i); lbajardsilogic@0: m_pointCount--; lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: ++i; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: // std::cout << "SparseOneDimensionalModel: emit modelChanged(" lbajardsilogic@0: // << point.frame << ")" << std::endl; lbajardsilogic@0: emit modelChanged(point.frame, point.frame + m_resolution); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::setCompletion(int completion) lbajardsilogic@0: { lbajardsilogic@0: // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl; lbajardsilogic@0: lbajardsilogic@0: if (m_completion != completion) { lbajardsilogic@0: m_completion = completion; lbajardsilogic@0: lbajardsilogic@0: if (completion == 100) { lbajardsilogic@0: lbajardsilogic@0: m_notifyOnAdd = true; // henceforth lbajardsilogic@0: emit modelChanged(); lbajardsilogic@0: lbajardsilogic@0: } else if (!m_notifyOnAdd) { lbajardsilogic@0: lbajardsilogic@0: if (m_sinceLastNotifyMin >= 0 && lbajardsilogic@0: m_sinceLastNotifyMax >= 0) { lbajardsilogic@0: emit modelChanged(m_sinceLastNotifyMin, m_sinceLastNotifyMax); lbajardsilogic@0: m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1; lbajardsilogic@0: } else { lbajardsilogic@0: emit completionChanged(); lbajardsilogic@0: } lbajardsilogic@0: } else { lbajardsilogic@0: emit completionChanged(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::toXml(QTextStream &out, lbajardsilogic@0: QString indent, lbajardsilogic@0: QString extraAttributes) const lbajardsilogic@0: { lbajardsilogic@0: Model::toXml lbajardsilogic@0: (out, lbajardsilogic@0: indent, lbajardsilogic@0: QString("type=\"sparse\" dimensions=\"%1\" resolution=\"%2\" notifyOnAdd=\"%3\" dataset=\"%4\" %5") lbajardsilogic@0: .arg(PointType(0).getDimensions()) lbajardsilogic@0: .arg(m_resolution) lbajardsilogic@0: .arg(m_notifyOnAdd ? "true" : "false") lbajardsilogic@0: .arg(getObjectExportId(&m_points)) lbajardsilogic@0: .arg(extraAttributes)); lbajardsilogic@0: lbajardsilogic@0: out << indent; lbajardsilogic@0: out << QString("\n") lbajardsilogic@0: .arg(getObjectExportId(&m_points)) lbajardsilogic@0: .arg(PointType(0).getDimensions()); lbajardsilogic@0: lbajardsilogic@0: for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { lbajardsilogic@0: out << i->toXmlString(indent + " "); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: out << indent; lbajardsilogic@0: out << "\n"; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: QString lbajardsilogic@0: SparseModel::toXmlString(QString indent, lbajardsilogic@0: QString extraAttributes) const lbajardsilogic@0: { lbajardsilogic@0: QString s; lbajardsilogic@0: lbajardsilogic@0: { lbajardsilogic@0: QTextStream out(&s); lbajardsilogic@0: toXml(out, indent, extraAttributes); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return s; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: SparseModel::EditCommand::EditCommand(SparseModel *model, lbajardsilogic@0: QString commandName) : lbajardsilogic@0: MacroCommand(commandName), lbajardsilogic@0: m_model(model) lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::EditCommand::addPoint(const PointType &point) lbajardsilogic@0: { lbajardsilogic@0: addCommand(new AddPointCommand(m_model, point), true); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::EditCommand::deletePoint(const PointType &point) lbajardsilogic@0: { lbajardsilogic@0: addCommand(new DeletePointCommand(m_model, point), true); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::EditCommand::finish() lbajardsilogic@0: { lbajardsilogic@0: if (!m_commands.empty()) { lbajardsilogic@0: CommandHistory::getInstance()->addCommand(this, false); lbajardsilogic@0: } else { lbajardsilogic@0: delete this; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: template lbajardsilogic@0: void lbajardsilogic@0: SparseModel::EditCommand::addCommand(Command *command, lbajardsilogic@0: bool executeFirst) lbajardsilogic@0: { lbajardsilogic@0: if (executeFirst) command->execute(); lbajardsilogic@0: lbajardsilogic@0: if (!m_commands.empty()) { lbajardsilogic@0: DeletePointCommand *dpc = dynamic_cast(command); lbajardsilogic@0: if (dpc) { lbajardsilogic@0: AddPointCommand *apc = dynamic_cast lbajardsilogic@0: (m_commands[m_commands.size() - 1]); lbajardsilogic@0: typename PointType::Comparator comparator; lbajardsilogic@0: if (apc) { lbajardsilogic@0: if (!comparator(apc->getPoint(), dpc->getPoint()) && lbajardsilogic@0: !comparator(dpc->getPoint(), apc->getPoint())) { lbajardsilogic@0: deleteCommand(apc); lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: MacroCommand::addCommand(command); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: #endif lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: