view src/pngplayer.cpp @ 103:43af5fccf61e

Fix possible double free on exit
author Andre Heinecke <andre.heinecke@intevation.de>
date Fri, 18 Nov 2016 12:47:21 +0100
parents 73e6b6b12412
children
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 "pngplayer.h"
#include "constants.h"
#include "imagelabel.h"
#include <QVBoxLayout>
#include <QPixmap>
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QSlider>
#include <QSettings>
#include <QApplication>
#include <QStyle>

#include <QDebug>

PNGPlayer::PNGPlayer(QWidget *parent, Qt::WindowFlags f) : QWidget(parent, f) {
    setupGUI();
    QSettings settings;
    double settingsSecs = settings.value(REPLAY_SPEED_KEY, REPLAY_SPEED_DEFAULT).toDouble();
    if (settingsSecs != 0) {
        mSpeedSlider->setValue(settingsSecs * 1000 / REPLAY_SPEED_STEP_MS);
    }
    speedChanged();
}

void PNGPlayer::setupGUI() {
    QVBoxLayout *baseLayout = new QVBoxLayout;
    mPNGLabel = new ImageLabel;
    mPNGLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    connect(mPNGLabel, &ImageLabel::doubleClicked, this, &PNGPlayer::togglePicFullscreen);
    connect(mPNGLabel, &ImageLabel::closeRequested, this, &PNGPlayer::togglePicFullscreen);

    QHBoxLayout *controlArea = new QHBoxLayout;
    QHBoxLayout *controlBtns = new QHBoxLayout;
    controlArea->addLayout(controlBtns);
    controlArea->addStretch(-1);

    QPushButton *firstBtn = new QPushButton;
    firstBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSkipBackward));
    controlBtns->addWidget(firstBtn);
    connect(firstBtn, &QPushButton::clicked, this, &PNGPlayer::firstClicked);

    QPushButton *prevBtn = new QPushButton;
    prevBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSeekBackward));
    controlBtns->addWidget(prevBtn);
    connect(prevBtn, &QPushButton::clicked, this, &PNGPlayer::back);

    mPlayBtn = new QPushButton;
    mPlayBtn->setCheckable(true);
    mPlayBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaPlay));
    controlBtns->addWidget(mPlayBtn);
    connect(mPlayBtn, &QPushButton::clicked, this, &PNGPlayer::togglePlay);

    QPushButton *nextBtn = new QPushButton;
    nextBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSeekForward));
    connect(nextBtn, &QPushButton::clicked, this, &PNGPlayer::advance);
    controlBtns->addWidget(nextBtn);

    QPushButton *lastBtn = new QPushButton;
    lastBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaSkipForward));
    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(10);
    mSpeedSlider->setTickInterval(1);
    mSpeedSlider->setTickPosition(QSlider::TicksBelow);
    mSpeedSlider->setTracking(false);
    mSpeedSlider->setInvertedAppearance(true);
    mSpeedSlider->setSingleStep(1);
    mSpeedSlider->setPageStep(1);

    speedArea->addWidget(mSpeedSlider);
    connect(mSpeedSlider, &QSlider::valueChanged, this, &PNGPlayer::speedChanged);

    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);
}

void PNGPlayer::showPicture(const QString& fileName, int current, int max,
        const QString& timestamp, int number) {
    QPixmap pic(mBaseDir.filePath(fileName));
    /* If this is too slow we could use a pixmap cache here and do
     * some intelligent preloading */
    if (pic.isNull()) {
        qWarning() << "Failed to load picture: " << fileName;
//        emit error(tr("Failed to load picture: '%1'").arg(fileName));
        QIcon errIcon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxCritical);
        mPNGLabel->setPixmap(errIcon.pixmap(QSize(128, 128)));
    } else {
        mPNGLabel->setPixmap(pic);
    }
    updatePositions(current, max, timestamp, number);
}

void PNGPlayer::updatePositions(int current, int max, const QString& timestamp,
        int number) {
    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 + 1).arg(max + 1) +
            "/ <b>" + tr("Index Nr.:") + " </b>" + QString::number(number) + " / <b>" +
        tr("Timestamp:") + " </b>" + timestamp);

    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.));
    }
    mAdvanceTimer.setInterval(mSecsPerPicture);
}

void PNGPlayer::togglePlay() {
    if (mAdvanceTimer.isActive()) {
        mAdvanceTimer.stop();
        mPlayBtn->setChecked(false);
        mPlayBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaPlay));
    } else {
        mAdvanceTimer.start();
        mPlayBtn->setChecked(true);
        mPlayBtn->setIcon(QApplication::style()->standardIcon(QStyle::SP_MediaPause));
        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);
}

void PNGPlayer::speedChanged() {
    if (mSpeedSlider->value()) {
        setSpeed(mSpeedSlider->value() * REPLAY_SPEED_STEP_MS);
    } else {
        setSpeed(REPLAY_SPEED_STEP_MS / 2);
    }
    QSettings settings;
    settings.setValue(REPLAY_SPEED_KEY, (mSpeedSlider->value() * REPLAY_SPEED_STEP_MS) / 1000.0);
}

void PNGPlayer::togglePicFullscreen() {
    QSettings settings;
    bool enabled = settings.value(DETACHABLE_IMAGE_KEY, DETACHABLE_IMAGE_DEFAULT).toBool();
    settings.setValue(DETACHABLE_IMAGE_KEY, enabled);

    if (!enabled) {
        return;
    }

    QVBoxLayout *baseLayout = qobject_cast<QVBoxLayout*>(layout());
    if (!baseLayout) {
        qWarning() << "Wrong layout!";
        return;
    }
    if (baseLayout->indexOf(mPNGLabel) == -1) {
        baseLayout->insertWidget(0, mPNGLabel);
    } else {
        baseLayout->removeWidget(mPNGLabel);
        mPNGLabel->setParent(NULL, Qt::Tool);
        mPNGLabel->showMaximized();
    }
}

void PNGPlayer::close() {
    QWidget::close();
}
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)