[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [kdepim-runtime/akonadi-todo] qml: todo widget for displaying todos using akonadi resources
From: heena mahour <heena393 () gmail ! com>
Date: 2014-02-21 18:08:56
Message-ID: E1WGuWu-0003jc-Lw () scm ! kde ! org
[Download RAW message or body]
Git commit f607ed6c44aab5754370e9b26d2c331255699186 by heena mahour.
Committed on 21/02/2014 at 17:49.
Pushed by heenamahour into branch 'akonadi-todo'.
todo widget for displaying todos using akonadi resources
M +1 -0 qml/CMakeLists.txt
A +244 -0 qml/todo_epic/todo.cpp [License: GPL (v2+)]
A +95 -0 qml/todo_epic/todo.h [License: GPL (v2+)]
A +193 -0 qml/todo_epic/todofiltermodel.cpp [License: GPL (v2+)]
A +51 -0 qml/todo_epic/todofiltermodel.h [License: GPL (v2+)]
A +211 -0 qml/todo_epic/todoitemdelegate.cpp [License: GPL (v2+)]
A +49 -0 qml/todo_epic/todoitemdelegate.h [License: GPL (v2+)]
A +610 -0 qml/todo_epic/todomodel.cpp [License: GPL (v2+)]
A +116 -0 qml/todo_epic/todomodel.h [License: GPL (v2+)]
A +79 -0 qml/todo_epic/todotreeview.cpp [License: GPL (v2+)]
A +49 -0 qml/todo_epic/todotreeview.h [License: GPL (v2+)]
http://commits.kde.org/kdepim-runtime/f607ed6c44aab5754370e9b26d2c331255699186
diff --git a/qml/CMakeLists.txt b/qml/CMakeLists.txt
index b93eb02..27c59e1 100644
--- a/qml/CMakeLists.txt
+++ b/qml/CMakeLists.txt
@@ -3,3 +3,4 @@ add_definitions( -DQT_NO_CAST_TO_ASCII )
add_subdirectory( kde )
add_subdirectory( akonadi )
+add_subdirectory( todo_epic )
diff --git a/qml/todo_epic/todo.cpp b/qml/todo_epic/todo.cpp
new file mode 100644
index 0000000..c99672f
--- /dev/null
+++ b/qml/todo_epic/todo.cpp
@@ -0,0 +1,244 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#include "todo.h"
+#include "todomodel.h"
+#include "todofiltermodel.h"
+#include "todoitemdelegate.h"
+#include "todotreeview.h"
+#include <QComboBox>
+#include <QGraphicsLinearLayout>
+#include <QGraphicsProxyWidget>
+#include <QLabel>
+#include <QToolButton>
+#include <QModelIndex>
+#include <QTimer>
+#include <QAction>
+#include <QDateTime>
+#include <QMap>
+#include <QVariant>
+#include <QTreeWidgetItem>
+#include <QTreeWidgetItemIterator>
+#include <QDBusConnection>
+#include <QDBusInterface>
+#include <QDBusConnectionInterface>
+#include <QDBusServiceWatcher>
+
+#include <KColorScheme>
+#include <KConfigDialog>
+#include <KIcon>
+#include <KStandardDirs>
+#include <KDirWatch>
+#include <KTabWidget>
+#include <KToolInvocation>
+#include <KProcess>
+#include <KMessageBox>
+#include <Plasma/Theme>
+
+#include <akonadi/control.h>
+#include <akonadi/agentinstance.h>
+#include <akonadi/servermanager.h>
+#include <akonadi/itemdeletejob.h>
+
+K_EXPORT_PLASMA_APPLET(events, Todo)
+
+static const int MAX_RETRIES = 12;
+static const int WAIT_FOR_KO_MSECS = 2000;
+
+Todo::Todo(QObject *parent, const QVariantList &args) :
+ Plasma::PopupApplet(parent, args),
+ m_graphicsWidget(0),
+ m_view(0),
+ m_delegate(0),
+ m_todoFormatConfig(),
+ m_colorConfigUi(),
+ m_timer(0),
+ m_agentManager(0),
+ incidenceTypesDialog(0),
+ collectionDialog(0),
+ categoriesDialog(0),
+ m_openEventWatcher(0),
+ m_addEventWatcher(0),
+ m_addTodoWatcher(0)
+{
+ KGlobal::locale()->insertCatalog("libkcal");
+ setBackgroundHints(DefaultBackground);
+ setAspectRatioMode(Plasma::IgnoreAspectRatio);
+ setHasConfigurationInterface(true);
+
+ setPopupIcon("view-pim-tasks");
+
+ Akonadi::ServerManager::start();
+}
+
+Todo::~Todo()
+{
+ delete m_view;
+}
+
+void Todo::init()
+{
+ KConfigGroup cg = config();
+
+ disabledTypes = cg.readEntry("DisabledIncidenceTypes", QStringList());
+ disabledCollections = cg.readEntry("DisabledCollections", QStringList());
+ disabledCategories = cg.readEntry("DisabledCategories", QStringList());
+
+ QString normalEventFormat = cg.readEntry("NormalEventFormat", \
QString("%{startDate} %{startTime} %{summary}")); + QString todoFormat = \
cg.readEntry("TodoFormat", QString("%{dueDate} %{summary}")); + QString \
noDueDateFormat = cg.readEntry("NoDueDateFormat", QString("%{summary}")); + int \
dtFormat = cg.readEntry("DateFormat", ShortDateFormat); + QString dtString = \
cg.readEntry("CustomDateFormat", QString("dd.MM.yyyy")); + m_appletTitle = \
cg.readEntry("AppletTitle", i18n("Upcoming Todos")); + m_period = \
cg.readEntry("Period", 365); + m_recurringCount = cg.readEntry("RecurringCount", \
0); +
+ m_urgency = cg.readEntry("UrgencyTime", 15);
+ m_birthdayUrgency = cg.readEntry("BirthdayUrgencyTime", 14);
+
+ m_urgentBg = QColor(cg.readEntry("UrgentColor", QString("#FF0000")));
+ m_colors.insert(urgentColorPos, m_urgentBg);
+ m_passedFg = QColor(cg.readEntry("PassedColor", QString("#C3C3C3")));
+ m_colors.insert(passedColorPos, m_passedFg);
+ m_todoBg = QColor(cg.readEntry("TodoColor", QString("#FFD235")));
+ m_colors.insert(todoColorPos, m_todoBg);
+ m_showFinishedTodos = cg.readEntry("ShowFinishedTodos", false);
+ m_finishedTodoBg = QColor(cg.readEntry("FinishedTodoColor", \
QString("#6FACE0"))); + m_colors.insert(finishedTodoColorPos, m_finishedTodoBg);
+ QStringList keys, values;
+ keys << i18n("Birthday") << i18n("Holiday");
+ values << QString("%{startDate} %{yearsSince}. %{summary}") << \
QString("%{startDate} %{summary} to %{endDate}"); + keys = \
cg.readEntry("CategoryFormatsKeys", keys); + values = \
cg.readEntry("CategoryFormatsValues", values); +
+ for (int i = 0; i < keys.size(); ++i) {
+ m_categoryFormat.insert(keys.at(i), values.at(i));
+ }
+
+ QStringList headerList;
+ headerList << i18n("Todo for today") << i18n("Events of today") << \
QString::number(0); + headerList << i18n("Todo for tomorrow") << i18n("Events for \
tomorrow") << QString::number(1); + headerList << i18n("Next week's todo") << \
i18n("Events of the next 7 days") << QString::number(2); + headerList << \
i18n("Todo for next 4 weeks") << i18n("Events for the next 4 weeks") << \
QString::number(8); + headerList << i18n("Later todos ") << i18n("Events later \
than 4 weeks") << QString::number(29); + m_headerItemsList = \
cg.readEntry("HeaderItems", headerList); + m_autoGroupHeader = \
cg.readEntry("AutoGroupHeader", false); +
+ m_delegate = new TodoItemDelegate(this, normalEventFormat, todoFormat, \
noDueDateFormat, dtFormat, dtString); + \
m_delegate->setCategoryFormats(m_categoryFormat); +
+ graphicsWidget();
+
+ Plasma::ToolTipManager::self()->registerWidget(this);
+ createToolTip();
+
+ lastCheckTime = QDateTime::currentDateTime();
+ m_timer = new QTimer();
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(timerExpired()));
+ QTimer::singleShot(5000, this, SLOT(setupModel()));
+ setBusy(true);
+}
+
+void Todo::setupModel()
+{
+ setBusy(false);
+ m_agentManager = Akonadi::AgentManager::self();
+
+ m_model = new TodoModel(this, m_urgency, m_birthdayUrgency, m_colors, \
m_recurringCount, m_autoGroupHeader); + \
m_model->setCategoryColors(m_categoryColors); + \
m_model->setHeaderItems(m_headerItemsList); + if \
(Akonadi::ServerManager::isRunning()) { + m_model->initModel();
+ m_model->initMonitor();
+ }
+
+ m_filterModel = new TodoFilterModel(this);
+ m_filterModel->setPeriod(m_period);
+ m_filterModel->setShowFinishedTodos(m_showFinishedTodos);
+ m_filterModel->setDisabledTypes(disabledTypes);
+ m_filterModel->setExcludedCollections(disabledCollections);
+ m_filterModel->setDisabledCategories(disabledCategories);
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->setSourceModel(m_model);
+
+ m_view->setModel(m_filterModel);
+ m_view->expandAll();
+ connect(m_model, SIGNAL(modelNeedsExpanding()), m_view, SLOT(expandAll()));
+ m_timer->start(10000);
+
+ connect(Akonadi::ServerManager::self(), SIGNAL(started()), this, \
SLOT(akonadiStatusChanged())); +}
+
+void Todo::akonadiStatusChanged()
+{
+ m_model->resetModel();
+}
+
+QGraphicsWidget *Todo::graphicsWidget()
+{
+ if (!m_graphicsWidget) {
+ m_graphicsWidget = new QGraphicsWidget(this);
+ m_graphicsWidget->setMinimumSize(200, 125);
+ m_graphicsWidget->setPreferredSize(350, 200);
+ QPalette p = palette();
+ p.setColor( QPalette::Base, Qt::darkCyan);
+ p.setColor( QPalette::AlternateBase, Qt::gray);
+ p.setColor( QPalette::Button, Qt::gray );
+ p.setColor( QPalette::Foreground, Qt::darkGray );
+ p.setColor( QPalette::Text, Qt::yellow);
+ proxyWidget = new QGraphicsProxyWidget();
+ m_view = new TodoTreeView();
+ proxyWidget->setWidget(m_view);
+ proxyWidget->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding \
); + m_view->setItemDelegate(m_delegate);
+ m_view->setPalette(p);
+ m_view->viewport()->setPalette( p );
+ connect(m_view, SIGNAL(tooltipUpdated(QString)),
+ SLOT(slotUpdateTooltip(QString)));
+ title = new Plasma::Label();
+ title->setText("<qt><b><center>" + m_appletTitle + \
"</center></b></br></br>"+ "Todo list"+"</qt>"); + layout = new \
QGraphicsLinearLayout(Qt::Vertical); + layout->addItem(title);
+ layout->addItem(proxyWidget);
+
+ m_graphicsWidget->setLayout(layout);
+ registerAsDragHandle(m_graphicsWidget);
+ }
+
+ return m_graphicsWidget;
+}
+void Todo::slotUpdateTooltip(QString text)
+{
+ tooltip.setSubText(text);
+ Plasma::ToolTipManager::self()->setContent(this, tooltip);
+}
+
+void Todo::createToolTip()
+{
+ tooltip = Plasma::ToolTipContent(i18n("Todo list"), "", \
KIcon("view-pim-tasks")); + tooltip.setMainText(i18n("Browse through the tree view \
and explore/add the todos")); + tooltip.setSubText(i18n("Move mouse over the todo \
items to know their details(start date, duration,percentage completion etc .")); + \
tooltip.setAutohide(false); +}
+
+void Todo::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ Q_UNUSED(event);
+ createToolTip();
+ Plasma::ToolTipManager::self()->setContent(this, tooltip);
+}
+#include "todo.moc"
diff --git a/qml/todo_epic/todo.h b/qml/todo_epic/todo.h
new file mode 100644
index 0000000..1f4859e
--- /dev/null
+++ b/qml/todo_epic/todo.h
@@ -0,0 +1,95 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#ifndef TODO_H
+#define TODO_H
+#include "ui_todoformatconfig.h"
+#include "ui_eventappletcolorconfig.h"
+#include <QHash>
+#include <QGraphicsSceneHoverEvent>
+#include <Plasma/PopupApplet>
+#include <Plasma/Label>
+#include <Plasma/ToolTipManager>
+
+#include <akonadi/agentmanager.h>
+
+class QDateTime;
+class QTimer;
+class QModelIndex;
+class QAction;
+class KConfigDialog;
+class CheckBoxDialog;
+class TodoModel;
+class TodoFilterModel;
+class TodoItemDelegate;
+class QGraphicsLinearLayout;
+class QGraphicsProxyWidget;
+class TodoTreeView;
+class KDirWatch;
+class QDBusServiceWatcher;
+
+class Todo : public Plasma::PopupApplet
+{
+ Q_OBJECT
+
+public:
+ Todo(QObject *parent, const QVariantList &args);
+ ~Todo();
+
+ void init();
+ QGraphicsWidget *graphicsWidget();
+
+private slots:
+ void slotUpdateTooltip(QString);
+ void setupModel();
+ void akonadiStatusChanged();
+
+protected:
+ void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+
+private:
+ void createToolTip();
+
+private:
+ QGraphicsWidget *m_graphicsWidget;
+ QGraphicsLinearLayout *layout;
+ TodoModel *m_model;
+ TodoFilterModel *m_filterModel;
+ KDirWatch *m_categoryColorWatch;
+ QGraphicsProxyWidget *proxyWidget;
+ TodoTreeView *m_view;
+ Plasma::ToolTipContent tooltip;
+ Plasma::Label *title;
+ TodoItemDelegate *m_delegate;
+ Ui::TodoFormatConfig m_todoFormatConfig;
+ Ui::EventAppletColorConfig m_colorConfigUi;
+ int m_urgency, m_birthdayUrgency, m_checkInterval, m_period, m_recurringCount;
+ QColor m_urgentBg, m_passedFg, m_todoBg, m_finishedTodoBg;
+ QHash<QString, QColor> m_categoryColors;
+ QMap<QString, QString> m_categoryFormat;
+ QList<QColor> m_colors;
+ QTimer *m_timer;
+ Akonadi::AgentManager *m_agentManager;
+ QStringList disabledTypes, disabledCollections, disabledCategories, \
m_headerItemsList, m_categories; + CheckBoxDialog *incidenceTypesDialog, \
*collectionDialog, *categoriesDialog; + QDateTime lastCheckTime;
+ bool m_showFinishedTodos, m_autoGroupHeader;
+ QString m_uid, m_appletTitle;
+ QModelIndex m_indexAtCursor;
+ QDBusServiceWatcher *m_openEventWatcher, *m_addEventWatcher, *m_addTodoWatcher;
+};
+
+#endif
diff --git a/qml/todo_epic/todofiltermodel.cpp b/qml/todo_epic/todofiltermodel.cpp
new file mode 100644
index 0000000..c1b4266
--- /dev/null
+++ b/qml/todo_epic/todofiltermodel.cpp
@@ -0,0 +1,193 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#include "todofiltermodel.h"
+#include "todomodel.h"
+#include <QVariant>
+#include <QDate>
+
+TodoFilterModel::TodoFilterModel(QObject *parent) : QSortFilterProxyModel(parent)
+{
+ m_period = 365;
+ m_excludedCollections = QStringList();
+ m_disabledCategories = QStringList();
+}
+
+TodoFilterModel::~TodoFilterModel()
+{
+}
+
+void TodoFilterModel::setPeriod(int period)
+{
+ m_period = period;
+ invalidateFilter();
+}
+
+void TodoFilterModel::setShowFinishedTodos(bool showFinishedTodos)
+{
+ m_showFinishedTodos = showFinishedTodos;
+ invalidateFilter();
+}
+
+void TodoFilterModel::setDisabledTypes(QStringList types)
+{
+ m_disabledTypes = types;
+ m_disabledTypes.sort();
+ invalidateFilter();
+}
+
+void TodoFilterModel::setExcludedCollections(QStringList collections)
+{
+ m_excludedCollections = collections;
+ m_excludedCollections.sort();
+ invalidateFilter();
+}
+
+void TodoFilterModel::setDisabledCategories(QStringList categories)
+{
+ m_disabledCategories = categories;
+ m_disabledCategories.sort();
+ invalidateFilter();
+}
+
+bool TodoFilterModel::isDisabledType(QModelIndex idx) const
+{
+ bool isDisabled = false;
+ const int type = idx.data(TodoModel::ItemTypeRole).toInt();
+ if (type == TodoModel::NormalItem || type == TodoModel::BirthdayItem || type == \
TodoModel::AnniversaryItem) { + if (m_disabledTypes.contains("events"))
+ isDisabled = true;
+ } else if (type == TodoModel::TodoItem) {
+ if (m_disabledTypes.contains("todos"))
+ isDisabled = true;
+ }
+
+ return isDisabled;
+}
+
+bool TodoFilterModel::isDisabledCategory(QModelIndex idx) const
+{
+ const QMap<QString, QVariant> values = idx.data(Qt::DisplayRole).toMap();
+ QStringList itemCategories = values["categories"].toStringList();
+ QStringList allCategories = m_disabledCategories + itemCategories;
+
+ bool allItemCategoriesDisabled = allCategories.removeDuplicates() == \
itemCategories.count(); + return allItemCategoriesDisabled;
+}
+
+bool TodoFilterModel::filterAcceptsRow( int sourceRow, const QModelIndex \
&sourceParent ) const +{
+ const QModelIndex idx = sourceModel()->index( sourceRow, 0, sourceParent );
+
+ const int itemType = idx.data(TodoModel::ItemTypeRole).toInt();
+ const QString collectionRole = idx.data(TodoModel::CollectionRole).toString();
+
+ const QVariant d = idx.data(TodoModel::SortRole);
+ const QDate date= d.toDate();
+
+ if (date.isValid()) {
+ if (date > QDate::currentDate().addDays(365)) { // todos with no specified \
due date + if (itemType == TodoModel::HeaderItem) {
+ int rows = sourceModel()->rowCount(idx);
+ for (int row = 0; row < rows; ++ row) {
+ QModelIndex childIdx = sourceModel()->index(row, 0, idx);
+ const QString cr = \
childIdx.data(TodoModel::CollectionRole).toString(); + if \
(!m_excludedCollections.contains(cr) && !isDisabledType(childIdx) && \
!isDisabledCategory(childIdx)) { + const QMap<QString, \
QVariant> values = childIdx.data(Qt::DisplayRole).toMap(); + \
if (m_showFinishedTodos || values["completed"].toBool() == false) + \
return true; + }
+ }
+ return false;
+ } else {
+ if (!m_excludedCollections.contains(collectionRole) && \
!isDisabledType(idx) && !isDisabledCategory(idx)) { + const \
QMap<QString, QVariant> values = idx.data(Qt::DisplayRole).toMap(); + \
if (m_showFinishedTodos || values["completed"].toBool() == false) { + \
return true; + }
+ }
+ return false;
+ }
+ } else if (date > QDate::currentDate().addDays(m_period)) {
+ return false;
+ } else if (date < QDate::currentDate()) {
+ if (itemType == TodoModel::HeaderItem) {
+ if (sourceModel()->hasChildren(idx)) {
+ int rows = sourceModel()->rowCount(idx);
+ for (int row = 0; row < rows; ++row) {
+ QModelIndex childIdx = sourceModel()->index(row, 0, idx);
+ const QString cr = \
childIdx.data(TodoModel::CollectionRole).toString(); + if \
(!m_excludedCollections.contains(cr) && !isDisabledType(childIdx) && \
!isDisabledCategory(childIdx)) { + const int childType = \
childIdx.data(TodoModel::ItemTypeRole).toInt(); + const \
QMap<QString, QVariant> values = childIdx.data(Qt::DisplayRole).toMap(); + \
if (childType == TodoModel::TodoItem) { + if \
(values["completed"].toBool() == false) + return \
true; + } else {
+ if (values["endDate"].toDate() >= \
QDate::currentDate()) + return true;
+ }
+ }
+ }
+ }
+ return false;
+ } else {
+ if (m_excludedCollections.contains(collectionRole) || \
isDisabledType(idx) || isDisabledCategory(idx)) { + return false;
+ }
+
+ const QMap<QString, QVariant> values = \
idx.data(Qt::DisplayRole).toMap(); + if (itemType == \
TodoModel::TodoItem) { + if (values["completed"].toBool() == true) \
{ + return false;
+ }
+ } else if (values["endDate"].toDate() < QDate::currentDate()) {
+ return false;
+ }
+ }
+ } else {
+ if (itemType == TodoModel::HeaderItem) {
+ int rows = sourceModel()->rowCount(idx);
+ for (int row = 0; row < rows; ++ row) {
+ QModelIndex childIdx = sourceModel()->index(row, 0, idx);
+ const QString cr = \
childIdx.data(TodoModel::CollectionRole).toString(); + const QDate \
cd = childIdx.data(TodoModel::SortRole).toDate(); + if \
((!m_excludedCollections.contains(cr) && !isDisabledType(childIdx) && \
!isDisabledCategory(childIdx)) && cd <= QDate::currentDate().addDays(m_period)) { + \
const int childType = childIdx.data(TodoModel::ItemTypeRole).toInt(); + \
const QMap<QString, QVariant> values = childIdx.data(Qt::DisplayRole).toMap(); + \
if (childType != TodoModel::TodoItem) { + return true;
+ } else if (m_showFinishedTodos || \
values["completed"].toBool() == false) { + return true;
+ }
+ }
+ }
+ return false;
+ } else if (m_excludedCollections.contains(collectionRole) || \
isDisabledType(idx) || isDisabledCategory(idx)) { + return false;
+ } else if (itemType == TodoModel::TodoItem) {
+ const QMap<QString, QVariant> values = \
idx.data(Qt::DisplayRole).toMap(); + if (!m_showFinishedTodos && \
values["completed"].toBool() == true) + return false;
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
diff --git a/qml/todo_epic/todofiltermodel.h b/qml/todo_epic/todofiltermodel.h
new file mode 100644
index 0000000..8ff198c
--- /dev/null
+++ b/qml/todo_epic/todofiltermodel.h
@@ -0,0 +1,51 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#ifndef TODOFILTERMODEL_H
+#define TODOFILTERMODEL_H
+
+#include <QSortFilterProxyModel>
+#include <QStringList>
+
+class TodoFilterModel : public QSortFilterProxyModel
+{
+ Q_OBJECT
+
+public:
+ explicit TodoFilterModel(QObject *parent = 0);
+ ~TodoFilterModel();
+
+ void setPeriod(int period);
+ void setShowFinishedTodos(bool showFinishedTodos);
+ void setDisabledTypes(QStringList types);
+ void setExcludedCollections(QStringList collections);
+ void setDisabledCategories(QStringList categories);
+
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+
+private:
+ bool isDisabledType(QModelIndex idx) const;
+ bool isDisabledCategory(QModelIndex idx) const;
+
+private:
+ int m_period;
+ bool m_showFinishedTodos;
+ QStringList m_disabledTypes, m_excludedCollections, m_disabledCategories;
+};
+
+#endif
diff --git a/qml/todo_epic/todoitemdelegate.cpp b/qml/todo_epic/todoitemdelegate.cpp
new file mode 100644
index 0000000..61a1ece
--- /dev/null
+++ b/qml/todo_epic/todoitemdelegate.cpp
@@ -0,0 +1,211 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#include "todoitemdelegate.h"
+#include "todomodel.h"
+
+#include <KGlobal>
+#include <KLocale>
+#include <KMacroExpanderBase>
+
+#include <QDateTime>
+#include <QHash>
+#include <QTextDocument>
+#include <QPainter>
+#include <QAbstractTextDocumentLayout>
+
+TodoItemDelegate::TodoItemDelegate(QObject* parent, QString normal, QString todo, \
QString noDueDate, int dtFormat, QString dtString) + : \
QStyledItemDelegate(parent), + m_normal(normal),
+ m_todo(todo),
+ m_noDueDate(noDueDate),
+ m_dateString(dtString),
+ m_dateFormat(dtFormat)
+{
+}
+
+TodoItemDelegate::~TodoItemDelegate()
+{
+}
+
+QString TodoItemDelegate::displayText(const QVariant &value, const QLocale &locale) \
const +{
+ Q_UNUSED(locale);
+ QMap<QString, QVariant> data = value.toMap();
+ QString mainCategory = data["mainCategory"].toString();
+
+ int itemType = data["itemType"].toInt();
+ switch (itemType) {
+ case TodoModel::HeaderItem:
+ return KMacroExpander::expandMacros(data["title"].toString(), \
titleHash(data)); + break;
+ case TodoModel::NormalItem:
+ case TodoModel::BirthdayItem:
+ case TodoModel::AnniversaryItem:
+ if (m_categoryFormats.contains(mainCategory))
+ return \
KMacroExpander::expandMacros(m_categoryFormats.value(mainCategory), eventHash(data)); \
+ else + return KMacroExpander::expandMacros(m_normal, \
eventHash(data)); + break;
+ case TodoModel::TodoItem:
+ if (data["hasDueDate"].toBool() == false)
+ return KMacroExpander::expandMacros(m_noDueDate, todoHash(data));
+ else
+ return KMacroExpander::expandMacros(m_todo, todoHash(data));
+ break;
+ default:
+ break;
+ }
+
+ return QString();
+}
+
+void TodoItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & \
option, const QModelIndex & index ) const +{
+ painter->save();
+
+ QStyleOptionViewItemV4 opt = option;
+ initStyleOption(&opt, index);
+
+ QVariant value = index.data();
+ QBrush bgBrush = qvariant_cast<QBrush>(index.data(Qt::BackgroundRole));
+ QBrush fgBrush = qvariant_cast<QBrush>(index.data(Qt::ForegroundRole));
+ painter->setClipRect( opt.rect );
+ painter->setBackgroundMode(Qt::OpaqueMode);
+ painter->setBackground(Qt::transparent);
+ painter->setBrush(bgBrush);
+
+ if (bgBrush.style() != Qt::NoBrush) {
+ QPen bgPen;
+ bgPen.setColor(bgBrush.color().darker(250));
+ bgPen.setStyle(Qt::SolidLine);
+ bgPen.setWidth(1);
+ painter->setPen(bgPen);
+ painter->drawRoundedRect(opt.rect.x(), opt.rect.y(), opt.rect.width() - \
bgPen.width(), opt.rect.height() - bgPen.width(), 3.0, 3.0); + }
+
+ QTextDocument doc;
+ doc.setDocumentMargin(3);
+ doc.setDefaultStyleSheet("* {color: " + fgBrush.color().name() + ";}");
+ doc.setHtml("<html><qt></head><meta name=\"qrichtext\" content=\"1\" />" + \
displayText(value, QLocale::system()) + "</qt></html>"); + \
QAbstractTextDocumentLayout::PaintContext context; + doc.setPageSize( \
opt.rect.size()); + painter->translate(opt.rect.x(), opt.rect.y());
+ doc.documentLayout()->draw(painter, context);
+ painter->restore();
+}
+
+QSize TodoItemDelegate::sizeHint(const QStyleOptionViewItem &option, const \
QModelIndex &index) const +{
+ QVariant value = index.data();
+ QTextDocument doc;
+ doc.setDocumentMargin(3);
+ doc.setHtml("<html><qt></head><meta name=\"qrichtext\" content=\"1\" />" + \
displayText(value, QLocale::system()) + "</qt></html>"); + \
doc.setTextWidth(option.rect.width()); + return doc.size().toSize();
+}
+
+QHash<QString, QString> TodoItemDelegate::titleHash(QMap<QString, QVariant> data) \
const +{
+ QHash<QString,QString> dataHash;
+ dataHash.insert("date", formattedDate(data["date"]));
+ dataHash.insert("weekday", data["date"].toDateTime().toString("dddd"));
+
+ return dataHash;
+}
+
+QHash<QString, QString> TodoItemDelegate::eventHash(QMap<QString, QVariant> data) \
const +{
+ QHash<QString,QString> dataHash;
+ ulong s;
+ dataHash.insert("startDate", formattedDate(data["startDate"]));
+ dataHash.insert("endDate", formattedDate(data["endDate"]));
+ dataHash.insert("startTime", \
KGlobal::locale()->formatTime(data["startDate"].toTime())); + \
dataHash.insert("endTime", KGlobal::locale()->formatTime(data["endDate"].toTime())); \
+ s = data["startDate"].toDateTime().secsTo(data["endDate"].toDateTime()); + \
dataHash.insert("duration", KGlobal::locale()->prettyFormatDuration(s * 1000)); + \
dataHash.insert("summary", data["summary"].toString()); + \
dataHash.insert("description", data["description"].toString()); + \
dataHash.insert("location", data["location"].toString()); + \
dataHash.insert("yearsSince", data["yearsSince"].toString()); + \
dataHash.insert("collectionName", data["collectionName"].toString()); + \
dataHash.insert("mainCategory", data["mainCategory"].toString()); + \
dataHash.insert("categories", data["categories"].toStringList().join(", ")); + \
dataHash.insert("contactName", data["contactName"].toString()); + \
dataHash.insert("tab", "\t"); +
+ return dataHash;
+}
+
+QHash<QString, QString> TodoItemDelegate::todoHash(QMap<QString, QVariant> data) \
const +{
+ QHash<QString,QString> dataHash;
+ dataHash.insert("startDate", formattedDate(data["startDate"]));
+ dataHash.insert("startTime", \
KGlobal::locale()->formatTime(data["startDate"].toTime())); + \
dataHash.insert("dueDate", formattedDate(data["dueDate"])); + \
dataHash.insert("dueTime", KGlobal::locale()->formatTime(data["dueDate"].toTime())); \
+ dataHash.insert("summary", data["summary"].toString()); + \
dataHash.insert("description", data["description"].toString()); + \
dataHash.insert("location", data["location"].toString()); + \
dataHash.insert("collectionName", data["collectionName"].toString()); + \
dataHash.insert("mainCategory", data["mainCategory"].toString()); + \
dataHash.insert("categories", data["categories"].toStringList().join(", ")); + \
dataHash.insert("percent", QString::number(data["percent"].toInt())); + \
dataHash.insert("tab", "\t"); +
+ return dataHash;
+}
+
+void TodoItemDelegate::setCategoryFormats(QMap<QString, QString> formats)
+{
+ m_categoryFormats = formats;
+}
+
+QString TodoItemDelegate::formattedDate(const QVariant &dtTime) const
+{
+ QString date;
+ if (dtTime.toDateTime().isValid()) {
+ switch (m_dateFormat) {
+ case ShortDateFormat:
+ date = KGlobal::locale()->formatDate(dtTime.toDate(), \
KLocale::ShortDate); + break;
+ case LongDateFormat:
+ date = KGlobal::locale()->formatDate(dtTime.toDate(), \
KLocale::LongDate); + break;
+ case FancyShortDateFormat:
+ date = KGlobal::locale()->formatDate(dtTime.toDate(), \
KLocale::FancyShortDate); + break;
+ case FancyLongDateFormat:
+ date = KGlobal::locale()->formatDate(dtTime.toDate(), \
KLocale::FancyLongDate); + break;
+ case CustomDateFormat:
+ date = dtTime.toDate().toString(m_dateString);
+ break;
+ }
+ }
+
+ return date;
+}
+
+void TodoItemDelegate::settingsChanged(QString normal, QString todo, QString \
noDueDate, int format, QString customString) +{
+ m_normal = normal;
+ m_todo= todo;
+ m_noDueDate = noDueDate;
+ m_dateFormat = format;
+ m_dateString = customString;
+}
diff --git a/qml/todo_epic/todoitemdelegate.h b/qml/todo_epic/todoitemdelegate.h
new file mode 100644
index 0000000..ad481fe
--- /dev/null
+++ b/qml/todo_epic/todoitemdelegate.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#ifndef TODOITEMDELEGATE_H
+#define TODOITEMDELEGATE_H
+
+#include <QStyledItemDelegate>
+
+class TodoItemDelegate : public QStyledItemDelegate
+{
+ Q_OBJECT
+
+public:
+ TodoItemDelegate(QObject* parent, QString normal, QString todo, QString \
noDueDate, int dtFormat, QString dtString); + ~TodoItemDelegate();
+
+ QString displayText(const QVariant &value, const QLocale &locale) const;
+ void paint(QPainter *painter, const QStyleOptionViewItem &option, const \
QModelIndex &index) const; + QSize sizeHint(const QStyleOptionViewItem &option, \
const QModelIndex &index) const; + void settingsChanged(QString normal, QString \
todo, QString noDueDate, int format, QString customString); + void \
setCategoryFormats(QMap<QString, QString>); +
+private:
+ QHash<QString, QString> titleHash(QMap<QString, QVariant>) const;
+ QHash<QString, QString> eventHash(QMap<QString, QVariant>) const;
+ QHash<QString, QString> todoHash(QMap<QString, QVariant>) const;
+ QMap<QString, QString> m_categoryFormats;
+ QString formattedDate(const QVariant &dtTime) const;
+
+ QString m_normal, m_todo, m_noDueDate, m_dateString;
+ int m_dateFormat;
+};
+
+#endif
+
diff --git a/qml/todo_epic/todomodel.cpp b/qml/todo_epic/todomodel.cpp
new file mode 100644
index 0000000..420f28c
--- /dev/null
+++ b/qml/todo_epic/todomodel.cpp
@@ -0,0 +1,610 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#include "todomodel.h"
+
+#include <kcalcore/recurrence.h>
+#include <kcalutils/incidenceformatter.h>
+
+#include <akonadi/collectionfetchjob.h>
+#include <akonadi/collectionfetchscope.h>
+#include <akonadi/item.h>
+#include <akonadi/itemfetchjob.h>
+#include <akonadi/itemfetchscope.h>
+#include <akonadi/entitydisplayattribute.h>
+#include <akonadi/servermanager.h>
+
+#include <QDate>
+#include <QStandardItem>
+#include <KIcon>
+#include <KGlobal>
+#include <KLocale>
+#include <KGlobalSettings>
+#include <KDateTime>
+
+#include <Plasma/Theme>
+
+#include <KDebug>
+
+TodoModel::TodoModel(QObject *parent, int urgencyTime, int birthdayTime, \
QList<QColor> colorList, int count, bool autoGroupHeader) : \
QStandardItemModel(parent), + parentItem(0),
+ m_monitor(0)
+{
+ parentItem = invisibleRootItem();
+ settingsChanged(urgencyTime, birthdayTime, colorList, count, autoGroupHeader);
+}
+
+TodoModel::~TodoModel()
+{
+}
+
+void TodoModel::initModel()
+{
+ createHeaderItems(m_headerPartsList);
+
+ Akonadi::CollectionFetchScope scope;
+ QStringList mimeTypes;
+ mimeTypes << KCalCore::Event::eventMimeType();
+ mimeTypes << KCalCore::Todo::todoMimeType();
+ mimeTypes << "text/calendar";
+ scope.setContentMimeTypes(mimeTypes);
+
+ Akonadi::CollectionFetchJob *job = new \
Akonadi::CollectionFetchJob(Akonadi::Collection::root(), + \
Akonadi::CollectionFetchJob::Recursive); + job->setFetchScope(scope);
+ connect(job, SIGNAL(result(KJob *)), this, \
SLOT(initialCollectionFetchFinished(KJob *))); + job->start();
+}
+
+void TodoModel::initialCollectionFetchFinished(KJob *job)
+{
+ if (job->error()) {
+ kDebug() << "Initial collection fetch failed!";
+ } else {
+ Akonadi::CollectionFetchJob *cJob = qobject_cast<Akonadi::CollectionFetchJob \
*>(job); + Akonadi::Collection::List collections = cJob->collections();
+ foreach (const Akonadi::Collection &collection, collections) {
+ m_collections.insert(collection.id(), collection);
+ Akonadi::ItemFetchJob *job = new Akonadi::ItemFetchJob(collection);
+ job->fetchScope().fetchFullPayload();
+ job->fetchScope().setAncestorRetrieval( Akonadi::ItemFetchScope::Parent \
); +
+ connect(job, SIGNAL(result(KJob *)), this, \
SLOT(initialItemFetchFinished(KJob *))); + job->start();
+ }
+ }
+}
+
+void TodoModel::initialItemFetchFinished(KJob *job)
+{
+ if (job->error()) {
+ kDebug() << "Initial item fetch failed!";
+ } else {
+ Akonadi::ItemFetchJob *iJob = qobject_cast<Akonadi::ItemFetchJob *>(job);
+ Akonadi::Item::List items = iJob->items();
+ foreach (const Akonadi::Item &item, items) {
+ if (itemIds.contains(item.id())) {
+ removeItem(item);
+ }
+
+ if (item.hasPayload <KCalCore::Event::Ptr>()) {
+ KCalCore::Event::Ptr event = item.payload <KCalCore::Event::Ptr>();
+ if (event) {
+ addEventItem(eventDetails(item, event));
+ itemIds.append(item.id());
+ }
+ } else if (item.hasPayload <KCalCore::Todo::Ptr>()) {
+ KCalCore::Todo::Ptr todo = item.payload<KCalCore::Todo::Ptr>();
+ if (todo) {
+ addTodoItem(todoDetails(item, todo));
+ itemIds.append(item.id());
+ }
+ }
+ }
+ }
+
+ setSortRole(TodoModel::SortRole);
+ sort(0, Qt::AscendingOrder);
+}
+
+void TodoModel::initMonitor()
+{
+ m_monitor = new Akonadi::Monitor(this);
+ Akonadi::ItemFetchScope scope;
+ scope.fetchFullPayload(true);
+ scope.fetchAllAttributes(true);
+ m_monitor->fetchCollection(true);
+ m_monitor->setItemFetchScope(scope);
+ m_monitor->setCollectionMonitored(Akonadi::Collection::root());
+ m_monitor->setMimeTypeMonitored(KCalCore::Event::eventMimeType(), true);
+ m_monitor->setMimeTypeMonitored(KCalCore::Todo::todoMimeType(), true);
+ m_monitor->setMimeTypeMonitored("text/calendar", true);
+
+ connect(m_monitor, SIGNAL(itemAdded(const Akonadi::Item &, const \
Akonadi::Collection &)), + SLOT(itemAdded(const Akonadi::Item \
&, const Akonadi::Collection &))); + connect(m_monitor, SIGNAL(itemRemoved(const \
Akonadi::Item &)), + SLOT(removeItem(const Akonadi::Item &)));
+ connect(m_monitor, SIGNAL(itemChanged(const Akonadi::Item &, const \
QSet<QByteArray> &)), + SLOT(itemChanged(const Akonadi::Item &, \
const QSet<QByteArray> &))); + connect(m_monitor, SIGNAL(itemMoved(const \
Akonadi::Item &, const Akonadi::Collection &, const Akonadi::Collection &)), + \
SLOT(itemMoved(const Akonadi::Item &, const Akonadi::Collection &, const \
Akonadi::Collection &))); +}
+
+void TodoModel::initHeaderItem(QStandardItem *item, QString title, QString toolTip, \
int days) +{
+ QMap<QString, QVariant> data;
+ QDateTime date = QDateTime(QDate::currentDate().addDays(days));
+ data["itemType"] = HeaderItem;
+ data["title"] = QString("<b>" + title + "</b>");
+ data["date"] = date;
+ item->setData(data, Qt::DisplayRole);
+ QColor textColor = \
Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + \
item->setForeground(QBrush(textColor)); + item->setData(QVariant(date), SortRole);
+ item->setData(QVariant(HeaderItem), ItemTypeRole);
+ item->setData(QVariant(QString()), CollectionRole);
+ item->setData(QVariant(QString()), UIDRole);
+ item->setData(QVariant("<qt><b>" + toolTip + "</b></qt>"), TooltipRole);
+}
+
+void TodoModel::resetModel()
+{
+ clear();
+ m_sectionItemsMap.clear();
+ m_collections.clear();
+ m_usedCollections.clear();
+ itemIds.clear();
+ parentItem = invisibleRootItem();
+ delete m_monitor;
+ m_monitor = 0;
+
+ if (!Akonadi::ServerManager::isRunning()) {
+ QStandardItem *errorItem = new QStandardItem();
+ errorItem->setData(QVariant(i18n("Sorry,the Akonadi server is not \
running!akonadictl start can save you")), Qt::DisplayRole); + \
parentItem->appendRow(errorItem); + } else {
+ initModel();
+ initMonitor();
+ }
+}
+
+void TodoModel::settingsChanged(int urgencyTime, int birthdayTime, QList<QColor> \
itemColors, int count, bool autoGroupHeader) +{
+ urgency = urgencyTime;
+ birthdayUrgency = birthdayTime;
+ urgentBg = itemColors.at(urgentColorPos);
+ passedFg = itemColors.at(passedColorPos);
+ todoBg = itemColors.at(todoColorPos);
+ finishedTodoBg = itemColors.at(finishedTodoColorPos);
+ recurringCount = count;
+ useAutoGroupHeader = autoGroupHeader;
+}
+
+void TodoModel::setCategoryColors(QHash<QString, QColor> categoryColors)
+{
+ m_categoryColors = categoryColors;
+}
+
+void TodoModel::setHeaderItems(QStringList headerParts)
+{
+ m_headerPartsList = headerParts;
+}
+
+void TodoModel::createHeaderItems(QStringList headerParts)
+{
+ QStandardItem *olderItem = new QStandardItem();
+ initHeaderItem(olderItem, i18n("Older todos"), i18n("Unfinished todos"), -28);
+ m_sectionItemsMap.insert(olderItem->data(SortRole).toDate(), olderItem);
+
+ QStandardItem *somedayItem = new QStandardItem();
+ initHeaderItem(somedayItem, i18n("Due Date not specified - Todos"), i18n("Todos \
with no due date"), 366); + \
m_sectionItemsMap.insert(somedayItem->data(SortRole).toDate(), somedayItem); +
+ if (!useAutoGroupHeader) {
+ for (int i = 0; i < headerParts.size(); i += 3) {
+ QStandardItem *item = new QStandardItem();
+ initHeaderItem(item, headerParts.value(i), headerParts.value(i + 1), \
headerParts.value(i + 2).toInt()); + \
m_sectionItemsMap.insert(item->data(SortRole).toDate(), item); + }
+ }
+}
+
+void TodoModel::itemAdded(const Akonadi::Item &item, const Akonadi::Collection \
&collection) +{
+ m_collections.insert(collection.id(), collection);
+ addItem(item, collection);
+}
+
+void TodoModel::removeItem(const Akonadi::Item &item)
+{
+ foreach (QStandardItem *i, m_sectionItemsMap) {
+ QModelIndexList l;
+ if (i->hasChildren())
+ l = match(i->child(0, 0)->index(), TodoModel::ItemIDRole, item.id(), \
-1); +
+ for (int c = l.count(); c > 0; --c) {
+ i->removeRow(l.at(c - 1).row());
+ }
+
+ int r = i->row();
+ if (r != -1 && !i->hasChildren()) {
+ takeRow(r);
+ emit modelNeedsExpanding();
+ }
+ }
+
+ itemIds.removeAll(item.id());
+}
+
+void TodoModel::itemChanged(const Akonadi::Item &item, const QSet<QByteArray> &)
+{
+ kDebug() << "item changed";
+ removeItem(item);
+ addItem(item, item.parentCollection());
+}
+
+void TodoModel::itemMoved(const Akonadi::Item &item, const Akonadi::Collection &, \
const Akonadi::Collection &) +{
+ kDebug() << "item moved";
+ removeItem(item);
+ addItem(item, item.parentCollection());
+}
+
+void TodoModel::addItem(const Akonadi::Item &item, const Akonadi::Collection \
&collection) +{
+ Q_UNUSED(collection);
+
+ if (itemIds.contains(item.id())) {
+ removeItem(item);
+ }
+
+ if (item.hasPayload<KCalCore::Event::Ptr>()) {
+ KCalCore::Event::Ptr event = item.payload <KCalCore::Event::Ptr>();
+ if (event) {
+ addEventItem(eventDetails(item, event));
+ itemIds.append(item.id());
+ } // if event
+ } else if (item.hasPayload <KCalCore::Todo::Ptr>()) {
+ KCalCore::Todo::Ptr todo = item.payload<KCalCore::Todo::Ptr>();
+ if (todo) {
+ addTodoItem(todoDetails(item, todo));
+ itemIds.append(item.id());
+ }
+ }
+}
+
+void TodoModel::addEventItem(const QMap<QString, QVariant> &values)
+{
+ QMap<QString, QVariant> data = values;
+ QString category = values["mainCategory"].toString();
+ QColor textColor = \
Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); +
+ // dont add events starting later than a year
+ if (values["startDate"].toDate() > QDate::currentDate().addDays(365)) {
+ return;
+ }
+
+ if (values["recurs"].toBool()) {
+ int c = 0;
+ QList<QVariant> dtTimes = values["recurDates"].toList();
+ foreach (const QVariant &eventDtTime, dtTimes) {
+ if (recurringCount != 0 && c >= recurringCount)
+ break;
+
+ QStandardItem *eventItem = new QStandardItem();
+ eventItem->setForeground(QBrush(textColor));
+ data["startDate"] = eventDtTime;
+
+ int d = \
values["startDate"].toDateTime().secsTo(values["endDate"].toDateTime()); + \
data["endDate"] = eventDtTime.toDateTime().addSecs(d); +
+ QDate itemDt = eventDtTime.toDate();
+ if (values["isBirthday"].toBool()) {
+ data["itemType"] = BirthdayItem;
+ int n = eventDtTime.toDate().year() - \
values["startDate"].toDate().year(); + n > 2000 ? data["yearsSince"] = \
"XX" : data["yearsSince"] = QString::number(n); // workaround missing facebook \
birthdays + if (itemDt >= QDate::currentDate() && \
QDate::currentDate().daysTo(itemDt) < birthdayUrgency) { + \
eventItem->setBackground(QBrush(urgentBg)); + } else {
+ if (m_categoryColors.contains(i18n("Birthday")) || \
m_categoryColors.contains("Birthday")) { + QString b = \
"Birthday"; + if (m_categoryColors.contains(i18n("Birthday"))) \
{ + b = i18n("Birthday");
+ }
+ eventItem->setBackground(QBrush(m_categoryColors.value(b)));
+ }
+ }
+ eventItem->setData(QVariant(BirthdayItem), ItemTypeRole);
+ } else if (values["isAnniversary"].toBool()) {
+ data["itemType"] = AnniversaryItem;
+ int n = eventDtTime.toDate().year() - \
values["startDate"].toDate().year(); + data["yearsSince"] = \
QString::number(n); + if (itemDt >= QDate::currentDate() && \
QDate::currentDate().daysTo(itemDt) < birthdayUrgency) { + \
eventItem->setBackground(QBrush(urgentBg)); + } else {
+ if (m_categoryColors.contains(category)) {
+ \
eventItem->setBackground(QBrush(m_categoryColors.value(category))); + \
} + }
+ eventItem->setData(QVariant(AnniversaryItem), ItemTypeRole);
+ } else {
+ data["itemType"] = NormalItem;
+ eventItem->setData(QVariant(NormalItem), ItemTypeRole);
+ QDateTime itemDtTime = data["startDate"].toDateTime();
+ if (itemDtTime > QDateTime::currentDateTime() && \
QDateTime::currentDateTime().secsTo(itemDtTime) < urgency * 60) { + \
eventItem->setBackground(QBrush(urgentBg)); + } else if \
(QDateTime::currentDateTime() > itemDtTime) { + \
eventItem->setForeground(QBrush(passedFg)); + } else if \
(m_categoryColors.contains(category)) { + \
eventItem->setBackground(QBrush(m_categoryColors.value(category))); + \
} + }
+
+ eventItem->setData(data, Qt::DisplayRole);
+ eventItem->setData(eventDtTime, SortRole);
+ eventItem->setData(values["uid"], UIDRole);
+ eventItem->setData(values["itemid"], ItemIDRole);
+ eventItem->setData(values["collectionId"], CollectionRole);
+ eventItem->setData(values["tooltip"], TooltipRole);
+
+ addItemRow(eventDtTime.toDate(), eventItem);
+
+ ++c;
+ }
+ } else {
+ QStandardItem *eventItem;
+ eventItem = new QStandardItem();
+ data["itemType"] = NormalItem;
+ eventItem->setData(QVariant(NormalItem), ItemTypeRole);
+ eventItem->setForeground(QBrush(textColor));
+ eventItem->setData(data, Qt::DisplayRole);
+ eventItem->setData(values["startDate"], SortRole);
+ eventItem->setData(values["uid"], TodoModel::UIDRole);
+ eventItem->setData(values["itemid"], ItemIDRole);
+ eventItem->setData(values["collectionId"], CollectionRole);
+ eventItem->setData(values["tooltip"], TooltipRole);
+ QDateTime itemDtTime = values["startDate"].toDateTime();
+ if (itemDtTime > QDateTime::currentDateTime() && \
QDateTime::currentDateTime().secsTo(itemDtTime) < urgency * 60) { + \
eventItem->setBackground(QBrush(urgentBg)); + } else if \
(QDateTime::currentDateTime() > itemDtTime) { + \
eventItem->setForeground(QBrush(passedFg)); + } else if \
(m_categoryColors.contains(category)) { + \
eventItem->setBackground(QBrush(m_categoryColors.value(category))); + }
+
+ addItemRow(values["startDate"].toDate(), eventItem);
+ }
+}
+
+void TodoModel::addTodoItem(const QMap <QString, QVariant> &values)
+{
+ QColor textColor = \
Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); + QMap<QString, \
QVariant> data = values; + QString category = values["mainCategory"].toString();
+
+ // dont add todos starting later than a year
+ if (values["hasDueDate"].toBool() == true && values["dueDate"].toDate() > \
QDate::currentDate().addDays(365)) { + return;
+ }
+
+ if (values["recurs"].toBool()) {
+ int c = 0;
+ QList<QVariant> dtTimes = values["recurDates"].toList();
+ foreach (const QVariant &eventDtTime, dtTimes) {
+ if (recurringCount != 0 && c >= recurringCount)
+ break;
+
+ QStandardItem *todoItem = new QStandardItem();
+ data["dueDate"] = eventDtTime;
+ data["itemType"] = TodoItem;
+ todoItem->setData(QVariant(TodoItem), ItemTypeRole);
+ todoItem->setForeground(QBrush(textColor));
+ todoItem->setData(data, Qt::DisplayRole);
+ todoItem->setData(eventDtTime, SortRole);
+ todoItem->setData(values["uid"], TodoModel::UIDRole);
+ todoItem->setData(values["itemid"], ItemIDRole);
+ todoItem->setData(values["collectionId"], CollectionRole);
+ todoItem->setData(values["tooltip"], TooltipRole);
+ if (values["completed"].toBool() == true) {
+ todoItem->setBackground(QBrush(finishedTodoBg));
+ } else if (m_categoryColors.contains(category)) {
+ todoItem->setBackground(QBrush(m_categoryColors.value(category)));
+ } else {
+ todoItem->setBackground(QBrush(todoBg));
+ }
+
+ addItemRow(eventDtTime.toDate(), todoItem);
+
+ ++c;
+ }
+ } else {
+ QStandardItem *todoItem = new QStandardItem();
+ data["itemType"] = TodoItem;
+ todoItem->setData(QVariant(TodoItem), ItemTypeRole);
+ todoItem->setForeground(QBrush(textColor));
+ todoItem->setData(data, Qt::DisplayRole);
+ todoItem->setData(values["dueDate"], SortRole);
+ todoItem->setData(values["uid"], TodoModel::UIDRole);
+ todoItem->setData(values["itemid"], ItemIDRole);
+ todoItem->setData(values["collectionId"], CollectionRole);
+ todoItem->setData(values["tooltip"], TooltipRole);
+ if (values["completed"].toBool() == true) {
+ todoItem->setBackground(QBrush(finishedTodoBg));
+ } else if (m_categoryColors.contains(category)) {
+ todoItem->setBackground(QBrush(m_categoryColors.value(category)));
+ } else {
+ todoItem->setBackground(QBrush(todoBg));
+ }
+
+ addItemRow(values["dueDate"].toDate(), todoItem);
+ }
+}
+
+void TodoModel::addItemRow(QDate eventDate, QStandardItem *incidenceItem)
+{
+ QStandardItem *headerItem = 0;
+
+ foreach (QStandardItem *item, m_sectionItemsMap) {
+ if (eventDate < item->data(SortRole).toDate())
+ break;
+ else
+ headerItem = item;
+ }
+
+ if (useAutoGroupHeader) {
+ if ((headerItem && eventDate >= QDate::currentDate() && eventDate > \
headerItem->data(SortRole).toDate()) || (headerItem == 0 && eventDate > \
QDate::currentDate().addDays(-29))) { + int days = \
QDate::currentDate().daysTo(eventDate); + QStandardItem *item = new \
QStandardItem(); + initHeaderItem(item, QString("%{date}"), QString(), \
days); + m_sectionItemsMap.insert(item->data(SortRole).toDate(), item);
+ headerItem = item;
+ }
+ }
+
+
+ if (headerItem) {
+ headerItem->appendRow(incidenceItem);
+ headerItem->sortChildren(0, Qt::AscendingOrder);
+ if (headerItem->row() == -1) {
+ parentItem->appendRow(headerItem);
+ parentItem->sortChildren(0, Qt::AscendingOrder);
+ }
+
+ emit modelNeedsExpanding();
+ }
+}
+
+QMap<QString, QVariant> TodoModel::eventDetails(const Akonadi::Item &item, \
KCalCore::Event::Ptr event) +{
+ QMap <QString, QVariant> values;
+ Akonadi::Collection itemCollection = \
m_collections.value(item.storageCollectionId()); + \
m_usedCollections.insert(itemCollection.name(), \
QString::number(itemCollection.id())); + values["resource"] = \
itemCollection.resource(); + values["collectionName"] = itemCollection.name();
+ values["collectionId"] = QString::number(itemCollection.id());
+ values["uid"] = event->uid();
+ values["itemid"] = item.id();
+ values["remoteid"] = item.remoteId();
+ values["summary"] = event->summary();
+ values["description"] = event->description();
+ values["location"] = event->location();
+ QStringList categories = event->categories();
+ if (categories.isEmpty()) {
+ values["categories"] = i18n("Unspecified");
+ values["mainCategory"] = i18n("Unspecified");
+ } else {
+ values["categories"] = categories;
+ values["mainCategory"] = categories.first();
+ }
+
+ values["status"] = event->status();
+ values["startDate"] = event->dtStart().toLocalZone().dateTime();
+ values["endDate"] = event->dtEnd().toLocalZone().dateTime();
+
+ bool recurs = event->recurs();
+ values["recurs"] = recurs;
+ QList<QVariant> recurDates;
+ if (recurs) {
+ KCalCore::Recurrence *r = event->recurrence();
+ KCalCore::DateTimeList dtTimes = \
r->timesInInterval(KDateTime(QDate::currentDate()), \
KDateTime(QDate::currentDate()).addDays(365)); + dtTimes.sortUnique();
+ foreach (const KDateTime &t, dtTimes) {
+ recurDates << QVariant(t.toLocalZone().dateTime());
+ }
+ }
+ values["recurDates"] = recurDates;
+
+ if (event->customProperty("KABC", "BIRTHDAY") == QString("YES") || \
categories.contains(i18n("Birthday")) || categories.contains("Birthday")) { + \
values["isBirthday"] = QVariant(true); + } else {
+ values["isBirthday"] = QVariant(false);
+ }
+
+ event->customProperty("KABC", "ANNIVERSARY") == QString("YES") ? values \
["isAnniversary"] = QVariant(true) : QVariant(false); + values["contactName"] = \
event->customProperty("KABC", "NAME-1"); + values["tooltip"] = \
KCalUtils::IncidenceFormatter::toolTipStr(itemCollection.name(), event, \
event->dtStart().date(), true, KDateTime::Spec::LocalZone()); +
+ return values;
+}
+
+QMap<QString, QVariant> TodoModel::todoDetails(const Akonadi::Item &item, \
KCalCore::Todo::Ptr todo) +{
+ QMap <QString, QVariant> values;
+ Akonadi::Collection itemCollection = \
m_collections.value(item.storageCollectionId()); + \
m_usedCollections.insert(itemCollection.name(), \
QString::number(itemCollection.id())); + values["resource"] = \
itemCollection.resource(); + values["collectionName"] = itemCollection.name();
+ values["collectionId"] = QString::number(itemCollection.id());
+ values["uid"] = todo->uid();
+ values["itemid"] = item.id();
+ values["remoteid"] = item.remoteId();
+ values["summary"] = todo->summary();
+ values["description"] = todo->description();
+ values["location"] = todo->location();
+ QStringList categories = todo->categories();
+ if (categories.isEmpty()) {
+ values["categories"] = i18n("Unspecified");
+ values["mainCategory"] = i18n("Unspecified");
+ } else {
+ values["categories"] = categories;
+ values["mainCategory"] = categories.first();
+ }
+
+ values["completed"] = todo->isCompleted();
+ values["percent"] = todo->percentComplete();
+ if (todo->hasStartDate()) {
+ values["startDate"] = todo->dtStart(false).toLocalZone().dateTime();
+ values["hasStartDate"] = true;
+ } else {
+ values["startDate"] = QDateTime();
+ values["hasStartDate"] = false;
+ }
+ values["completedDate"] = todo->completed().toLocalZone().dateTime();
+ values["inProgress"] = todo->isInProgress(false);
+ values["isOverdue"] = todo->isOverdue();
+ if (todo->hasDueDate()) {
+ values["dueDate"] = todo->dtDue().toLocalZone().dateTime();
+ values["hasDueDate"] = true;
+ } else {
+ values["dueDate"] = QDateTime::currentDateTime().addDays(366);
+ values["hasDueDate"] = false;
+ }
+
+ bool recurs = todo->recurs();
+ values["recurs"] = recurs;
+ QList<QVariant> recurDates;
+ if (recurs) {
+ KCalCore::Recurrence *r = todo->recurrence();
+ KCalCore::DateTimeList dtTimes = \
r->timesInInterval(KDateTime(QDate::currentDate()), \
KDateTime(QDate::currentDate()).addDays(365)); + dtTimes.sortUnique();
+ foreach (const KDateTime &t, dtTimes) {
+ recurDates << QVariant(t.toLocalZone().dateTime());
+ }
+ }
+ values["recurDates"] = recurDates;
+
+ values["tooltip"] = \
KCalUtils::IncidenceFormatter::toolTipStr(itemCollection.name(), todo, \
todo->dtStart().date(), true, KDateTime::Spec::LocalZone()); +
+ return values;
+}
+
+QMap<QString, QString> TodoModel::usedCollections()
+{
+ return m_usedCollections;
+}
+
+#include "todomodel.moc"
diff --git a/qml/todo_epic/todomodel.h b/qml/todo_epic/todomodel.h
new file mode 100644
index 0000000..967ca1e
--- /dev/null
+++ b/qml/todo_epic/todomodel.h
@@ -0,0 +1,116 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#ifndef TODOMODEL_H
+#define TODOMODEL_H
+
+#include <akonadi/monitor.h>
+#include <akonadi/collection.h>
+
+#include <kcalcore/event.h>
+#include <kcalcore/todo.h>
+
+#include <KUrl>
+#include <QStandardItemModel>
+#include <QColor>
+#include <QHash>
+#include <QString>
+
+class QStandardItem;
+class KJob;
+
+static const int ShortDateFormat = 0;
+static const int LongDateFormat = 1;
+static const int FancyShortDateFormat = 2;
+static const int FancyLongDateFormat = 3;
+static const int CustomDateFormat = 4;
+
+static const int urgentColorPos = 0;
+static const int passedColorPos = 1;
+static const int todoColorPos = 2;
+static const int finishedTodoColorPos = 3;
+
+class TodoModel : public QStandardItemModel
+{
+ Q_OBJECT
+public:
+ enum EventRole {
+ SortRole = Qt::UserRole + 1,
+ UIDRole,
+ ItemTypeRole,
+ TooltipRole,
+ ItemIDRole,
+ CollectionRole
+ };
+
+ enum ItemType {
+ HeaderItem = 0,
+ NormalItem,
+ BirthdayItem,
+ AnniversaryItem,
+ TodoItem
+ };
+
+ explicit TodoModel(QObject *parent = 0, int urgencyTime = 15, int birthdayTime = \
14, QList<QColor> colorList = QList<QColor>(), int count = 0, bool autoGroupHeader = \
false); + ~TodoModel();
+
+public:
+ void setDateFormat(int format, QString string);
+ void setCategoryColors(const QHash<QString, QColor>);
+ void setHeaderItems(QStringList headerParts);
+ void initModel();
+ void initMonitor();
+ void resetModel();
+ void settingsChanged(int urgencyTime, int birthdayTime, QList<QColor> \
itemColors, int count, bool autoGroupHeader); + QMap<QString, QString> \
usedCollections(); +
+private slots:
+ void initialCollectionFetchFinished(KJob *);
+ void initialItemFetchFinished(KJob *);
+ void addEventItem(const QMap <QString, QVariant> &values);
+ void addTodoItem(const QMap <QString, QVariant> &values);
+ void itemAdded(const Akonadi::Item &, const Akonadi::Collection &);
+ void removeItem(const Akonadi::Item &);
+ void itemChanged(const Akonadi::Item &, const QSet<QByteArray> &);
+ void itemMoved(const Akonadi::Item &, const Akonadi::Collection &, const \
Akonadi::Collection &); +
+private:
+ void createHeaderItems(QStringList headerParts);
+ void initHeaderItem(QStandardItem *item, QString title, QString toolTip, int \
days); + void addItem(const Akonadi::Item &item, const Akonadi::Collection \
&collection); + void addItemRow(QDate eventDate, QStandardItem *items);
+ QMap<QString, QVariant> eventDetails(const Akonadi::Item &, \
KCalCore::Event::Ptr); + QMap<QString, QVariant> todoDetails(const Akonadi::Item \
&, KCalCore::Todo::Ptr); +
+private:
+ QStandardItem *parentItem;
+ QStringList m_headerPartsList;
+ QMap<QDate, QStandardItem *> m_sectionItemsMap;
+ QMap<QString, QString> m_usedCollections;
+ int urgency, birthdayUrgency, recurringCount;
+ QColor urgentBg, passedFg, todoBg, finishedTodoBg;
+ QHash<QString, QColor> m_categoryColors;
+ QHash<Akonadi::Entity::Id, Akonadi::Collection> m_collections;
+ QList<Akonadi::Entity::Id> itemIds;
+ Akonadi::Monitor *m_monitor;
+ bool useAutoGroupHeader;
+
+signals:
+ void modelNeedsExpanding();
+};
+
+#endif
diff --git a/qml/todo_epic/todotreeview.cpp b/qml/todo_epic/todotreeview.cpp
new file mode 100644
index 0000000..125bc18
--- /dev/null
+++ b/qml/todo_epic/todotreeview.cpp
@@ -0,0 +1,79 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#include "todotreeview.h"
+#include "todomodel.h"
+
+#include <QModelIndex>
+#include <QMouseEvent>
+
+TodoTreeView::TodoTreeView(QWidget* parent)
+ : QTreeView(parent)
+{
+ setAttribute(Qt::WA_NoSystemBackground);
+ setMouseTracking(true);
+ setWordWrap(true);
+ setIndentation(50);
+ setEditTriggers(QAbstractItemView::NoEditTriggers);
+}
+
+TodoTreeView::~TodoTreeView()
+{
+}
+
+void TodoTreeView::mouseMoveEvent(QMouseEvent *event)
+{
+ QString oldTip = tip;
+
+ idx = indexAt(event->pos());
+ if (idx.isValid()) {
+ tip = idx.data(TodoModel::TooltipRole).toString();
+ } else {
+ tip.clear();
+ }
+ if (tip != oldTip)
+ emit tooltipUpdated(tip);
+}
+
+void TodoTreeView::mousePressEvent(QMouseEvent *event)
+{
+ QString oldTip = tip;
+
+ idx = indexAt(event->pos());
+ if (idx.isValid()) {
+ tip = idx.data(TodoModel::TooltipRole).toString();
+ } else {
+ tip.clear();
+ }
+
+ if (tip != oldTip)
+ emit tooltipUpdated(tip);
+}
+
+QModelIndex TodoTreeView::indexAtCursor()
+{
+ return idx;
+}
+
+QString TodoTreeView::summaryAtCursor()
+{
+ const QVariant v = idx.data(Qt::DisplayRole);
+ QMap<QString, QVariant> values = v.toMap();
+ return values["summary"].toString();
+}
+
+#include "todotreeview.moc"
diff --git a/qml/todo_epic/todotreeview.h b/qml/todo_epic/todotreeview.h
new file mode 100644
index 0000000..1a60078
--- /dev/null
+++ b/qml/todo_epic/todotreeview.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ * Copyright (C) 2014 by Heena Mahour <heena393@gmail.com>
+ */
+
+#ifndef TODOTREEVIEW_H
+#define TODOTREEVIEW_H
+
+#include <QTreeView>
+
+class QModelIndex;
+class QMouseEvent;
+
+class TodoTreeView : public QTreeView
+{
+ Q_OBJECT
+
+public:
+ TodoTreeView(QWidget* parent = 0);
+ ~TodoTreeView();
+
+ QModelIndex indexAtCursor();
+ QString summaryAtCursor();
+
+protected:
+ void mouseMoveEvent(QMouseEvent *event);
+ void mousePressEvent(QMouseEvent *event);
+
+signals:
+ void tooltipUpdated(QString);
+
+private:
+ QString tip;
+ QModelIndex idx;
+};
+
+#endif
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic