Mercurial > hg > svcore
comparison data/model/SparseModel.h @ 1527:710e6250a401 zoom
Merge from default branch
author | Chris Cannam |
---|---|
date | Mon, 17 Sep 2018 13:51:14 +0100 |
parents | f68911282993 |
children | c01cbe41aeb5 |
comparison
equal
deleted
inserted
replaced
1324:d4a28d1479a8 | 1527:710e6250a401 |
---|---|
11 published by the Free Software Foundation; either version 2 of the | 11 published by the Free Software Foundation; either version 2 of the |
12 License, or (at your option) any later version. See the file | 12 License, or (at your option) any later version. See the file |
13 COPYING included with this distribution for more information. | 13 COPYING included with this distribution for more information. |
14 */ | 14 */ |
15 | 15 |
16 #ifndef _SPARSE_MODEL_H_ | 16 #ifndef SV_SPARSE_MODEL_H |
17 #define _SPARSE_MODEL_H_ | 17 #define SV_SPARSE_MODEL_H |
18 | 18 |
19 #include "Model.h" | 19 #include "Model.h" |
20 #include "TabularModel.h" | 20 #include "TabularModel.h" |
21 #include "base/Command.h" | 21 #include "base/Command.h" |
22 #include "base/RealTime.h" | 22 #include "base/RealTime.h" |
41 | 41 |
42 template <typename PointType> | 42 template <typename PointType> |
43 class SparseModel : public Model, | 43 class SparseModel : public Model, |
44 public TabularModel | 44 public TabularModel |
45 { | 45 { |
46 // If we omit the Q_OBJECT macro, lupdate complains. | |
47 | |
48 // If we include it, moc fails (can't handle template classes). | |
49 | |
50 // If we omit it, lupdate still seems to emit translatable | |
51 // messages for the tr() strings in here. So I guess we omit it. | |
52 | |
46 public: | 53 public: |
47 SparseModel(sv_samplerate_t sampleRate, int resolution, | 54 SparseModel(sv_samplerate_t sampleRate, int resolution, |
48 bool notifyOnAdd = true); | 55 bool notifyOnAdd = true); |
49 virtual ~SparseModel() { } | 56 virtual ~SparseModel() { } |
50 | 57 |
51 virtual bool isOK() const { return true; } | 58 virtual bool isOK() const { return true; } |
52 virtual sv_frame_t getStartFrame() const; | 59 virtual sv_frame_t getStartFrame() const; |
53 virtual sv_frame_t getEndFrame() const; | 60 virtual sv_frame_t getEndFrame() const; |
64 virtual void setResolution(int resolution); | 71 virtual void setResolution(int resolution); |
65 | 72 |
66 // Extend the end of the model. If this is set to something beyond | 73 // Extend the end of the model. If this is set to something beyond |
67 // the end of the final point in the model, then getEndFrame() | 74 // the end of the final point in the model, then getEndFrame() |
68 // will return this value. Otherwise getEndFrame() will return the | 75 // will return this value. Otherwise getEndFrame() will return the |
69 // end of the final point. | 76 // end of the final point. (This is used by the Tony application) |
70 virtual void extendEndFrame(sv_frame_t to) { m_extendTo = to; } | 77 virtual void extendEndFrame(sv_frame_t to) { m_extendTo = to; } |
71 | 78 |
72 typedef PointType Point; | 79 typedef PointType Point; |
73 typedef std::multiset<PointType, | 80 typedef std::multiset<PointType, |
74 typename PointType::OrderComparator> PointList; | 81 typename PointType::OrderComparator> PointList; |
75 typedef typename PointList::iterator PointListIterator; | 82 typedef typename PointList::iterator PointListIterator; |
76 typedef typename PointList::const_iterator PointListConstIterator; | 83 typedef typename PointList::const_iterator PointListConstIterator; |
77 | 84 |
78 /** | 85 /** |
79 * Return whether the model is empty or not. | 86 * Return whether the model is empty or not. |
149 virtual void setCompletion(int completion, bool update = true); | 156 virtual void setCompletion(int completion, bool update = true); |
150 virtual int getCompletion() const { return m_completion; } | 157 virtual int getCompletion() const { return m_completion; } |
151 | 158 |
152 virtual bool hasTextLabels() const { return m_hasTextLabels; } | 159 virtual bool hasTextLabels() const { return m_hasTextLabels; } |
153 | 160 |
161 virtual bool isSparse() const { return true; } | |
162 | |
154 QString getTypeName() const { return tr("Sparse"); } | 163 QString getTypeName() const { return tr("Sparse"); } |
155 | 164 |
156 virtual QString getXmlOutputType() const { return "sparse"; } | 165 virtual QString getXmlOutputType() const { return "sparse"; } |
157 | 166 |
158 virtual void toXml(QTextStream &out, | 167 virtual void toXml(QTextStream &out, |
166 | 175 |
167 virtual QString toDelimitedDataStringWithOptions(QString delimiter, | 176 virtual QString toDelimitedDataStringWithOptions(QString delimiter, |
168 DataExportOptions opts) const { | 177 DataExportOptions opts) const { |
169 return toDelimitedDataStringSubsetWithOptions | 178 return toDelimitedDataStringSubsetWithOptions |
170 (delimiter, opts, | 179 (delimiter, opts, |
171 std::min(getStartFrame(), sv_frame_t(0)), getEndFrame() + 1); | 180 std::min(getStartFrame(), sv_frame_t(0)), getEndFrame()); |
172 } | 181 } |
173 | 182 |
174 virtual QString toDelimitedDataStringSubset(QString delimiter, sv_frame_t f0, sv_frame_t f1) const { | 183 virtual QString toDelimitedDataStringSubset(QString delimiter, sv_frame_t f0, sv_frame_t f1) const { |
175 return toDelimitedDataStringSubsetWithOptions | 184 return toDelimitedDataStringSubsetWithOptions |
176 (delimiter, DataExportDefaults, f0, f1); | 185 (delimiter, DataExportDefaults, f0, f1); |
194 * Command to add a point, with undo. | 203 * Command to add a point, with undo. |
195 */ | 204 */ |
196 class AddPointCommand : public Command | 205 class AddPointCommand : public Command |
197 { | 206 { |
198 public: | 207 public: |
199 AddPointCommand(SparseModel<PointType> *model, | 208 AddPointCommand(SparseModel<PointType> *model, |
200 const PointType &point, | 209 const PointType &point, |
201 QString name = "") : | 210 QString name = "") : |
202 m_model(model), m_point(point), m_name(name) { } | 211 m_model(model), m_point(point), m_name(name) { } |
203 | 212 |
204 virtual QString getName() const { | 213 virtual QString getName() const { |
205 return (m_name == "" ? tr("Add Point") : m_name); | 214 return (m_name == "" ? tr("Add Point") : m_name); |
206 } | 215 } |
207 | 216 |
208 virtual void execute() { m_model->addPoint(m_point); } | 217 virtual void execute() { m_model->addPoint(m_point); } |
209 virtual void unexecute() { m_model->deletePoint(m_point); } | 218 virtual void unexecute() { m_model->deletePoint(m_point); } |
210 | 219 |
211 const PointType &getPoint() const { return m_point; } | 220 const PointType &getPoint() const { return m_point; } |
212 | 221 |
213 private: | 222 private: |
214 SparseModel<PointType> *m_model; | 223 SparseModel<PointType> *m_model; |
215 PointType m_point; | 224 PointType m_point; |
216 QString m_name; | 225 QString m_name; |
217 }; | 226 }; |
218 | 227 |
219 | 228 |
220 /** | 229 /** |
221 * Command to remove a point, with undo. | 230 * Command to remove a point, with undo. |
222 */ | 231 */ |
223 class DeletePointCommand : public Command | 232 class DeletePointCommand : public Command |
224 { | 233 { |
225 public: | 234 public: |
226 DeletePointCommand(SparseModel<PointType> *model, | 235 DeletePointCommand(SparseModel<PointType> *model, |
227 const PointType &point) : | 236 const PointType &point) : |
228 m_model(model), m_point(point) { } | 237 m_model(model), m_point(point) { } |
229 | 238 |
230 virtual QString getName() const { return tr("Delete Point"); } | 239 virtual QString getName() const { return tr("Delete Point"); } |
231 | 240 |
232 virtual void execute() { m_model->deletePoint(m_point); } | 241 virtual void execute() { m_model->deletePoint(m_point); } |
233 virtual void unexecute() { m_model->addPoint(m_point); } | 242 virtual void unexecute() { m_model->addPoint(m_point); } |
234 | 243 |
235 const PointType &getPoint() const { return m_point; } | 244 const PointType &getPoint() const { return m_point; } |
236 | 245 |
237 private: | 246 private: |
238 SparseModel<PointType> *m_model; | 247 SparseModel<PointType> *m_model; |
239 PointType m_point; | 248 PointType m_point; |
240 }; | 249 }; |
241 | 250 |
242 | 251 |
243 /** | 252 /** |
244 * Command to add or remove a series of points, with undo. | 253 * Command to add or remove a series of points, with undo. |
245 * Consecutive add/remove pairs for the same point are collapsed. | 254 * Consecutive add/remove pairs for the same point are collapsed. |
246 */ | 255 */ |
247 class EditCommand : public MacroCommand | 256 class EditCommand : public MacroCommand |
248 { | 257 { |
249 public: | 258 public: |
250 EditCommand(SparseModel<PointType> *model, QString commandName); | 259 EditCommand(SparseModel<PointType> *model, QString commandName); |
251 | 260 |
252 virtual void addPoint(const PointType &point); | 261 virtual void addPoint(const PointType &point); |
253 virtual void deletePoint(const PointType &point); | 262 virtual void deletePoint(const PointType &point); |
254 | 263 |
255 /** | 264 /** |
256 * Stack an arbitrary other command in the same sequence. | 265 * Stack an arbitrary other command in the same sequence. |
257 */ | 266 */ |
258 virtual void addCommand(Command *command) { addCommand(command, true); } | 267 virtual void addCommand(Command *command) { addCommand(command, true); } |
259 | 268 |
260 /** | 269 /** |
261 * If any points have been added or deleted, return this | 270 * If any points have been added or deleted, return this |
262 * command (so the caller can add it to the command history). | 271 * command (so the caller can add it to the command history). |
263 * Otherwise delete the command and return NULL. | 272 * Otherwise delete the command and return NULL. |
264 */ | 273 */ |
265 virtual EditCommand *finish(); | 274 virtual EditCommand *finish(); |
266 | 275 |
267 protected: | 276 protected: |
268 virtual void addCommand(Command *command, bool executeFirst); | 277 virtual void addCommand(Command *command, bool executeFirst); |
269 | 278 |
270 SparseModel<PointType> *m_model; | 279 SparseModel<PointType> *m_model; |
271 }; | 280 }; |
272 | 281 |
273 | 282 |
274 /** | 283 /** |
275 * Command to relabel a point. | 284 * Command to relabel a point. |
276 */ | 285 */ |
277 class RelabelCommand : public Command | 286 class RelabelCommand : public Command |
278 { | 287 { |
279 public: | 288 public: |
280 RelabelCommand(SparseModel<PointType> *model, | 289 RelabelCommand(SparseModel<PointType> *model, |
281 const PointType &point, | 290 const PointType &point, |
282 QString newLabel) : | 291 QString newLabel) : |
283 m_model(model), m_oldPoint(point), m_newPoint(point) { | 292 m_model(model), m_oldPoint(point), m_newPoint(point) { |
284 m_newPoint.label = newLabel; | 293 m_newPoint.label = newLabel; |
285 } | 294 } |
286 | 295 |
287 virtual QString getName() const { return tr("Re-Label Point"); } | 296 virtual QString getName() const { return tr("Re-Label Point"); } |
288 | 297 |
289 virtual void execute() { | 298 virtual void execute() { |
290 m_model->deletePoint(m_oldPoint); | 299 m_model->deletePoint(m_oldPoint); |
291 m_model->addPoint(m_newPoint); | 300 m_model->addPoint(m_newPoint); |
292 std::swap(m_oldPoint, m_newPoint); | 301 std::swap(m_oldPoint, m_newPoint); |
293 } | 302 } |
294 | 303 |
295 virtual void unexecute() { execute(); } | 304 virtual void unexecute() { execute(); } |
296 | 305 |
297 private: | 306 private: |
298 SparseModel<PointType> *m_model; | 307 SparseModel<PointType> *m_model; |
299 PointType m_oldPoint; | 308 PointType m_oldPoint; |
300 PointType m_newPoint; | 309 PointType m_newPoint; |
301 }; | 310 }; |
302 | 311 |
303 /** | 312 /** |
304 * TabularModel methods. | 313 * TabularModel methods. |
305 */ | 314 */ |
556 SparseModel<PointType>::getStartFrame() const | 565 SparseModel<PointType>::getStartFrame() const |
557 { | 566 { |
558 QMutexLocker locker(&m_mutex); | 567 QMutexLocker locker(&m_mutex); |
559 sv_frame_t f = 0; | 568 sv_frame_t f = 0; |
560 if (!m_points.empty()) { | 569 if (!m_points.empty()) { |
561 f = m_points.begin()->frame; | 570 f = m_points.begin()->frame; |
562 } | 571 } |
563 return f; | 572 return f; |
564 } | 573 } |
565 | 574 |
566 template <typename PointType> | 575 template <typename PointType> |
568 SparseModel<PointType>::getEndFrame() const | 577 SparseModel<PointType>::getEndFrame() const |
569 { | 578 { |
570 QMutexLocker locker(&m_mutex); | 579 QMutexLocker locker(&m_mutex); |
571 sv_frame_t f = 0; | 580 sv_frame_t f = 0; |
572 if (!m_points.empty()) { | 581 if (!m_points.empty()) { |
573 PointListConstIterator i(m_points.end()); | 582 PointListConstIterator i(m_points.end()); |
574 f = (--i)->frame; | 583 f = (--i)->frame + 1; |
575 } | 584 } |
576 if (m_extendTo > f) return m_extendTo; | 585 if (m_extendTo > f) { |
577 else return f; | 586 return m_extendTo; |
587 } else { | |
588 return f; | |
589 } | |
578 } | 590 } |
579 | 591 |
580 template <typename PointType> | 592 template <typename PointType> |
581 bool | 593 bool |
582 SparseModel<PointType>::isEmpty() const | 594 SparseModel<PointType>::isEmpty() const |
616 if (endItr != m_points.end()) ++endItr; | 628 if (endItr != m_points.end()) ++endItr; |
617 | 629 |
618 PointList rv; | 630 PointList rv; |
619 | 631 |
620 for (PointListConstIterator i = startItr; i != endItr; ++i) { | 632 for (PointListConstIterator i = startItr; i != endItr; ++i) { |
621 rv.insert(*i); | 633 rv.insert(*i); |
622 } | 634 } |
623 | 635 |
624 return rv; | 636 return rv; |
625 } | 637 } |
626 | 638 |
632 getPointIterators(frame, startItr, endItr); | 644 getPointIterators(frame, startItr, endItr); |
633 | 645 |
634 PointList rv; | 646 PointList rv; |
635 | 647 |
636 for (PointListConstIterator i = startItr; i != endItr; ++i) { | 648 for (PointListConstIterator i = startItr; i != endItr; ++i) { |
637 rv.insert(*i); | 649 rv.insert(*i); |
638 } | 650 } |
639 | 651 |
640 return rv; | 652 return rv; |
641 } | 653 } |
642 | 654 |
702 if (i == m_points.begin()) return rv; | 714 if (i == m_points.begin()) return rv; |
703 | 715 |
704 --i; | 716 --i; |
705 sv_frame_t frame = i->frame; | 717 sv_frame_t frame = i->frame; |
706 while (i->frame == frame) { | 718 while (i->frame == frame) { |
707 rv.insert(*i); | 719 rv.insert(*i); |
708 if (i == m_points.begin()) break; | 720 if (i == m_points.begin()) break; |
709 --i; | 721 --i; |
710 } | 722 } |
711 | 723 |
712 return rv; | 724 return rv; |
713 } | 725 } |
714 | 726 |
724 PointListConstIterator i = m_points.upper_bound(lookupPoint); | 736 PointListConstIterator i = m_points.upper_bound(lookupPoint); |
725 if (i == m_points.end()) return rv; | 737 if (i == m_points.end()) return rv; |
726 | 738 |
727 sv_frame_t frame = i->frame; | 739 sv_frame_t frame = i->frame; |
728 while (i != m_points.end() && i->frame == frame) { | 740 while (i != m_points.end() && i->frame == frame) { |
729 rv.insert(*i); | 741 rv.insert(*i); |
730 ++i; | 742 ++i; |
731 } | 743 } |
732 | 744 |
733 return rv; | 745 return rv; |
734 } | 746 } |
735 | 747 |
736 template <typename PointType> | 748 template <typename PointType> |
737 void | 749 void |
738 SparseModel<PointType>::setResolution(int resolution) | 750 SparseModel<PointType>::setResolution(int resolution) |
739 { | 751 { |
740 { | 752 { |
741 QMutexLocker locker(&m_mutex); | 753 QMutexLocker locker(&m_mutex); |
742 m_resolution = resolution; | 754 m_resolution = resolution; |
743 m_rows.clear(); | 755 m_rows.clear(); |
744 } | 756 } |
745 emit modelChanged(); | 757 emit modelChanged(); |
746 } | 758 } |
747 | 759 |
748 template <typename PointType> | 760 template <typename PointType> |
749 void | 761 void |
750 SparseModel<PointType>::clear() | 762 SparseModel<PointType>::clear() |
751 { | 763 { |
752 { | 764 { |
753 QMutexLocker locker(&m_mutex); | 765 QMutexLocker locker(&m_mutex); |
754 m_points.clear(); | 766 m_points.clear(); |
755 m_pointCount = 0; | 767 m_pointCount = 0; |
756 m_rows.clear(); | 768 m_rows.clear(); |
757 } | 769 } |
758 emit modelChanged(); | 770 emit modelChanged(); |
759 } | 771 } |
760 | 772 |
761 template <typename PointType> | 773 template <typename PointType> |
762 void | 774 void |
763 SparseModel<PointType>::addPoint(const PointType &point) | 775 SparseModel<PointType>::addPoint(const PointType &point) |
764 { | 776 { |
765 QMutexLocker locker(&m_mutex); | 777 { |
766 | 778 QMutexLocker locker(&m_mutex); |
767 m_points.insert(point); | 779 |
768 m_pointCount++; | 780 m_points.insert(point); |
769 if (point.getLabel() != "") m_hasTextLabels = true; | 781 m_pointCount++; |
770 | 782 if (point.getLabel() != "") m_hasTextLabels = true; |
771 // Even though this model is nominally sparse, there may still be | 783 |
772 // too many signals going on here (especially as they'll probably | 784 // Even though this model is nominally sparse, there may still |
773 // be queued from one thread to another), which is why we need the | 785 // be too many signals going on here (especially as they'll |
774 // notifyOnAdd as an option rather than a necessity (the | 786 // probably be queued from one thread to another), which is |
775 // alternative is to notify on setCompletion). | 787 // why we need the notifyOnAdd as an option rather than a |
788 // necessity (the alternative is to notify on setCompletion). | |
789 | |
790 if (m_notifyOnAdd) { | |
791 m_rows.clear(); //!!! inefficient | |
792 } else { | |
793 if (m_sinceLastNotifyMin == -1 || | |
794 point.frame < m_sinceLastNotifyMin) { | |
795 m_sinceLastNotifyMin = point.frame; | |
796 } | |
797 if (m_sinceLastNotifyMax == -1 || | |
798 point.frame > m_sinceLastNotifyMax) { | |
799 m_sinceLastNotifyMax = point.frame; | |
800 } | |
801 } | |
802 } | |
776 | 803 |
777 if (m_notifyOnAdd) { | 804 if (m_notifyOnAdd) { |
778 m_rows.clear(); //!!! inefficient | 805 emit modelChangedWithin(point.frame, point.frame + m_resolution); |
779 emit modelChangedWithin(point.frame, point.frame + m_resolution); | |
780 } else { | |
781 if (m_sinceLastNotifyMin == -1 || | |
782 point.frame < m_sinceLastNotifyMin) { | |
783 m_sinceLastNotifyMin = point.frame; | |
784 } | |
785 if (m_sinceLastNotifyMax == -1 || | |
786 point.frame > m_sinceLastNotifyMax) { | |
787 m_sinceLastNotifyMax = point.frame; | |
788 } | |
789 } | 806 } |
790 } | 807 } |
791 | 808 |
792 template <typename PointType> | 809 template <typename PointType> |
793 bool | 810 bool |
810 | 827 |
811 template <typename PointType> | 828 template <typename PointType> |
812 void | 829 void |
813 SparseModel<PointType>::deletePoint(const PointType &point) | 830 SparseModel<PointType>::deletePoint(const PointType &point) |
814 { | 831 { |
815 QMutexLocker locker(&m_mutex); | 832 { |
816 | 833 QMutexLocker locker(&m_mutex); |
817 PointListIterator i = m_points.lower_bound(point); | 834 |
818 typename PointType::Comparator comparator; | 835 PointListIterator i = m_points.lower_bound(point); |
819 while (i != m_points.end()) { | 836 typename PointType::Comparator comparator; |
820 if (i->frame > point.frame) break; | 837 while (i != m_points.end()) { |
821 if (!comparator(*i, point) && !comparator(point, *i)) { | 838 if (i->frame > point.frame) break; |
822 m_points.erase(i); | 839 if (!comparator(*i, point) && !comparator(point, *i)) { |
823 m_pointCount--; | 840 m_points.erase(i); |
824 break; | 841 m_pointCount--; |
825 } | 842 break; |
826 ++i; | 843 } |
827 } | 844 ++i; |
845 } | |
828 | 846 |
829 // std::cout << "SparseOneDimensionalModel: emit modelChanged(" | 847 // std::cout << "SparseOneDimensionalModel: emit modelChanged(" |
830 // << point.frame << ")" << std::endl; | 848 // << point.frame << ")" << std::endl; |
831 m_rows.clear(); //!!! inefficient | 849 m_rows.clear(); //!!! inefficient |
850 } | |
851 | |
832 emit modelChangedWithin(point.frame, point.frame + m_resolution); | 852 emit modelChangedWithin(point.frame, point.frame + m_resolution); |
833 } | 853 } |
834 | 854 |
835 template <typename PointType> | 855 template <typename PointType> |
836 void | 856 void |
837 SparseModel<PointType>::setCompletion(int completion, bool update) | 857 SparseModel<PointType>::setCompletion(int completion, bool update) |
838 { | 858 { |
839 // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl; | 859 // std::cerr << "SparseModel::setCompletion(" << completion << ")" << std::endl; |
840 | 860 bool emitCompletionChanged = true; |
841 QMutexLocker locker(&m_mutex); | 861 bool emitGeneralModelChanged = false; |
842 | 862 bool emitRegionChanged = false; |
843 if (m_completion != completion) { | 863 |
844 m_completion = completion; | 864 { |
845 | 865 QMutexLocker locker(&m_mutex); |
846 if (completion == 100) { | 866 |
847 | 867 if (m_completion != completion) { |
848 if (!m_notifyOnAdd) { | 868 m_completion = completion; |
849 emit completionChanged(); | 869 |
870 if (completion == 100) { | |
871 | |
872 if (m_notifyOnAdd) { | |
873 emitCompletionChanged = false; | |
874 } | |
875 | |
876 m_notifyOnAdd = true; // henceforth | |
877 m_rows.clear(); //!!! inefficient | |
878 emitGeneralModelChanged = true; | |
879 | |
880 } else if (!m_notifyOnAdd) { | |
881 | |
882 if (update && | |
883 m_sinceLastNotifyMin >= 0 && | |
884 m_sinceLastNotifyMax >= 0) { | |
885 m_rows.clear(); //!!! inefficient | |
886 emitRegionChanged = true; | |
887 } | |
850 } | 888 } |
851 | 889 } |
852 m_notifyOnAdd = true; // henceforth | 890 } |
853 m_rows.clear(); //!!! inefficient | 891 |
854 emit modelChanged(); | 892 if (emitCompletionChanged) { |
855 | 893 emit completionChanged(); |
856 } else if (!m_notifyOnAdd) { | 894 } |
857 | 895 if (emitGeneralModelChanged) { |
858 if (update && | 896 emit modelChanged(); |
859 m_sinceLastNotifyMin >= 0 && | 897 } |
860 m_sinceLastNotifyMax >= 0) { | 898 if (emitRegionChanged) { |
861 m_rows.clear(); //!!! inefficient | 899 emit modelChangedWithin(m_sinceLastNotifyMin, m_sinceLastNotifyMax); |
862 emit modelChangedWithin(m_sinceLastNotifyMin, m_sinceLastNotifyMax); | 900 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1; |
863 m_sinceLastNotifyMin = m_sinceLastNotifyMax = -1; | |
864 } else { | |
865 emit completionChanged(); | |
866 } | |
867 } else { | |
868 emit completionChanged(); | |
869 } | |
870 } | 901 } |
871 } | 902 } |
872 | 903 |
873 template <typename PointType> | 904 template <typename PointType> |
874 void | 905 void |
880 // << extraAttributes.toStdString() << std::endl; | 911 // << extraAttributes.toStdString() << std::endl; |
881 | 912 |
882 QString type = getXmlOutputType(); | 913 QString type = getXmlOutputType(); |
883 | 914 |
884 Model::toXml | 915 Model::toXml |
885 (out, | 916 (out, |
886 indent, | 917 indent, |
887 QString("type=\"%1\" dimensions=\"%2\" resolution=\"%3\" notifyOnAdd=\"%4\" dataset=\"%5\" %6") | 918 QString("type=\"%1\" dimensions=\"%2\" resolution=\"%3\" notifyOnAdd=\"%4\" dataset=\"%5\" %6") |
888 .arg(type) | 919 .arg(type) |
889 .arg(PointType(0).getDimensions()) | 920 .arg(PointType(0).getDimensions()) |
890 .arg(m_resolution) | 921 .arg(m_resolution) |
891 .arg(m_notifyOnAdd ? "true" : "false") | 922 .arg(m_notifyOnAdd ? "true" : "false") |
892 .arg(getObjectExportId(&m_points)) | 923 .arg(getObjectExportId(&m_points)) |
893 .arg(extraAttributes)); | 924 .arg(extraAttributes)); |
894 | 925 |
895 out << indent; | 926 out << indent; |
896 out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n") | 927 out << QString("<dataset id=\"%1\" dimensions=\"%2\">\n") |
897 .arg(getObjectExportId(&m_points)) | 928 .arg(getObjectExportId(&m_points)) |
898 .arg(PointType(0).getDimensions()); | 929 .arg(PointType(0).getDimensions()); |
899 | 930 |
900 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { | 931 for (PointListConstIterator i = m_points.begin(); i != m_points.end(); ++i) { |
901 i->toXml(out, indent + " "); | 932 i->toXml(out, indent + " "); |
902 } | 933 } |
903 | 934 |
940 } | 971 } |
941 | 972 |
942 template <typename PointType> | 973 template <typename PointType> |
943 void | 974 void |
944 SparseModel<PointType>::EditCommand::addCommand(Command *command, | 975 SparseModel<PointType>::EditCommand::addCommand(Command *command, |
945 bool executeFirst) | 976 bool executeFirst) |
946 { | 977 { |
947 if (executeFirst) command->execute(); | 978 if (executeFirst) command->execute(); |
948 | 979 |
949 if (!m_commands.empty()) { | 980 if (!m_commands.empty()) { |
950 DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command); | 981 DeletePointCommand *dpc = dynamic_cast<DeletePointCommand *>(command); |
951 if (dpc) { | 982 if (dpc) { |
952 AddPointCommand *apc = dynamic_cast<AddPointCommand *> | 983 AddPointCommand *apc = dynamic_cast<AddPointCommand *> |
953 (m_commands[m_commands.size() - 1]); | 984 (m_commands[m_commands.size() - 1]); |
954 typename PointType::Comparator comparator; | 985 typename PointType::Comparator comparator; |
955 if (apc) { | 986 if (apc) { |
956 if (!comparator(apc->getPoint(), dpc->getPoint()) && | 987 if (!comparator(apc->getPoint(), dpc->getPoint()) && |
957 !comparator(dpc->getPoint(), apc->getPoint())) { | 988 !comparator(dpc->getPoint(), apc->getPoint())) { |
958 deleteCommand(apc); | 989 deleteCommand(apc); |
959 return; | 990 return; |
960 } | 991 } |
961 } | 992 } |
962 } | 993 } |
963 } | 994 } |
964 | 995 |
965 MacroCommand::addCommand(command); | 996 MacroCommand::addCommand(command); |
966 } | 997 } |
967 | 998 |