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