kde-extraapps/kdeplasma-addons/applets/rememberthemilk/rememberthemilk-plasmoid.cpp
2015-10-28 09:36:32 +02:00

433 lines
15 KiB
C++

/*
* Copyright 2009 Andrew Stromme <astromme@chatonka.com>
* Copyright 2012 Jeremy Whiting <jpwhiting@kde.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as
* published by the Free Software Foundation; either version 2, 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 Library General Public
* License along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "rememberthemilk-plasmoid.h"
// Qt Includes
#include <QPushButton>
#include <QCheckBox>
#include <QTreeView>
// KDE Includes
#include <KConfigDialog>
#include <KDebug>
#include <KToolInvocation>
// Plasma Includes
#include <Plasma/Theme>
#include <Plasma/Service>
#include <Plasma/Animator>
#include <Plasma/TreeView>
#include <Plasma/TabBar>
#include <Plasma/Label>
#include <Plasma/LineEdit>
#include <Plasma/ServiceJob>
// Local
#include "ui_authenticate.h"
#include "ui_general.h"
#include "taskmodel.h"
#include "tasksortfilter.h"
#include <KLineEdit>
RememberTheMilkPlasmoid::RememberTheMilkPlasmoid(QObject* parent, const QVariantList& args)
: Plasma::PopupApplet(parent, args),
m_authenticated(false),
m_sortBy(SortDue),
m_taskEditor(0),
m_engine(0),
m_taskService(0),
m_graphicsWidget(0),
m_authService(0),
m_authWidgetUi(new Ui::AuthWidget),
m_generalOptionsUi(new Ui::GeneralWidget)
{
setBackgroundHints(DefaultBackground);
setPopupIcon("view-pim-journal"); // TODO: Create/Find better item
m_authWidget = new QWidget();
m_authWidgetUi->setupUi(m_authWidget);
m_authWidgetUi->webView->hide();
m_generalOptions = new QWidget();
connect(m_authWidgetUi->signupLabel, SIGNAL(leftClickedUrl(QString)), KToolInvocation::self(), SLOT(invokeBrowser(QString)));
m_generalOptionsUi->setupUi(m_generalOptions);
m_generalOptionsUi->sortType->addItem(i18n("Due Date"));
m_generalOptionsUi->sortType->addItem(i18n("Priority"));
}
RememberTheMilkPlasmoid::~RememberTheMilkPlasmoid() {
if (hasFailedToLaunch()) {
kDebug() << "failed to launch";
}
delete m_authWidget;
delete m_authWidgetUi;
delete m_generalOptions;
delete m_generalOptionsUi;
}
void RememberTheMilkPlasmoid::init() {
setAspectRatioMode(Plasma::IgnoreAspectRatio);
graphicsWidget();
if (!m_engine || !m_engine->isValid()) {
return Plasma::Applet::init();
}
m_engine->connectSource("Auth", this);
m_authService = m_engine->serviceForSource("Auth");
m_authService->setParent(this);
connect(m_authService, SIGNAL(finished(Plasma::ServiceJob*)), SLOT(jobFinished(Plasma::ServiceJob*)));
configChanged();
Plasma::Applet::init();
setAssociatedApplicationUrls(KUrl("http://rememberthemilk.com"));
}
void RememberTheMilkPlasmoid::startAuth()
{
disconnect(m_authWidgetUi->authenticateButton, SIGNAL(clicked(bool)), this, SLOT(startAuth()));
connect(m_authWidgetUi->authenticateButton, SIGNAL(clicked(bool)), this, SLOT(continueAuth()));
m_authWidgetUi->authenticateButton->setText(i18n("Click to finish authentication"));
KConfigGroup cg = m_authService->operationDescription("StartLogin");
Plasma::ServiceJob* authJob = m_authService->startOperationCall(cg);
connect(authJob, SIGNAL(finished(KJob*)), SLOT(authJobFinished(KJob*)));
busyUntil(authJob);
busyUntil(0); // Sets busy until we manually call jobFinished(0). Busy until first tasks refresh
m_authenticated = false;
}
void RememberTheMilkPlasmoid::authJobFinished(KJob* job)
{
Plasma::ServiceJob *authJob = qobject_cast<Plasma::ServiceJob*>(job);
QString url = authJob->result().toString();
m_authWidgetUi->webView->setUrl(QUrl(url));
m_authWidgetUi->webView->show();
}
void RememberTheMilkPlasmoid::continueAuth()
{
KConfigGroup cg = m_authService->operationDescription("Login");
Plasma::ServiceJob* authJob = m_authService->startOperationCall(cg);
busyUntil(authJob);
busyUntil(0); // Sets busy until we manually call jobFinished(0). Busy until first tasks refresh
m_authenticated = false;
}
void RememberTheMilkPlasmoid::configAccepted() {
switch(m_generalOptionsUi->sortType->currentIndex()) {
case 0:
setSortBy(SortDue);
break;
case 1:
setSortBy(SortPriority);
break;
}
}
void RememberTheMilkPlasmoid::configFinished()
{
m_authWidget->setParent(0); // We don't want these widgets destroyed along with the configuration window
m_generalOptions->setParent(0); // They are reused later
}
void RememberTheMilkPlasmoid::createConfigurationInterface(KConfigDialog* parent) {
connect(parent, SIGNAL(finished()), this, SLOT(configFinished()));
connect(parent, SIGNAL(applyClicked()), this, SLOT(configAccepted()));
connect(parent, SIGNAL(okClicked()), this, SLOT(configAccepted()));
connect(m_authWidgetUi->authenticateButton, SIGNAL(clicked(bool)), this, SLOT(startAuth()));
m_generalOptionsUi->sortType->setCurrentIndex(m_sortBy);
KPageWidgetItem* general = parent->addPage(m_generalOptions, i18n("General"), "configure", i18n("General Configuration Options"));
KPageWidgetItem* auth = parent->addPage(m_authWidget, i18n("Authentication"), icon(), i18n("Remember The Milk Authentication"));
if (!m_authenticated)
parent->setCurrentPage(auth);
else
parent->setCurrentPage(general);
connect(m_generalOptionsUi->sortType, SIGNAL(currentIndexChanged(int)), parent, SLOT(settingsModified()));
connect(this, SIGNAL(authenticated()), parent, SLOT(settingsModified()));
}
void RememberTheMilkPlasmoid::setSortBy(SortBy sortBy)
{
m_filterModel->setSortBy(sortBy);
m_model->setDropType(sortBy);
switch (sortBy) {
case SortPriority:
config().writeEntry("SortBy", "Priority");
m_delegate->setSmallTasks(false);
break;
case SortDue:
config().writeEntry("SortBy", "Date");
m_delegate->setSmallTasks(true);
break;
}
m_sortBy = sortBy;
}
void RememberTheMilkPlasmoid::dataUpdated(const QString& name, const Plasma::DataEngine::Data& data) {
if (name == "Auth") {
m_authenticated = data.value("ValidToken").toBool();
kDebug() << "Auth: " << m_authenticated;
m_authWidgetUi->webView->hide();
if (m_authenticated) {
m_authWidgetUi->authStatus->setText(i18n("Authenticated"));
m_authWidgetUi->kled->setState(KLed::On);
m_authWidgetUi->kled->setColor(Qt::green);
} else {
m_authWidgetUi->authStatus->setText(i18n("Not Authenticated"));
m_authWidgetUi->kled->setState(KLed::Off);
m_authWidgetUi->kled->setColor(Qt::red);
m_busyUntil.clear(); // no longer trying to authenticate
setBusy(false);
}
if (m_authenticated) {
setConfigurationRequired(false);
m_token = data.value("Token").toString();
config().writeEntry("token", m_token);
m_engine->connectSource("Lists", this);
m_engine->connectSource("Tasks", this);
busyUntil(0);
emit authenticated();
}
else if (m_categoriesBar->count() == 1 && m_lists.isEmpty())
m_categoriesBar->nativeWidget()->setTabText(0, i18n("Login Failed. Please try again."));
}
else if (name == "Lists") {
if (m_categoriesBar->count() == 1 && m_lists.isEmpty())
m_categoriesBar->removeTab(0); // remove "refreshing" tab;
//while (m_categoriesBar->count())
// m_categoriesBar->removeTab(0);
//m_lists.clear(); //FIXME: What happens when a list is deleted?
foreach(const QString &key, data.keys()) {
if (!m_lists.contains(key.toULongLong())) {
m_categoriesBar->addTab(data.value(key).toString());
m_lists.append(key.toULongLong());
}
m_model->listUpdate(key.toULongLong());
}
int current = config().readEntry("CurrentList").toInt();
if (m_categoriesBar->count() >= current) {
m_categoriesBar->setCurrentIndex(current);
listChanged(current); // doesn't always update.. i.e if current is actually the current
}
}
else if (name == "Tasks") {
if (data.keys().count() > 0)
jobFinished(0); // No longer busy.
}
}
void RememberTheMilkPlasmoid::listChanged(int pos)
{
if (pos < 0 || pos >= m_lists.size())
return;
config().writeEntry("CurrentList", pos);
m_model->switchToList(m_lists.at(pos));
}
void RememberTheMilkPlasmoid::createTask(const QString& task)
{
if (!m_taskService) {
m_taskService = m_engine->serviceForSource("Tasks");
m_taskService->setParent(this);
connect(m_taskService, SIGNAL(finished(Plasma::ServiceJob*)), SLOT(jobFinished(Plasma::ServiceJob*)));
}
KConfigGroup cg = m_taskService->operationDescription("create");
cg.writeEntry("task", task);
kDebug() << "QString::number(m_model->currentList()->id)";
cg.writeEntry("listid", m_model->currentList()->id);
busyUntil(m_taskService->startOperationCall(cg));
}
void RememberTheMilkPlasmoid::onTaskEditorHide() {
m_tasksView->nativeWidget()->setEnabled(true);
m_priorityLabel->setText(i18n("Remember The Milk Tasks"));
}
void RememberTheMilkPlasmoid::showTaskEditor(QModelIndex index) {
if (index.data(Qt::RTMItemType).toInt() != RTMTaskItem) // We have a header rather than a task.
return;
m_taskEditor->setModelIndex(index);
m_taskEditor->hide();
m_taskEditor->show();
m_tasksView->nativeWidget()->setEnabled(false);
m_taskEditor->setEnabled(true);
m_taskEditor->startAnimation(m_tasksView->size());
m_priorityLabel->setText(i18n("Editing Task: ") + index.data(Qt::RTMNameRole).toString());
geometryChanged();
}
void RememberTheMilkPlasmoid::busyUntil(Plasma::ServiceJob* job)
{
setBusy(true);
m_busyUntil.append(job);
}
void RememberTheMilkPlasmoid::jobFinished(Plasma::ServiceJob* job)
{
if (m_busyUntil.contains(job)) {
m_busyUntil.removeAll(job);
}
if (m_busyUntil.isEmpty())
setBusy(false);
}
void RememberTheMilkPlasmoid::resizeEvent(QGraphicsSceneResizeEvent* event) {
if (m_taskEditor)
m_taskEditor->resize(m_tasksView->size());
Plasma::Applet::resizeEvent(event);
}
QGraphicsWidget* RememberTheMilkPlasmoid::graphicsWidget() {
if (m_graphicsWidget)
return m_graphicsWidget;
m_engine = dataEngine("rtm");
if (!m_engine || !m_engine->isValid()) {
setFailedToLaunch(true, i18n("Failed to load the Remember The Milk DataEngine"));
return m_graphicsWidget;
}
m_graphicsWidget = new QGraphicsWidget(this);
m_model = new TaskModel(m_engine, this);
connect(m_model, SIGNAL(jobStarted(Plasma::ServiceJob*)), SLOT(busyUntil(Plasma::ServiceJob*)));
connect(m_model, SIGNAL(jobFinished(Plasma::ServiceJob*)), SLOT(jobFinished(Plasma::ServiceJob*)));
m_priorityLabel = new Plasma::Label(this);
m_priorityLabel->setAlignment(Qt::AlignHCenter);
m_priorityLabel->setText(i18n("Remember The Milk Tasks"));
m_categoriesBar = new Plasma::TabBar(this);
m_categoriesBar->addTab(i18n("No Data Yet. Refreshing..."));
connect(m_categoriesBar, SIGNAL(currentChanged(int)), SLOT(listChanged(int)));
QPalette palette;
palette.setBrush(QPalette::Background, Plasma::Theme::defaultTheme()->color(Plasma::Theme::BackgroundColor));
palette.setBrush(QPalette::Text, Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor));
m_delegate = new TaskItemDelegate(this);
m_filterModel = new TaskSortFilter(m_model, this);
connect(m_model, SIGNAL(modelUpdated()), m_filterModel, SLOT(listChanged()));
m_tasksView = new Plasma::TreeView(this);
m_tasksView->installEventFilter(m_delegate);
m_tasksView->setModel(m_filterModel);
m_tasksView->nativeWidget()->setItemDelegate(m_delegate);
m_tasksView->nativeWidget()->header()->setHidden(true);
m_tasksView->nativeWidget()->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
m_tasksView->nativeWidget()->setRootIsDecorated(false);
m_tasksView->nativeWidget()->setIndentation(0);
m_tasksView->nativeWidget()->viewport()->setAutoFillBackground(false);
m_tasksView->nativeWidget()->viewport()->setPalette( palette );
m_tasksView->nativeWidget()->setSelectionMode(QAbstractItemView::SingleSelection);
m_tasksView->nativeWidget()->setDragEnabled(true);
m_tasksView->nativeWidget()->setAcceptDrops(true);
m_tasksView->nativeWidget()->viewport()->setAcceptDrops(true);
m_tasksView->nativeWidget()->setDropIndicatorShown(false);
m_tasksView->nativeWidget()->setDragDropMode(QAbstractItemView::DragDrop);
m_tasksView->nativeWidget()->setSortingEnabled(true);
m_tasksView->nativeWidget()->sortByColumn(0, Qt::AscendingOrder);
m_tasksView->nativeWidget()->expandAll();
connect(m_tasksView->nativeWidget(), SIGNAL(clicked(QModelIndex)), this, SLOT(showTaskEditor(QModelIndex)));
m_searchLine = new Plasma::LineEdit(this);
m_searchLine->nativeWidget()->setClearButtonShown(true);
m_searchLine->nativeWidget()->setClickMessage(i18n("Filter Tasks..."));
connect(m_searchLine->nativeWidget(), SIGNAL(textChanged(QString)), m_filterModel, SLOT(setFilterWildcard(QString)));
m_addTaskLine = new Plasma::LineEdit(this); // must wait for plasma theming (4.3?) to get a themed lineedit
m_addTaskLine->nativeWidget()->setClearButtonShown(true);
m_addTaskLine->nativeWidget()->setClickMessage(i18n("Create New Task..."));
connect(m_addTaskLine->nativeWidget(), SIGNAL(returnPressed(QString)), m_addTaskLine->nativeWidget(), SLOT(clear()));
connect(m_addTaskLine->nativeWidget(), SIGNAL(returnPressed(QString)), this, SLOT(createTask(QString)));
kDebug() << "Creating layout";
m_mainLayout = new QGraphicsLinearLayout(Qt::Vertical, m_graphicsWidget);
m_mainLayout->addItem(m_priorityLabel);
m_mainLayout->addItem(m_categoriesBar);
m_mainLayout->addItem(m_searchLine);
m_mainLayout->addItem(m_tasksView);
m_mainLayout->addItem(m_addTaskLine);
m_graphicsWidget->setLayout(m_mainLayout);
m_graphicsWidget->setMinimumSize(250, 300);
m_graphicsWidget->setPreferredSize(300, 500);
m_taskEditor = new TaskEditor(m_engine, m_tasksView);
m_taskEditor->hide();
connect(m_taskEditor, SIGNAL(requestDiscardChanges()), this, SLOT(onTaskEditorHide()));
connect(m_taskEditor, SIGNAL(requestSaveChanges()), this, SLOT(onTaskEditorHide()));
connect(m_taskEditor, SIGNAL(jobStarted(Plasma::ServiceJob*)), SLOT(busyUntil(Plasma::ServiceJob*)));
connect(m_taskEditor, SIGNAL(jobFinished(Plasma::ServiceJob*)), SLOT(jobFinished(Plasma::ServiceJob*)));
return m_graphicsWidget;
}
void RememberTheMilkPlasmoid::configChanged()
{
KConfigGroup cg = config();
m_token = cg.readEntry("token");
kDebug() << "Token from config: " << m_token;
if (m_token.isNull())
setConfigurationRequired(true, i18n("Authentication to Remember The Milk needed"));
else {
KConfigGroup cg = m_authService->operationDescription("AuthWithToken");
cg.writeEntry("token", m_token);
busyUntil(m_authService->startOperationCall(cg));
busyUntil(0); // Sets busy until we manually call jobFinished(0). Busy until first tasks refresh
}
QString sortBy = config().readEntry("SortBy").toLower();
kDebug() << "Config says sort by " << sortBy;
if (sortBy == "date" || sortBy == "due")
setSortBy(SortDue);
else if (sortBy == "priority")
setSortBy(SortPriority);
else
setSortBy(SortDue); // Default
}
#include "moc_rememberthemilk-plasmoid.cpp"