Mercurial > retraceit
view src/metadataview.cpp @ 68:93d3197a883b
Only create application bundle on MacOS
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 26 May 2015 12:42:21 +0200 |
parents | 016cbcb1a233 |
children | 5923d569167b |
line wrap: on
line source
/* Copyright (C) 2015 by ETH Zürich * Software engineering by Intevation GmbH * * This file is Free Software under the GNU GPL (v>=2) * and comes with ABSOLUTELY NO WARRANTY! * See LICENSE.txt for details. */ #include "metadataview.h" #include "qxtcsvmodel.h" #include "filterwidget.h" #include "constants.h" #include <QTextCodec> #include <QTableView> #include <QSortFilterProxyModel> #include <QVBoxLayout> #include <QLabel> #include <QDebug> #include <QModelIndex> #include <QHeaderView> #include <QItemSelectionModel> #include <QSettings> #include <QFontMetrics> #include <QApplication> /**@brief Small wrapper around csv model to enable numerical sorting. */ class numericSortCSVModel : public QxtCsvModel { public: /**@brief returns the data as string, integer or double variant. */ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const { QVariant base = QxtCsvModel::data(index, role); bool ok = false; int intVal = base.toInt(&ok); if (ok) { return intVal; } double dblVal = base.toDouble(&ok); if (ok) { return dblVal; } return base; } }; MetaDataView::MetaDataView(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f), mDateColIdx(-1) { /* Create models */ mSortModel = new QSortFilterProxyModel; mCSVModel = new numericSortCSVModel; setupGUI(); connect(mView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &MetaDataView::viewSelectionChanged); connect(mSortModel, &QSortFilterProxyModel::dataChanged, this, &MetaDataView::dataChanged); return; } void MetaDataView::setupGUI() { QVBoxLayout *baseLayout = new QVBoxLayout; FilterWidget *filterWidget = new FilterWidget(mSortModel); connect(filterWidget, &FilterWidget::filterHasChanged, this, &MetaDataView::applyDefaultSort); connect(filterWidget, &FilterWidget::filterHasChanged, this, &MetaDataView::selectFirstRow); baseLayout->addWidget(filterWidget); mView = new QTableView; mView->setModel(mSortModel); mView->horizontalHeader()->setStretchLastSection(true); // mView->setColumnWidth(0, 60); mView->setSelectionBehavior(QAbstractItemView::SelectRows); mView->setSelectionMode(QAbstractItemView::SingleSelection); mView->setSortingEnabled(true); mView->setEditTriggers(QAbstractItemView::NoEditTriggers); baseLayout->addWidget(mView); mView->verticalHeader()->setVisible(false); setLayout(baseLayout); } QString MetaDataView::parseMetaData(const QString& filePath) { mCSVModel->setSource(filePath, true, ';', QTextCodec::codecForName("UTF8")); if (!mCSVModel->rowCount()) { return tr("Failed to parse file: '%1'").arg(filePath); } mSortModel->setSourceModel(mCSVModel); qDebug() << "Parsed: " << mCSVModel->rowCount() << " rows."; applyDefaultSort(); resizeColsToHeaders(); QSettings settings; const QString displayDate = settings.value(DATE_COLUMN_KEY, DATE_COLUMN_DEFAULT).toString(); settings.setValue(DATE_COLUMN_KEY, displayDate); for (int i=0; i < mSortModel->columnCount(); i++) { QString entry = mSortModel->headerData(i, Qt::Horizontal).toString(); if (entry.toLower() == displayDate.toLower()) { mDateColIdx = i; break; } } if (mDateColIdx == -1) { qDebug() << "Failed to find displayDate column: " << displayDate; mDateColIdx = DATE_COLUMN_FALLBACK_IDX; } return QString(); } void MetaDataView::dataChanged() { QItemSelectionModel *selection = mView->selectionModel(); QModelIndexList selected = selection->selectedIndexes(); qDebug() << "Data Changed."; if (selected.isEmpty()) { /* Nothing selected still we need to emit this signal to update * the viewer otherwise selection changed handles it. */ emit selectionChanged(QString(), 0, mSortModel->rowCount() - 1, QString(), 0); } } void MetaDataView::viewSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected) { if (selected.indexes().isEmpty()) { /* Nothing selected */ return; } /* One row selected */ Q_ASSERT(selected.indexes().count() == mCSVModel->columnCount()); const QModelIndex idx = selected.indexes()[FILENAME_COLUMN_IDX]; const QString dateString = selected.indexes()[mDateColIdx].data().toString(); bool ok; qint64 secondsSinceEpoch = dateString.toLongLong(&ok); QString timestamp = dateString; if (ok) { QDateTime datetime = QDateTime::fromMSecsSinceEpoch(secondsSinceEpoch * 1000); if (datetime.isValid()) { timestamp = datetime.toString(LONG_DATE_FORMAT); } } emit selectionChanged(idx.data().toString(), idx.row(), mSortModel->rowCount() - 1, timestamp, selected.indexes()[0].data().toInt()); qDebug() << "Selection changed: " << idx.data(); } void MetaDataView::selectFirstRow() { qDebug() << "Selecting first row"; selectRow(0); } void MetaDataView::selectRow(int row) { QItemSelectionModel *selection = mView->selectionModel(); if (!mSortModel->hasIndex(row, 0)) { qDebug() << "Invalid row: " << row; return; } QModelIndex newIdx = mSortModel->index(row, 0); selection->select(newIdx, QItemSelectionModel::Clear | QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); } void MetaDataView::selectPrevRow() { QItemSelectionModel *selection = mView->selectionModel(); QModelIndexList selected = selection->selectedIndexes(); int row = 0, col = 0; if (selected.isEmpty()) { qDebug() << "Selection empty. Start at row 0"; if (!mSortModel->hasIndex(row, col)) { qDebug() << "Empty model. Failed to advance."; return; } } else { QModelIndex old = selection->selectedIndexes().first(); if (!mSortModel->hasIndex(old.row() - 1, old.column())) { qDebug() << "No less rows."; return; } row = old.row() - 1; col = old.column(); } QModelIndex newIdx = mSortModel->index(row, col); selection->select(newIdx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); } void MetaDataView::selectNextRow() { QItemSelectionModel *selection = mView->selectionModel(); QModelIndexList selected = selection->selectedIndexes(); int row = 0, col = 0; if (selected.isEmpty()) { qDebug() << "Selection empty. Start at row 0"; if (!mSortModel->hasIndex(row, col)) { qDebug() << "Empty model. Failed to advance."; return; } } else { QModelIndex old = selection->selectedIndexes().first(); if (!mSortModel->hasIndex(old.row() + 1, old.column())) { qDebug() << "No more rows."; return; } row = old.row() + 1; col = old.column(); } QModelIndex newIdx = mSortModel->index(row, col); selection->select(newIdx, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); } void MetaDataView::applyDefaultSort() { QSettings settings; QString sortField = settings.value(SORT_COLUMN_KEY, SORT_COLUMN_DEFAULT).toString(); settings.setValue(SORT_COLUMN_KEY, sortField); bool sortAsc = settings.value(SORT_ORDER_KEY, SORT_ORDER_VALUE).toBool(); settings.setValue(SORT_ORDER_KEY, sortAsc); int idx = -1; for (int i=0; i < mSortModel->columnCount(); i++) { QString entry = mSortModel->headerData(i, Qt::Horizontal).toString(); if (entry.toLower() == sortField.toLower()) { idx = i; break; } } if (idx == -1) { return; } qDebug() << "Applying default sort order on column " << idx; mView->sortByColumn(idx, sortAsc ? Qt::AscendingOrder : Qt::DescendingOrder); } void MetaDataView::resizeColsToHeaders() { QFontMetrics fm(qApp->font()); /* We do this manually here to avoid resizing to the real contents as * we want the columns in the width of the header data. And we only * want to increase that size. */ for (int i=0; i < mSortModel->columnCount(); i++) { const QString entry = mSortModel->headerData(i, Qt::Horizontal).toString(); int w = fm.width(entry) + 20; if (w > mView->horizontalHeader()->sectionSize(i)) { mView->horizontalHeader()->resizeSection(i, w); qDebug() << "Resizing " << i << " to: " << w; } } }