annotate data/model/ModelDataTableModel.cpp @ 1455:ec9e65fcf749

The use of the begin/end pairs here just seems to cause too many rows to be deleted (from the visual representation, not the underlying model). Things apparently work better if we just modify the underlying model and let the change signals percolate back up again. To that end, update the change handlers so as to cover their proper ranges with dataChanged signals.
author Chris Cannam
date Mon, 23 Apr 2018 16:03:35 +0100
parents cbdd534f517a
children 70e172e6cc59
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 Command *command = m_model->getInsertRowCommand(getUnsorted(row));
Chris@427 77
Chris@427 78 if (command) {
Chris@427 79 emit addCommand(command);
Chris@427 80 }
Chris@427 81
Chris@427 82 return (command ? true : false);
Chris@427 83 }
Chris@427 84
Chris@427 85 bool
Chris@427 86 ModelDataTableModel::removeRow(int row, const QModelIndex &parent)
Chris@427 87 {
Chris@454 88 if (!m_model) return false;
Chris@427 89 if (parent.isValid()) return false;
Chris@427 90
Chris@427 91 Command *command = m_model->getRemoveRowCommand(getUnsorted(row));
Chris@427 92
Chris@427 93 if (command) {
Chris@427 94 emit addCommand(command);
Chris@427 95 }
Chris@427 96
Chris@427 97 return (command ? true : false);
Chris@427 98 }
Chris@427 99
Chris@413 100 Qt::ItemFlags
Chris@929 101 ModelDataTableModel::flags(const QModelIndex &) 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@454 111 if (!m_model) return QVariant();
Chris@454 112
Chris@425 113 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
Chris@425 114 return section + 1;
Chris@425 115 }
Chris@413 116 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
Chris@420 117 return m_model->getHeading(section);
Chris@425 118 }
Chris@413 119 return QVariant();
Chris@413 120 }
Chris@413 121
Chris@413 122 QModelIndex
Chris@929 123 ModelDataTableModel::index(int row, int column, const QModelIndex &) const
Chris@413 124 {
Chris@763 125 return createIndex(row, column, (void *)0);
Chris@413 126 }
Chris@413 127
Chris@413 128 QModelIndex
Chris@929 129 ModelDataTableModel::parent(const QModelIndex &) const
Chris@413 130 {
Chris@413 131 return QModelIndex();
Chris@413 132 }
Chris@413 133
Chris@413 134 int
Chris@413 135 ModelDataTableModel::rowCount(const QModelIndex &parent) const
Chris@413 136 {
Chris@454 137 if (!m_model) return 0;
Chris@413 138 if (parent.isValid()) return 0;
Chris@1455 139 int count = m_model->getRowCount();
Chris@1455 140 return count;
Chris@413 141 }
Chris@413 142
Chris@413 143 int
Chris@413 144 ModelDataTableModel::columnCount(const QModelIndex &parent) const
Chris@413 145 {
Chris@454 146 if (!m_model) return 0;
Chris@413 147 if (parent.isValid()) return 0;
Chris@420 148 return m_model->getColumnCount();
Chris@416 149 }
Chris@416 150
Chris@416 151 QModelIndex
Chris@1038 152 ModelDataTableModel::getModelIndexForFrame(sv_frame_t frame) const
Chris@416 153 {
Chris@454 154 if (!m_model) return createIndex(0, 0);
Chris@420 155 int row = m_model->getRowForFrame(frame);
Chris@763 156 return createIndex(getSorted(row), 0, (void *)0);
Chris@413 157 }
Chris@413 158
Chris@1038 159 sv_frame_t
Chris@419 160 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
Chris@419 161 {
Chris@454 162 if (!m_model) return 0;
Chris@420 163 return m_model->getFrameForRow(getUnsorted(index.row()));
Chris@420 164 }
Chris@420 165
Chris@618 166 QModelIndex
Chris@618 167 ModelDataTableModel::findText(QString text) const
Chris@618 168 {
Chris@618 169 if (text == "") return QModelIndex();
Chris@618 170 int rows = rowCount();
Chris@618 171 int cols = columnCount();
Chris@618 172 int current = getCurrentRow();
Chris@618 173 for (int row = 1; row <= rows; ++row) {
Chris@618 174 int wrapped = (row + current) % rows;
Chris@618 175 for (int col = 0; col < cols; ++col) {
Chris@618 176 if (m_model->getSortType(col) != TabularModel::SortAlphabetical) {
Chris@618 177 continue;
Chris@618 178 }
Chris@618 179 QString cell = m_model->getData(getUnsorted(wrapped), col,
Chris@618 180 Qt::DisplayRole).toString();
Chris@618 181 if (cell.contains(text, Qt::CaseInsensitive)) {
Chris@618 182 return createIndex(wrapped, col);
Chris@618 183 }
Chris@618 184 }
Chris@618 185 }
Chris@618 186 return QModelIndex();
Chris@618 187 }
Chris@618 188
Chris@420 189 void
Chris@420 190 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
Chris@420 191 {
Chris@690 192 // SVDEBUG << "ModelDataTableModel::sort(" << column << ", " << sortOrder
Chris@687 193 // << ")" << endl;
Chris@428 194 int prevCurrent = getCurrentRow();
Chris@422 195 if (m_sortColumn != column) {
Chris@428 196 clearSort();
Chris@422 197 }
Chris@420 198 m_sortColumn = column;
Chris@420 199 m_sortOrdering = sortOrder;
Chris@428 200 int current = getCurrentRow();
Chris@428 201 if (current != prevCurrent) {
Chris@843 202 // cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << endl;
Chris@763 203 emit currentChanged(createIndex(current, 0, (void *)0));
Chris@428 204 }
Chris@420 205 emit layoutChanged();
Chris@419 206 }
Chris@419 207
Chris@413 208 void
Chris@413 209 ModelDataTableModel::modelChanged()
Chris@413 210 {
Chris@1455 211 SVDEBUG << "ModelDataTableModel::modelChanged" << endl;
Chris@1455 212 QModelIndex ix0;
Chris@1455 213 QModelIndex ix1;
Chris@1455 214 if (rowCount() > 0) {
Chris@1455 215 ix0 = createIndex(0, 0);
Chris@1455 216 int lastCol = columnCount() - 1;
Chris@1455 217 if (lastCol < 0) lastCol = 0;
Chris@1455 218 ix1 = createIndex(rowCount(), lastCol);
Chris@1455 219 }
Chris@1455 220 SVDEBUG << "emitting dataChanged from row " << ix0.row() << " to " << ix1.row() << endl;
Chris@1455 221 emit dataChanged(ix0, ix1);
Chris@428 222 clearSort();
Chris@413 223 emit layoutChanged();
Chris@413 224 }
Chris@413 225
Chris@413 226 void
Chris@1455 227 ModelDataTableModel::modelChangedWithin(sv_frame_t f0, sv_frame_t f1)
Chris@416 228 {
Chris@1455 229 SVDEBUG << "ModelDataTableModel::modelChangedWithin(" << f0 << "," << f1 << ")" << endl;
Chris@1455 230 QModelIndex ix0 = getModelIndexForFrame(f0);
Chris@1455 231 QModelIndex ix1 = getModelIndexForFrame(f1);
Chris@1455 232 int row0 = ix0.row();
Chris@1455 233 int row1 = ix1.row();
Chris@1455 234 if (row0 > 0) {
Chris@1455 235 ix0 = createIndex(row0 - 1, ix0.column(), (void *)0);
Chris@1455 236 }
Chris@1455 237 if (row1 + 1 < rowCount()) {
Chris@1455 238 ix1 = createIndex(row1 + 1, ix1.column(), (void *)0);
Chris@1455 239 }
Chris@1455 240 SVDEBUG << "emitting dataChanged from row " << ix0.row() << " to " << ix1.row() << endl;
Chris@1455 241 emit dataChanged(ix0, ix1);
Chris@428 242 clearSort();
Chris@416 243 emit layoutChanged();
Chris@416 244 }
Chris@413 245
Chris@454 246 void
Chris@454 247 ModelDataTableModel::modelAboutToBeDeleted()
Chris@454 248 {
Chris@454 249 m_model = 0;
Chris@454 250 emit modelRemoved();
Chris@454 251 }
Chris@454 252
Chris@420 253 int
Chris@426 254 ModelDataTableModel::getSorted(int row) const
Chris@413 255 {
Chris@454 256 if (!m_model) return row;
Chris@454 257
Chris@420 258 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 259 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 260 return row;
Chris@420 261 } else {
Chris@420 262 return rowCount() - row - 1;
Chris@420 263 }
Chris@420 264 }
Chris@413 265
Chris@420 266 if (m_sort.empty()) {
Chris@420 267 resort();
Chris@413 268 }
Chris@422 269 int result = 0;
Chris@929 270 if (row >= 0 && row < (int)m_sort.size()) {
Chris@422 271 result = m_sort[row];
Chris@422 272 }
Chris@422 273 if (m_sortOrdering == Qt::DescendingOrder) {
Chris@422 274 result = rowCount() - result - 1;
Chris@422 275 }
Chris@422 276
Chris@422 277 return result;
Chris@413 278 }
Chris@413 279
Chris@420 280 int
Chris@426 281 ModelDataTableModel::getUnsorted(int row) const
Chris@413 282 {
Chris@454 283 if (!m_model) return row;
Chris@454 284
Chris@420 285 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 286 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 287 return row;
Chris@420 288 } else {
Chris@420 289 return rowCount() - row - 1;
Chris@420 290 }
Chris@413 291 }
Chris@422 292
Chris@420 293 if (m_sort.empty()) {
Chris@420 294 resort();
Chris@420 295 }
Chris@422 296
Chris@422 297 int result = 0;
Chris@929 298 if (row >= 0 && row < (int)m_sort.size()) {
Chris@422 299 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@422 300 result = m_rsort[row];
Chris@422 301 } else {
Chris@422 302 result = m_rsort[rowCount() - row - 1];
Chris@422 303 }
Chris@422 304 }
Chris@422 305
Chris@422 306 return result;
Chris@413 307 }
Chris@413 308
Chris@420 309 void
Chris@426 310 ModelDataTableModel::resort() const
Chris@413 311 {
Chris@454 312 if (!m_model) return;
Chris@454 313
Chris@422 314 bool numeric = (m_model->getSortType(m_sortColumn) ==
Chris@422 315 TabularModel::SortNumeric);
Chris@422 316
Chris@843 317 // cerr << "resort: numeric == " << numeric << endl;
Chris@618 318
Chris@422 319 m_sort.clear();
Chris@422 320 m_rsort.clear();
Chris@422 321
Chris@422 322 if (numeric) resortNumeric();
Chris@422 323 else resortAlphabetical();
Chris@422 324
Chris@422 325 std::map<int, int> tmp;
Chris@422 326
Chris@422 327 // rsort maps from sorted row number to original row number
Chris@422 328
Chris@929 329 for (int i = 0; i < (int)m_rsort.size(); ++i) {
Chris@422 330 tmp[m_rsort[i]] = i;
Chris@422 331 }
Chris@422 332
Chris@422 333 // tmp now maps from original row number to sorted row number
Chris@422 334
Chris@422 335 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
Chris@422 336 m_sort.push_back(i->second);
Chris@422 337 }
Chris@422 338
Chris@422 339 // and sort now maps from original row number to sorted row number
Chris@413 340 }
Chris@413 341
Chris@422 342 void
Chris@426 343 ModelDataTableModel::resortNumeric() const
Chris@422 344 {
Chris@454 345 if (!m_model) return;
Chris@454 346
Chris@422 347 typedef std::multimap<double, int> MapType;
Chris@422 348
Chris@422 349 MapType rowMap;
Chris@422 350 int rows = m_model->getRowCount();
Chris@422 351
Chris@422 352 for (int i = 0; i < rows; ++i) {
Chris@424 353 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 354 rowMap.insert(MapType::value_type(value.toDouble(), i));
Chris@422 355 }
Chris@422 356
Chris@422 357 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@843 358 // cerr << "resortNumeric: " << i->second << ": " << i->first << endl;
Chris@422 359 m_rsort.push_back(i->second);
Chris@422 360 }
Chris@422 361
Chris@422 362 // rsort now maps from sorted row number to original row number
Chris@422 363 }
Chris@422 364
Chris@422 365 void
Chris@426 366 ModelDataTableModel::resortAlphabetical() const
Chris@422 367 {
Chris@454 368 if (!m_model) return;
Chris@454 369
Chris@422 370 typedef std::multimap<QString, int> MapType;
Chris@422 371
Chris@422 372 MapType rowMap;
Chris@422 373 int rows = m_model->getRowCount();
Chris@422 374
Chris@422 375 for (int i = 0; i < rows; ++i) {
Chris@422 376 QVariant value =
Chris@422 377 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 378 rowMap.insert(MapType::value_type(value.toString(), i));
Chris@422 379 }
Chris@422 380
Chris@422 381 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@843 382 // cerr << "resortAlphabetical: " << i->second << ": " << i->first << endl;
Chris@422 383 m_rsort.push_back(i->second);
Chris@422 384 }
Chris@422 385
Chris@422 386 // rsort now maps from sorted row number to original row number
Chris@422 387 }
Chris@422 388
Chris@428 389 int
Chris@618 390 ModelDataTableModel::getCurrentRow() const
Chris@428 391 {
Chris@428 392 return getSorted(m_currentRow);
Chris@428 393 }
Chris@428 394
Chris@428 395 void
Chris@428 396 ModelDataTableModel::setCurrentRow(int row)
Chris@428 397 {
Chris@428 398 m_currentRow = getUnsorted(row);
Chris@428 399 }
Chris@428 400
Chris@428 401 void
Chris@428 402 ModelDataTableModel::clearSort()
Chris@428 403 {
Chris@428 404 // int prevCurrent = getCurrentRow();
Chris@428 405 m_sort.clear();
Chris@428 406 // int current = getCurrentRow(); //!!! no -- not until the sort criteria have changed
Chris@428 407 // if (current != prevCurrent) {
Chris@843 408 // cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << endl;
Chris@428 409 // emit currentRowChanged(createIndex(current, 0, 0));
Chris@428 410 // }
Chris@428 411 }
Chris@428 412
Chris@428 413