File indexing completed on 2024-05-19 04:26:15

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_idle_watcher.h"
0008 
0009 #include <QTimer>
0010 #include "kis_image.h"
0011 #include "kis_signal_auto_connection.h"
0012 #include "kis_signal_compressor.h"
0013 
0014 
0015 struct KisIdleWatcher::Private
0016 {
0017     static const int IDLE_CHECK_COUNT = 4; /* ticks */
0018 
0019     Private(int delay, KisIdleWatcher *q)
0020         : imageModifiedCompressor(delay,
0021                                   KisSignalCompressor::POSTPONE, q),
0022           idleCheckCounter(0)
0023     {
0024         idleCheckTimer.setSingleShot(true);
0025         idleCheckTimer.setInterval(delay);
0026     }
0027 
0028     KisSignalAutoConnectionsStore connectionsStore;
0029     QVector<KisImageWSP> trackedImages;
0030 
0031     KisSignalCompressor imageModifiedCompressor;
0032 
0033     QTimer idleCheckTimer;
0034 
0035     /**
0036      * We wait until the counter reaches IDLE_CHECK_COUNT, then consider the
0037      * image to be really "idle". If the counter is negative, it means that
0038      * "no delay" update is triggered, which desables couting and the event
0039      * is triggered on the next non-busy tick.
0040      */
0041     int idleCheckCounter;
0042 };
0043 
0044 KisIdleWatcher::KisIdleWatcher(int delay, QObject *parent)
0045     : QObject(parent), m_d(new Private(delay, this))
0046 {
0047     connect(&m_d->imageModifiedCompressor, SIGNAL(timeout()), SLOT(startIdleCheck()));
0048     connect(&m_d->idleCheckTimer, SIGNAL(timeout()), SLOT(slotIdleCheckTick()));
0049 }
0050 
0051 KisIdleWatcher::~KisIdleWatcher()
0052 {
0053 }
0054 
0055 bool KisIdleWatcher::isIdle() const
0056 {
0057     bool idle = true;
0058 
0059     Q_FOREACH (KisImageSP image, m_d->trackedImages) {
0060         if (!image) continue;
0061 
0062         if (!image->isIdle()) {
0063             idle = false;
0064             break;
0065         }
0066     }
0067 
0068     return idle;
0069 }
0070 
0071 bool KisIdleWatcher::isCounting() const
0072 {
0073     return m_d->idleCheckTimer.isActive();
0074 }
0075 
0076 void KisIdleWatcher::setTrackedImages(const QVector<KisImageSP> &images)
0077 {
0078     m_d->connectionsStore.clear();
0079     m_d->trackedImages.clear();
0080 
0081     Q_FOREACH (KisImageSP image, images) {
0082         if (image) {
0083             m_d->trackedImages << image;
0084             m_d->connectionsStore.addConnection(image, SIGNAL(sigImageModified()),
0085                                                 this, SLOT(slotImageModified()));
0086 
0087             m_d->connectionsStore.addConnection(image, SIGNAL(sigIsolatedModeChanged()),
0088                                                 this, SLOT(slotImageModified()));
0089         }
0090     }
0091 }
0092 
0093 void KisIdleWatcher::setTrackedImage(KisImageSP image)
0094 {
0095     QVector<KisImageSP> images;
0096     images << image;
0097     setTrackedImages(images);
0098 }
0099 
0100 void KisIdleWatcher::restartCountdown()
0101 {
0102     stopIdleCheck();
0103     m_d->imageModifiedCompressor.start();
0104 }
0105 
0106 void KisIdleWatcher::triggerCountdownNoDelay()
0107 {
0108     stopIdleCheck();
0109     m_d->idleCheckCounter = -1;
0110     m_d->idleCheckTimer.start();
0111 }
0112 
0113 void KisIdleWatcher::slotImageModified()
0114 {
0115     if (m_d->idleCheckCounter >= 0) {
0116         restartCountdown();
0117     }
0118     Q_EMIT imageModified();
0119 }
0120 
0121 void KisIdleWatcher::startIdleCheck()
0122 {
0123     m_d->idleCheckCounter = 0;
0124     m_d->idleCheckTimer.start();
0125 }
0126 
0127 void KisIdleWatcher::stopIdleCheck()
0128 {
0129     m_d->idleCheckTimer.stop();
0130     m_d->idleCheckCounter = 0;
0131 }
0132 
0133 void KisIdleWatcher::slotIdleCheckTick()
0134 {
0135     if (isIdle()) {
0136         if (m_d->idleCheckCounter < 0 ||
0137             m_d->idleCheckCounter >= Private::IDLE_CHECK_COUNT) {
0138 
0139             stopIdleCheck();
0140             if (!m_d->trackedImages.isEmpty()) {
0141                 emit startedIdleMode();
0142             }
0143         } else {
0144             m_d->idleCheckCounter++;
0145             m_d->idleCheckTimer.start();
0146         }
0147     } else {
0148         if (m_d->idleCheckCounter >= 0) {
0149             restartCountdown();
0150         } else {
0151             m_d->idleCheckTimer.start();
0152         }
0153     }
0154 }