Mercurial > retraceit
changeset 3:248d5d1cdb38
Add functionalty to control buttons and make picture resizable
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 23 Mar 2015 19:10:01 +0100 |
parents | 97d2c8869c39 |
children | e4748da7140b |
files | src/CMakeLists.txt src/constants.h src/imagelabel.cpp src/imagelabel.h src/l10n/main_de_DE.ts src/mainwindow.cpp src/metadataview.cpp src/metadataview.h src/pngplayer.cpp src/pngplayer.h |
diffstat | 10 files changed, 341 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/src/CMakeLists.txt Mon Mar 23 16:34:42 2015 +0100 +++ b/src/CMakeLists.txt Mon Mar 23 19:10:01 2015 +0100 @@ -19,6 +19,7 @@ util_linux.c metadataview.cpp pngplayer.cpp + imagelabel.cpp ) find_package(Qt5LinguistTools)
--- a/src/constants.h Mon Mar 23 16:34:42 2015 +0100 +++ b/src/constants.h Mon Mar 23 19:10:01 2015 +0100 @@ -53,4 +53,13 @@ /**@def the default value for the root folder pattern */ #define SUB_FOLDER_PATTERN "IP-Addr_Nethz-Login" +/**@def how to format a timestamp */ +#define LONG_DATE_FORMAT "dd.MM.yyyy, hh:mm:ss.zzz" + +/**@def the config key for the replay speed */ +#define REPLAY_SPEED_KEY "MSecsPerPicture" + +/**@def the default value for the replay speed in ms*/ +#define REPLAY_SPEED_DEFAULT 1000 + #endif // CONSTANTS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/imagelabel.cpp Mon Mar 23 19:10:01 2015 +0100 @@ -0,0 +1,28 @@ +#include "imagelabel.h" + +ImageLabel::ImageLabel(QWidget *parent) : + QWidget(parent) { + label = new QLabel(this); + label->setScaledContents(true); + label->setFixedSize(0,0); +} + +void ImageLabel::resizeEvent(QResizeEvent *event) { + QWidget::resizeEvent(event); + resizeImage(); +} + +const QPixmap* ImageLabel::pixmap() const { + return label->pixmap(); +} + +void ImageLabel::setPixmap (const QPixmap &pixmap){ + label->setPixmap(pixmap); + resizeImage(); +} + +void ImageLabel::resizeImage() { + QSize pixSize = label->pixmap()->size(); + pixSize.scale(size(), Qt::KeepAspectRatio); + label->setFixedSize(pixSize); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/imagelabel.h Mon Mar 23 19:10:01 2015 +0100 @@ -0,0 +1,35 @@ +#ifndef IMAGELABEL_H +#define IMAGELABEL_H +/* Copyright (C) 2014 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 <QWidget> +#include <QPixmap> +#include <QLabel> + +class ImageLabel : public QWidget +{ + Q_OBJECT + +public: + explicit ImageLabel(QWidget *parent = 0); + const QPixmap* pixmap() const; + +public slots: + void setPixmap(const QPixmap&); + +protected: + void resizeEvent(QResizeEvent *); + +private slots: + void resizeImage(); + +private: + QLabel *label; +}; + +#endif // IMAGELABEL_H
--- a/src/l10n/main_de_DE.ts Mon Mar 23 16:34:42 2015 +0100 +++ b/src/l10n/main_de_DE.ts Mon Mar 23 19:10:01 2015 +0100 @@ -14,22 +14,22 @@ <translation type="unfinished"></translation> </message> <message> - <location filename="../mainwindow.cpp" line="67"/> + <location filename="../mainwindow.cpp" line="70"/> <source>Error!</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../mainwindow.cpp" line="129"/> + <location filename="../mainwindow.cpp" line="132"/> <source>Failed to access directory: '%1'</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../mainwindow.cpp" line="134"/> + <location filename="../mainwindow.cpp" line="137"/> <source>Failed to access meta data file: '%1'</source> <translation type="unfinished"></translation> </message> <message> - <location filename="../mainwindow.cpp" line="143"/> + <location filename="../mainwindow.cpp" line="146"/> <source>Parsed: '%1'</source> <translation type="unfinished"></translation> </message> @@ -45,10 +45,35 @@ <context> <name>PNGPlayer</name> <message> - <location filename="../pngplayer.cpp" line="32"/> + <location filename="../pngplayer.cpp" line="63"/> + <source>Speed:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../pngplayer.cpp" line="95"/> <source>Failed to load picture: '%1'</source> <translation type="unfinished"></translation> </message> + <message> + <location filename="../pngplayer.cpp" line="108"/> + <source>Screenshot Nr.:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../pngplayer.cpp" line="110"/> + <source>Timestamp:</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../pngplayer.cpp" line="119"/> + <source>%1 second per Picture</source> + <translation type="unfinished"></translation> + </message> + <message> + <location filename="../pngplayer.cpp" line="122"/> + <source>%1 seconds per Picture</source> + <translation type="unfinished"></translation> + </message> </context> <context> <name>main</name>
--- a/src/mainwindow.cpp Mon Mar 23 16:34:42 2015 +0100 +++ b/src/mainwindow.cpp Mon Mar 23 19:10:01 2015 +0100 @@ -36,7 +36,7 @@ MainWindow::MainWindow() : mDataView(NULL) { setStatusBar(new QStatusBar()); - resize(1190, 500); + //resize(1190, 500); setupGUI(); readSettings(); @@ -59,8 +59,11 @@ connect (mPlayer, &PNGPlayer::error, this, &MainWindow::showErrorMessage); connect (mPlayer, &PNGPlayer::advance, mDataView, &MetaDataView::selectNextRow); + connect (mPlayer, &PNGPlayer::back, mDataView, &MetaDataView::selectPrevRow); + connect (mPlayer, &PNGPlayer::jumpToFrame, mDataView, &MetaDataView::selectRow); connect (mDataView, &MetaDataView::selectionChanged, mPlayer, &PNGPlayer::showPicture); + mPlayer->setSpeed(mSettings.value(REPLAY_SPEED_KEY, REPLAY_SPEED_DEFAULT).toInt()); } void MainWindow::showErrorMessage(const QString& errMsg) { @@ -144,4 +147,5 @@ qDebug() << "Parsed: " << metaData.filePath(); mCurFolder = folder; mPlayer->setBaseDir(folder); + mDataView->selectNextRow(); }
--- a/src/metadataview.cpp Mon Mar 23 16:34:42 2015 +0100 +++ b/src/metadataview.cpp Mon Mar 23 19:10:01 2015 +0100 @@ -57,10 +57,53 @@ /* One row selected */ Q_ASSERT(selected.indexes().count() == mCSVModel->columnCount()); const QModelIndex idx = selected.indexes()[0]; - emit selectionChanged(idx.data().toString(), QString()); + 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();
--- a/src/metadataview.h Mon Mar 23 16:34:42 2015 +0100 +++ b/src/metadataview.h Mon Mar 23 19:10:01 2015 +0100 @@ -8,6 +8,7 @@ */ #include <QWidget> #include <QItemSelection> +#include <QDateTime> class QTableView; class QSortFilterProxyModel; @@ -34,15 +35,23 @@ * * @param pictureFile: The file that is now selected. * @param info: Additional info to show with the file.*/ - void selectionChanged(const QString& pictureFile, const QString& info); + void selectionChanged(const QString& pictureFile, int current, int max, + const QDateTime& timestamp); protected slots: + /** @brief internal slot to handle table view selection changes */ void viewSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected); public slots: /**@brief selects the next row and emits a selection changed signal */ void selectNextRow(); + /**@brief selects the previous row and emits a selection changed signal */ + void selectPrevRow(); + + /**@brief select a specific row. */ + void selectRow(int row); + protected: QxtCsvModel *mCSVModel; QSortFilterProxyModel *mSortModel;
--- a/src/pngplayer.cpp Mon Mar 23 16:34:42 2015 +0100 +++ b/src/pngplayer.cpp Mon Mar 23 19:10:01 2015 +0100 @@ -5,26 +5,89 @@ * See LICENSE.txt for details. */ #include "pngplayer.h" +#include "constants.h" +#include "imagelabel.h" #include <QVBoxLayout> #include <QPixmap> #include <QLabel> +#include <QPushButton> +#include <QHBoxLayout> +#include <QSlider> + +#include <QDebug> PNGPlayer::PNGPlayer(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) { setupGUI(); - return; } void PNGPlayer::setupGUI() { QVBoxLayout *baseLayout = new QVBoxLayout; - mPNGLabel = new QLabel; + mPNGLabel = new ImageLabel; + mPNGLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + + QHBoxLayout *controlArea = new QHBoxLayout; + QHBoxLayout *controlBtns = new QHBoxLayout; + controlArea->addLayout(controlBtns); + + QPushButton *firstBtn = new QPushButton("First"); + controlBtns->addWidget(firstBtn); + connect(firstBtn, &QPushButton::clicked, this, &PNGPlayer::firstClicked); + + QPushButton *prevBtn = new QPushButton("Prev"); + controlBtns->addWidget(prevBtn); + connect(prevBtn, &QPushButton::clicked, this, &PNGPlayer::back); + + mPlayBtn = new QPushButton("Play"); + mPlayBtn->setCheckable(true); + controlBtns->addWidget(mPlayBtn); + connect(mPlayBtn, &QPushButton::clicked, this, &PNGPlayer::togglePlay); + + QPushButton *nextBtn = new QPushButton("Next"); + connect(nextBtn, &QPushButton::clicked, this, &PNGPlayer::advance); + controlBtns->addWidget(nextBtn); + + QPushButton *lastBtn = new QPushButton("Last"); + controlBtns->addWidget(lastBtn); + connect(lastBtn, &QPushButton::clicked, this, &PNGPlayer::lastClicked); + + mSlider = new QSlider(Qt::Horizontal); + mSlider->setTickPosition(QSlider::TicksBelow); + connect(mSlider, &QSlider::valueChanged, this, &PNGPlayer::sliderChanged); + connect(mSlider, &QSlider::sliderPressed, this, &PNGPlayer::sliderPressed); + connect(mSlider, &QSlider::sliderReleased, this, &PNGPlayer::sliderReleased); + + QVBoxLayout *speedInfoArea = new QVBoxLayout; + QHBoxLayout *speedArea = new QHBoxLayout; + speedInfoArea->addLayout(speedArea); + + QLabel *speedLabel = new QLabel(tr("Speed:")); + speedArea->addWidget(speedLabel); + + mSpeedSlider = new QSlider(Qt::Horizontal); + mSpeedSlider->setMaximum(10000); + mSpeedSlider->setTickInterval(500); + mSpeedSlider->setTickPosition(QSlider::TicksBelow); + speedArea->addWidget(mSpeedSlider); + + mCurSpeedLabel = new QLabel; + speedArea->addWidget(mCurSpeedLabel); + speedArea->addStretch(-1); + + mPositionLabel = new QLabel; + speedInfoArea->addWidget(mPositionLabel); + + controlArea->addLayout(speedInfoArea); + baseLayout->addWidget(mPNGLabel); + baseLayout->addLayout(controlArea); + baseLayout->addWidget(mSlider); + connect(&mAdvanceTimer, SIGNAL(timeout()), this, SIGNAL(advance())); setLayout(baseLayout); - mAdvanceTimer.setInterval(2000); - mAdvanceTimer.start(); } -void PNGPlayer::showPicture(const QString& fileName, const QString& info) { +void PNGPlayer::showPicture(const QString& fileName, int current, int max, + const QDateTime& timestamp) { QPixmap pic(mBaseDir.filePath(fileName)); /* If this is too slow we could use a pixmap cache here and do * some intelligent preloading */ @@ -33,4 +96,69 @@ return; } mPNGLabel->setPixmap(pic); + updatePositions(current, max, timestamp); } + +void PNGPlayer::updatePositions(int current, int max, const QDateTime& timestamp) { + mMax = max; + mSlider->blockSignals(true); /* We only want user generated changes */ + mSlider->setValue(current); + mSlider->blockSignals(false); + mSlider->setMaximum(max); + mPositionLabel->setText("<b>" + tr("Screenshot Nr.:") + " </b>" + + QString("%1 (%2)").arg(current).arg(max) + " / <b>" + + tr("Timestamp:") + " </b>" + timestamp.toString(LONG_DATE_FORMAT)); + + if (mMax == current && mAdvanceTimer.isActive()) { + togglePlay(); + } +} + +void PNGPlayer::setSpeed(int mSecsPerPicture) { + if (mSecsPerPicture == 1000) { + mCurSpeedLabel->setText(tr("%1 second per Picture"). + arg(mSecsPerPicture / 1000)); + } else { + mCurSpeedLabel->setText(tr("%1 seconds per Picture"). + arg(mSecsPerPicture / 1000)); + } + mSpeedSlider->setValue(mSecsPerPicture); + mAdvanceTimer.setInterval(mSecsPerPicture); +} + +void PNGPlayer::togglePlay() { + if (mAdvanceTimer.isActive()) { + mAdvanceTimer.stop(); + mPlayBtn->setText("Play"); + mPlayBtn->setChecked(false); + } else { + mAdvanceTimer.start(); + mPlayBtn->setText("Pause"); + mPlayBtn->setChecked(true); + emit advance(); + } +} + +void PNGPlayer::sliderChanged() { + qDebug() << "Slider moved. "; + emit jumpToFrame(mSlider->value()); +} + +void PNGPlayer::sliderPressed() { + qDebug() << "Slider pressed. Deactivating timer. "; + mAdvanceTimer.stop(); +} + +void PNGPlayer::sliderReleased() { + if (mPlayBtn->isChecked()) { + mAdvanceTimer.start(); + } +} + +void PNGPlayer::firstClicked() { + emit jumpToFrame(0); +} + +void PNGPlayer::lastClicked() { + emit jumpToFrame(mMax); +}
--- a/src/pngplayer.h Mon Mar 23 16:34:42 2015 +0100 +++ b/src/pngplayer.h Mon Mar 23 19:10:01 2015 +0100 @@ -9,8 +9,12 @@ #include <QWidget> #include <QDir> #include <QTimer> +#include <QDateTime> +class QSlider; class QLabel; +class QPushButton; +class ImageLabel; class PNGPlayer: public QWidget { @@ -22,16 +26,42 @@ protected: void setupGUI(); +protected slots: + /**@brief the view slider was changed manually */ + void sliderChanged(); + /**@brief the view slider was pressed */ + void sliderPressed(); + /**@brief the view slider was released */ + void sliderReleased(); + + /**@brief jump to the first frame */ + void firstClicked(); + + /**@brief jump to the last frame */ + void lastClicked(); + public slots: /**@brief show a PNG in the viewer. * * @param fileName: The picture file to show. - * @param info: Additional meta data to show with the image. + * @param current: The row index of the currently shown image. + * @param max: The row count. + * @param timestamp: The timestamp of the image. */ - void showPicture(const QString& fileName, const QString& info); + void showPicture(const QString& fileName, int current, int max, + const QDateTime& timestamp); + /**@brief set the base dir to which filenames will be relative. */ void setBaseDir(const QString& dirName) { mBaseDir.setPath(dirName); } + /**@brief update positional information / slider current / max info. */ + void updatePositions(int current, int max, const QDateTime& timestamp); + + /**@brief set the replay speed */ + void setSpeed(int mSecsPerPicture); + + /**@brief start or pause the replay */ + void togglePlay(); Q_SIGNALS: /** @brief Emited if something went wrong. e.g. file not readable */ void error(const QString& msg); @@ -39,10 +69,23 @@ /** @brief Emited if the player wants to advance to the next picture */ void advance(); + /** @brief Emited if the player wants to go back to the last picture */ + void back(); + + /** @brief Emited it the player wants to advance to a specific frame. */ + void jumpToFrame(int frame); + protected: - QLabel * mPNGLabel; + ImageLabel *mPNGLabel; + QLabel *mPositionLabel, + *mCurSpeedLabel; + int mCurSpeed; + int mMax; QDir mBaseDir; QTimer mAdvanceTimer; + QSlider *mSlider, + *mSpeedSlider; + QPushButton *mPlayBtn; };