1/*
2 This file is part of the kcal library.
3
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@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 Event class.
25
26 @brief
27 This class provides an Event in the sense of RFC2445.
28
29 @author Cornelius Schumacher \<schumacher@kde.org\>
30*/
31
32#include "event.h"
33#include "incidenceformatter.h"
34
35#include <kglobal.h>
36#include <klocale.h>
37#include <klocalizedstring.h>
38#include <kdebug.h>
39#include <ksystemtimezone.h>
40
41using namespace KCal;
42
43/**
44 Private class that helps to provide binary compatibility between releases.
45 @internal
46*/
47//@cond PRIVATE
48class KCal::Event::Private
49{
50 public:
51 Private()
52 : mHasEndDate( false ),
53 mTransparency( Opaque )
54 {}
55 Private( const KCal::Event::Private &other )
56 : mDtEnd( other.mDtEnd ),
57 mHasEndDate( other.mHasEndDate ),
58 mTransparency( other.mTransparency )
59 {}
60
61 KDateTime mDtEnd;
62 bool mHasEndDate;
63 Transparency mTransparency;
64};
65//@endcond
66
67Event::Event()
68 : d( new KCal::Event::Private )
69{
70}
71
72Event::Event( const Event &other )
73 : Incidence( other ), d( new KCal::Event::Private( *other.d ) )
74{
75}
76
77Event::~Event()
78{
79 delete d;
80}
81
82Event *Event::clone()
83{
84 return new Event( *this );
85}
86
87Event &Event::operator=( const Event &other )
88{
89 // check for self assignment
90 if ( &other == this ) {
91 return *this;
92 }
93
94 Incidence::operator=( other );
95 *d = *other.d;
96 return *this;
97}
98
99bool Event::operator==( const Event &event ) const
100{
101 return
102 Incidence::operator==( event ) &&
103 dtEnd() == event.dtEnd() &&
104 hasEndDate() == event.hasEndDate() &&
105 transparency() == event.transparency();
106}
107
108QByteArray Event::type() const
109{
110 return "Event";
111}
112
113//KDE5:
114//QString Event::typeStr() const
115//{
116// return i18nc( "incidence type is event", "event" );
117//}
118
119void Event::setDtEnd( const KDateTime &dtEnd )
120{
121 if ( mReadOnly ) {
122 return;
123 }
124
125 d->mDtEnd = dtEnd;
126 setHasEndDate( true );
127 setHasDuration( false );
128
129 updated();
130}
131
132KDateTime Event::dtEnd() const
133{
134 if ( hasEndDate() ) {
135 return d->mDtEnd;
136 }
137
138 if ( hasDuration() ) {
139 if ( allDay() ) {
140 // For all day events, dtEnd is always inclusive
141 KDateTime end = duration().end( dtStart() ).addDays( -1 );
142 return end >= dtStart() ? end : dtStart();
143 } else {
144 return duration().end( dtStart() );
145 }
146 }
147
148 // It is valid for a VEVENT to be without a DTEND. See RFC2445, Sect4.6.1.
149 // Be careful to use Event::dateEnd() as appropriate due to this possibility.
150 return dtStart();
151}
152
153QDate Event::dateEnd() const
154{
155 KDateTime end = dtEnd().toTimeSpec( dtStart() );
156 if ( allDay() ) {
157 return end.date();
158 } else {
159 return end.addSecs(-1).date();
160 }
161}
162
163QString Event::dtEndTimeStr( bool shortfmt, const KDateTime::Spec &spec ) const
164{
165 if ( spec.isValid() ) {
166
167 QString timeZone;
168 if ( spec.timeZone() != KSystemTimeZones::local() ) {
169 timeZone = ' ' + spec.timeZone().name();
170 }
171
172 return KGlobal::locale()->formatTime(
173 dtEnd().toTimeSpec( spec ).time(), !shortfmt ) + timeZone;
174 } else {
175 return KGlobal::locale()->formatTime( dtEnd().time(), !shortfmt );
176 }
177}
178
179QString Event::dtEndDateStr( bool shortfmt, const KDateTime::Spec &spec ) const
180{
181 if ( spec.isValid() ) {
182
183 QString timeZone;
184 if ( spec.timeZone() != KSystemTimeZones::local() ) {
185 timeZone = ' ' + spec.timeZone().name();
186 }
187
188 return KGlobal::locale()->formatDate(
189 dtEnd().toTimeSpec( spec ).date(),
190 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
191 } else {
192 return KGlobal::locale()->formatDate(
193 dtEnd().date(),
194 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
195 }
196}
197
198QString Event::dtEndStr( bool shortfmt, const KDateTime::Spec &spec ) const
199{
200 if ( allDay() ) {
201 return IncidenceFormatter::dateToString( dtEnd(), shortfmt, spec );
202 }
203
204 if ( spec.isValid() ) {
205
206 QString timeZone;
207 if ( spec.timeZone() != KSystemTimeZones::local() ) {
208 timeZone = ' ' + spec.timeZone().name();
209 }
210
211 return KGlobal::locale()->formatDateTime(
212 dtEnd().toTimeSpec( spec ).dateTime(),
213 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) ) + timeZone;
214 } else {
215 return KGlobal::locale()->formatDateTime(
216 dtEnd().dateTime(),
217 ( shortfmt ? KLocale::ShortDate : KLocale::LongDate ) );
218 }
219}
220
221void Event::setHasEndDate( bool b )
222{
223 d->mHasEndDate = b;
224}
225
226bool Event::hasEndDate() const
227{
228 return d->mHasEndDate;
229}
230
231bool Event::isMultiDay( const KDateTime::Spec &spec ) const
232{
233 // End date is non inclusive, so subtract 1 second...
234 KDateTime start, end;
235 if ( spec.isValid() ) {
236 start = dtStart().toTimeSpec( spec );
237 end = dtEnd().toTimeSpec( spec );
238 } else {
239 start = dtStart();
240 end = dtEnd();
241 }
242
243 if ( !allDay() ) {
244 end = end.addSecs( -1 );
245 }
246
247 bool multi = ( start.date() != end.date() && start <= end );
248 return multi;
249}
250
251void Event::shiftTimes( const KDateTime::Spec &oldSpec,
252 const KDateTime::Spec &newSpec )
253{
254 Incidence::shiftTimes( oldSpec, newSpec );
255 if ( hasEndDate() ) {
256 d->mDtEnd = d->mDtEnd.toTimeSpec( oldSpec );
257 d->mDtEnd.setTimeSpec( newSpec );
258 }
259}
260
261void Event::setTransparency( Event::Transparency transparency )
262{
263 if ( mReadOnly ) {
264 return;
265 }
266 d->mTransparency = transparency;
267 updated();
268}
269
270Event::Transparency Event::transparency() const
271{
272 return d->mTransparency;
273}
274
275void Event::setDuration( const Duration &duration )
276{
277 setHasEndDate( false );
278 Incidence::setDuration( duration );
279}
280
281KDateTime Event::endDateRecurrenceBase() const
282{
283 return dtEnd();
284}
285