libkcal

incidenceformatter.cpp
1/*
2 This file is part of libkcal.
3
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6 Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this library; see the file COPYING.LIB. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 Boston, MA 02110-1301, USA.
22*/
23
24#include "incidenceformatter.h"
25
26#include <libkcal/attachment.h>
27#include <libkcal/event.h>
28#include <libkcal/todo.h>
29#include <libkcal/journal.h>
30#include <libkcal/calendar.h>
31#include <libkcal/calendarlocal.h>
32#include <libkcal/icalformat.h>
33#include <libkcal/freebusy.h>
35
36#include <libemailfunctions/email.h>
37
38#include <ktnef/ktnefparser.h>
39#include <ktnef/ktnefmessage.h>
40#include <ktnef/ktnefdefs.h>
41#include <tdeabc/phonenumber.h>
42#include <tdeabc/vcardconverter.h>
43#include <tdeabc/stdaddressbook.h>
44
45#include <tdeapplication.h>
46#include <tdeemailsettings.h>
47
48#include <tdelocale.h>
49#include <tdeglobal.h>
50#include <kiconloader.h>
51#include <kcalendarsystem.h>
52#include <kmimetype.h>
53
54#include <tqbuffer.h>
55#include <tqstylesheet.h>
56#include <tqdatetime.h>
57#include <tqregexp.h>
58
59#include <time.h>
60
61using namespace KCal;
62
63/*******************
64 * General helpers
65 *******************/
66
67static TQString htmlAddLink( const TQString &ref, const TQString &text,
68 bool newline = true )
69{
70 TQString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
71 if ( newline ) tmpStr += "\n";
72 return tmpStr;
73}
74
75static TQString htmlAddTag( const TQString & tag, const TQString & text )
76{
77 int numLineBreaks = text.contains( "\n" );
78 TQString str = "<" + tag + ">";
79 TQString tmpText = text;
80 TQString tmpStr = str;
81 if( numLineBreaks >= 0 ) {
82 if ( numLineBreaks > 0) {
83 int pos = 0;
84 TQString tmp;
85 for( int i = 0; i <= numLineBreaks; i++ ) {
86 pos = tmpText.find( "\n" );
87 tmp = tmpText.left( pos );
88 tmpText = tmpText.right( tmpText.length() - pos - 1 );
89 tmpStr += tmp + "<br>";
90 }
91 } else {
92 tmpStr += tmpText;
93 }
94 }
95 tmpStr += "</" + tag + ">";
96 return tmpStr;
97}
98
99static bool iamAttendee( Attendee *attendee )
100{
101 // Check if I'm this attendee
102
103 bool iam = false;
104 KEMailSettings settings;
105 TQStringList profiles = settings.profiles();
106 for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
107 settings.setProfile( *it );
108 if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->email() ) {
109 iam = true;
110 break;
111 }
112 }
113 return iam;
114}
115
116static bool iamOrganizer( Incidence *incidence )
117{
118 // Check if I'm the organizer for this incidence
119
120 if ( !incidence ) {
121 return false;
122 }
123
124 bool iam = false;
125 KEMailSettings settings;
126 TQStringList profiles = settings.profiles();
127 for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
128 settings.setProfile( *it );
129 if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->organizer().email() ) {
130 iam = true;
131 break;
132 }
133 }
134 return iam;
135}
136
137static bool senderIsOrganizer( Incidence *incidence, const TQString &sender )
138{
139 // Check if the specified sender is the organizer
140
141 if ( !incidence || sender.isEmpty() ) {
142 return true;
143 }
144 bool isorg = true;
145 TQString senderName, senderEmail;
146 if ( KPIM::getNameAndMail( sender, senderName, senderEmail ) ) {
147 // for this heuristic, we say the sender is the organizer if either the name or the email match.
148 if ( incidence->organizer().email() != senderEmail &&
149 incidence->organizer().name() != senderName ) {
150 isorg = false;
151 }
152 }
153 return isorg;
154}
155
156static TQString firstAttendeeName( Incidence *incidence, const TQString &defName )
157{
158 TQString name;
159 if ( !incidence ) {
160 return name;
161 }
162
163 Attendee::List attendees = incidence->attendees();
164 if( attendees.count() > 0 ) {
165 Attendee *attendee = *attendees.begin();
166 name = attendee->name();
167 if ( name.isEmpty() ) {
168 name = attendee->email();
169 }
170 if ( name.isEmpty() ) {
171 name = defName;
172 }
173 }
174 return name;
175}
176
177/*******************************************************************
178 * Helper functions for the extensive display (display viewer)
179 *******************************************************************/
180
181static TQString displayViewLinkPerson( const TQString& email, TQString name, TQString uid )
182{
183 // Make the search, if there is an email address to search on,
184 // and either name or uid is missing
185 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
186 TDEABC::AddressBook *add_book = TDEABC::StdAddressBook::self( true );
187 TDEABC::Addressee::List addressList = add_book->findByEmail( email );
188 if ( !addressList.isEmpty() ) {
189 TDEABC::Addressee o = addressList.first();
190 if ( !o.isEmpty() && addressList.size() < 2 ) {
191 if ( name.isEmpty() ) {
192 // No name set, so use the one from the addressbook
193 name = o.formattedName();
194 }
195 uid = o.uid();
196 } else {
197 // Email not found in the addressbook. Don't make a link
198 uid = TQString();
199 }
200 }
201 }
202
203 // Show the attendee
204 TQString tmpString;
205 if ( !uid.isEmpty() ) {
206 // There is a UID, so make a link to the addressbook
207 if ( name.isEmpty() ) {
208 // Use the email address for text
209 tmpString += htmlAddLink( "uid:" + uid, email );
210 } else {
211 tmpString += htmlAddLink( "uid:" + uid, name );
212 }
213 } else {
214 // No UID, just show some text
215 tmpString += ( name.isEmpty() ? email : name );
216 }
217
218 // Make the mailto link
219 if ( !email.isEmpty() ) {
220 KURL mailto;
221 mailto.setProtocol( "mailto" );
222 mailto.setPath( email );
223 const TQString iconPath =
224 TDEGlobal::iconLoader()->iconPath( "mail-message-new", TDEIcon::Small );
225 tmpString += "&nbsp;" +
226 htmlAddLink( mailto.url(),
227 "<img valign=\"top\" src=\"" + iconPath + "\">" );
228 }
229
230 return tmpString;
231}
232
233static TQString displayViewFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role )
234{
235 TQString tmpStr;
236 Attendee::List::ConstIterator it;
237 Attendee::List attendees = incidence->attendees();
238
239 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
240 Attendee *a = *it;
241 if ( a->role() != role ) {
242 // skip this role
243 continue;
244 }
245 if ( a->email() == incidence->organizer().email() ) {
246 // skip attendee that is also the organizer
247 continue;
248 }
249 tmpStr += displayViewLinkPerson( a->email(), a->name(), a->uid() );
250 if ( !a->delegator().isEmpty() ) {
251 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
252 }
253 if ( !a->delegate().isEmpty() ) {
254 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
255 }
256 tmpStr += "<br>";
257 }
258 if ( tmpStr.endsWith( "<br>" ) ) {
259 tmpStr.truncate( tmpStr.length() - 4 );
260 }
261 return tmpStr;
262}
263
264static TQString displayViewFormatAttendees( Incidence *incidence )
265{
266 TQString tmpStr, str;
267
268 // Add organizer link
269 int attendeeCount = incidence->attendees().count();
270 if ( attendeeCount > 1 ||
271 ( attendeeCount == 1 &&
272 incidence->organizer().email() != incidence->attendees().first()->email() ) ) {
273 tmpStr += "<tr>";
274 tmpStr += "<td><b>" + i18n( "Organizer:" ) + "</b></td>";
275 tmpStr += "<td>" +
276 displayViewLinkPerson( incidence->organizer().email(),
277 incidence->organizer().name(),
278 TQString() ) +
279 "</td>";
280 tmpStr += "</tr>";
281 }
282
283 // Add "chair"
284 str = displayViewFormatAttendeeRoleList( incidence, Attendee::Chair );
285 if ( !str.isEmpty() ) {
286 tmpStr += "<tr>";
287 tmpStr += "<td><b>" + i18n( "Chair:" ) + "</b></td>";
288 tmpStr += "<td>" + str + "</td>";
289 tmpStr += "</tr>";
290 }
291
292 // Add required participants
293 str = displayViewFormatAttendeeRoleList( incidence, Attendee::ReqParticipant );
294 if ( !str.isEmpty() ) {
295 tmpStr += "<tr>";
296 tmpStr += "<td><b>" + i18n( "Required Participants:" ) + "</b></td>";
297 tmpStr += "<td>" + str + "</td>";
298 tmpStr += "</tr>";
299 }
300
301 // Add optional participants
302 str = displayViewFormatAttendeeRoleList( incidence, Attendee::OptParticipant );
303 if ( !str.isEmpty() ) {
304 tmpStr += "<tr>";
305 tmpStr += "<td><b>" + i18n( "Optional Participants:" ) + "</b></td>";
306 tmpStr += "<td>" + str + "</td>";
307 tmpStr += "</tr>";
308 }
309
310 // Add observers
311 str = displayViewFormatAttendeeRoleList( incidence, Attendee::NonParticipant );
312 if ( !str.isEmpty() ) {
313 tmpStr += "<tr>";
314 tmpStr += "<td><b>" + i18n( "Observers:" ) + "</b></td>";
315 tmpStr += "<td>" + str + "</td>";
316 tmpStr += "</tr>";
317 }
318
319 return tmpStr;
320}
321
322static TQString displayViewFormatAttachments( Incidence *incidence )
323{
324 TQString tmpStr;
325 Attachment::List as = incidence->attachments();
326 Attachment::List::ConstIterator it;
327 uint count = 0;
328 for( it = as.begin(); it != as.end(); ++it ) {
329 count++;
330 if ( (*it)->isUri() ) {
331 TQString name;
332 if ( (*it)->uri().startsWith( "kmail:" ) ) {
333 name = i18n( "Show mail" );
334 } else {
335 if ( (*it)->label().isEmpty() ) {
336 name = (*it)->uri();
337 } else {
338 name = (*it)->label();
339 }
340 }
341 tmpStr += htmlAddLink( (*it)->uri(), name );
342 } else {
343 tmpStr += htmlAddLink( "ATTACH:" + incidence->uid() + ':' + (*it)->label(),
344 (*it)->label(), false );
345 }
346 if ( count < as.count() ) {
347 tmpStr += "<br>";
348 }
349 }
350 return tmpStr;
351}
352
353static TQString displayViewFormatCategories( Incidence *incidence )
354{
355 // We do not use Incidence::categoriesStr() since it does not have whitespace
356 return incidence->categories().join( ", " );
357}
358
359static TQString displayViewFormatCreationDate( Incidence *incidence )
360{
361 return i18n( "Creation date: %1" ).
362 arg( IncidenceFormatter::dateTimeToString( incidence->created(), false, true ) );
363}
364
365static TQString displayViewFormatBirthday( Event *event )
366{
367 if ( !event ) {
368 return TQString();
369 }
370 if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) {
371 return TQString();
372 }
373
374 TQString uid = event->customProperty("KABC","UID-1");
375 TQString name = event->customProperty("KABC","NAME-1");
376 TQString email= event->customProperty("KABC","EMAIL-1");
377
378 TQString tmpStr = displayViewLinkPerson( email, name, uid );
379
380 if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
381 uid = event->customProperty("KABC","UID-2");
382 name = event->customProperty("KABC","NAME-2");
383 email= event->customProperty("KABC","EMAIL-2");
384 tmpStr += "<br>";
385 tmpStr += displayViewLinkPerson( email, name, uid );
386 }
387
388 return tmpStr;
389}
390
391static TQString displayViewFormatHeader( Incidence *incidence )
392{
393 TQString tmpStr = "<table><tr>";
394
395 // show icons
396 {
397 tmpStr += "<td>";
398
399 if ( incidence->type() == "Event" ) {
400 TQString iconPath;
401 if ( incidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
402 if ( incidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
403 iconPath =
404 TDEGlobal::iconLoader()->iconPath( "calendaranniversary", TDEIcon::Small );
405 } else {
406 iconPath = TDEGlobal::iconLoader()->iconPath( "calendarbirthday", TDEIcon::Small );
407 }
408 } else {
409 iconPath = TDEGlobal::iconLoader()->iconPath( "appointment", TDEIcon::Small );
410 }
411 tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
412 }
413 if ( incidence->type() == "Todo" ) {
414 tmpStr += "<img valign=\"top\" src=\"" +
415 TDEGlobal::iconLoader()->iconPath( "todo", TDEIcon::Small ) +
416 "\">";
417 }
418 if ( incidence->type() == "Journal" ) {
419 tmpStr += "<img valign=\"top\" src=\"" +
420 TDEGlobal::iconLoader()->iconPath( "journal", TDEIcon::Small ) +
421 "\">";
422 }
423 if ( incidence->isAlarmEnabled() ) {
424 tmpStr += "<img valign=\"top\" src=\"" +
425 TDEGlobal::iconLoader()->iconPath( "bell", TDEIcon::Small ) +
426 "\">";
427 }
428 if ( incidence->doesRecur() ) {
429 tmpStr += "<img valign=\"top\" src=\"" +
430 TDEGlobal::iconLoader()->iconPath( "recur", TDEIcon::Small ) +
431 "\">";
432 }
433 if ( incidence->isReadOnly() ) {
434 tmpStr += "<img valign=\"top\" src=\"" +
435 TDEGlobal::iconLoader()->iconPath( "readonlyevent", TDEIcon::Small ) +
436 "\">";
437 }
438
439 tmpStr += "</td>";
440 }
441
442 tmpStr += "<td>";
443 tmpStr += "<b><u>" + incidence->summary() + "</u></b>";
444 tmpStr += "</td>";
445
446 tmpStr += "</tr></table>";
447
448 return tmpStr;
449}
450
451static TQString displayViewFormatEvent( Calendar *calendar, Event *event,
452 const TQDate &date )
453{
454 if ( !event ) {
455 return TQString();
456 }
457
458 TQString tmpStr = displayViewFormatHeader( event );
459
460 tmpStr += "<table>";
461 tmpStr += "<col width=\"25%\"/>";
462 tmpStr += "<col width=\"75%\"/>";
463
464 if ( calendar ) {
465 TQString calStr = IncidenceFormatter::resourceString( calendar, event );
466 if ( !calStr.isEmpty() ) {
467 tmpStr += "<tr>";
468 tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
469 tmpStr += "<td>" + calStr + "</td>";
470 tmpStr += "</tr>";
471 }
472 }
473
474 if ( !event->location().isEmpty() ) {
475 tmpStr += "<tr>";
476 tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
477 tmpStr += "<td>" + event->location() + "</td>";
478 tmpStr += "</tr>";
479 }
480
481 TQDateTime startDt = event->dtStart();
482 TQDateTime endDt = event->dtEnd();
483 if ( event->doesRecur() ) {
484 if ( date.isValid() ) {
485 TQDateTime dt( date, TQTime( 0, 0, 0 ) );
486 int diffDays = startDt.daysTo( dt );
487 dt = dt.addSecs( -1 );
488 startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
489 if ( event->hasEndDate() ) {
490 endDt = endDt.addDays( diffDays );
491 if ( startDt > endDt ) {
492 startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
493 endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
494 }
495 }
496 }
497 }
498
499 tmpStr += "<tr>";
500 if ( event->doesFloat() ) {
501 if ( event->isMultiDay() ) {
502 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
503 tmpStr += "<td>" +
504 i18n("<beginDate> - <endDate>","%1 - %2").
505 arg( IncidenceFormatter::dateToString( startDt, false ) ).
506 arg( IncidenceFormatter::dateToString( endDt, false ) ) +
507 "</td>";
508 } else {
509 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
510 tmpStr += "<td>" +
511 i18n("date as string","%1").
512 arg( IncidenceFormatter::dateToString( startDt, false ) ) +
513 "</td>";
514 }
515 } else {
516 if ( event->isMultiDay() ) {
517 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
518 tmpStr += "<td>" +
519 i18n("<beginDate> - <endDate>","%1 - %2").
520 arg( IncidenceFormatter::dateToString( startDt, false ) ).
521 arg( IncidenceFormatter::dateToString( endDt, false ) ) +
522 "</td>";
523 } else {
524 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
525 tmpStr += "<td>" +
526 i18n("date as string","%1").
527 arg( IncidenceFormatter::dateToString( startDt, false ) ) +
528 "</td>";
529
530 tmpStr += "</tr><tr>";
531 tmpStr += "<td><b>" + i18n( "Time:" ) + "</b></td>";
532 if ( event->hasEndDate() && startDt != endDt ) {
533 tmpStr += "<td>" +
534 i18n("<beginTime> - <endTime>","%1 - %2").
535 arg( IncidenceFormatter::timeToString( startDt, true ) ).
536 arg( IncidenceFormatter::timeToString( endDt, true ) ) +
537 "</td>";
538 } else {
539 tmpStr += "<td>" +
540 IncidenceFormatter::timeToString( startDt, true ) +
541 "</td>";
542 }
543 }
544 }
545 tmpStr += "</tr>";
546
547 TQString durStr = IncidenceFormatter::durationString( event );
548 if ( !durStr.isEmpty() ) {
549 tmpStr += "<tr>";
550 tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
551 tmpStr += "<td>" + durStr + "</td>";
552 tmpStr += "</tr>";
553 }
554
555 if ( event->doesRecur() ) {
556 tmpStr += "<tr>";
557 tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
558 tmpStr += "<td>" +
559 IncidenceFormatter::recurrenceString( event ) +
560 "</td>";
561 tmpStr += "</tr>";
562 }
563
564 if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
565 tmpStr += "<tr>";
566 if ( event->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
567 tmpStr += "<td><b>" + i18n( "Anniversary:" ) + "</b></td>";
568 } else {
569 tmpStr += "<td><b>" + i18n( "Birthday:" ) + "</b></td>";
570 }
571 tmpStr += "<td>" + displayViewFormatBirthday( event ) + "</td>";
572 tmpStr += "</tr>";
573 tmpStr += "</table>";
574 return tmpStr;
575 }
576
577 if ( !event->description().isEmpty() ) {
578 tmpStr += "<tr>";
579 tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
580 tmpStr += "<td>" + event->description() + "</td>";
581 tmpStr += "</tr>";
582 }
583
584 // TODO: print comments?
585
586 int reminderCount = event->alarms().count();
587 if ( reminderCount > 0 && event->isAlarmEnabled() ) {
588 tmpStr += "<tr>";
589 tmpStr += "<td><b>" +
590 i18n( "Reminder:", "%n Reminders:", reminderCount ) +
591 "</b></td>";
592 tmpStr += "<td>" + IncidenceFormatter::reminderStringList( event ).join( "<br>" ) + "</td>";
593 tmpStr += "</tr>";
594 }
595
596 tmpStr += displayViewFormatAttendees( event );
597
598 int categoryCount = event->categories().count();
599 if ( categoryCount > 0 ) {
600 tmpStr += "<tr>";
601 tmpStr += "<td><b>" +
602 i18n( "Category:", "%n Categories:", categoryCount ) +
603 "</b></td>";
604 tmpStr += "<td>" + displayViewFormatCategories( event ) + "</td>";
605 tmpStr += "</tr>";
606 }
607
608 int attachmentCount = event->attachments().count();
609 if ( attachmentCount > 0 ) {
610 tmpStr += "<tr>";
611 tmpStr += "<td><b>" +
612 i18n( "Attachment:", "%n Attachments:", attachmentCount ) +
613 "</b></td>";
614 tmpStr += "<td>" + displayViewFormatAttachments( event ) + "</td>";
615 tmpStr += "</tr>";
616 }
617 tmpStr += "</table>";
618
619 tmpStr += "<em>" + displayViewFormatCreationDate( event ) + "</em>";
620
621 return tmpStr;
622}
623
624static TQString displayViewFormatTodo( Calendar *calendar, Todo *todo,
625 const TQDate &date )
626{
627 if ( !todo ) {
628 return TQString();
629 }
630
631 TQString tmpStr = displayViewFormatHeader( todo );
632
633 tmpStr += "<table>";
634 tmpStr += "<col width=\"25%\"/>";
635 tmpStr += "<col width=\"75%\"/>";
636
637 if ( calendar ) {
638 TQString calStr = IncidenceFormatter::resourceString( calendar, todo );
639 if ( !calStr.isEmpty() ) {
640 tmpStr += "<tr>";
641 tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
642 tmpStr += "<td>" + calStr + "</td>";
643 tmpStr += "</tr>";
644 }
645 }
646
647 if ( !todo->location().isEmpty() ) {
648 tmpStr += "<tr>";
649 tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
650 tmpStr += "<td>" + todo->location() + "</td>";
651 tmpStr += "</tr>";
652 }
653
654 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
655 TQDateTime startDt = todo->dtStart();
656 if ( todo->doesRecur() ) {
657 if ( date.isValid() ) {
658 startDt.setDate( date );
659 }
660 }
661 tmpStr += "<tr>";
662 tmpStr += "<td><b>" + i18n( "Start:" ) + "</b></td>";
663 tmpStr += "<td>" +
664 IncidenceFormatter::dateTimeToString( startDt,
665 todo->doesFloat(), false ) +
666 "</td>";
667 tmpStr += "</tr>";
668 }
669
670 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
671 TQDateTime dueDt = todo->dtDue();
672 if ( todo->doesRecur() ) {
673 if ( date.isValid() ) {
674 TQDateTime dt( date, TQTime( 0, 0, 0 ) );
675 dt = dt.addSecs( -1 );
676 dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
677 }
678 }
679 tmpStr += "<tr>";
680 tmpStr += "<td><b>" + i18n( "Due:" ) + "</b></td>";
681 tmpStr += "<td>" +
682 IncidenceFormatter::dateTimeToString( dueDt,
683 todo->doesFloat(), false ) +
684 "</td>";
685 tmpStr += "</tr>";
686 }
687
688 TQString durStr = IncidenceFormatter::durationString( todo );
689 if ( !durStr.isEmpty() ) {
690 tmpStr += "<tr>";
691 tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
692 tmpStr += "<td>" + durStr + "</td>";
693 tmpStr += "</tr>";
694 }
695
696 if ( todo->doesRecur() ) {
697 tmpStr += "<tr>";
698 tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
699 tmpStr += "<td>" +
700 IncidenceFormatter::recurrenceString( todo ) +
701 "</td>";
702 tmpStr += "</tr>";
703 }
704
705 if ( !todo->description().isEmpty() ) {
706 tmpStr += "<tr>";
707 tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
708 tmpStr += "<td>" + todo->description() + "</td>";
709 tmpStr += "</tr>";
710 }
711
712 // TODO: print comments?
713
714 int reminderCount = todo->alarms().count();
715 if ( reminderCount > 0 && todo->isAlarmEnabled() ) {
716 tmpStr += "<tr>";
717 tmpStr += "<td><b>" +
718 i18n( "Reminder:", "%n Reminders:", reminderCount ) +
719 "</b></td>";
720 tmpStr += "<td>" + IncidenceFormatter::reminderStringList( todo ).join( "<br>" ) + "</td>";
721 tmpStr += "</tr>";
722 }
723
724 tmpStr += displayViewFormatAttendees( todo );
725
726 int categoryCount = todo->categories().count();
727 if ( categoryCount > 0 ) {
728 tmpStr += "<tr>";
729 tmpStr += "<td><b>" +
730 i18n( "Category:", "%n Categories:", categoryCount ) +
731 "</b></td>";
732 tmpStr += "<td>" + displayViewFormatCategories( todo ) + "</td>";
733 tmpStr += "</tr>";
734 }
735
736 if ( todo->priority() > 0 ) {
737 tmpStr += "<tr>";
738 tmpStr += "<td><b>" + i18n( "Priority:" ) + "</b></td>";
739 tmpStr += "<td>";
740 tmpStr += TQString::number( todo->priority() );
741 tmpStr += "</td>";
742 tmpStr += "</tr>";
743 }
744
745 tmpStr += "<tr>";
746 if ( todo->isCompleted() ) {
747 tmpStr += "<td><b>" + i18n( "Completed:" ) + "</b></td>";
748 tmpStr += "<td>";
749 tmpStr += todo->completedStr();
750 } else {
751 tmpStr += "<td><b>" + i18n( "Percent Done:" ) + "</b></td>";
752 tmpStr += "<td>";
753 tmpStr += i18n( "%1%" ).arg( todo->percentComplete() );
754 }
755 tmpStr += "</td>";
756 tmpStr += "</tr>";
757
758 int attachmentCount = todo->attachments().count();
759 if ( attachmentCount > 0 ) {
760 tmpStr += "<tr>";
761 tmpStr += "<td><b>" +
762 i18n( "Attachment:", "Attachments:", attachmentCount ) +
763 "</b></td>";
764 tmpStr += "<td>" + displayViewFormatAttachments( todo ) + "</td>";
765 tmpStr += "</tr>";
766 }
767
768 tmpStr += "</table>";
769
770 tmpStr += "<em>" + displayViewFormatCreationDate( todo ) + "</em>";
771
772 return tmpStr;
773}
774
775static TQString displayViewFormatJournal( Calendar *calendar, Journal *journal )
776{
777 if ( !journal ) {
778 return TQString();
779 }
780
781 TQString tmpStr = displayViewFormatHeader( journal );
782
783 tmpStr += "<table>";
784 tmpStr += "<col width=\"25%\"/>";
785 tmpStr += "<col width=\"75%\"/>";
786
787 if ( calendar ) {
788 TQString calStr = IncidenceFormatter::resourceString( calendar, journal );
789 if ( !calStr.isEmpty() ) {
790 tmpStr += "<tr>";
791 tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
792 tmpStr += "<td>" + calStr + "</td>";
793 tmpStr += "</tr>";
794 }
795 }
796
797 tmpStr += "<tr>";
798 tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
799 tmpStr += "<td>" +
800 IncidenceFormatter::dateToString( journal->dtStart(), false ) +
801 "</td>";
802 tmpStr += "</tr>";
803
804 if ( !journal->description().isEmpty() ) {
805 tmpStr += "<tr>";
806 tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
807 tmpStr += "<td>" + journal->description() + "</td>";
808 tmpStr += "</tr>";
809 }
810
811 int categoryCount = journal->categories().count();
812 if ( categoryCount > 0 ) {
813 tmpStr += "<tr>";
814 tmpStr += "<td><b>" +
815 i18n( "Category:", "%n Categories:", categoryCount ) +
816 "</b></td>";
817 tmpStr += "<td>" + displayViewFormatCategories( journal ) + "</td>";
818 tmpStr += "</tr>";
819 }
820 tmpStr += "</table>";
821
822 tmpStr += "<em>" + displayViewFormatCreationDate( journal ) + "</em>";
823
824 return tmpStr;
825}
826
827static TQString displayViewFormatFreeBusy( Calendar * /*calendar*/, FreeBusy *fb )
828{
829 if ( !fb ) {
830 return TQString();
831 }
832
833 TQString tmpStr = htmlAddTag( "h2",
834 htmlAddTag( "b",
835 i18n("Free/Busy information for %1").
836 arg( fb->organizer().fullName() ) ) );
837
838 tmpStr += htmlAddTag( "h4", i18n("Busy times in date range %1 - %2:").
839 arg( IncidenceFormatter::dateToString( fb->dtStart(), true ) ).
840 arg( IncidenceFormatter::dateToString( fb->dtEnd(), true ) ) );
841
842 TQValueList<Period> periods = fb->busyPeriods();
843
844 TQString text = htmlAddTag( "em", htmlAddTag( "b", i18n("Busy:") ) );
845 TQValueList<Period>::iterator it;
846 for ( it = periods.begin(); it != periods.end(); ++it ) {
847 Period per = *it;
848 if ( per.hasDuration() ) {
849 int dur = per.duration().asSeconds();
850 TQString cont;
851 if ( dur >= 3600 ) {
852 cont += i18n("1 hour ", "%n hours ", dur / 3600 );
853 dur %= 3600;
854 }
855 if ( dur >= 60 ) {
856 cont += i18n("1 minute ", "%n minutes ", dur / 60);
857 dur %= 60;
858 }
859 if ( dur > 0 ) {
860 cont += i18n("1 second", "%n seconds", dur);
861 }
862 text += i18n("startDate for duration", "%1 for %2").
863 arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
864 arg( cont );
865 text += "<br>";
866 } else {
867 if ( per.start().date() == per.end().date() ) {
868 text += i18n("date, fromTime - toTime ", "%1, %2 - %3").
869 arg( IncidenceFormatter::dateToString( per.start().date(), true ) ).
870 arg( IncidenceFormatter::timeToString( per.start(), true ) ).
871 arg( IncidenceFormatter::timeToString( per.end(), true ) );
872 } else {
873 text += i18n("fromDateTime - toDateTime", "%1 - %2").
874 arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
875 arg( IncidenceFormatter::dateTimeToString( per.end(), false, true ) );
876 }
877 text += "<br>";
878 }
879 }
880 tmpStr += htmlAddTag( "p", text );
881 return tmpStr;
882}
883
884class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
885{
886 public:
887 EventViewerVisitor()
888 : mCalendar( 0 ), mResult( "" ) {}
889
890 bool act( Calendar *calendar, IncidenceBase *incidence, const TQDate &date )
891 {
892 mCalendar = calendar;
893 mDate = date;
894 mResult = "";
895 return incidence->accept( *this );
896 }
897 TQString result() const { return mResult; }
898
899 protected:
900 bool visit( Event *event )
901 {
902 mResult = displayViewFormatEvent( mCalendar, event, mDate );
903 return !mResult.isEmpty();
904 }
905 bool visit( Todo *todo )
906 {
907 mResult = displayViewFormatTodo( mCalendar, todo, mDate );
908 return !mResult.isEmpty();
909 }
910 bool visit( Journal *journal )
911 {
912 mResult = displayViewFormatJournal( mCalendar, journal );
913 return !mResult.isEmpty();
914 }
915 bool visit( FreeBusy *fb )
916 {
917 mResult = displayViewFormatFreeBusy( mCalendar, fb );
918 return !mResult.isEmpty();
919 }
920
921 protected:
922 Calendar *mCalendar;
923 TQDate mDate;
924 TQString mResult;
925};
926
927TQString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
928{
929 return extensiveDisplayStr( 0, incidence, TQDate() );
930}
931
932TQString IncidenceFormatter::extensiveDisplayStr( Calendar *calendar,
933 IncidenceBase *incidence,
934 const TQDate &date )
935{
936 if ( !incidence ) {
937 return TQString();
938 }
939
940 EventViewerVisitor v;
941 if ( v.act( calendar, incidence, date ) ) {
942 return v.result();
943 } else {
944 return TQString();
945 }
946}
947
948/***********************************************************************
949 * Helper functions for the body part formatter of kmail (Invitations)
950 ***********************************************************************/
951
952static TQString string2HTML( const TQString& str )
953{
954 return TQStyleSheet::convertFromPlainText(str, TQStyleSheetItem::WhiteSpaceNormal);
955}
956
957static TQString cleanHtml( const TQString &html )
958{
959 TQRegExp rx( "<body[^>]*>(.*)</body>" );
960 rx.setCaseSensitive( false );
961 rx.search( html );
962 TQString body = rx.cap( 1 );
963
964 return TQStyleSheet::escape( body.remove( TQRegExp( "<[^>]*>" ) ).stripWhiteSpace() );
965}
966
967static TQString eventStartTimeStr( Event *event )
968{
969 TQString tmp;
970 if ( !event->doesFloat() ) {
971 tmp = i18n( "%1: Start Date, %2: Start Time", "%1 %2" ).
972 arg( IncidenceFormatter::dateToString( event->dtStart(), true ),
973 IncidenceFormatter::timeToString( event->dtStart(), true ) );
974 } else {
975 tmp = i18n( "%1: Start Date", "%1 (all day)" ).
976 arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
977 }
978 return tmp;
979}
980
981static TQString eventEndTimeStr( Event *event )
982{
983 TQString tmp;
984 if ( event->hasEndDate() && event->dtEnd().isValid() ) {
985 if ( !event->doesFloat() ) {
986 tmp = i18n( "%1: End Date, %2: End Time", "%1 %2" ).
987 arg( IncidenceFormatter::dateToString( event->dtEnd(), true ),
988 IncidenceFormatter::timeToString( event->dtEnd(), true ) );
989 } else {
990 tmp = i18n( "%1: End Date", "%1 (all day)" ).
991 arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
992 }
993 }
994 return tmp;
995}
996
997static TQString invitationRow( const TQString &cell1, const TQString &cell2 )
998{
999 return "<tr><td>" + cell1 + "</td><td>" + cell2 + "</td></tr>\n";
1000}
1001
1002static Attendee *findDelegatedFromMyAttendee( Incidence *incidence )
1003{
1004 // Return the first attendee that was delegated-from me
1005
1006 Attendee *attendee = 0;
1007 if ( !incidence ) {
1008 return attendee;
1009 }
1010
1011 KEMailSettings settings;
1012 TQStringList profiles = settings.profiles();
1013 for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
1014 settings.setProfile( *it );
1015
1016 TQString delegatorName, delegatorEmail;
1017 Attendee::List attendees = incidence->attendees();
1018 Attendee::List::ConstIterator it2;
1019 for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
1020 Attendee *a = *it2;
1021 KPIM::getNameAndMail( a->delegator(), delegatorName, delegatorEmail );
1022 if ( settings.getSetting( KEMailSettings::EmailAddress ) == delegatorEmail ) {
1023 attendee = a;
1024 break;
1025 }
1026 }
1027 }
1028 return attendee;
1029}
1030
1031static Attendee *findMyAttendee( Incidence *incidence )
1032{
1033 // Return the attendee for the incidence that is probably me
1034
1035 Attendee *attendee = 0;
1036 if ( !incidence ) {
1037 return attendee;
1038 }
1039
1040 KEMailSettings settings;
1041 TQStringList profiles = settings.profiles();
1042 for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
1043 settings.setProfile( *it );
1044
1045 Attendee::List attendees = incidence->attendees();
1046 Attendee::List::ConstIterator it2;
1047 for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
1048 Attendee *a = *it2;
1049 if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->email() ) {
1050 attendee = a;
1051 break;
1052 }
1053 }
1054 }
1055 return attendee;
1056}
1057
1058static Attendee *findAttendee( Incidence *incidence, const TQString &email )
1059{
1060 // Search for an attendee by email address
1061
1062 Attendee *attendee = 0;
1063 if ( !incidence ) {
1064 return attendee;
1065 }
1066
1067 Attendee::List attendees = incidence->attendees();
1068 Attendee::List::ConstIterator it;
1069 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
1070 Attendee *a = *it;
1071 if ( email == a->email() ) {
1072 attendee = a;
1073 break;
1074 }
1075 }
1076 return attendee;
1077}
1078
1079static bool rsvpRequested( Incidence *incidence )
1080{
1081 if ( !incidence ) {
1082 return false;
1083 }
1084
1085 //use a heuristic to determine if a response is requested.
1086
1087 bool rsvp = true; // better send superfluously than not at all
1088 Attendee::List attendees = incidence->attendees();
1089 Attendee::List::ConstIterator it;
1090 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
1091 if ( it == attendees.begin() ) {
1092 rsvp = (*it)->RSVP(); // use what the first one has
1093 } else {
1094 if ( (*it)->RSVP() != rsvp ) {
1095 rsvp = true; // they differ, default
1096 break;
1097 }
1098 }
1099 }
1100 return rsvp;
1101}
1102
1103static TQString rsvpRequestedStr( bool rsvpRequested, const TQString &role )
1104{
1105 if ( rsvpRequested ) {
1106 if ( role.isEmpty() ) {
1107 return i18n( "Your response is requested" );
1108 } else {
1109 return i18n( "Your response as <b>%1</b> is requested" ).arg( role );
1110 }
1111 } else {
1112 if ( role.isEmpty() ) {
1113 return i18n( "No response is necessary" );
1114 } else {
1115 return i18n( "No response as <b>%1</b> is necessary" ).arg( role );
1116 }
1117 }
1118}
1119
1120static TQString myStatusStr( Incidence *incidence )
1121{
1122 TQString ret;
1123 Attendee *a = findMyAttendee( incidence );
1124 if ( a &&
1125 a->status() != Attendee::NeedsAction && a->status() != Attendee::Delegated ) {
1126 ret = i18n( "(<b>Note</b>: the Organizer preset your response to <b>%1</b>)" ).
1127 arg( Attendee::statusName( a->status() ) );
1128 }
1129 return ret;
1130}
1131
1132static TQString invitationPerson( const TQString& email, TQString name, TQString uid )
1133{
1134 // Make the search, if there is an email address to search on,
1135 // and either name or uid is missing
1136 if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
1137 TDEABC::AddressBook *add_book = TDEABC::StdAddressBook::self( true );
1138 TDEABC::Addressee::List addressList = add_book->findByEmail( email );
1139 if ( !addressList.isEmpty() ) {
1140 TDEABC::Addressee o = addressList.first();
1141 if ( !o.isEmpty() && addressList.size() < 2 ) {
1142 if ( name.isEmpty() ) {
1143 // No name set, so use the one from the addressbook
1144 name = o.formattedName();
1145 }
1146 uid = o.uid();
1147 } else {
1148 // Email not found in the addressbook. Don't make a link
1149 uid = TQString();
1150 }
1151 }
1152 }
1153
1154 // Show the attendee
1155 TQString tmpString;
1156 if ( !uid.isEmpty() ) {
1157 // There is a UID, so make a link to the addressbook
1158 if ( name.isEmpty() ) {
1159 // Use the email address for text
1160 tmpString += htmlAddLink( "uid:" + uid, email );
1161 } else {
1162 tmpString += htmlAddLink( "uid:" + uid, name );
1163 }
1164 } else {
1165 // No UID, just show some text
1166 tmpString += ( name.isEmpty() ? email : name );
1167 }
1168 tmpString += '\n';
1169
1170 // Make the mailto link
1171 if ( !email.isEmpty() ) {
1172 KCal::Person person( name, email );
1173 KURL mailto;
1174 mailto.setProtocol( "mailto" );
1175 mailto.setPath( person.fullName() );
1176 const TQString iconPath =
1177 TDEGlobal::iconLoader()->iconPath( "mail-message-new", TDEIcon::Small );
1178 tmpString += "&nbsp;" +
1179 htmlAddLink( mailto.url(), "<img src=\"" + iconPath + "\">" )
1180;
1181 }
1182 tmpString += "\n";
1183
1184 return tmpString;
1185}
1186
1187static TQString invitationsDetailsIncidence( Incidence *incidence, bool noHtmlMode )
1188{
1189 // if description and comment -> use both
1190 // if description, but no comment -> use the desc as the comment (and no desc)
1191 // if comment, but no description -> use the comment and no description
1192
1193 TQString html;
1194 TQString descr;
1195 TQStringList comments;
1196
1197 if ( incidence->comments().isEmpty() ) {
1198 if ( !incidence->description().isEmpty() ) {
1199 // use description as comments
1200 if ( !TQStyleSheet::mightBeRichText( incidence->description() ) ) {
1201 comments << string2HTML( incidence->description() );
1202 } else {
1203 comments << incidence->description();
1204 if ( noHtmlMode ) {
1205 comments[0] = cleanHtml( comments[0] );
1206 }
1207 comments[0] = htmlAddTag( "p", comments[0] );
1208 }
1209 }
1210 //else desc and comments are empty
1211 } else {
1212 // non-empty comments
1213 TQStringList cl = incidence->comments();
1214 uint i = 0;
1215 for( TQStringList::Iterator it=cl.begin(); it!=cl.end(); ++it ) {
1216 if ( !TQStyleSheet::mightBeRichText( *it ) ) {
1217 comments.append( string2HTML( *it ) );
1218 } else {
1219 if ( noHtmlMode ) {
1220 comments.append( cleanHtml( "<body>" + (*it) + "</body>" ) );
1221 } else {
1222 comments.append( *it );
1223 }
1224 }
1225 i++;
1226 }
1227 if ( !incidence->description().isEmpty() ) {
1228 // use description too
1229 if ( !TQStyleSheet::mightBeRichText( incidence->description() ) ) {
1230 descr = string2HTML( incidence->description() );
1231 } else {
1232 descr = incidence->description();
1233 if ( noHtmlMode ) {
1234 descr = cleanHtml( descr );
1235 }
1236 descr = htmlAddTag( "p", descr );
1237 }
1238 }
1239 }
1240
1241 if( !descr.isEmpty() ) {
1242 html += "<p>";
1243 html += "<table border=\"0\" style=\"margin-top:4px;\">";
1244 html += "<tr><td><center>" +
1245 htmlAddTag( "u", i18n( "Description:" ) ) +
1246 "</center></td></tr>";
1247 html += "<tr><td>" + descr + "</td></tr>";
1248 html += "</table>";
1249 }
1250
1251 if ( !comments.isEmpty() ) {
1252 html += "<p>";
1253 html += "<table border=\"0\" style=\"margin-top:4px;\">";
1254 html += "<tr><td><center>" +
1255 htmlAddTag( "u", i18n( "Comments:" ) ) +
1256 "</center></td></tr>";
1257 html += "<tr><td>";
1258 if ( comments.count() > 1 ) {
1259 html += "<ul>";
1260 for ( uint i=0; i < comments.count(); ++i ) {
1261 html += "<li>" + comments[i] + "</li>";
1262 }
1263 html += "</ul>";
1264 } else {
1265 html += comments[0];
1266 }
1267 html += "</td></tr>";
1268 html += "</table>";
1269 }
1270 return html;
1271}
1272
1273static TQString invitationDetailsEvent( Event* event, bool noHtmlMode )
1274{
1275 // Invitation details are formatted into an HTML table
1276 if ( !event ) {
1277 return TQString();
1278 }
1279
1280 TQString sSummary = i18n( "Summary unspecified" );
1281 if ( !event->summary().isEmpty() ) {
1282 if ( !TQStyleSheet::mightBeRichText( event->summary() ) ) {
1283 sSummary = TQStyleSheet::escape( event->summary() );
1284 } else {
1285 sSummary = event->summary();
1286 if ( noHtmlMode ) {
1287 sSummary = cleanHtml( sSummary );
1288 }
1289 }
1290 }
1291
1292 TQString sLocation = i18n( "Location unspecified" );
1293 if ( !event->location().isEmpty() ) {
1294 if ( !TQStyleSheet::mightBeRichText( event->location() ) ) {
1295 sLocation = TQStyleSheet::escape( event->location() );
1296 } else {
1297 sLocation = event->location();
1298 if ( noHtmlMode ) {
1299 sLocation = cleanHtml( sLocation );
1300 }
1301 }
1302 }
1303
1304 TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
1305 TQString html = TQString("<div dir=\"%1\">\n").arg(dir);
1306
1307 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
1308
1309 // Invitation summary & location rows
1310 html += invitationRow( i18n( "What:" ), sSummary );
1311 html += invitationRow( i18n( "Where:" ), sLocation );
1312
1313 if (event->doesRecur() == true) {
1314 html += invitationRow( i18n( "First Start Time:" ), eventStartTimeStr( event ) );
1315 html += invitationRow( i18n( "First End Time:" ), eventEndTimeStr( event ) );
1316 }
1317// else {
1318 // If a 1 day event
1319 if ( event->dtStart().date() == event->dtEnd().date() ) {
1320 html += invitationRow( i18n( "Date:" ),
1321 IncidenceFormatter::dateToString( event->dtStart(), false ) );
1322 if ( !event->doesFloat() ) {
1323 html += invitationRow( i18n( "Time:" ),
1324 IncidenceFormatter::timeToString( event->dtStart(), true ) +
1325 " - " +
1326 IncidenceFormatter::timeToString( event->dtEnd(), true ) );
1327 }
1328 } else {
1329 html += invitationRow( i18n( "Starting date of an event", "From:" ),
1330 IncidenceFormatter::dateToString( event->dtStart(), false ) );
1331 if ( !event->doesFloat() ) {
1332 html += invitationRow( i18n( "Starting time of an event", "At:" ),
1333 IncidenceFormatter::timeToString( event->dtStart(), true ) );
1334 }
1335 if ( event->hasEndDate() ) {
1336 html += invitationRow( i18n( "Ending date of an event", "To:" ),
1337 IncidenceFormatter::dateToString( event->dtEnd(), false ) );
1338 if ( !event->doesFloat() ) {
1339 html += invitationRow( i18n( "Starting time of an event", "At:" ),
1340 IncidenceFormatter::timeToString( event->dtEnd(), true ) );
1341 }
1342 } else {
1343 html += invitationRow( i18n( "Ending date of an event", "To:" ),
1344 i18n( "no end date specified" ) );
1345 }
1346 }
1347// }
1348
1349 // Invitation Duration Row
1350 TQString durStr = IncidenceFormatter::durationString( event );
1351 if ( !durStr.isEmpty() ) {
1352 html += invitationRow( i18n( "Duration:" ), durStr );
1353 }
1354
1355 // Recurrence Information Rows
1356 if ( event->doesRecur() ) {
1357 Recurrence *recur = event->recurrence();
1358 html += invitationRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( event ) );
1359
1360 DateList exceptions = recur->exDates();
1361 if (exceptions.isEmpty() == false) {
1362 bool isFirstExRow;
1363 isFirstExRow = true;
1364 DateList::ConstIterator ex_iter;
1365 for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
1366 if (isFirstExRow == true) {
1367 isFirstExRow = false;
1368 html += invitationRow( i18n("Cancelled on:"), TDEGlobal::locale()->formatDate(* ex_iter ) );
1369 }
1370 else {
1371 html += invitationRow(" ", TDEGlobal::locale()->formatDate(* ex_iter ) );
1372 }
1373 }
1374 }
1375 }
1376
1377 html += "</table>\n";
1378 html += invitationsDetailsIncidence( event, noHtmlMode );
1379 html += "</div>\n";
1380
1381 return html;
1382}
1383
1384static TQString invitationDetailsTodo( Todo *todo, bool noHtmlMode )
1385{
1386 // Task details are formatted into an HTML table
1387 if ( !todo ) {
1388 return TQString();
1389 }
1390
1391 TQString sSummary = i18n( "Summary unspecified" );
1392 if ( !todo->summary().isEmpty() ) {
1393 if ( !TQStyleSheet::mightBeRichText( todo->summary() ) ) {
1394 sSummary = TQStyleSheet::escape( todo->summary() );
1395 } else {
1396 sSummary = todo->summary();
1397 if ( noHtmlMode ) {
1398 sSummary = cleanHtml( sSummary );
1399 }
1400 }
1401 }
1402
1403 TQString sLocation = i18n( "Location unspecified" );
1404 if ( !todo->location().isEmpty() ) {
1405 if ( !TQStyleSheet::mightBeRichText( todo->location() ) ) {
1406 sLocation = TQStyleSheet::escape( todo->location() );
1407 } else {
1408 sLocation = todo->location();
1409 if ( noHtmlMode ) {
1410 sLocation = cleanHtml( sLocation );
1411 }
1412 }
1413 }
1414
1415 TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
1416 TQString html = TQString("<div dir=\"%1\">\n").arg(dir);
1417 html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
1418
1419 // Invitation summary & location rows
1420 html += invitationRow( i18n( "What:" ), sSummary );
1421 html += invitationRow( i18n( "Where:" ), sLocation );
1422
1423 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
1424 html += invitationRow( i18n( "Start Date:" ),
1425 IncidenceFormatter::dateToString( todo->dtStart(), false ) );
1426 if ( !todo->doesFloat() ) {
1427 html += invitationRow( i18n( "Start Time:" ),
1428 IncidenceFormatter::timeToString( todo->dtStart(), false ) );
1429 }
1430 }
1431 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
1432 html += invitationRow( i18n( "Due Date:" ),
1433 IncidenceFormatter::dateToString( todo->dtDue(), false ) );
1434 if ( !todo->doesFloat() ) {
1435 html += invitationRow( i18n( "Due Time:" ),
1436 IncidenceFormatter::timeToString( todo->dtDue(), false ) );
1437 }
1438
1439 } else {
1440 html += invitationRow( i18n( "Due Date:" ), i18n( "Due Date: None", "None" ) );
1441 }
1442
1443 html += "</table></div>\n";
1444 html += invitationsDetailsIncidence( todo, noHtmlMode );
1445
1446 return html;
1447}
1448
1449static TQString invitationDetailsJournal( Journal *journal, bool noHtmlMode )
1450{
1451 if ( !journal ) {
1452 return TQString();
1453 }
1454
1455 TQString sSummary = i18n( "Summary unspecified" );
1456 TQString sDescr = i18n( "Description unspecified" );
1457 if ( ! journal->summary().isEmpty() ) {
1458 sSummary = journal->summary();
1459 if ( noHtmlMode ) {
1460 sSummary = cleanHtml( sSummary );
1461 }
1462 }
1463 if ( ! journal->description().isEmpty() ) {
1464 sDescr = journal->description();
1465 if ( noHtmlMode ) {
1466 sDescr = cleanHtml( sDescr );
1467 }
1468 }
1469 TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
1470 html += invitationRow( i18n( "Summary:" ), sSummary );
1471 html += invitationRow( i18n( "Date:" ),
1472 IncidenceFormatter::dateToString( journal->dtStart(), false ) );
1473 html += invitationRow( i18n( "Description:" ), sDescr );
1474 html += "</table>\n";
1475 html += invitationsDetailsIncidence( journal, noHtmlMode );
1476
1477 return html;
1478}
1479
1480static TQString invitationDetailsFreeBusy( FreeBusy *fb, bool /*noHtmlMode*/ )
1481{
1482 if ( !fb )
1483 return TQString();
1484 TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
1485
1486 html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
1487 html += invitationRow( i18n("Start date:"),
1488 IncidenceFormatter::dateToString( fb->dtStart(), true ) );
1489 html += invitationRow( i18n("End date:"),
1490 TDEGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
1491 html += "<tr><td colspan=2><hr></td></tr>\n";
1492 html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
1493
1494 TQValueList<Period> periods = fb->busyPeriods();
1495
1496 TQValueList<Period>::iterator it;
1497 for ( it = periods.begin(); it != periods.end(); ++it ) {
1498 Period per = *it;
1499 if ( per.hasDuration() ) {
1500 int dur = per.duration().asSeconds();
1501 TQString cont;
1502 if ( dur >= 3600 ) {
1503 cont += i18n("1 hour ", "%n hours ", dur / 3600);
1504 dur %= 3600;
1505 }
1506 if ( dur >= 60 ) {
1507 cont += i18n("1 minute", "%n minutes ", dur / 60);
1508 dur %= 60;
1509 }
1510 if ( dur > 0 ) {
1511 cont += i18n("1 second", "%n seconds", dur);
1512 }
1513 html += invitationRow( TQString(), i18n("startDate for duration", "%1 for %2")
1514 .arg( TDEGlobal::locale()->formatDateTime( per.start(), false ) )
1515 .arg(cont) );
1516 } else {
1517 TQString cont;
1518 if ( per.start().date() == per.end().date() ) {
1519 cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
1520 .arg( TDEGlobal::locale()->formatDate( per.start().date() ) )
1521 .arg( TDEGlobal::locale()->formatTime( per.start().time() ) )
1522 .arg( TDEGlobal::locale()->formatTime( per.end().time() ) );
1523 } else {
1524 cont = i18n("fromDateTime - toDateTime", "%1 - %2")
1525 .arg( TDEGlobal::locale()->formatDateTime( per.start(), false ) )
1526 .arg( TDEGlobal::locale()->formatDateTime( per.end(), false ) );
1527 }
1528
1529 html += invitationRow( TQString(), cont );
1530 }
1531 }
1532
1533 html += "</table>\n";
1534 return html;
1535}
1536
1537static bool replyMeansCounter( Incidence */*incidence*/ )
1538{
1539 return false;
1554}
1555
1556static TQString invitationHeaderEvent( Event *event, Incidence *existingIncidence,
1557 ScheduleMessage *msg, const TQString &sender )
1558{
1559 if ( !msg || !event )
1560 return TQString();
1561
1562 switch ( msg->method() ) {
1563 case Scheduler::Publish:
1564 return i18n( "This invitation has been published" );
1565 case Scheduler::Request:
1566 if ( existingIncidence && event->revision() > 0 ) {
1567 return i18n( "This invitation has been updated by the organizer %1" ).
1568 arg( event->organizer().fullName() );
1569 }
1570 if ( iamOrganizer( event ) ) {
1571 return i18n( "I created this invitation" );
1572 } else {
1573 TQString orgStr;
1574 if ( !event->organizer().fullName().isEmpty() ) {
1575 orgStr = event->organizer().fullName();
1576 } else if ( !event->organizer().email().isEmpty() ) {
1577 orgStr = event->organizer().email();
1578 }
1579 if ( senderIsOrganizer( event, sender ) ) {
1580 if ( !orgStr.isEmpty() ) {
1581 return i18n( "You received an invitation from %1" ).arg( orgStr );
1582 } else {
1583 return i18n( "You received an invitation" );
1584 }
1585 } else {
1586 if ( !orgStr.isEmpty() ) {
1587 return i18n( "You received an invitation from %1 as a representative of %2" ).
1588 arg( sender, orgStr );
1589 } else {
1590 return i18n( "You received an invitation from %1 as the organizer's representative" ).
1591 arg( sender );
1592 }
1593 }
1594 }
1595 case Scheduler::Refresh:
1596 return i18n( "This invitation was refreshed" );
1597 case Scheduler::Cancel:
1598 return i18n( "This invitation has been canceled" );
1599 case Scheduler::Add:
1600 return i18n( "Addition to the invitation" );
1601 case Scheduler::Reply:
1602 {
1603 if ( replyMeansCounter( event ) ) {
1604 return i18n( "%1 makes this counter proposal" ).
1605 arg( firstAttendeeName( event, i18n( "Sender" ) ) );
1606 }
1607
1608 Attendee::List attendees = event->attendees();
1609 if( attendees.count() == 0 ) {
1610 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
1611 return TQString();
1612 }
1613 if( attendees.count() != 1 ) {
1614 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
1615 << "but is " << attendees.count() << endl;
1616 }
1617 TQString attendeeName = firstAttendeeName( event, i18n( "Sender" ) );
1618
1619 TQString delegatorName, dummy;
1620 Attendee* attendee = *attendees.begin();
1621 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
1622 if ( delegatorName.isEmpty() ) {
1623 delegatorName = attendee->delegator();
1624 }
1625
1626 switch( attendee->status() ) {
1627 case Attendee::NeedsAction:
1628 return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
1629 case Attendee::Accepted:
1630 if ( event->revision() > 0 ) {
1631 if ( !sender.isEmpty() ) {
1632 return i18n( "This invitation has been updated by attendee %1" ).arg( sender );
1633 } else {
1634 return i18n( "This invitation has been updated by an attendee" );
1635 }
1636 } else {
1637 if ( delegatorName.isEmpty() ) {
1638 return i18n( "%1 accepts this invitation" ).arg( attendeeName );
1639 } else {
1640 return i18n( "%1 accepts this invitation on behalf of %2" ).
1641 arg( attendeeName ).arg( delegatorName );
1642 }
1643 }
1644 case Attendee::Tentative:
1645 if ( delegatorName.isEmpty() ) {
1646 return i18n( "%1 tentatively accepts this invitation" ).
1647 arg( attendeeName );
1648 } else {
1649 return i18n( "%1 tentatively accepts this invitation on behalf of %2" ).
1650 arg( attendeeName ).arg( delegatorName );
1651 }
1652 case Attendee::Declined:
1653 if ( delegatorName.isEmpty() ) {
1654 return i18n( "%1 declines this invitation" ).arg( attendeeName );
1655 } else {
1656 return i18n( "%1 declines this invitation on behalf of %2" ).
1657 arg( attendeeName ).arg( delegatorName );
1658 }
1659 case Attendee::Delegated: {
1660 TQString delegate, dummy;
1661 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
1662 if ( delegate.isEmpty() ) {
1663 delegate = attendee->delegate();
1664 }
1665 if ( !delegate.isEmpty() ) {
1666 return i18n( "%1 has delegated this invitation to %2" ).
1667 arg( attendeeName ) .arg( delegate );
1668 } else {
1669 return i18n( "%1 has delegated this invitation" ).arg( attendeeName );
1670 }
1671 }
1672 case Attendee::Completed:
1673 return i18n( "This invitation is now completed" );
1674 case Attendee::InProcess:
1675 return i18n( "%1 is still processing the invitation" ).
1676 arg( attendeeName );
1677 default:
1678 return i18n( "Unknown response to this invitation" );
1679 }
1680 break;
1681 }
1682
1683 case Scheduler::Counter:
1684 return i18n( "%1 makes this counter proposal" ).
1685 arg( firstAttendeeName( event, i18n( "Sender" ) ) );
1686
1687 case Scheduler::Declinecounter:
1688 return i18n( "%1 declines the counter proposal" ).
1689 arg( firstAttendeeName( event, i18n( "Sender" ) ) );
1690
1691 case Scheduler::NoMethod:
1692 return i18n("Error: iMIP message with unknown method: '%1'").
1693 arg( msg->method() );
1694 }
1695 return TQString();
1696}
1697
1698static TQString invitationHeaderTodo( Todo *todo, Incidence *existingIncidence,
1699 ScheduleMessage *msg, const TQString &sender )
1700{
1701 if ( !msg || !todo ) {
1702 return TQString();
1703 }
1704
1705 switch ( msg->method() ) {
1706 case Scheduler::Publish:
1707 return i18n("This task has been published");
1708 case Scheduler::Request:
1709 if ( existingIncidence && todo->revision() > 0 ) {
1710 return i18n( "This task has been updated by the organizer %1" ).
1711 arg( todo->organizer().fullName() );
1712 } else {
1713 if ( iamOrganizer( todo ) ) {
1714 return i18n( "I created this task" );
1715 } else {
1716 TQString orgStr;
1717 if ( !todo->organizer().fullName().isEmpty() ) {
1718 orgStr = todo->organizer().fullName();
1719 } else if ( !todo->organizer().email().isEmpty() ) {
1720 orgStr = todo->organizer().email();
1721 }
1722 if ( senderIsOrganizer( todo, sender ) ) {
1723 if ( !orgStr.isEmpty() ) {
1724 return i18n( "You have been assigned this task by %1" ).arg( orgStr );
1725 } else {
1726 return i18n( "You have been assigned this task" );
1727 }
1728 } else {
1729 if ( !orgStr.isEmpty() ) {
1730 return i18n( "You have been assigned this task by %1 as a representative of %2" ).
1731 arg( sender, orgStr );
1732 } else {
1733 return i18n( "You have been assigned this task by %1 as the organizer's representative" ).
1734 arg( sender );
1735 }
1736 }
1737 }
1738 }
1739 case Scheduler::Refresh:
1740 return i18n( "This task was refreshed" );
1741 case Scheduler::Cancel:
1742 return i18n( "This task was canceled" );
1743 case Scheduler::Add:
1744 return i18n( "Addition to the task" );
1745 case Scheduler::Reply:
1746 {
1747 if ( replyMeansCounter( todo ) ) {
1748 return i18n( "%1 makes this counter proposal" ).
1749 arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
1750 }
1751
1752 Attendee::List attendees = todo->attendees();
1753 if( attendees.count() == 0 ) {
1754 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
1755 return TQString();
1756 }
1757 if( attendees.count() != 1 ) {
1758 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
1759 << "but is " << attendees.count() << endl;
1760 }
1761 TQString attendeeName = firstAttendeeName( todo, i18n( "Sender" ) );
1762
1763 TQString delegatorName, dummy;
1764 Attendee* attendee = *attendees.begin();
1765 KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
1766 if ( delegatorName.isEmpty() ) {
1767 delegatorName = attendee->delegator();
1768 }
1769
1770 switch( attendee->status() ) {
1771 case Attendee::NeedsAction:
1772 return i18n( "%1 indicates this task assignment still needs some action" ).arg( attendeeName );
1773 case Attendee::Accepted:
1774 if ( todo->revision() > 0 ) {
1775 if ( !sender.isEmpty() ) {
1776 if ( todo->isCompleted() ) {
1777 return i18n( "This task has been completed by assignee %1" ).arg( sender );
1778 } else {
1779 return i18n( "This task has been updated by assignee %1" ).arg( sender );
1780 }
1781 } else {
1782 if ( todo->isCompleted() ) {
1783 return i18n( "This task has been completed by an assignee" );
1784 } else {
1785 return i18n( "This task has been updated by an assignee" );
1786 }
1787 }
1788 } else {
1789 if ( delegatorName.isEmpty() ) {
1790 return i18n( "%1 accepts this task" ).arg( attendeeName );
1791 } else {
1792 return i18n( "%1 accepts this task on behalf of %2" ).
1793 arg( attendeeName ).arg( delegatorName );
1794 }
1795 }
1796 case Attendee::Tentative:
1797 if ( delegatorName.isEmpty() ) {
1798 return i18n( "%1 tentatively accepts this task" ).
1799 arg( attendeeName );
1800 } else {
1801 return i18n( "%1 tentatively accepts this task on behalf of %2" ).
1802 arg( attendeeName ).arg( delegatorName );
1803 }
1804 case Attendee::Declined:
1805 if ( delegatorName.isEmpty() ) {
1806 return i18n( "%1 declines this task" ).arg( attendeeName );
1807 } else {
1808 return i18n( "%1 declines this task on behalf of %2" ).
1809 arg( attendeeName ).arg( delegatorName );
1810 }
1811 case Attendee::Delegated: {
1812 TQString delegate, dummy;
1813 KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
1814 if ( delegate.isEmpty() ) {
1815 delegate = attendee->delegate();
1816 }
1817 if ( !delegate.isEmpty() ) {
1818 return i18n( "%1 has delegated this request for the task to %2" ).
1819 arg( attendeeName ).arg( delegate );
1820 } else {
1821 return i18n( "%1 has delegated this request for the task" ).
1822 arg( attendeeName );
1823 }
1824 }
1825 case Attendee::Completed:
1826 return i18n( "The request for this task is now completed" );
1827 case Attendee::InProcess:
1828 return i18n( "%1 is still processing the task" ).
1829 arg( attendeeName );
1830 default:
1831 return i18n( "Unknown response to this task" );
1832 }
1833 break;
1834 }
1835
1836 case Scheduler::Counter:
1837 return i18n( "%1 makes this counter proposal" ).
1838 arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
1839
1840 case Scheduler::Declinecounter:
1841 return i18n( "%1 declines the counter proposal" ).
1842 arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
1843
1844 case Scheduler::NoMethod:
1845 return i18n( "Error: iMIP message with unknown method: '%1'" ).
1846 arg( msg->method() );
1847 }
1848 return TQString();
1849}
1850
1851static TQString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
1852{
1853 if ( !msg || !journal ) {
1854 return TQString();
1855 }
1856
1857 switch ( msg->method() ) {
1858 case Scheduler::Publish:
1859 return i18n("This journal has been published");
1860 case Scheduler::Request:
1861 return i18n( "You have been assigned this journal" );
1862 case Scheduler::Refresh:
1863 return i18n( "This journal was refreshed" );
1864 case Scheduler::Cancel:
1865 return i18n( "This journal was canceled" );
1866 case Scheduler::Add:
1867 return i18n( "Addition to the journal" );
1868 case Scheduler::Reply:
1869 {
1870 if ( replyMeansCounter( journal ) ) {
1871 return i18n( "Sender makes this counter proposal" );
1872 }
1873
1874 Attendee::List attendees = journal->attendees();
1875 if( attendees.count() == 0 ) {
1876 kdDebug(5850) << "No attendees in the iCal reply!" << endl;
1877 return TQString();
1878 }
1879 if( attendees.count() != 1 ) {
1880 kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
1881 << "but is " << attendees.count() << endl;
1882 }
1883 Attendee* attendee = *attendees.begin();
1884
1885 switch( attendee->status() ) {
1886 case Attendee::NeedsAction:
1887 return i18n( "Sender indicates this journal assignment still needs some action" );
1888 case Attendee::Accepted:
1889 return i18n( "Sender accepts this journal" );
1890 case Attendee::Tentative:
1891 return i18n( "Sender tentatively accepts this journal" );
1892 case Attendee::Declined:
1893 return i18n( "Sender declines this journal" );
1894 case Attendee::Delegated:
1895 return i18n( "Sender has delegated this request for the journal" );
1896 case Attendee::Completed:
1897 return i18n( "The request for this journal is now completed" );
1898 case Attendee::InProcess:
1899 return i18n( "Sender is still processing the invitation" );
1900 default:
1901 return i18n( "Unknown response to this journal" );
1902 }
1903 break;
1904 }
1905 case Scheduler::Counter:
1906 return i18n( "Sender makes this counter proposal" );
1907 case Scheduler::Declinecounter:
1908 return i18n( "Sender declines the counter proposal" );
1909 case Scheduler::NoMethod:
1910 return i18n("Error: iMIP message with unknown method: '%1'").
1911 arg( msg->method() );
1912 }
1913 return TQString();
1914}
1915
1916static TQString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
1917{
1918 if ( !msg || !fb ) {
1919 return TQString();
1920 }
1921
1922 switch ( msg->method() ) {
1923 case Scheduler::Publish:
1924 return i18n("This free/busy list has been published");
1925 case Scheduler::Request:
1926 return i18n( "The free/busy list has been requested" );
1927 case Scheduler::Refresh:
1928 return i18n( "This free/busy list was refreshed" );
1929 case Scheduler::Cancel:
1930 return i18n( "This free/busy list was canceled" );
1931 case Scheduler::Add:
1932 return i18n( "Addition to the free/busy list" );
1933 case Scheduler::NoMethod:
1934 default:
1935 return i18n("Error: Free/Busy iMIP message with unknown method: '%1'").
1936 arg( msg->method() );
1937 }
1938}
1939
1940static TQString invitationAttendees( Incidence *incidence )
1941{
1942 TQString tmpStr;
1943 if ( !incidence ) {
1944 return tmpStr;
1945 }
1946
1947 if ( incidence->type() == "Todo" ) {
1948 tmpStr += htmlAddTag( "u", i18n( "Assignees" ) );
1949 } else {
1950 tmpStr += htmlAddTag( "u", i18n( "Attendees" ) );
1951 }
1952 tmpStr += "<br/>";
1953
1954 int count=0;
1955 Attendee::List attendees = incidence->attendees();
1956 if ( !attendees.isEmpty() ) {
1957
1958 Attendee::List::ConstIterator it;
1959 for( it = attendees.begin(); it != attendees.end(); ++it ) {
1960 Attendee *a = *it;
1961 if ( !iamAttendee( a ) ) {
1962 count++;
1963 if ( count == 1 ) {
1964 tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"2\">";
1965 }
1966 tmpStr += "<tr>";
1967 tmpStr += "<td>";
1968 tmpStr += invitationPerson( a->email(), a->name(), TQString() );
1969 if ( !a->delegator().isEmpty() ) {
1970 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
1971 }
1972 if ( !a->delegate().isEmpty() ) {
1973 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
1974 }
1975 tmpStr += "</td>";
1976 tmpStr += "<td>" + a->statusStr() + "</td>";
1977 tmpStr += "</tr>";
1978 }
1979 }
1980 }
1981 if ( count ) {
1982 tmpStr += "</table>";
1983 } else {
1984 tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
1985 }
1986
1987 return tmpStr;
1988}
1989
1990static TQString invitationAttachments( InvitationFormatterHelper *helper, Incidence *incidence )
1991{
1992 TQString tmpStr;
1993 if ( !incidence ) {
1994 return tmpStr;
1995 }
1996
1997 Attachment::List attachments = incidence->attachments();
1998 if ( !attachments.isEmpty() ) {
1999 tmpStr += i18n( "Attached Documents:" ) + "<ol>";
2000
2001 Attachment::List::ConstIterator it;
2002 for( it = attachments.begin(); it != attachments.end(); ++it ) {
2003 Attachment *a = *it;
2004 tmpStr += "<li>";
2005 // Attachment icon
2006 KMimeType::Ptr mimeType = KMimeType::mimeType( a->mimeType() );
2007 const TQString iconStr = mimeType ? mimeType->icon( a->uri(), false ) : TQString( "application-octet-stream" );
2008 const TQString iconPath = TDEGlobal::iconLoader()->iconPath( iconStr, TDEIcon::Small );
2009 if ( !iconPath.isEmpty() ) {
2010 tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
2011 }
2012 tmpStr += helper->makeLink( "ATTACH:" + a->label(), a->label() );
2013 tmpStr += "</li>";
2014 }
2015 tmpStr += "</ol>";
2016 }
2017
2018 return tmpStr;
2019}
2020
2021class IncidenceFormatter::ScheduleMessageVisitor
2022 : public IncidenceBase::Visitor
2023{
2024 public:
2025 ScheduleMessageVisitor() : mExistingIncidence( 0 ), mMessage( 0 ) { mResult = ""; }
2026 bool act( IncidenceBase *incidence, Incidence *existingIncidence, ScheduleMessage *msg,
2027 const TQString &sender )
2028 {
2029 mExistingIncidence = existingIncidence;
2030 mMessage = msg;
2031 mSender = sender;
2032 return incidence->accept( *this );
2033 }
2034 TQString result() const { return mResult; }
2035
2036 protected:
2037 TQString mResult;
2038 Incidence *mExistingIncidence;
2039 ScheduleMessage *mMessage;
2040 TQString mSender;
2041};
2042
2043class IncidenceFormatter::InvitationHeaderVisitor
2044 : public IncidenceFormatter::ScheduleMessageVisitor
2045{
2046 protected:
2047 bool visit( Event *event )
2048 {
2049 mResult = invitationHeaderEvent( event, mExistingIncidence, mMessage, mSender );
2050 return !mResult.isEmpty();
2051 }
2052 bool visit( Todo *todo )
2053 {
2054 mResult = invitationHeaderTodo( todo, mExistingIncidence, mMessage, mSender );
2055 return !mResult.isEmpty();
2056 }
2057 bool visit( Journal *journal )
2058 {
2059 mResult = invitationHeaderJournal( journal, mMessage );
2060 return !mResult.isEmpty();
2061 }
2062 bool visit( FreeBusy *fb )
2063 {
2064 mResult = invitationHeaderFreeBusy( fb, mMessage );
2065 return !mResult.isEmpty();
2066 }
2067};
2068
2069class IncidenceFormatter::InvitationBodyVisitor
2070 : public IncidenceFormatter::ScheduleMessageVisitor
2071{
2072 public:
2073 InvitationBodyVisitor( bool noHtmlMode )
2074 : ScheduleMessageVisitor(), mNoHtmlMode( noHtmlMode ) {}
2075
2076 protected:
2077 bool visit( Event *event )
2078 {
2079 mResult = invitationDetailsEvent( event, mNoHtmlMode );
2080 return !mResult.isEmpty();
2081 }
2082 bool visit( Todo *todo )
2083 {
2084 mResult = invitationDetailsTodo( todo, mNoHtmlMode );
2085 return !mResult.isEmpty();
2086 }
2087 bool visit( Journal *journal )
2088 {
2089 mResult = invitationDetailsJournal( journal, mNoHtmlMode );
2090 return !mResult.isEmpty();
2091 }
2092 bool visit( FreeBusy *fb )
2093 {
2094 mResult = invitationDetailsFreeBusy( fb, mNoHtmlMode );
2095 return !mResult.isEmpty();
2096 }
2097
2098 private:
2099 bool mNoHtmlMode;
2100};
2101
2102class IncidenceFormatter::IncidenceCompareVisitor
2103 : public IncidenceBase::Visitor
2104{
2105 public:
2106 IncidenceCompareVisitor() : mExistingIncidence(0) {}
2107 bool act( IncidenceBase *incidence, Incidence *existingIncidence, int method )
2108 {
2109 Incidence *inc = dynamic_cast<Incidence*>( incidence );
2110 if ( !inc || !existingIncidence || inc->revision() <= existingIncidence->revision() )
2111 return false;
2112 mExistingIncidence = existingIncidence;
2113 mMethod = method;
2114 return incidence->accept( *this );
2115 }
2116
2117 TQString result() const
2118 {
2119 if ( mChanges.isEmpty() ) {
2120 return TQString();
2121 }
2122 TQString html = "<div align=\"left\"><ul><li>";
2123 html += mChanges.join( "</li><li>" );
2124 html += "</li><ul></div>";
2125 return html;
2126 }
2127
2128 protected:
2129 bool visit( Event *event )
2130 {
2131 compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
2132 compareIncidences( event, mExistingIncidence, mMethod );
2133 return !mChanges.isEmpty();
2134 }
2135 bool visit( Todo *todo )
2136 {
2137 compareTodos( todo, dynamic_cast<Todo*>( mExistingIncidence ) );
2138 compareIncidences( todo, mExistingIncidence, mMethod );
2139 return !mChanges.isEmpty();
2140 }
2141 bool visit( Journal *journal )
2142 {
2143 compareIncidences( journal, mExistingIncidence, mMethod );
2144 return !mChanges.isEmpty();
2145 }
2146 bool visit( FreeBusy *fb )
2147 {
2148 Q_UNUSED( fb );
2149 return !mChanges.isEmpty();
2150 }
2151
2152 private:
2153 void compareEvents( Event *newEvent, Event *oldEvent )
2154 {
2155 if ( !oldEvent || !newEvent )
2156 return;
2157 if ( oldEvent->dtStart() != newEvent->dtStart() || oldEvent->doesFloat() != newEvent->doesFloat() )
2158 mChanges += i18n( "The invitation starting time has been changed from %1 to %2" )
2159 .arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
2160 if ( oldEvent->dtEnd() != newEvent->dtEnd() || oldEvent->doesFloat() != newEvent->doesFloat() )
2161 mChanges += i18n( "The invitation ending time has been changed from %1 to %2" )
2162 .arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
2163 }
2164
2165 void compareTodos( Todo *newTodo, Todo *oldTodo )
2166 {
2167 if ( !oldTodo || !newTodo ) {
2168 return;
2169 }
2170
2171 if ( !oldTodo->isCompleted() && newTodo->isCompleted() ) {
2172 mChanges += i18n( "The task has been completed" );
2173 }
2174 if ( oldTodo->isCompleted() && !newTodo->isCompleted() ) {
2175 mChanges += i18n( "The task is no longer completed" );
2176 }
2177 if ( oldTodo->percentComplete() != newTodo->percentComplete() ) {
2178 const TQString oldPer = i18n( "%1%" ).arg( oldTodo->percentComplete() );
2179 const TQString newPer = i18n( "%1%" ).arg( newTodo->percentComplete() );
2180 mChanges += i18n( "The task completed percentage has changed from %1 to %2" ).
2181 arg( oldPer, newPer );
2182 }
2183
2184 if ( !oldTodo->hasStartDate() && newTodo->hasStartDate() ) {
2185 mChanges += i18n( "A task starting time has been added" );
2186 }
2187 if ( oldTodo->hasStartDate() && !newTodo->hasStartDate() ) {
2188 mChanges += i18n( "The task starting time has been removed" );
2189 }
2190 if ( oldTodo->hasStartDate() && newTodo->hasStartDate() &&
2191 oldTodo->dtStart() != newTodo->dtStart() ) {
2192 mChanges += i18n( "The task starting time has been changed from %1 to %2" ).
2193 arg( dateTimeToString( oldTodo->dtStart(), oldTodo->doesFloat(), false ),
2194 dateTimeToString( newTodo->dtStart(), newTodo->doesFloat(), false ) );
2195 }
2196
2197 if ( !oldTodo->hasDueDate() && newTodo->hasDueDate() ) {
2198 mChanges += i18n( "A task due time has been added" );
2199 }
2200 if ( oldTodo->hasDueDate() && !newTodo->hasDueDate() ) {
2201 mChanges += i18n( "The task due time has been removed" );
2202 }
2203 if ( oldTodo->hasDueDate() && newTodo->hasDueDate() &&
2204 oldTodo->dtDue() != newTodo->dtDue() ) {
2205 mChanges += i18n( "The task due time has been changed from %1 to %2" ).
2206 arg( dateTimeToString( oldTodo->dtDue(), oldTodo->doesFloat(), false ),
2207 dateTimeToString( newTodo->dtDue(), newTodo->doesFloat(), false ) );
2208 }
2209 }
2210
2211 void compareIncidences( Incidence *newInc, Incidence *oldInc, int method )
2212 {
2213 if ( !oldInc || !newInc )
2214 return;
2215 if ( oldInc->summary() != newInc->summary() )
2216 mChanges += i18n( "The summary has been changed to: \"%1\"" ).arg( newInc->summary() );
2217 if ( oldInc->location() != newInc->location() )
2218 mChanges += i18n( "The location has been changed to: \"%1\"" ).arg( newInc->location() );
2219 if ( oldInc->description() != newInc->description() )
2220 mChanges += i18n( "The description has been changed to: \"%1\"" ).arg( newInc->description() );
2221 Attendee::List oldAttendees = oldInc->attendees();
2222 Attendee::List newAttendees = newInc->attendees();
2223 for ( Attendee::List::ConstIterator it = newAttendees.constBegin();
2224 it != newAttendees.constEnd(); ++it ) {
2225 Attendee *oldAtt = oldInc->attendeeByMail( (*it)->email() );
2226 if ( !oldAtt ) {
2227 mChanges += i18n( "Attendee %1 has been added" ).arg( (*it)->fullName() );
2228 } else {
2229 if ( oldAtt->status() != (*it)->status() )
2230 mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).
2231 arg( (*it)->fullName() ).arg( (*it)->statusStr() );
2232 }
2233 }
2234 if ( method == Scheduler::Request ) {
2235 for ( Attendee::List::ConstIterator it = oldAttendees.constBegin();
2236 it != oldAttendees.constEnd(); ++it ) {
2237 if ( (*it)->email() != oldInc->organizer().email() ) {
2238 Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
2239 if ( !newAtt ) {
2240 mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
2241 }
2242 }
2243 }
2244 }
2245 }
2246
2247 private:
2248 Incidence *mExistingIncidence;
2249 int mMethod;
2250 TQStringList mChanges;
2251};
2252
2253
2254TQString InvitationFormatterHelper::makeLink( const TQString &id, const TQString &text )
2255{
2256 if ( !id.startsWith( "ATTACH:" ) ) {
2257 TQString res = TQString( "<a href=\"%1\"><b>%2</b></a>" ).
2258 arg( generateLinkURL( id ), text );
2259 return res;
2260 } else {
2261 // draw the attachment links in non-bold face
2262 TQString res = TQString( "<a href=\"%1\">%2</a>" ).
2263 arg( generateLinkURL( id ), text );
2264 return res;
2265 }
2266}
2267
2268// Check if the given incidence is likely one that we own instead one from
2269// a shared calendar (Kolab-specific)
2270static bool incidenceOwnedByMe( Calendar *calendar, Incidence *incidence )
2271{
2272 CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
2273 if ( !cal || !incidence ) {
2274 return true;
2275 }
2276 ResourceCalendar *res = cal->resource( incidence );
2277 if ( !res ) {
2278 return true;
2279 }
2280 const TQString subRes = res->subresourceIdentifier( incidence );
2281 if ( !subRes.contains( "/.INBOX.directory/" ) ) {
2282 return false;
2283 }
2284 return true;
2285}
2286
2287// The spacer for the invitation buttons
2288static TQString spacer = "<td> &nbsp; </td>";
2289// The open & close table cell tags for the invitation buttons
2290static TQString tdOpen = "<td>";
2291static TQString tdClose = "</td>" + spacer;
2292
2293static TQString responseButtons( Incidence *inc, bool rsvpReq, bool rsvpRec,
2294 InvitationFormatterHelper *helper )
2295{
2296 TQString html;
2297 if ( !helper ) {
2298 return html;
2299 }
2300
2301 if ( !rsvpReq && ( inc && inc->revision() == 0 ) ) {
2302 // Record only
2303 html += tdOpen;
2304 html += helper->makeLink( "record", i18n( "[Record]" ) );
2305 html += tdClose;
2306
2307 // Move to trash
2308 html += tdOpen;
2309 html += helper->makeLink( "delete", i18n( "[Move to Trash]" ) );
2310 html += tdClose;
2311
2312 } else {
2313
2314 // Accept
2315 html += tdOpen;
2316 html += helper->makeLink( "accept", i18n( "[Accept]" ) );
2317 html += tdClose;
2318
2319 // Tentative
2320 html += tdOpen;
2321 html += helper->makeLink( "accept_conditionally",
2322 i18n( "Accept conditionally", "[Accept cond.]" ) );
2323 html += tdClose;
2324
2325 // Counter proposal
2326 html += tdOpen;
2327 html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
2328 html += tdClose;
2329
2330 // Decline
2331 html += tdOpen;
2332 html += helper->makeLink( "decline", i18n( "[Decline]" ) );
2333 html += tdClose;
2334 }
2335
2336 if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
2337 // Delegate
2338 html += tdOpen;
2339 html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
2340 html += tdClose;
2341
2342 // Forward
2343 html += tdOpen;
2344 html += helper->makeLink( "forward", i18n( "[Forward]" ) );
2345 html += tdClose;
2346
2347 // Check calendar
2348 if ( inc && inc->type() == "Event" ) {
2349 html += tdOpen;
2350 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
2351 html += tdClose;
2352 }
2353 }
2354 return html;
2355}
2356
2357static TQString counterButtons( Incidence *incidence,
2358 InvitationFormatterHelper *helper )
2359{
2360 TQString html;
2361 if ( !helper ) {
2362 return html;
2363 }
2364
2365 // Accept proposal
2366 html += tdOpen;
2367 html += helper->makeLink( "accept_counter", i18n("[Accept]") );
2368 html += tdClose;
2369
2370 // Decline proposal
2371 html += tdOpen;
2372 html += helper->makeLink( "decline_counter", i18n("[Decline]") );
2373 html += tdClose;
2374
2375 // Check calendar
2376 if ( incidence && incidence->type() == "Event" ) {
2377 html += tdOpen;
2378 html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
2379 html += tdClose;
2380 }
2381 return html;
2382}
2383
2384TQString IncidenceFormatter::formatICalInvitationHelper( TQString invitation,
2385 Calendar *mCalendar,
2386 InvitationFormatterHelper *helper,
2387 bool noHtmlMode,
2388 const TQString &sender )
2389{
2390 if ( invitation.isEmpty() ) {
2391 return TQString();
2392 }
2393
2394 ICalFormat format;
2395 // parseScheduleMessage takes the tz from the calendar, no need to set it manually here for the format!
2396 ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
2397
2398 if( !msg ) {
2399 kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
2400 Q_ASSERT( format.exception() );
2401 kdDebug( 5850 ) << format.exception()->message() << endl;
2402 return TQString();
2403 }
2404
2405 IncidenceBase *incBase = msg->event();
2406
2407 // Determine if this incidence is in my calendar (and owned by me)
2408 Incidence *existingIncidence = 0;
2409 if ( incBase && helper->calendar() ) {
2410 existingIncidence = helper->calendar()->incidence( incBase->uid() );
2411 if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) ) {
2412 existingIncidence = 0;
2413 }
2414 if ( !existingIncidence ) {
2415 const Incidence::List list = helper->calendar()->incidences();
2416 for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
2417 if ( (*it)->schedulingID() == incBase->uid() &&
2418 incidenceOwnedByMe( helper->calendar(), *it ) ) {
2419 existingIncidence = *it;
2420 break;
2421 }
2422 }
2423 }
2424 }
2425
2426 // First make the text of the message
2427 TQString html;
2428
2429 TQString tableStyle = TQString::fromLatin1(
2430 "style=\"border: solid 1px; margin: 0em;\"" );
2431 TQString tableHead = TQString::fromLatin1(
2432 "<div align=\"center\">"
2433 "<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
2434 "<tr><td>").arg(tableStyle);
2435
2436 html += tableHead;
2437 InvitationHeaderVisitor headerVisitor;
2438 // The InvitationHeaderVisitor returns false if the incidence is somehow invalid, or not handled
2439 if ( !headerVisitor.act( incBase, existingIncidence, msg, sender ) )
2440 return TQString();
2441 html += "<b>" + headerVisitor.result() + "</b>";
2442
2443 InvitationBodyVisitor bodyVisitor( noHtmlMode );
2444 if ( !bodyVisitor.act( incBase, existingIncidence, msg, sender ) )
2445 return TQString();
2446 html += bodyVisitor.result();
2447
2448 if ( msg->method() == Scheduler::Request ) {
2449 IncidenceCompareVisitor compareVisitor;
2450 if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
2451 html += "<p align=\"left\">";
2452 html += i18n( "The following changes have been made by the organizer:" );
2453 html += "</p>";
2454 html += compareVisitor.result();
2455 }
2456 }
2457 if ( msg->method() == Scheduler::Reply ) {
2458 IncidenceCompareVisitor compareVisitor;
2459 if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
2460 html += "<p align=\"left\">";
2461 if ( !sender.isEmpty() ) {
2462 html += i18n( "The following changes have been made by %1:" ).arg( sender );
2463 } else {
2464 html += i18n( "The following changes have been made by an attendee:" );
2465 }
2466 html += "</p>";
2467 html += compareVisitor.result();
2468 }
2469 }
2470
2471 Incidence *inc = dynamic_cast<Incidence*>( incBase );
2472
2473 // determine if I am the organizer for this invitation
2474 bool myInc = iamOrganizer( inc );
2475
2476 // determine if the invitation response has already been recorded
2477 bool rsvpRec = false;
2478 Attendee *ea = 0;
2479 if ( !myInc ) {
2480 Incidence *rsvpIncidence = existingIncidence;
2481 if ( !rsvpIncidence && inc && inc->revision() > 0 ) {
2482 rsvpIncidence = inc;
2483 }
2484 if ( rsvpIncidence ) {
2485 ea = findMyAttendee( rsvpIncidence );
2486 }
2487 if ( ea &&
2488 ( ea->status() == Attendee::Accepted ||
2489 ea->status() == Attendee::Declined ||
2490 ea->status() == Attendee::Tentative ) ) {
2491 rsvpRec = true;
2492 }
2493 }
2494
2495 // determine invitation role
2496 TQString role;
2497 bool isDelegated = false;
2498 Attendee *a = findMyAttendee( inc );
2499 if ( !a && inc ) {
2500 if ( !inc->attendees().isEmpty() ) {
2501 a = inc->attendees().first();
2502 }
2503 }
2504 if ( a ) {
2505 isDelegated = ( a->status() == Attendee::Delegated );
2506 role = Attendee::roleName( a->role() );
2507 }
2508
2509 // determine if RSVP needed, not-needed, or response already recorded
2510 bool rsvpReq = rsvpRequested( inc );
2511 if ( !myInc && a ) {
2512 html += "<br/>";
2513 html += "<i><u>";
2514 if ( rsvpRec && inc ) {
2515 if ( inc->revision() == 0 ) {
2516 html += i18n( "Your <b>%1</b> response has already been recorded" ).
2517 arg( ea->statusStr() );
2518 } else {
2519 html += i18n( "Your status for this invitation is <b>%1</b>" ).
2520 arg( ea->statusStr() );
2521 }
2522 rsvpReq = false;
2523 } else if ( msg->method() == Scheduler::Cancel ) {
2524 html += i18n( "This invitation was declined" );
2525 } else if ( msg->method() == Scheduler::Add ) {
2526 html += i18n( "This invitation was accepted" );
2527 } else {
2528 if ( !isDelegated ) {
2529 html += rsvpRequestedStr( rsvpReq, role );
2530 } else {
2531 html += i18n( "Awaiting delegation response" );
2532 }
2533 }
2534 html += "</u></i>";
2535 }
2536
2537 // Print if the organizer gave you a preset status
2538 if ( !myInc ) {
2539 if ( inc && inc->revision() == 0 ) {
2540 TQString statStr = myStatusStr( inc );
2541 if ( !statStr.isEmpty() ) {
2542 html += "<br/>";
2543 html += "<i>";
2544 html += statStr;
2545 html += "</i>";
2546 }
2547 }
2548 }
2549
2550 // Add groupware links
2551
2552 html += "<br><table border=\"0\" cellspacing=\"0\"><tr><td>&nbsp;</td></tr>";
2553
2554 switch ( msg->method() ) {
2555 case Scheduler::Publish:
2556 case Scheduler::Request:
2557 case Scheduler::Refresh:
2558 case Scheduler::Add:
2559 {
2560 if ( inc && inc->revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
2561 html += "<tr>";
2562 if ( inc->type() == "Todo" ) {
2563 html += "<td colspan=\"9\">";
2564 html += helper->makeLink( "reply", i18n( "[Record invitation in my task list]" ) );
2565 } else {
2566 html += "<td colspan=\"13\">";
2567 html += helper->makeLink( "reply", i18n( "[Record invitation in my calendar]" ) );
2568 }
2569 html += "</td></tr>";
2570 }
2571
2572 if ( !myInc && a ) {
2573 html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
2574 }
2575 break;
2576 }
2577
2578 case Scheduler::Cancel:
2579 // Remove invitation
2580 if ( inc ) {
2581 html += "<tr>";
2582 if ( inc->type() == "Todo" ) {
2583 html += "<td colspan=\"9\">";
2584 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my task list]" ) );
2585 } else {
2586 html += "<td colspan=\"13\">";
2587 html += helper->makeLink( "cancel", i18n( "[Remove invitation from my calendar]" ) );
2588 }
2589 html += "</td></tr>";
2590 }
2591 break;
2592
2593 case Scheduler::Reply:
2594 {
2595 // Record invitation response
2596 Attendee *a = 0;
2597 Attendee *ea = 0;
2598 if ( inc ) {
2599 // First, determine if this reply is really a counter in disguise.
2600 if ( replyMeansCounter( inc ) ) {
2601 html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
2602 break;
2603 }
2604
2605 // Next, maybe this is a declined reply that was delegated from me?
2606 // find first attendee who is delegated-from me
2607 // look a their PARTSTAT response, if the response is declined,
2608 // then we need to start over which means putting all the action
2609 // buttons and NOT putting on the [Record response..] button
2610 a = findDelegatedFromMyAttendee( inc );
2611 if ( a ) {
2612 if ( a->status() != Attendee::Accepted ||
2613 a->status() != Attendee::Tentative ) {
2614 html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
2615 break;
2616 }
2617 }
2618
2619 // Finally, simply allow a Record of the reply
2620 if ( !inc->attendees().isEmpty() ) {
2621 a = inc->attendees().first();
2622 }
2623 if ( a ) {
2624 ea = findAttendee( existingIncidence, a->email() );
2625 }
2626 }
2627 if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
2628 if ( inc && inc->revision() > 0 ) {
2629 html += "<br><u><i>";
2630 html += i18n( "The response has been recorded [%1]" ).arg( ea->statusStr() );
2631 html += "</i></u>";
2632 }
2633 } else {
2634 if ( inc ) {
2635 html += "<tr><td>";
2636 if ( inc->type() == "Todo" ) {
2637 html += helper->makeLink( "reply", i18n( "[Record response in my task list]" ) );
2638 } else {
2639 html += helper->makeLink( "reply", i18n( "[Record response in my calendar]" ) );
2640 }
2641 html += "</td></tr>";
2642 }
2643 }
2644 break;
2645 }
2646
2647 case Scheduler::Counter:
2648 // Counter proposal
2649 html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
2650 break;
2651
2652 case Scheduler::Declinecounter:
2653 case Scheduler::NoMethod:
2654 break;
2655 }
2656
2657 // close the groupware table
2658 html += "</td></tr></table>";
2659
2660 // Add the attendee list if I am the organizer
2661 if ( myInc && helper->calendar() ) {
2662 html += invitationAttendees( helper->calendar()->incidence( inc->uid() ) );
2663 }
2664
2665 // close the top-level table
2666 html += "</td></tr></table><br></div>";
2667
2668 // Add the attachment list
2669 html += invitationAttachments( helper, inc );
2670
2671 return html;
2672}
2673
2674TQString IncidenceFormatter::formatICalInvitation( TQString invitation,
2675 Calendar *mCalendar,
2676 InvitationFormatterHelper *helper )
2677{
2678 return formatICalInvitationHelper( invitation, mCalendar, helper, false, TQString() );
2679}
2680
2681TQString IncidenceFormatter::formatICalInvitationNoHtml( TQString invitation,
2682 Calendar *mCalendar,
2683 InvitationFormatterHelper *helper )
2684{
2685 return formatICalInvitationHelper( invitation, mCalendar, helper, true, TQString() );
2686}
2687
2688TQString IncidenceFormatter::formatICalInvitationNoHtml( TQString invitation,
2689 Calendar *mCalendar,
2690 InvitationFormatterHelper *helper,
2691 const TQString &sender )
2692{
2693 return formatICalInvitationHelper( invitation, mCalendar, helper, true, sender );
2694}
2695
2696
2697/*******************************************************************
2698 * Helper functions for the msTNEF -> VPart converter
2699 *******************************************************************/
2700
2701
2702//-----------------------------------------------------------------------------
2703
2704static TQString stringProp( KTNEFMessage* tnefMsg, const TQ_UINT32& key,
2705 const TQString& fallback = TQString())
2706{
2707 return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
2708 fallback );
2709}
2710
2711static TQString sNamedProp( KTNEFMessage* tnefMsg, const TQString& name,
2712 const TQString& fallback = TQString() )
2713{
2714 return tnefMsg->findNamedProp( name, fallback );
2715}
2716
2717struct save_tz { char* old_tz; char* tz_env_str; };
2718
2719/* temporarily go to a different timezone */
2720static struct save_tz set_tz( const char* _tc )
2721{
2722 const char *tc = _tc?_tc:"UTC";
2723
2724 struct save_tz rv;
2725
2726 rv.old_tz = 0;
2727 rv.tz_env_str = 0;
2728
2729 //kdDebug(5006) << "set_tz(), timezone before = " << timezone << endl;
2730
2731 char* tz_env = 0;
2732 if( getenv( "TZ" ) ) {
2733 tz_env = strdup( getenv( "TZ" ) );
2734 rv.old_tz = tz_env;
2735 }
2736 char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
2737 strcpy( tmp_env, "TZ=" );
2738 strcpy( tmp_env+3, tc );
2739 putenv( tmp_env );
2740
2741 rv.tz_env_str = tmp_env;
2742
2743 /* tmp_env is not free'ed -- it is part of the environment */
2744
2745 tzset();
2746 //kdDebug(5006) << "set_tz(), timezone after = " << timezone << endl;
2747
2748 return rv;
2749}
2750
2751/* restore previous timezone */
2752static void unset_tz( struct save_tz old_tz )
2753{
2754 if( old_tz.old_tz ) {
2755 char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
2756 strcpy( tmp_env, "TZ=" );
2757 strcpy( tmp_env+3, old_tz.old_tz );
2758 putenv( tmp_env );
2759 /* tmp_env is not free'ed -- it is part of the environment */
2760 free( old_tz.old_tz );
2761 } else {
2762 /* clear TZ from env */
2763 putenv( strdup("TZ") );
2764 }
2765 tzset();
2766
2767 /* is this OK? */
2768 if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
2769}
2770
2771static TQDateTime utc2Local( const TQDateTime& utcdt )
2772{
2773 struct tm tmL;
2774
2775 save_tz tmp_tz = set_tz("UTC");
2776 time_t utc = utcdt.toTime_t();
2777 unset_tz( tmp_tz );
2778
2779 localtime_r( &utc, &tmL );
2780 return TQDateTime( TQDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
2781 TQTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
2782}
2783
2784
2785static TQDateTime pureISOToLocalTQDateTime( const TQString& dtStr,
2786 bool bDateOnly = false )
2787{
2788 TQDate tmpDate;
2789 TQTime tmpTime;
2790 int year, month, day, hour, minute, second;
2791
2792 if( bDateOnly ) {
2793 year = dtStr.left( 4 ).toInt();
2794 month = dtStr.mid( 4, 2 ).toInt();
2795 day = dtStr.mid( 6, 2 ).toInt();
2796 hour = 0;
2797 minute = 0;
2798 second = 0;
2799 } else {
2800 year = dtStr.left( 4 ).toInt();
2801 month = dtStr.mid( 4, 2 ).toInt();
2802 day = dtStr.mid( 6, 2 ).toInt();
2803 hour = dtStr.mid( 9, 2 ).toInt();
2804 minute = dtStr.mid( 11, 2 ).toInt();
2805 second = dtStr.mid( 13, 2 ).toInt();
2806 }
2807 tmpDate.setYMD( year, month, day );
2808 tmpTime.setHMS( hour, minute, second );
2809
2810 if( tmpDate.isValid() && tmpTime.isValid() ) {
2811 TQDateTime dT = TQDateTime( tmpDate, tmpTime );
2812
2813 if( !bDateOnly ) {
2814 // correct for GMT ( == Zulu time == UTC )
2815 if (dtStr.at(dtStr.length()-1) == 'Z') {
2816 //dT = dT.addSecs( 60 * KRFCDate::localUTCOffset() );
2817 //localUTCOffset( dT ) );
2818 dT = utc2Local( dT );
2819 }
2820 }
2821 return dT;
2822 } else
2823 return TQDateTime();
2824}
2825
2826
2827
2828TQString IncidenceFormatter::msTNEFToVPart( const TQByteArray& tnef )
2829{
2830 bool bOk = false;
2831
2832 KTNEFParser parser;
2833 TQBuffer buf( tnef );
2834 CalendarLocal cal ( TQString::fromLatin1( "UTC" ) );
2835 TDEABC::Addressee addressee;
2836 TDEABC::VCardConverter cardConv;
2837 ICalFormat calFormat;
2838 Event* event = new Event();
2839
2840 if( parser.openDevice( &buf ) ) {
2841 KTNEFMessage* tnefMsg = parser.message();
2842 //TQMap<int,KTNEFProperty*> props = parser.message()->properties();
2843
2844 // Everything depends from property PR_MESSAGE_CLASS
2845 // (this is added by KTNEFParser):
2846 TQString msgClass = tnefMsg->findProp( 0x001A, TQString(), true )
2847 .upper();
2848 if( !msgClass.isEmpty() ) {
2849 // Match the old class names that might be used by Outlook for
2850 // compatibility with Microsoft Mail for Windows for Workgroups 3.1.
2851 bool bCompatClassAppointment = false;
2852 bool bCompatMethodRequest = false;
2853 bool bCompatMethodCancled = false;
2854 bool bCompatMethodAccepted = false;
2855 bool bCompatMethodAcceptedCond = false;
2856 bool bCompatMethodDeclined = false;
2857 if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
2858 bCompatClassAppointment = true;
2859 if( msgClass.endsWith( ".MTGREQ" ) )
2860 bCompatMethodRequest = true;
2861 if( msgClass.endsWith( ".MTGCNCL" ) )
2862 bCompatMethodCancled = true;
2863 if( msgClass.endsWith( ".MTGRESPP" ) )
2864 bCompatMethodAccepted = true;
2865 if( msgClass.endsWith( ".MTGRESPA" ) )
2866 bCompatMethodAcceptedCond = true;
2867 if( msgClass.endsWith( ".MTGRESPN" ) )
2868 bCompatMethodDeclined = true;
2869 }
2870 bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
2871
2872 if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
2873 // Compose a vCal
2874 bool bIsReply = false;
2875 TQString prodID = "-//Microsoft Corporation//Outlook ";
2876 prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
2877 prodID += "MIMEDIR/EN\n";
2878 prodID += "VERSION:2.0\n";
2879 calFormat.setApplication( "Outlook", prodID );
2880
2881 Scheduler::Method method;
2882 if( bCompatMethodRequest )
2883 method = Scheduler::Request;
2884 else if( bCompatMethodCancled )
2885 method = Scheduler::Cancel;
2886 else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
2887 bCompatMethodDeclined ) {
2888 method = Scheduler::Reply;
2889 bIsReply = true;
2890 } else {
2891 // pending(khz): verify whether "0x0c17" is the right tag ???
2892 //
2893 // at the moment we think there are REQUESTS and UPDATES
2894 //
2895 // but WHAT ABOUT REPLIES ???
2896 //
2897 //
2898
2899 if( tnefMsg->findProp(0x0c17) == "1" )
2900 bIsReply = true;
2901 method = Scheduler::Request;
2902 }
2903
2905 ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
2906
2907 TQString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
2908
2909 if( !sSenderSearchKeyEmail.isEmpty() ) {
2910 int colon = sSenderSearchKeyEmail.find( ':' );
2911 // May be e.g. "SMTP:KHZ@KDE.ORG"
2912 if( sSenderSearchKeyEmail.find( ':' ) == -1 )
2913 sSenderSearchKeyEmail.remove( 0, colon+1 );
2914 }
2915
2916 TQString s( tnefMsg->findProp( 0x0e04 ) );
2917 TQStringList attendees = TQStringList::split( ';', s );
2918 if( attendees.count() ) {
2919 for( TQStringList::Iterator it = attendees.begin();
2920 it != attendees.end(); ++it ) {
2921 // Skip all entries that have no '@' since these are
2922 // no mail addresses
2923 if( (*it).find('@') == -1 ) {
2924 s = (*it).stripWhiteSpace();
2925
2926 Attendee *attendee = new Attendee( s, s, true );
2927 if( bIsReply ) {
2928 if( bCompatMethodAccepted )
2929 attendee->setStatus( Attendee::Accepted );
2930 if( bCompatMethodDeclined )
2931 attendee->setStatus( Attendee::Declined );
2932 if( bCompatMethodAcceptedCond )
2933 attendee->setStatus(Attendee::Tentative);
2934 } else {
2935 attendee->setStatus( Attendee::NeedsAction );
2936 attendee->setRole( Attendee::ReqParticipant );
2937 }
2938 event->addAttendee(attendee);
2939 }
2940 }
2941 } else {
2942 // Oops, no attendees?
2943 // This must be old style, let us use the PR_SENDER_SEARCH_KEY.
2944 s = sSenderSearchKeyEmail;
2945 if( !s.isEmpty() ) {
2946 Attendee *attendee = new Attendee( TQString(), TQString(),
2947 true );
2948 if( bIsReply ) {
2949 if( bCompatMethodAccepted )
2950 attendee->setStatus( Attendee::Accepted );
2951 if( bCompatMethodAcceptedCond )
2952 attendee->setStatus( Attendee::Declined );
2953 if( bCompatMethodDeclined )
2954 attendee->setStatus( Attendee::Tentative );
2955 } else {
2956 attendee->setStatus(Attendee::NeedsAction);
2957 attendee->setRole(Attendee::ReqParticipant);
2958 }
2959 event->addAttendee(attendee);
2960 }
2961 }
2962 s = tnefMsg->findProp( 0x0c1f ); // look for organizer property
2963 if( s.isEmpty() && !bIsReply )
2964 s = sSenderSearchKeyEmail;
2965 // TODO: Use the common name?
2966 if( !s.isEmpty() )
2967 event->setOrganizer( s );
2968
2969 s = tnefMsg->findProp( 0x8516 ).replace( TQChar( '-' ), TQString() )
2970 .replace( TQChar( ':' ), TQString() );
2971 event->setDtStart( TQDateTime::fromString( s ) ); // ## Format??
2972
2973 s = tnefMsg->findProp( 0x8517 ).replace( TQChar( '-' ), TQString() )
2974 .replace( TQChar( ':' ), TQString() );
2975 event->setDtEnd( TQDateTime::fromString( s ) );
2976
2977 s = tnefMsg->findProp( 0x8208 );
2978 event->setLocation( s );
2979
2980 // is it OK to set this to OPAQUE always ??
2981 //vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme!
2982 //vPart += "SEQUENCE:0\n";
2983
2984 // is "0x0023" OK - or should we look for "0x0003" ??
2985 s = tnefMsg->findProp( 0x0023 );
2986 event->setUid( s );
2987
2988 // PENDING(khz): is this value in local timezone? Must it be
2989 // adjusted? Most likely this is a bug in the server or in
2990 // Outlook - we ignore it for now.
2991 s = tnefMsg->findProp( 0x8202 ).replace( TQChar( '-' ), TQString() )
2992 .replace( TQChar( ':' ), TQString() );
2993 // ### libkcal always uses currentDateTime()
2994 // event->setDtStamp(TQDateTime::fromString(s));
2995
2996 s = tnefMsg->findNamedProp( "Keywords" );
2997 event->setCategories( s );
2998
2999 s = tnefMsg->findProp( 0x1000 );
3000 event->setDescription( s );
3001
3002 s = tnefMsg->findProp( 0x0070 );
3003 event->setSummary( s );
3004
3005 s = tnefMsg->findProp( 0x0026 );
3006 event->setPriority( s.toInt() );
3007
3008 // is reminder flag set ?
3009 if(!tnefMsg->findProp(0x8503).isEmpty()) {
3010 Alarm *alarm = new Alarm(event);
3011 TQDateTime highNoonTime =
3012 pureISOToLocalTQDateTime( tnefMsg->findProp( 0x8502 )
3013 .replace( TQChar( '-' ), "" )
3014 .replace( TQChar( ':' ), "" ) );
3015 TQDateTime wakeMeUpTime =
3016 pureISOToLocalTQDateTime( tnefMsg->findProp( 0x8560, "" )
3017 .replace( TQChar( '-' ), "" )
3018 .replace( TQChar( ':' ), "" ) );
3019 alarm->setTime(wakeMeUpTime);
3020
3021 if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
3022 alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
3023 else
3024 // default: wake them up 15 minutes before the appointment
3025 alarm->setStartOffset( Duration( 15*60 ) );
3026 alarm->setDisplayAlarm( i18n( "Reminder" ) );
3027
3028 // Sorry: the different action types are not known (yet)
3029 // so we always set 'DISPLAY' (no sounds, no images...)
3030 event->addAlarm( alarm );
3031 }
3032 cal.addEvent( event );
3033 bOk = true;
3034 // we finished composing a vCal
3035 } else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
3036 addressee.setUid( stringProp( tnefMsg, attMSGID ) );
3037 addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
3038 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
3039 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
3040 addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
3041 addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
3042 addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
3043 addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
3044 addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
3045 addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
3046 addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
3047 addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
3048
3049 TQString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
3050 .replace( TQChar( '-' ), TQString() )
3051 .replace( TQChar( ':' ), TQString() );
3052 if( !s.isEmpty() )
3053 addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
3054
3055 addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
3056
3057 // collect parts of Name entry
3058 addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
3059 addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
3060 addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
3061 addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
3062 addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
3063
3064 addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
3065 addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
3066 addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
3067 /*
3068 the MAPI property ID of this (multiline) )field is unknown:
3069 vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" );
3070 */
3071
3072 TDEABC::Address adr;
3073 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
3074 adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
3075 adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
3076 adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
3077 adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
3078 adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
3079 adr.setType(TDEABC::Address::Home);
3080 addressee.insertAddress(adr);
3081
3082 adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
3083 adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
3084 adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
3085 adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
3086 adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
3087 adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
3088 adr.setType( TDEABC::Address::Work );
3089 addressee.insertAddress( adr );
3090
3091 adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
3092 adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
3093 adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
3094 adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
3095 adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
3096 adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
3097 adr.setType( TDEABC::Address::Dom );
3098 addressee.insertAddress(adr);
3099
3100 // problem: the 'other' address was stored by KOrganizer in
3101 // a line looking like the following one:
3102 // vPart += "\nADR;TYPE=dom;TYPE=intl;TYPE=parcel;TYPE=postal;TYPE=work;TYPE=home:other_pobox;;other_str1\nother_str2;other_loc;other_region;other_pocode;other_country
3103
3104 TQString nr;
3105 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
3106 addressee.insertPhoneNumber( TDEABC::PhoneNumber( nr, TDEABC::PhoneNumber::Home ) );
3107 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
3108 addressee.insertPhoneNumber( TDEABC::PhoneNumber( nr, TDEABC::PhoneNumber::Work ) );
3109 nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
3110 addressee.insertPhoneNumber( TDEABC::PhoneNumber( nr, TDEABC::PhoneNumber::Cell ) );
3111 nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
3112 addressee.insertPhoneNumber( TDEABC::PhoneNumber( nr, TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Home ) );
3113 nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
3114 addressee.insertPhoneNumber( TDEABC::PhoneNumber( nr, TDEABC::PhoneNumber::Fax | TDEABC::PhoneNumber::Work ) );
3115
3116 s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
3117 .replace( TQChar( '-' ), TQString() )
3118 .replace( TQChar( ':' ), TQString() );
3119 if( !s.isEmpty() )
3120 addressee.setBirthday( TQDateTime::fromString( s ) );
3121
3122 bOk = ( !addressee.isEmpty() );
3123 } else if( "IPM.NOTE" == msgClass ) {
3124
3125 } // else if ... and so on ...
3126 }
3127 }
3128
3129 // Compose return string
3130 TQString iCal = calFormat.toString( &cal );
3131 if( !iCal.isEmpty() )
3132 // This was an iCal
3133 return iCal;
3134
3135 // Not an iCal - try a vCard
3136 TDEABC::VCardConverter converter;
3137 return converter.createVCard( addressee );
3138}
3139
3140
3141TQString IncidenceFormatter::formatTNEFInvitation( const TQByteArray& tnef,
3142 Calendar *mCalendar, InvitationFormatterHelper *helper )
3143{
3144 TQString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
3145 TQString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
3146 if( !iCal.isEmpty() )
3147 return iCal;
3148 return vPart;
3149}
3150
3151
3152
3153
3154/*******************************************************************
3155 * Helper functions for the Incidence tooltips
3156 *******************************************************************/
3157
3158class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
3159{
3160 public:
3161 ToolTipVisitor()
3162 : mCalendar( 0 ), mRichText( true ), mResult( "" ) {}
3163
3164 bool act( Calendar *calendar, IncidenceBase *incidence,
3165 const TQDate &date=TQDate(), bool richText=true )
3166 {
3167 mCalendar = calendar;
3168 mDate = date;
3169 mRichText = richText;
3170 mResult = "";
3171 return incidence ? incidence->accept( *this ) : false;
3172 }
3173 TQString result() const { return mResult; }
3174
3175 protected:
3176 bool visit( Event *event );
3177 bool visit( Todo *todo );
3178 bool visit( Journal *journal );
3179 bool visit( FreeBusy *fb );
3180
3181 TQString dateRangeText( Event *event, const TQDate &date );
3182 TQString dateRangeText( Todo *todo, const TQDate &date );
3183 TQString dateRangeText( Journal *journal );
3184 TQString dateRangeText( FreeBusy *fb );
3185
3186 TQString generateToolTip( Incidence* incidence, TQString dtRangeText );
3187
3188 protected:
3189 Calendar *mCalendar;
3190 TQDate mDate;
3191 bool mRichText;
3192 TQString mResult;
3193};
3194
3195TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event *event, const TQDate &date )
3196{
3197 TQString ret;
3198 TQString tmp;
3199
3200 TQDateTime startDt = event->dtStart();
3201 TQDateTime endDt = event->dtEnd();
3202 if ( event->doesRecur() ) {
3203 if ( date.isValid() ) {
3204 TQDateTime dt( date, TQTime( 0, 0, 0 ) );
3205 int diffDays = startDt.daysTo( dt );
3206 dt = dt.addSecs( -1 );
3207 startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
3208 if ( event->hasEndDate() ) {
3209 endDt = endDt.addDays( diffDays );
3210 if ( startDt > endDt ) {
3211 startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
3212 endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
3213 }
3214 }
3215 }
3216 }
3217 if ( event->isMultiDay() ) {
3218
3219 tmp = "<br>" + i18n("Event start", "<i>From:</i>&nbsp;%1");
3220 if (event->doesFloat())
3221 ret += tmp.arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", "&nbsp;") );
3222 else
3223 ret += tmp.arg( IncidenceFormatter::dateToString( startDt ).replace(" ", "&nbsp;") );
3224
3225 tmp = "<br>" + i18n("Event end","<i>To:</i>&nbsp;%1");
3226 if (event->doesFloat())
3227 ret += tmp.arg( IncidenceFormatter::dateToString( endDt, false ).replace(" ", "&nbsp;") );
3228 else
3229 ret += tmp.arg( IncidenceFormatter::dateToString( endDt ).replace(" ", "&nbsp;") );
3230
3231 } else {
3232
3233 ret += "<br>"+i18n("<i>Date:</i>&nbsp;%1").
3234 arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", "&nbsp;") );
3235 if ( !event->doesFloat() ) {
3236 const TQString dtStartTime =
3237 IncidenceFormatter::timeToString( startDt, true ).replace( " ", "&nbsp;" );
3238 const TQString dtEndTime =
3239 IncidenceFormatter::timeToString( endDt, true ).replace( " ", "&nbsp;" );
3240 if ( dtStartTime == dtEndTime ) { // to prevent 'Time: 17:00 - 17:00'
3241 tmp = "<br>" + i18n("time for event, &nbsp; to prevent ugly line breaks",
3242 "<i>Time:</i>&nbsp;%1").
3243 arg( dtStartTime );
3244 } else {
3245 tmp = "<br>" + i18n("time range for event, &nbsp; to prevent ugly line breaks",
3246 "<i>Time:</i>&nbsp;%1&nbsp;-&nbsp;%2").
3247 arg( dtStartTime, dtEndTime );
3248 }
3249 ret += tmp;
3250 }
3251
3252 }
3253 return ret;
3254}
3255
3256TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo *todo, const TQDate &date )
3257{
3258 TQString ret;
3259 bool floats( todo->doesFloat() );
3260
3261 if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
3262 TQDateTime startDt = todo->dtStart();
3263 if ( todo->doesRecur() ) {
3264 if ( date.isValid() ) {
3265 startDt.setDate( date );
3266 }
3267 }
3268 ret += "<br>" +
3269 i18n("<i>Start:</i>&nbsp;%1").
3270 arg( IncidenceFormatter::dateTimeToString( startDt, floats, false ).
3271 replace( " ", "&nbsp;" ) );
3272 }
3273
3274 if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
3275 TQDateTime dueDt = todo->dtDue();
3276 if ( todo->doesRecur() ) {
3277 if ( date.isValid() ) {
3278 TQDateTime dt( date, TQTime( 0, 0, 0 ) );
3279 dt = dt.addSecs( -1 );
3280 dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
3281 }
3282 }
3283 ret += "<br>" +
3284 i18n("<i>Due:</i>&nbsp;%1").
3285 arg( IncidenceFormatter::dateTimeToString( dueDt, floats, false ).
3286 replace( " ", "&nbsp;" ) );
3287 }
3288
3289 // Print priority and completed info here, for lack of a better place
3290
3291 if ( todo->priority() > 0 ) {
3292 ret += "<br>";
3293 ret += "<i>" + i18n( "Priority:" ) + "</i>" + "&nbsp;";
3294 ret += TQString::number( todo->priority() );
3295 }
3296
3297 ret += "<br>";
3298 if ( todo->isCompleted() ) {
3299 ret += "<i>" + i18n( "Completed:" ) + "</i>" + "&nbsp;";
3300 ret += todo->completedStr().replace( " ", "&nbsp;" );
3301 } else {
3302 ret += "<i>" + i18n( "Percent Done:" ) + "</i>" + "&nbsp;";
3303 ret += i18n( "%1%" ).arg( todo->percentComplete() );
3304 }
3305
3306 return ret;
3307}
3308
3309TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
3310{
3311 TQString ret;
3312 if (journal->dtStart().isValid() ) {
3313 ret += "<br>" +
3314 i18n("<i>Date:</i>&nbsp;%1").
3315 arg( IncidenceFormatter::dateToString( journal->dtStart(), false ) );
3316 }
3317 return ret;
3318}
3319
3320TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
3321{
3322 TQString tmp( "<br>" + i18n("<i>Period start:</i>&nbsp;%1") );
3323 TQString ret = tmp.arg( TDEGlobal::locale()->formatDateTime( fb->dtStart() ) );
3324 tmp = "<br>" + i18n("<i>Period start:</i>&nbsp;%1");
3325 ret += tmp.arg( TDEGlobal::locale()->formatDateTime( fb->dtEnd() ) );
3326 return ret;
3327}
3328
3329
3330
3331bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
3332{
3333 mResult = generateToolTip( event, dateRangeText( event, mDate ) );
3334 return !mResult.isEmpty();
3335}
3336
3337bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
3338{
3339 mResult = generateToolTip( todo, dateRangeText( todo, mDate ) );
3340 return !mResult.isEmpty();
3341}
3342
3343bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
3344{
3345 mResult = generateToolTip( journal, dateRangeText( journal ) );
3346 return !mResult.isEmpty();
3347}
3348
3349bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
3350{
3351 mResult = "<qt><b>" + i18n("Free/Busy information for %1")
3352 .arg(fb->organizer().fullName()) + "</b>";
3353 mResult += dateRangeText( fb );
3354 mResult += "</qt>";
3355 return !mResult.isEmpty();
3356}
3357
3358static TQString tooltipPerson( const TQString& email, TQString name )
3359{
3360 // Make the search, if there is an email address to search on,
3361 // and name is missing
3362 if ( name.isEmpty() && !email.isEmpty() ) {
3363 TDEABC::AddressBook *add_book = TDEABC::StdAddressBook::self( true );
3364 TDEABC::Addressee::List addressList = add_book->findByEmail( email );
3365 if ( !addressList.isEmpty() ) {
3366 TDEABC::Addressee o = addressList.first();
3367 if ( !o.isEmpty() && addressList.size() < 2 ) {
3368 // use the name from the addressbook
3369 name = o.formattedName();
3370 }
3371 }
3372 }
3373
3374 // Show the attendee
3375 TQString tmpString = ( name.isEmpty() ? email : name );
3376
3377 return tmpString;
3378}
3379
3380static TQString etc = i18n( "elipsis", "..." );
3381static TQString tooltipFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role )
3382{
3383 int maxNumAtts = 8; // maximum number of people to print per attendee role
3384 TQString sep = i18n( "separator for lists of people names", ", " );
3385 int sepLen = sep.length();
3386
3387 int i = 0;
3388 TQString tmpStr;
3389 Attendee::List::ConstIterator it;
3390 Attendee::List attendees = incidence->attendees();
3391
3392 for( it = attendees.begin(); it != attendees.end(); ++it ) {
3393 Attendee *a = *it;
3394 if ( a->role() != role ) {
3395 // skip not this role
3396 continue;
3397 }
3398 if ( a->email() == incidence->organizer().email() ) {
3399 // skip attendee that is also the organizer
3400 continue;
3401 }
3402 if ( i == maxNumAtts ) {
3403 tmpStr += etc;
3404 break;
3405 }
3406 tmpStr += tooltipPerson( a->email(), a->name() );
3407 if ( !a->delegator().isEmpty() ) {
3408 tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
3409 }
3410 if ( !a->delegate().isEmpty() ) {
3411 tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
3412 }
3413 tmpStr += sep;
3414 i++;
3415 }
3416 if ( tmpStr.endsWith( sep ) ) {
3417 tmpStr.truncate( tmpStr.length() - sepLen );
3418 }
3419 return tmpStr;
3420}
3421
3422static TQString tooltipFormatAttendees( Incidence *incidence )
3423{
3424 TQString tmpStr, str;
3425
3426 // Add organizer link
3427 int attendeeCount = incidence->attendees().count();
3428 if ( attendeeCount > 1 ||
3429 ( attendeeCount == 1 &&
3430 incidence->organizer().email() != incidence->attendees().first()->email() ) ) {
3431 tmpStr += "<i>" + i18n( "Organizer:" ) + "</i>" + "&nbsp;";
3432 tmpStr += tooltipPerson( incidence->organizer().email(),
3433 incidence->organizer().name() );
3434 }
3435
3436 // Add "chair"
3437 str = tooltipFormatAttendeeRoleList( incidence, Attendee::Chair );
3438 if ( !str.isEmpty() ) {
3439 tmpStr += "<br><i>" + i18n( "Chair:" ) + "</i>" + "&nbsp;";
3440 tmpStr += str;
3441 }
3442
3443 // Add required participants
3444 str = tooltipFormatAttendeeRoleList( incidence, Attendee::ReqParticipant );
3445 if ( !str.isEmpty() ) {
3446 tmpStr += "<br><i>" + i18n( "Required Participants:" ) + "</i>" + "&nbsp;";
3447 tmpStr += str;
3448 }
3449
3450 // Add optional participants
3451 str = tooltipFormatAttendeeRoleList( incidence, Attendee::OptParticipant );
3452 if ( !str.isEmpty() ) {
3453 tmpStr += "<br><i>" + i18n( "Optional Participants:" ) + "</i>" + "&nbsp;";
3454 tmpStr += str;
3455 }
3456
3457 // Add observers
3458 str = tooltipFormatAttendeeRoleList( incidence, Attendee::NonParticipant );
3459 if ( !str.isEmpty() ) {
3460 tmpStr += "<br><i>" + i18n( "Observers:" ) + "</i>" + "&nbsp;";
3461 tmpStr += str;
3462 }
3463
3464 return tmpStr;
3465}
3466
3467TQString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, TQString dtRangeText )
3468{
3469 uint maxDescLen = 120; // maximum description chars to print (before elipsis)
3470
3471 if ( !incidence ) {
3472 return TQString();
3473 }
3474
3475 TQString tmp = "<qt>";
3476
3477 // header
3478 tmp += "<b>" + incidence->summary().replace( "\n", "<br>" ) + "</b>";
3479 //NOTE: using <hr> seems to confuse TQt3 tooltips in some cases so use "-----"
3480 tmp += "<br>----------<br>";
3481
3482 if ( mCalendar ) {
3483 TQString calStr = IncidenceFormatter::resourceString( mCalendar, incidence );
3484 if ( !calStr.isEmpty() ) {
3485 tmp += "<i>" + i18n( "Calendar:" ) + "</i>" + "&nbsp;";
3486 tmp += calStr;
3487 }
3488 }
3489
3490 tmp += dtRangeText;
3491
3492 if ( !incidence->location().isEmpty() ) {
3493 tmp += "<br>";
3494 tmp += "<i>" + i18n( "Location:" ) + "</i>" + "&nbsp;";
3495 tmp += incidence->location().replace( "\n", "<br>" );
3496 }
3497
3498 TQString durStr = IncidenceFormatter::durationString( incidence );
3499 if ( !durStr.isEmpty() ) {
3500 tmp += "<br>";
3501 tmp += "<i>" + i18n( "Duration:" ) + "</i>" + "&nbsp;";
3502 tmp += durStr;
3503 }
3504
3505 if ( incidence->doesRecur() ) {
3506 tmp += "<br>";
3507 tmp += "<i>" + i18n( "Recurrence:" ) + "</i>" + "&nbsp;";
3508 tmp += IncidenceFormatter::recurrenceString( incidence );
3509 }
3510
3511 if ( !incidence->description().isEmpty() ) {
3512 TQString desc( incidence->description() );
3513 if ( desc.length() > maxDescLen ) {
3514 desc = desc.left( maxDescLen ) + etc;
3515 }
3516 tmp += "<br>----------<br>";
3517 tmp += "<i>" + i18n( "Description:" ) + "</i>" + "<br>";
3518 tmp += desc.replace( "\n", "<br>" );
3519 tmp += "<br>----------";
3520 }
3521
3522 int reminderCount = incidence->alarms().count();
3523 if ( reminderCount > 0 && incidence->isAlarmEnabled() ) {
3524 tmp += "<br>";
3525 tmp += "<i>" + i18n( "Reminder:", "%n Reminders:", reminderCount ) + "</i>" + "&nbsp;";
3526 tmp += IncidenceFormatter::reminderStringList( incidence ).join( ", " );
3527 }
3528
3529 tmp += "<br>";
3530 tmp += tooltipFormatAttendees( incidence );
3531
3532 int categoryCount = incidence->categories().count();
3533 if ( categoryCount > 0 ) {
3534 tmp += "<br>";
3535 tmp += "<i>" + i18n( "Category:", "%n Categories:", categoryCount ) + "</i>" + "&nbsp;";
3536 tmp += incidence->categories().join( ", " );
3537 }
3538
3539 tmp += "</qt>";
3540 return tmp;
3541}
3542
3543TQString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
3544{
3545 return toolTipStr( 0, incidence, TQDate(), richText );
3546}
3547
3548TQString IncidenceFormatter::toolTipStr( Calendar *calendar,
3549 IncidenceBase *incidence,
3550 const TQDate &date,
3551 bool richText )
3552{
3553 ToolTipVisitor v;
3554 if ( v.act( calendar, incidence, date, richText ) ) {
3555 return v.result();
3556 } else {
3557 return TQString();
3558 }
3559}
3560
3561/*******************************************************************
3562 * Helper functions for the Incidence tooltips
3563 *******************************************************************/
3564
3565class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
3566{
3567 public:
3568 MailBodyVisitor() : mResult( "" ) {}
3569
3570 bool act( IncidenceBase *incidence )
3571 {
3572 mResult = "";
3573 return incidence ? incidence->accept( *this ) : false;
3574 }
3575 TQString result() const { return mResult; }
3576
3577 protected:
3578 bool visit( Event *event );
3579 bool visit( Todo *todo );
3580 bool visit( Journal *journal );
3581 bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
3582 protected:
3583 TQString mResult;
3584};
3585
3586
3587static TQString mailBodyIncidence( Incidence *incidence )
3588{
3589 TQString body;
3590 if ( !incidence->summary().isEmpty() ) {
3591 body += i18n("Summary: %1\n").arg( incidence->summary() );
3592 }
3593 if ( !incidence->organizer().isEmpty() ) {
3594 body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
3595 }
3596 if ( !incidence->location().isEmpty() ) {
3597 body += i18n("Location: %1\n").arg( incidence->location() );
3598 }
3599 return body;
3600}
3601
3602bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
3603{
3604 TQString recurrence[]= {i18n("no recurrence", "None"),
3605 i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
3606 i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
3607 i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
3608
3609 mResult = mailBodyIncidence( event );
3610 mResult += i18n("Start Date: %1\n").
3611 arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
3612 if ( !event->doesFloat() ) {
3613 mResult += i18n("Start Time: %1\n").
3614 arg( IncidenceFormatter::timeToString( event->dtStart(), true ) );
3615 }
3616 if ( event->dtStart() != event->dtEnd() ) {
3617 mResult += i18n("End Date: %1\n").
3618 arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
3619 }
3620 if ( !event->doesFloat() ) {
3621 mResult += i18n("End Time: %1\n").
3622 arg( IncidenceFormatter::timeToString( event->dtEnd(), true ) );
3623 }
3624 if ( event->doesRecur() ) {
3625 Recurrence *recur = event->recurrence();
3626 // TODO: Merge these two to one of the form "Recurs every 3 days"
3627 mResult += i18n("Recurs: %1\n")
3628 .arg( recurrence[ recur->recurrenceType() ] );
3629 mResult += i18n("Frequency: %1\n")
3630 .arg( event->recurrence()->frequency() );
3631
3632 if ( recur->duration() > 0 ) {
3633 mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
3634 mResult += '\n';
3635 } else {
3636 if ( recur->duration() != -1 ) {
3637// TODO_Recurrence: What to do with floating
3638 TQString endstr;
3639 if ( event->doesFloat() ) {
3640 endstr = TDEGlobal::locale()->formatDate( recur->endDate() );
3641 } else {
3642 endstr = TDEGlobal::locale()->formatDateTime( recur->endDateTime() );
3643 }
3644 mResult += i18n("Repeat until: %1\n").arg( endstr );
3645 } else {
3646 mResult += i18n("Repeats forever\n");
3647 }
3648 }
3649
3650 DateList exceptions = recur->exDates();
3651 if (exceptions.isEmpty() == false) {
3652 mResult += i18n("This recurring meeting has been cancelled on the following days:\n");
3653 DateList::ConstIterator ex_iter;
3654 for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
3655 mResult += i18n(" %1\n").arg( TDEGlobal::locale()->formatDate(* ex_iter ) );
3656 }
3657 }
3658 }
3659 TQString details = event->description();
3660 if ( !details.isEmpty() ) {
3661 mResult += i18n("Details:\n%1\n").arg( details );
3662 }
3663 return !mResult.isEmpty();
3664}
3665
3666bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
3667{
3668 mResult = mailBodyIncidence( todo );
3669
3670 if ( todo->hasStartDate() ) {
3671 mResult += i18n("Start Date: %1\n").
3672 arg( IncidenceFormatter::dateToString( todo->dtStart( false ), true ) );
3673 if ( !todo->doesFloat() ) {
3674 mResult += i18n("Start Time: %1\n").
3675 arg( IncidenceFormatter::timeToString( todo->dtStart( false ),true ) );
3676 }
3677 }
3678 if ( todo->hasDueDate() ) {
3679 mResult += i18n("Due Date: %1\n").
3680 arg( IncidenceFormatter::dateToString( todo->dtDue(), true ) );
3681 if ( !todo->doesFloat() ) {
3682 mResult += i18n("Due Time: %1\n").
3683 arg( IncidenceFormatter::timeToString( todo->dtDue(), true ) );
3684 }
3685 }
3686 TQString details = todo->description();
3687 if ( !details.isEmpty() ) {
3688 mResult += i18n("Details:\n%1\n").arg( details );
3689 }
3690 return !mResult.isEmpty();
3691}
3692
3693bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
3694{
3695 mResult = mailBodyIncidence( journal );
3696 mResult += i18n("Date: %1\n").
3697 arg( IncidenceFormatter::dateToString( journal->dtStart(), true ) );
3698 if ( !journal->doesFloat() ) {
3699 mResult += i18n("Time: %1\n").
3700 arg( IncidenceFormatter::timeToString( journal->dtStart(), true ) );
3701 }
3702 if ( !journal->description().isEmpty() )
3703 mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
3704 return !mResult.isEmpty();
3705}
3706
3707
3708
3709TQString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
3710{
3711 if ( !incidence )
3712 return TQString();
3713
3714 MailBodyVisitor v;
3715 if ( v.act( incidence ) ) {
3716 return v.result();
3717 }
3718 return TQString();
3719}
3720
3721static TQString recurEnd( Incidence *incidence )
3722{
3723 TQString endstr;
3724 if ( incidence->doesFloat() ) {
3725 endstr = TDEGlobal::locale()->formatDate( incidence->recurrence()->endDate() );
3726 } else {
3727 endstr = TDEGlobal::locale()->formatDateTime( incidence->recurrence()->endDateTime() );
3728 }
3729 return endstr;
3730}
3731
3732/************************************
3733 * More static formatting functions
3734 ************************************/
3735TQString IncidenceFormatter::recurrenceString( Incidence *incidence )
3736{
3737 if ( !incidence->doesRecur() ) {
3738 return i18n( "No recurrence" );
3739 }
3740 TQStringList dayList;
3741 dayList.append( i18n( "31st Last" ) );
3742 dayList.append( i18n( "30th Last" ) );
3743 dayList.append( i18n( "29th Last" ) );
3744 dayList.append( i18n( "28th Last" ) );
3745 dayList.append( i18n( "27th Last" ) );
3746 dayList.append( i18n( "26th Last" ) );
3747 dayList.append( i18n( "25th Last" ) );
3748 dayList.append( i18n( "24th Last" ) );
3749 dayList.append( i18n( "23rd Last" ) );
3750 dayList.append( i18n( "22nd Last" ) );
3751 dayList.append( i18n( "21st Last" ) );
3752 dayList.append( i18n( "20th Last" ) );
3753 dayList.append( i18n( "19th Last" ) );
3754 dayList.append( i18n( "18th Last" ) );
3755 dayList.append( i18n( "17th Last" ) );
3756 dayList.append( i18n( "16th Last" ) );
3757 dayList.append( i18n( "15th Last" ) );
3758 dayList.append( i18n( "14th Last" ) );
3759 dayList.append( i18n( "13th Last" ) );
3760 dayList.append( i18n( "12th Last" ) );
3761 dayList.append( i18n( "11th Last" ) );
3762 dayList.append( i18n( "10th Last" ) );
3763 dayList.append( i18n( "9th Last" ) );
3764 dayList.append( i18n( "8th Last" ) );
3765 dayList.append( i18n( "7th Last" ) );
3766 dayList.append( i18n( "6th Last" ) );
3767 dayList.append( i18n( "5th Last" ) );
3768 dayList.append( i18n( "4th Last" ) );
3769 dayList.append( i18n( "3rd Last" ) );
3770 dayList.append( i18n( "2nd Last" ) );
3771 dayList.append( i18n( "last day of the month", "Last" ) );
3772 dayList.append( i18n( "unknown day of the month", "unknown" ) ); //#31 - zero offset from UI
3773 dayList.append( i18n( "1st" ) );
3774 dayList.append( i18n( "2nd" ) );
3775 dayList.append( i18n( "3rd" ) );
3776 dayList.append( i18n( "4th" ) );
3777 dayList.append( i18n( "5th" ) );
3778 dayList.append( i18n( "6th" ) );
3779 dayList.append( i18n( "7th" ) );
3780 dayList.append( i18n( "8th" ) );
3781 dayList.append( i18n( "9th" ) );
3782 dayList.append( i18n( "10th" ) );
3783 dayList.append( i18n( "11th" ) );
3784 dayList.append( i18n( "12th" ) );
3785 dayList.append( i18n( "13th" ) );
3786 dayList.append( i18n( "14th" ) );
3787 dayList.append( i18n( "15th" ) );
3788 dayList.append( i18n( "16th" ) );
3789 dayList.append( i18n( "17th" ) );
3790 dayList.append( i18n( "18th" ) );
3791 dayList.append( i18n( "19th" ) );
3792 dayList.append( i18n( "20th" ) );
3793 dayList.append( i18n( "21st" ) );
3794 dayList.append( i18n( "22nd" ) );
3795 dayList.append( i18n( "23rd" ) );
3796 dayList.append( i18n( "24th" ) );
3797 dayList.append( i18n( "25th" ) );
3798 dayList.append( i18n( "26th" ) );
3799 dayList.append( i18n( "27th" ) );
3800 dayList.append( i18n( "28th" ) );
3801 dayList.append( i18n( "29th" ) );
3802 dayList.append( i18n( "30th" ) );
3803 dayList.append( i18n( "31st" ) );
3804 int weekStart = TDEGlobal::locale()->weekStartDay();
3805 TQString dayNames;
3806 TQString recurStr, txt;
3807 const KCalendarSystem *calSys = TDEGlobal::locale()->calendar();
3808 Recurrence *recur = incidence->recurrence();
3809 switch ( recur->recurrenceType() ) {
3810 case Recurrence::rNone:
3811 return i18n( "No recurrence" );
3812
3813 case Recurrence::rMinutely:
3814 recurStr = i18n( "Recurs every minute", "Recurs every %n minutes", recur->frequency() );
3815 if ( recur->duration() != -1 ) {
3816 txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
3817 if ( recur->duration() > 0 ) {
3818 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3819 }
3820 return txt;
3821 }
3822 return recurStr;
3823
3824 case Recurrence::rHourly:
3825 recurStr = i18n( "Recurs hourly", "Recurs every %n hours", recur->frequency() );
3826 if ( recur->duration() != -1 ) {
3827 txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
3828 if ( recur->duration() > 0 ) {
3829 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3830 }
3831 return txt;
3832 }
3833 return recurStr;
3834
3835 case Recurrence::rDaily:
3836 recurStr = i18n( "Recurs daily", "Recurs every %n days", recur->frequency() );
3837 if ( recur->duration() != -1 ) {
3838
3839 txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
3840 if ( recur->duration() > 0 ) {
3841 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3842 }
3843 return txt;
3844 }
3845 return recurStr;
3846
3847 case Recurrence::rWeekly:
3848 {
3849 recurStr = i18n( "Recurs weekly", "Recurs every %n weeks", recur->frequency() );
3850
3851 bool addSpace = false;
3852 for ( int i = 0; i < 7; ++i ) {
3853 if ( recur->days().testBit( ( i + weekStart + 6 ) % 7 ) ) {
3854 if ( addSpace ) {
3855 dayNames.append( i18n( "separator for list of days", ", " ) );
3856 }
3857 dayNames.append( calSys->weekDayName( ( ( i + weekStart + 6 ) % 7 ) + 1, true ) );
3858 addSpace = true;
3859 }
3860 }
3861 if ( dayNames.isEmpty() ) {
3862 dayNames = i18n( "Recurs weekly on no days", "no days" );
3863 }
3864 if ( recur->duration() != -1 ) {
3865 txt = i18n( "%1 on %2 until %3" ).
3866 arg( recurStr ).arg( dayNames ).arg( recurEnd( incidence ) );
3867 if ( recur->duration() > 0 ) {
3868 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3869 }
3870 return txt;
3871 }
3872 txt = i18n( "%1 on %2" ).arg( recurStr ).arg( dayNames );
3873 return txt;
3874 }
3875 case Recurrence::rMonthlyPos:
3876 {
3877 recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
3878
3879 if ( !recur->monthPositions().isEmpty() ) {
3881 if ( recur->duration() != -1 ) {
3882 txt = i18n( "%1 on the %2 %3 until %4" ).
3883 arg( recurStr ).
3884 arg( dayList[rule.pos() + 31] ).
3885 arg( calSys->weekDayName( rule.day(), false ) ).
3886 arg( recurEnd( incidence ) );
3887 if ( recur->duration() > 0 ) {
3888 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3889 }
3890 return txt;
3891 }
3892 txt = i18n( "%1 on the %2 %3" ).
3893 arg( recurStr ).
3894 arg( dayList[rule.pos() + 31] ).
3895 arg( calSys->weekDayName( rule.day(), false ) );
3896 return txt;
3897 } else {
3898 return recurStr;
3899 }
3900 break;
3901 }
3902 case Recurrence::rMonthlyDay:
3903 {
3904 recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
3905
3906 if ( !recur->monthDays().isEmpty() ) {
3907 int days = recur->monthDays()[0];
3908 if ( recur->duration() != -1 ) {
3909 txt = i18n( "%1 on the %2 day until %3" ).
3910 arg( recurStr ).
3911 arg( dayList[days + 31] ).
3912 arg( recurEnd( incidence ) );
3913 if ( recur->duration() > 0 ) {
3914 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3915 }
3916 return txt;
3917 }
3918 txt = i18n( "%1 on the %2 day" ).arg( recurStr ).arg( dayList[days + 31] );
3919 return txt;
3920 } else {
3921 return recurStr;
3922 }
3923 break;
3924 }
3925 case Recurrence::rYearlyMonth:
3926 {
3927 recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
3928
3929 if ( recur->duration() != -1 ) {
3930 if ( !recur->yearDates().isEmpty() ) {
3931 txt = i18n( "%1 on %2 %3 until %4" ).
3932 arg( recurStr ).
3933 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
3934 arg( dayList[ recur->yearDates()[0] + 31 ] ).
3935 arg( recurEnd( incidence ) );
3936 if ( recur->duration() > 0 ) {
3937 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3938 }
3939 return txt;
3940 }
3941 }
3942 if ( !recur->yearDates().isEmpty() ) {
3943 txt = i18n( "%1 on %2 %3" ).
3944 arg( recurStr ).
3945 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
3946 arg( dayList[ recur->yearDates()[0] + 31 ] );
3947 return txt;
3948 } else {
3949 if ( !recur->yearMonths().isEmpty() ) {
3950 txt = i18n( "Recurs yearly on %1 %2" ).
3951 arg( calSys->monthName( recur->yearMonths()[0],
3952 recur->startDate().year() ) ).
3953 arg( dayList[ recur->startDate().day() + 31 ] );
3954 } else {
3955 txt = i18n( "Recurs yearly on %1 %2" ).
3956 arg( calSys->monthName( recur->startDate().month(),
3957 recur->startDate().year() ) ).
3958 arg( dayList[ recur->startDate().day() + 31 ] );
3959 }
3960 return txt;
3961 }
3962 break;
3963 }
3964 case Recurrence::rYearlyDay:
3965 {
3966 recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
3967 if ( !recur->yearDays().isEmpty() ) {
3968 if ( recur->duration() != -1 ) {
3969 txt = i18n( "%1 on day %2 until %3" ).
3970 arg( recurStr ).
3971 arg( recur->yearDays()[0] ).
3972 arg( recurEnd( incidence ) );
3973 if ( recur->duration() > 0 ) {
3974 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3975 }
3976 return txt;
3977 }
3978 txt = i18n( "%1 on day %2" ).arg( recurStr ).arg( recur->yearDays()[0] );
3979 return txt;
3980 } else {
3981 return recurStr;
3982 }
3983 break;
3984 }
3985 case Recurrence::rYearlyPos:
3986 {
3987 recurStr = i18n( "Every year", "Every %n years", recur->frequency() );
3988 if ( !recur->yearPositions().isEmpty() && !recur->yearMonths().isEmpty() ) {
3990 if ( recur->duration() != -1 ) {
3991 txt = i18n( "%1 on the %2 %3 of %4 until %5" ).
3992 arg( recurStr ).
3993 arg( dayList[rule.pos() + 31] ).
3994 arg( calSys->weekDayName( rule.day(), false ) ).
3995 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
3996 arg( recurEnd( incidence ) );
3997 if ( recur->duration() > 0 ) {
3998 txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
3999 }
4000 return txt;
4001 }
4002 txt = i18n( "%1 on the %2 %3 of %4" ).
4003 arg( recurStr ).
4004 arg( dayList[rule.pos() + 31] ).
4005 arg( calSys->weekDayName( rule.day(), false ) ).
4006 arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) );
4007 return txt;
4008 } else {
4009 return recurStr;
4010 }
4011 break;
4012 }
4013 }
4014
4015 return i18n( "Incidence recurs" );
4016}
4017
4018TQString IncidenceFormatter::timeToString( const TQDateTime &date, bool shortfmt )
4019{
4020 return TDEGlobal::locale()->formatTime( date.time(), !shortfmt );
4021}
4022
4023TQString IncidenceFormatter::dateToString( const TQDateTime &date, bool shortfmt )
4024{
4025 return
4026 TDEGlobal::locale()->formatDate( date.date(), shortfmt );
4027}
4028
4029TQString IncidenceFormatter::dateTimeToString( const TQDateTime &date,
4030 bool allDay, bool shortfmt )
4031{
4032 if ( allDay ) {
4033 return dateToString( date, shortfmt );
4034 }
4035
4036 return TDEGlobal::locale()->formatDateTime( date, shortfmt );
4037}
4038
4040{
4041 if ( !calendar || !incidence ) {
4042 return TQString();
4043 }
4044
4045 CalendarResources *calendarResource = dynamic_cast<CalendarResources*>( calendar );
4046 if ( !calendarResource ) {
4047 return TQString();
4048 }
4049
4050 ResourceCalendar *resourceCalendar = calendarResource->resource( incidence );
4051 if ( resourceCalendar ) {
4052 if ( !resourceCalendar->subresources().isEmpty() ) {
4053 TQString subRes = resourceCalendar->subresourceIdentifier( incidence );
4054 if ( subRes.isEmpty() ) {
4055 return resourceCalendar->resourceName();
4056 } else {
4057 return resourceCalendar->labelForSubresource( subRes );
4058 }
4059 }
4060 return resourceCalendar->resourceName();
4061 }
4062
4063 return TQString();
4064}
4065
4066static TQString secs2Duration( int secs )
4067{
4068 TQString tmp;
4069 int days = secs / 86400;
4070 if ( days > 0 ) {
4071 tmp += i18n( "1 day", "%n days", days );
4072 tmp += ' ';
4073 secs -= ( days * 86400 );
4074 }
4075 int hours = secs / 3600;
4076 if ( hours > 0 ) {
4077 tmp += i18n( "1 hour", "%n hours", hours );
4078 tmp += ' ';
4079 secs -= ( hours * 3600 );
4080 }
4081 int mins = secs / 60;
4082 if ( mins > 0 ) {
4083 tmp += i18n( "1 minute", "%n minutes", mins );
4084 }
4085 return tmp;
4086}
4087
4089{
4090 TQString tmp;
4091 if ( incidence->type() == "Event" ) {
4092 Event *event = static_cast<Event *>( incidence );
4093 if ( event->hasEndDate() ) {
4094 if ( !event->doesFloat() ) {
4095 tmp = secs2Duration( event->dtStart().secsTo( event->dtEnd() ) );
4096 } else {
4097 tmp = i18n( "1 day", "%n days",
4098 event->dtStart().date().daysTo( event->dtEnd().date() ) + 1 );
4099 }
4100 } else {
4101 tmp = i18n( "forever" );
4102 }
4103 } else if ( incidence->type() == "Todo" ) {
4104 Todo *todo = static_cast<Todo *>( incidence );
4105 if ( todo->hasDueDate() ) {
4106 if ( todo->hasStartDate() ) {
4107 if ( !todo->doesFloat() ) {
4108 tmp = secs2Duration( todo->dtStart().secsTo( todo->dtDue() ) );
4109 } else {
4110 tmp = i18n( "1 day", "%n days",
4111 todo->dtStart().date().daysTo( todo->dtDue().date() ) + 1 );
4112 }
4113 }
4114 }
4115 }
4116 return tmp;
4117}
4118
4119TQStringList IncidenceFormatter::reminderStringList( Incidence *incidence, bool shortfmt )
4120{
4121 //TODO: implement shortfmt=false
4122 Q_UNUSED( shortfmt );
4123
4124 TQStringList reminderStringList;
4125
4126 if ( incidence ) {
4127 Alarm::List alarms = incidence->alarms();
4128 Alarm::List::ConstIterator it;
4129 for ( it = alarms.begin(); it != alarms.end(); ++it ) {
4130 Alarm *alarm = *it;
4131 int offset = 0;
4132 TQString remStr, atStr, offsetStr;
4133 if ( alarm->hasTime() ) {
4134 offset = 0;
4135 if ( alarm->time().isValid() ) {
4136 atStr = TDEGlobal::locale()->formatDateTime( alarm->time() );
4137 }
4138 } else if ( alarm->hasStartOffset() ) {
4139 offset = alarm->startOffset().asSeconds();
4140 if ( offset < 0 ) {
4141 offset = -offset;
4142 offsetStr = i18n( "N days/hours/minutes before the start datetime",
4143 "%1 before the start" );
4144 } else if ( offset > 0 ) {
4145 offsetStr = i18n( "N days/hours/minutes after the start datetime",
4146 "%1 after the start" );
4147 } else { //offset is 0
4148 if ( incidence->dtStart().isValid() ) {
4149 atStr = TDEGlobal::locale()->formatDateTime( incidence->dtStart() );
4150 }
4151 }
4152 } else if ( alarm->hasEndOffset() ) {
4153 offset = alarm->endOffset().asSeconds();
4154 if ( offset < 0 ) {
4155 offset = -offset;
4156 if ( incidence->type() == "Todo" ) {
4157 offsetStr = i18n( "N days/hours/minutes before the due datetime",
4158 "%1 before the to-do is due" );
4159 } else {
4160 offsetStr = i18n( "N days/hours/minutes before the end datetime",
4161 "%1 before the end" );
4162 }
4163 } else if ( offset > 0 ) {
4164 if ( incidence->type() == "Todo" ) {
4165 offsetStr = i18n( "N days/hours/minutes after the due datetime",
4166 "%1 after the to-do is due" );
4167 } else {
4168 offsetStr = i18n( "N days/hours/minutes after the end datetime",
4169 "%1 after the end" );
4170 }
4171 } else { //offset is 0
4172 if ( incidence->type() == "Todo" ) {
4173 Todo *t = static_cast<Todo *>( incidence );
4174 if ( t->dtDue().isValid() ) {
4175 atStr = TDEGlobal::locale()->formatDateTime( t->dtDue() );
4176 }
4177 } else {
4178 Event *e = static_cast<Event *>( incidence );
4179 if ( e->dtEnd().isValid() ) {
4180 atStr = TDEGlobal::locale()->formatDateTime( e->dtEnd() );
4181 }
4182 }
4183 }
4184 }
4185 if ( offset == 0 ) {
4186 if ( !atStr.isEmpty() ) {
4187 remStr = i18n( "reminder occurs at datetime", "at %1" ).arg( atStr );
4188 }
4189 } else {
4190 remStr = offsetStr.arg( secs2Duration( offset ) );
4191 }
4192
4193 if ( alarm->repeatCount() > 0 ) {
4194 TQString countStr = i18n( "repeats once", "repeats %n times", alarm->repeatCount() );
4195 TQString intervalStr = i18n( "interval is N days/hours/minutes", "interval is %1" ).
4196 arg( secs2Duration( alarm->snoozeTime().asSeconds() ) );
4197 TQString repeatStr = i18n( "(repeat string, interval string)", "(%1, %2)" ).
4198 arg( countStr, intervalStr );
4199 remStr = remStr + ' ' + repeatStr;
4200
4201 }
4202 reminderStringList << remStr;
4203 }
4204 }
4205
4206 return reminderStringList;
4207}
Provides the main "calendar" object class.
Provides a Calendar composed of several Calendar Resources.
This class represents an alarm notification.
Definition alarm.h:46
bool hasStartOffset() const
Return whether the alarm is defined in terms of an offset relative to the start of the event.
Definition alarm.cpp:456
Duration snoozeTime() const
Get how long the alarm snooze interval is.
Definition alarm.cpp:362
TQDateTime time() const
Return the date/time when an alarm goes off.
Definition alarm.cpp:329
Duration endOffset() const
Return offset of alarm in time relative to the end of the event.
Definition alarm.cpp:474
bool hasEndOffset() const
Return whether the alarm is defined in terms of an offset relative to the end of the event.
Definition alarm.cpp:461
void setDisplayAlarm(const TQString &text=TQString())
Set the alarm to be a display alarm.
Definition alarm.cpp:300
Duration startOffset() const
Return offset of alarm in time relative to the start of the event.
Definition alarm.cpp:451
bool hasTime() const
Return true, if the alarm has an explicit date/time.
Definition alarm.cpp:349
void setStartOffset(const Duration &)
Set offset of alarm in time relative to the start of the event.
Definition alarm.cpp:443
void setTime(const TQDateTime &alarmTime)
Set the time to trigger an alarm.
Definition alarm.cpp:321
int repeatCount() const
Get how many times an alarm repeats, after its initial occurrence.
Definition alarm.cpp:373
This class represents information related to an attachment.
Definition attachment.h:35
This class represents information related to an attendee of an event.
Definition attendee.h:37
void setRole(Role)
Set role of Attendee.
Definition attendee.cpp:117
TQString uid() const
Return unique id of the attendee.
Definition attendee.cpp:137
TQString delegate() const
Returns the delegate.
Definition attendee.h:135
Role role() const
Return role of Attendee.
Definition attendee.cpp:122
static TQString roleName(Role)
Return string represenation of role.
Definition attendee.cpp:142
TQString delegator() const
Returns the delegator.
Definition attendee.h:144
void setStatus(PartStat s)
Set status.
Definition attendee.cpp:56
static TQString statusName(PartStat)
Return string representation of attendee status.
Definition attendee.cpp:71
PartStat status() const
Return status.
Definition attendee.cpp:61
TQString statusStr() const
Return status as human-readable string.
Definition attendee.cpp:66
ErrorFormat * exception()
Return exception, if there is any, containing information about the last error that occurred.
Definition calformat.cpp:56
static void setApplication(const TQString &app, const TQString &productID)
Set the application name for use in unique IDs and error messages, and product ID for incidence PRODI...
Definition calformat.cpp:61
This class provides a calendar stored as a local file.
bool addEvent(Event *event)
Add Event to calendar.
This class provides a Calendar which is composed of other Calendars known as "Resources".
ResourceCalendar * resource(Incidence *incidence)
Get the Resource associated with a specified Incidence.
This is the main "calendar" object class.
Definition calendar.h:171
TQString customProperty(const TQCString &app, const TQCString &key) const
Return the value of a custom calendar property.
This class represents a duration.
Definition duration.h:34
int asSeconds() const
Returns the length of the duration in seconds.
Definition duration.cpp:165
TQString message()
Return format error message.
This class provides an Event in the sense of RFC2445.
Definition event.h:33
virtual TQDateTime dtEnd() const
Return end date and time.
Definition event.cpp:85
bool isMultiDay() const
Return true if the event spans multiple days, otherwise return false.
Definition event.cpp:126
bool hasEndDate() const
Return whether the event has an end date/time.
Definition event.cpp:121
This class provides information about free/busy time of a calendar user.
Definition freebusy.h:41
This class implements the iCalendar format.
Definition icalformat.h:44
ScheduleMessage * parseScheduleMessage(Calendar *, const TQString &s)
Parse scheduling message provided as string s.
TQString toString(Calendar *)
Return calendar information as string.
This class provides the interface for a visitor of calendar components.
virtual bool visit(Event *)
Reimplement this function in your concrete subclass of IncidenceBase::Visitor to perform actions on a...
This class provides the base class common to all calendar components.
TQStringList comments() const
Return all comments associated with this incidence.
bool doesFloat() const
Return true or false depending on whether the incidence "floats," i.e.
TQString uid() const
Return the unique id for the event.
Attendee * attendeeByMail(const TQString &) const
Return the Attendee with this email address.
const Attendee::List & attendees() const
Return list of attendees.
virtual TQDateTime dtStart() const
returns an event's starting date/time as a TQDateTime.
virtual bool accept(Visitor &)
Accept IncidenceVisitor.
bool isReadOnly() const
Return if the object is read-only.
static TQString msTNEFToVPart(const TQByteArray &tnef)
static TQString resourceString(Calendar *calendar, Incidence *incidence)
Returns a Calendar Resource label name for the specified Incidence.
static TQString durationString(Incidence *incidence)
Returns a duration string computed for the specified Incidence.
This class provides the base class common to all calendar components.
Definition incidence.h:48
const Alarm::List & alarms() const
All alarms that are associated with this incidence.
TQDateTime created() const
Return time and date of creation.
int revision() const
Return the number of revisions this event has seen.
TQString description() const
Return long description.
TQStringList categories() const
Return categories as a list of strings.
int priority() const
Return priority.
bool doesRecur() const
Forward to Recurrence::doesRecur().
bool isAlarmEnabled() const
Return whether any alarm associated with this incidence is enabled.
TQString location() const
Return the event's/todo's location.
Attachment::List attachments() const
Return list of all associated attachments.
TQString summary() const
Return short summary.
Recurrence * recurrence() const
Return the recurrence rule associated with this incidence.
This class provides a Journal in the sense of RFC2445.
Definition journal.h:34
This class represents a period of time.
Definition period.h:36
This class represents a person.
Definition person.h:35
structure for describing the n-th weekday of the month/year.
This class represents a recurrence rule for a calendar incidence.
Definition recurrence.h:90
ushort recurrenceType() const
Returns the event's recurrence status.
TQDateTime endDateTime() const
Returns the date/time of the last recurrence.
int frequency() const
Returns frequency of recurrence, in terms of the recurrence time period type.
TQValueList< RecurrenceRule::WDayPos > yearPositions() const
Returns the positions within a yearly recurrence.
TQBitArray days() const
Returns week day mask (bit 0 = Monday).
TQDate startDate() const
Return the start date/time of the recurrence.
Definition recurrence.h:116
TQValueList< int > monthDays() const
Returns list of day numbers of a month.
TQDateTime getPreviousDateTime(const TQDateTime &afterDateTime) const
Returns the date and time of the last previous recurrence, before the specified date/time.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
TQDate endDate() const
Returns the date of the last recurrence.
TQValueList< int > yearMonths() const
Returns the months within a yearly recurrence.
TQValueList< RecurrenceRule::WDayPos > monthPositions() const
Returns list of day positions in months.
TQValueList< int > yearDays() const
Returns the day numbers within a yearly recurrence.
TQValueList< int > yearDates() const
Returns the dates within a yearly recurrence.
TQDateTime getNextDateTime(const TQDateTime &preDateTime) const
Returns the date and time of the next recurrence, after the specified date/time.
This class provides the interfaces for a calendar resource.
virtual TQString subresourceIdentifier(Incidence *incidence)
Get the identifier of the subresource associated with a specified incidence.
virtual TQStringList subresources() const
If this resource has subresources, return a TQStringList of them.
virtual const TQString labelForSubresource(const TQString &resource) const
What is the label for this subresource?
This class provides an encapsulation of a scheduling message.
Definition scheduler.h:45
int method()
Return iTIP method associated with this message.
Definition scheduler.h:67
IncidenceBase * event()
Return event associated with this message.
Definition scheduler.h:63
Method
iTIP methods.
Definition scheduler.h:103
This class provides a Todo in the sense of RFC2445.
Definition todo.h:32
bool hasDueDate() const
Returns true if the todo has a due date, otherwise return false.
Definition todo.cpp:144
TQString completedStr() const
Returns string contaiting date and time when the todo was completed formatted according to the users ...
Definition todo.cpp:243
bool isCompleted() const
Returns true if the todo is 100% completed, otherwise return false.
Definition todo.cpp:217
bool hasStartDate() const
Returns true if the todo has a start date, otherwise return false.
Definition todo.cpp:157
TQDateTime dtStart(bool first=false) const
Returns the startdate of the todo.
Definition todo.cpp:177
int percentComplete() const
Returns how many percent of the task are completed.
Definition todo.cpp:263
TQDateTime dtDue(bool first=false) const
Returns due date and time.
Definition todo.cpp:117
Namespace KCal is for global classes, objects and/or functions in libkcal.
Definition alarm.h:38