view src/metadataview.cpp @ 35:f10d4e035eec

(issue10) Use width of header as minimum of the column size
author Andre Heinecke <andre.heinecke@intevation.de>
date Wed, 06 May 2015 16:08:41 +0200
parents 4e16fbd10945
children 0c05958d254c
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>

MetaDataView::MetaDataView(QWidget *parent, Qt::WindowFlags f) :
    QWidget(parent, f) {
    /* Create models */
    mSortModel = new QSortFilterProxyModel;
    mCSVModel = new QxtCsvModel;
    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);
    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);

    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();
    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,
                QDateTime());
    }
}

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()[0];
    const QString dateString = selected.indexes()[1].data().toString();
    bool ok;
    qint64 secondsSinceEpoch = dateString.toLongLong(&ok);
    if (!ok) {
        // TODO emit error
        qDebug() << "Unparsable date.";
    }
    QDateTime timestamp = QDateTime::fromMSecsSinceEpoch(secondsSinceEpoch * 1000);
    emit selectionChanged(idx.data().toString(), idx.row(), mSortModel->rowCount() - 1,
            timestamp);
    qDebug() << "Selection changed: " << idx.data();
}

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::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();
    bool sortAsc = settings.value(SORT_ORDER_KEY, SORT_ORDER_VALUE).toBool();

    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 = 1;
            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;
        }
    }
}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)