1/*
2 This file is part of the kcal library.
3
4 Copyright (c) 2002,2006,2010 David Jarvie <djarvie@kde.org>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21/**
22 @file
23 This file is part of the API for handling calendar data and
24 defines the CustomProperties class.
25
26 @brief
27 A class to manage custom calendar properties.
28
29 @author David Jarvie \<djarvie@kde.org\>
30*/
31
32#include "customproperties.h"
33#include <kdebug.h>
34#include <QtCore/QByteArray>
35
36using namespace KCal;
37
38//@cond PRIVATE
39static bool checkName( const QByteArray &name );
40
41class CustomProperties::Private
42{
43 public:
44 bool operator==( const Private &other ) const;
45 QMap<QByteArray, QString> mProperties; // custom calendar properties
46};
47
48bool CustomProperties::Private::operator==( const CustomProperties::Private &other ) const
49{
50 if ( mProperties.count() != other.mProperties.count() ) {
51 return false;
52 }
53 for ( QMap<QByteArray, QString>::ConstIterator it = mProperties.begin();
54 it != mProperties.end(); ++it ) {
55 QMap<QByteArray, QString>::ConstIterator itOther =
56 other.mProperties.find( it.key() );
57 if ( itOther == other.mProperties.end() || itOther.value() != it.value() ) {
58 return false;
59 }
60 }
61 return true;
62}
63//@endcond
64
65CustomProperties::CustomProperties()
66 : d( new Private )
67{
68}
69
70CustomProperties::CustomProperties( const CustomProperties &cp )
71 : d( new Private( *cp.d ) )
72{
73}
74
75CustomProperties &CustomProperties::operator=( const CustomProperties &other )
76{
77 // check for self assignment
78 if ( &other == this ) {
79 return *this;
80 }
81
82 *d = *other.d;
83 return *this;
84}
85
86CustomProperties::~CustomProperties()
87{
88 delete d;
89}
90
91bool CustomProperties::operator==( const CustomProperties &other ) const
92{
93 return *d == *other.d;
94}
95
96void CustomProperties::setCustomProperty( const QByteArray &app, const QByteArray &key,
97 const QString &value )
98{
99 if ( value.isNull() || key.isEmpty() || app.isEmpty() ) {
100 return;
101 }
102 QByteArray property = "X-KDE-" + app + '-' + key;
103 if ( !checkName( property ) ) {
104 return;
105 }
106 d->mProperties[property] = value;
107 customPropertyUpdated();
108}
109
110void CustomProperties::removeCustomProperty( const QByteArray &app, const QByteArray &key )
111{
112 removeNonKDECustomProperty( QByteArray( "X-KDE-" + app + '-' + key ) );
113}
114
115QString CustomProperties::customProperty( const QByteArray &app, const QByteArray &key ) const
116{
117 return nonKDECustomProperty( QByteArray( "X-KDE-" + app + '-' + key ) );
118}
119
120QByteArray CustomProperties::customPropertyName( const QByteArray &app, const QByteArray &key )
121{
122 QByteArray property( "X-KDE-" + app + '-' + key );
123 if ( !checkName( property ) ) {
124 return QByteArray();
125 }
126 return property;
127}
128
129void CustomProperties::setNonKDECustomProperty( const QByteArray &name, const QString &value )
130{
131 if ( value.isNull() || !checkName( name ) ) {
132 return;
133 }
134 d->mProperties[name] = value;
135 customPropertyUpdated();
136}
137
138void CustomProperties::removeNonKDECustomProperty( const QByteArray &name )
139{
140 if ( d->mProperties.remove( name ) ) {
141 customPropertyUpdated();
142 }
143}
144
145QString CustomProperties::nonKDECustomProperty( const QByteArray &name ) const
146{
147 return d->mProperties.value( name );
148}
149
150void CustomProperties::setCustomProperties( const QMap<QByteArray, QString> &properties )
151{
152 bool changed = false;
153 for ( QMap<QByteArray, QString>::ConstIterator it = properties.begin();
154 it != properties.end(); ++it ) {
155 // Validate the property name and convert any null string to empty string
156 if ( checkName( it.key() ) ) {
157 d->mProperties[it.key()] = it.value().isNull() ? QString( "" ) : it.value();
158 changed = true;
159 }
160 }
161 if ( changed ) {
162 customPropertyUpdated();
163 }
164}
165
166QMap<QByteArray, QString> CustomProperties::customProperties() const
167{
168 return d->mProperties;
169}
170
171//@cond PRIVATE
172bool checkName( const QByteArray &name )
173{
174 // Check that the property name starts with 'X-' and contains
175 // only the permitted characters
176 const char *n = name;
177 int len = name.length();
178 if ( len < 2 || n[0] != 'X' || n[1] != '-' ) {
179 return false;
180 }
181 for ( int i = 2; i < len; ++i ) {
182 char ch = n[i];
183 if ( ( ch >= 'A' && ch <= 'Z' ) ||
184 ( ch >= 'a' && ch <= 'z' ) ||
185 ( ch >= '0' && ch <= '9' ) ||
186 ch == '-' ) {
187 continue;
188 }
189 return false; // invalid character found
190 }
191 return true;
192}
193//@endcond
194