[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