annotate data/model/SparseModel.h @ 422:4caa28a0a8a2

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