Commit bdeb74c3 authored by Dan Vrátil's avatar Dan Vrátil

Move Akonadi resources for Google Contacts and Calendar to kdepim-runtime

REVIEW: 104775
parent efa76044
......@@ -93,6 +93,17 @@ endif(NOT KDEPIM_NO_NEPOMUK)
find_package(Strigi)
macro_log_feature(STRIGI_FOUND "Strigi" "Index metadata of files" "http://strigi.sourceforge.net" FALSE "" "")
set(LIBKGOOGLE_MIN_VERSION 0.3.1)
find_package(LibKGoogle)
macro_log_feature(LIBKGOOGLE_FOUND "LibKGoogle" "A library to access Google services" "http://projects.kde.org/libkgoogle" FALSE "${LIBKGOOGLE_MIN_VERSION}" "LibKGoogle is required to build Akonadi resources to access Google Contacts, Calendars and Tasks" )
if(LIBKGOOGLE_FOUND)
find_package(QJSON)
macro_log_feature(QJSON_FOUND "QJSON" "Qt library for handling JSON data" "http://qjson.sourceforge.net/" TRUE)
endif(LIBKGOOGLE_FOUND)
############### search programs & libraries used by kdepim-runtime ###############
find_program(XSLTPROC_EXECUTABLE xsltproc)
......
......@@ -52,6 +52,10 @@ macro_optional_add_subdirectory( microblog )
macro_optional_add_subdirectory( openxchange )
add_subdirectory( pop3 )
if ( LIBKGOOGLE_FOUND )
add_subdirectory ( google )
endif ( LIBKGOOGLE_FOUND )
if (NOT WINCE)
if ( NEPOMUK_FOUND )
add_subdirectory( nepomuktag )
......
macro_optional_add_subdirectory(calendar)
macro_optional_add_subdirectory(contacts)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
set(calendarresource_SRCS
calendareditor.cpp
calendarresource.cpp
defaultreminderattribute.cpp
resource_tasks.cpp
resource_events.cpp
settings.cpp
settingsdialog.cpp
tasklisteditor.cpp
)
kde4_add_ui_files(calendarresource_SRCS
ui/settingsdialog.ui
ui/calendar_editor.ui
ui/tasklist_editor.ui)
kde4_add_kcfg_files(calendarresource_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/settingsbase.kcfgc)
kcfg_generate_dbus_interface(${CMAKE_CURRENT_SOURCE_DIR}/settingsbase.kcfg org.kde.Akonadi.GoogleCalendar.Settings)
qt4_add_dbus_adaptor(calendarresource_SRCS
${CMAKE_CURRENT_BINARY_DIR}/org.kde.Akonadi.GoogleCalendar.Settings.xml
${CMAKE_CURRENT_SOURCE_DIR}/settings.h Settings)
kde4_add_executable(akonadi_googlecalendar_resource RUN_UNINSTALLED ${calendarresource_SRCS})
target_link_libraries(akonadi_googlecalendar_resource
${KDEPIMLIBS_AKONADI_LIBS}
${KDEPIMLIBS_KCAL_LIBS}
${KDEPIMLIBS_KCALCORE_LIBS}
${KDEPIMLIBS_KMIME_LIBS}
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${QT_QTDBUS_LIBRARY}
${QT_QTNETWORK_LIBRARY}
${KDE4_KDECORE_LIBS}
${KDE4_KDEWEBKIT_LIBS}
${QJSON_LIBRARIES}
${LIBKGOOGLE_LIBRARY}
)
install(TARGETS akonadi_googlecalendar_resource ${INSTALL_TARGETS_DEFAULT_ARGS})
install(FILES googlecalendarresource.desktop DESTINATION "${CMAKE_INSTALL_PREFIX}/share/akonadi/agents" )
/*
Copyright (C) 2011, 2012 Dan Vratil <dan@progdan.cz>
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 3 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/>.
*/
#include "calendareditor.h"
#include "ui_calendar_editor.h"
#include <libkgoogle/services/calendar.h>
#include <QtCore/QFile>
#include <KStandardDirs>
#include <KSystemTimeZone>
using namespace KGoogle::Objects;
CalendarEditor::CalendarEditor( Calendar *calendar ) :
QDialog(),
m_calendar( calendar )
{
m_ui = new Ui::CalendarEditor();
m_ui->setupUi( this );
initTimezones();
if ( calendar ) {
initWidgets();
} else {
int i = m_ui->timezoneCombo->findText( KSystemTimeZones::local().name(), Qt::MatchContains );
if ( i > -1 ) {
m_ui->timezoneCombo->setCurrentIndex( i );
}
}
connect( m_ui->buttons, SIGNAL( accepted() ),
this, SLOT( accepted() ) );
}
CalendarEditor::~CalendarEditor()
{
delete m_ui;
}
void CalendarEditor::accepted()
{
if ( !m_calendar ) {
m_calendar = new KGoogle::Objects::Calendar();
}
m_calendar->setTitle( m_ui->nameEdit->text() );
m_calendar->setDetails( m_ui->descriptionEdit->toPlainText() );
m_calendar->setLocation( m_ui->locationEdit->text() );
m_calendar->setTimezone( m_ui->timezoneCombo->currentText() );
Q_EMIT accepted( m_calendar );
}
void CalendarEditor::initTimezones()
{
Q_FOREACH ( const KTimeZone tz, KSystemTimeZones::zones() ) {
QIcon icon;
QString flag = KStandardDirs::locate( "locale", QString( "l10n/%1/flag.png" ).arg( tz.countryCode().toLower() ) );
if ( QFile::exists( flag ) ) {
icon = QIcon( flag );
}
m_ui->timezoneCombo->addItem( icon, tz.name() );
}
}
void CalendarEditor::initWidgets()
{
m_ui->nameEdit->setText( m_calendar->title() );
m_ui->descriptionEdit->setText( m_calendar->details() );
m_ui->locationEdit->setText( m_calendar->location() );
int tzIndex = m_ui->timezoneCombo->findText( m_calendar->timezone(), Qt::MatchContains );
if ( tzIndex > -1 ) {
m_ui->timezoneCombo->setCurrentIndex( tzIndex );
}
}
/*
Copyright (C) 2011, 2012 Dan Vratil <dan@progdan.cz>
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 3 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/>.
*/
#ifndef CALENDAREDITOR_H
#define CALENDAREDITOR_H
#include <QtGui/QDialog>
#include <libkgoogle/objects/calendar.h>
namespace Ui {
class CalendarEditor;
}
using namespace KGoogle::Objects;
class CalendarEditor: public QDialog
{
Q_OBJECT
public:
explicit CalendarEditor( Calendar *calendar = 0 );
virtual ~CalendarEditor();
Q_SIGNALS:
void accepted( KGoogle::Objects::Calendar *calendar );
private Q_SLOTS:
void accepted();
private:
void initTimezones();
void initColors();
void initWidgets();
Calendar *m_calendar;
Ui::CalendarEditor *m_ui;
};
#endif /* CALENDAREDITOR_H */
/*
Copyright (C) 2011, 2012 Dan Vratil <dan@progdan.cz>
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 3 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/>.
*/
#include "calendarresource.h"
#include "defaultreminderattribute.h"
#include "settings.h"
#include "settingsdialog.h"
#include <libkgoogle/common.h>
#include <libkgoogle/account.h>
#include <libkgoogle/accessmanager.h>
#include <libkgoogle/auth.h>
#include <libkgoogle/fetchlistjob.h>
#include <libkgoogle/request.h>
#include <libkgoogle/reply.h>
#include <libkgoogle/objects/calendar.h>
#include <libkgoogle/objects/event.h>
#include <libkgoogle/objects/task.h>
#include <libkgoogle/objects/tasklist.h>
#include <libkgoogle/services/calendar.h>
#include <libkgoogle/services/tasks.h>
#include <QtCore/QStringList>
#include <QtCore/QMetaType>
#include <KLocalizedString>
#include <KDialog>
#include <Akonadi/Attribute>
#include <Akonadi/AttributeFactory>
#include <Akonadi/CachePolicy>
#include <Akonadi/ChangeRecorder>
#include <Akonadi/CollectionFetchScope>
#include <Akonadi/EntityDisplayAttribute>
#include <Akonadi/ItemFetchJob>
#include <Akonadi/ItemFetchScope>
#include <KCalCore/Calendar>
using namespace KCalCore;
using namespace Akonadi;
using namespace KGoogle;
CalendarResource::CalendarResource( const QString &id ):
ResourceBase( id ),
m_account( 0 ),
m_fetchedCalendars( false ),
m_fetchedTaskLists( false )
{
qRegisterMetaType< KGoogle::Services::Calendar >( "Calendar" );
qRegisterMetaType< KGoogle::Services::Tasks >( "Tasks" );
AttributeFactory::registerAttribute< DefaultReminderAttribute >();
Auth *auth = Auth::instance();
auth->init( "Akonadi Google", Settings::self()->clientId(), Settings::self()->clientSecret() );
setNeedsNetwork( true );
setOnline( true );
m_gam = new AccessManager();
connect( m_gam, SIGNAL( error( KGoogle::Error, QString ) ),
this, SLOT( error( KGoogle::Error, QString ) ) );
connect( m_gam, SIGNAL( replyReceived( KGoogle::Reply * ) ),
this, SLOT( replyReceived( KGoogle::Reply * ) ) );
connect( this, SIGNAL( abortRequested() ),
this, SLOT( slotAbortRequested() ) );
connect( this, SIGNAL( reloadConfiguration() ),
this, SLOT( reloadConfig() ) );
changeRecorder()->itemFetchScope().fetchFullPayload( true );
changeRecorder()->itemFetchScope().setAncestorRetrieval( ItemFetchScope::All );
changeRecorder()->fetchCollection( true );
changeRecorder()->collectionFetchScope().setAncestorRetrieval( CollectionFetchScope::All );
if ( !Settings::self()->account().isEmpty() ) {
if ( !getAccount().isNull() ) {
synchronize();
}
}
}
CalendarResource::~CalendarResource()
{
delete m_gam;
}
void CalendarResource::aboutToQuit()
{
slotAbortRequested();
}
void CalendarResource::abort()
{
cancelTask( i18n( "Aborted" ) );
}
void CalendarResource::slotAbortRequested()
{
abort();
}
void CalendarResource::error( const KGoogle::Error errCode, const QString &msg )
{
cancelTask( msg );
if ( ( errCode == AuthError ) || ( errCode == BackendNotReady ) ) {
status( Broken, msg );
}
}
void CalendarResource::configure( WId windowId )
{
SettingsDialog *settingsDialog = new SettingsDialog( windowId );
if ( settingsDialog->exec() == KDialog::Accepted ) {
Q_EMIT configurationDialogAccepted();
delete settingsDialog;
if( !getAccount().isNull() ) {
synchronize();
}
} else {
Q_EMIT configurationDialogRejected();
delete settingsDialog;
}
}
void CalendarResource::reloadConfig()
{
if ( getAccount().isNull() ) {
return;
}
synchronize();
}
Account::Ptr CalendarResource::getAccount()
{
if ( !m_account.isNull() )
return m_account;
Auth *auth = Auth::instance();
try {
m_account = auth->getAccount( Settings::self()->account() );
} catch( KGoogle::Exception::BaseException &e ) {
Q_EMIT status( Broken, e.what() );
return Account::Ptr();
}
return m_account;
}
void CalendarResource::retrieveItems( const Akonadi::Collection &collection )
{
/* Do not initiate item-retrieval for the root collection as this
* collection is only used to authenticate agains google and to hold
* all the calendars associated with this account. There are no items
* to be fetched from this collection! */
if ( collection.parentCollection() != Akonadi::Collection::root() ) {
ItemFetchJob *fetchJob = new ItemFetchJob( collection, this );
connect( fetchJob, SIGNAL( finished( KJob * ) ),
this, SLOT( cachedItemsRetrieved( KJob * ) ) );
connect( fetchJob, SIGNAL( finished( KJob * ) ),
fetchJob, SLOT( deleteLater() ) );
fetchJob->fetchScope().fetchFullPayload( false );
fetchJob->setProperty( "collection", qVariantFromValue( collection ) );
fetchJob->start();
Q_EMIT percent( 0 );
} else {
itemsRetrievalDone();
}
}
void CalendarResource::cachedItemsRetrieved( KJob *job )
{
QUrl url;
QString service;
QString lastSync;
Collection collection = job->property( "collection" ).value<Collection>();
if ( collection.contentMimeTypes().contains( Event::eventMimeType() ) ) {
service = "Calendar";
url = Services::Calendar::fetchEventsUrl( collection.remoteId() );
} else if ( collection.contentMimeTypes().contains( Todo::todoMimeType() ) ) {
service = "Tasks";
url = Services::Tasks::fetchAllTasksUrl( collection.remoteId() );
} else {
Q_EMIT cancelTask( i18n( "Invalid collection" ) );
return;
}
lastSync = collection.remoteRevision();
if ( !lastSync.isEmpty() ) {
KDateTime dt;
dt.setTime_t( lastSync.toInt() );
lastSync = AccessManager::dateToRFC3339String( dt );
url.addQueryItem( "updatedMin", lastSync );
}
url.addQueryItem( "showDeleted", "true" );
Account::Ptr account = getAccount();
if ( account.isNull() ) {
deferTask();
return;
}
FetchListJob *fetchJob = new FetchListJob( url, service, account->accountName() );
fetchJob->setProperty( "collection", qVariantFromValue( collection ) );
connect( fetchJob, SIGNAL( finished( KJob * ) ),
this, SLOT( itemsReceived( KJob * ) ) );
connect( fetchJob, SIGNAL( percent( KJob *, ulong ) ),
this, SLOT( emitPercent( KJob *, ulong ) ) );
fetchJob->start();
}
bool CalendarResource::retrieveItem( const Akonadi::Item &item, const QSet< QByteArray >& parts )
{
Q_UNUSED( parts );
QString service;
QUrl url;
if ( item.parentCollection().contentMimeTypes().contains( Event::eventMimeType() ) ) {
service = "Calendar";
url = Services::Calendar::fetchEventUrl( item.parentCollection().remoteId(), item.remoteId() );
} else if ( item.parentCollection().contentMimeTypes().contains( Todo::todoMimeType() ) ) {
service = "Tasks";
url = Services::Tasks::fetchTaskUrl( item.parentCollection().remoteId(), item.remoteId() );
}
Account::Ptr account = getAccount();
if ( account.isNull() ) {
deferTask();
return true;
}
Request *request = new Request( url, KGoogle::Request::Fetch, service, account );
request->setProperty( "Item", QVariant::fromValue( item ) );
m_gam->sendRequest( request );
return true;
}
void CalendarResource::retrieveCollections()
{
Account::Ptr account = getAccount();
if ( account.isNull() ) {
deferTask();
return;
}
Akonadi::EntityDisplayAttribute *attr = new Akonadi::EntityDisplayAttribute();
attr->setDisplayName( account->accountName() );
Collection collection;
collection.setName( identifier() );
collection.setRemoteId( identifier() );
collection.setParentCollection( Akonadi::Collection::root() );
collection.setContentMimeTypes( QStringList() << Collection::mimeType()
<< Event::eventMimeType()
<< Todo::todoMimeType() );
collection.addAttribute( attr );
collection.setRights( Collection::ReadOnly );
m_collections.clear();
m_collections.append( collection );
FetchListJob *fetchJob;
fetchJob = new FetchListJob( Services::Calendar::fetchCalendarsUrl(), "Calendar", account->accountName() );
connect( fetchJob, SIGNAL( finished( KJob * ) ),
this, SLOT( calendarsReceived( KJob * ) ) );
fetchJob->start();
fetchJob = new FetchListJob( Services::Tasks::fetchTaskListsUrl(), "Tasks", account->accountName() );
connect( fetchJob, SIGNAL( finished( KJob * ) ),
this, SLOT( taskListReceived( KJob * ) ) );
fetchJob->start();
}
void CalendarResource::itemAdded( const Akonadi::Item &item, const Akonadi::Collection &collection )
{
QString service;
QUrl url;
QByteArray data;
if ( collection.parentCollection() == Akonadi::Collection::root() ) {
cancelTask( i18n( "The top-level collection cannot contain any tasks or events" ) );
return;
}
Account::Ptr account = getAccount();
if ( account.isNull() ) {
deferTask();
return;
}
if ( item.mimeType() == Event::eventMimeType() ) {
Event::Ptr event = item.payload< Event::Ptr >();
Objects::Event kevent( *event );
service = "Calendar";
url = Services::Calendar::createEventUrl( collection.remoteId() );
Services::Calendar service;
kevent.setUid( "" );
data = service.objectToJSON( static_cast< KGoogle::Object * >( &kevent ) );
} else if ( item.mimeType() == Todo::todoMimeType() ) {
Todo::Ptr todo = item.payload< Todo::Ptr >();
todo->setUid( "" );
Objects::Task ktodo( *todo );
service = "Tasks";
url = Services::Tasks::createTaskUrl( collection.remoteId() );
if ( !todo->relatedTo( Incidence::RelTypeParent ).isEmpty() )
url.addQueryItem( "parent", todo->relatedTo( Incidence::RelTypeParent ) );
Services::Tasks service;
data = service.objectToJSON( static_cast< KGoogle::Object * >( &ktodo ) );
} else {
cancelTask( i18n( "Unknown payload type '%1'" ).arg( item.mimeType() ) );