svcore  1.9
ModelDataTableModel.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2008 QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "ModelDataTableModel.h"
00017 
00018 #include "TabularModel.h"
00019 #include "Model.h"
00020 
00021 #include <map>
00022 #include <algorithm>
00023 #include <iostream>
00024 
00025 ModelDataTableModel::ModelDataTableModel(TabularModel *m) :
00026     m_model(m),
00027     m_sortColumn(0),
00028     m_sortOrdering(Qt::AscendingOrder),
00029     m_currentRow(0)
00030 {
00031     Model *baseModel = dynamic_cast<Model *>(m);
00032 
00033     connect(baseModel, SIGNAL(modelChanged()), this, SLOT(modelChanged()));
00034     connect(baseModel, SIGNAL(modelChangedWithin(int, int)),
00035             this, SLOT(modelChangedWithin(int, int)));
00036     connect(baseModel, SIGNAL(aboutToBeDeleted()),
00037             this, SLOT(modelAboutToBeDeleted()));
00038 }
00039 
00040 ModelDataTableModel::~ModelDataTableModel()
00041 {
00042 }
00043 
00044 QVariant
00045 ModelDataTableModel::data(const QModelIndex &index, int role) const
00046 {
00047     if (!m_model) return QVariant();
00048     if (role != Qt::EditRole && role != Qt::DisplayRole) return QVariant();
00049     if (!index.isValid()) return QVariant();
00050     return m_model->getData(getUnsorted(index.row()), index.column(), role);
00051 }
00052 
00053 bool
00054 ModelDataTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
00055 {
00056     if (!m_model) return false;
00057     if (!index.isValid()) return false;
00058     Command *command = m_model->getSetDataCommand(getUnsorted(index.row()),
00059                                                   index.column(),
00060                                                   value, role);
00061     if (command) {
00062         emit addCommand(command);
00063         return true;
00064     } else {
00065         return false;
00066     }
00067 }
00068 
00069 bool
00070 ModelDataTableModel::insertRow(int row, const QModelIndex &parent)
00071 {
00072     if (!m_model) return false;
00073     if (parent.isValid()) return false;
00074 
00075     emit beginInsertRows(parent, row, row);
00076 
00077     Command *command = m_model->getInsertRowCommand(getUnsorted(row));
00078 
00079     if (command) {
00080         emit addCommand(command);
00081     }
00082 
00083     emit endInsertRows();
00084 
00085     return (command ? true : false);
00086 }
00087 
00088 bool
00089 ModelDataTableModel::removeRow(int row, const QModelIndex &parent)
00090 {
00091     if (!m_model) return false;
00092     if (parent.isValid()) return false;
00093 
00094     emit beginRemoveRows(parent, row, row);
00095 
00096     Command *command = m_model->getRemoveRowCommand(getUnsorted(row));
00097 
00098     if (command) {
00099         emit addCommand(command);
00100     }
00101 
00102     emit endRemoveRows();
00103 
00104     return (command ? true : false);
00105 }
00106 
00107 Qt::ItemFlags
00108 ModelDataTableModel::flags(const QModelIndex &) const
00109 {
00110     Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsEditable |
00111         Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsSelectable;
00112     return flags;
00113 }
00114 
00115 QVariant
00116 ModelDataTableModel::headerData(int section, Qt::Orientation orientation, int role) const
00117 {
00118     if (!m_model) return QVariant();
00119 
00120     if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
00121         return section + 1;
00122     }
00123     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
00124         return m_model->getHeading(section);
00125     } 
00126     return QVariant();
00127 }
00128 
00129 QModelIndex
00130 ModelDataTableModel::index(int row, int column, const QModelIndex &) const
00131 {
00132     return createIndex(row, column, (void *)0);
00133 }
00134 
00135 QModelIndex
00136 ModelDataTableModel::parent(const QModelIndex &) const
00137 {
00138     return QModelIndex();
00139 }
00140 
00141 int
00142 ModelDataTableModel::rowCount(const QModelIndex &parent) const
00143 {
00144     if (!m_model) return 0;
00145     if (parent.isValid()) return 0;
00146     return m_model->getRowCount();
00147 }
00148 
00149 int
00150 ModelDataTableModel::columnCount(const QModelIndex &parent) const
00151 {
00152     if (!m_model) return 0;
00153     if (parent.isValid()) return 0;
00154     return m_model->getColumnCount();
00155 }
00156 
00157 QModelIndex 
00158 ModelDataTableModel::getModelIndexForFrame(int frame) const
00159 {
00160     if (!m_model) return createIndex(0, 0);
00161     int row = m_model->getRowForFrame(frame);
00162     return createIndex(getSorted(row), 0, (void *)0);
00163 }
00164 
00165 int 
00166 ModelDataTableModel::getFrameForModelIndex(const QModelIndex &index) const
00167 {
00168     if (!m_model) return 0;
00169     return m_model->getFrameForRow(getUnsorted(index.row()));
00170 }
00171 
00172 QModelIndex
00173 ModelDataTableModel::findText(QString text) const
00174 {
00175     if (text == "") return QModelIndex();
00176     int rows = rowCount();
00177     int cols = columnCount();
00178     int current = getCurrentRow();
00179     for (int row = 1; row <= rows; ++row) {
00180         int wrapped = (row + current) % rows;
00181         for (int col = 0; col < cols; ++col) {
00182             if (m_model->getSortType(col) != TabularModel::SortAlphabetical) {
00183                 continue;
00184             }
00185             QString cell = m_model->getData(getUnsorted(wrapped), col,
00186                                             Qt::DisplayRole).toString();
00187             if (cell.contains(text, Qt::CaseInsensitive)) {
00188                 return createIndex(wrapped, col);
00189             }
00190         }
00191     }
00192     return QModelIndex();
00193 }
00194 
00195 void
00196 ModelDataTableModel::sort(int column, Qt::SortOrder sortOrder)
00197 {
00198 //    SVDEBUG << "ModelDataTableModel::sort(" << column << ", " << sortOrder
00199 //              << ")" << endl;
00200     int prevCurrent = getCurrentRow();
00201     if (m_sortColumn != column) {
00202         clearSort();
00203     }
00204     m_sortColumn = column;
00205     m_sortOrdering = sortOrder;
00206     int current = getCurrentRow();
00207     if (current != prevCurrent) {
00208 //         cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << endl;
00209         emit currentChanged(createIndex(current, 0, (void *)0));
00210     }
00211     emit layoutChanged();
00212 }
00213 
00214 void
00215 ModelDataTableModel::modelChanged()
00216 {
00217     clearSort();
00218     emit layoutChanged();
00219 }
00220 
00221 void 
00222 ModelDataTableModel::modelChangedWithin(int, int)
00223 {
00225     clearSort();
00226     emit layoutChanged();
00227 }
00228 
00229 void
00230 ModelDataTableModel::modelAboutToBeDeleted()
00231 {
00232     m_model = 0;
00233     emit modelRemoved();
00234 }
00235 
00236 int
00237 ModelDataTableModel::getSorted(int row) const
00238 {
00239     if (!m_model) return row;
00240 
00241     if (m_model->isColumnTimeValue(m_sortColumn)) {
00242         if (m_sortOrdering == Qt::AscendingOrder) {
00243             return row;
00244         } else {
00245             return rowCount() - row - 1;
00246         }
00247     }
00248 
00249     if (m_sort.empty()) {
00250         resort();
00251     }
00252     int result = 0;
00253     if (row >= 0 && row < (int)m_sort.size()) {
00254         result = m_sort[row];
00255     }
00256     if (m_sortOrdering == Qt::DescendingOrder) {
00257         result = rowCount() - result - 1;
00258     }
00259 
00260     return result;
00261 }
00262 
00263 int
00264 ModelDataTableModel::getUnsorted(int row) const
00265 {
00266     if (!m_model) return row;
00267 
00268     if (m_model->isColumnTimeValue(m_sortColumn)) {
00269         if (m_sortOrdering == Qt::AscendingOrder) {
00270             return row;
00271         } else {
00272             return rowCount() - row - 1;
00273         }
00274     }
00275 
00276     if (m_sort.empty()) {
00277         resort();
00278     }
00279 
00280     int result = 0;
00281     if (row >= 0 && row < (int)m_sort.size()) {
00282         if (m_sortOrdering == Qt::AscendingOrder) {
00283             result = m_rsort[row];
00284         } else {
00285             result = m_rsort[rowCount() - row - 1];
00286         }
00287     }
00288 
00289     return result;
00290 }
00291 
00292 void
00293 ModelDataTableModel::resort() const
00294 {
00295     if (!m_model) return;
00296 
00297     bool numeric = (m_model->getSortType(m_sortColumn) ==
00298                     TabularModel::SortNumeric);
00299 
00300 //    cerr << "resort: numeric == " << numeric << endl;
00301 
00302     m_sort.clear();
00303     m_rsort.clear();
00304 
00305     if (numeric) resortNumeric();
00306     else resortAlphabetical();
00307 
00308     std::map<int, int> tmp;
00309 
00310     // rsort maps from sorted row number to original row number
00311 
00312     for (int i = 0; i < (int)m_rsort.size(); ++i) {
00313         tmp[m_rsort[i]] = i;
00314     }
00315 
00316     // tmp now maps from original row number to sorted row number
00317 
00318     for (std::map<int, int>::const_iterator i = tmp.begin(); i != tmp.end(); ++i) {
00319         m_sort.push_back(i->second);
00320     }
00321 
00322     // and sort now maps from original row number to sorted row number
00323 }
00324 
00325 void
00326 ModelDataTableModel::resortNumeric() const
00327 {
00328     if (!m_model) return;
00329 
00330     typedef std::multimap<double, int> MapType;
00331 
00332     MapType rowMap;
00333     int rows = m_model->getRowCount();
00334 
00335     for (int i = 0; i < rows; ++i) {
00336         QVariant value = m_model->getData(i, m_sortColumn, TabularModel::SortRole);
00337         rowMap.insert(MapType::value_type(value.toDouble(), i));
00338     }
00339 
00340     for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
00341 //        cerr << "resortNumeric: " << i->second << ": " << i->first << endl;
00342         m_rsort.push_back(i->second);
00343     }
00344 
00345     // rsort now maps from sorted row number to original row number
00346 }
00347 
00348 void
00349 ModelDataTableModel::resortAlphabetical() const
00350 {
00351     if (!m_model) return;
00352 
00353     typedef std::multimap<QString, int> MapType;
00354 
00355     MapType rowMap;
00356     int rows = m_model->getRowCount();
00357 
00358     for (int i = 0; i < rows; ++i) {
00359         QVariant value =
00360             m_model->getData(i, m_sortColumn, TabularModel::SortRole);
00361         rowMap.insert(MapType::value_type(value.toString(), i));
00362     }
00363 
00364     for (MapType::iterator i = rowMap.begin(); i != rowMap.end(); ++i) {
00365 //        cerr << "resortAlphabetical: " << i->second << ": " << i->first << endl;
00366         m_rsort.push_back(i->second);
00367     }
00368 
00369     // rsort now maps from sorted row number to original row number
00370 }
00371 
00372 int
00373 ModelDataTableModel::getCurrentRow() const
00374 {
00375     return getSorted(m_currentRow);
00376 }
00377 
00378 void
00379 ModelDataTableModel::setCurrentRow(int row)
00380 {
00381     m_currentRow = getUnsorted(row);
00382 }
00383 
00384 void
00385 ModelDataTableModel::clearSort()
00386 {
00387 //    int prevCurrent = getCurrentRow();
00388     m_sort.clear();
00389 //    int current = getCurrentRow(); //!!! no --  not until the sort criteria have changed
00390 //    if (current != prevCurrent) {
00391 //        cerr << "Current row changed from " << prevCurrent << " to " << current << " for underlying row " << m_currentRow << endl;
00392 //        emit currentRowChanged(createIndex(current, 0, 0));
00393 //    }
00394 }
00395 
00396