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 }