Paste #BxPjmU4XS

#include "InformativePopup.h"
#include "ui_InformativePopup.h"

#include <QMouseEvent>
#include <QGraphicsDropShadowEffect>
#include <QGraphicsOpacityEffect>

#include <QDebug>

#define FINAL_OPACITY 0.8
#define MIDDLE_OPACITY 0.55

InformativePopup::InformativePopup(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::InformativePopup),
    m_currentMsg(-1),
    m_removeCurrent(false)
{
    ui->setupUi(this);
    setVisible(false);

    QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect(this);
    shadow->setBlurRadius(10);
    shadow->setOffset(0);
    shadow->setColor(QApplication::palette().dark().color());
    ui->frame->setGraphicsEffect(shadow);

    QGraphicsOpacityEffect *m_opacityEffect = new QGraphicsOpacityEffect(this);
    m_opacityEffect->setOpacity(0); // hidden at start
    this->setGraphicsEffect(m_opacityEffect);

    m_opacityAnimation = new QPropertyAnimation(m_opacityEffect, "opacity", this);
    connect(m_opacityAnimation, SIGNAL(finished()), this, SLOT(rotate()));
    m_opacityAnimation->setDuration(400);
    m_opacityAnimation->setEndValue(FINAL_OPACITY);

    m_rotateTimer = new QTimer(this);
    connect(m_rotateTimer, SIGNAL(timeout()), this, SLOT(startRotate()));
    m_rotateTimer->setInterval(5000);
    m_rotateTimer->start();
}

InformativePopup::~InformativePopup()
{
    delete ui;
}

void InformativePopup::startRotate()
{
    if (m_messagesV.size() > 1 ||
        m_removeCurrent || // we are removing the current item (and enter/leave event would break animation)
        m_messagesV.isEmpty() || // fade message as the list is empty now
        sender() == 0) // sender == 0, we are forcing it to rotate
                       // - the current item is being replaced by another and the list has size == 1
    {
        m_opacityAnimation->setStartValue(m_opacityAnimation->currentValue());
        m_opacityAnimation->setEndValue(0);
        m_opacityAnimation->start();
    } else {
//        qDebug() << "startRotate stop" << m_messagesV.size();
        m_rotateTimer->stop();
    }
}

void InformativePopup::statusMessages(const QStringList &messages)
{
    QString title;
    QObject *senderPtr = sender();
    if (senderPtr) {
        title = senderPtr->property("title").toString();
    }

    // Remove messages from the blacklist which aren't in the messages list
    int i = 0;
    while (i < m_blacklistV.size()) {
        const PopMessage &pop = m_blacklistV.at(i);
        if (pop.sender == senderPtr && !messages.contains(pop.message)) {
            // The item is not on the list, remove it from the blacklist
            m_blacklistV.remove(i);
            continue;
        }
        ++i;
    }

    // Remove messages from the current list which were not sent again
    // ie "case open" is not blacklisted and was not sent again
    i = 0;
    while (i < m_messagesV.size()) {
        const PopMessage &pop = m_messagesV.at(i);
        if (pop.sender == senderPtr && !messages.contains(pop.message)) {
            // The item is not on the list, remove it from the normal list
            qDebug() << "REMOVE " << m_currentMsg << m_messagesV.at(i).message;
            m_messagesV.remove(i);
            if (m_currentMsg == i) {
                m_removeCurrent = true;
                startRotate(); // Force a rotate here to hide the message
                --m_currentMsg; // Reduce the current coun
            }

            continue;
        }
        ++i;
    }

    // Insert messages into the end of the list ignoring the blacklisted ones
    foreach (const QString &message, messages) {
        bool blacklisted = false;
        // Check if blacklisted
        foreach (const PopMessage pop, m_blacklistV) {
            if (pop.sender == senderPtr  && pop.message == message) {
                // Warning already on the messages list #ignoring
                blacklisted = true;
                break;
            }
        }

        if (!blacklisted) {
            PopMessage pop;
            pop.message = message;
            pop.title = title;
            pop.sender = senderPtr;
            appendMessage(pop);
        }
    }
}

void InformativePopup::warningMessage(const QString &warning, const QString &title)
{
    PopMessage pop;
    pop.message = warning;
    pop.sender = 0;
    pop.title = title;
    appendMessage(pop);
}

void InformativePopup::reposition()
{
    // The Y position should be the height of the toolBar
    move(QPoint(parentWidget()->size().width() - size().width(), 20));
}

void InformativePopup::rotate()
{
    m_removeCurrent = false;
    if (m_messagesV.isEmpty() && m_opacityAnimation->currentValue().toInt() == 0) {
        hide();
    } else if (m_opacityAnimation->currentValue().toInt() == 0) {
//        qDebug() << "rotate + size" << m_currentMsg << m_messagesV.size();
        m_currentMsg = ((m_currentMsg + 1) % m_messagesV.size());
//        qDebug() << "rotate" << m_currentMsg;
        const PopMessage &pop = m_messagesV.at(m_currentMsg);
        ui->title->setVisible(!pop.title.isEmpty());
        ui->title->setText(pop.title);
        ui->message->setText(pop.message);

        if (!isVisible()) {
            setVisible(true);
        }

        m_opacityAnimation->setStartValue(m_opacityAnimation->currentValue());
        m_opacityAnimation->setEndValue(underMouse() ? MIDDLE_OPACITY : FINAL_OPACITY);
        m_opacityAnimation->start();
    }
}

void InformativePopup::mousePressEvent(QMouseEvent *event)
{
    // Blacklist the current text and rotate
    if (m_messagesV.isEmpty()) {
        return;
    }

    qDebug() << "Click" << m_currentMsg;
    m_removeCurrent = true;
    if (m_messagesV.first().sender) {
        // put the message on the blacklist
        const PopMessage &pop = m_messagesV.at(m_currentMsg);
        m_blacklistV.append(pop);
    }
    m_messagesV.remove(m_currentMsg);
    --m_currentMsg;

    startRotate();

    QWidget::mousePressEvent(event);
}

void InformativePopup::resizeEvent(QResizeEvent *event)
{
    // When text changes the widget is resized, so we need to reposition
    QWidget::resizeEvent(event);
    reposition();
}

void InformativePopup::enterEvent(QEvent *event)
{
    // Mouse enters the widget
    if (!m_removeCurrent) {
        m_opacityAnimation->setStartValue(m_opacityAnimation->currentValue());
        m_opacityAnimation->setEndValue(MIDDLE_OPACITY);
        m_opacityAnimation->start();
        m_rotateTimer->stop();
    }
    QWidget::enterEvent(event);
}

void InformativePopup::leaveEvent(QEvent *event)
{
    // Mouse leaves the widget
    if (!m_removeCurrent) {
        m_opacityAnimation->setStartValue(m_opacityAnimation->currentValue());
        m_opacityAnimation->setEndValue(FINAL_OPACITY);
        m_opacityAnimation->start();
        m_rotateTimer->start();
    }

    QWidget::leaveEvent(event);
}

void InformativePopup::appendMessage(const PopMessage &popMessage)
{
    // Avoid duplicated messages
    foreach (const PopMessage pop, m_messagesV) {
        if (pop.sender  == popMessage.sender &&
            pop.title   == popMessage.title  &&
            pop.message == popMessage.message) {
            // already on the messages list #ignoring
            return;
        }
    }

    // Append the message to the end of the list
    m_messagesV.append(popMessage);

    // if this is the first message
    if (m_messagesV.size() == 1) {
        rotate();
    } else if (m_messagesV.size() == 2 &&
               m_rotateTimer->isActive() == false &&
               underMouse() == false) {
        // Rotate timer stops if we have only 1 message
        // This makes sures it starts again if a new one is added
        m_rotateTimer->start();
    }
}