annotate data/model/SparseModel.h @ 558:1d7ebc05157e

* Some fairly simplistic code to set up layer type properties based on RDF data about feature types (both when running transforms and when importing features from RDF files).
author Chris Cannam
date Thu, 12 Feb 2009 15:26:43 +0000
parents 6441b31b37ac
children 1415e35881f6
rev   line source
Chris@147 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@147 2
Chris@147 3 /*
Chris@147 4 Sonic Visualiser
Chris@147 5 An audio file viewer and annotation editor.
Chris@147 6 Centre for Digital Music, Queen Mary, University of London.
Chris@147 7 This file copyright 2006 Chris Cannam.
Chris@147 8
Chris@147 9 This program is free software; you can redistribute it and/or
Chris@147 10 modify it under the terms of the GNU General Public License as
Chris@147 11 published by the Free Software Foundation; either version 2 of the
Chris@147 12 License, or (at your option) any later version. See the file
Chris@147 13 COPYING included with this distribution for more information.
Chris@147 14 */
Chris@147 15
Chris@147 16 #ifndef _SPARSE_MODEL_H_
Chris@147 17 #define _SPARSE_MODEL_H_
Chris@147 18
Chris@150 19 #include "Model.h"
Chris@420 20 #include "TabularModel.h"
Chris@147 21 #include "base/Command.h"
Chris@425 22 #include "base/RealTime.h"
Chris@147 23
Chris@147 24 #include <iostream>
Chris@147 25
Chris@147 26 #include <set>
Chris@420 27 #include <vector>
Chris@420 28 #include <algorithm>
Chris@420 29
Chris@425 30 #include <cmath>
Chris@425 31
Chris@147 32 #include <QMutex>
Chris@147 33 #include <QTextStream>
Chris@147 34
Chris@147 35 /**
Chris@147 36 * Model containing sparse data (points with some properties). The
Chris@147 37 * properties depend on the point type.
Chris@147 38 */
Chris@147 39
Chris@147 40 template <typename PointType>
Chris@420 41 class SparseModel : public Model,
Chris@420 42 public TabularModel
Chris@147 43 {
Chris@147 44 public:
Chris@147 45 SparseModel(size_t sampleRate, size_t resolution,
Chris@147 46 bool notifyOnAdd = true);
Chris@147 47 virtual ~SparseModel() { }
Chris@147 48
Chris@147 49 virtual bool isOK() const { return true; }
Chris@147 50 virtual size_t getStartFrame() const;
Chris@147 51 virtual size_t getEndFrame() const;
Chris@147 52 virtual size_t getSampleRate() const { return m_sampleRate; }
Chris@147 53
Chris@147 54 virtual Model *clone() const;
Chris@147 55
Chris@147 56 // Number of frames of the underlying sample rate that this model
Chris@147 57 // is capable of resolving to. For example, if m_resolution == 10
Chris@147 58 // then every point in this model will be at a multiple of 10
Chris@147 59 // sample frames and should be considered to cover a window ending
Chris@147 60 // 10 sample frames later.
Chris@147 61 virtual size_t getResolution() const {
Chris@147 62 return m_resolution ? m_resolution : 1;
Chris@147 63 }
Chris@147 64 virtual void setResolution(size_t resolution);
Chris@147 65
Chris@147 66 typedef PointType Point;
Chris@147 67 typedef std::multiset<PointType,
Chris@147 68 typename PointType::OrderComparator> PointList;
Chris@147 69 typedef typename PointList::iterator PointListIterator;
Chris@147 70
Chris@147 71 /**
Chris@147 72 * Return whether the model is empty or not.
Chris@147 73 */
Chris@147 74 virtual bool isEmpty() const;
Chris@147 75
Chris@147 76 /**
Chris@147 77 * Get the total number of points in the model.
Chris@147 78 */
Chris@147 79 virtual size_t getPointCount() const;
Chris@147 80
Chris@147 81 /**
Chris@459 82 * Get all points.
Chris@459 83 */
Chris@459 84 virtual const PointList &getPoints() const;
Chris@459 85
Chris@459 86 /**
Chris@147 87 * Get all of the points in this model between the given
Chris@147 88 * boundaries (in frames), as well as up to two points before and
Chris@147 89 * after the boundaries. If you need exact boundaries, check the
Chris@147 90 * point coordinates in the returned list.
Chris@147 91 */
Chris@147 92 virtual PointList getPoints(long start, long end) const;
Chris@147 93
Chris@147 94 /**
Chris@147 95 * Get all points that cover the given frame number, taking the
Chris@147 96 * resolution of the model into account.
Chris@147 97 */
Chris@147 98 virtual PointList getPoints(long frame) const;
Chris@147 99
Chris@147 100 /**
Chris@147 101 * Return all points that share the nearest frame number prior to
Chris@147 102 * the given one at which there are any points.
Chris@147 103 */
Chris@147 104 virtual PointList getPreviousPoints(long frame) const;
Chris@147 105
Chris@147 106 /**
Chris@147 107 * Return all points that share the nearest frame number
Chris@147 108 * subsequent to the given one at which there are any points.
Chris@147 109 */
Chris@147 110 virtual PointList getNextPoints(long frame) const;
Chris@147 111
Chris@147 112 /**
Chris@147 113 * Remove all points.
Chris@147 114 */
Chris@147 115 virtual void clear();
Chris@147 116
Chris@147 117 /**
Chris@147 118 * Add a point.
Chris@147 119 */
Chris@147 120 virtual void addPoint(const PointType &point);
Chris@147 121
Chris@147 122 /**
Chris@147 123 * Remove a point. Points are not necessarily unique, so this
Chris@147 124 * function will remove the first point that compares equal to the
Chris@147 125 * supplied one using Point::Comparator. Other identical points
Chris@147 126 * may remain in the model.
Chris@147 127 */
Chris@147 128 virtual void deletePoint(const PointType &point);
Chris@147 129
Chris@297 130 virtual bool isReady(int *completion = 0) const {
Chris@297 131 bool ready = isOK() && (m_completion == 100);
Chris@297 132 if (completion) *completion = m_completion;
Chris@297 133 return ready;
Chris@297 134 }
Chris@297 135
Chris@333 136 virtual void setCompletion(int completion, bool update = true);
Chris@147 137 virtual int getCompletion() const { return m_completion; }
Chris@147 138
Chris@147 139 virtual bool hasTextLabels() const { return m_hasTextLabels; }
Chris@147 140
Chris@345 141 QString getTypeName() const { return tr("Sparse"); }
Chris@345 142
Chris@407 143 virtual QString getXmlOutputType() const { return "sparse"; }
Chris@407 144
Chris@147 145 virtual void toXml(QTextStream &out,
Chris@147 146 QString indent = "",
Chris@147 147 QString extraAttributes = "") const;
Chris@147 148
Chris@147 149 virtual QString toDelimitedDataString(QString delimiter) const
Chris@147 150 {
Chris@147 151 QString s;
Chris@147 152 for (PointListIterator i = m_points.begin(); i != m_points.end(); ++i) {
Chris@147 153 s += i->toDelimitedDataString(delimiter, m_sampleRate) + "\n";
Chris@147 154 }
Chris@147 155 return s;
Chris@147 156 }
Chris@147 157
Chris@147 158 /**
Chris@147 159 * Command to add a point, with undo.
Chris@147 160 */
Chris@147 161 class AddPointCommand : public Command
Chris@147 162 {
Chris@147 163 public:
Chris@147 164 AddPointCommand(SparseModel<PointType> *model,
Chris@147 165 const PointType &point,
Chris@147 166 QString name = "") :
Chris@147 167 m_model(model), m_point(point), m_name(name) { }
Chris@147 168
Chris@147 169 virtual QString getName() const {
Chris@147 170 return (m_name == "" ? tr("Add Point") : m_name);
Chris@147 171 }
Chris@147 172
Chris@147 173 virtual void execute() { m_model->addPoint(m_point); }
Chris@147 174 virtual void unexecute() { m_model->deletePoint(m_point); }
Chris@147 175
Chris@147 176 const PointType &getPoint() const { return m_point; }
Chris@147 177
Chris@147 178 private:
Chris@147 179 SparseModel<PointType> *m_model;
Chris@147 180 PointType m_point;
Chris@147 181 QString m_name;
Chris@147 182 };
Chris@147 183
Chris@147 184
Chris@147 185 /**
Chris@147 186 * Command to remove a point, with undo.
Chris@147 187 */
Chris@147 188 class DeletePointCommand : public Command
Chris@147 189 {
Chris@147 190 public:
Chris@147 191 DeletePointCommand(SparseModel<PointType> *model,
Chris@147 192 const PointType &point) :
Chris@147 193 m_model(model), m_point(point) { }
Chris@147 194
Chris@147 195 virtual QString getName() const { return tr("Delete Point"); }
Chris@147 196
Chris@147 197 virtual void execute() { m_model->deletePoint(m_point); }
Chris@147 198 virtual void unexecute() { m_model->addPoint(m_point); }
Chris@147 199
Chris@147 200 const PointType &getPoint() const { return m_point; }
Chris@147 201
Chris@147 202 private:
Chris@147 203 SparseModel<PointType> *m_model;
Chris@147 204 PointType m_point;
Chris@147 205 };
Chris@147 206
Chris@147 207
Chris@147 208 /**
Chris@147 209 * Command to add or remove a series of points, with undo.
Chris@147 210 * Consecutive add/remove pairs for the same point are collapsed.
Chris@147 211 */
Chris@147 212 class EditCommand : public MacroCommand
Chris@147 213 {
Chris@147 214 public:
Chris@147 215 EditCommand(SparseModel<PointType> *model, QString commandName);
Chris@147 216
Chris@147 217 virtual void addPoint(const PointType &point);
Chris@147 218 virtual void deletePoint(const PointType &point);
Chris@147 219
Chris@147 220 /**
Chris@147 221 * Stack an arbitrary other command in the same sequence.
Chris@147 222 */
Chris@147 223 virtual void addCommand(Command *command) { addCommand(command, true); }
Chris@147 224
Chris@147 225 /**
Chris@387 226 * If any points have been added or deleted, return this
Chris@387 227 * command (so the caller can add it to the command history).
Chris@416 228 * Otherwise delete the command and return NULL.
Chris@147 229 */
Chris@416 230 virtual EditCommand *finish();
Chris@147 231
Chris@147 232 protected:
Chris@147 233 virtual void addCommand(Command *command, bool executeFirst);
Chris@147 234
Chris@147 235 SparseModel<PointType> *m_model;
Chris@147 236 };
Chris@147 237
Chris@147 238
Chris@147 239 /**
Chris@147 240 * Command to relabel a point.
Chris@147 241 */
Chris@147 242 class RelabelCommand : public Command
Chris@147 243 {
Chris@147 244 public:
Chris@147 245 RelabelCommand(SparseModel<PointType> *model,
Chris@147 246 const PointType &point,
Chris@147 247 QString newLabel) :
Chris@147 248 m_model(model), m_oldPoint(point), m_newPoint(point) {
Chris@147 249 m_newPoint.label = newLabel;
Chris@147 250 }
Chris@147 251
Chris@147 252 virtual QString getName() const { return tr("Re-Label Point"); }
Chris@147 253
Chris@147 254 virtual void execute() {
Chris@147 255 m_model->deletePoint(m_oldPoint);
Chris@147 256 m_model->addPoint(m_newPoint);
Chris@147 257 std::swap(m_oldPoint, m_newPoint);
Chris@147 258 }
Chris@147 259
Chris@147 260 virtual void unexecute() { execute(); }
Chris@147 261
Chris@147 262 private:
Chris@147 263 SparseModel<PointType> *m_model;
Chris@147 264 PointType m_oldPoint;
Chris@147 265 PointType m_newPoint;
Chris@147 266 };
Chris@147 267
Chris@420 268 /**
Chris@420 269 * TabularModel methods.
Chris@420 270 */
Chris@420 271
Chris@420 272 virtual int getRowCount() const
Chris@420 273 {
Chris@420 274 return m_points.size();
Chris@420 275 }
Chris@420 276
Chris@420 277 virtual long getFrameForRow(int row) const
Chris@420 278 {
Chris@420 279 PointListIterator i = getPointListIteratorForRow(row);
Chris@420 280 if (i == m_points.end()) return 0;
Chris@420 281 return i->frame;
Chris@420 282 }
Chris@420 283
Chris@420 284 virtual int getRowForFrame(long frame) const
Chris@420 285 {
Chris@420 286 if (m_rows.empty()) rebuildRowVector();
Chris@420 287 std::vector<long>::iterator i =
Chris@420 288 std::lower_bound(m_rows.begin(), m_rows.end(), frame);
Chris@432 289 int row = std::distance(m_rows.begin(), i);
Chris@432 290 if (i != m_rows.begin() && (i == m_rows.end() || *i != frame)) {
Chris@432 291 --row;
Chris@432 292 }
Chris@432 293 return row;
Chris@420 294 }
Chris@420 295
Chris@420 296 virtual int getColumnCount() const { return 1; }
Chris@425 297 virtual QVariant getData(int row, int column, int role) const
Chris@425 298 {
Chris@425 299 PointListIterator i = getPointListIteratorForRow(row);
Chris@425 300 if (i == m_points.end()) return QVariant();
Chris@425 301
Chris@425 302 switch (column) {
Chris@425 303 case 0: {
Chris@425 304 if (role == SortRole) return int(i->frame);
Chris@425 305 RealTime rt = RealTime::frame2RealTime(i->frame, getSampleRate());
Chris@425 306 if (role == Qt::EditRole) return rt.toString().c_str();
Chris@425 307 else return rt.toText().c_str();
Chris@425 308 }
Chris@425 309 case 1: return int(i->frame);
Chris@425 310 }
Chris@425 311
Chris@420 312 return QVariant();
Chris@420 313 }
Chris@427 314
Chris@425 315 virtual Command *getSetDataCommand(int row, int column,
Chris@425 316 const QVariant &value, int role)
Chris@425 317 {
Chris@425 318 if (role != Qt::EditRole) return false;
Chris@425 319 PointListIterator i = getPointListIteratorForRow(row);
Chris@425 320 if (i == m_points.end()) return false;
Chris@425 321 EditCommand *command = new EditCommand(this, tr("Edit Data"));
Chris@425 322
Chris@425 323 Point point(*i);
Chris@425 324 command->deletePoint(point);
Chris@425 325
Chris@425 326 switch (column) {
Chris@425 327 case 0: point.frame = lrint(value.toDouble() * getSampleRate()); break;
Chris@425 328 case 1: point.frame = value.toInt(); break;
Chris@425 329 }
Chris@425 330
Chris@425 331 command->addPoint(point);
Chris@425 332 return command->finish();
Chris@425 333 }
Chris@425 334
Chris@427 335 virtual Command *getInsertRowCommand(int row)
Chris@427 336 {
Chris@427 337 EditCommand *command = new EditCommand(this, tr("Insert Data Point"));
Chris@427 338 Point point(0);
Chris@427 339 PointListIterator i = getPointListIteratorForRow(row);
Chris@427 340 if (i == m_points.end() && i != m_points.begin()) --i;
Chris@427 341 if (i != m_points.end()) point = *i;
Chris@427 342 command->addPoint(point);
Chris@427 343 return command->finish();
Chris@427 344 }
Chris@427 345
Chris@427 346 virtual Command *getRemoveRowCommand(int row)
Chris@427 347 {
Chris@427 348 EditCommand *command = new EditCommand(this, tr("Delete Data Point"));
Chris@427 349 PointListIterator i = getPointListIteratorForRow(row);
Chris@427 350 if (i == m_points.end()) return 0;
Chris@427 351 command->deletePoint(*i);
Chris@427 352 return command->finish();
Chris@427 353 }
Chris@427 354
Chris@147 355 protected:
Chris@147 356 size_t m_sampleRate;
Chris@147 357 size_t m_resolution;
Chris@147 358 bool m_notifyOnAdd;
Chris@147 359 long m_sinceLastNotifyMin;
Chris@147 360 long m_sinceLastNotifyMax;
Chris@147 361 bool m_hasTextLabels;
Chris@147 362
Chris@147 363 PointList m_points;
Chris@147 364 size_t m_pointCount;
Chris@147 365 mutable QMutex m_mutex;
Chris@147 366 int m_completion;
Chris@420 367
Chris@420 368 void getPointIterators(long frame,
Chris@420 369 PointListIterator &startItr,
Chris@420 370 PointListIterator &endItr) const;
Chris@420 371
Chris@420 372 // This is only used if the model is called on to act in
Chris@420 373 // TabularModel mode
Chris@420 374 mutable std::vector<long> m_rows; // map from row number to frame
Chris@420 375 void rebuildRowVector() const
Chris@420 376 {
Chris@420 377 m_rows.clear();
Chris@420 378 for (PointListIterator i = m_points.begin(); i != m_points.end(); ++i) {
Chris@420 379 m_rows.push_back(i->frame);
Chris@420 380 }
Chris@420 381 }
Chris@420 382
Chris@420 383 PointListIterator getPointListIteratorForRow(int row) const
Chris@420 384 {
Chris@420 385 if (m_rows.empty()) rebuildRowVector();
Chris@425 386 if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end();
Chris@420 387
Chris@420 388 size_t frame = m_rows[row];
Chris@420 389 int indexAtFrame = 0;
Chris@420 390 int ri = row;
Chris@420 391 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; }
Chris@420 392 int initialIndexAtFrame = indexAtFrame;
Chris@420 393
Chris@420 394 PointListIterator i0, i1;
Chris@420 395 getPointIterators(frame, i0, i1);
Chris@420 396 PointListIterator i = i0;
Chris@420 397
Chris@420 398 for (i = i0; i != i1; ++i) {
Chris@420 399 if (indexAtFrame > 0) { --indexAtFrame; continue; }
Chris@420 400 return i;
Chris@420 401 }
Chris@420 402
Chris@420 403 if (indexAtFrame > 0) {
Chris@420 404 std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl;
Chris@420 405 }
Chris@420 406 return i;
Chris@420 407 }
Chris@147 408 };
Chris@147 409
Chris@147 410
Chris@147 411 template <typename PointType>
Chris@147 412 SparseModel<PointType>::SparseModel(size_t sampleRate,
Chris@147 413 size_t resolution,
Chris@147 414 bool notifyOnAdd) :
Chris@147 415 m_sampleRate(sampleRate),
Chris@147 416 m_resolution(resolution),
Chris@147 417 m_notifyOnAdd(notifyOnAdd),
Chris@147 418 m_sinceLastNotifyMin(-1),
Chris@147 419 m_sinceLastNotifyMax(-1),
Chris@147 420 m_hasTextLabels(false),
Chris@147 421 m_pointCount(0),
Chris@147 422 m_completion(100)
Chris@147 423 {
Chris@147 424 }
Chris@147 425
Chris@147 426 template <typename PointType>
Chris@147 427 size_t
Chris@147 428 SparseModel<PointType>::getStartFrame() const
Chris@147 429 {
Chris@147 430 QMutexLocker locker(&m_mutex);
Chris@147 431 size_t f = 0;
Chris@147 432 if (!m_points.empty()) {
Chris@147 433 f = m_points.begin()->frame;
Chris@147 434 }
Chris@147 435 return f;
Chris@147 436 }
Chris@147 437
Chris@147 438 template <typename PointType>
Chris@147 439 size_t
Chris@147 440 SparseModel<PointType>::getEndFrame() const
Chris@147 441 {
Chris@147 442 QMutexLocker locker(&m_mutex);
Chris@147 443 size_t f = 0;
Chris@147 444 if (!m_points.empty()) {
Chris@147 445 PointListIterator i(m_points.end());
Chris@147 446 f = (--i)->frame;
Chris@147 447 }
Chris@147 448 return f;
Chris@147 449 }
Chris@147 450
Chris@147 451 template <typename PointType>
Chris@147 452 Model *
Chris@147 453 SparseModel<PointType>::clone() const
Chris@147 454 {
Chris@425 455 return 0; //!!! is this ever used?
Chris@425 456 /*
Chris@147 457 SparseModel<PointType> *model =
Chris@147 458 new SparseModel<PointType>(m_sampleRate, m_resolution, m_notifyOnAdd);
Chris@147 459 model->m_points = m_points;
Chris@147 460 model->m_pointCount = m_pointCount;
Chris@147 461 return model;
Chris@425 462 */
Chris@147 463 }
Chris@147 464
Chris@147 465 template <typename PointType>
Chris@147 466 bool
Chris@147 467 SparseModel<PointType>::isEmpty() const
Chris@147 468 {
Chris@147 469 return m_pointCount == 0;
Chris@147 470 }
Chris@147 471
Chris@147 472 template <typename PointType>
Chris@147 473 size_t
Chris@147 474 SparseModel<PointType>::getPointCount() const
Chris@147 475 {
Chris@147 476 return m_pointCount;
Chris@147 477 }
Chris@147 478
Chris@147 479 template <typename PointType>
Chris@459 480 const typename SparseModel<PointType>::PointList &
Chris@459 481 SparseModel<PointType>::getPoints() const
Chris@459 482 {
Chris@459 483 return m_points;
Chris@459 484 }
Chris@459 485
Chris@459 486 template <typename PointType>
Chris@147 487 typename SparseModel<PointType>::PointList
Chris@147 488 SparseModel<PointType>::getPoints(long start, long end) const
Chris@147 489 {
Chris@147 490 if (start > end) return PointList();
Chris@147 491 QMutexLocker locker(&m_mutex);
Chris@147 492
Chris@147 493 PointType startPoint(start), endPoint(end);
Chris@147 494
Chris@147 495 PointListIterator startItr = m_points.lower_bound(startPoint);
Chris@147 496 PointListIterator endItr = m_points.upper_bound(endPoint);
Chris@147 497
Chris@147 498 if (startItr != m_points.begin()) --startItr;
Chris@147 499 if (startItr != m_points.begin()) --startItr;
Chris@147 500 if (endItr != m_points.end()) ++endItr;
Chris@147 501 if (endItr != m_points.end()) ++endItr;
Chris@147 502
Chris@147 503 PointList rv;
Chris@147 504
Chris@147 505 for (PointListIterator i = startItr; i != endItr; ++i) {
Chris@147 506 rv.insert(*i);
Chris@147 507 }
Chris@147 508
Chris@147 509 return rv;
Chris@147 510 }
Chris@147 511
Chris@147 512 template <typename PointType>
Chris@147 513 typename SparseModel<PointType>::PointList
Chris@147 514 SparseModel<PointType>::getPoints(long frame) const
Chris@147 515 {
Chris@420 516 PointListIterator startItr, endItr;
Chris@420 517 getPointIterators(frame, startItr, endItr);
Chris@147 518
Chris@147 519 PointList rv;
Chris@147 520
Chris@147 521 for (PointListIterator i = startItr; i != endItr; ++i) {
Chris@147 522 rv.insert(*i);
Chris@147 523 }
Chris@147 524
Chris@147 525 return rv;
Chris@147 526 }
Chris@147 527
Chris@147 528 template <typename PointType>
Chris@420 529 void
Chris@420 530 SparseModel<PointType>::getPointIterators(long frame,
Chris@420 531 PointListIterator &startItr,
Chris@420 532 PointListIterator &endItr) const
Chris@420 533 {
Chris@420 534 QMutexLocker locker(&m_mutex);
Chris@420 535
Chris@420 536 if (m_resolution == 0) {
Chris@420 537 startItr = m_points.end();
Chris@420 538 endItr = m_points.end();
Chris@420 539 return;
Chris@420 540 }
Chris@420 541
Chris@420 542 long start = (frame / m_resolution) * m_resolution;
Chris@420 543 long end = start + m_resolution;
Chris@420 544
Chris@420 545 PointType startPoint(start), endPoint(end);
Chris@420 546
Chris@420 547 startItr = m_points.lower_bound(startPoint);
Chris@420 548 endItr = m_points.upper_bound(endPoint);
Chris@420 549 }
Chris@420 550
Chris@420 551 template <typename PointType>
Chris@147 552 typename SparseModel<PointType>::PointList
Chris@147 553 SparseModel<PointType>::getPreviousPoints(long originFrame) const
Chris@147 554 {
Chris@147 555 QMutexLocker locker(&m_mutex);
Chris@147 556
Chris@147 557 PointType lookupPoint(originFrame);
Chris@147 558 PointList rv;
Chris@147 559
Chris@147 560 PointListIterator i = m_points.lower_bound(lookupPoint);
Chris@147 561 if (i == m_points.begin()) return rv;
Chris@147 562
Chris@147 563 --i;
Chris@147 564 long frame = i->frame;
Chris@147 565 while (i->frame == frame) {
Chris@147 566 rv.insert(*i);
Chris@147 567 if (i == m_points.begin()) break;
Chris@147 568 --i;
Chris@147 569 }
Chris@147 570
Chris@147 571 return rv;
Chris@147 572 }
Chris@147 573
Chris@147 574 template <typename PointType>
Chris@147 575 typename SparseModel<PointType>::PointList
Chris@147 576 SparseModel<PointType>::getNextPoints(long originFrame) const
Chris@147 577 {
Chris@147 578 QMutexLocker locker(&m_mutex);
Chris@147 579
Chris@147 580 PointType lookupPoint(originFrame);
Chris@147 581 PointList rv;
Chris@147 582
Chris@147 583 PointListIterator i = m_points.upper_bound(lookupPoint);
Chris@147 584 if (i == m_points.end()) return rv;
Chris@147 585
Chris@147 586 long frame = i->frame;
Chris@147 587 while (i != m_points.end() && i->frame == frame) {
Chris@147 588 rv.insert(*i);
Chris@147 589 ++i;
Chris@147 590 }
Chris@147 591
Chris@147 592 return rv;
Chris@147 593 }
Chris@147 594
Chris@147 595 template <typename PointType>
Chris@147 596 void
Chris@147 597 SparseModel<PointType>::setResolution(size_t resolution)
Chris@147 598 {
Chris@147 599 {
Chris@147 600 QMutexLocker locker(&m_mutex);
Chris@147 601 m_resolution = resolution;
Chris@147 602 }
Chris@420 603 m_rows.clear();
Chris@147 604 emit modelChanged();
Chris@147 605 }
Chris@147 606
Chris@147 607 template <typename PointType>
Chris@147 608 void
Chris@147 609 SparseModel<PointType>::clear()
Chris@147 610 {
Chris@147 611 {
Chris@147 612 QMutexLocker locker(&m_mutex);
Chris@147 613 m_points.clear();
Chris@147 614 m_pointCount = 0;
Chris@147 615 }
Chris@420 616 m_rows.clear();
Chris@147 617 emit modelChanged();
Chris@147 618 }
Chris@147 619
Chris@147 620 template <typename PointType>
Chris@147 621 void
Chris@147 622 SparseModel<PointType>::addPoint(const PointType &point)
Chris@147 623 {
Chris@147 624 {
Chris@147 625 QMutexLocker locker(&m_mutex);
Chris@147 626 m_points.insert(point);
Chris@147 627 m_pointCount++;
Chris@338 628 if (point.getLabel() != "") m_hasTextLabels = true;
Chris@147 629 }
Chris@147 630
Chris@147 631 // Even though this model is nominally sparse, there may still be
Chris@147 632 // too many signals going on here (especially as they'll probably
Chris@147 633 // be queued from one thread to another), which is why we need the
Chris@147 634 // notifyOnAdd as an option rather than a necessity (the
Chris@147 635 // alternative is to notify on setCompletion).
Chris@147 636
Chris@147 637 if (m_notifyOnAdd) {
Chris@420 638 m_rows.clear(); //!!! inefficient
Chris@147 639 emit modelChanged(point.frame, point.frame + m_resolution);
Chris@147 640 } else {
Chris@147 641 if (m_sinceLastNotifyMin == -1 ||
Chris@147 642 point.frame < m_sinceLastNotifyMin) {
Chris@147 643 m_sinceLastNotifyMin = point.frame;
Chris@147 644 }
Chris@147 645 if (m_sinceLastNotifyMax == -1 ||
Chris@147 646 point.frame > m_sinceLastNotifyMax) {
Chris@147 647 m_sinceLastNotifyMax = point.frame;
Chris@147 648 }
Chris@147 649 }
Chris@147 650 }
Chris@147 651
Chris@147 652 template <typename PointType>
Chris@147 653 void
Chris@147 654 SparseModel<PointType>::deletePoint(const PointType &point)
Chris@147 655 {
Chris@147 656 {
Chris@147 657 QMutexLocker locker(&m_mutex);
Chris@147 658
Chris@147 659 PointListIterator i = m_points.lower_bound(point);
Chris@147 660 typename PointType::Comparator comparator;
Chris@147 661 while (i != m_points.end()) {
Chris@147 662 if (i->frame > point.frame) break;
Chris@147 663 if (!comparator(*i, point) && !comparator(point, *i)) {
Chris@147 664 m_points.erase(i);
Chris@147 665 m_pointCount--;
Chris@147 666 break;
Chris@147 667 }
Chris@147 668 ++i;
Chris@147 669 }
Chris@147 670 }
Chris@147 671 // std::cout << "SparseOneDimensionalModel: emit modelChanged("
Chris@147 672 // << point.frame << ")" << std::endl;
Chris@420 673 m_rows.clear(); //!!! inefficient
Chris@147 674 emit modelChanged(point.frame, point.frame + m_resolution);
Chris@147 675 }
Chris@147 676
Chris@147 677 template <typename PointType>
Chris@147 678 void
Chris@333 679 SparseModel<PointType>::setCompletion(int completion, bool update)
Chris@147 680 {
Chris@301 681 // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl;
Chris@191 682
Chris@147 683 if (m_completion != completion) {
Chris@147 684 m_completion = completion;
Chris@147 685
Chris@147 686 if (completion == 100) {
Chris@147 687
Chris@297 688 if (!m_notifyOnAdd) {
Chris@297 689 emit completionChanged();
Chris@297 690 }
Chris@297 691
Chris@147 692 m_notifyOnAdd = true; // henceforth
Chris@420 693 m_rows.clear(); //!!! inefficient
Chris@147 694 emit modelChanged();
Chris@147 695
Chris@147 696 } else if (!m_notifyOnAdd) {
Chris@147 697
Chris@333 698 if (update &&
Chris@333 699 m_sinceLastNotifyMin >= 0 &&
Chris@147 700 m_sinceLastNotifyMax >= 0) {
Chris@420 701 m_rows.clear(); //!!! inefficient
Chris@147 702 emit modelChanged(m_sinceLastNotifyMin, m_sinceLastNotifyMax);
Chris@147 703 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1;
Chris@147 704 } else {
Chris@147 705 emit completionChanged();
Chris@147 706 }
Chris@147 707 } else {
Chris@147 708 emit completionChanged();
Chris@147 709 }
Chris@147 710 }
Chris@147 711 }
Chris@147 712
Chris@147 713 template <typename PointType>
Chris@147 714 void
Chris@147 715 SparseModel<PointType>::toXml(QTextStream &out,
Chris@147 716 QString indent,
Chris@147 717 QString extraAttributes) const
Chris@147 718 {
Chris@318 719 std::cerr << "SparseModel::toXml: extraAttributes = \""
Chris@318 720 << extraAttributes.toStdString() << std::endl;
Chris@318 721
Chris@407 722 QString type = getXmlOutputType();
Chris@407 723
Chris@147 724 Model::toXml
Chris@147 725 (out,
Chris@147 726 indent,
Chris@407 727 QString("type=\"%1\" dimensions=\"%2\" resolution=\"%3\" notifyOnAdd=\"%4\" dataset=\"%5\" %6")
Chris@407 728 .arg(type)
Chris@147 729 .arg(PointType(0).getDimensions())
Chris@147 730 .arg(m_resolution)
Chris@147 731 .arg(m_notifyOnAdd ? "true" : "false")
Chris@147 732 .arg(getObjectExportId(&m_points))
Chris@147 733 .arg(extraAttributes));
Chris@147 734
Chris@147 735 out << indent;
Chris@147 736 out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n")
Chris@147 737 .arg(getObjectExportId(&m_points))
Chris@147 738 .arg(PointType(0).getDimensions());
Chris@147 739
Chris@147 740 for (PointListIterator i = m_points.begin(); i != m_points.end(); ++i) {
Chris@314 741 i->toXml(out, indent + " ");
Chris@147 742 }
Chris@147 743
Chris@147 744 out << indent;
Chris@147 745 out << "</dataset>\n";
Chris@147 746 }
Chris@147 747
Chris@147 748 template <typename PointType>
Chris@147 749 SparseModel<PointType>::EditCommand::EditCommand(SparseModel *model,
Chris@147 750 QString commandName) :
Chris@147 751 MacroCommand(commandName),
Chris@147 752 m_model(model)
Chris@147 753 {
Chris@147 754 }
Chris@147 755
Chris@147 756 template <typename PointType>
Chris@147 757 void
Chris@147 758 SparseModel<PointType>::EditCommand::addPoint(const PointType &point)
Chris@147 759 {
Chris@147 760 addCommand(new AddPointCommand(m_model, point), true);
Chris@147 761 }
Chris@147 762
Chris@147 763 template <typename PointType>
Chris@147 764 void
Chris@147 765 SparseModel<PointType>::EditCommand::deletePoint(const PointType &point)
Chris@147 766 {
Chris@147 767 addCommand(new DeletePointCommand(m_model, point), true);
Chris@147 768 }
Chris@147 769
Chris@147 770 template <typename PointType>
Chris@416 771 typename SparseModel<PointType>::EditCommand *
Chris@147 772 SparseModel<PointType>::EditCommand::finish()
Chris@147 773 {
Chris@147 774 if (!m_commands.empty()) {
Chris@387 775 return this;
Chris@147 776 } else {
Chris@147 777 delete this;
Chris@389 778 return 0;
Chris@147 779 }
Chris@147 780 }
Chris@147 781
Chris@147 782 template <typename PointType>
Chris@147 783 void
Chris@147 784 SparseModel<PointType>::EditCommand::addCommand(Command *command,
Chris@147 785 bool executeFirst)
Chris@147 786 {
Chris@147 787 if (executeFirst) command->execute();
Chris@147 788
Chris@147 789 if (!m_commands.empty()) {
Chris@147 790 DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command);
Chris@147 791 if (dpc) {
Chris@147 792 AddPointCommand *apc = dynamic_cast<AddPointCommand *>
Chris@147 793 (m_commands[m_commands.size() - 1]);
Chris@147 794 typename PointType::Comparator comparator;
Chris@147 795 if (apc) {
Chris@147 796 if (!comparator(apc->getPoint(), dpc->getPoint()) &&
Chris@147 797 !comparator(dpc->getPoint(), apc->getPoint())) {
Chris@147 798 deleteCommand(apc);
Chris@147 799 return;
Chris@147 800 }
Chris@147 801 }
Chris@147 802 }
Chris@147 803 }
Chris@147 804
Chris@147 805 MacroCommand::addCommand(command);
Chris@147 806 }
Chris@147 807
Chris@147 808
Chris@147 809 #endif
Chris@147 810
Chris@147 811
Chris@147 812