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 | |
41 | using namespace KCal; |
42 | |
43 | /** |
44 | Private class that helps to provide binary compatibility between releases. |
45 | @internal |
46 | */ |
47 | //@cond PRIVATE |
48 | class 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 | |
67 | Event::Event() |
68 | : d( new KCal::Event::Private ) |
69 | { |
70 | } |
71 | |
72 | Event::Event( const Event &other ) |
73 | : Incidence( other ), d( new KCal::Event::Private( *other.d ) ) |
74 | { |
75 | } |
76 | |
77 | Event::~Event() |
78 | { |
79 | delete d; |
80 | } |
81 | |
82 | Event *Event::clone() |
83 | { |
84 | return new Event( *this ); |
85 | } |
86 | |
87 | Event &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 | |
99 | bool 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 | |
108 | QByteArray 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 | |
119 | void 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 | |
132 | KDateTime 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 | |
153 | QDate 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 | |
163 | QString 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 | |
179 | QString 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 | |
198 | QString 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 | |
221 | void Event::setHasEndDate( bool b ) |
222 | { |
223 | d->mHasEndDate = b; |
224 | } |
225 | |
226 | bool Event::hasEndDate() const |
227 | { |
228 | return d->mHasEndDate; |
229 | } |
230 | |
231 | bool 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 | |
251 | void 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 | |
261 | void Event::setTransparency( Event::Transparency transparency ) |
262 | { |
263 | if ( mReadOnly ) { |
264 | return; |
265 | } |
266 | d->mTransparency = transparency; |
267 | updated(); |
268 | } |
269 | |
270 | Event::Transparency Event::transparency() const |
271 | { |
272 | return d->mTransparency; |
273 | } |
274 | |
275 | void Event::setDuration( const Duration &duration ) |
276 | { |
277 | setHasEndDate( false ); |
278 | Incidence::setDuration( duration ); |
279 | } |
280 | |
281 | KDateTime Event::endDateRecurrenceBase() const |
282 | { |
283 | return dtEnd(); |
284 | } |
285 | |