annotate data/model/ModelDataTableModel.cpp @ 428:3e1d190048f4

* a bit of progress on retaining current row when sorting changes &c
author Chris Cannam
date Tue, 17 Jun 2008 16:07:56 +0000
parents 72ec275e458b
children 304fd0223fa6
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@413 36 }
Chris@413 37
Chris@413 38 ModelDataTableModel::~ModelDataTableModel()
Chris@413 39 {
Chris@413 40 }
Chris@413 41
Chris@413 42 QVariant
Chris@413 43 ModelDataTableModel::data(const QModelIndex &index, int role) const
Chris@413 44 {
Chris@424 45 if (role != Qt::EditRole && role != Qt::DisplayRole) return QVariant();
Chris@413 46 if (!index.isValid()) return QVariant();
Chris@420 47 return m_model->getData(getUnsorted(index.row()), index.column(), role);
Chris@413 48 }
Chris@413 49
Chris@413 50 bool
Chris@413 51 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
Chris@413 52 {
Chris@420 53 if (!index.isValid()) return false;
Chris@421 54 Command *command = m_model->getSetDataCommand(getUnsorted(index.row()),
Chris@421 55 index.column(),
Chris@421 56 value, role);
Chris@420 57 if (command) {
Chris@427 58 emit addCommand(command);
Chris@420 59 return true;
Chris@420 60 } else {
Chris@416 61 return false;
Chris@416 62 }
Chris@413 63 }
Chris@413 64
Chris@427 65 bool
Chris@427 66 ModelDataTableModel::insertRow(int row, const QModelIndex &parent)
Chris@427 67 {
Chris@427 68 if (parent.isValid()) return false;
Chris@427 69
Chris@427 70 emit beginInsertRows(parent, row, row);
Chris@427 71
Chris@427 72 Command *command = m_model->getInsertRowCommand(getUnsorted(row));
Chris@427 73
Chris@427 74 if (command) {
Chris@427 75 emit addCommand(command);
Chris@427 76 }
Chris@427 77
Chris@427 78 emit endInsertRows();
Chris@427 79
Chris@427 80 return (command ? true : false);
Chris@427 81 }
Chris@427 82
Chris@427 83 bool
Chris@427 84 ModelDataTableModel::removeRow(int row, const QModelIndex &parent)
Chris@427 85 {
Chris@427 86 if (parent.isValid()) return false;
Chris@427 87
Chris@427 88 emit beginRemoveRows(parent, row, row);
Chris@427 89
Chris@427 90 Command *command = m_model->getRemoveRowCommand(getUnsorted(row));
Chris@427 91
Chris@427 92 if (command) {
Chris@427 93 emit addCommand(command);
Chris@427 94 }
Chris@427 95
Chris@427 96 emit endRemoveRows();
Chris@427 97
Chris@427 98 return (command ? true : false);
Chris@427 99 }
Chris@427 100
Chris@413 101 Qt::ItemFlags
Chris@413 102 ModelDataTableModel::flags(const QModelIndex &index) const
Chris@413 103 {
Chris@416 104 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
Chris@416 105 Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
Chris@416 106 return flags;
Chris@413 107 }
Chris@413 108
Chris@413 109 QVariant
Chris@413 110 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
Chris@413 111 {
Chris@425 112 if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
Chris@425 113 return section + 1;
Chris@425 114 }
Chris@413 115 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
Chris@420 116 return m_model->getHeading(section);
Chris@425 117 }
Chris@413 118 return QVariant();
Chris@413 119 }
Chris@413 120
Chris@413 121 QModelIndex
Chris@413 122 ModelDataTableModel::index(int row, int column, const QModelIndex &parent) const
Chris@413 123 {
Chris@413 124 return createIndex(row, column, 0);
Chris@413 125 }
Chris@413 126
Chris@413 127 QModelIndex
Chris@413 128 ModelDataTableModel::parent(const QModelIndex &index) const
Chris@413 129 {
Chris@413 130 return QModelIndex();
Chris@413 131 }
Chris@413 132
Chris@413 133 int
Chris@413 134 ModelDataTableModel::rowCount(const QModelIndex &parent) const
Chris@413 135 {
Chris@413 136 if (parent.isValid()) return 0;
Chris@420 137 return m_model->getRowCount();
Chris@413 138 }
Chris@413 139
Chris@413 140 int
Chris@413 141 ModelDataTableModel::columnCount(const QModelIndex &parent) const
Chris@413 142 {
Chris@413 143 if (parent.isValid()) return 0;
Chris@420 144 return m_model->getColumnCount();
Chris@416 145 }
Chris@416 146
Chris@416 147 QModelIndex
Chris@416 148 ModelDataTableModel::getModelIndexForFrame(size_t frame) const
Chris@416 149 {
Chris@420 150 int row = m_model->getRowForFrame(frame);
Chris@420 151 return createIndex(getSorted(row), 0, 0);
Chris@413 152 }
Chris@413 153
Chris@419 154 size_t
Chris@419 155 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
Chris@419 156 {
Chris@420 157 return m_model->getFrameForRow(getUnsorted(index.row()));
Chris@420 158 }
Chris@420 159
Chris@428 160 QModelIndex
Chris@428 161 ModelDataTableModel::getModelIndexForRow(int row) const
Chris@428 162 {
Chris@428 163 return createIndex(row, 0, 0);
Chris@428 164 }
Chris@428 165
Chris@420 166 void
Chris@420 167 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
Chris@420 168 {
Chris@420 169 std::cerr << "ModelDataTableModel::sort(" << column << ", " << sortOrder
Chris@420 170 << ")" << std::endl;
Chris@428 171 int prevCurrent = getCurrentRow();
Chris@422 172 if (m_sortColumn != column) {
Chris@428 173 clearSort();
Chris@422 174 }
Chris@420 175 m_sortColumn = column;
Chris@420 176 m_sortOrdering = sortOrder;
Chris@428 177 int current = getCurrentRow();
Chris@428 178 if (current != prevCurrent) {
Chris@428 179 std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
Chris@428 180 emit currentChanged(createIndex(current, 0, 0));
Chris@428 181 }
Chris@420 182 emit layoutChanged();
Chris@419 183 }
Chris@419 184
Chris@413 185 void
Chris@413 186 ModelDataTableModel::modelChanged()
Chris@413 187 {
Chris@428 188 clearSort();
Chris@413 189 emit layoutChanged();
Chris@413 190 }
Chris@413 191
Chris@413 192 void
Chris@416 193 ModelDataTableModel::modelChanged(size_t f0, size_t f1)
Chris@416 194 {
Chris@420 195 //!!! inefficient
Chris@428 196 clearSort();
Chris@416 197 emit layoutChanged();
Chris@416 198 }
Chris@413 199
Chris@420 200 int
Chris@426 201 ModelDataTableModel::getSorted(int row) const
Chris@413 202 {
Chris@420 203 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 204 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 205 return row;
Chris@420 206 } else {
Chris@420 207 return rowCount() - row - 1;
Chris@420 208 }
Chris@420 209 }
Chris@413 210
Chris@420 211 if (m_sort.empty()) {
Chris@420 212 resort();
Chris@413 213 }
Chris@422 214 int result = 0;
Chris@422 215 if (row >= 0 && row < m_sort.size()) {
Chris@422 216 result = m_sort[row];
Chris@422 217 }
Chris@422 218 if (m_sortOrdering == Qt::DescendingOrder) {
Chris@422 219 result = rowCount() - result - 1;
Chris@422 220 }
Chris@422 221
Chris@422 222 return result;
Chris@413 223 }
Chris@413 224
Chris@420 225 int
Chris@426 226 ModelDataTableModel::getUnsorted(int row) const
Chris@413 227 {
Chris@420 228 if (m_model->isColumnTimeValue(m_sortColumn)) {
Chris@420 229 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@420 230 return row;
Chris@420 231 } else {
Chris@420 232 return rowCount() - row - 1;
Chris@420 233 }
Chris@413 234 }
Chris@422 235
Chris@420 236 if (m_sort.empty()) {
Chris@420 237 resort();
Chris@420 238 }
Chris@422 239
Chris@422 240 int result = 0;
Chris@422 241 if (row >= 0 && row < m_sort.size()) {
Chris@422 242 if (m_sortOrdering == Qt::AscendingOrder) {
Chris@422 243 result = m_rsort[row];
Chris@422 244 } else {
Chris@422 245 result = m_rsort[rowCount() - row - 1];
Chris@422 246 }
Chris@422 247 }
Chris@422 248
Chris@422 249 return result;
Chris@413 250 }
Chris@413 251
Chris@420 252 void
Chris@426 253 ModelDataTableModel::resort() const
Chris@413 254 {
Chris@422 255 bool numeric = (m_model->getSortType(m_sortColumn) ==
Chris@422 256 TabularModel::SortNumeric);
Chris@422 257
Chris@422 258 m_sort.clear();
Chris@422 259 m_rsort.clear();
Chris@422 260
Chris@422 261 if (numeric) resortNumeric();
Chris@422 262 else resortAlphabetical();
Chris@422 263
Chris@422 264 std::map<int, int> tmp;
Chris@422 265
Chris@422 266 // rsort maps from sorted row number to original row number
Chris@422 267
Chris@422 268 for (int i = 0; i < m_rsort.size(); ++i) {
Chris@422 269 tmp[m_rsort[i]] = i;
Chris@422 270 }
Chris@422 271
Chris@422 272 // tmp now maps from original row number to sorted row number
Chris@422 273
Chris@422 274 for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
Chris@422 275 m_sort.push_back(i->second);
Chris@422 276 }
Chris@422 277
Chris@422 278 // and sort now maps from original row number to sorted row number
Chris@413 279 }
Chris@413 280
Chris@422 281 void
Chris@426 282 ModelDataTableModel::resortNumeric() const
Chris@422 283 {
Chris@422 284 typedef std::multimap<double, int> MapType;
Chris@422 285
Chris@422 286 MapType rowMap;
Chris@422 287 int rows = m_model->getRowCount();
Chris@422 288
Chris@422 289 for (int i = 0; i < rows; ++i) {
Chris@424 290 QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 291 rowMap.insert(MapType::value_type(value.toDouble(), i));
Chris@422 292 }
Chris@422 293
Chris@422 294 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@422 295 m_rsort.push_back(i->second);
Chris@422 296 }
Chris@422 297
Chris@422 298 // rsort now maps from sorted row number to original row number
Chris@422 299 }
Chris@422 300
Chris@422 301 void
Chris@426 302 ModelDataTableModel::resortAlphabetical() const
Chris@422 303 {
Chris@422 304 typedef std::multimap<QString, int> MapType;
Chris@422 305
Chris@422 306 MapType rowMap;
Chris@422 307 int rows = m_model->getRowCount();
Chris@422 308
Chris@422 309 for (int i = 0; i < rows; ++i) {
Chris@422 310 QVariant value =
Chris@422 311 m_model->getData(i, m_sortColumn, TabularModel::SortRole);
Chris@422 312 rowMap.insert(MapType::value_type(value.toString(), i));
Chris@422 313 }
Chris@422 314
Chris@422 315 for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
Chris@422 316 m_rsort.push_back(i->second);
Chris@422 317 }
Chris@422 318
Chris@422 319 // rsort now maps from sorted row number to original row number
Chris@422 320 }
Chris@422 321
Chris@428 322 int
Chris@428 323 ModelDataTableModel::getCurrentRow()
Chris@428 324 {
Chris@428 325 return getSorted(m_currentRow);
Chris@428 326 }
Chris@428 327
Chris@428 328 void
Chris@428 329 ModelDataTableModel::setCurrentRow(int row)
Chris@428 330 {
Chris@428 331 m_currentRow = getUnsorted(row);
Chris@428 332 }
Chris@428 333
Chris@428 334 void
Chris@428 335 ModelDataTableModel::clearSort()
Chris@428 336 {
Chris@428 337 // int prevCurrent = getCurrentRow();
Chris@428 338 m_sort.clear();
Chris@428 339 // int current = getCurrentRow(); //!!! no -- not until the sort criteria have changed
Chris@428 340 // if (current != prevCurrent) {
Chris@428 341 // std::cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << std::endl;
Chris@428 342 // emit currentRowChanged(createIndex(current, 0, 0));
Chris@428 343 // }
Chris@428 344 }
Chris@428 345
Chris@428 346