File indexing completed on 2025-01-05 04:59:41
0001 /* 0002 * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org> 0003 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 0007 #include "akonaditaskqueries.h" 0008 0009 #include "utils/datetime.h" 0010 0011 #include <QTimer> 0012 0013 using namespace Akonadi; 0014 0015 TaskQueries::TaskQueries(const StorageInterface::Ptr &storage, 0016 const SerializerInterface::Ptr &serializer, 0017 const MonitorInterface::Ptr &monitor, 0018 const Cache::Ptr &cache) 0019 : m_serializer(serializer), 0020 m_monitor(monitor), 0021 m_cache(cache), 0022 m_helpers(new LiveQueryHelpers(serializer, storage)), 0023 m_integrator(new LiveQueryIntegrator(serializer, monitor)), 0024 m_workdayPollTimer(new QTimer(this)) 0025 { 0026 m_workdayPollTimer->setInterval(30000); 0027 connect(m_workdayPollTimer, &QTimer::timeout, this, &TaskQueries::onWorkdayPollTimeout); 0028 0029 m_integrator->addRemoveHandler([this] (const Item &item) { 0030 m_findChildren.remove(item.id()); 0031 m_findContexts.remove(item.id()); 0032 }); 0033 0034 connect(m_monitor.data(), &MonitorInterface::itemChanged, this, [this] (const Item &item) { 0035 const auto it = m_findContexts.find(item.id()); 0036 if (it == m_findContexts.end()) 0037 return; 0038 0039 m_findContextsItem[item.id()] = item; 0040 (*it)->reset(); 0041 }); 0042 } 0043 0044 int TaskQueries::workdayPollInterval() const 0045 { 0046 return m_workdayPollTimer->interval(); 0047 } 0048 0049 void TaskQueries::setWorkdayPollInterval(int interval) 0050 { 0051 m_workdayPollTimer->setInterval(interval); 0052 } 0053 0054 TaskQueries::TaskResult::Ptr TaskQueries::findAll() const 0055 { 0056 auto fetch = m_helpers->fetchItems(const_cast<TaskQueries*>(this)); 0057 auto predicate = [this] (const Akonadi::Item &item) { 0058 return m_serializer->isTaskItem(item); 0059 }; 0060 m_integrator->bind("TaskQueries::findAll", m_findAll, fetch, predicate); 0061 return m_findAll->result(); 0062 } 0063 0064 TaskQueries::TaskResult::Ptr TaskQueries::findChildren(Domain::Task::Ptr task) const 0065 { 0066 Akonadi::Item item = m_serializer->createItemFromTask(task); 0067 auto &query = m_findChildren[item.id()]; 0068 auto fetch = m_helpers->fetchSiblings(item, const_cast<TaskQueries*>(this)); 0069 auto predicate = [this, task] (const Akonadi::Item &childItem) { 0070 return m_serializer->isTaskChild(task, childItem); 0071 }; 0072 m_integrator->bind("TaskQueries::findChildren", query, fetch, predicate); 0073 return query->result(); 0074 } 0075 0076 TaskQueries::ProjectResult::Ptr TaskQueries::findProject(Domain::Task::Ptr task) const 0077 { 0078 Akonadi::Item childItem = m_serializer->createItemFromTask(task); 0079 auto &query = m_findProject[childItem.id()]; 0080 auto fetch = m_helpers->fetchTaskAndAncestors(task, const_cast<TaskQueries*>(this)); 0081 auto predicate = [this, childItem] (const Akonadi::Item &item) { 0082 return m_serializer->isProjectItem(item); 0083 }; 0084 auto compare = [] (const Akonadi::Item &item1, const Akonadi::Item &item2) { 0085 return item1.id() == item2.id(); 0086 }; 0087 m_integrator->bindRelationship("TaskQueries::findProject", query, fetch, compare, predicate); 0088 return query->result(); 0089 } 0090 0091 TaskQueries::DataSourceResult::Ptr TaskQueries::findDataSource(Domain::Task::Ptr task) const 0092 { 0093 Akonadi::Item item = m_serializer->createItemFromTask(task); 0094 auto &query = m_findDataSource[item.id()]; 0095 auto fetch = m_helpers->fetchItemCollection(item, const_cast<TaskQueries*>(this)); 0096 auto predicate = [] (const Akonadi::Collection &) { return true; }; 0097 0098 m_integrator->bind("TaskQueries::findDataSource", query, fetch, predicate); 0099 return query->result(); 0100 } 0101 0102 TaskQueries::TaskResult::Ptr TaskQueries::findTopLevel() const 0103 { 0104 Q_ASSERT(m_cache); 0105 auto fetch = m_helpers->fetchItems(const_cast<TaskQueries*>(this)); 0106 auto predicate = [this] (const Akonadi::Item &item) { 0107 // Tasks with no parent, or whose parent is a project (not a task) 0108 if (!m_serializer->isTaskItem(item)) 0109 return false; 0110 0111 const auto items = m_cache->items(item.parentCollection()); 0112 auto currentItem = item; 0113 auto parentUid = m_serializer->relatedUidFromItem(currentItem); 0114 while (!parentUid.isEmpty()) { 0115 const auto parent = std::find_if(items.cbegin(), items.cend(), 0116 [this, parentUid] (const Akonadi::Item &item) { 0117 return m_serializer->itemUid(item) == parentUid; 0118 }); 0119 if (parent == items.cend()) 0120 break; 0121 0122 if (m_serializer->isTaskItem(*parent)) 0123 return false; 0124 0125 currentItem = *parent; 0126 parentUid = m_serializer->relatedUidFromItem(currentItem); 0127 } 0128 return true; 0129 }; 0130 m_integrator->bind("TaskQueries::findTopLevel", m_findTopLevel, fetch, predicate); 0131 return m_findTopLevel->result(); 0132 } 0133 0134 TaskQueries::TaskResult::Ptr TaskQueries::findInboxTopLevel() const 0135 { 0136 auto fetch = m_helpers->fetchItems(const_cast<TaskQueries*>(this)); 0137 auto predicate = [this] (const Akonadi::Item &item) { 0138 // Tasks without a parent (neither task nor project) 0139 return m_serializer->isTaskItem(item) && m_serializer->relatedUidFromItem(item).isEmpty(); 0140 }; 0141 m_integrator->bind("TaskQueries::findInboxTopLevel", m_findInboxTopLevel, fetch, predicate); 0142 return m_findInboxTopLevel->result(); 0143 } 0144 0145 TaskQueries::TaskResult::Ptr TaskQueries::findWorkdayTopLevel() const 0146 { 0147 if (!m_findWorkdayTopLevel) { 0148 m_workdayPollTimer->start(); 0149 m_today = Utils::DateTime::currentDate(); 0150 } 0151 0152 auto fetch = m_helpers->fetchItems(const_cast<TaskQueries*>(this)); 0153 auto isWorkdayItem = [this] (const Akonadi::Item &item) { 0154 if (!m_serializer->isTaskItem(item)) 0155 return false; 0156 0157 const Domain::Task::Ptr task = m_serializer->createTaskFromItem(item); 0158 0159 const QDate doneDate = task->doneDate(); 0160 const QDate startDate = task->startDate(); 0161 const QDate dueDate = task->dueDate(); 0162 const QDate today = Utils::DateTime::currentDate(); 0163 0164 const bool pastStartDate = startDate.isValid() && startDate <= today; 0165 const bool pastDueDate = dueDate.isValid() && dueDate <= today; 0166 const bool todayDoneDate = doneDate == today; 0167 0168 if (task->isDone()) 0169 return todayDoneDate; 0170 else 0171 return pastStartDate || pastDueDate; 0172 }; 0173 auto predicate = [this, isWorkdayItem] (const Akonadi::Item &item) { 0174 if (!isWorkdayItem(item)) 0175 return false; 0176 0177 const auto items = m_cache->items(item.parentCollection()); 0178 auto currentItem = item; 0179 auto parentUid = m_serializer->relatedUidFromItem(currentItem); 0180 while (!parentUid.isEmpty()) { 0181 const auto parent = std::find_if(items.cbegin(), items.cend(), 0182 [this, parentUid] (const Akonadi::Item &item) { 0183 return m_serializer->itemUid(item) == parentUid; 0184 }); 0185 if (parent == items.cend()) 0186 break; 0187 0188 if (isWorkdayItem(*parent)) 0189 return false; 0190 0191 currentItem = *parent; 0192 parentUid = m_serializer->relatedUidFromItem(currentItem); 0193 } 0194 0195 return true; 0196 }; 0197 m_integrator->bind("TaskQueries::findWorkdayTopLevel", m_findWorkdayTopLevel, fetch, predicate); 0198 return m_findWorkdayTopLevel->result(); 0199 } 0200 0201 TaskQueries::ContextResult::Ptr TaskQueries::findContexts(Domain::Task::Ptr task) const 0202 { 0203 Akonadi::Item taskItem = m_serializer->createItemFromTask(task); 0204 const auto taskItemId = taskItem.id(); 0205 m_findContextsItem[taskItemId] = taskItem; 0206 0207 auto &query = m_findContexts[taskItemId]; 0208 auto fetch = m_helpers->fetchItems(const_cast<TaskQueries*>(this)); 0209 auto predicate = [this, taskItemId] (const Akonadi::Item &contextItem) { 0210 auto context = m_serializer->createContextFromItem(contextItem); 0211 if (!context) 0212 return false; 0213 0214 const auto taskItem = m_findContextsItem[taskItemId]; 0215 return m_serializer->isContextChild(context, taskItem); 0216 }; 0217 m_integrator->bind("TaskQueries::findContexts", query, fetch, predicate); 0218 return query->result(); 0219 } 0220 0221 void TaskQueries::onWorkdayPollTimeout() 0222 { 0223 auto newDate = Utils::DateTime::currentDate(); 0224 if (m_findWorkdayTopLevel && m_today != newDate) { 0225 m_today = newDate; 0226 m_findWorkdayTopLevel->reset(); 0227 } 0228 } 0229 0230 #include "moc_akonaditaskqueries.cpp"