Skip to content

Instantly share code, notes, and snippets.

@shadeslayer
Created July 15, 2011 12:39
Show Gist options
  • Select an option

  • Save shadeslayer/1084608 to your computer and use it in GitHub Desktop.

Select an option

Save shadeslayer/1084608 to your computer and use it in GitHub Desktop.
/*
Copyright © 2011 Rohan Garg <[email protected]>
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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/>.
*/
#include "Module.h"
#include "ui_Module.h"
#include <QDebug>
#include <KAboutData>
#include <KPluginFactory>
#include <KStandardDirs>
#include <KMessageBox>
#include "Version.h"
#include "server_interface.h"
#include "session_interface.h"
K_PLUGIN_FACTORY_DECLARATION(KcmSynqConfigFactory);
Module::Module(QWidget *parent, const QVariantList &args) :
KCModule(KcmSynqConfigFactory::componentData(), parent, args),
ui(new Ui::MainWidget)
{
//Register custom types
syncevolution_qt_dbus_register_types();
KAboutData *about = new KAboutData("kcm-synq", 0,
ki18n("Synq Configuration"),
global_s_versionStringFull,
ki18n("Configure your synq accounts"),
KAboutData::License_GPL_V3,
ki18n("Copyright 2011 Rohan Garg"),
KLocalizedString(), QByteArray(),
"[email protected]");
about->addAuthor(ki18n("Rohan Garg"), ki18n("shadeslayer"), "[email protected]");
setAboutData(about);
//Don't know why this ain't working
QDBusInterface *interface = new QDBusInterface("org.freedesktop.DBus",
"/org.freedesktop.DBus",
"StartServiceByName",
QDBusConnection::sessionBus(),
this);
interface->call(staticInterfaceName());
m_server = new OrgSyncevolutionServerInterface(staticInterfaceName(), "/org/syncevolution/Server", QDBusConnection::sessionBus());
if (m_server->isValid()) {
m_server->Attach();
ui->setupUi(this);
updateOrAddFlag = addingProfile;
ui->addAccountButton->setIcon(KIcon("list-add"));
ui->removeAccountButton->setIcon(KIcon("edit-delete"));
//Add list of configured profiles
ui->listWidget->addItem(i18n("New Profile"));
ui->listWidget->addItems(m_server->GetConfigs(false));
//Add list of available templates
ui->templateList->addItems(m_server->GetConfigs(true));
setSyncOptions(ui->templateList->currentText());
// Sync type map, used for mapping sync type from combobox to a sync property
// As will be seen later on, we will use the current index of the combobox to map it to a sync property
m_syncType = new QMap<int, QString>();
m_syncType->insert(0, "two-way");
m_syncType->insert(1, "refresh-from-server");
m_syncType->insert(2, "refresh-from-client");
m_syncType->insert(3, "one-way-from-server");
m_syncType->insert(4, "one-way-from-client");
connect(ui->templateList, SIGNAL(currentIndexChanged(QString)), this, SLOT(setSyncOptions(QString)));
connect(ui->addAccountButton, SIGNAL(clicked(bool)), this, SLOT(addProfile(bool)));
connect(ui->removeAccountButton, SIGNAL(clicked(bool)), this, SLOT(removeProfile(bool)));
connect(m_server, SIGNAL(ConfigChanged()), this, SLOT(reloadConfigList()));
connect(ui->listWidget, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(showConfig(QListWidgetItem*)));
} else {
QVBoxLayout *layout = new QVBoxLayout(this);
QListWidget *list = new QListWidget(this);
layout->addWidget(list);
new ErrorOverlay(this, "Could not find the SyncEvolution DBus Server", this);
return;
}
// We have no help so remove the button from the buttons.
setButtons(buttons() ^ KCModule::Help);
}
Module::~Module()
{
m_server->Detach();
delete ui;
}
void Module::setSyncOptions(QString serverName)
{
m_server->Attach();
QStringMultiMap templateConfig = m_server->GetConfig(serverName, true);
m_devID = templateConfig.value(QString()).value("deviceId");
ui->addressResourceList->clear();
ui->calendarResourceList->clear();
ui->memoResourceList->clear();
ui->taskResourceList->clear();
QArrayOfDatabases addressBookDatabase = m_server->GetDatabases(serverName, "addressbook");
if (!addressBookDatabase.isEmpty() && templateConfig.value("source/addressbook").value("sync") != "disabled") {
m_addressSourceDatabaseMap.clear();
ui->contactsToolBar->setEnabled(true);
ui->customAddressbookURI->setEnabled(true);
ui->customAddressbookURI->setText(templateConfig.value("source/addressbook").value("uri"));
foreach(SyncDatabase tempAddressbook, addressBookDatabase) {
ui->addressResourceList->addItem(tempAddressbook.name);
// The logic for this is, the current index will *always* be 0 when the combobox is being setup
// so, we need to depend on the count() function here, but, the index is always count() - 1, which
// is why we have to use this
m_addressSourceDatabaseMap.insert(ui->addressResourceList->count()-1 , tempAddressbook.source);
}
ui->addressResourceList->addItem("New Addressbook resource");
}
QArrayOfDatabases calendarDatabase = m_server->GetDatabases(serverName, "calendar");
if (!calendarDatabase.isEmpty() && templateConfig.value("source/calendar").value("sync") != "disabled") {
m_calendarSourceDatabaseMap.clear();
ui->calendarToolBar->setEnabled(true);
ui->customCalendarURI->setEnabled(true);
ui->customCalendarURI->setText(templateConfig.value("source/calendar").value("uri"));
foreach(SyncDatabase tempcalendar, calendarDatabase) {
ui->calendarResourceList->addItem(tempcalendar.name);
m_calendarSourceDatabaseMap.insert(ui->calendarResourceList->count()-1, tempcalendar.source);
}
ui->calendarResourceList->addItem("New Calendar resource");
}
QArrayOfDatabases memoDatabase = m_server->GetDatabases(serverName, "memo");
if (!memoDatabase.isEmpty() && templateConfig.value("source/memo").value("sync") != "disabled") {
m_memoSourceDatabaseMap.clear();
ui->memosToolBar->setEnabled(true);
ui->customMemosURI->setEnabled(true);
ui->customMemosURI->setText(templateConfig.value(QString("source/memo")).value("uri"));
foreach(SyncDatabase tempmemo, memoDatabase) {
ui->memoResourceList->addItem(tempmemo.name);
m_memoSourceDatabaseMap.insert(ui->memoResourceList->count()-1, tempmemo.source);
}
ui->memoResourceList->addItem("New Memo resouce");
}
QArrayOfDatabases tasksDatabase = m_server->GetDatabases(serverName, "todo");
if (!tasksDatabase.isEmpty() && templateConfig.value("source/todo").value("sync") != "disabled") {
m_todoSourceDatabaseMap.clear();
ui->tasksToolBar->setEnabled(true);
ui->customTasksURI->setEnabled(true);
ui->customTasksURI->setText(templateConfig.value(QString("source/todo")).value("uri"));
foreach(SyncDatabase temptodo, tasksDatabase) {
ui->taskResourceList->addItem(temptodo.name);
m_todoSourceDatabaseMap.insert(ui->taskResourceList->count()-1, temptodo.source);
}
ui->taskResourceList->addItem("New Tasks resource");
}
ui->syncURL->setText(templateConfig.value(QString()).value("syncURL"));
}
void Module::addProfile(bool)
{
readConfigFromUI();
if (updateOrAddFlag == addingProfile) {
qDebug() << "New profile";
QDBusObjectPath sessionPath = m_server->StartSession(ui->templateList->currentText());
OrgSyncevolutionSessionInterface *session = new OrgSyncevolutionSessionInterface(staticInterfaceName(), sessionPath.path(), QDBusConnection::sessionBus());
session->SetConfig(false, false, config);
session->Detach();
} else if (updateOrAddFlag == updatingProfile) {
qDebug() << "Updating Profile";
QDBusObjectPath sessionPath = m_server->StartSession(ui->profileName->text());
OrgSyncevolutionSessionInterface *session = new OrgSyncevolutionSessionInterface(staticInterfaceName(), sessionPath.path(), QDBusConnection::sessionBus());
session->SetConfig(true, false, config);
session->Detach();
}
}
void Module::removeProfile(bool)
{
QStringMultiMap emptyConfig;
qDebug() << "WARNING : Removing Config " << ui->listWidget->currentItem()->text() << " " << ui->profileName->text();
KMessageBox::Options options;
options |= KMessageBox::Dangerous;
if (KMessageBox::warningContinueCancel(this,
i18nc("Warning message on attempting to delete a connection", "Do you really want to delete the profile '%1'?", ui->profileName->text()),
i18n("Confirm Delete"),
KStandardGuiItem::del())
== KMessageBox::Continue) {
QDBusObjectPath sessionPath = m_server->StartSession(ui->profileName->text());
OrgSyncevolutionSessionInterface *session = new OrgSyncevolutionSessionInterface(staticInterfaceName(), sessionPath.path(), QDBusConnection::sessionBus());
session->SetConfig(false, false, emptyConfig);
ui->listWidget->setCurrentRow(0);
//TODO: We should ideally have some sort of error handling over here, before we detach and delete the listwidget, consult and implement later on
session->Detach();
}
}
void Module::reloadConfigList()
{
ui->listWidget->clear();
ui->listWidget->addItem(i18n("New Profile"));
ui->listWidget->addItems(m_server->GetConfigs(false));
ui->listWidget->setCurrentRow(0);
}
void Module::showConfig(QListWidgetItem* selectedProfile)
{
if (ui->listWidget->currentRow() == 0) {
ui->addAccountButton->setText(i18n("Add Profile"));
ui->addAccountButton->setIcon(KIcon("list-add"));
ui->templateList->setEnabled(true);
ui->profileName->clear();
ui->usernameInput->clear();
ui->passwordInput->clear();
ui->removeAccountButton->setEnabled(true);
updateOrAddFlag = addingProfile;
setSyncOptions(ui->templateList->currentText());
return;
}
QStringMultiMap readConfig;
readConfig = m_server->GetConfig(selectedProfile->text(), false);
QStringMap configMap;
configMap = readConfig[QString()];
//Hide template list because the template name isn't stored
ui->templateList->setDisabled(true);
ui->addAccountButton->setText(i18n("Update Profile"));
ui->addAccountButton->setIcon(KIcon("configure"));
ui->removeAccountButton->setEnabled(true);
updateOrAddFlag = updatingProfile;
ui->profileName->setText(configMap["configName"]);
ui->usernameInput->setText(configMap["username"]);
ui->passwordInput->setText(configMap["password"]);
ui->syncURL->setUrl(KUrl(configMap["syncURL"]));
foreach(QString key, readConfig.keys()) {
configMap.clear();
configMap = readConfig[key];
if (configMap.value("sync") != "disabled") {
switch (toSourceEnum(key)) {
case addressbook:
ui->checkContacts->setChecked(true);
qDebug() << "Addressbook choosen [from config]" << m_addressSourceDatabaseMap.key(configMap.value("database"));
ui->addressResourceList->setCurrentIndex(m_addressSourceDatabaseMap.key(configMap.value("database")));
ui->contactSyncType->setCurrentIndex(m_syncType->key(configMap.value("sync")));
ui->customAddressbookURI->setText(configMap.value("uri"));
break;
case calendar:
ui->checkCalendar->setChecked(true);
ui->calendarResourceList->setCurrentIndex(m_calendarSourceDatabaseMap.key(configMap.value("database")));
ui->calendarSyncType->setCurrentIndex(m_syncType->key(configMap.value("sync")));
ui->customCalendarURI->setText(configMap.value("uri"));
break;
case todo:
ui->checkTasks->setChecked(true);
ui->taskResourceList->setCurrentIndex(m_todoSourceDatabaseMap.key(configMap.value("database")));
ui->taskSyncType->setCurrentIndex(m_syncType->key(configMap.value("sync")));
ui->customTasksURI->setText(configMap.value("uri"));
break;
case memo:
ui->checkMemos->setChecked(true);
ui->memoResourceList->setCurrentIndex(m_memoSourceDatabaseMap.key(configMap.value("database")));
ui->memoSyncType->setCurrentIndex(m_syncType->key(configMap.value("sync")));
ui->customMemosURI->setText(configMap.value("uri"));
break;
default:
break;
}
}
}
}
void Module::readConfigFromUI()
{
config.clear();
//Initial config from UI
QStringMap tempConfig1;
if (updateOrAddFlag == updatingProfile) {
config = m_server->GetConfig(ui->profileName->text(), false);
tempConfig1 = config.value(QString());
}
tempConfig1.insert("templateName", ui->templateList->currentText());
tempConfig1.insert("configName", ui->profileName->text());
tempConfig1.insert("username", ui->usernameInput->text());
tempConfig1.insert("password", ui->passwordInput->text());
tempConfig1.insert("syncURL", ui->syncURL->text());
tempConfig1.insert("ConsumerReady", "1");
tempConfig1.insert("deviceId", m_devID);
config.insert(QString(), tempConfig1);
if (ui->checkContacts->isChecked()) {
tempConfig1.clear();
if (updateOrAddFlag == updatingProfile) {
tempConfig1 = config.value("source/addressbook");
}
//Insert Config for addressbook
tempConfig1.insert("backend", "addressbook");
qDebug() << "Index: " <<ui->addressResourceList->currentIndex() << " value : " << m_addressSourceDatabaseMap[ui->addressResourceList->currentIndex()];
tempConfig1.insert("database", m_addressSourceDatabaseMap[ui->addressResourceList->currentIndex()]);
tempConfig1.insert("sync", m_syncType->value(ui->contactSyncType->currentIndex()));
tempConfig1.insert("uri", ui->customAddressbookURI->text());
tempConfig1.insert("syncFormat", "text/vcard");
config.insert("source/addressbook", tempConfig1);
}
else{
tempConfig1.clear();
tempConfig1.insert("sync", "disabled");
config.insert("source/addressbook",tempConfig1 );
}
if (ui->checkCalendar->isChecked()) {
tempConfig1.clear();
if (updateOrAddFlag == updatingProfile) {
tempConfig1 = config.value("source/calendar");
}
//Insert Config for Calendars
tempConfig1.insert("backend", "calendar");
tempConfig1.insert("database", m_calendarSourceDatabaseMap[ui->calendarResourceList->currentIndex()]);
tempConfig1.insert("sync", m_syncType->value(ui->calendarSyncType->currentIndex()));
tempConfig1.insert("uri", ui->customCalendarURI->text());
tempConfig1.insert("syncFormat", "text/calendar");
config.insert("source/calendar", tempConfig1);
}
else{
tempConfig1.clear();
tempConfig1.insert("sync", "disabled");
config.insert("source/calendar",tempConfig1 );
}
if (ui->checkMemos->isChecked()) {
tempConfig1.clear();
if (updateOrAddFlag == updatingProfile) {
tempConfig1 = config.value("source/memo");
}
//Insert Config for Memos
tempConfig1.insert("backend", "memo");
tempConfig1.insert("database", m_memoSourceDatabaseMap[ui->memoResourceList->currentIndex()]);
tempConfig1.insert("sync", m_syncType->value(ui->memoSyncType->currentIndex()));
tempConfig1.insert("uri", ui->customMemosURI->text());
// tempConfig1.insert("syncFormat", "text/calendar");
config.insert("source/memo", tempConfig1);
}
else{
tempConfig1.clear();
tempConfig1.insert("sync", "disabled");
config.insert("source/memo",tempConfig1 );
}
if (ui->checkTasks->isChecked()) {
tempConfig1.clear();
if (updateOrAddFlag == updatingProfile) {
tempConfig1 = config.value("source/todo");
}
//Insert Config for todo
tempConfig1.insert("backend", "todo");
tempConfig1.insert("database", m_todoSourceDatabaseMap[ui->taskResourceList->currentIndex()]);
tempConfig1.insert("sync", m_syncType->value(ui->taskSyncType->currentIndex()));
tempConfig1.insert("uri", ui->customTasksURI->text());
// tempConfig1.insert("syncFormat", "text/calendar");
config.insert("source/todo", tempConfig1);
}
else{
tempConfig1.clear();
tempConfig1.insert("sync", "disabled");
config.insert("source/todo",tempConfig1 );
}
}
configValue Module::toSourceEnum(QString key)
{
if (key == "source/addressbook")
return addressbook;
else if (key == "source/calendar")
return calendar;
else if (key == "source/memo")
return memo;
else if (key == "source/todo")
return todo;
else
return error;
}
////
ErrorOverlay::ErrorOverlay(QWidget *baseWidget, const QString &details, QWidget *parent) :
QWidget(parent ? parent : baseWidget->window()),
m_BaseWidget(baseWidget)
{
Q_UNUSED(details);
// Build the UI
QVBoxLayout *layout = new QVBoxLayout;
layout->setSpacing(10);
QLabel *pixmap = new QLabel();
pixmap->setPixmap(KIcon("dialog-error").pixmap(64));
QLabel *message = new QLabel(i18n("Something went terribly wrong and the SyncEvolution backend could not be initialized.\n"
"It is likely your system is missing the SyncEvolution package.\n"
"Please install it and restart this module."));
message->setAlignment(Qt::AlignHCenter);
pixmap->setAlignment(Qt::AlignHCenter);
layout->addStretch();
layout->addWidget(pixmap);
layout->addWidget(message);
layout->addStretch();
setLayout(layout);
// Draw the transparent overlay background
QPalette p = palette();
p.setColor(backgroundRole(), QColor(0, 0, 0, 128));
p.setColor(foregroundRole(), Qt::white);
setPalette(p);
setAutoFillBackground(true);
m_BaseWidget->installEventFilter(this);
reposition();
}
ErrorOverlay::~ErrorOverlay()
{
}
void ErrorOverlay::reposition()
{
if (!m_BaseWidget) {
return;
}
// reparent to the current top level widget of the base widget if needed
// needed eg. in dock widgets
if (parentWidget() != m_BaseWidget->window()) {
setParent(m_BaseWidget->window());
}
// follow base widget visibility
// needed eg. in tab widgets
if (!m_BaseWidget->isVisible()) {
hide();
return;
}
show();
// follow position changes
const QPoint topLevelPos = m_BaseWidget->mapTo(window(), QPoint(0, 0));
const QPoint parentPos = parentWidget()->mapFrom(window(), topLevelPos);
move(parentPos);
// follow size changes
// TODO: hide/scale icon if we don't have enough space
resize(m_BaseWidget->size());
}
bool ErrorOverlay::eventFilter(QObject * object, QEvent * event)
{
if (object == m_BaseWidget &&
(event->type() == QEvent::Move || event->type() == QEvent::Resize ||
event->type() == QEvent::Show || event->type() == QEvent::Hide ||
event->type() == QEvent::ParentChange)) {
reposition();
}
return QWidget::eventFilter(object, event);
}
/*
Copyright © 2011 Rohan Garg <[email protected]>
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) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy
defined in Section 14 of version 3 of the license.
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/>.
*/
#ifndef MODULE_H
#define MODULE_H
#include <QMap>
#include <KCModule>
#include "dbustypes.h"
class QListWidgetItem;
namespace Ui
{
class MainWidget;
}
class OrgSyncevolutionServerInterface;
class OrgSyncevolutionSessionInterface;
enum updateOrAdd {
addingProfile,
updatingProfile
};
enum configValue {
addressbook,
calendar,
memo,
todo,
error
};
class Module : public KCModule
{
Q_OBJECT
public:
/**
* Constructor.
*/
Module(QWidget *parent, const QVariantList &args = QVariantList());
/**
* Destructor.
*/
~Module();
/**
*
* Method to return DBus server path
*/
static inline const char *staticInterfaceName() {
return "org.syncevolution";
}
private:
/**
* UI
*/
Ui::MainWidget *ui;
OrgSyncevolutionServerInterface *m_server;
OrgSyncevolutionSessionInterface *m_session;
QStringMultiMap config;
QMap<int, QString> m_addressSourceDatabaseMap;
QMap<int, QString> m_calendarSourceDatabaseMap;
QMap<int, QString> m_memoSourceDatabaseMap;
QMap<int, QString> m_todoSourceDatabaseMap;
QMap<int, QString> *m_syncType;
QString m_devID;
updateOrAdd updateOrAddFlag;
public:
void readConfigFromUI();
configValue toSourceEnum(QString key);
public slots:
void addProfile(bool);
void removeProfile(bool);
void reloadConfigList();
void showConfig(QListWidgetItem* selectedProfile);
void setSyncOptions(QString);
};
// Helper class for drawing error overlays
class ErrorOverlay : public QWidget
{
Q_OBJECT
public:
explicit ErrorOverlay(QWidget *baseWidget, const QString &details, QWidget *parent = 0);
~ErrorOverlay();
void startSyncEvoDBusServer(Qt::AlignmentFlag AlignHCenter);
protected:
bool eventFilter(QObject *object, QEvent *event);
private:
void reposition();
private:
QWidget *m_BaseWidget;
};
#endif // MODULE_H
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment