annotate data/model/ModelDataTableModel.cpp @ 968:6b931eeba385

clarify
author Chris Cannam
date Wed, 03 Sep 2014 11:04:41 +0100
parents cd42620e3f40
children cc27f35aa75c
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@947 34 connect(baseModel, SIGNAL(modelChangedWithin(int, int)),
Chris@947 35 this, SLOT(modelChangedWithin(int, int)));
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@929 108 ModelDataTableModel::flags(const QModelIndex &) 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@929 130 ModelDataTableModel::index(int row, int column, const QModelIndex &) const
Chris@413 131 {
Chris@763 132 return createIndex(row, column, (void *)0);
Chris@413 133 }
Chris@413 134
Chris@413 135 QModelIndex
Chris@929 136 ModelDataTableModel::parent(const QModelIndex &) 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@929 158 ModelDataTableModel::getModelIndexForFrame(int 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@763 162 return createIndex(getSorted(row), 0, (void *)0);
Chris@413 163 }
Chris@413 164
Chris@929 165 int
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@618 172 QModelIndex
Chris@618 173 ModelDataTableModel::findText(QString text) const
Chris@618 174 {
Chris@618 175 if (text == "") return QModelIndex();
Chris@618 176 int rows = rowCount();
Chris@618 177 int cols = columnCount();
Chris@618 178 int current = getCurrentRow();
Chris@618 179 for (int row = 1; row <= rows; ++row) {
Chris@618 180 int wrapped = (row + current) % rows;
Chris@618 181 for (int col = 0; col < cols; ++col) {
Chris@618 182 if (m_model->getSortType(col) != TabularModel::SortAlphabetical) {
Chris@618 183 continue;
Chris@618 184 }
Chris@618 185 QString cell = m_model->getData(getUnsorted(wrapped), col,
Chris@618 186 Qt::DisplayRole).toString();
Chris@618 187 if (cell.contains(text, Qt::CaseInsensitive)) {
Chris@618 188 return createIndex(wrapped, col);
Chris@618 189 }
Chris@618 190 }
Chris@618 191 }
Chris@618 192 return QModelIndex();
Chris@618 193 }
Chris@618 194
Chris@420 195 void
Chris@420 196 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
Chris@420 197 {
Chris@690 198 // SVDEBUG << "ModelDataTableModel::sort(" << column << ", " << sortOrder
Chris@687 199 // << ")" << endl;
Chris@428 200 int prevCurrent = getCurrentRow();
Chris@422 201 if (m_sortColumn != column) {
Chris@428 202 clearSort();
Chris@422 203 }
Chris@420 204 m_sortColumn = column;
Chris@420 205 m_sortOrdering = sortOrder;
Chris@428 206 int current = getCurrentRow();
Chris@428 207 if (current != prevCurrent) {
Chris@843 208 // cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << endl;
Chris@763 209 emit currentChanged(createIndex(current, 0, (void *)0));
Chris@428 210 }
Chris@420 211 emit layoutChanged();
Chris@419 212 }
Chris@419 213
Chris@413 214 void
Chris@413 215 ModelDataTableModel::modelChanged()
Chris@413 216 {
Chris@428 217 clearSort();
Chris@413 218 emit layoutChanged();
Chris@413 219 }
Chris@413 220
Chris@413 221 void
Chris@947 222 ModelDataTableModel::modelChangedWithin(int, int)
Chris@416 223 {
Chris@420 224 //!!! inefficient
Chris@428 225 clearSort();
Chris@416 226 emit layoutChanged();
Chris@416 227 }
Chris@413 228
Chris@454 229 void
Chris@454 230 ModelDataTableModel::modelAboutToBeDeleted()
Chris@454 231 {
Chris@454 232 m_model = 0;
Chris@454 233 emit modelRemoved();
Chris@454 234 }
Chris@454 235
Chris@420 236 int
Chris@426 237 ModelDataTableModel::getSorted(int row) const
Chris@413 238 {
Chris@454 239 if (!m_model) return row;
Chris@454 240
Chris@420 241 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 242 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 243 return row;
Chris@420 244 } else {
Chris@420 245 return rowCount() - row - 1;
Chris@420 246 }
Chris@420 247 }
Chris@413 248
Chris@420 249 if (m_sort.empty()) {
Chris@420 250 resort();
Chris@413 251 }
Chris@422 252 int result = 0;
Chris@929 253 if (row >= 0 && row < (int)m_sort.size()) {
Chris@422 254 result = m_sort[row];
Chris@422 255 }
Chris@422 256 if (m_sortOrdering == Qt::DescendingOrder) {
Chris@422 257 result = rowCount() - result - 1;
Chris@422 258 }
Chris@422 259
Chris@422 260 return result;
Chris@413 261 }
Chris@413 262
Chris@420 263 int
Chris@426 264 ModelDataTableModel::getUnsorted(int row) const
Chris@413 265 {
Chris@454 266 if (!m_model) return row;
Chris@454 267
Chris@420 268 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 269 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 270 return row;
Chris@420 271 } else {
Chris@420 272 return rowCount() - row - 1;
Chris@420 273 }
Chris@413 274 }
Chris@422 275
Chris@420 276 if (m_sort.empty()) {
Chris@420 277 resort();
Chris@420 278 }
Chris@422 279
Chris@422 280 int result = 0;
Chris@929 281 if (row >= 0 && row < (int)m_sort.size()) {
Chris@422 282 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@422 283 result = m_rsort[row];
Chris@422 284 } else {
Chris@422 285 result = m_rsort[rowCount() - row - 1];
Chris@422 286 }
Chris@422 287 }
Chris@422 288
Chris@422 289 return result;
Chris@413 290 }
Chris@413 291
Chris@420 292 void
Chris@426 293 ModelDataTableModel::resort() const
Chris@413 294 {
Chris@454 295 if (!m_model) return;
Chris@454 296
Chris@422 297 bool numeric = (m_model->getSortType(m_sortColumn) ==
Chris@422 298 TabularModel::SortNumeric);
Chris@422 299
Chris@843 300 // cerr << "resort: numeric == " << numeric << endl;
Chris@618 301
Chris@422 302 m_sort.clear();
Chris@422 303 m_rsort.clear();
Chris@422 304
Chris@422 305 if (numeric) resortNumeric();
Chris@422 306 else resortAlphabetical();
Chris@422 307
Chris@422 308 std::map<int, int> tmp;
Chris@422 309
Chris@422 310 // rsort maps from sorted row number to original row number
Chris@422 311
Chris@929 312 for (int i = 0; i < (int)m_rsort.size(); ++i) {
Chris@422 313 tmp[m_rsort[i]] = i;
Chris@422 314 }
Chris@422 315
Chris@422 316 // tmp now maps from original row number to sorted row number
Chris@422 317
Chris@422 318 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
Chris@422 319 m_sort.push_back(i->second);
Chris@422 320 }
Chris@422 321
Chris@422 322 // and sort now maps from original row number to sorted row number
Chris@413 323 }
Chris@413 324
Chris@422 325 void
Chris@426 326 ModelDataTableModel::resortNumeric() const
Chris@422 327 {
Chris@454 328 if (!m_model) return;
Chris@454 329
Chris@422 330 typedef std::multimap<double, int> MapType;
Chris@422 331
Chris@422 332 MapType rowMap;
Chris@422 333 int rows = m_model->getRowCount();
Chris@422 334
Chris@422 335 for (int i = 0; i < rows; ++i) {
Chris@424 336 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 337 rowMap.insert(MapType::value_type(value.toDouble(), i));
Chris@422 338 }
Chris@422 339
Chris@422 340 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@843 341 // cerr << "resortNumeric: " << i->second << ": " << i->first << endl;
Chris@422 342 m_rsort.push_back(i->second);
Chris@422 343 }
Chris@422 344
Chris@422 345 // rsort now maps from sorted row number to original row number
Chris@422 346 }
Chris@422 347
Chris@422 348 void
Chris@426 349 ModelDataTableModel::resortAlphabetical() const
Chris@422 350 {
Chris@454 351 if (!m_model) return;
Chris@454 352
Chris@422 353 typedef std::multimap<QString, int> MapType;
Chris@422 354
Chris@422 355 MapType rowMap;
Chris@422 356 int rows = m_model->getRowCount();
Chris@422 357
Chris@422 358 for (int i = 0; i < rows; ++i) {
Chris@422 359 QVariant value =
Chris@422 360 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 361 rowMap.insert(MapType::value_type(value.toString(), i));
Chris@422 362 }
Chris@422 363
Chris@422 364 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@843 365 // cerr << "resortAlphabetical: " << i->second << ": " << i->first << endl;
Chris@422 366 m_rsort.push_back(i->second);
Chris@422 367 }
Chris@422 368
Chris@422 369 // rsort now maps from sorted row number to original row number
Chris@422 370 }
Chris@422 371
Chris@428 372 int
Chris@618 373 ModelDataTableModel::getCurrentRow() const
Chris@428 374 {
Chris@428 375 return getSorted(m_currentRow);
Chris@428 376 }
Chris@428 377
Chris@428 378 void
Chris@428 379 ModelDataTableModel::setCurrentRow(int row)
Chris@428 380 {
Chris@428 381 m_currentRow = getUnsorted(row);
Chris@428 382 }
Chris@428 383
Chris@428 384 void
Chris@428 385 ModelDataTableModel::clearSort()
Chris@428 386 {
Chris@428 387 // int prevCurrent = getCurrentRow();
Chris@428 388 m_sort.clear();
Chris@428 389 // int current = getCurrentRow(); //!!! no -- not until the sort criteria have changed
Chris@428 390 // if (current != prevCurrent) {
Chris@843 391 // cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << endl;
Chris@428 392 // emit currentRowChanged(createIndex(current, 0, 0));
Chris@428 393 // }
Chris@428 394 }
Chris@428 395
Chris@428 396