annotate data/model/ModelDataTableModel.cpp @ 557:a40023bebd15

* Fix crash when processing a file that is shorter than a single block
author Chris Cannam
date Tue, 10 Feb 2009 17:24:30 +0000
parents ba7aaacb7211
children b1dc68507e46
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@428 28 m_sortOrdering(Qt::AscendingOrder),
Chris@428 29 m_currentRow(0)
Chris@413 30 {
Chris@420 31 Model *baseModel = dynamic_cast<Model *>(m);
Chris@420 32
Chris@420 33 connect(baseModel, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
Chris@420 34 connect(baseModel, SIGNAL(modelChanged(size_t, size_t)),
Chris@413 35 this, SLOT(modelChanged(size_t, size_t)));
Chris@454 36 connect(baseModel, SIGNAL(aboutToBeDeleted()),
Chris@454 37 this, SLOT(modelAboutToBeDeleted()));
Chris@413 38 }
Chris@413 39
Chris@413 40 ModelDataTableModel::~ModelDataTableModel()
Chris@413 41 {
Chris@413 42 }
Chris@413 43
Chris@413 44 QVariant
Chris@413 45 ModelDataTableModel::data(const QModelIndex &index, int role) const
Chris@413 46 {
Chris@454 47 if (!m_model) return QVariant();
Chris@424 48 if (role != Qt::EditRole && role != Qt::DisplayRole) return QVariant();
Chris@413 49 if (!index.isValid()) return QVariant();
Chris@420 50 return m_model->getData(getUnsorted(index.row()), index.column(), role);
Chris@413 51 }
Chris@413 52
Chris@413 53 bool
Chris@413 54 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
Chris@413 55 {
Chris@454 56 if (!m_model) return false;
Chris@420 57 if (!index.isValid()) return false;
Chris@421 58 Command *command = m_model->getSetDataCommand(getUnsorted(index.row()),
Chris@421 59 index.column(),
Chris@421 60 value, role);
Chris@420 61 if (command) {
Chris@427 62 emit addCommand(command);
Chris@420 63 return true;
Chris@420 64 } else {
Chris@416 65 return false;
Chris@416 66 }
Chris@413 67 }
Chris@413 68
Chris@427 69 bool
Chris@427 70 ModelDataTableModel::insertRow(int row, const QModelIndex &parent)
Chris@427 71 {
Chris@454 72 if (!m_model) return false;
Chris@427 73 if (parent.isValid()) return false;
Chris@427 74
Chris@427 75 emit beginInsertRows(parent, row, row);
Chris@427 76
Chris@427 77 Command *command = m_model->getInsertRowCommand(getUnsorted(row));
Chris@427 78
Chris@427 79 if (command) {
Chris@427 80 emit addCommand(command);
Chris@427 81 }
Chris@427 82
Chris@427 83 emit endInsertRows();
Chris@427 84
Chris@427 85 return (command ? true : false);
Chris@427 86 }
Chris@427 87
Chris@427 88 bool
Chris@427 89 ModelDataTableModel::removeRow(int row, const QModelIndex &parent)
Chris@427 90 {
Chris@454 91 if (!m_model) return false;
Chris@427 92 if (parent.isValid()) return false;
Chris@427 93
Chris@427 94 emit beginRemoveRows(parent, row, row);
Chris@427 95
Chris@427 96 Command *command = m_model->getRemoveRowCommand(getUnsorted(row));
Chris@427 97
Chris@427 98 if (command) {
Chris@427 99 emit addCommand(command);
Chris@427 100 }
Chris@427 101
Chris@427 102 emit endRemoveRows();
Chris@427 103
Chris@427 104 return (command ? true : false);
Chris@427 105 }
Chris@427 106
Chris@413 107 Qt::ItemFlags
Chris@413 108 ModelDataTableModel::flags(const QModelIndex &index) const
Chris@413 109 {
Chris@416 110 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
Chris@416 111 Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
Chris@416 112 return flags;
Chris@413 113 }
Chris@413 114
Chris@413 115 QVariant
Chris@413 116 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
Chris@413 117 {
Chris@454 118 if (!m_model) return QVariant();
Chris@454 119
Chris@425 120 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
Chris@425 121 return section + 1;
Chris@425 122 }
Chris@413 123 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
Chris@420 124 return m_model->getHeading(section);
Chris@425 125 }
Chris@413 126 return QVariant();
Chris@413 127 }
Chris@413 128
Chris@413 129 QModelIndex
Chris@413 130 ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const
Chris@413 131 {
Chris@413 132 return createIndex(row, column, 0);
Chris@413 133 }
Chris@413 134
Chris@413 135 QModelIndex
Chris@413 136 ModelDataTableModel::parent(const QModelIndex &index) const
Chris@413 137 {
Chris@413 138 return QModelIndex();
Chris@413 139 }
Chris@413 140
Chris@413 141 int
Chris@413 142 ModelDataTableModel::rowCount(const QModelIndex &parent) const
Chris@413 143 {
Chris@454 144 if (!m_model) return 0;
Chris@413 145 if (parent.isValid()) return 0;
Chris@420 146 return m_model->getRowCount();
Chris@413 147 }
Chris@413 148
Chris@413 149 int
Chris@413 150 ModelDataTableModel::columnCount(const QModelIndex &parent) const
Chris@413 151 {
Chris@454 152 if (!m_model) return 0;
Chris@413 153 if (parent.isValid()) return 0;
Chris@420 154 return m_model->getColumnCount();
Chris@416 155 }
Chris@416 156
Chris@416 157 QModelIndex
Chris@416 158 ModelDataTableModel::getModelIndexForFrame(size_t frame) const
Chris@416 159 {
Chris@454 160 if (!m_model) return createIndex(0, 0);
Chris@420 161 int row = m_model->getRowForFrame(frame);
Chris@420 162 return createIndex(getSorted(row), 0, 0);
Chris@413 163 }
Chris@413 164
Chris@419 165 size_t
Chris@419 166 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
Chris@419 167 {
Chris@454 168 if (!m_model) return 0;
Chris@420 169 return m_model->getFrameForRow(getUnsorted(index.row()));
Chris@420 170 }
Chris@420 171
Chris@420 172 void
Chris@420 173 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
Chris@420 174 {
Chris@437 175 // std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
Chris@437 176 // << ")" << std::endl;
Chris@428 177 int prevCurrent = getCurrentRow();
Chris@422 178 if (m_sortColumn != column) {
Chris@428 179 clearSort();
Chris@422 180 }
Chris@420 181 m_sortColumn = column;
Chris@420 182 m_sortOrdering = sortOrder;
Chris@428 183 int current = getCurrentRow();
Chris@428 184 if (current != prevCurrent) {
Chris@437 185 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
Chris@428 186 emit currentChanged(createIndex(current, 0, 0));
Chris@428 187 }
Chris@420 188 emit layoutChanged();
Chris@419 189 }
Chris@419 190
Chris@413 191 void
Chris@413 192 ModelDataTableModel::modelChanged()
Chris@413 193 {
Chris@428 194 clearSort();
Chris@413 195 emit layoutChanged();
Chris@413 196 }
Chris@413 197
Chris@413 198 void
Chris@416 199 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
Chris@416 200 {
Chris@420 201 //!!! inefficient
Chris@428 202 clearSort();
Chris@416 203 emit layoutChanged();
Chris@416 204 }
Chris@413 205
Chris@454 206 void
Chris@454 207 ModelDataTableModel::modelAboutToBeDeleted()
Chris@454 208 {
Chris@454 209 m_model = 0;
Chris@454 210 emit modelRemoved();
Chris@454 211 }
Chris@454 212
Chris@420 213 int
Chris@426 214 ModelDataTableModel::getSorted(int row) const
Chris@413 215 {
Chris@454 216 if (!m_model) return row;
Chris@454 217
Chris@420 218 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 219 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 220 return row;
Chris@420 221 } else {
Chris@420 222 return rowCount() - row - 1;
Chris@420 223 }
Chris@420 224 }
Chris@413 225
Chris@420 226 if (m_sort.empty()) {
Chris@420 227 resort();
Chris@413 228 }
Chris@422 229 int result = 0;
Chris@422 230 if (row >= 0 && row < m_sort.size()) {
Chris@422 231 result = m_sort[row];
Chris@422 232 }
Chris@422 233 if (m_sortOrdering == Qt::DescendingOrder) {
Chris@422 234 result = rowCount() - result - 1;
Chris@422 235 }
Chris@422 236
Chris@422 237 return result;
Chris@413 238 }
Chris@413 239
Chris@420 240 int
Chris@426 241 ModelDataTableModel::getUnsorted(int row) const
Chris@413 242 {
Chris@454 243 if (!m_model) return row;
Chris@454 244
Chris@420 245 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 246 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 247 return row;
Chris@420 248 } else {
Chris@420 249 return rowCount() - row - 1;
Chris@420 250 }
Chris@413 251 }
Chris@422 252
Chris@420 253 if (m_sort.empty()) {
Chris@420 254 resort();
Chris@420 255 }
Chris@422 256
Chris@422 257 int result = 0;
Chris@422 258 if (row >= 0 && row < m_sort.size()) {
Chris@422 259 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@422 260 result = m_rsort[row];
Chris@422 261 } else {
Chris@422 262 result = m_rsort[rowCount() - row - 1];
Chris@422 263 }
Chris@422 264 }
Chris@422 265
Chris@422 266 return result;
Chris@413 267 }
Chris@413 268
Chris@420 269 void
Chris@426 270 ModelDataTableModel::resort() const
Chris@413 271 {
Chris@454 272 if (!m_model) return;
Chris@454 273
Chris@422 274 bool numeric = (m_model->getSortType(m_sortColumn) ==
Chris@422 275 TabularModel::SortNumeric);
Chris@422 276
Chris@422 277 m_sort.clear();
Chris@422 278 m_rsort.clear();
Chris@422 279
Chris@422 280 if (numeric) resortNumeric();
Chris@422 281 else resortAlphabetical();
Chris@422 282
Chris@422 283 std::map<int, int> tmp;
Chris@422 284
Chris@422 285 // rsort maps from sorted row number to original row number
Chris@422 286
Chris@422 287 for (int i = 0; i < m_rsort.size(); ++i) {
Chris@422 288 tmp[m_rsort[i]] = i;
Chris@422 289 }
Chris@422 290
Chris@422 291 // tmp now maps from original row number to sorted row number
Chris@422 292
Chris@422 293 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
Chris@422 294 m_sort.push_back(i->second);
Chris@422 295 }
Chris@422 296
Chris@422 297 // and sort now maps from original row number to sorted row number
Chris@413 298 }
Chris@413 299
Chris@422 300 void
Chris@426 301 ModelDataTableModel::resortNumeric() const
Chris@422 302 {
Chris@454 303 if (!m_model) return;
Chris@454 304
Chris@422 305 typedef std::multimap<double, int> MapType;
Chris@422 306
Chris@422 307 MapType rowMap;
Chris@422 308 int rows = m_model->getRowCount();
Chris@422 309
Chris@422 310 for (int i = 0; i < rows; ++i) {
Chris@424 311 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 312 rowMap.insert(MapType::value_type(value.toDouble(), i));
Chris@422 313 }
Chris@422 314
Chris@422 315 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@422 316 m_rsort.push_back(i->second);
Chris@422 317 }
Chris@422 318
Chris@422 319 // rsort now maps from sorted row number to original row number
Chris@422 320 }
Chris@422 321
Chris@422 322 void
Chris@426 323 ModelDataTableModel::resortAlphabetical() const
Chris@422 324 {
Chris@454 325 if (!m_model) return;
Chris@454 326
Chris@422 327 typedef std::multimap<QString, int> MapType;
Chris@422 328
Chris@422 329 MapType rowMap;
Chris@422 330 int rows = m_model->getRowCount();
Chris@422 331
Chris@422 332 for (int i = 0; i < rows; ++i) {
Chris@422 333 QVariant value =
Chris@422 334 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 335 rowMap.insert(MapType::value_type(value.toString(), i));
Chris@422 336 }
Chris@422 337
Chris@422 338 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@422 339 m_rsort.push_back(i->second);
Chris@422 340 }
Chris@422 341
Chris@422 342 // rsort now maps from sorted row number to original row number
Chris@422 343 }
Chris@422 344
Chris@428 345 int
Chris@428 346 ModelDataTableModel::getCurrentRow()
Chris@428 347 {
Chris@428 348 return getSorted(m_currentRow);
Chris@428 349 }
Chris@428 350
Chris@428 351 void
Chris@428 352 ModelDataTableModel::setCurrentRow(int row)
Chris@428 353 {
Chris@428 354 m_currentRow = getUnsorted(row);
Chris@428 355 }
Chris@428 356
Chris@428 357 void
Chris@428 358 ModelDataTableModel::clearSort()
Chris@428 359 {
Chris@428 360 // int prevCurrent = getCurrentRow();
Chris@428 361 m_sort.clear();
Chris@428 362 // int current = getCurrentRow(); //!!! no -- not until the sort criteria have changed
Chris@428 363 // if (current != prevCurrent) {
Chris@428 364 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
Chris@428 365 // emit currentRowChanged(createIndex(current, 0, 0));
Chris@428 366 // }
Chris@428 367 }
Chris@428 368
Chris@428 369