annotate data/model/ImageModel.h @ 1455:ec9e65fcf749

The use of the begin/end pairs here just seems to cause too many rows to be deleted (from the visual representation, not the underlying model). Things apparently work better if we just modify the underlying model and let the change signals percolate back up again. To that end, update the change handlers so as to cover their proper ranges with dataChanged signals.
author Chris Cannam
date Mon, 23 Apr 2018 16:03:35 +0100
parents 48e9f538e6e9
children c01cbe41aeb5
rev   line source
Chris@302 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@302 2
Chris@302 3 /*
Chris@302 4 Sonic Visualiser
Chris@302 5 An audio file viewer and annotation editor.
Chris@302 6 Centre for Digital Music, Queen Mary, University of London.
Chris@302 7 This file copyright 2006-2007 Chris Cannam and QMUL.
Chris@302 8
Chris@302 9 This program is free software; you can redistribute it and/or
Chris@302 10 modify it under the terms of the GNU General Public License as
Chris@302 11 published by the Free Software Foundation; either version 2 of the
Chris@302 12 License, or (at your option) any later version. See the file
Chris@302 13 COPYING included with this distribution for more information.
Chris@302 14 */
Chris@302 15
Chris@302 16 #ifndef _IMAGE_MODEL_H_
Chris@302 17 #define _IMAGE_MODEL_H_
Chris@302 18
Chris@302 19 #include "SparseModel.h"
Chris@302 20 #include "base/XmlExportable.h"
Chris@302 21 #include "base/RealTime.h"
Chris@302 22
Chris@423 23 #include <QStringList>
Chris@423 24
Chris@302 25 /**
Chris@302 26 * Image point type for use in a SparseModel. This represents an
Chris@302 27 * image, identified by filename, at a given time. The filename can
Chris@302 28 * be empty, in which case we instead have a space to put an image in.
Chris@302 29 */
Chris@302 30
Chris@302 31 struct ImagePoint : public XmlExportable
Chris@302 32 {
Chris@302 33 public:
Chris@1110 34 ImagePoint(sv_frame_t _frame) : frame(_frame) { }
Chris@1110 35 ImagePoint(sv_frame_t _frame, QString _image, QString _label) :
Chris@302 36 frame(_frame), image(_image), label(_label) { }
Chris@302 37
Chris@302 38 int getDimensions() const { return 1; }
Chris@302 39
Chris@1110 40 sv_frame_t frame;
Chris@302 41 QString image;
Chris@302 42 QString label;
Chris@338 43
Chris@338 44 QString getLabel() const { return label; }
Chris@302 45
Chris@314 46 void toXml(QTextStream &stream,
Chris@314 47 QString indent = "",
Chris@314 48 QString extraAttributes = "") const
Chris@302 49 {
Chris@1429 50 stream <<
Chris@314 51 QString("%1<point frame=\"%2\" image=\"%3\" label=\"%4\" %5/>\n")
Chris@1429 52 .arg(indent).arg(frame)
Chris@302 53 .arg(encodeEntities(image))
Chris@302 54 .arg(encodeEntities(label))
Chris@302 55 .arg(extraAttributes);
Chris@302 56 }
Chris@302 57
Chris@1060 58 QString toDelimitedDataString(QString delimiter, DataExportOptions, sv_samplerate_t sampleRate) const
Chris@302 59 {
Chris@302 60 QStringList list;
Chris@302 61 list << RealTime::frame2RealTime(frame, sampleRate).toString().c_str();
Chris@302 62 list << image;
Chris@318 63 if (label != "") list << label;
Chris@302 64 return list.join(delimiter);
Chris@302 65 }
Chris@302 66
Chris@302 67 struct Comparator {
Chris@1429 68 bool operator()(const ImagePoint &p1,
Chris@1429 69 const ImagePoint &p2) const {
Chris@1429 70 if (p1.frame != p2.frame) return p1.frame < p2.frame;
Chris@302 71 if (p1.label != p2.label) return p1.label < p2.label;
Chris@1429 72 return p1.image < p2.image;
Chris@1429 73 }
Chris@302 74 };
Chris@302 75
Chris@302 76 struct OrderComparator {
Chris@1429 77 bool operator()(const ImagePoint &p1,
Chris@1429 78 const ImagePoint &p2) const {
Chris@1429 79 return p1.frame < p2.frame;
Chris@1429 80 }
Chris@302 81 };
Chris@302 82 };
Chris@302 83
Chris@302 84
Chris@302 85 // Make this a class rather than a typedef so it can be predeclared.
Chris@302 86
Chris@302 87 class ImageModel : public SparseModel<ImagePoint>
Chris@302 88 {
Chris@423 89 Q_OBJECT
Chris@423 90
Chris@302 91 public:
Chris@1040 92 ImageModel(sv_samplerate_t sampleRate, int resolution, bool notifyOnAdd = true) :
Chris@1429 93 SparseModel<ImagePoint>(sampleRate, resolution, notifyOnAdd)
Chris@302 94 { }
Chris@302 95
Chris@345 96 QString getTypeName() const { return tr("Image"); }
Chris@345 97
Chris@302 98 virtual void toXml(QTextStream &out,
Chris@302 99 QString indent = "",
Chris@302 100 QString extraAttributes = "") const
Chris@302 101 {
Chris@302 102 SparseModel<ImagePoint>::toXml
Chris@1429 103 (out,
Chris@302 104 indent,
Chris@1429 105 QString("%1 subtype=\"image\"")
Chris@1429 106 .arg(extraAttributes));
Chris@302 107 }
Chris@302 108
Chris@302 109 /**
Chris@302 110 * Command to change the image for a point.
Chris@302 111 */
Chris@302 112 class ChangeImageCommand : public Command
Chris@302 113 {
Chris@302 114 public:
Chris@302 115 ChangeImageCommand(ImageModel *model,
Chris@302 116 const ImagePoint &point,
Chris@302 117 QString newImage,
Chris@302 118 QString newLabel) :
Chris@1429 119 m_model(model), m_oldPoint(point), m_newPoint(point) {
Chris@1429 120 m_newPoint.image = newImage;
Chris@302 121 m_newPoint.label = newLabel;
Chris@1429 122 }
Chris@302 123
Chris@1429 124 virtual QString getName() const { return tr("Edit Image"); }
Chris@302 125
Chris@1429 126 virtual void execute() {
Chris@1429 127 m_model->deletePoint(m_oldPoint);
Chris@1429 128 m_model->addPoint(m_newPoint);
Chris@1429 129 std::swap(m_oldPoint, m_newPoint);
Chris@1429 130 }
Chris@302 131
Chris@1429 132 virtual void unexecute() { execute(); }
Chris@302 133
Chris@302 134 private:
Chris@1429 135 ImageModel *m_model;
Chris@1429 136 ImagePoint m_oldPoint;
Chris@1429 137 ImagePoint m_newPoint;
Chris@302 138 };
Chris@424 139
Chris@424 140 /**
Chris@424 141 * TabularModel methods.
Chris@424 142 */
Chris@424 143
Chris@424 144 virtual int getColumnCount() const
Chris@424 145 {
Chris@424 146 return 4;
Chris@424 147 }
Chris@424 148
Chris@424 149 virtual QString getHeading(int column) const
Chris@424 150 {
Chris@424 151 switch (column) {
Chris@424 152 case 0: return tr("Time");
Chris@424 153 case 1: return tr("Frame");
Chris@424 154 case 2: return tr("Image");
Chris@424 155 case 3: return tr("Label");
Chris@424 156 default: return tr("Unknown");
Chris@424 157 }
Chris@424 158 }
Chris@424 159
Chris@424 160 virtual QVariant getData(int row, int column, int role) const
Chris@424 161 {
Chris@425 162 if (column < 2) {
Chris@425 163 return SparseModel<ImagePoint>::getData
Chris@425 164 (row, column, role);
Chris@425 165 }
Chris@425 166
Chris@608 167 PointListConstIterator i = getPointListIteratorForRow(row);
Chris@424 168 if (i == m_points.end()) return QVariant();
Chris@424 169
Chris@424 170 switch (column) {
Chris@424 171 case 2: return i->image;
Chris@424 172 case 3: return i->label;
Chris@424 173 default: return QVariant();
Chris@424 174 }
Chris@424 175 }
Chris@424 176
Chris@424 177 virtual Command *getSetDataCommand(int row, int column, const QVariant &value, int role)
Chris@424 178 {
Chris@425 179 if (column < 2) {
Chris@425 180 return SparseModel<ImagePoint>::getSetDataCommand
Chris@425 181 (row, column, value, role);
Chris@425 182 }
Chris@425 183
Chris@740 184 if (role != Qt::EditRole) return 0;
Chris@424 185 PointListIterator i = getPointListIteratorForRow(row);
Chris@740 186 if (i == m_points.end()) return 0;
Chris@424 187 EditCommand *command = new EditCommand(this, tr("Edit Data"));
Chris@424 188
Chris@424 189 Point point(*i);
Chris@424 190 command->deletePoint(point);
Chris@424 191
Chris@424 192 switch (column) {
Chris@424 193 case 2: point.image = value.toString(); break;
Chris@424 194 case 3: point.label = value.toString(); break;
Chris@424 195 }
Chris@424 196
Chris@424 197 command->addPoint(point);
Chris@424 198 return command->finish();
Chris@424 199 }
Chris@424 200
Chris@424 201 virtual bool isColumnTimeValue(int column) const
Chris@424 202 {
Chris@424 203 return (column < 2);
Chris@424 204 }
Chris@424 205
Chris@424 206 virtual SortType getSortType(int column) const
Chris@424 207 {
Chris@424 208 if (column > 2) return SortAlphabetical;
Chris@424 209 return SortNumeric;
Chris@424 210 }
Chris@302 211 };
Chris@302 212
Chris@302 213
Chris@302 214 #endif
Chris@302 215
Chris@302 216
Chris@302 217