annotate data/model/ModelDataTableModel.cpp @ 1410:c4af57d59434 scale-ticks

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