annotate data/model/ImageModel.h @ 1008:d9e0e59a1581

When using an aggregate model to pass data to a transform, zero-pad the shorter input to the duration of the longer rather than truncating the longer. (This is better behaviour for e.g. MATCH, and in any case the code was previously truncating incorrectly and ending up with garbage data at the end.)
author Chris Cannam
date Fri, 14 Nov 2014 13:51:33 +0000
parents 59e7fe1b1003
children a1cd5abcb38b
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@302 34 ImagePoint(long _frame) : frame(_frame) { }
Chris@302 35 ImagePoint(long _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@302 40 long 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@314 50 stream <<
Chris@314 51 QString("%1<point frame=\"%2\" image=\"%3\" label=\"%4\" %5/>\n")
Chris@302 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@929 58 QString toDelimitedDataString(QString delimiter, int 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@302 68 bool operator()(const ImagePoint &p1,
Chris@302 69 const ImagePoint &p2) const {
Chris@302 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@302 72 return p1.image < p2.image;
Chris@302 73 }
Chris@302 74 };
Chris@302 75
Chris@302 76 struct OrderComparator {
Chris@302 77 bool operator()(const ImagePoint &p1,
Chris@302 78 const ImagePoint &p2) const {
Chris@302 79 return p1.frame < p2.frame;
Chris@302 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@929 92 ImageModel(int sampleRate, int resolution, bool notifyOnAdd = true) :
Chris@302 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@302 103 (out,
Chris@302 104 indent,
Chris@302 105 QString("%1 subtype=\"image\"")
Chris@302 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@302 119 m_model(model), m_oldPoint(point), m_newPoint(point) {
Chris@302 120 m_newPoint.image = newImage;
Chris@302 121 m_newPoint.label = newLabel;
Chris@302 122 }
Chris@302 123
Chris@302 124 virtual QString getName() const { return tr("Edit Image"); }
Chris@302 125
Chris@302 126 virtual void execute() {
Chris@302 127 m_model->deletePoint(m_oldPoint);
Chris@302 128 m_model->addPoint(m_newPoint);
Chris@302 129 std::swap(m_oldPoint, m_newPoint);
Chris@302 130 }
Chris@302 131
Chris@302 132 virtual void unexecute() { execute(); }
Chris@302 133
Chris@302 134 private:
Chris@302 135 ImageModel *m_model;
Chris@302 136 ImagePoint m_oldPoint;
Chris@302 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