annotate data/model/ImageModel.h @ 1651:7a56bb85030f single-point

Introduce deferred notifier, + start converting sparse time-value model (perhaps we should rename it too)
author Chris Cannam
date Mon, 18 Mar 2019 14:17:20 +0000
parents ad5f892c0c4d
children a77a7e8c085c
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@1581 16 #ifndef SV_IMAGE_MODEL_H
Chris@1581 17 #define SV_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@1580 48 QString extraAttributes = "") const override
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@1580 96 QString getTypeName() const override { return tr("Image"); }
Chris@345 97
Chris@1580 98 void toXml(QTextStream &out,
Chris@302 99 QString indent = "",
Chris@1580 100 QString extraAttributes = "") const override
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@1580 124 QString getName() const override { return tr("Edit Image"); }
Chris@302 125
Chris@1580 126 void execute() override {
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@1580 132 void unexecute() override { 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@1580 144 int getColumnCount() const override
Chris@424 145 {
Chris@424 146 return 4;
Chris@424 147 }
Chris@424 148
Chris@1580 149 QString getHeading(int column) const override
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@1580 160 QVariant getData(int row, int column, int role) const override
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@1580 177 Command *getSetDataCommand(int row, int column, const QVariant &value, int role) override
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@1580 201 bool isColumnTimeValue(int column) const override
Chris@424 202 {
Chris@424 203 return (column < 2);
Chris@424 204 }
Chris@424 205
Chris@1580 206 SortType getSortType(int column) const override
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