Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
PIM
KAlarm
Commits
1681114a
Commit
1681114a
authored
Mar 03, 2022
by
David Jarvie
Browse files
Merge kalarmcal into kalarm
parents
0a7bc059
d452d428
Changes
33
Expand all
Hide whitespace changes
Inline
Side-by-side
DESIGN-kalarmcalendar.html
0 → 100644
View file @
1681114a
This diff is collapsed.
Click to expand it.
src/kalarmcalendar/Mainpage.dox
0 → 100644
View file @
1681114a
/*!
* @mainpage The KAlarm client library
*
* @section purpose Purpose
*
* This library provides access to and handling of KAlarm calendar data.
*
* @section desc Description
*
* This library provides access to KAlarm calendar data, but not to the storage
* of the data, which is handled separately.
* The main class, KAEvent, represents a KAlarm event, and contains both the
* event definition including the main alarm and optional subsidiary alarms, and
* status information about the event.
*
* Calendar format information is accessed through the KACalendar class, which
* provides read and write access to the calendar format version and
* iCalendar product ID.
*
* Recurrence and sub-repetition information is represented by the KARecurrence
* and Repetition classes respectively.
*
* The KADateTime class is analagous to QDateTime, but can alternatively hold
* a date-only value, and its time zone definition is more flexible than
* QDateTime. The DateTime class is similar to KADateTime but with a
* configurable start-of-day time for date-only times.
*
* Three Akonadi attributes, for Collections and Items, are provided by
* CollectionAttribute, CompatibilityAttribute and EventAttribute classes.
*
* @authors
* David Jarvie \<djarvie@kde.org\>
*
* @licenses
* @lgpl
*/
// DOXYGEN_PROJECTNAME=KAlarm Library
// DOXYGEN_REFERENCES=kdecore kcalendarcore kholidays kpimidentities akonadi
src/kalarmcalendar/akonadi.cpp
0 → 100644
View file @
1681114a
/*
* akonadi.cpp - Akonadi object functions
* This file is part of kalarmcal library, which provides access to KAlarm
* calendar data.
* SPDX-FileCopyrightText: 2011, 2019 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include
"akonadi.h"
#include
"kaevent.h"
#include
<Akonadi/Item>
namespace
KAlarmCal
{
/******************************************************************************
* Initialise an Item with the event.
* Note that the event is not updated with the Item ID.
* Reply = true if successful,
* false if event's category does not match collection's mime types.
*/
bool
setItemPayload
(
Akonadi
::
Item
&
item
,
const
KAEvent
&
event
,
const
QStringList
&
collectionMimeTypes
)
{
QString
mimetype
;
switch
(
event
.
category
())
{
case
CalEvent
::
ACTIVE
:
mimetype
=
MIME_ACTIVE
;
break
;
case
CalEvent
::
ARCHIVED
:
mimetype
=
MIME_ARCHIVED
;
break
;
case
CalEvent
::
TEMPLATE
:
mimetype
=
MIME_TEMPLATE
;
break
;
default:
Q_ASSERT
(
0
);
return
false
;
}
if
(
!
collectionMimeTypes
.
contains
(
mimetype
))
{
return
false
;
}
item
.
setMimeType
(
mimetype
);
item
.
setPayload
<
KAEvent
>
(
event
);
return
true
;
}
}
src/kalarmcalendar/akonadi.h
0 → 100644
View file @
1681114a
/*
* akonadi.h - Akonadi object functions
* This file is part of kalarmcal library, which provides access to KAlarm
* calendar data.
* SPDX-FileCopyrightText: 2011, 2019 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#pragma once
#include
"kalarmcal_export.h"
#include
<QStringList>
namespace
Akonadi
{
class
Item
;
}
namespace
KAlarmCal
{
class
KAEvent
;
/** Initialise an Akonadi::Item with the event's data.
* Note that the event is not updated with the Item ID, and the Item is not
* added to the Collection.
* @param item the Item to initialise.
* @param event the event whose data will be used to initialise the Item.
* @param collectionMimeTypes the mime types for the Collection which will contain the Item.
* @return @c true if successful; @c false if the event's category does not match the
* collection's mime types.
*/
KALARMCAL_EXPORT
bool
setItemPayload
(
Akonadi
::
Item
&
item
,
const
KAEvent
&
event
,
const
QStringList
&
collectionMimeTypes
);
}
src/kalarmcalendar/alarmtext.cpp
0 → 100644
View file @
1681114a
/*
* alarmtext.cpp - text/email alarm text conversion
* This file is part of kalarmcal library, which provides access to KAlarm
* calendar data.
* SPDX-FileCopyrightText: 2004-2020 David Jarvie <djarvie@kde.org>
*
* SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include
"alarmtext.h"
#include
"kaevent.h"
#include
<KLocalizedString>
#include
<QStringList>
#include
<QDateTime>
#include
<QLocale>
#include
<QRegExp>
namespace
{
const
int
MAIL_FROM_LINE
=
0
;
// line number containing From in email text
const
int
MAIL_TO_LINE
=
1
;
// line number containing To in email text
const
int
MAIL_CC_LINE
=
2
;
// line number containing CC in email text
const
int
MAIL_MIN_LINES
=
4
;
// allow for From, To, no CC, Date, Subject
}
namespace
KAlarmCal
{
class
Q_DECL_HIDDEN
AlarmText
::
Private
{
public:
enum
Type
{
None
,
Email
,
Script
,
Todo
};
QString
displayText
()
const
;
void
clear
();
static
void
initialise
();
static
void
setUpTranslations
();
static
int
emailHeaderCount
(
const
QStringList
&
);
static
QString
todoTitle
(
const
QString
&
text
);
static
QString
mFromPrefix
;
// translated header prefixes
static
QString
mToPrefix
;
static
QString
mCcPrefix
;
static
QString
mDatePrefix
;
static
QString
mSubjectPrefix
;
static
QString
mTitlePrefix
;
static
QString
mLocnPrefix
;
static
QString
mDuePrefix
;
static
QString
mFromPrefixEn
;
// untranslated header prefixes
static
QString
mToPrefixEn
;
static
QString
mCcPrefixEn
;
static
QString
mDatePrefixEn
;
static
QString
mSubjectPrefixEn
;
static
bool
mInitialised
;
QString
mBody
,
mFrom
,
mTo
,
mCc
,
mTime
,
mSubject
;
Akonadi
::
Item
::
Id
mAkonadiItemId
;
// if email, message's Akonadi item ID, else -1
Type
mType
;
bool
mIsEmail
;
};
QString
AlarmText
::
Private
::
mFromPrefix
;
QString
AlarmText
::
Private
::
mToPrefix
;
QString
AlarmText
::
Private
::
mCcPrefix
;
QString
AlarmText
::
Private
::
mDatePrefix
;
QString
AlarmText
::
Private
::
mSubjectPrefix
;
QString
AlarmText
::
Private
::
mTitlePrefix
;
QString
AlarmText
::
Private
::
mLocnPrefix
;
QString
AlarmText
::
Private
::
mDuePrefix
;
QString
AlarmText
::
Private
::
mFromPrefixEn
;
QString
AlarmText
::
Private
::
mToPrefixEn
;
QString
AlarmText
::
Private
::
mCcPrefixEn
;
QString
AlarmText
::
Private
::
mDatePrefixEn
;
QString
AlarmText
::
Private
::
mSubjectPrefixEn
;
bool
AlarmText
::
Private
::
mInitialised
=
false
;
void
AlarmText
::
Private
::
initialise
()
{
if
(
!
mInitialised
)
{
mInitialised
=
true
;
mFromPrefixEn
=
QStringLiteral
(
"From:"
);
mToPrefixEn
=
QStringLiteral
(
"To:"
);
mCcPrefixEn
=
QStringLiteral
(
"Cc:"
);
mDatePrefixEn
=
QStringLiteral
(
"Date:"
);
mSubjectPrefixEn
=
QStringLiteral
(
"Subject:"
);
}
}
AlarmText
::
AlarmText
(
const
QString
&
text
)
:
d
(
new
Private
)
{
Private
::
initialise
();
setText
(
text
);
}
AlarmText
::
AlarmText
(
const
AlarmText
&
other
)
:
d
(
new
Private
(
*
other
.
d
))
{
}
AlarmText
::~
AlarmText
()
{
delete
d
;
}
AlarmText
&
AlarmText
::
operator
=
(
const
AlarmText
&
other
)
{
if
(
&
other
!=
this
)
{
*
d
=
*
other
.
d
;
}
return
*
this
;
}
void
AlarmText
::
clear
()
{
d
->
clear
();
}
void
AlarmText
::
setText
(
const
QString
&
text
)
{
d
->
clear
();
d
->
mBody
=
text
;
if
(
text
.
startsWith
(
QLatin1String
(
"#!"
)))
{
d
->
mType
=
Private
::
Script
;
}
}
void
AlarmText
::
setScript
(
const
QString
&
text
)
{
setText
(
text
);
d
->
mType
=
Private
::
Script
;
}
void
AlarmText
::
setEmail
(
const
QString
&
to
,
const
QString
&
from
,
const
QString
&
cc
,
const
QString
&
time
,
const
QString
&
subject
,
const
QString
&
body
,
Akonadi
::
Item
::
Id
itemId
)
{
d
->
clear
();
d
->
mType
=
Private
::
Email
;
d
->
mTo
=
to
;
d
->
mFrom
=
from
;
d
->
mCc
=
cc
;
d
->
mTime
=
time
;
d
->
mSubject
=
subject
;
d
->
mBody
=
body
;
d
->
mAkonadiItemId
=
itemId
;
}
void
AlarmText
::
setTodo
(
const
KCalendarCore
::
Todo
::
Ptr
&
todo
)
{
d
->
clear
();
d
->
mType
=
Private
::
Todo
;
d
->
mSubject
=
todo
->
summary
();
d
->
mBody
=
todo
->
description
();
d
->
mTo
=
todo
->
location
();
if
(
todo
->
hasDueDate
())
{
QDateTime
due
=
todo
->
dtDue
(
false
);
// fetch the next due date
if
(
todo
->
hasStartDate
()
&&
todo
->
dtStart
(
true
)
!=
due
)
{
d
->
mTime
=
todo
->
allDay
()
?
QLocale
().
toString
(
due
.
date
(),
QLocale
::
ShortFormat
)
:
QLocale
().
toString
(
due
,
QLocale
::
ShortFormat
);
}
}
}
/******************************************************************************
* Return the text for a text message alarm, in display format.
*/
QString
AlarmText
::
displayText
()
const
{
return
d
->
displayText
();
}
QString
AlarmText
::
Private
::
displayText
()
const
{
QString
text
;
switch
(
mType
)
{
case
Email
:
// Format the email into a text alarm
setUpTranslations
();
text
=
mFromPrefix
+
QLatin1Char
(
'\t'
)
+
mFrom
+
QLatin1Char
(
'\n'
);
text
+=
mToPrefix
+
QLatin1Char
(
'\t'
)
+
mTo
+
QLatin1Char
(
'\n'
);
if
(
!
mCc
.
isEmpty
())
{
text
+=
mCcPrefix
+
QLatin1Char
(
'\t'
)
+
mCc
+
QLatin1Char
(
'\n'
);
}
if
(
!
mTime
.
isEmpty
())
{
text
+=
mDatePrefix
+
QLatin1Char
(
'\t'
)
+
mTime
+
QLatin1Char
(
'\n'
);
}
text
+=
mSubjectPrefix
+
QLatin1Char
(
'\t'
)
+
mSubject
;
if
(
!
mBody
.
isEmpty
())
{
text
+=
QLatin1String
(
"
\n\n
"
);
text
+=
mBody
;
}
break
;
case
Todo
:
// Format the todo into a text alarm
setUpTranslations
();
if
(
!
mSubject
.
isEmpty
())
{
text
=
mTitlePrefix
+
QLatin1Char
(
'\t'
)
+
mSubject
+
QLatin1Char
(
'\n'
);
}
if
(
!
mTo
.
isEmpty
())
{
text
+=
mLocnPrefix
+
QLatin1Char
(
'\t'
)
+
mTo
+
QLatin1Char
(
'\n'
);
}
if
(
!
mTime
.
isEmpty
())
{
text
+=
mDuePrefix
+
QLatin1Char
(
'\t'
)
+
mTime
+
QLatin1Char
(
'\n'
);
}
if
(
!
mBody
.
isEmpty
())
{
if
(
!
text
.
isEmpty
())
{
text
+=
QLatin1Char
(
'\n'
);
}
text
+=
mBody
;
}
break
;
default:
break
;
}
return
!
text
.
isEmpty
()
?
text
:
mBody
;
}
QString
AlarmText
::
to
()
const
{
return
(
d
->
mType
==
Private
::
Email
)
?
d
->
mTo
:
QString
();
}
QString
AlarmText
::
from
()
const
{
return
(
d
->
mType
==
Private
::
Email
)
?
d
->
mFrom
:
QString
();
}
QString
AlarmText
::
cc
()
const
{
return
(
d
->
mType
==
Private
::
Email
)
?
d
->
mCc
:
QString
();
}
QString
AlarmText
::
time
()
const
{
return
(
d
->
mType
==
Private
::
Email
)
?
d
->
mTime
:
QString
();
}
QString
AlarmText
::
subject
()
const
{
return
(
d
->
mType
==
Private
::
Email
)
?
d
->
mSubject
:
QString
();
}
QString
AlarmText
::
body
()
const
{
return
(
d
->
mType
==
Private
::
Email
)
?
d
->
mBody
:
QString
();
}
QString
AlarmText
::
summary
()
const
{
return
(
d
->
mType
==
Private
::
Todo
)
?
d
->
mSubject
:
QString
();
}
QString
AlarmText
::
location
()
const
{
return
(
d
->
mType
==
Private
::
Todo
)
?
d
->
mTo
:
QString
();
}
QString
AlarmText
::
due
()
const
{
return
(
d
->
mType
==
Private
::
Todo
)
?
d
->
mTime
:
QString
();
}
QString
AlarmText
::
description
()
const
{
return
(
d
->
mType
==
Private
::
Todo
)
?
d
->
mBody
:
QString
();
}
/******************************************************************************
* Return whether there is any text.
*/
bool
AlarmText
::
isEmpty
()
const
{
if
(
!
d
->
mBody
.
isEmpty
())
{
return
false
;
}
if
(
d
->
mType
!=
Private
::
Email
)
{
return
true
;
}
return
d
->
mFrom
.
isEmpty
()
&&
d
->
mTo
.
isEmpty
()
&&
d
->
mCc
.
isEmpty
()
&&
d
->
mTime
.
isEmpty
()
&&
d
->
mSubject
.
isEmpty
();
}
bool
AlarmText
::
isEmail
()
const
{
return
d
->
mType
==
Private
::
Email
;
}
bool
AlarmText
::
isScript
()
const
{
return
d
->
mType
==
Private
::
Script
;
}
bool
AlarmText
::
isTodo
()
const
{
return
d
->
mType
==
Private
::
Todo
;
}
Akonadi
::
Item
::
Id
AlarmText
::
akonadiItemId
()
const
{
return
d
->
mAkonadiItemId
;
}
/******************************************************************************
* Return the alarm summary text for either single line or tooltip display.
* The maximum number of line returned is determined by 'maxLines'.
* If 'truncated' is non-null, it will be set true if the text returned has been
* truncated, other than to strip a trailing newline.
*/
QString
AlarmText
::
summary
(
const
KAEvent
&
event
,
int
maxLines
,
bool
*
truncated
)
{
static
const
QRegExp
localfile
(
QStringLiteral
(
"^file:/+"
));
QString
text
;
switch
(
event
.
actionSubType
())
{
case
KAEvent
::
AUDIO
:
text
=
event
.
audioFile
();
if
(
localfile
.
indexIn
(
text
)
>=
0
)
{
text
=
text
.
mid
(
localfile
.
matchedLength
()
-
1
);
}
break
;
case
KAEvent
::
EMAIL
:
text
=
event
.
emailSubject
();
break
;
case
KAEvent
::
COMMAND
:
text
=
event
.
cleanText
();
if
(
localfile
.
indexIn
(
text
)
>=
0
)
{
text
=
text
.
mid
(
localfile
.
matchedLength
()
-
1
);
}
break
;
case
KAEvent
::
FILE
:
text
=
event
.
cleanText
();
break
;
case
KAEvent
::
MESSAGE
:
{
text
=
event
.
cleanText
();
// If the message is the text of an email, return its headers or just subject line
QString
subject
=
emailHeaders
(
text
,
(
maxLines
<=
1
));
if
(
!
subject
.
isNull
())
{
if
(
truncated
)
{
*
truncated
=
true
;
}
return
subject
;
}
if
(
maxLines
==
1
)
{
// If the message is the text of a todo, return either the
// title/description or the whole text.
subject
=
Private
::
todoTitle
(
text
);
if
(
!
subject
.
isEmpty
())
{
if
(
truncated
)
{
*
truncated
=
true
;
}
return
subject
;
}
}
break
;
}
}
if
(
truncated
)
{
*
truncated
=
false
;
}
if
(
text
.
count
(
QLatin1Char
(
'\n'
))
<
maxLines
)
{
return
text
;
}
int
newline
=
-
1
;
for
(
int
i
=
0
;
i
<
maxLines
;
++
i
)
{
newline
=
text
.
indexOf
(
QLatin1Char
(
'\n'
),
newline
+
1
);
if
(
newline
<
0
)
{
return
text
;
// not truncated after all !?!
}
}
if
(
newline
==
static_cast
<
int
>
(
text
.
length
())
-
1
)
{
return
text
.
left
(
newline
);
// text ends in newline
}
if
(
truncated
)
{
*
truncated
=
true
;
}
return
text
.
left
(
newline
+
(
maxLines
<=
1
?
0
:
1
))
+
QLatin1String
(
"..."
);
}
/******************************************************************************
* Check whether a text is an email.
*/
bool
AlarmText
::
checkIfEmail
(
const
QString
&
text
)
{
const
QStringList
lines
=
text
.
split
(
QLatin1Char
(
'\n'
),
Qt
::
SkipEmptyParts
);
return
Private
::
emailHeaderCount
(
lines
);
}
/******************************************************************************
* Check whether a text is an email, and if so return its headers or optionally
* only its subject line.
* Reply = headers/subject line, or QString() if not the text of an email.
*/
QString
AlarmText
::
emailHeaders
(
const
QString
&
text
,
bool
subjectOnly
)
{
const
QStringList
lines
=
text
.
split
(
QLatin1Char
(
'\n'
),
Qt
::
SkipEmptyParts
);
const
int
n
=
Private
::
emailHeaderCount
(
lines
);
if
(
!
n
)
{
return
{};
}
if
(
subjectOnly
)
{
return
lines
[
n
-
1
].
mid
(
Private
::
mSubjectPrefix
.
length
()).
trimmed
();
}
QString
h
=
lines
[
0
];
for
(
int
i
=
1
;
i
<
n
;
++
i
)
{
h
+=
QLatin1Char
(
'\n'
);
h
+=
lines
[
i
];
}
return
h
;
}
/******************************************************************************
* Translate an alarm calendar text to a display text.
* Translation is needed for email texts, since the alarm calendar stores
* untranslated email prefixes.
* 'email' is set to indicate whether it is an email text.
*/
QString
AlarmText
::
fromCalendarText
(
const
QString
&
text
,
bool
&
email
)
{
Private
::
initialise
();
const
QStringList
lines
=
text
.
split
(
QLatin1Char
(
'\n'
),
Qt
::
SkipEmptyParts
);
const
int
maxn
=
lines
.
count
();
if
(
maxn
>=
MAIL_MIN_LINES
&&
lines
[
MAIL_FROM_LINE
].
startsWith
(
Private
::
mFromPrefixEn
)
&&
lines
[
MAIL_TO_LINE
].
startsWith
(
Private
::
mToPrefixEn
))
{
int
n
=
MAIL_CC_LINE
;
if
(
lines
[
MAIL_CC_LINE
].
startsWith
(
Private
::
mCcPrefixEn
))
{
++
n
;
}
if
(
maxn
>
n
+
1
&&
lines
[
n
].
startsWith
(
Private
::
mDatePrefixEn
)
&&
lines
[
n
+
1
].
startsWith
(
Private
::
mSubjectPrefixEn
))
{
Private
::
setUpTranslations
();
QString
dispText
;
dispText
=
Private
::
mFromPrefix
+
lines
[
MAIL_FROM_LINE
].
mid
(
Private
::
mFromPrefixEn
.
length
())
+
QLatin1Char
(
'\n'
);
dispText
+=
Private
::
mToPrefix
+
lines
[
MAIL_TO_LINE
].
mid
(
Private
::
mToPrefixEn
.
length
())
+
QLatin1Char
(
'\n'
);
if
(
n
>
MAIL_CC_LINE
)
{
dispText
+=
Private
::
mCcPrefix
+
lines
[
MAIL_CC_LINE
].
mid
(
Private
::
mCcPrefixEn
.
length
())
+
QLatin1Char
(
'\n'
);
}
dispText
+=
Private
::
mDatePrefix
+
lines
[
n
].
mid
(
Private
::
mDatePrefixEn
.
length
())
+
QLatin1Char
(
'\n'
);
dispText
+=
Private
::
mSubjectPrefix
+
lines
[
n
+
1
].
mid
(
Private
::
mSubjectPrefixEn
.
length
());
int
i
=
text
.
indexOf
(
Private
::
mSubjectPrefixEn
);
i
=
text
.
indexOf
(
QLatin1Char
(
'\n'
),
i
);
if
(
i
>
0
)
{
dispText
+=
QStringView
(
text
).
mid
(
i
);
}
email
=
true
;
return
dispText
;
}
}
email
=
false
;
return
text
;
}
/******************************************************************************
* Return the text for a text message alarm, in alarm calendar format.
* (The prefix strings are untranslated in the calendar.)
*/
QString
AlarmText
::
toCalendarText
(
const
QString
&
text
)
{
Private
::
setUpTranslations
();
const
QStringList
lines
=
text
.
split
(
QLatin1Char
(
'\n'
),
Qt
::
SkipEmptyParts
);
const
int
maxn
=
lines
.
count
();
if
(
maxn
>=
MAIL_MIN_LINES
&&
lines
[
MAIL_FROM_LINE
].
startsWith
(
Private
::
mFromPrefix
)
&&
lines
[
MAIL_TO_LINE
].
startsWith
(
Private
::
mToPrefix
))
{
int
n
=
MAIL_CC_LINE
;
if
(
lines
[
MAIL_CC_LINE
].
startsWith
(
Private
::
mCcPrefix
))
{
++
n
;
}
if
(
maxn
>
n
+
1
&&
lines
[
n
].
startsWith
(
Private
::
mDatePrefix
)
&&
lines
[
n
+
1
].
startsWith
(
Private
::
mSubjectPrefix
))
{
// Format the email into a text alarm
QString
calText
;
calText
=
Private
::
mFromPrefixEn
+
lines
[
MAIL_FROM_LINE
].
mid
(
Private
::
mFromPrefix
.
length
())
+
QLatin1Char
(
'\n'
);
calText
+=
Private
::
mToPrefixEn
+
lines
[
MAIL_TO_LINE
].
mid
(
Private
::
mToPrefix
.
length
())
+
QLatin1Char
(
'\n'
);
if
(
n
>
MAIL_CC_LINE
)
{
calText
+=
Private
::
mCcPrefixEn
+
lines
[
MAIL_CC_LINE
].
mid
(
Private
::
mCcPrefix
.
length
())
+
QLatin1Char
(
'\n'
);
}
calText
+=
Private
::
mDatePrefixEn
+
lines
[
n
].
mid
(
Private
::
mDatePrefix
.
length
())
+
QLatin1Char
(
'\n'
);
calText
+=
Private
::
mSubjectPrefixEn
+
lines
[
n
+
1
].
mid
(
Private
::
mSubjectPrefix
.
length
());
int
i
=
text
.
indexOf
(
Private
::
mSubjectPrefix
);