annotate data/model/ModelDataTableModel.cpp @ 427:72ec275e458b

* Basic implementation of add and remove point in data editor * Improve resilience of frame - real-time - frame round-trip conversions
author Chris Cannam
date Mon, 16 Jun 2008 14:48:42 +0000
parents 2386582f67cd
children 3e1d190048f4
rev   line source
Chris@413 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@413 2
Chris@413 3 /*
Chris@413 4 Sonic Visualiser
Chris@413 5 An audio file viewer and annotation editor.
Chris@413 6 Centre for Digital Music, Queen Mary, University of London.
Chris@413 7 This file copyright 2008 QMUL.
Chris@413 8
Chris@413 9 This program is free software; you can redistribute it and/or
Chris@413 10 modify it under the terms of the GNU General Public License as
Chris@413 11 published by the Free Software Foundation; either version 2 of the
Chris@413 12 License, or (at your option) any later version. See the file
Chris@413 13 COPYING included with this distribution for more information.
Chris@413 14 */
Chris@413 15
Chris@413 16 #include "ModelDataTableModel.h"
Chris@413 17
Chris@420 18 #include "TabularModel.h"
Chris@420 19 #include "Model.h"
Chris@413 20
Chris@422 21 #include <map>
Chris@417 22 #include <algorithm>
Chris@420 23 #include <iostream>
Chris@417 24
Chris@420 25 ModelDataTableModel::ModelDataTableModel(TabularModel *m) :
Chris@421 26 m_model(m),
Chris@421 27 m_sortColumn(0),
Chris@421 28 m_sortOrdering(Qt::AscendingOrder)
Chris@413 29 {
Chris@420 30 Model *baseModel = dynamic_cast<Model *>(m);
Chris@420 31
Chris@420 32 connect(baseModel, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
Chris@420 33 connect(baseModel, SIGNAL(modelChanged(size_t, size_t)),
Chris@413 34 this, SLOT(modelChanged(size_t, size_t)));
Chris@413 35 }
Chris@413 36
Chris@413 37 ModelDataTableModel::~ModelDataTableModel()
Chris@413 38 {
Chris@413 39 }
Chris@413 40
Chris@413 41 QVariant
Chris@413 42 ModelDataTableModel::data(const QModelIndex &index, int role) const
Chris@413 43 {
Chris@424 44 if (role != Qt::EditRole && role != Qt::DisplayRole) return QVariant();
Chris@413 45 if (!index.isValid()) return QVariant();
Chris@420 46 return m_model->getData(getUnsorted(index.row()), index.column(), role);
Chris@413 47 }
Chris@413 48
Chris@413 49 bool
Chris@413 50 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
Chris@413 51 {
Chris@420 52 if (!index.isValid()) return false;
Chris@421 53 Command *command = m_model->getSetDataCommand(getUnsorted(index.row()),
Chris@421 54 index.column(),
Chris@421 55 value, role);
Chris@420 56 if (command) {
Chris@427 57 emit addCommand(command);
Chris@420 58 return true;
Chris@420 59 } else {
Chris@416 60 return false;
Chris@416 61 }
Chris@413 62 }
Chris@413 63
Chris@427 64 bool
Chris@427 65 ModelDataTableModel::insertRow(int row, const QModelIndex &parent)
Chris@427 66 {
Chris@427 67 if (parent.isValid()) return false;
Chris@427 68
Chris@427 69 emit beginInsertRows(parent, row, row);
Chris@427 70
Chris@427 71 Command *command = m_model->getInsertRowCommand(getUnsorted(row));
Chris@427 72
Chris@427 73 if (command) {
Chris@427 74 emit addCommand(command);
Chris@427 75 }
Chris@427 76
Chris@427 77 emit endInsertRows();
Chris@427 78
Chris@427 79 return (command ? true : false);
Chris@427 80 }
Chris@427 81
Chris@427 82 bool
Chris@427 83 ModelDataTableModel::removeRow(int row, const QModelIndex &parent)
Chris@427 84 {
Chris@427 85 if (parent.isValid()) return false;
Chris@427 86
Chris@427 87 emit beginRemoveRows(parent, row, row);
Chris@427 88
Chris@427 89 Command *command = m_model->getRemoveRowCommand(getUnsorted(row));
Chris@427 90
Chris@427 91 if (command) {
Chris@427 92 emit addCommand(command);
Chris@427 93 }
Chris@427 94
Chris@427 95 emit endRemoveRows();
Chris@427 96
Chris@427 97 return (command ? true : false);
Chris@427 98 }
Chris@427 99
Chris@413 100 Qt::ItemFlags
Chris@413 101 ModelDataTableModel::flags(const QModelIndex &index) const
Chris@413 102 {
Chris@416 103 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
Chris@416 104 Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
Chris@416 105 return flags;
Chris@413 106 }
Chris@413 107
Chris@413 108 QVariant
Chris@413 109 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
Chris@413 110 {
Chris@425 111 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
Chris@425 112 return section + 1;
Chris@425 113 }
Chris@413 114 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
Chris@420 115 return m_model->getHeading(section);
Chris@425 116 }
Chris@413 117 return QVariant();
Chris@413 118 }
Chris@413 119
Chris@413 120 QModelIndex
Chris@413 121 ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const
Chris@413 122 {
Chris@413 123 return createIndex(row, column, 0);
Chris@413 124 }
Chris@413 125
Chris@413 126 QModelIndex
Chris@413 127 ModelDataTableModel::parent(const QModelIndex &index) const
Chris@413 128 {
Chris@413 129 return QModelIndex();
Chris@413 130 }
Chris@413 131
Chris@413 132 int
Chris@413 133 ModelDataTableModel::rowCount(const QModelIndex &parent) const
Chris@413 134 {
Chris@413 135 if (parent.isValid()) return 0;
Chris@420 136 return m_model->getRowCount();
Chris@413 137 }
Chris@413 138
Chris@413 139 int
Chris@413 140 ModelDataTableModel::columnCount(const QModelIndex &parent) const
Chris@413 141 {
Chris@413 142 if (parent.isValid()) return 0;
Chris@420 143 return m_model->getColumnCount();
Chris@416 144 }
Chris@416 145
Chris@416 146 QModelIndex
Chris@416 147 ModelDataTableModel::getModelIndexForFrame(size_t frame) const
Chris@416 148 {
Chris@420 149 int row = m_model->getRowForFrame(frame);
Chris@420 150 return createIndex(getSorted(row), 0, 0);
Chris@413 151 }
Chris@413 152
Chris@419 153 size_t
Chris@419 154 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
Chris@419 155 {
Chris@420 156 return m_model->getFrameForRow(getUnsorted(index.row()));
Chris@420 157 }
Chris@420 158
Chris@420 159 void
Chris@420 160 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
Chris@420 161 {
Chris@420 162 std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
Chris@420 163 << ")" << std::endl;
Chris@422 164 if (m_sortColumn != column) {
Chris@422 165 m_sort.clear();
Chris@422 166 }
Chris@420 167 m_sortColumn = column;
Chris@420 168 m_sortOrdering = sortOrder;
Chris@420 169 emit layoutChanged();
Chris@419 170 }
Chris@419 171
Chris@413 172 void
Chris@413 173 ModelDataTableModel::modelChanged()
Chris@413 174 {
Chris@420 175 m_sort.clear();
Chris@413 176 emit layoutChanged();
Chris@413 177 }
Chris@413 178
Chris@413 179 void
Chris@416 180 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
Chris@416 181 {
Chris@420 182 //!!! inefficient
Chris@420 183 m_sort.clear();
Chris@416 184 emit layoutChanged();
Chris@416 185 }
Chris@413 186
Chris@420 187 int
Chris@426 188 ModelDataTableModel::getSorted(int row) const
Chris@413 189 {
Chris@420 190 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 191 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 192 return row;
Chris@420 193 } else {
Chris@420 194 return rowCount() - row - 1;
Chris@420 195 }
Chris@420 196 }
Chris@413 197
Chris@420 198 if (m_sort.empty()) {
Chris@420 199 resort();
Chris@413 200 }
Chris@422 201 int result = 0;
Chris@422 202 if (row >= 0 && row < m_sort.size()) {
Chris@422 203 result = m_sort[row];
Chris@422 204 }
Chris@422 205 if (m_sortOrdering == Qt::DescendingOrder) {
Chris@422 206 result = rowCount() - result - 1;
Chris@422 207 }
Chris@422 208
Chris@422 209 return result;
Chris@413 210 }
Chris@413 211
Chris@420 212 int
Chris@426 213 ModelDataTableModel::getUnsorted(int row) const
Chris@413 214 {
Chris@420 215 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 216 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 217 return row;
Chris@420 218 } else {
Chris@420 219 return rowCount() - row - 1;
Chris@420 220 }
Chris@413 221 }
Chris@422 222
Chris@420 223 if (m_sort.empty()) {
Chris@420 224 resort();
Chris@420 225 }
Chris@422 226
Chris@422 227 int result = 0;
Chris@422 228 if (row >= 0 && row < m_sort.size()) {
Chris@422 229 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@422 230 result = m_rsort[row];
Chris@422 231 } else {
Chris@422 232 result = m_rsort[rowCount() - row - 1];
Chris@422 233 }
Chris@422 234 }
Chris@422 235
Chris@422 236 return result;
Chris@413 237 }
Chris@413 238
Chris@420 239 void
Chris@426 240 ModelDataTableModel::resort() const
Chris@413 241 {
Chris@422 242 bool numeric = (m_model->getSortType(m_sortColumn) ==
Chris@422 243 TabularModel::SortNumeric);
Chris@422 244
Chris@422 245 m_sort.clear();
Chris@422 246 m_rsort.clear();
Chris@422 247
Chris@422 248 if (numeric) resortNumeric();
Chris@422 249 else resortAlphabetical();
Chris@422 250
Chris@422 251 std::map<int, int> tmp;
Chris@422 252
Chris@422 253 // rsort maps from sorted row number to original row number
Chris@422 254
Chris@422 255 for (int i = 0; i < m_rsort.size(); ++i) {
Chris@422 256 tmp[m_rsort[i]] = i;
Chris@422 257 }
Chris@422 258
Chris@422 259 // tmp now maps from original row number to sorted row number
Chris@422 260
Chris@422 261 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
Chris@422 262 m_sort.push_back(i->second);
Chris@422 263 }
Chris@422 264
Chris@422 265 // and sort now maps from original row number to sorted row number
Chris@413 266 }
Chris@413 267
Chris@422 268 void
Chris@426 269 ModelDataTableModel::resortNumeric() const
Chris@422 270 {
Chris@422 271 typedef std::multimap<double, int> MapType;
Chris@422 272
Chris@422 273 MapType rowMap;
Chris@422 274 int rows = m_model->getRowCount();
Chris@422 275
Chris@422 276 for (int i = 0; i < rows; ++i) {
Chris@424 277 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 278 rowMap.insert(MapType::value_type(value.toDouble(), i));
Chris@422 279 }
Chris@422 280
Chris@422 281 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@422 282 m_rsort.push_back(i->second);
Chris@422 283 }
Chris@422 284
Chris@422 285 // rsort now maps from sorted row number to original row number
Chris@422 286 }
Chris@422 287
Chris@422 288 void
Chris@426 289 ModelDataTableModel::resortAlphabetical() const
Chris@422 290 {
Chris@422 291 typedef std::multimap<QString, int> MapType;
Chris@422 292
Chris@422 293 MapType rowMap;
Chris@422 294 int rows = m_model->getRowCount();
Chris@422 295
Chris@422 296 for (int i = 0; i < rows; ++i) {
Chris@422 297 QVariant value =
Chris@422 298 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 299 rowMap.insert(MapType::value_type(value.toString(), i));
Chris@422 300 }
Chris@422 301
Chris@422 302 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@422 303 m_rsort.push_back(i->second);
Chris@422 304 }
Chris@422 305
Chris@422 306 // rsort now maps from sorted row number to original row number
Chris@422 307 }
Chris@422 308