File indexing completed on 2024-05-19 04:29:13
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 #include "KisIdleTasksManager.h" 0007 0008 #include <QQueue> 0009 #include <kis_idle_watcher.h> 0010 #include <kis_image.h> 0011 #include <KisMpl.h> 0012 #include <boost/none.hpp> 0013 0014 0015 namespace { 0016 struct TaskStruct { 0017 int id = 0; 0018 KisIdleTaskStrokeStrategyFactory factory; 0019 }; 0020 } 0021 0022 struct KisIdleTasksManager::Private 0023 { 0024 KisImageWSP image; 0025 KisIdleWatcher idleWatcher; 0026 QVector<TaskStruct> tasks; 0027 QQueue<int> queue; 0028 QWeakPointer<boost::none_t> currentTaskCookie; 0029 }; 0030 0031 KisIdleTasksManager::KisIdleTasksManager() 0032 : m_d(new Private()) 0033 { 0034 connect(&m_d->idleWatcher, SIGNAL(startedIdleMode()), SLOT(slotImageIsIdle())); 0035 connect(&m_d->idleWatcher, SIGNAL(imageModified()), SLOT(slotImageIsModified())); 0036 } 0037 0038 KisIdleTasksManager::~KisIdleTasksManager() = default; 0039 0040 void KisIdleTasksManager::setImage(KisImageSP image) 0041 { 0042 m_d->idleWatcher.setTrackedImage(image); 0043 m_d->image = image; 0044 m_d->queue.clear(); 0045 0046 if (image) { 0047 slotImageIsModified(); 0048 m_d->idleWatcher.triggerCountdownNoDelay(); 0049 } 0050 } 0051 0052 int KisIdleTasksManager::addIdleTask(KisIdleTaskStrokeStrategyFactory factory) 0053 { 0054 /** 0055 * TODO: don't restart the whole queue on the the task change, just 0056 * restart the currently added task 0057 */ 0058 0059 const int newId = 0060 !m_d->tasks.isEmpty() ? 0061 m_d->tasks.last().id + 1 : 0; 0062 0063 m_d->tasks.append({newId, factory}); 0064 triggerIdleTask(newId); 0065 0066 return newId; 0067 } 0068 0069 void KisIdleTasksManager::removeIdleTask(int id) 0070 { 0071 { 0072 auto it = std::remove_if(m_d->tasks.begin(), m_d->tasks.end(), 0073 kismpl::mem_equal_to(&TaskStruct::id, id)); 0074 KIS_SAFE_ASSERT_RECOVER_NOOP(it != m_d->tasks.end()); 0075 m_d->tasks.erase(it, m_d->tasks.end()); 0076 } 0077 0078 { 0079 auto it = std::remove(m_d->queue.begin(), m_d->queue.end(), id); 0080 m_d->queue.erase(it, m_d->queue.end()); 0081 } 0082 } 0083 0084 void KisIdleTasksManager::triggerIdleTask(int id) 0085 { 0086 { 0087 // just verify that this tasks actually exists 0088 auto it = std::find_if(m_d->tasks.begin(), m_d->tasks.end(), 0089 kismpl::mem_equal_to(&TaskStruct::id, id)); 0090 KIS_SAFE_ASSERT_RECOVER_NOOP(it != m_d->tasks.end()); 0091 } 0092 0093 auto it = std::find(m_d->queue.begin(), m_d->queue.end(), id); 0094 if (it == m_d->queue.end()) { 0095 m_d->queue.enqueue(id); 0096 } 0097 0098 m_d->idleWatcher.triggerCountdownNoDelay(); 0099 } 0100 0101 KisIdleTasksManager::TaskGuard 0102 KisIdleTasksManager::addIdleTaskWithGuard(KisIdleTaskStrokeStrategyFactory factory) 0103 { 0104 return {addIdleTask(factory), this}; 0105 } 0106 0107 void KisIdleTasksManager::slotImageIsModified() 0108 { 0109 m_d->queue.clear(); 0110 m_d->queue.reserve(m_d->tasks.size()); 0111 std::transform(m_d->tasks.begin(), m_d->tasks.end(), 0112 std::back_inserter(m_d->queue), 0113 std::mem_fn(&TaskStruct::id)); 0114 } 0115 0116 void KisIdleTasksManager::slotImageIsIdle() 0117 { 0118 KisImageSP image = m_d->image; 0119 if (!image) return; 0120 0121 if (m_d->currentTaskCookie) { 0122 m_d->idleWatcher.restartCountdown(); 0123 return; 0124 } 0125 0126 if (m_d->queue.isEmpty()) return; 0127 0128 const int newTaskId = m_d->queue.dequeue(); 0129 0130 auto it = std::find_if(m_d->tasks.begin(), m_d->tasks.end(), 0131 kismpl::mem_equal_to(&TaskStruct::id, newTaskId)); 0132 KIS_SAFE_ASSERT_RECOVER_NOOP(it != m_d->tasks.end()); 0133 0134 KisIdleTaskStrokeStrategy *strategy = it->factory(image); 0135 0136 connect(strategy, SIGNAL(sigIdleTaskFinished()), SLOT(slotTaskIsCompleted())); 0137 m_d->currentTaskCookie = strategy->idleTaskCookie(); 0138 0139 KisStrokeId strokeId = image->startStroke(strategy); 0140 image->endStroke(strokeId); 0141 } 0142 0143 void KisIdleTasksManager::slotTaskIsCompleted() 0144 { 0145 if (m_d->queue.isEmpty()) { 0146 // all tasks are completed! 0147 } else { 0148 if (m_d->idleWatcher.isIdle()) { 0149 slotImageIsIdle(); 0150 } else if (!m_d->idleWatcher.isCounting()) { 0151 m_d->idleWatcher.restartCountdown(); 0152 } 0153 } 0154 } 0155