annotate data/model/ModelDataTableModel.cpp @ 631:3a5ee4b6c9ad

* Complete the overhaul of CSV file import; now you can pick the purpose for each column in the file, and SV should do the rest. The most significant practical improvement here is that we can now handle files in which time and duration do not necessarily appear in known columns.
author Chris Cannam
date Mon, 19 Jul 2010 17:08:56 +0000
parents b1dc68507e46
children b4a8d8221eaf
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@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@437 198 // std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
Chris@437 199 // << ")" << std::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@437 208 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
Chris@428 209 emit currentChanged(createIndex(current, 0, 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@416 222 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
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@422 253 if (row >= 0 && row < 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@422 281 if (row >= 0 && row < 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@618 300 // std::cerr << "resort: numeric == " << numeric << std::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@422 312 for (int i = 0; i < 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@618 341 // std::cerr << "resortNumeric: " << i->second << ": " << i->first << std::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@618 365 // std::cerr << "resortAlphabetical: " << i->second << ": " << i->first.toStdString() << std::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@428 391 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
Chris@428 392 // emit currentRowChanged(createIndex(current, 0, 0));
Chris@428 393 // }
Chris@428 394 }
Chris@428 395
Chris@428 396