File indexing completed on 2025-01-05 04:59:43
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 #include "availablepagesmodel.h" 0007 0008 #include <QIcon> 0009 #include <QMimeData> 0010 0011 #include <KLocalizedString> 0012 0013 0014 #include "presentation/alltaskspagemodel.h" 0015 #include "presentation/availablepagessortfilterproxymodel.h" 0016 #include "presentation/contextpagemodel.h" 0017 #include "presentation/inboxpagemodel.h" 0018 #include "presentation/projectpagemodel.h" 0019 #include "presentation/querytreemodel.h" 0020 #include "presentation/workdaypagemodel.h" 0021 0022 #include "utils/jobhandler.h" 0023 #include "utils/datetime.h" 0024 0025 using namespace Presentation; 0026 0027 AvailablePagesModel::AvailablePagesModel(const Domain::DataSourceQueries::Ptr &dataSourceQueries, 0028 const Domain::ProjectQueries::Ptr &projectQueries, 0029 const Domain::ProjectRepository::Ptr &projectRepository, 0030 const Domain::ContextQueries::Ptr &contextQueries, 0031 const Domain::ContextRepository::Ptr &contextRepository, 0032 const Domain::TaskQueries::Ptr &taskQueries, 0033 const Domain::TaskRepository::Ptr &taskRepository, 0034 QObject *parent) 0035 : QObject(parent), 0036 m_pageListModel(nullptr), 0037 m_sortProxyModel(nullptr), 0038 m_dataSourceQueries(dataSourceQueries), 0039 m_projectQueries(projectQueries), 0040 m_projectRepository(projectRepository), 0041 m_contextQueries(contextQueries), 0042 m_contextRepository(contextRepository), 0043 m_taskQueries(taskQueries), 0044 m_taskRepository(taskRepository) 0045 { 0046 } 0047 0048 QAbstractItemModel *AvailablePagesModel::pageListModel() 0049 { 0050 if (!m_pageListModel) 0051 m_pageListModel = createPageListModel(); 0052 0053 if (!m_sortProxyModel) { 0054 m_sortProxyModel = new AvailablePagesSortFilterProxyModel(this); 0055 m_sortProxyModel->setSourceModel(m_pageListModel); 0056 } 0057 0058 return m_sortProxyModel; 0059 } 0060 0061 QObject *AvailablePagesModel::createPageForIndex(const QModelIndex &index) 0062 { 0063 QObjectPtr object = index.data(QueryTreeModelBase::ObjectRole).value<QObjectPtr>(); 0064 0065 if (object == m_inboxObject) { 0066 auto inboxPageModel = new InboxPageModel(m_taskQueries, 0067 m_taskRepository, 0068 this); 0069 inboxPageModel->setErrorHandler(errorHandler()); 0070 return inboxPageModel; 0071 } else if (object == m_workdayObject) { 0072 auto workdayPageModel = new WorkdayPageModel(m_taskQueries, 0073 m_taskRepository, 0074 this); 0075 workdayPageModel->setErrorHandler(errorHandler()); 0076 return workdayPageModel; 0077 } else if (auto project = object.objectCast<Domain::Project>()) { 0078 auto projectPageModel = new ProjectPageModel(project, 0079 m_projectQueries, 0080 m_projectRepository, 0081 m_taskQueries, 0082 m_taskRepository, 0083 this); 0084 projectPageModel->setErrorHandler(errorHandler()); 0085 return projectPageModel; 0086 } else if (auto context = object.objectCast<Domain::Context>()) { 0087 auto contextPageModel = new ContextPageModel(context, 0088 m_contextQueries, 0089 m_contextRepository, 0090 m_taskQueries, 0091 m_taskRepository, 0092 this); 0093 contextPageModel->setErrorHandler(errorHandler()); 0094 return contextPageModel; 0095 } else if (object == m_allTasksObject) { 0096 auto allTasksPageModel = new AllTasksPageModel(m_taskQueries, 0097 m_taskRepository, 0098 this); 0099 allTasksPageModel->setErrorHandler(errorHandler()); 0100 return allTasksPageModel; 0101 } 0102 0103 return nullptr; 0104 } 0105 0106 void AvailablePagesModel::addProject(const QString &name, const Domain::DataSource::Ptr &source) 0107 { 0108 auto project = Domain::Project::Ptr::create(); 0109 project->setName(name); 0110 const auto job = m_projectRepository->create(project, source); 0111 installHandler(job, i18n("Cannot add project %1 in dataSource %2", name, source->name())); 0112 } 0113 0114 void AvailablePagesModel::addContext(const QString &name, const Domain::DataSource::Ptr &source) 0115 { 0116 auto context = Domain::Context::Ptr::create(); 0117 context->setName(name); 0118 const auto job = m_contextRepository->create(context, source); 0119 installHandler(job, i18n("Cannot add context %1", name)); 0120 } 0121 0122 void AvailablePagesModel::removeItem(const QModelIndex &index) 0123 { 0124 QObjectPtr object = index.data(QueryTreeModelBase::ObjectRole).value<QObjectPtr>(); 0125 if (auto project = object.objectCast<Domain::Project>()) { 0126 const auto job = m_projectRepository->remove(project); 0127 installHandler(job, i18n("Cannot remove project %1", project->name())); 0128 } else if (auto context = object.objectCast<Domain::Context>()) { 0129 const auto job = m_contextRepository->remove(context); 0130 installHandler(job, i18n("Cannot remove context %1", context->name())); 0131 } else { 0132 Q_ASSERT(false); 0133 } 0134 } 0135 0136 QAbstractItemModel *AvailablePagesModel::createPageListModel() 0137 { 0138 m_inboxObject = QObjectPtr::create(); 0139 m_inboxObject->setProperty("name", i18n("Inbox")); 0140 m_workdayObject = QObjectPtr::create(); 0141 m_workdayObject->setProperty("name", i18n("Workday")); 0142 m_projectsObject = QObjectPtr::create(); 0143 m_projectsObject->setProperty("name", i18n("Projects")); 0144 m_contextsObject = QObjectPtr::create(); 0145 m_contextsObject->setProperty("name", i18n("Contexts")); 0146 m_allTasksObject = QObjectPtr::create(); 0147 m_allTasksObject->setProperty("name", i18n("All Tasks")); 0148 0149 m_rootsProvider = Domain::QueryResultProvider<QObjectPtr>::Ptr::create(); 0150 m_rootsProvider->append(m_inboxObject); 0151 m_rootsProvider->append(m_workdayObject); 0152 m_rootsProvider->append(m_projectsObject); 0153 m_rootsProvider->append(m_contextsObject); 0154 m_rootsProvider->append(m_allTasksObject); 0155 0156 auto query = [this](const QObjectPtr &object) -> Domain::QueryResultInterface<QObjectPtr>::Ptr { 0157 if (!object) 0158 return Domain::QueryResult<QObjectPtr>::create(m_rootsProvider); 0159 else if (object == m_projectsObject) 0160 return Domain::QueryResult<Domain::DataSource::Ptr, QObjectPtr>::copy(m_dataSourceQueries->findAllSelected()); 0161 else if (object == m_contextsObject) 0162 return Domain::QueryResult<Domain::Context::Ptr, QObjectPtr>::copy(m_contextQueries->findAll()); 0163 else if (const auto source = object.objectCast<Domain::DataSource>()) 0164 return Domain::QueryResult<Domain::Project::Ptr, QObjectPtr>::copy(m_dataSourceQueries->findProjects(source)); 0165 else 0166 return Domain::QueryResult<QObjectPtr>::Ptr(); 0167 }; 0168 0169 auto flags = [this](const QObjectPtr &object) { 0170 const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable 0171 | Qt::ItemIsEnabled 0172 | Qt::ItemIsEditable 0173 | Qt::ItemIsDropEnabled; 0174 const Qt::ItemFlags immutableNodeFlags = Qt::ItemIsSelectable 0175 | Qt::ItemIsEnabled 0176 | Qt::ItemIsDropEnabled; 0177 const Qt::ItemFlags nonDroppableNodeFlags = Qt::ItemIsSelectable 0178 | Qt::ItemIsEnabled; 0179 const Qt::ItemFlags structureNodeFlags = Qt::NoItemFlags; 0180 0181 return object.objectCast<Domain::Project>() ? defaultFlags 0182 : object.objectCast<Domain::Context>() ? defaultFlags 0183 : object == m_inboxObject ? immutableNodeFlags 0184 : object == m_workdayObject ? immutableNodeFlags 0185 : object == m_allTasksObject ? nonDroppableNodeFlags 0186 : structureNodeFlags; 0187 }; 0188 0189 auto data = [this](const QObjectPtr &object, int role, int) -> QVariant { 0190 if (role != Qt::DisplayRole 0191 && role != Qt::EditRole 0192 && role != Qt::DecorationRole 0193 && role != QueryTreeModelBase::IconNameRole) { 0194 return QVariant(); 0195 } 0196 0197 if (role == Qt::EditRole 0198 && (object == m_inboxObject 0199 || object == m_workdayObject 0200 || object == m_projectsObject 0201 || object == m_contextsObject 0202 || object == m_allTasksObject 0203 || object.objectCast<Domain::DataSource>())) { 0204 return QVariant(); 0205 } 0206 0207 if (role == Qt::DisplayRole || role == Qt::EditRole) { 0208 return object->property("name").toString(); 0209 } else if (role == Qt::DecorationRole || role == QueryTreeModelBase::IconNameRole) { 0210 const QString iconName = object == m_inboxObject ? QStringLiteral("mail-folder-inbox") 0211 : (object == m_workdayObject) ? QStringLiteral("go-jump-today") 0212 : (object == m_projectsObject) ? QStringLiteral("folder") 0213 : (object == m_contextsObject) ? QStringLiteral("folder") 0214 : (object == m_allTasksObject) ? QStringLiteral("view-pim-tasks") 0215 : object.objectCast<Domain::DataSource>() ? QStringLiteral("folder") 0216 : object.objectCast<Domain::Context>() ? QStringLiteral("view-pim-notes") 0217 : QStringLiteral("view-pim-tasks"); 0218 0219 if (role == Qt::DecorationRole) 0220 return QVariant::fromValue(QIcon::fromTheme(iconName)); 0221 else 0222 return iconName; 0223 } else { 0224 return QVariant(); 0225 } 0226 }; 0227 0228 auto setData = [this](const QObjectPtr &object, const QVariant &value, int role) { 0229 if (role != Qt::EditRole) { 0230 return false; 0231 } 0232 0233 if (object == m_inboxObject 0234 || object == m_workdayObject 0235 || object == m_projectsObject 0236 || object == m_contextsObject 0237 || object == m_allTasksObject 0238 || object.objectCast<Domain::DataSource>()) { 0239 return false; 0240 } 0241 0242 if (auto project = object.objectCast<Domain::Project>()) { 0243 const auto currentName = project->name(); 0244 project->setName(value.toString()); 0245 const auto job = m_projectRepository->update(project); 0246 installHandler(job, i18n("Cannot modify project %1", currentName)); 0247 } else if (auto context = object.objectCast<Domain::Context>()) { 0248 const auto currentName = context->name(); 0249 context->setName(value.toString()); 0250 const auto job = m_contextRepository->update(context); 0251 installHandler(job, i18n("Cannot modify context %1", currentName)); 0252 } else { 0253 Q_ASSERT(false); 0254 } 0255 0256 return true; 0257 }; 0258 0259 auto drop = [this](const QMimeData *mimeData, Qt::DropAction, const QObjectPtr &object) { 0260 if (!mimeData->hasFormat(QStringLiteral("application/x-zanshin-object"))) 0261 return false; 0262 0263 auto droppedTasks = mimeData->property("objects").value<Domain::Task::List>(); 0264 if (droppedTasks.isEmpty()) 0265 return false; 0266 0267 if (auto project = object.objectCast<Domain::Project>()) { 0268 foreach (const auto &task, droppedTasks) { 0269 const auto job = m_projectRepository->associate(project, task); 0270 installHandler(job, i18n("Cannot add %1 to project %2", task->title(), project->name())); 0271 } 0272 return true; 0273 } else if (auto context = object.objectCast<Domain::Context>()) { 0274 foreach (const auto &task, droppedTasks) { 0275 const auto job = m_contextRepository->associate(context, task); 0276 installHandler(job, i18n("Cannot add %1 to context %2", task->title(), context->name())); 0277 } 0278 return true; 0279 } else if (object == m_inboxObject) { 0280 foreach (const auto &task, droppedTasks) { 0281 const auto job = m_projectRepository->dissociate(task); 0282 installHandler(job, i18n("Cannot move %1 to Inbox", task->title())); 0283 0284 Utils::JobHandler::install(job, [this, task] { 0285 const auto dissociateJob = m_taskRepository->dissociateAll(task); 0286 installHandler(dissociateJob, i18n("Cannot move task %1 to Inbox", task->title())); 0287 }); 0288 } 0289 return true; 0290 } else if (object == m_workdayObject) { 0291 foreach (const auto &task, droppedTasks) { 0292 task->setStartDate(Utils::DateTime::currentDate()); 0293 const auto job = m_taskRepository->update(task); 0294 0295 installHandler(job, i18n("Cannot update task %1 to Workday", task->title())); 0296 } 0297 return true; 0298 } 0299 0300 return false; 0301 }; 0302 0303 auto drag = [](const QObjectPtrList &) -> QMimeData* { 0304 return nullptr; 0305 }; 0306 0307 return new QueryTreeModel<QObjectPtr>(query, flags, data, setData, drop, drag, nullptr, this); 0308 } 0309 0310 #include "moc_availablepagesmodel.cpp"