SparseModel.h

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #ifndef _SPARSE_MODEL_H_
00017 #define _SPARSE_MODEL_H_
00018 
00019 #include "Model.h"
00020 #include "base/Command.h"
00021 #include "base/CommandHistory.h"
00022 
00023 #include <iostream>
00024 
00025 #include <set>
00026 #include <QMutex>
00027 #include <QTextStream>
00028 
00029 
00035 template <typename PointType>
00036 class SparseModel : public Model
00037 {
00038 public:
00039     SparseModel(size_t sampleRate, size_t resolution,
00040                 bool notifyOnAdd = true);
00041     virtual ~SparseModel() { }
00042     
00043     virtual bool isOK() const { return true; }
00044     virtual size_t getStartFrame() const;
00045     virtual size_t getEndFrame() const;
00046     virtual size_t getSampleRate() const { return m_sampleRate; }
00047 
00048     virtual Model *clone() const;
00049 
00050     // Number of frames of the underlying sample rate that this model
00051     // is capable of resolving to.  For example, if m_resolution == 10
00052     // then every point in this model will be at a multiple of 10
00053     // sample frames and should be considered to cover a window ending
00054     // 10 sample frames later.
00055     virtual size_t getResolution() const {
00056         return m_resolution ? m_resolution : 1;
00057     }
00058     virtual void setResolution(size_t resolution);
00059 
00060     typedef PointType Point;
00061     typedef std::multiset<PointType,
00062                           typename PointType::OrderComparator> PointList;
00063     typedef typename PointList::iterator PointListIterator;
00064 
00068     virtual bool isEmpty() const;
00069 
00073     virtual size_t getPointCount() const;
00074 
00081     virtual PointList getPoints(long start, long end) const;
00082 
00087     virtual PointList getPoints(long frame) const;
00088 
00092     virtual const PointList &getPoints() const { return m_points; }
00093 
00098     virtual PointList getPreviousPoints(long frame) const;
00099 
00104     virtual PointList getNextPoints(long frame) const;
00105 
00109     virtual void clear();
00110 
00114     virtual void addPoint(const PointType &point);
00115 
00122     virtual void deletePoint(const PointType &point);
00123 
00124     virtual bool isReady(int *completion = 0) const {
00125         bool ready = isOK() && (m_completion == 100);
00126         if (completion) *completion = m_completion;
00127         return ready;
00128     }
00129 
00130     virtual void setCompletion(int completion, bool update = true);
00131     virtual int getCompletion() const { return m_completion; }
00132 
00133     virtual bool hasTextLabels() const { return m_hasTextLabels; }
00134 
00135     QString getTypeName() const { return tr("Sparse"); }
00136 
00137     virtual void toXml(QTextStream &out,
00138                        QString indent = "",
00139                        QString extraAttributes = "") const;
00140 
00141     virtual QString toDelimitedDataString(QString delimiter) const
00142     { 
00143         QString s;
00144         for (PointListIterator i = m_points.begin(); i != m_points.end(); ++i) {
00145             s += i->toDelimitedDataString(delimiter, m_sampleRate) + "\n";
00146         }
00147         return s;
00148     }
00149 
00153     class AddPointCommand : public Command
00154     {
00155     public:
00156         AddPointCommand(SparseModel<PointType> *model,
00157                         const PointType &point,
00158                         QString name = "") :
00159             m_model(model), m_point(point), m_name(name) { }
00160 
00161         virtual QString getName() const {
00162             return (m_name == "" ? tr("Add Point") : m_name);
00163         }
00164 
00165         virtual void execute() { m_model->addPoint(m_point); }
00166         virtual void unexecute() { m_model->deletePoint(m_point); }
00167 
00168         const PointType &getPoint() const { return m_point; }
00169 
00170     private:
00171         SparseModel<PointType> *m_model;
00172         PointType m_point;
00173         QString m_name;
00174     };
00175 
00176 
00180     class DeletePointCommand : public Command
00181     {
00182     public:
00183         DeletePointCommand(SparseModel<PointType> *model,
00184                            const PointType &point) :
00185             m_model(model), m_point(point) { }
00186 
00187         virtual QString getName() const { return tr("Delete Point"); }
00188 
00189         virtual void execute() { m_model->deletePoint(m_point); }
00190         virtual void unexecute() { m_model->addPoint(m_point); }
00191 
00192         const PointType &getPoint() const { return m_point; }
00193 
00194     private:
00195         SparseModel<PointType> *m_model;
00196         PointType m_point;
00197     };
00198 
00199     
00204     class EditCommand : public MacroCommand
00205     {
00206     public:
00207         EditCommand(SparseModel<PointType> *model, QString commandName);
00208 
00209         virtual void addPoint(const PointType &point);
00210         virtual void deletePoint(const PointType &point);
00211 
00215         virtual void addCommand(Command *command) { addCommand(command, true); }
00216 
00221         virtual void finish();
00222 
00223     protected:
00224         virtual void addCommand(Command *command, bool executeFirst);
00225 
00226         SparseModel<PointType> *m_model;
00227     };
00228 
00229 
00233     class RelabelCommand : public Command
00234     {
00235     public:
00236         RelabelCommand(SparseModel<PointType> *model,
00237                        const PointType &point,
00238                        QString newLabel) :
00239             m_model(model), m_oldPoint(point), m_newPoint(point) {
00240             m_newPoint.label = newLabel;
00241         }
00242 
00243         virtual QString getName() const { return tr("Re-Label Point"); }
00244 
00245         virtual void execute() { 
00246             m_model->deletePoint(m_oldPoint);
00247             m_model->addPoint(m_newPoint);
00248             std::swap(m_oldPoint, m_newPoint);
00249         }
00250 
00251         virtual void unexecute() { execute(); }
00252 
00253     private:
00254         SparseModel<PointType> *m_model;
00255         PointType m_oldPoint;
00256         PointType m_newPoint;
00257     };
00258 
00259     
00260 
00261 protected:
00262     size_t m_sampleRate;
00263     size_t m_resolution;
00264     bool m_notifyOnAdd;
00265     long m_sinceLastNotifyMin;
00266     long m_sinceLastNotifyMax;
00267     bool m_hasTextLabels;
00268 
00269     PointList m_points;
00270     size_t m_pointCount;
00271     mutable QMutex m_mutex;
00272     int m_completion;
00273 };
00274 
00275 
00276 template <typename PointType>
00277 SparseModel<PointType>::SparseModel(size_t sampleRate,
00278                                     size_t resolution,
00279                                     bool notifyOnAdd) :
00280     m_sampleRate(sampleRate),
00281     m_resolution(resolution),
00282     m_notifyOnAdd(notifyOnAdd),
00283     m_sinceLastNotifyMin(-1),
00284     m_sinceLastNotifyMax(-1),
00285     m_hasTextLabels(false),
00286     m_pointCount(0),
00287     m_completion(100)
00288 {
00289 }
00290 
00291 template <typename PointType>
00292 size_t
00293 SparseModel<PointType>::getStartFrame() const
00294 {
00295     QMutexLocker locker(&m_mutex);
00296     size_t f = 0;
00297     if (!m_points.empty()) {
00298         f = m_points.begin()->frame;
00299     }
00300     return f;
00301 }
00302 
00303 template <typename PointType>
00304 size_t
00305 SparseModel<PointType>::getEndFrame() const
00306 {
00307     QMutexLocker locker(&m_mutex);
00308     size_t f = 0;
00309     if (!m_points.empty()) {
00310         PointListIterator i(m_points.end());
00311         f = (--i)->frame;
00312     }
00313     return f;
00314 }
00315 
00316 template <typename PointType>
00317 Model *
00318 SparseModel<PointType>::clone() const
00319 {
00320     SparseModel<PointType> *model =
00321         new SparseModel<PointType>(m_sampleRate, m_resolution, m_notifyOnAdd);
00322     model->m_points = m_points;
00323     model->m_pointCount = m_pointCount;
00324     return model;
00325 }
00326 
00327 template <typename PointType>
00328 bool
00329 SparseModel<PointType>::isEmpty() const
00330 {
00331     return m_pointCount == 0;
00332 }
00333 
00334 template <typename PointType>
00335 size_t
00336 SparseModel<PointType>::getPointCount() const
00337 {
00338     return m_pointCount;
00339 }
00340 
00341 template <typename PointType>
00342 typename SparseModel<PointType>::PointList
00343 SparseModel<PointType>::getPoints(long start, long end) const
00344 {
00345     if (start > end) return PointList();
00346     QMutexLocker locker(&m_mutex);
00347 
00348     PointType startPoint(start), endPoint(end);
00349     
00350     PointListIterator startItr = m_points.lower_bound(startPoint);
00351     PointListIterator   endItr = m_points.upper_bound(endPoint);
00352 
00353     if (startItr != m_points.begin()) --startItr;
00354     if (startItr != m_points.begin()) --startItr;
00355     if (endItr != m_points.end()) ++endItr;
00356     if (endItr != m_points.end()) ++endItr;
00357 
00358     PointList rv;
00359 
00360     for (PointListIterator i = startItr; i != endItr; ++i) {
00361         rv.insert(*i);
00362     }
00363 
00364     return rv;
00365 }
00366 
00367 template <typename PointType>
00368 typename SparseModel<PointType>::PointList
00369 SparseModel<PointType>::getPoints(long frame) const
00370 {
00371     QMutexLocker locker(&m_mutex);
00372 
00373     if (m_resolution == 0) return PointList();
00374 
00375     long start = (frame / m_resolution) * m_resolution;
00376     long end = start + m_resolution;
00377 
00378     PointType startPoint(start), endPoint(end);
00379     
00380     PointListIterator startItr = m_points.lower_bound(startPoint);
00381     PointListIterator   endItr = m_points.upper_bound(endPoint);
00382 
00383     PointList rv;
00384 
00385     for (PointListIterator i = startItr; i != endItr; ++i) {
00386         rv.insert(*i);
00387     }
00388 
00389     return rv;
00390 }
00391 
00392 template <typename PointType>
00393 typename SparseModel<PointType>::PointList
00394 SparseModel<PointType>::getPreviousPoints(long originFrame) const
00395 {
00396     QMutexLocker locker(&m_mutex);
00397 
00398     PointType lookupPoint(originFrame);
00399     PointList rv;
00400 
00401     PointListIterator i = m_points.lower_bound(lookupPoint);
00402     if (i == m_points.begin()) return rv;
00403 
00404     --i;
00405     long frame = i->frame;
00406     while (i->frame == frame) {
00407         rv.insert(*i);
00408         if (i == m_points.begin()) break;
00409         --i;
00410     }
00411 
00412     return rv;
00413 }
00414  
00415 template <typename PointType>
00416 typename SparseModel<PointType>::PointList
00417 SparseModel<PointType>::getNextPoints(long originFrame) const
00418 {
00419     QMutexLocker locker(&m_mutex);
00420 
00421     PointType lookupPoint(originFrame);
00422     PointList rv;
00423 
00424     PointListIterator i = m_points.upper_bound(lookupPoint);
00425     if (i == m_points.end()) return rv;
00426 
00427     long frame = i->frame;
00428     while (i != m_points.end() && i->frame == frame) {
00429         rv.insert(*i);
00430         ++i;
00431     }
00432 
00433     return rv;
00434 }
00435 
00436 template <typename PointType>
00437 void
00438 SparseModel<PointType>::setResolution(size_t resolution)
00439 {
00440     {
00441         QMutexLocker locker(&m_mutex);
00442         m_resolution = resolution;
00443     }
00444     emit modelChanged();
00445 }
00446 
00447 template <typename PointType>
00448 void
00449 SparseModel<PointType>::clear()
00450 {
00451     {
00452         QMutexLocker locker(&m_mutex);
00453         m_points.clear();
00454         m_pointCount = 0;
00455     }
00456     emit modelChanged();
00457 }
00458 
00459 template <typename PointType>
00460 void
00461 SparseModel<PointType>::addPoint(const PointType &point)
00462 {
00463     {
00464         QMutexLocker locker(&m_mutex);
00465         m_points.insert(point);
00466         m_pointCount++;
00467         if (point.getLabel() != "") m_hasTextLabels = true;
00468     }
00469 
00470     // Even though this model is nominally sparse, there may still be
00471     // too many signals going on here (especially as they'll probably
00472     // be queued from one thread to another), which is why we need the
00473     // notifyOnAdd as an option rather than a necessity (the
00474     // alternative is to notify on setCompletion).
00475 
00476     if (m_notifyOnAdd) {
00477         emit modelChanged(point.frame, point.frame + m_resolution);
00478     } else {
00479         if (m_sinceLastNotifyMin == -1 ||
00480             point.frame < m_sinceLastNotifyMin) {
00481             m_sinceLastNotifyMin = point.frame;
00482         }
00483         if (m_sinceLastNotifyMax == -1 ||
00484             point.frame > m_sinceLastNotifyMax) {
00485             m_sinceLastNotifyMax = point.frame;
00486         }
00487     }
00488 }
00489 
00490 template <typename PointType>
00491 void
00492 SparseModel<PointType>::deletePoint(const PointType &point)
00493 {
00494     {
00495         QMutexLocker locker(&m_mutex);
00496 
00497         PointListIterator i = m_points.lower_bound(point);
00498         typename PointType::Comparator comparator;
00499         while (i != m_points.end()) {
00500             if (i->frame > point.frame) break;
00501             if (!comparator(*i, point) && !comparator(point, *i)) {
00502                 m_points.erase(i);
00503                 m_pointCount--;
00504                 break;
00505             }
00506             ++i;
00507         }
00508     }
00509 //    std::cout << "SparseOneDimensionalModel: emit modelChanged("
00510 //            << point.frame << ")" << std::endl;
00511     emit modelChanged(point.frame, point.frame + m_resolution);
00512 }
00513 
00514 template <typename PointType>
00515 void
00516 SparseModel<PointType>::setCompletion(int completion, bool update)
00517 {
00518 //    std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl;
00519 
00520     if (m_completion != completion) {
00521         m_completion = completion;
00522 
00523         if (completion == 100) {
00524 
00525             if (!m_notifyOnAdd) {
00526                 emit completionChanged();
00527             }
00528 
00529             m_notifyOnAdd = true; // henceforth
00530             emit modelChanged();
00531 
00532         } else if (!m_notifyOnAdd) {
00533 
00534             if (update &&
00535                 m_sinceLastNotifyMin >= 0 &&
00536                 m_sinceLastNotifyMax >= 0) {
00537                 emit modelChanged(m_sinceLastNotifyMin, m_sinceLastNotifyMax);
00538                 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
00539             } else {
00540                 emit completionChanged();
00541             }
00542         } else {
00543             emit completionChanged();
00544         }           
00545     }
00546 }
00547 
00548 template <typename PointType>
00549 void
00550 SparseModel<PointType>::toXml(QTextStream &out,
00551                               QString indent,
00552                               QString extraAttributes) const
00553 {
00554     std::cerr << "SparseModel::toXml: extraAttributes = \"" 
00555               << extraAttributes.toStdString() << std::endl;
00556 
00557     Model::toXml
00558         (out,
00559          indent,
00560          QString("type=\"sparse\" dimensions=\"%1\" resolution=\"%2\" notifyOnAdd=\"%3\" dataset=\"%4\" %5")
00561          .arg(PointType(0).getDimensions())
00562          .arg(m_resolution)
00563          .arg(m_notifyOnAdd ? "true" : "false")
00564          .arg(getObjectExportId(&m_points))
00565          .arg(extraAttributes));
00566 
00567     out << indent;
00568     out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n")
00569         .arg(getObjectExportId(&m_points))
00570         .arg(PointType(0).getDimensions());
00571 
00572     for (PointListIterator i = m_points.begin(); i != m_points.end(); ++i) {
00573         i->toXml(out, indent + "  ");
00574     }
00575 
00576     out << indent;
00577     out << "</dataset>\n";
00578 }
00579 
00580 template <typename PointType>
00581 SparseModel<PointType>::EditCommand::EditCommand(SparseModel *model,
00582                                                  QString commandName) :
00583     MacroCommand(commandName),
00584     m_model(model)
00585 {
00586 }
00587 
00588 template <typename PointType>
00589 void
00590 SparseModel<PointType>::EditCommand::addPoint(const PointType &point)
00591 {
00592     addCommand(new AddPointCommand(m_model, point), true);
00593 }
00594 
00595 template <typename PointType>
00596 void
00597 SparseModel<PointType>::EditCommand::deletePoint(const PointType &point)
00598 {
00599     addCommand(new DeletePointCommand(m_model, point), true);
00600 }
00601 
00602 template <typename PointType>
00603 void
00604 SparseModel<PointType>::EditCommand::finish()
00605 {
00606     if (!m_commands.empty()) {
00607         CommandHistory::getInstance()->addCommand(this, false);
00608     } else {
00609         delete this;
00610     }
00611 }
00612 
00613 template <typename PointType>
00614 void
00615 SparseModel<PointType>::EditCommand::addCommand(Command *command,
00616                                                 bool executeFirst)
00617 {
00618     if (executeFirst) command->execute();
00619 
00620     if (!m_commands.empty()) {
00621         DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command);
00622         if (dpc) {
00623             AddPointCommand *apc = dynamic_cast<AddPointCommand *>
00624                 (m_commands[m_commands.size() - 1]);
00625             typename PointType::Comparator comparator;
00626             if (apc) {
00627                 if (!comparator(apc->getPoint(), dpc->getPoint()) &&
00628                     !comparator(dpc->getPoint(), apc->getPoint())) {
00629                     deleteCommand(apc);
00630                     return;
00631                 }
00632             }
00633         }
00634     }
00635 
00636     MacroCommand::addCommand(command);
00637 }
00638 
00639 
00640 #endif
00641 
00642 
00643     

Generated on Wed Feb 20 15:45:28 2008 for SonicVisualiser by  doxygen 1.5.1