00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
00051
00052
00053
00054
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
00471
00472
00473
00474
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
00510
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
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;
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