Commit d7152869 authored by Tobias Koenig's avatar Tobias Koenig

Bring back a new version of custom fields for contacts

BUG: 222678

svn path=/trunk/KDE/kdepimlibs/; revision=1101153
parent 00bac754
......@@ -25,6 +25,10 @@ set(akonadicontact_editor_SRCS
editor/addresseditwidget.cpp
editor/categorieseditwidget.cpp
editor/contacteditorwidget.cpp
editor/customfieldeditordialog.cpp
editor/customfieldsdelegate.cpp
editor/customfieldseditwidget.cpp
editor/customfieldsmodel.cpp
editor/dateeditwidget.cpp
editor/displaynameeditwidget.cpp
editor/emaileditwidget.cpp
......@@ -68,6 +72,8 @@ set(akonadicontact_LIB_SRC
contactsearchjob.cpp
contactviewer.cpp
contactviewerdialog.cpp
customfields.cpp
customfieldmanager.cpp
recentcontactscollections.cpp
recentcontactscollectionrequestjob.cpp
waitingoverlay.cpp
......
......@@ -36,6 +36,7 @@ class ContactMetaData::Private
}
int mDisplayNameMode;
QVariantList mCustomFieldDescriptions;
};
ContactMetaData::ContactMetaData()
......@@ -60,6 +61,8 @@ void ContactMetaData::load( const Akonadi::Item &contact )
d->mDisplayNameMode = metaData.value( QLatin1String( "DisplayNameMode" ) ).toInt();
else
d->mDisplayNameMode = -1;
d->mCustomFieldDescriptions = metaData.value( QLatin1String( "CustomFieldDescriptions" ) ).toList();
}
void ContactMetaData::store( Akonadi::Item &contact )
......@@ -70,6 +73,9 @@ void ContactMetaData::store( Akonadi::Item &contact )
if ( d->mDisplayNameMode != -1 )
metaData.insert( QLatin1String( "DisplayNameMode" ), QVariant( d->mDisplayNameMode ) );
if ( !d->mCustomFieldDescriptions.isEmpty() )
metaData.insert( QLatin1String( "CustomFieldDescriptions" ), d->mCustomFieldDescriptions );
attribute->setMetaData( metaData );
}
......@@ -82,3 +88,13 @@ int ContactMetaData::displayNameMode() const
{
return d->mDisplayNameMode;
}
void ContactMetaData::setCustomFieldDescriptions( const QVariantList &descriptions )
{
d->mCustomFieldDescriptions = descriptions;
}
QVariantList ContactMetaData::customFieldDescriptions() const
{
return d->mCustomFieldDescriptions;
}
......@@ -23,6 +23,7 @@
#define AKONADI_CONTACTMETADATA_P_H
#include <QtCore/QStringList>
#include <QtCore/QVariant>
namespace Akonadi
{
......@@ -67,6 +68,29 @@ class ContactMetaData
*/
int displayNameMode() const;
/**
* Sets the @p descriptions of the custom fields of that contact.
*
* The description list contains a QVariantMap for each custom field
* with the following keys:
* - key (string) The identifier of the field
* - title (string) The i18n'ed title of the field
* - type (string) The type description of the field
* Possible values for type description are
* - text
* - numeric
* - boolean
* - date
* - time
* - datetime
*/
void setCustomFieldDescriptions( const QVariantList &descriptions );
/**
* Returns the descriptions of the custom fields of the contact.
*/
QVariantList customFieldDescriptions() const;
private:
//@cond PRIVATE
Q_DISABLE_COPY( ContactMetaData )
......
......@@ -21,6 +21,9 @@
#include "contactviewer.h"
#include "contactmetadata_p.h"
#include "contactmetadataattribute_p.h"
#include "customfieldmanager_p.h"
#include "textbrowser_p.h"
#include <akonadi/item.h>
......@@ -36,7 +39,7 @@
using namespace Akonadi;
static QString contactAsHtml( const KABC::Addressee &contact );
static QString contactAsHtml( const KABC::Addressee &contact, const QVariantList &customFieldDescriptions );
class ContactViewer::Private
{
......@@ -103,6 +106,7 @@ ContactViewer::ContactViewer( QWidget *parent )
// always fetch full payload for contacts
fetchScope().fetchFullPayload();
fetchScope().fetchAttribute<ContactMetaDataAttribute>();
}
ContactViewer::~ContactViewer()
......@@ -141,7 +145,23 @@ void ContactViewer::itemChanged( const Item &contactItem )
defaultPixmap );
}
d->mBrowser->setHtml( contactAsHtml( d->mCurrentContact ) );
// merge the local...
ContactMetaData metaData;
metaData.load( contactItem );
QVariantList customFieldDescriptions = metaData.customFieldDescriptions();
// ... and global custom field descriptions
const CustomField::List globalCustomFields = CustomFieldManager::globalCustomFieldDescriptions();
foreach ( const CustomField &field, globalCustomFields ) {
QVariantMap description;
description.insert( QLatin1String( "key" ), field.key() );
description.insert( QLatin1String( "title" ), field.title() );
customFieldDescriptions << description;
}
d->mBrowser->setHtml( contactAsHtml( d->mCurrentContact, customFieldDescriptions ) );
}
void ContactViewer::itemRemoved()
......@@ -149,7 +169,7 @@ void ContactViewer::itemRemoved()
d->mBrowser->clear();
}
static QString contactAsHtml( const KABC::Addressee &contact )
static QString contactAsHtml( const KABC::Addressee &contact, const QVariantList &customFieldDescriptions )
{
// We'll be building a table to display the vCard in.
// Each row of the table will be built using this string for its HTML.
......@@ -282,9 +302,20 @@ static QString contactAsHtml( const KABC::Addressee &contact )
if ( blacklistedKeys.contains( key ) )
continue;
// check whether we have a mapping for the title
const QMap<QString, QString>::ConstIterator keyIt = titleMap.constFind( key );
if ( keyIt != titleMap.constEnd() )
if ( keyIt != titleMap.constEnd() ) {
key = keyIt.value();
} else {
// check whether it is a custom local field
foreach ( const QVariant &description, customFieldDescriptions ) {
const QVariantMap field = description.toMap();
if ( field.value( QLatin1String( "key" ) ).toString() == key ) {
key = field.value( QLatin1String( "title" ) ).toString();
break;
}
}
}
customData += rowFmtStr.arg( key ).arg( value ) ;
}
......
/*
This file is part of Akonadi Contact.
Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
This library 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 of the License, or (at your
option) any later version.
This library 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 Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "customfieldmanager_p.h"
#include <kconfig.h>
#include <kconfiggroup.h>
void CustomFieldManager::setGlobalCustomFieldDescriptions( const CustomField::List &customFields )
{
KConfig config( QLatin1String( "akonadi_contactrc" ) );
KConfigGroup group( &config, QLatin1String( "GlobalCustomFields" ) );
group.deleteGroup();
foreach ( const CustomField &field, customFields ) {
const QString key = field.key();
const QString value = CustomField::typeToString( field.type() ) + QLatin1Char( ':' ) + field.title();
group.writeEntry( key, value );
}
}
CustomField::List CustomFieldManager::globalCustomFieldDescriptions()
{
KConfig config( QLatin1String( "akonadi_contactrc" ) );
const KConfigGroup group( &config, QLatin1String( "GlobalCustomFields" ) );
CustomField::List customFields;
const QStringList keys = group.keyList();
foreach ( const QString &key, keys ) {
CustomField field;
field.setKey( key );
field.setScope( CustomField::GlobalScope );
const QString value = group.readEntry( key, QString() );
const int pos = value.indexOf( QLatin1Char( ':' ) );
if ( pos != -1 ) {
field.setType( CustomField::stringToType( value.left( pos - 1 ) ) );
field.setTitle( value.mid( pos + 1 ) );
}
customFields << field;
}
return customFields;
}
/*
This file is part of Akonadi Contact.
Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
This library 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 of the License, or (at your
option) any later version.
This library 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 Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef CUSTOMFIELDMANAGER_P_H
#define CUSTOMFIELDMANAGER_P_H
#include "customfields_p.h"
/**
* @short A class that manages the descriptions of all custom fields with global scope.
*/
class CustomFieldManager
{
public:
static void setGlobalCustomFieldDescriptions( const CustomField::List &customFields );
static CustomField::List globalCustomFieldDescriptions();
};
#endif
/*
This file is part of Akonadi Contact.
Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
This library 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 of the License, or (at your
option) any later version.
This library 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 Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#include "customfields_p.h"
CustomField::CustomField()
: mType( TextType ), mScope( LocalScope )
{
}
CustomField::CustomField( const QString &key, const QString &title, Type type, Scope scope )
: mKey( key ), mTitle( title ), mType( type ), mScope( scope )
{
}
CustomField CustomField::fromVariantMap( const QVariantMap &map, Scope scope )
{
return CustomField( map.value( QLatin1String( "key" ) ).toString(),
map.value( QLatin1String( "title" ) ).toString(),
stringToType( map.value( QLatin1String( "type" ) ).toString() ),
scope );
}
void CustomField::setKey( const QString &key )
{
mKey = key;
}
QString CustomField::key() const
{
return mKey;
}
void CustomField::setTitle( const QString &title )
{
mTitle = title;
}
QString CustomField::title() const
{
return mTitle;
}
void CustomField::setType( Type type )
{
mType = type;
}
CustomField::Type CustomField::type() const
{
return mType;
}
void CustomField::setScope( Scope scope )
{
mScope = scope;
}
CustomField::Scope CustomField::scope() const
{
return mScope;
}
void CustomField::setValue( const QString &value )
{
mValue = value;
}
QString CustomField::value() const
{
return mValue;
}
QVariantMap CustomField::toVariantMap() const
{
QVariantMap map;
map.insert( QLatin1String( "key" ), mKey );
map.insert( QLatin1String( "title" ), mTitle );
map.insert( QLatin1String( "type" ), typeToString( mType ) );
return map;
}
CustomField::Type CustomField::stringToType( const QString &type )
{
if ( type == QLatin1String( "text" ) )
return CustomField::TextType;
if ( type == QLatin1String( "numeric" ) )
return CustomField::NumericType;
if ( type == QLatin1String( "boolean" ) )
return CustomField::BooleanType;
if ( type == QLatin1String( "date" ) )
return CustomField::DateType;
if ( type == QLatin1String( "time" ) )
return CustomField::TimeType;
if ( type == QLatin1String( "datetime" ) )
return CustomField::DateTimeType;
return CustomField::TextType;
}
QString CustomField::typeToString( CustomField::Type type )
{
switch ( type ) {
case CustomField::TextType:
default:
return QLatin1String( "text" );
break;
case CustomField::NumericType:
return QLatin1String( "numeric" );
break;
case CustomField::BooleanType:
return QLatin1String( "boolean" );
break;
case CustomField::DateType:
return QLatin1String( "date" );
break;
case CustomField::TimeType:
return QLatin1String( "time" );
break;
case CustomField::DateTimeType:
return QLatin1String( "datetime" );
break;
}
}
/*
This file is part of Akonadi Contact.
Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
This library 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 of the License, or (at your
option) any later version.
This library 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 Library General Public
License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
*/
#ifndef CUSTOMFIELDS_P_H
#define CUSTOMFIELDS_P_H
#include <QtCore/QList>
#include <QtCore/QString>
#include <QtCore/QVariant>
/**
* @short A class that represents non-standard contact fields.
*
* There exists three scopes of fields. To the local scope belong all
* custom fields that are defined by the user and that exists only for one
* contact. The description for these fields are stored inside ContactMetaData
* as custom attribute of the Akonadi item that represents the contact.
* To the global scope belong all custom fields that are defined by the user but
* shall be available in all contacts of the address book. Their description
* is stored by CustomFieldManager in $HOME/.kde/share/config/akonadi_contactrc.
* All other custom fields belong to the external scope, they come with import
* of contacts from other PIM applications (e.g. further X- entries in vCards).
* Their description is created on the fly when editing the custom fields.
*
* The description of a custom field covers the key, title and type.
*/
class CustomField
{
public:
typedef QList<CustomField> List;
enum Type
{
TextType,
NumericType,
BooleanType,
DateType,
TimeType,
DateTimeType
};
enum Scope
{
LocalScope, ///< Field has been defined by user for one contact
GlobalScope, ///< Field has been defined by user for all contacts
ExternalScope ///< Field has been defined by the external data source (e.g. vCard)
};
CustomField();
CustomField( const QString &key, const QString &title, Type type, Scope scope );
static CustomField fromVariantMap( const QVariantMap &map, Scope scope );
void setKey( const QString &key );
QString key() const;
void setTitle( const QString &title );
QString title() const;
void setType( Type type );
Type type() const;
void setScope( Scope scope );
Scope scope() const;
void setValue( const QString &value );
QString value() const;
QVariantMap toVariantMap() const;
static QString typeToString( Type type );
static Type stringToType( const QString &type );
private:
QString mKey;
QString mTitle;
Type mType;
Scope mScope;
QString mValue;
};
#endif
......@@ -25,6 +25,7 @@
#include "categorieseditwidget.h"
#include "contacteditorpageplugin.h"
#include "contactmetadata_p.h"
#include "customfieldseditwidget.h"
#include "dateeditwidget.h"
#include "displaynameeditwidget.h"
#include "emaileditwidget.h"
......@@ -64,6 +65,7 @@ class ContactEditorWidget::Private
void initGuiLocationTab();
void initGuiBusinessTab();
void initGuiPersonalTab();
void initGuiCustomFieldsTab();
void loadCustomPages();
......@@ -120,6 +122,9 @@ class ContactEditorWidget::Private
// widgets from family group
KLineEdit *mPartnerWidget;
// widgets from custom fields group
CustomFieldsEditWidget *mCustomFieldsWidget;
// custom editor pages
QList<Akonadi::ContactEditorPagePlugin*> mCustomPages;
};
......@@ -136,6 +141,7 @@ void ContactEditorWidget::Private::initGui()
initGuiLocationTab();
initGuiBusinessTab();
initGuiPersonalTab();
initGuiCustomFieldsTab();
loadCustomPages();
}
......@@ -432,6 +438,17 @@ void ContactEditorWidget::Private::initGuiPersonalTab()
familyLayout->setRowStretch( 1, 1 );
}
void ContactEditorWidget::Private::initGuiCustomFieldsTab()
{
QWidget *widget = new QWidget;
QVBoxLayout *layout = new QVBoxLayout( widget );
mTabWidget->addTab( widget, i18n( "Custom Fields" ) );
mCustomFieldsWidget = new CustomFieldsEditWidget;
layout->addWidget( mCustomFieldsWidget );
}
void ContactEditorWidget::Private::loadCustomPages()
{
qDeleteAll( mCustomPages );
......@@ -537,6 +554,10 @@ void ContactEditorWidget::loadContact( const KABC::Addressee &contact, const Ako
d->mDisplayNameWidget->setDisplayType( (DisplayNameEditWidget::DisplayType)metaData.displayNameMode() );
// custom fields group
d->mCustomFieldsWidget->setLocalCustomFieldDescriptions( metaData.customFieldDescriptions() );
d->mCustomFieldsWidget->loadContact( contact );
// custom pages
foreach ( Akonadi::ContactEditorPagePlugin *plugin, d->mCustomPages )
plugin->loadContact( contact );
......@@ -592,6 +613,10 @@ void ContactEditorWidget::storeContact( KABC::Addressee &contact, Akonadi::Conta
// family group
d->storeCustom( contact, QLatin1String( "X-SpousesName" ), d->mPartnerWidget->text().trimmed() );
// custom fields group
d->mCustomFieldsWidget->storeContact( contact );
metaData.setCustomFieldDescriptions( d->mCustomFieldsWidget->localCustomFieldDescriptions() );
metaData.setDisplayNameMode( d->mDisplayNameWidget->displayType() );
// custom pages
......@@ -649,6 +674,9 @@ void ContactEditorWidget::setReadOnly( bool readOnly )
// widgets from family group
d->mPartnerWidget->setReadOnly( readOnly );
// widgets from custom fields group
d->mCustomFieldsWidget->setReadOnly( readOnly );
// custom pages
foreach ( Akonadi::ContactEditorPagePlugin *plugin, d->mCustomPages )
plugin->setReadOnly( readOnly );
......
/*
This file is part of Akonadi Contact.
Copyright (c) 2010 Tobias Koenig <tokoe@kde.org>
This library 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 of the License, or (at your
option) any later version.
This library is distributed in the hope that it will be useful, but WITHOUT