svcore
1.9
|
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 "TabularModel.h" 00021 #include "base/Command.h" 00022 #include "base/RealTime.h" 00023 00024 #include <iostream> 00025 00026 #include <set> 00027 #include <vector> 00028 #include <algorithm> 00029 #include <iterator> 00030 00031 #include <cmath> 00032 00033 #include <QMutex> 00034 #include <QTextStream> 00035 00041 template <typename PointType> 00042 class SparseModel : public Model, 00043 public TabularModel 00044 { 00045 public: 00046 SparseModel(int sampleRate, int resolution, 00047 bool notifyOnAdd = true); 00048 virtual ~SparseModel() { } 00049 00050 virtual bool isOK() const { return true; } 00051 virtual int getStartFrame() const; 00052 virtual int getEndFrame() const; 00053 virtual int getSampleRate() const { return m_sampleRate; } 00054 00055 virtual Model *clone() const; 00056 00057 // Number of frames of the underlying sample rate that this model 00058 // is capable of resolving to. For example, if m_resolution == 10 00059 // then every point in this model will be at a multiple of 10 00060 // sample frames and should be considered to cover a window ending 00061 // 10 sample frames later. 00062 virtual int getResolution() const { 00063 return m_resolution ? m_resolution : 1; 00064 } 00065 virtual void setResolution(int resolution); 00066 00067 typedef PointType Point; 00068 typedef std::multiset<PointType, 00069 typename PointType::OrderComparator> PointList; 00070 typedef typename PointList::iterator PointListIterator; 00071 typedef typename PointList::const_iterator PointListConstIterator; 00072 00076 virtual bool isEmpty() const; 00077 00081 virtual int getPointCount() const; 00082 00086 virtual const PointList &getPoints() const; 00087 00094 virtual PointList getPoints(long start, long end) const; 00095 00100 virtual PointList getPoints(long frame) const; 00101 00106 virtual PointList getPreviousPoints(long frame) const; 00107 00112 virtual PointList getNextPoints(long frame) const; 00113 00117 virtual void clear(); 00118 00122 virtual void addPoint(const PointType &point); 00123 00130 virtual void deletePoint(const PointType &point); 00131 00132 virtual bool isReady(int *completion = 0) const { 00133 bool ready = isOK() && (m_completion == 100); 00134 if (completion) *completion = m_completion; 00135 return ready; 00136 } 00137 00138 virtual void setCompletion(int completion, bool update = true); 00139 virtual int getCompletion() const { return m_completion; } 00140 00141 virtual bool hasTextLabels() const { return m_hasTextLabels; } 00142 00143 QString getTypeName() const { return tr("Sparse"); } 00144 00145 virtual QString getXmlOutputType() const { return "sparse"; } 00146 00147 virtual void toXml(QTextStream &out, 00148 QString indent = "", 00149 QString extraAttributes = "") const; 00150 00151 virtual QString toDelimitedDataString(QString delimiter) const 00152 { 00153 QString s; 00154 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { 00155 s += i->toDelimitedDataString(delimiter, m_sampleRate) + "\n"; 00156 } 00157 return s; 00158 } 00159 00160 virtual QString toDelimitedDataStringSubset(QString delimiter, int f0, int f1) const 00161 { 00162 QString s; 00163 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { 00164 if (i->frame >= (long)f0 && i->frame < (long)f1) { 00165 s += i->toDelimitedDataString(delimiter, m_sampleRate) + "\n"; 00166 } 00167 } 00168 return s; 00169 } 00170 00174 class AddPointCommand : public Command 00175 { 00176 public: 00177 AddPointCommand(SparseModel<PointType> *model, 00178 const PointType &point, 00179 QString name = "") : 00180 m_model(model), m_point(point), m_name(name) { } 00181 00182 virtual QString getName() const { 00183 return (m_name == "" ? tr("Add Point") : m_name); 00184 } 00185 00186 virtual void execute() { m_model->addPoint(m_point); } 00187 virtual void unexecute() { m_model->deletePoint(m_point); } 00188 00189 const PointType &getPoint() const { return m_point; } 00190 00191 private: 00192 SparseModel<PointType> *m_model; 00193 PointType m_point; 00194 QString m_name; 00195 }; 00196 00197 00201 class DeletePointCommand : public Command 00202 { 00203 public: 00204 DeletePointCommand(SparseModel<PointType> *model, 00205 const PointType &point) : 00206 m_model(model), m_point(point) { } 00207 00208 virtual QString getName() const { return tr("Delete Point"); } 00209 00210 virtual void execute() { m_model->deletePoint(m_point); } 00211 virtual void unexecute() { m_model->addPoint(m_point); } 00212 00213 const PointType &getPoint() const { return m_point; } 00214 00215 private: 00216 SparseModel<PointType> *m_model; 00217 PointType m_point; 00218 }; 00219 00220 00225 class EditCommand : public MacroCommand 00226 { 00227 public: 00228 EditCommand(SparseModel<PointType> *model, QString commandName); 00229 00230 virtual void addPoint(const PointType &point); 00231 virtual void deletePoint(const PointType &point); 00232 00236 virtual void addCommand(Command *command) { addCommand(command, true); } 00237 00243 virtual EditCommand *finish(); 00244 00245 protected: 00246 virtual void addCommand(Command *command, bool executeFirst); 00247 00248 SparseModel<PointType> *m_model; 00249 }; 00250 00251 00255 class RelabelCommand : public Command 00256 { 00257 public: 00258 RelabelCommand(SparseModel<PointType> *model, 00259 const PointType &point, 00260 QString newLabel) : 00261 m_model(model), m_oldPoint(point), m_newPoint(point) { 00262 m_newPoint.label = newLabel; 00263 } 00264 00265 virtual QString getName() const { return tr("Re-Label Point"); } 00266 00267 virtual void execute() { 00268 m_model->deletePoint(m_oldPoint); 00269 m_model->addPoint(m_newPoint); 00270 std::swap(m_oldPoint, m_newPoint); 00271 } 00272 00273 virtual void unexecute() { execute(); } 00274 00275 private: 00276 SparseModel<PointType> *m_model; 00277 PointType m_oldPoint; 00278 PointType m_newPoint; 00279 }; 00280 00285 virtual int getRowCount() const 00286 { 00287 return m_points.size(); 00288 } 00289 00290 virtual long getFrameForRow(int row) const 00291 { 00292 PointListConstIterator i = getPointListIteratorForRow(row); 00293 if (i == m_points.end()) return 0; 00294 return i->frame; 00295 } 00296 00297 virtual int getRowForFrame(long frame) const 00298 { 00299 if (m_rows.empty()) rebuildRowVector(); 00300 std::vector<long>::iterator i = 00301 std::lower_bound(m_rows.begin(), m_rows.end(), frame); 00302 #if defined(__SUNPRO_CC) && defined(__STD_RW_ITERATOR__) 00303 int row = 0; 00304 std::distance(m_rows.begin(), i, row); 00305 #else 00306 int row = std::distance(m_rows.begin(), i); 00307 #endif 00308 if (i != m_rows.begin() && (i == m_rows.end() || *i != frame)) { 00309 --row; 00310 } 00311 return row; 00312 } 00313 00314 virtual int getColumnCount() const { return 1; } 00315 virtual QVariant getData(int row, int column, int role) const 00316 { 00317 PointListConstIterator i = getPointListIteratorForRow(row); 00318 if (i == m_points.end()) return QVariant(); 00319 00320 switch (column) { 00321 case 0: { 00322 if (role == SortRole) return int(i->frame); 00323 RealTime rt = RealTime::frame2RealTime(i->frame, getSampleRate()); 00324 if (role == Qt::EditRole) return rt.toString().c_str(); 00325 else return rt.toText().c_str(); 00326 } 00327 case 1: return int(i->frame); 00328 } 00329 00330 return QVariant(); 00331 } 00332 00333 virtual Command *getSetDataCommand(int row, int column, 00334 const QVariant &value, int role) 00335 { 00336 if (role != Qt::EditRole) return 0; 00337 PointListIterator i = getPointListIteratorForRow(row); 00338 if (i == m_points.end()) return 0; 00339 EditCommand *command = new EditCommand(this, tr("Edit Data")); 00340 00341 Point point(*i); 00342 command->deletePoint(point); 00343 00344 switch (column) { 00345 case 0: point.frame = lrint(value.toDouble() * getSampleRate()); break; 00346 case 1: point.frame = value.toInt(); break; 00347 } 00348 00349 command->addPoint(point); 00350 return command->finish(); 00351 } 00352 00353 virtual Command *getInsertRowCommand(int row) 00354 { 00355 EditCommand *command = new EditCommand(this, tr("Insert Data Point")); 00356 Point point(0); 00357 PointListIterator i = getPointListIteratorForRow(row); 00358 if (i == m_points.end() && i != m_points.begin()) --i; 00359 if (i != m_points.end()) point = *i; 00360 command->addPoint(point); 00361 return command->finish(); 00362 } 00363 00364 virtual Command *getRemoveRowCommand(int row) 00365 { 00366 PointListIterator i = getPointListIteratorForRow(row); 00367 if (i == m_points.end()) return 0; 00368 EditCommand *command = new EditCommand(this, tr("Delete Data Point")); 00369 command->deletePoint(*i); 00370 return command->finish(); 00371 } 00372 00373 protected: 00374 int m_sampleRate; 00375 int m_resolution; 00376 bool m_notifyOnAdd; 00377 long m_sinceLastNotifyMin; 00378 long m_sinceLastNotifyMax; 00379 bool m_hasTextLabels; 00380 00381 PointList m_points; 00382 int m_pointCount; 00383 mutable QMutex m_mutex; 00384 int m_completion; 00385 00386 void getPointIterators(long frame, 00387 PointListIterator &startItr, 00388 PointListIterator &endItr); 00389 void getPointIterators(long frame, 00390 PointListConstIterator &startItr, 00391 PointListConstIterator &endItr) const; 00392 00393 // This is only used if the model is called on to act in 00394 // TabularModel mode 00395 mutable std::vector<long> m_rows; // map from row number to frame 00396 void rebuildRowVector() const 00397 { 00398 m_rows.clear(); 00399 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { 00400 // std::cerr << "rebuildRowVector: row " << m_rows.size() << " -> " << i->frame << std::endl; 00401 m_rows.push_back(i->frame); 00402 } 00403 } 00404 00405 PointListIterator getPointListIteratorForRow(int row) 00406 { 00407 if (m_rows.empty()) rebuildRowVector(); 00408 if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end(); 00409 00410 int frame = m_rows[row]; 00411 int indexAtFrame = 0; 00412 int ri = row; 00413 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; } 00414 int initialIndexAtFrame = indexAtFrame; 00415 00416 PointListIterator i0, i1; 00417 getPointIterators(frame, i0, i1); 00418 PointListIterator i = i0; 00419 00420 for (i = i0; i != i1; ++i) { 00421 if (i->frame < (int)frame) { continue; } 00422 if (indexAtFrame > 0) { --indexAtFrame; continue; } 00423 return i; 00424 } 00425 00426 if (indexAtFrame > 0) { 00427 std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl; 00428 } 00429 return i; 00430 } 00431 00432 PointListConstIterator getPointListIteratorForRow(int row) const 00433 { 00434 if (m_rows.empty()) rebuildRowVector(); 00435 if (row < 0 || row + 1 > int(m_rows.size())) return m_points.end(); 00436 00437 int frame = m_rows[row]; 00438 int indexAtFrame = 0; 00439 int ri = row; 00440 while (ri > 0 && m_rows[ri-1] == m_rows[row]) { --ri; ++indexAtFrame; } 00441 int initialIndexAtFrame = indexAtFrame; 00442 00443 // std::cerr << "getPointListIteratorForRow " << row << ": initialIndexAtFrame = " << initialIndexAtFrame << std::endl; 00444 00445 PointListConstIterator i0, i1; 00446 getPointIterators(frame, i0, i1); 00447 PointListConstIterator i = i0; 00448 00449 for (i = i0; i != i1; ++i) { 00450 // std::cerr << "i->frame is " << i->frame << ", wanting " << frame << std::endl; 00451 00452 if (i->frame < (int)frame) { continue; } 00453 if (indexAtFrame > 0) { --indexAtFrame; continue; } 00454 return i; 00455 } 00456 00457 // std::cerr << "returning i with i->frame = " << i->frame << std::endl; 00458 00459 if (indexAtFrame > 0) { 00460 std::cerr << "WARNING: SparseModel::getPointListIteratorForRow: No iterator available for row " << row << " (frame = " << frame << ", index at frame = " << initialIndexAtFrame << ", leftover index " << indexAtFrame << ")" << std::endl; 00461 } 00462 return i; 00463 } 00464 }; 00465 00466 00467 template <typename PointType> 00468 SparseModel<PointType>::SparseModel(int sampleRate, 00469 int resolution, 00470 bool notifyOnAdd) : 00471 m_sampleRate(sampleRate), 00472 m_resolution(resolution), 00473 m_notifyOnAdd(notifyOnAdd), 00474 m_sinceLastNotifyMin(-1), 00475 m_sinceLastNotifyMax(-1), 00476 m_hasTextLabels(false), 00477 m_pointCount(0), 00478 m_completion(100) 00479 { 00480 } 00481 00482 template <typename PointType> 00483 int 00484 SparseModel<PointType>::getStartFrame() const 00485 { 00486 QMutexLocker locker(&m_mutex); 00487 int f = 0; 00488 if (!m_points.empty()) { 00489 f = m_points.begin()->frame; 00490 } 00491 return f; 00492 } 00493 00494 template <typename PointType> 00495 int 00496 SparseModel<PointType>::getEndFrame() const 00497 { 00498 QMutexLocker locker(&m_mutex); 00499 int f = 0; 00500 if (!m_points.empty()) { 00501 PointListConstIterator i(m_points.end()); 00502 f = (--i)->frame; 00503 } 00504 return f; 00505 } 00506 00507 template <typename PointType> 00508 Model * 00509 SparseModel<PointType>::clone() const 00510 { 00511 return 0; 00512 /* 00513 SparseModel<PointType> *model = 00514 new SparseModel<PointType>(m_sampleRate, m_resolution, m_notifyOnAdd); 00515 model->m_points = m_points; 00516 model->m_pointCount = m_pointCount; 00517 return model; 00518 */ 00519 } 00520 00521 template <typename PointType> 00522 bool 00523 SparseModel<PointType>::isEmpty() const 00524 { 00525 return m_pointCount == 0; 00526 } 00527 00528 template <typename PointType> 00529 int 00530 SparseModel<PointType>::getPointCount() const 00531 { 00532 return m_pointCount; 00533 } 00534 00535 template <typename PointType> 00536 const typename SparseModel<PointType>::PointList & 00537 SparseModel<PointType>::getPoints() const 00538 { 00539 return m_points; 00540 } 00541 00542 template <typename PointType> 00543 typename SparseModel<PointType>::PointList 00544 SparseModel<PointType>::getPoints(long start, long end) const 00545 { 00546 if (start > end) return PointList(); 00547 QMutexLocker locker(&m_mutex); 00548 00549 PointType startPoint(start), endPoint(end); 00550 00551 PointListConstIterator startItr = m_points.lower_bound(startPoint); 00552 PointListConstIterator endItr = m_points.upper_bound(endPoint); 00553 00554 if (startItr != m_points.begin()) --startItr; 00555 if (startItr != m_points.begin()) --startItr; 00556 if (endItr != m_points.end()) ++endItr; 00557 if (endItr != m_points.end()) ++endItr; 00558 00559 PointList rv; 00560 00561 for (PointListConstIterator i = startItr; i != endItr; ++i) { 00562 rv.insert(*i); 00563 } 00564 00565 return rv; 00566 } 00567 00568 template <typename PointType> 00569 typename SparseModel<PointType>::PointList 00570 SparseModel<PointType>::getPoints(long frame) const 00571 { 00572 PointListConstIterator startItr, endItr; 00573 getPointIterators(frame, startItr, endItr); 00574 00575 PointList rv; 00576 00577 for (PointListConstIterator i = startItr; i != endItr; ++i) { 00578 rv.insert(*i); 00579 } 00580 00581 return rv; 00582 } 00583 00584 template <typename PointType> 00585 void 00586 SparseModel<PointType>::getPointIterators(long frame, 00587 PointListIterator &startItr, 00588 PointListIterator &endItr) 00589 { 00590 QMutexLocker locker(&m_mutex); 00591 00592 if (m_resolution == 0) { 00593 startItr = m_points.end(); 00594 endItr = m_points.end(); 00595 return; 00596 } 00597 00598 long start = (frame / m_resolution) * m_resolution; 00599 long end = start + m_resolution; 00600 00601 PointType startPoint(start), endPoint(end); 00602 00603 startItr = m_points.lower_bound(startPoint); 00604 endItr = m_points.upper_bound(endPoint); 00605 } 00606 00607 template <typename PointType> 00608 void 00609 SparseModel<PointType>::getPointIterators(long frame, 00610 PointListConstIterator &startItr, 00611 PointListConstIterator &endItr) const 00612 { 00613 QMutexLocker locker(&m_mutex); 00614 00615 if (m_resolution == 0) { 00616 // std::cerr << "getPointIterators: resolution == 0, returning end()" << std::endl; 00617 startItr = m_points.end(); 00618 endItr = m_points.end(); 00619 return; 00620 } 00621 00622 long start = (frame / m_resolution) * m_resolution; 00623 long end = start + m_resolution; 00624 00625 PointType startPoint(start), endPoint(end); 00626 00627 // std::cerr << "getPointIterators: start frame " << start << ", end frame " << end << ", m_resolution " << m_resolution << std::endl; 00628 00629 startItr = m_points.lower_bound(startPoint); 00630 endItr = m_points.upper_bound(endPoint); 00631 } 00632 00633 template <typename PointType> 00634 typename SparseModel<PointType>::PointList 00635 SparseModel<PointType>::getPreviousPoints(long originFrame) const 00636 { 00637 QMutexLocker locker(&m_mutex); 00638 00639 PointType lookupPoint(originFrame); 00640 PointList rv; 00641 00642 PointListConstIterator i = m_points.lower_bound(lookupPoint); 00643 if (i == m_points.begin()) return rv; 00644 00645 --i; 00646 long frame = i->frame; 00647 while (i->frame == frame) { 00648 rv.insert(*i); 00649 if (i == m_points.begin()) break; 00650 --i; 00651 } 00652 00653 return rv; 00654 } 00655 00656 template <typename PointType> 00657 typename SparseModel<PointType>::PointList 00658 SparseModel<PointType>::getNextPoints(long originFrame) const 00659 { 00660 QMutexLocker locker(&m_mutex); 00661 00662 PointType lookupPoint(originFrame); 00663 PointList rv; 00664 00665 PointListConstIterator i = m_points.upper_bound(lookupPoint); 00666 if (i == m_points.end()) return rv; 00667 00668 long frame = i->frame; 00669 while (i != m_points.end() && i->frame == frame) { 00670 rv.insert(*i); 00671 ++i; 00672 } 00673 00674 return rv; 00675 } 00676 00677 template <typename PointType> 00678 void 00679 SparseModel<PointType>::setResolution(int resolution) 00680 { 00681 { 00682 QMutexLocker locker(&m_mutex); 00683 m_resolution = resolution; 00684 } 00685 m_rows.clear(); 00686 emit modelChanged(); 00687 } 00688 00689 template <typename PointType> 00690 void 00691 SparseModel<PointType>::clear() 00692 { 00693 { 00694 QMutexLocker locker(&m_mutex); 00695 m_points.clear(); 00696 m_pointCount = 0; 00697 } 00698 m_rows.clear(); 00699 emit modelChanged(); 00700 } 00701 00702 template <typename PointType> 00703 void 00704 SparseModel<PointType>::addPoint(const PointType &point) 00705 { 00706 { 00707 QMutexLocker locker(&m_mutex); 00708 m_points.insert(point); 00709 m_pointCount++; 00710 if (point.getLabel() != "") m_hasTextLabels = true; 00711 } 00712 00713 // Even though this model is nominally sparse, there may still be 00714 // too many signals going on here (especially as they'll probably 00715 // be queued from one thread to another), which is why we need the 00716 // notifyOnAdd as an option rather than a necessity (the 00717 // alternative is to notify on setCompletion). 00718 00719 if (m_notifyOnAdd) { 00720 m_rows.clear(); 00721 emit modelChangedWithin(point.frame, point.frame + m_resolution); 00722 } else { 00723 if (m_sinceLastNotifyMin == -1 || 00724 point.frame < m_sinceLastNotifyMin) { 00725 m_sinceLastNotifyMin = point.frame; 00726 } 00727 if (m_sinceLastNotifyMax == -1 || 00728 point.frame > m_sinceLastNotifyMax) { 00729 m_sinceLastNotifyMax = point.frame; 00730 } 00731 } 00732 } 00733 00734 template <typename PointType> 00735 void 00736 SparseModel<PointType>::deletePoint(const PointType &point) 00737 { 00738 { 00739 QMutexLocker locker(&m_mutex); 00740 00741 PointListIterator i = m_points.lower_bound(point); 00742 typename PointType::Comparator comparator; 00743 while (i != m_points.end()) { 00744 if (i->frame > point.frame) break; 00745 if (!comparator(*i, point) && !comparator(point, *i)) { 00746 m_points.erase(i); 00747 m_pointCount--; 00748 break; 00749 } 00750 ++i; 00751 } 00752 } 00753 // std::cout << "SparseOneDimensionalModel: emit modelChanged(" 00754 // << point.frame << ")" << std::endl; 00755 m_rows.clear(); 00756 emit modelChangedWithin(point.frame, point.frame + m_resolution); 00757 } 00758 00759 template <typename PointType> 00760 void 00761 SparseModel<PointType>::setCompletion(int completion, bool update) 00762 { 00763 // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl; 00764 00765 if (m_completion != completion) { 00766 m_completion = completion; 00767 00768 if (completion == 100) { 00769 00770 if (!m_notifyOnAdd) { 00771 emit completionChanged(); 00772 } 00773 00774 m_notifyOnAdd = true; // henceforth 00775 m_rows.clear(); 00776 emit modelChanged(); 00777 00778 } else if (!m_notifyOnAdd) { 00779 00780 if (update && 00781 m_sinceLastNotifyMin >= 0 && 00782 m_sinceLastNotifyMax >= 0) { 00783 m_rows.clear(); 00784 emit modelChangedWithin(m_sinceLastNotifyMin, m_sinceLastNotifyMax); 00785 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1; 00786 } else { 00787 emit completionChanged(); 00788 } 00789 } else { 00790 emit completionChanged(); 00791 } 00792 } 00793 } 00794 00795 template <typename PointType> 00796 void 00797 SparseModel<PointType>::toXml(QTextStream &out, 00798 QString indent, 00799 QString extraAttributes) const 00800 { 00801 // std::cerr << "SparseModel::toXml: extraAttributes = \"" 00802 // << extraAttributes.toStdString() << std::endl; 00803 00804 QString type = getXmlOutputType(); 00805 00806 Model::toXml 00807 (out, 00808 indent, 00809 QString("type=\"%1\" dimensions=\"%2\" resolution=\"%3\" notifyOnAdd=\"%4\" dataset=\"%5\" %6") 00810 .arg(type) 00811 .arg(PointType(0).getDimensions()) 00812 .arg(m_resolution) 00813 .arg(m_notifyOnAdd ? "true" : "false") 00814 .arg(getObjectExportId(&m_points)) 00815 .arg(extraAttributes)); 00816 00817 out << indent; 00818 out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n") 00819 .arg(getObjectExportId(&m_points)) 00820 .arg(PointType(0).getDimensions()); 00821 00822 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { 00823 i->toXml(out, indent + " "); 00824 } 00825 00826 out << indent; 00827 out << "</dataset>\n"; 00828 } 00829 00830 template <typename PointType> 00831 SparseModel<PointType>::EditCommand::EditCommand(SparseModel *model, 00832 QString commandName) : 00833 MacroCommand(commandName), 00834 m_model(model) 00835 { 00836 } 00837 00838 template <typename PointType> 00839 void 00840 SparseModel<PointType>::EditCommand::addPoint(const PointType &point) 00841 { 00842 addCommand(new AddPointCommand(m_model, point), true); 00843 } 00844 00845 template <typename PointType> 00846 void 00847 SparseModel<PointType>::EditCommand::deletePoint(const PointType &point) 00848 { 00849 addCommand(new DeletePointCommand(m_model, point), true); 00850 } 00851 00852 template <typename PointType> 00853 typename SparseModel<PointType>::EditCommand * 00854 SparseModel<PointType>::EditCommand::finish() 00855 { 00856 if (!m_commands.empty()) { 00857 return this; 00858 } else { 00859 delete this; 00860 return 0; 00861 } 00862 } 00863 00864 template <typename PointType> 00865 void 00866 SparseModel<PointType>::EditCommand::addCommand(Command *command, 00867 bool executeFirst) 00868 { 00869 if (executeFirst) command->execute(); 00870 00871 if (!m_commands.empty()) { 00872 DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command); 00873 if (dpc) { 00874 AddPointCommand *apc = dynamic_cast<AddPointCommand *> 00875 (m_commands[m_commands.size() - 1]); 00876 typename PointType::Comparator comparator; 00877 if (apc) { 00878 if (!comparator(apc->getPoint(), dpc->getPoint()) && 00879 !comparator(dpc->getPoint(), apc->getPoint())) { 00880 deleteCommand(apc); 00881 return; 00882 } 00883 } 00884 } 00885 } 00886 00887 MacroCommand::addCommand(command); 00888 } 00889 00890 00891 #endif 00892 00893 00894