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: &apos;%1&apos;</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: &apos;%1&apos;</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../mainwindow.cpp" line="143"/>
+        <location filename="../mainwindow.cpp" line="146"/>
         <source>Parsed: &apos;%1&apos;</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: &apos;%1&apos;</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;
 };
 
 
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)