annotate data/model/ModelDataTableModel.cpp @ 1412:b7a9edee85e0 scale-ticks

Change loop to something that feels more correct, though it makes no difference to the tests here. More tests, one failing.
author Chris Cannam
date Thu, 04 May 2017 08:32:41 +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