Skip to content
This repository has been archived by the owner on Nov 11, 2021. It is now read-only.

Commit

Permalink
Add support for volatile properties, needed to fix a few bugs.
Browse files Browse the repository at this point in the history
volatile properties are CustomProperties that are only used in
runtime, they will not be written back to ical as they are not
part of the Incidence payload.

Volatile properties start with X-KDE-VOLATILE

This doesn't add new public API and is safe to commit to 4.11.

The first use case for this is to have X-KDE-VOLATILE-AKONADI-ID
that is set internally by the calendar classes, this is needed
because the old KCalCore::Calendar::CalendarObserver::calendarIncidenceDeleted()
has an Incidence as argument and we have no way to get the corresponding Item id
which is key of various hashes.

CCMAIL: winter@kde.org
CCMAIL: chrigi_1@fastmail.fm
  • Loading branch information
iamsergio authored and dcaliste committed Jul 13, 2020
1 parent 6094b59 commit 6b03be0
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 6 deletions.
38 changes: 34 additions & 4 deletions kcalcore/customproperties.cpp
Expand Up @@ -44,6 +44,16 @@ class CustomProperties::Private
bool operator==( const Private &other ) const;
QMap<QByteArray, QString> mProperties; // custom calendar properties
QMap<QByteArray, QString> mPropertyParameters;

// Volatile properties are not written back to the serialized format and are not compared in operator==
// They are only used for runtime purposes and are not part of the payload.
QMap<QByteArray, QString> mVolatileProperties;


bool isVolatileProperty( const QString &name ) const
{
return name.startsWith( "X-KDE-VOLATILE" );
}
};

bool CustomProperties::Private::operator==( const CustomProperties::Private &other ) const
Expand Down Expand Up @@ -113,7 +123,13 @@ void CustomProperties::setCustomProperty( const QByteArray &app, const QByteArra
return;
}
customPropertyUpdate();
d->mProperties[property] = value;

if ( d->isVolatileProperty( property ) ) {
d->mVolatileProperties[property] = value;
} else {
d->mProperties[property] = value;
}

customPropertyUpdated();
}

Expand Down Expand Up @@ -154,12 +170,16 @@ void CustomProperties::removeNonKDECustomProperty( const QByteArray &name )
d->mProperties.remove( name );
d->mPropertyParameters.remove( name );
customPropertyUpdated();
} else if ( d->mVolatileProperties.contains( name ) ) {
customPropertyUpdate();
d->mVolatileProperties.remove( name );
customPropertyUpdated();
}
}

QString CustomProperties::nonKDECustomProperty( const QByteArray &name ) const
{
return d->mProperties.value( name );
return d->isVolatileProperty( name ) ? d->mVolatileProperties.value( name ) : d->mProperties.value( name );
}

QString CustomProperties::nonKDECustomPropertyParameters( const QByteArray &name ) const
Expand All @@ -174,7 +194,11 @@ void CustomProperties::setCustomProperties( const QMap<QByteArray, QString> &pro
it != properties.end(); ++it ) {
// Validate the property name and convert any null string to empty string
if ( checkName( it.key() ) ) {
d->mProperties[it.key()] = it.value().isNull() ? QString( "" ) : it.value();
if ( d->isVolatileProperty( it.key() ) ) {
d->mVolatileProperties[it.key()] = it.value().isNull() ? QString( "" ) : it.value();
} else {
d->mProperties[it.key()] = it.value().isNull() ? QString( "" ) : it.value();
}
if ( !changed ) {
customPropertyUpdate();
}
Expand All @@ -188,7 +212,12 @@ void CustomProperties::setCustomProperties( const QMap<QByteArray, QString> &pro

QMap<QByteArray, QString> CustomProperties::customProperties() const
{
return d->mProperties;
QMap<QByteArray, QString> result = d->mProperties;
for (auto it = d->mVolatileProperties.begin(), end = d->mVolatileProperties.end(); it != end; ++it) {
result.insert(it.key(), it.value());
}

return result;
}

void CustomProperties::customPropertyUpdate()
Expand Down Expand Up @@ -240,6 +269,7 @@ QDataStream &KCalCore::operator<<( QDataStream &stream,
QDataStream &KCalCore::operator>>( QDataStream &stream,
KCalCore::CustomProperties &properties )
{
properties.d->mVolatileProperties.clear();
return stream >> properties.d->mProperties
>> properties.d->mPropertyParameters;
}
Expand Down
5 changes: 4 additions & 1 deletion kcalcore/icalformat_p.cpp
Expand Up @@ -667,7 +667,10 @@ void ICalFormatImpl::Private::writeCustomProperties( icalcomponent *parent,
{
const QMap<QByteArray, QString> custom = properties->customProperties();
for ( QMap<QByteArray, QString>::ConstIterator c = custom.begin(); c != custom.end(); ++c ) {

if ( c.key().startsWith( "X-KDE-VOLATILE" ) ) {
// We don't write these properties to disk to disk
continue;
}
icalproperty *p = icalproperty_new_x( c.value().toUtf8() );
QString parameters = properties->nonKDECustomPropertyParameters( c.key() );

Expand Down
34 changes: 34 additions & 0 deletions kcalcore/tests/testcustomproperties.cpp
Expand Up @@ -181,6 +181,40 @@ void CustomPropertiesTest::testDataStreamIn()
QVERIFY( cpmap == cpmap2 );
}

void CustomPropertiesTest::testVolatile()
{
QMap<QByteArray, QString> cpmap;
cpmap.insert( "X-key1", QString( "val1" ) );
cpmap.insert( "X-KDE-VOLATILE-FOO", QString( "val2" ) );

CustomProperties cp;
cp.setCustomProperties( cpmap );

QCOMPARE( cp.customProperties().count(), 2 );

QMap<QByteArray, QString> cpmap2;
cpmap2.insert( "X-key1", QString( "val1" ) );
CustomProperties cp2;
cp2.setCustomProperties( cpmap2 );
QCOMPARE( cp, cp2 );

cp.removeCustomProperty( "VOLATILE", "FOO" );
QCOMPARE( cp.customProperties().count(), 1 );

cp.setCustomProperty( "VOLATILE", "FOO", "BAR" );
QCOMPARE( cp.customProperties().count(), 2 );

QByteArray byteArray;
QDataStream out_stream( &byteArray, QIODevice::WriteOnly );

out_stream << cp;
QDataStream in_stream( &byteArray, QIODevice::ReadOnly );
in_stream >> cp;

QCOMPARE( cp.customProperties().count(), 1 );

}

void CustomPropertiesTest::testDataStreamOut()
{
QMap<QByteArray, QString> cpmap;
Expand Down
1 change: 1 addition & 0 deletions kcalcore/tests/testcustomproperties.h
Expand Up @@ -37,6 +37,7 @@ class CustomPropertiesTest : public QObject
void testEmpty();
void testDataStreamOut();
void testDataStreamIn();
void testVolatile();
};

#endif
17 changes: 17 additions & 0 deletions kcalcore/tests/testicalformat.cpp
Expand Up @@ -103,3 +103,20 @@ void ICalFormatTest::testCharsets()

unlink( "hommer.ics" );
}

void ICalFormatTest::testVolatileProperties()
{
// Volatile properties are not written to the serialized data
ICalFormat format;
const QDate currentDate = QDate::currentDate();
Event::Ptr event = Event::Ptr( new Event() );
event->setUid( "12345" );
event->setDtStart( KDateTime( currentDate ) );
event->setDtEnd( KDateTime( currentDate.addDays( 1 ) ) );
event->setCustomProperty( "VOLATILE", "FOO", "BAR" );
QString string = format.toICalString( event );
Incidence::Ptr incidence = format.fromString( string );

QCOMPARE( incidence->uid(), QLatin1String( "12345" ) );
QVERIFY( incidence->customProperties().isEmpty() );
}
1 change: 1 addition & 0 deletions kcalcore/tests/testicalformat.h
Expand Up @@ -30,6 +30,7 @@ class ICalFormatTest : public QObject
Q_OBJECT
private Q_SLOTS:
void testCharsets();
void testVolatileProperties();
};

#endif
3 changes: 2 additions & 1 deletion kcalcore/vcalformat.cpp
Expand Up @@ -2670,7 +2670,8 @@ void VCalFormat::writeCustomProperties( VObject *o, const Incidence::Ptr &i )
const QMap<QByteArray, QString> custom = i->customProperties();
for ( QMap<QByteArray, QString>::ConstIterator c = custom.begin();
c != custom.end(); ++c ) {
if ( d->mManuallyWrittenExtensionFields.contains( c.key() ) ) {
if ( d->mManuallyWrittenExtensionFields.contains( c.key() ) ||
c.key().startsWith( "X-KDE-VOLATILE" ) ) {
continue;
}

Expand Down

0 comments on commit 6b03be0

Please sign in to comment.