You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4208 lines
136 KiB
4208 lines
136 KiB
/*
|
|
This file is part of libkcal.
|
|
|
|
Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
|
|
Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
|
|
Copyright (c) 2009-2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Library General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#include "incidenceformatter.h"
|
|
|
|
#include <libkcal/attachment.h>
|
|
#include <libkcal/event.h>
|
|
#include <libkcal/todo.h>
|
|
#include <libkcal/journal.h>
|
|
#include <libkcal/calendar.h>
|
|
#include <libkcal/calendarlocal.h>
|
|
#include <libkcal/icalformat.h>
|
|
#include <libkcal/freebusy.h>
|
|
#include <libkcal/calendarresources.h>
|
|
|
|
#include <libemailfunctions/email.h>
|
|
|
|
#include <ktnef/ktnefparser.h>
|
|
#include <ktnef/ktnefmessage.h>
|
|
#include <ktnef/ktnefdefs.h>
|
|
#include <kabc/phonenumber.h>
|
|
#include <kabc/vcardconverter.h>
|
|
#include <kabc/stdaddressbook.h>
|
|
|
|
#include <kapplication.h>
|
|
#include <kemailsettings.h>
|
|
|
|
#include <klocale.h>
|
|
#include <kglobal.h>
|
|
#include <kiconloader.h>
|
|
#include <kcalendarsystem.h>
|
|
#include <kmimetype.h>
|
|
|
|
#include <tqbuffer.h>
|
|
#include <tqstylesheet.h>
|
|
#include <tqdatetime.h>
|
|
#include <tqregexp.h>
|
|
|
|
#include <time.h>
|
|
|
|
using namespace KCal;
|
|
|
|
/*******************
|
|
* General helpers
|
|
*******************/
|
|
|
|
static TQString htmlAddLink( const TQString &ref, const TQString &text,
|
|
bool newline = true )
|
|
{
|
|
TQString tmpStr( "<a href=\"" + ref + "\">" + text + "</a>" );
|
|
if ( newline ) tmpStr += "\n";
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString htmlAddTag( const TQString & tag, const TQString & text )
|
|
{
|
|
int numLineBreaks = text.contains( "\n" );
|
|
TQString str = "<" + tag + ">";
|
|
TQString tmpText = text;
|
|
TQString tmpStr = str;
|
|
if( numLineBreaks >= 0 ) {
|
|
if ( numLineBreaks > 0) {
|
|
int pos = 0;
|
|
TQString tmp;
|
|
for( int i = 0; i <= numLineBreaks; i++ ) {
|
|
pos = tmpText.find( "\n" );
|
|
tmp = tmpText.left( pos );
|
|
tmpText = tmpText.right( tmpText.length() - pos - 1 );
|
|
tmpStr += tmp + "<br>";
|
|
}
|
|
} else {
|
|
tmpStr += tmpText;
|
|
}
|
|
}
|
|
tmpStr += "</" + tag + ">";
|
|
return tmpStr;
|
|
}
|
|
|
|
static bool iamAttendee( Attendee *attendee )
|
|
{
|
|
// Check if I'm this attendee
|
|
|
|
bool iam = false;
|
|
KEMailSettings settings;
|
|
TQStringList profiles = settings.profiles();
|
|
for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
|
|
settings.setProfile( *it );
|
|
if ( settings.getSetting( KEMailSettings::EmailAddress ) == attendee->email() ) {
|
|
iam = true;
|
|
break;
|
|
}
|
|
}
|
|
return iam;
|
|
}
|
|
|
|
static bool iamOrganizer( Incidence *incidence )
|
|
{
|
|
// Check if I'm the organizer for this incidence
|
|
|
|
if ( !incidence ) {
|
|
return false;
|
|
}
|
|
|
|
bool iam = false;
|
|
KEMailSettings settings;
|
|
TQStringList profiles = settings.profiles();
|
|
for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
|
|
settings.setProfile( *it );
|
|
if ( settings.getSetting( KEMailSettings::EmailAddress ) == incidence->organizer().email() ) {
|
|
iam = true;
|
|
break;
|
|
}
|
|
}
|
|
return iam;
|
|
}
|
|
|
|
static bool senderIsOrganizer( Incidence *incidence, const TQString &sender )
|
|
{
|
|
// Check if the specified sender is the organizer
|
|
|
|
if ( !incidence || sender.isEmpty() ) {
|
|
return true;
|
|
}
|
|
bool isorg = true;
|
|
TQString senderName, senderEmail;
|
|
if ( KPIM::getNameAndMail( sender, senderName, senderEmail ) ) {
|
|
// for this heuristic, we say the sender is the organizer if either the name or the email match.
|
|
if ( incidence->organizer().email() != senderEmail &&
|
|
incidence->organizer().name() != senderName ) {
|
|
isorg = false;
|
|
}
|
|
}
|
|
return isorg;
|
|
}
|
|
|
|
static TQString firstAttendeeName( Incidence *incidence, const TQString &defName )
|
|
{
|
|
TQString name;
|
|
if ( !incidence ) {
|
|
return name;
|
|
}
|
|
|
|
Attendee::List attendees = incidence->attendees();
|
|
if( attendees.count() > 0 ) {
|
|
Attendee *attendee = *attendees.begin();
|
|
name = attendee->name();
|
|
if ( name.isEmpty() ) {
|
|
name = attendee->email();
|
|
}
|
|
if ( name.isEmpty() ) {
|
|
name = defName;
|
|
}
|
|
}
|
|
return name;
|
|
}
|
|
|
|
/*******************************************************************
|
|
* Helper functions for the extensive display (display viewer)
|
|
*******************************************************************/
|
|
|
|
static TQString displayViewLinkPerson( const TQString& email, TQString name, TQString uid )
|
|
{
|
|
// Make the search, if there is an email address to search on,
|
|
// and either name or uid is missing
|
|
if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
|
|
KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
|
|
KABC::Addressee::List addressList = add_book->findByEmail( email );
|
|
if ( !addressList.isEmpty() ) {
|
|
KABC::Addressee o = addressList.first();
|
|
if ( !o.isEmpty() && addressList.size() < 2 ) {
|
|
if ( name.isEmpty() ) {
|
|
// No name set, so use the one from the addressbook
|
|
name = o.formattedName();
|
|
}
|
|
uid = o.uid();
|
|
} else {
|
|
// Email not found in the addressbook. Don't make a link
|
|
uid = TQString();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show the attendee
|
|
TQString tmpString;
|
|
if ( !uid.isEmpty() ) {
|
|
// There is a UID, so make a link to the addressbook
|
|
if ( name.isEmpty() ) {
|
|
// Use the email address for text
|
|
tmpString += htmlAddLink( "uid:" + uid, email );
|
|
} else {
|
|
tmpString += htmlAddLink( "uid:" + uid, name );
|
|
}
|
|
} else {
|
|
// No UID, just show some text
|
|
tmpString += ( name.isEmpty() ? email : name );
|
|
}
|
|
|
|
// Make the mailto link
|
|
if ( !email.isEmpty() ) {
|
|
KURL mailto;
|
|
mailto.setProtocol( "mailto" );
|
|
mailto.setPath( email );
|
|
const TQString iconPath =
|
|
TDEGlobal::iconLoader()->iconPath( "mail_new", KIcon::Small );
|
|
tmpString += " " +
|
|
htmlAddLink( mailto.url(),
|
|
"<img valign=\"top\" src=\"" + iconPath + "\">" );
|
|
}
|
|
|
|
return tmpString;
|
|
}
|
|
|
|
static TQString displayViewFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role )
|
|
{
|
|
TQString tmpStr;
|
|
Attendee::List::ConstIterator it;
|
|
Attendee::List attendees = incidence->attendees();
|
|
|
|
for ( it = attendees.begin(); it != attendees.end(); ++it ) {
|
|
Attendee *a = *it;
|
|
if ( a->role() != role ) {
|
|
// skip this role
|
|
continue;
|
|
}
|
|
if ( a->email() == incidence->organizer().email() ) {
|
|
// skip attendee that is also the organizer
|
|
continue;
|
|
}
|
|
tmpStr += displayViewLinkPerson( a->email(), a->name(), a->uid() );
|
|
if ( !a->delegator().isEmpty() ) {
|
|
tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
|
|
}
|
|
if ( !a->delegate().isEmpty() ) {
|
|
tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
|
|
}
|
|
tmpStr += "<br>";
|
|
}
|
|
if ( tmpStr.endsWith( "<br>" ) ) {
|
|
tmpStr.truncate( tmpStr.length() - 4 );
|
|
}
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatAttendees( Incidence *incidence )
|
|
{
|
|
TQString tmpStr, str;
|
|
|
|
// Add organizer link
|
|
int attendeeCount = incidence->attendees().count();
|
|
if ( attendeeCount > 1 ||
|
|
( attendeeCount == 1 &&
|
|
incidence->organizer().email() != incidence->attendees().first()->email() ) ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Organizer:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
displayViewLinkPerson( incidence->organizer().email(),
|
|
incidence->organizer().name(),
|
|
TQString() ) +
|
|
"</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
// Add "chair"
|
|
str = displayViewFormatAttendeeRoleList( incidence, Attendee::Chair );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Chair:" ) + "</b></td>";
|
|
tmpStr += "<td>" + str + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
// Add required participants
|
|
str = displayViewFormatAttendeeRoleList( incidence, Attendee::ReqParticipant );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Required Participants:" ) + "</b></td>";
|
|
tmpStr += "<td>" + str + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
// Add optional participants
|
|
str = displayViewFormatAttendeeRoleList( incidence, Attendee::OptParticipant );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Optional Participants:" ) + "</b></td>";
|
|
tmpStr += "<td>" + str + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
// Add observers
|
|
str = displayViewFormatAttendeeRoleList( incidence, Attendee::NonParticipant );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Observers:" ) + "</b></td>";
|
|
tmpStr += "<td>" + str + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatAttachments( Incidence *incidence )
|
|
{
|
|
TQString tmpStr;
|
|
Attachment::List as = incidence->attachments();
|
|
Attachment::List::ConstIterator it;
|
|
uint count = 0;
|
|
for( it = as.begin(); it != as.end(); ++it ) {
|
|
count++;
|
|
if ( (*it)->isUri() ) {
|
|
TQString name;
|
|
if ( (*it)->uri().startsWith( "kmail:" ) ) {
|
|
name = i18n( "Show mail" );
|
|
} else {
|
|
if ( (*it)->label().isEmpty() ) {
|
|
name = (*it)->uri();
|
|
} else {
|
|
name = (*it)->label();
|
|
}
|
|
}
|
|
tmpStr += htmlAddLink( (*it)->uri(), name );
|
|
} else {
|
|
tmpStr += htmlAddLink( "ATTACH:" + incidence->uid() + ':' + (*it)->label(),
|
|
(*it)->label(), false );
|
|
}
|
|
if ( count < as.count() ) {
|
|
tmpStr += "<br>";
|
|
}
|
|
}
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatCategories( Incidence *incidence )
|
|
{
|
|
// We do not use Incidence::categoriesStr() since it does not have whitespace
|
|
return incidence->categories().join( ", " );
|
|
}
|
|
|
|
static TQString displayViewFormatCreationDate( Incidence *incidence )
|
|
{
|
|
return i18n( "Creation date: %1" ).
|
|
arg( IncidenceFormatter::dateTimeToString( incidence->created(), false, true ) );
|
|
}
|
|
|
|
static TQString displayViewFormatBirthday( Event *event )
|
|
{
|
|
if ( !event ) {
|
|
return TQString();
|
|
}
|
|
if ( event->customProperty("KABC","BIRTHDAY") != "YES" ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString uid = event->customProperty("KABC","UID-1");
|
|
TQString name = event->customProperty("KABC","NAME-1");
|
|
TQString email= event->customProperty("KABC","EMAIL-1");
|
|
|
|
TQString tmpStr = displayViewLinkPerson( email, name, uid );
|
|
|
|
if ( event->customProperty( "KABC", "ANNIVERSARY") == "YES" ) {
|
|
uid = event->customProperty("KABC","UID-2");
|
|
name = event->customProperty("KABC","NAME-2");
|
|
email= event->customProperty("KABC","EMAIL-2");
|
|
tmpStr += "<br>";
|
|
tmpStr += displayViewLinkPerson( email, name, uid );
|
|
}
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatHeader( Incidence *incidence )
|
|
{
|
|
TQString tmpStr = "<table><tr>";
|
|
|
|
// show icons
|
|
{
|
|
tmpStr += "<td>";
|
|
|
|
if ( incidence->type() == "Event" ) {
|
|
TQString iconPath;
|
|
if ( incidence->customProperty( "KABC", "BIRTHDAY" ) == "YES" ) {
|
|
if ( incidence->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
|
|
iconPath =
|
|
TDEGlobal::iconLoader()->iconPath( "calendaranniversary", KIcon::Small );
|
|
} else {
|
|
iconPath = TDEGlobal::iconLoader()->iconPath( "calendarbirthday", KIcon::Small );
|
|
}
|
|
} else {
|
|
iconPath = TDEGlobal::iconLoader()->iconPath( "appointment", KIcon::Small );
|
|
}
|
|
tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
|
|
}
|
|
if ( incidence->type() == "Todo" ) {
|
|
tmpStr += "<img valign=\"top\" src=\"" +
|
|
TDEGlobal::iconLoader()->iconPath( "todo", KIcon::Small ) +
|
|
"\">";
|
|
}
|
|
if ( incidence->type() == "Journal" ) {
|
|
tmpStr += "<img valign=\"top\" src=\"" +
|
|
TDEGlobal::iconLoader()->iconPath( "journal", KIcon::Small ) +
|
|
"\">";
|
|
}
|
|
if ( incidence->isAlarmEnabled() ) {
|
|
tmpStr += "<img valign=\"top\" src=\"" +
|
|
TDEGlobal::iconLoader()->iconPath( "bell", KIcon::Small ) +
|
|
"\">";
|
|
}
|
|
if ( incidence->doesRecur() ) {
|
|
tmpStr += "<img valign=\"top\" src=\"" +
|
|
TDEGlobal::iconLoader()->iconPath( "recur", KIcon::Small ) +
|
|
"\">";
|
|
}
|
|
if ( incidence->isReadOnly() ) {
|
|
tmpStr += "<img valign=\"top\" src=\"" +
|
|
TDEGlobal::iconLoader()->iconPath( "readonlyevent", KIcon::Small ) +
|
|
"\">";
|
|
}
|
|
|
|
tmpStr += "</td>";
|
|
}
|
|
|
|
tmpStr += "<td>";
|
|
tmpStr += "<b><u>" + incidence->summary() + "</u></b>";
|
|
tmpStr += "</td>";
|
|
|
|
tmpStr += "</tr></table>";
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatEvent( Calendar *calendar, Event *event,
|
|
const TQDate &date )
|
|
{
|
|
if ( !event ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString tmpStr = displayViewFormatHeader( event );
|
|
|
|
tmpStr += "<table>";
|
|
tmpStr += "<col width=\"25%\"/>";
|
|
tmpStr += "<col width=\"75%\"/>";
|
|
|
|
if ( calendar ) {
|
|
TQString calStr = IncidenceFormatter::resourceString( calendar, event );
|
|
if ( !calStr.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
|
|
tmpStr += "<td>" + calStr + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
}
|
|
|
|
if ( !event->location().isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
|
|
tmpStr += "<td>" + event->location() + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
TQDateTime startDt = event->dtStart();
|
|
TQDateTime endDt = event->dtEnd();
|
|
if ( event->doesRecur() ) {
|
|
if ( date.isValid() ) {
|
|
TQDateTime dt( date, TQTime( 0, 0, 0 ) );
|
|
int diffDays = startDt.daysTo( dt );
|
|
dt = dt.addSecs( -1 );
|
|
startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
|
|
if ( event->hasEndDate() ) {
|
|
endDt = endDt.addDays( diffDays );
|
|
if ( startDt > endDt ) {
|
|
startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
|
|
endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
tmpStr += "<tr>";
|
|
if ( event->doesFloat() ) {
|
|
if ( event->isMultiDay() ) {
|
|
tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
i18n("<beginDate> - <endDate>","%1 - %2").
|
|
arg( IncidenceFormatter::dateToString( startDt, false ) ).
|
|
arg( IncidenceFormatter::dateToString( endDt, false ) ) +
|
|
"</td>";
|
|
} else {
|
|
tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
i18n("date as string","%1").
|
|
arg( IncidenceFormatter::dateToString( startDt, false ) ) +
|
|
"</td>";
|
|
}
|
|
} else {
|
|
if ( event->isMultiDay() ) {
|
|
tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
i18n("<beginDate> - <endDate>","%1 - %2").
|
|
arg( IncidenceFormatter::dateToString( startDt, false ) ).
|
|
arg( IncidenceFormatter::dateToString( endDt, false ) ) +
|
|
"</td>";
|
|
} else {
|
|
tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
i18n("date as string","%1").
|
|
arg( IncidenceFormatter::dateToString( startDt, false ) ) +
|
|
"</td>";
|
|
|
|
tmpStr += "</tr><tr>";
|
|
tmpStr += "<td><b>" + i18n( "Time:" ) + "</b></td>";
|
|
if ( event->hasEndDate() && startDt != endDt ) {
|
|
tmpStr += "<td>" +
|
|
i18n("<beginTime> - <endTime>","%1 - %2").
|
|
arg( IncidenceFormatter::timeToString( startDt, true ) ).
|
|
arg( IncidenceFormatter::timeToString( endDt, true ) ) +
|
|
"</td>";
|
|
} else {
|
|
tmpStr += "<td>" +
|
|
IncidenceFormatter::timeToString( startDt, true ) +
|
|
"</td>";
|
|
}
|
|
}
|
|
}
|
|
tmpStr += "</tr>";
|
|
|
|
TQString durStr = IncidenceFormatter::durationString( event );
|
|
if ( !durStr.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
|
|
tmpStr += "<td>" + durStr + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( event->doesRecur() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
IncidenceFormatter::recurrenceString( event ) +
|
|
"</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( event->customProperty("KABC","BIRTHDAY")== "YES" ) {
|
|
tmpStr += "<tr>";
|
|
if ( event->customProperty( "KABC", "ANNIVERSARY" ) == "YES" ) {
|
|
tmpStr += "<td><b>" + i18n( "Anniversary:" ) + "</b></td>";
|
|
} else {
|
|
tmpStr += "<td><b>" + i18n( "Birthday:" ) + "</b></td>";
|
|
}
|
|
tmpStr += "<td>" + displayViewFormatBirthday( event ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
tmpStr += "</table>";
|
|
return tmpStr;
|
|
}
|
|
|
|
if ( !event->description().isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
|
|
tmpStr += "<td>" + event->description() + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
// TODO: print comments?
|
|
|
|
int reminderCount = event->alarms().count();
|
|
if ( reminderCount > 0 && event->isAlarmEnabled() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Reminder:", "%n Reminders:", reminderCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + IncidenceFormatter::reminderStringList( event ).join( "<br>" ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
tmpStr += displayViewFormatAttendees( event );
|
|
|
|
int categoryCount = event->categories().count();
|
|
if ( categoryCount > 0 ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Category:", "%n Categories:", categoryCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + displayViewFormatCategories( event ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
int attachmentCount = event->attachments().count();
|
|
if ( attachmentCount > 0 ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Attachment:", "%n Attachments:", attachmentCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + displayViewFormatAttachments( event ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
tmpStr += "</table>";
|
|
|
|
tmpStr += "<em>" + displayViewFormatCreationDate( event ) + "</em>";
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatTodo( Calendar *calendar, Todo *todo,
|
|
const TQDate &date )
|
|
{
|
|
if ( !todo ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString tmpStr = displayViewFormatHeader( todo );
|
|
|
|
tmpStr += "<table>";
|
|
tmpStr += "<col width=\"25%\"/>";
|
|
tmpStr += "<col width=\"75%\"/>";
|
|
|
|
if ( calendar ) {
|
|
TQString calStr = IncidenceFormatter::resourceString( calendar, todo );
|
|
if ( !calStr.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
|
|
tmpStr += "<td>" + calStr + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
}
|
|
|
|
if ( !todo->location().isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Location:" ) + "</b></td>";
|
|
tmpStr += "<td>" + todo->location() + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
|
|
TQDateTime startDt = todo->dtStart();
|
|
if ( todo->doesRecur() ) {
|
|
if ( date.isValid() ) {
|
|
startDt.setDate( date );
|
|
}
|
|
}
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Start:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
IncidenceFormatter::dateTimeToString( startDt,
|
|
todo->doesFloat(), false ) +
|
|
"</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
|
|
TQDateTime dueDt = todo->dtDue();
|
|
if ( todo->doesRecur() ) {
|
|
if ( date.isValid() ) {
|
|
TQDateTime dt( date, TQTime( 0, 0, 0 ) );
|
|
dt = dt.addSecs( -1 );
|
|
dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
|
|
}
|
|
}
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Due:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
IncidenceFormatter::dateTimeToString( dueDt,
|
|
todo->doesFloat(), false ) +
|
|
"</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
TQString durStr = IncidenceFormatter::durationString( todo );
|
|
if ( !durStr.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Duration:" ) + "</b></td>";
|
|
tmpStr += "<td>" + durStr + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( todo->doesRecur() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Recurrence:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
IncidenceFormatter::recurrenceString( todo ) +
|
|
"</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( !todo->description().isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
|
|
tmpStr += "<td>" + todo->description() + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
// TODO: print comments?
|
|
|
|
int reminderCount = todo->alarms().count();
|
|
if ( reminderCount > 0 && todo->isAlarmEnabled() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Reminder:", "%n Reminders:", reminderCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + IncidenceFormatter::reminderStringList( todo ).join( "<br>" ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
tmpStr += displayViewFormatAttendees( todo );
|
|
|
|
int categoryCount = todo->categories().count();
|
|
if ( categoryCount > 0 ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Category:", "%n Categories:", categoryCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + displayViewFormatCategories( todo ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
if ( todo->priority() > 0 ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Priority:" ) + "</b></td>";
|
|
tmpStr += "<td>";
|
|
tmpStr += TQString::number( todo->priority() );
|
|
tmpStr += "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
tmpStr += "<tr>";
|
|
if ( todo->isCompleted() ) {
|
|
tmpStr += "<td><b>" + i18n( "Completed:" ) + "</b></td>";
|
|
tmpStr += "<td>";
|
|
tmpStr += todo->completedStr();
|
|
} else {
|
|
tmpStr += "<td><b>" + i18n( "Percent Done:" ) + "</b></td>";
|
|
tmpStr += "<td>";
|
|
tmpStr += i18n( "%1%" ).arg( todo->percentComplete() );
|
|
}
|
|
tmpStr += "</td>";
|
|
tmpStr += "</tr>";
|
|
|
|
int attachmentCount = todo->attachments().count();
|
|
if ( attachmentCount > 0 ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Attachment:", "Attachments:", attachmentCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + displayViewFormatAttachments( todo ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
tmpStr += "</table>";
|
|
|
|
tmpStr += "<em>" + displayViewFormatCreationDate( todo ) + "</em>";
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatJournal( Calendar *calendar, Journal *journal )
|
|
{
|
|
if ( !journal ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString tmpStr = displayViewFormatHeader( journal );
|
|
|
|
tmpStr += "<table>";
|
|
tmpStr += "<col width=\"25%\"/>";
|
|
tmpStr += "<col width=\"75%\"/>";
|
|
|
|
if ( calendar ) {
|
|
TQString calStr = IncidenceFormatter::resourceString( calendar, journal );
|
|
if ( !calStr.isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Calendar:" ) + "</b></td>";
|
|
tmpStr += "<td>" + calStr + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
}
|
|
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Date:" ) + "</b></td>";
|
|
tmpStr += "<td>" +
|
|
IncidenceFormatter::dateToString( journal->dtStart(), false ) +
|
|
"</td>";
|
|
tmpStr += "</tr>";
|
|
|
|
if ( !journal->description().isEmpty() ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" + i18n( "Description:" ) + "</b></td>";
|
|
tmpStr += "<td>" + journal->description() + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
|
|
int categoryCount = journal->categories().count();
|
|
if ( categoryCount > 0 ) {
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td><b>" +
|
|
i18n( "Category:", "%n Categories:", categoryCount ) +
|
|
"</b></td>";
|
|
tmpStr += "<td>" + displayViewFormatCategories( journal ) + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
tmpStr += "</table>";
|
|
|
|
tmpStr += "<em>" + displayViewFormatCreationDate( journal ) + "</em>";
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString displayViewFormatFreeBusy( Calendar * /*calendar*/, FreeBusy *fb )
|
|
{
|
|
if ( !fb ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString tmpStr = htmlAddTag( "h2",
|
|
htmlAddTag( "b",
|
|
i18n("Free/Busy information for %1").
|
|
arg( fb->organizer().fullName() ) ) );
|
|
|
|
tmpStr += htmlAddTag( "h4", i18n("Busy times in date range %1 - %2:").
|
|
arg( IncidenceFormatter::dateToString( fb->dtStart(), true ) ).
|
|
arg( IncidenceFormatter::dateToString( fb->dtEnd(), true ) ) );
|
|
|
|
TQValueList<Period> periods = fb->busyPeriods();
|
|
|
|
TQString text = htmlAddTag( "em", htmlAddTag( "b", i18n("Busy:") ) );
|
|
TQValueList<Period>::iterator it;
|
|
for ( it = periods.begin(); it != periods.end(); ++it ) {
|
|
Period per = *it;
|
|
if ( per.hasDuration() ) {
|
|
int dur = per.duration().asSeconds();
|
|
TQString cont;
|
|
if ( dur >= 3600 ) {
|
|
cont += i18n("1 hour ", "%n hours ", dur / 3600 );
|
|
dur %= 3600;
|
|
}
|
|
if ( dur >= 60 ) {
|
|
cont += i18n("1 minute ", "%n minutes ", dur / 60);
|
|
dur %= 60;
|
|
}
|
|
if ( dur > 0 ) {
|
|
cont += i18n("1 second", "%n seconds", dur);
|
|
}
|
|
text += i18n("startDate for duration", "%1 for %2").
|
|
arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
|
|
arg( cont );
|
|
text += "<br>";
|
|
} else {
|
|
if ( per.start().date() == per.end().date() ) {
|
|
text += i18n("date, fromTime - toTime ", "%1, %2 - %3").
|
|
arg( IncidenceFormatter::dateToString( per.start().date(), true ) ).
|
|
arg( IncidenceFormatter::timeToString( per.start(), true ) ).
|
|
arg( IncidenceFormatter::timeToString( per.end(), true ) );
|
|
} else {
|
|
text += i18n("fromDateTime - toDateTime", "%1 - %2").
|
|
arg( IncidenceFormatter::dateTimeToString( per.start(), false, true ) ).
|
|
arg( IncidenceFormatter::dateTimeToString( per.end(), false, true ) );
|
|
}
|
|
text += "<br>";
|
|
}
|
|
}
|
|
tmpStr += htmlAddTag( "p", text );
|
|
return tmpStr;
|
|
}
|
|
|
|
class IncidenceFormatter::EventViewerVisitor : public IncidenceBase::Visitor
|
|
{
|
|
public:
|
|
EventViewerVisitor()
|
|
: mCalendar( 0 ), mResult( "" ) {}
|
|
|
|
bool act( Calendar *calendar, IncidenceBase *incidence, const TQDate &date )
|
|
{
|
|
mCalendar = calendar;
|
|
mDate = date;
|
|
mResult = "";
|
|
return incidence->accept( *this );
|
|
}
|
|
TQString result() const { return mResult; }
|
|
|
|
protected:
|
|
bool visit( Event *event )
|
|
{
|
|
mResult = displayViewFormatEvent( mCalendar, event, mDate );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( Todo *todo )
|
|
{
|
|
mResult = displayViewFormatTodo( mCalendar, todo, mDate );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( Journal *journal )
|
|
{
|
|
mResult = displayViewFormatJournal( mCalendar, journal );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( FreeBusy *fb )
|
|
{
|
|
mResult = displayViewFormatFreeBusy( mCalendar, fb );
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
protected:
|
|
Calendar *mCalendar;
|
|
TQDate mDate;
|
|
TQString mResult;
|
|
};
|
|
|
|
TQString IncidenceFormatter::extensiveDisplayString( IncidenceBase *incidence )
|
|
{
|
|
return extensiveDisplayStr( 0, incidence, TQDate() );
|
|
}
|
|
|
|
TQString IncidenceFormatter::extensiveDisplayStr( Calendar *calendar,
|
|
IncidenceBase *incidence,
|
|
const TQDate &date )
|
|
{
|
|
if ( !incidence ) {
|
|
return TQString();
|
|
}
|
|
|
|
EventViewerVisitor v;
|
|
if ( v.act( calendar, incidence, date ) ) {
|
|
return v.result();
|
|
} else {
|
|
return TQString();
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
* Helper functions for the body part formatter of kmail (Invitations)
|
|
***********************************************************************/
|
|
|
|
static TQString string2HTML( const TQString& str )
|
|
{
|
|
return TQStyleSheet::convertFromPlainText(str, TQStyleSheetItem::WhiteSpaceNormal);
|
|
}
|
|
|
|
static TQString cleanHtml( const TQString &html )
|
|
{
|
|
TQRegExp rx( "<body[^>]*>(.*)</body>" );
|
|
rx.setCaseSensitive( false );
|
|
rx.search( html );
|
|
TQString body = rx.cap( 1 );
|
|
|
|
return TQStyleSheet::escape( body.remove( TQRegExp( "<[^>]*>" ) ).stripWhiteSpace() );
|
|
}
|
|
|
|
static TQString eventStartTimeStr( Event *event )
|
|
{
|
|
TQString tmp;
|
|
if ( !event->doesFloat() ) {
|
|
tmp = i18n( "%1: Start Date, %2: Start Time", "%1 %2" ).
|
|
arg( IncidenceFormatter::dateToString( event->dtStart(), true ),
|
|
IncidenceFormatter::timeToString( event->dtStart(), true ) );
|
|
} else {
|
|
tmp = i18n( "%1: Start Date", "%1 (all day)" ).
|
|
arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
static TQString eventEndTimeStr( Event *event )
|
|
{
|
|
TQString tmp;
|
|
if ( event->hasEndDate() && event->dtEnd().isValid() ) {
|
|
if ( !event->doesFloat() ) {
|
|
tmp = i18n( "%1: End Date, %2: End Time", "%1 %2" ).
|
|
arg( IncidenceFormatter::dateToString( event->dtEnd(), true ),
|
|
IncidenceFormatter::timeToString( event->dtEnd(), true ) );
|
|
} else {
|
|
tmp = i18n( "%1: End Date", "%1 (all day)" ).
|
|
arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
|
|
}
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
static TQString invitationRow( const TQString &cell1, const TQString &cell2 )
|
|
{
|
|
return "<tr><td>" + cell1 + "</td><td>" + cell2 + "</td></tr>\n";
|
|
}
|
|
|
|
static Attendee *findDelegatedFromMyAttendee( Incidence *incidence )
|
|
{
|
|
// Return the first attendee that was delegated-from me
|
|
|
|
Attendee *attendee = 0;
|
|
if ( !incidence ) {
|
|
return attendee;
|
|
}
|
|
|
|
KEMailSettings settings;
|
|
TQStringList profiles = settings.profiles();
|
|
for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
|
|
settings.setProfile( *it );
|
|
|
|
TQString delegatorName, delegatorEmail;
|
|
Attendee::List attendees = incidence->attendees();
|
|
Attendee::List::ConstIterator it2;
|
|
for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
|
|
Attendee *a = *it2;
|
|
KPIM::getNameAndMail( a->delegator(), delegatorName, delegatorEmail );
|
|
if ( settings.getSetting( KEMailSettings::EmailAddress ) == delegatorEmail ) {
|
|
attendee = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return attendee;
|
|
}
|
|
|
|
static Attendee *findMyAttendee( Incidence *incidence )
|
|
{
|
|
// Return the attendee for the incidence that is probably me
|
|
|
|
Attendee *attendee = 0;
|
|
if ( !incidence ) {
|
|
return attendee;
|
|
}
|
|
|
|
KEMailSettings settings;
|
|
TQStringList profiles = settings.profiles();
|
|
for( TQStringList::Iterator it=profiles.begin(); it!=profiles.end(); ++it ) {
|
|
settings.setProfile( *it );
|
|
|
|
Attendee::List attendees = incidence->attendees();
|
|
Attendee::List::ConstIterator it2;
|
|
for ( it2 = attendees.begin(); it2 != attendees.end(); ++it2 ) {
|
|
Attendee *a = *it2;
|
|
if ( settings.getSetting( KEMailSettings::EmailAddress ) == a->email() ) {
|
|
attendee = a;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return attendee;
|
|
}
|
|
|
|
static Attendee *findAttendee( Incidence *incidence, const TQString &email )
|
|
{
|
|
// Search for an attendee by email address
|
|
|
|
Attendee *attendee = 0;
|
|
if ( !incidence ) {
|
|
return attendee;
|
|
}
|
|
|
|
Attendee::List attendees = incidence->attendees();
|
|
Attendee::List::ConstIterator it;
|
|
for ( it = attendees.begin(); it != attendees.end(); ++it ) {
|
|
Attendee *a = *it;
|
|
if ( email == a->email() ) {
|
|
attendee = a;
|
|
break;
|
|
}
|
|
}
|
|
return attendee;
|
|
}
|
|
|
|
static bool rsvpRequested( Incidence *incidence )
|
|
{
|
|
if ( !incidence ) {
|
|
return false;
|
|
}
|
|
|
|
//use a heuristic to determine if a response is requested.
|
|
|
|
bool rsvp = true; // better send superfluously than not at all
|
|
Attendee::List attendees = incidence->attendees();
|
|
Attendee::List::ConstIterator it;
|
|
for ( it = attendees.begin(); it != attendees.end(); ++it ) {
|
|
if ( it == attendees.begin() ) {
|
|
rsvp = (*it)->RSVP(); // use what the first one has
|
|
} else {
|
|
if ( (*it)->RSVP() != rsvp ) {
|
|
rsvp = true; // they differ, default
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return rsvp;
|
|
}
|
|
|
|
static TQString rsvpRequestedStr( bool rsvpRequested, const TQString &role )
|
|
{
|
|
if ( rsvpRequested ) {
|
|
if ( role.isEmpty() ) {
|
|
return i18n( "Your response is requested" );
|
|
} else {
|
|
return i18n( "Your response as <b>%1</b> is requested" ).arg( role );
|
|
}
|
|
} else {
|
|
if ( role.isEmpty() ) {
|
|
return i18n( "No response is necessary" );
|
|
} else {
|
|
return i18n( "No response as <b>%1</b> is necessary" ).arg( role );
|
|
}
|
|
}
|
|
}
|
|
|
|
static TQString myStatusStr( Incidence *incidence )
|
|
{
|
|
TQString ret;
|
|
Attendee *a = findMyAttendee( incidence );
|
|
if ( a &&
|
|
a->status() != Attendee::NeedsAction && a->status() != Attendee::Delegated ) {
|
|
ret = i18n( "(<b>Note</b>: the Organizer preset your response to <b>%1</b>)" ).
|
|
arg( Attendee::statusName( a->status() ) );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static TQString invitationPerson( const TQString& email, TQString name, TQString uid )
|
|
{
|
|
// Make the search, if there is an email address to search on,
|
|
// and either name or uid is missing
|
|
if ( !email.isEmpty() && ( name.isEmpty() || uid.isEmpty() ) ) {
|
|
KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
|
|
KABC::Addressee::List addressList = add_book->findByEmail( email );
|
|
if ( !addressList.isEmpty() ) {
|
|
KABC::Addressee o = addressList.first();
|
|
if ( !o.isEmpty() && addressList.size() < 2 ) {
|
|
if ( name.isEmpty() ) {
|
|
// No name set, so use the one from the addressbook
|
|
name = o.formattedName();
|
|
}
|
|
uid = o.uid();
|
|
} else {
|
|
// Email not found in the addressbook. Don't make a link
|
|
uid = TQString();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show the attendee
|
|
TQString tmpString;
|
|
if ( !uid.isEmpty() ) {
|
|
// There is a UID, so make a link to the addressbook
|
|
if ( name.isEmpty() ) {
|
|
// Use the email address for text
|
|
tmpString += htmlAddLink( "uid:" + uid, email );
|
|
} else {
|
|
tmpString += htmlAddLink( "uid:" + uid, name );
|
|
}
|
|
} else {
|
|
// No UID, just show some text
|
|
tmpString += ( name.isEmpty() ? email : name );
|
|
}
|
|
tmpString += '\n';
|
|
|
|
// Make the mailto link
|
|
if ( !email.isEmpty() ) {
|
|
KCal::Person person( name, email );
|
|
KURL mailto;
|
|
mailto.setProtocol( "mailto" );
|
|
mailto.setPath( person.fullName() );
|
|
const TQString iconPath =
|
|
TDEGlobal::iconLoader()->iconPath( "mail_new", KIcon::Small );
|
|
tmpString += " " +
|
|
htmlAddLink( mailto.url(), "<img src=\"" + iconPath + "\">" )
|
|
;
|
|
}
|
|
tmpString += "\n";
|
|
|
|
return tmpString;
|
|
}
|
|
|
|
static TQString invitationsDetailsIncidence( Incidence *incidence, bool noHtmlMode )
|
|
{
|
|
// if description and comment -> use both
|
|
// if description, but no comment -> use the desc as the comment (and no desc)
|
|
// if comment, but no description -> use the comment and no description
|
|
|
|
TQString html;
|
|
TQString descr;
|
|
TQStringList comments;
|
|
|
|
if ( incidence->comments().isEmpty() ) {
|
|
if ( !incidence->description().isEmpty() ) {
|
|
// use description as comments
|
|
if ( !TQStyleSheet::mightBeRichText( incidence->description() ) ) {
|
|
comments << string2HTML( incidence->description() );
|
|
} else {
|
|
comments << incidence->description();
|
|
if ( noHtmlMode ) {
|
|
comments[0] = cleanHtml( comments[0] );
|
|
}
|
|
comments[0] = htmlAddTag( "p", comments[0] );
|
|
}
|
|
}
|
|
//else desc and comments are empty
|
|
} else {
|
|
// non-empty comments
|
|
TQStringList cl = incidence->comments();
|
|
uint i = 0;
|
|
for( TQStringList::Iterator it=cl.begin(); it!=cl.end(); ++it ) {
|
|
if ( !TQStyleSheet::mightBeRichText( *it ) ) {
|
|
comments.append( string2HTML( *it ) );
|
|
} else {
|
|
if ( noHtmlMode ) {
|
|
comments.append( cleanHtml( "<body>" + (*it) + "</body>" ) );
|
|
} else {
|
|
comments.append( *it );
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
if ( !incidence->description().isEmpty() ) {
|
|
// use description too
|
|
if ( !TQStyleSheet::mightBeRichText( incidence->description() ) ) {
|
|
descr = string2HTML( incidence->description() );
|
|
} else {
|
|
descr = incidence->description();
|
|
if ( noHtmlMode ) {
|
|
descr = cleanHtml( descr );
|
|
}
|
|
descr = htmlAddTag( "p", descr );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( !descr.isEmpty() ) {
|
|
html += "<p>";
|
|
html += "<table border=\"0\" style=\"margin-top:4px;\">";
|
|
html += "<tr><td><center>" +
|
|
htmlAddTag( "u", i18n( "Description:" ) ) +
|
|
"</center></td></tr>";
|
|
html += "<tr><td>" + descr + "</td></tr>";
|
|
html += "</table>";
|
|
}
|
|
|
|
if ( !comments.isEmpty() ) {
|
|
html += "<p>";
|
|
html += "<table border=\"0\" style=\"margin-top:4px;\">";
|
|
html += "<tr><td><center>" +
|
|
htmlAddTag( "u", i18n( "Comments:" ) ) +
|
|
"</center></td></tr>";
|
|
html += "<tr><td>";
|
|
if ( comments.count() > 1 ) {
|
|
html += "<ul>";
|
|
for ( uint i=0; i < comments.count(); ++i ) {
|
|
html += "<li>" + comments[i] + "</li>";
|
|
}
|
|
html += "</ul>";
|
|
} else {
|
|
html += comments[0];
|
|
}
|
|
html += "</td></tr>";
|
|
html += "</table>";
|
|
}
|
|
return html;
|
|
}
|
|
|
|
static TQString invitationDetailsEvent( Event* event, bool noHtmlMode )
|
|
{
|
|
// Invitation details are formatted into an HTML table
|
|
if ( !event ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString sSummary = i18n( "Summary unspecified" );
|
|
if ( !event->summary().isEmpty() ) {
|
|
if ( !TQStyleSheet::mightBeRichText( event->summary() ) ) {
|
|
sSummary = TQStyleSheet::escape( event->summary() );
|
|
} else {
|
|
sSummary = event->summary();
|
|
if ( noHtmlMode ) {
|
|
sSummary = cleanHtml( sSummary );
|
|
}
|
|
}
|
|
}
|
|
|
|
TQString sLocation = i18n( "Location unspecified" );
|
|
if ( !event->location().isEmpty() ) {
|
|
if ( !TQStyleSheet::mightBeRichText( event->location() ) ) {
|
|
sLocation = TQStyleSheet::escape( event->location() );
|
|
} else {
|
|
sLocation = event->location();
|
|
if ( noHtmlMode ) {
|
|
sLocation = cleanHtml( sLocation );
|
|
}
|
|
}
|
|
}
|
|
|
|
TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
|
|
TQString html = TQString("<div dir=\"%1\">\n").arg(dir);
|
|
|
|
html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
|
|
|
|
// Invitation summary & location rows
|
|
html += invitationRow( i18n( "What:" ), sSummary );
|
|
html += invitationRow( i18n( "Where:" ), sLocation );
|
|
|
|
if (event->doesRecur() == true) {
|
|
html += invitationRow( i18n( "First Start Time:" ), eventStartTimeStr( event ) );
|
|
html += invitationRow( i18n( "First End Time:" ), eventEndTimeStr( event ) );
|
|
}
|
|
// else {
|
|
// If a 1 day event
|
|
if ( event->dtStart().date() == event->dtEnd().date() ) {
|
|
html += invitationRow( i18n( "Date:" ),
|
|
IncidenceFormatter::dateToString( event->dtStart(), false ) );
|
|
if ( !event->doesFloat() ) {
|
|
html += invitationRow( i18n( "Time:" ),
|
|
IncidenceFormatter::timeToString( event->dtStart(), true ) +
|
|
" - " +
|
|
IncidenceFormatter::timeToString( event->dtEnd(), true ) );
|
|
}
|
|
} else {
|
|
html += invitationRow( i18n( "Starting date of an event", "From:" ),
|
|
IncidenceFormatter::dateToString( event->dtStart(), false ) );
|
|
if ( !event->doesFloat() ) {
|
|
html += invitationRow( i18n( "Starting time of an event", "At:" ),
|
|
IncidenceFormatter::timeToString( event->dtStart(), true ) );
|
|
}
|
|
if ( event->hasEndDate() ) {
|
|
html += invitationRow( i18n( "Ending date of an event", "To:" ),
|
|
IncidenceFormatter::dateToString( event->dtEnd(), false ) );
|
|
if ( !event->doesFloat() ) {
|
|
html += invitationRow( i18n( "Starting time of an event", "At:" ),
|
|
IncidenceFormatter::timeToString( event->dtEnd(), true ) );
|
|
}
|
|
} else {
|
|
html += invitationRow( i18n( "Ending date of an event", "To:" ),
|
|
i18n( "no end date specified" ) );
|
|
}
|
|
}
|
|
// }
|
|
|
|
// Invitation Duration Row
|
|
TQString durStr = IncidenceFormatter::durationString( event );
|
|
if ( !durStr.isEmpty() ) {
|
|
html += invitationRow( i18n( "Duration:" ), durStr );
|
|
}
|
|
|
|
// Recurrence Information Rows
|
|
if ( event->doesRecur() ) {
|
|
Recurrence *recur = event->recurrence();
|
|
html += invitationRow( i18n( "Recurrence:" ), IncidenceFormatter::recurrenceString( event ) );
|
|
|
|
DateList exceptions = recur->exDates();
|
|
if (exceptions.isEmpty() == false) {
|
|
bool isFirstExRow;
|
|
isFirstExRow = true;
|
|
DateList::ConstIterator ex_iter;
|
|
for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
|
|
if (isFirstExRow == true) {
|
|
isFirstExRow = false;
|
|
html += invitationRow( i18n("Cancelled on:"), TDEGlobal::locale()->formatDate(* ex_iter ) );
|
|
}
|
|
else {
|
|
html += invitationRow(" ", TDEGlobal::locale()->formatDate(* ex_iter ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
html += "</table>\n";
|
|
html += invitationsDetailsIncidence( event, noHtmlMode );
|
|
html += "</div>\n";
|
|
|
|
return html;
|
|
}
|
|
|
|
static TQString invitationDetailsTodo( Todo *todo, bool noHtmlMode )
|
|
{
|
|
// Task details are formatted into an HTML table
|
|
if ( !todo ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString sSummary = i18n( "Summary unspecified" );
|
|
if ( !todo->summary().isEmpty() ) {
|
|
if ( !TQStyleSheet::mightBeRichText( todo->summary() ) ) {
|
|
sSummary = TQStyleSheet::escape( todo->summary() );
|
|
} else {
|
|
sSummary = todo->summary();
|
|
if ( noHtmlMode ) {
|
|
sSummary = cleanHtml( sSummary );
|
|
}
|
|
}
|
|
}
|
|
|
|
TQString sLocation = i18n( "Location unspecified" );
|
|
if ( !todo->location().isEmpty() ) {
|
|
if ( !TQStyleSheet::mightBeRichText( todo->location() ) ) {
|
|
sLocation = TQStyleSheet::escape( todo->location() );
|
|
} else {
|
|
sLocation = todo->location();
|
|
if ( noHtmlMode ) {
|
|
sLocation = cleanHtml( sLocation );
|
|
}
|
|
}
|
|
}
|
|
|
|
TQString dir = ( TQApplication::reverseLayout() ? "rtl" : "ltr" );
|
|
TQString html = TQString("<div dir=\"%1\">\n").arg(dir);
|
|
html += "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n";
|
|
|
|
// Invitation summary & location rows
|
|
html += invitationRow( i18n( "What:" ), sSummary );
|
|
html += invitationRow( i18n( "Where:" ), sLocation );
|
|
|
|
if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
|
|
html += invitationRow( i18n( "Start Date:" ),
|
|
IncidenceFormatter::dateToString( todo->dtStart(), false ) );
|
|
if ( !todo->doesFloat() ) {
|
|
html += invitationRow( i18n( "Start Time:" ),
|
|
IncidenceFormatter::timeToString( todo->dtStart(), false ) );
|
|
}
|
|
}
|
|
if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
|
|
html += invitationRow( i18n( "Due Date:" ),
|
|
IncidenceFormatter::dateToString( todo->dtDue(), false ) );
|
|
if ( !todo->doesFloat() ) {
|
|
html += invitationRow( i18n( "Due Time:" ),
|
|
IncidenceFormatter::timeToString( todo->dtDue(), false ) );
|
|
}
|
|
|
|
} else {
|
|
html += invitationRow( i18n( "Due Date:" ), i18n( "Due Date: None", "None" ) );
|
|
}
|
|
|
|
html += "</table></div>\n";
|
|
html += invitationsDetailsIncidence( todo, noHtmlMode );
|
|
|
|
return html;
|
|
}
|
|
|
|
static TQString invitationDetailsJournal( Journal *journal, bool noHtmlMode )
|
|
{
|
|
if ( !journal ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString sSummary = i18n( "Summary unspecified" );
|
|
TQString sDescr = i18n( "Description unspecified" );
|
|
if ( ! journal->summary().isEmpty() ) {
|
|
sSummary = journal->summary();
|
|
if ( noHtmlMode ) {
|
|
sSummary = cleanHtml( sSummary );
|
|
}
|
|
}
|
|
if ( ! journal->description().isEmpty() ) {
|
|
sDescr = journal->description();
|
|
if ( noHtmlMode ) {
|
|
sDescr = cleanHtml( sDescr );
|
|
}
|
|
}
|
|
TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
|
|
html += invitationRow( i18n( "Summary:" ), sSummary );
|
|
html += invitationRow( i18n( "Date:" ),
|
|
IncidenceFormatter::dateToString( journal->dtStart(), false ) );
|
|
html += invitationRow( i18n( "Description:" ), sDescr );
|
|
html += "</table>\n";
|
|
html += invitationsDetailsIncidence( journal, noHtmlMode );
|
|
|
|
return html;
|
|
}
|
|
|
|
static TQString invitationDetailsFreeBusy( FreeBusy *fb, bool /*noHtmlMode*/ )
|
|
{
|
|
if ( !fb )
|
|
return TQString();
|
|
TQString html( "<table border=\"0\" cellpadding=\"1\" cellspacing=\"1\">\n" );
|
|
|
|
html += invitationRow( i18n("Person:"), fb->organizer().fullName() );
|
|
html += invitationRow( i18n("Start date:"),
|
|
IncidenceFormatter::dateToString( fb->dtStart(), true ) );
|
|
html += invitationRow( i18n("End date:"),
|
|
TDEGlobal::locale()->formatDate( fb->dtEnd().date(), true ) );
|
|
html += "<tr><td colspan=2><hr></td></tr>\n";
|
|
html += "<tr><td colspan=2>Busy periods given in this free/busy object:</td></tr>\n";
|
|
|
|
TQValueList<Period> periods = fb->busyPeriods();
|
|
|
|
TQValueList<Period>::iterator it;
|
|
for ( it = periods.begin(); it != periods.end(); ++it ) {
|
|
Period per = *it;
|
|
if ( per.hasDuration() ) {
|
|
int dur = per.duration().asSeconds();
|
|
TQString cont;
|
|
if ( dur >= 3600 ) {
|
|
cont += i18n("1 hour ", "%n hours ", dur / 3600);
|
|
dur %= 3600;
|
|
}
|
|
if ( dur >= 60 ) {
|
|
cont += i18n("1 minute", "%n minutes ", dur / 60);
|
|
dur %= 60;
|
|
}
|
|
if ( dur > 0 ) {
|
|
cont += i18n("1 second", "%n seconds", dur);
|
|
}
|
|
html += invitationRow( TQString(), i18n("startDate for duration", "%1 for %2")
|
|
.arg( TDEGlobal::locale()->formatDateTime( per.start(), false ) )
|
|
.arg(cont) );
|
|
} else {
|
|
TQString cont;
|
|
if ( per.start().date() == per.end().date() ) {
|
|
cont = i18n("date, fromTime - toTime ", "%1, %2 - %3")
|
|
.arg( TDEGlobal::locale()->formatDate( per.start().date() ) )
|
|
.arg( TDEGlobal::locale()->formatTime( per.start().time() ) )
|
|
.arg( TDEGlobal::locale()->formatTime( per.end().time() ) );
|
|
} else {
|
|
cont = i18n("fromDateTime - toDateTime", "%1 - %2")
|
|
.arg( TDEGlobal::locale()->formatDateTime( per.start(), false ) )
|
|
.arg( TDEGlobal::locale()->formatDateTime( per.end(), false ) );
|
|
}
|
|
|
|
html += invitationRow( TQString(), cont );
|
|
}
|
|
}
|
|
|
|
html += "</table>\n";
|
|
return html;
|
|
}
|
|
|
|
static bool replyMeansCounter( Incidence */*incidence*/ )
|
|
{
|
|
return false;
|
|
/**
|
|
see kolab/issue 3665 for an example of when we might use this for something
|
|
|
|
bool status = false;
|
|
if ( incidence ) {
|
|
// put code here that looks at the incidence and determines that
|
|
// the reply is meant to be a counter proposal. We think this happens
|
|
// with Outlook counter proposals, but we aren't sure how yet.
|
|
if ( condition ) {
|
|
status = true;
|
|
}
|
|
}
|
|
return status;
|
|
*/
|
|
}
|
|
|
|
static TQString invitationHeaderEvent( Event *event, Incidence *existingIncidence,
|
|
ScheduleMessage *msg, const TQString &sender )
|
|
{
|
|
if ( !msg || !event )
|
|
return TQString();
|
|
|
|
switch ( msg->method() ) {
|
|
case Scheduler::Publish:
|
|
return i18n( "This invitation has been published" );
|
|
case Scheduler::Request:
|
|
if ( existingIncidence && event->revision() > 0 ) {
|
|
return i18n( "This invitation has been updated by the organizer %1" ).
|
|
arg( event->organizer().fullName() );
|
|
}
|
|
if ( iamOrganizer( event ) ) {
|
|
return i18n( "I created this invitation" );
|
|
} else {
|
|
TQString orgStr;
|
|
if ( !event->organizer().fullName().isEmpty() ) {
|
|
orgStr = event->organizer().fullName();
|
|
} else if ( !event->organizer().email().isEmpty() ) {
|
|
orgStr = event->organizer().email();
|
|
}
|
|
if ( senderIsOrganizer( event, sender ) ) {
|
|
if ( !orgStr.isEmpty() ) {
|
|
return i18n( "You received an invitation from %1" ).arg( orgStr );
|
|
} else {
|
|
return i18n( "You received an invitation" );
|
|
}
|
|
} else {
|
|
if ( !orgStr.isEmpty() ) {
|
|
return i18n( "You received an invitation from %1 as a representative of %2" ).
|
|
arg( sender, orgStr );
|
|
} else {
|
|
return i18n( "You received an invitation from %1 as the organizer's representative" ).
|
|
arg( sender );
|
|
}
|
|
}
|
|
}
|
|
case Scheduler::Refresh:
|
|
return i18n( "This invitation was refreshed" );
|
|
case Scheduler::Cancel:
|
|
return i18n( "This invitation has been canceled" );
|
|
case Scheduler::Add:
|
|
return i18n( "Addition to the invitation" );
|
|
case Scheduler::Reply:
|
|
{
|
|
if ( replyMeansCounter( event ) ) {
|
|
return i18n( "%1 makes this counter proposal" ).
|
|
arg( firstAttendeeName( event, i18n( "Sender" ) ) );
|
|
}
|
|
|
|
Attendee::List attendees = event->attendees();
|
|
if( attendees.count() == 0 ) {
|
|
kdDebug(5850) << "No attendees in the iCal reply!" << endl;
|
|
return TQString();
|
|
}
|
|
if( attendees.count() != 1 ) {
|
|
kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
|
|
<< "but is " << attendees.count() << endl;
|
|
}
|
|
TQString attendeeName = firstAttendeeName( event, i18n( "Sender" ) );
|
|
|
|
TQString delegatorName, dummy;
|
|
Attendee* attendee = *attendees.begin();
|
|
KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
|
|
if ( delegatorName.isEmpty() ) {
|
|
delegatorName = attendee->delegator();
|
|
}
|
|
|
|
switch( attendee->status() ) {
|
|
case Attendee::NeedsAction:
|
|
return i18n( "%1 indicates this invitation still needs some action" ).arg( attendeeName );
|
|
case Attendee::Accepted:
|
|
if ( event->revision() > 0 ) {
|
|
if ( !sender.isEmpty() ) {
|
|
return i18n( "This invitation has been updated by attendee %1" ).arg( sender );
|
|
} else {
|
|
return i18n( "This invitation has been updated by an attendee" );
|
|
}
|
|
} else {
|
|
if ( delegatorName.isEmpty() ) {
|
|
return i18n( "%1 accepts this invitation" ).arg( attendeeName );
|
|
} else {
|
|
return i18n( "%1 accepts this invitation on behalf of %2" ).
|
|
arg( attendeeName ).arg( delegatorName );
|
|
}
|
|
}
|
|
case Attendee::Tentative:
|
|
if ( delegatorName.isEmpty() ) {
|
|
return i18n( "%1 tentatively accepts this invitation" ).
|
|
arg( attendeeName );
|
|
} else {
|
|
return i18n( "%1 tentatively accepts this invitation on behalf of %2" ).
|
|
arg( attendeeName ).arg( delegatorName );
|
|
}
|
|
case Attendee::Declined:
|
|
if ( delegatorName.isEmpty() ) {
|
|
return i18n( "%1 declines this invitation" ).arg( attendeeName );
|
|
} else {
|
|
return i18n( "%1 declines this invitation on behalf of %2" ).
|
|
arg( attendeeName ).arg( delegatorName );
|
|
}
|
|
case Attendee::Delegated: {
|
|
TQString delegate, dummy;
|
|
KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
|
|
if ( delegate.isEmpty() ) {
|
|
delegate = attendee->delegate();
|
|
}
|
|
if ( !delegate.isEmpty() ) {
|
|
return i18n( "%1 has delegated this invitation to %2" ).
|
|
arg( attendeeName ) .arg( delegate );
|
|
} else {
|
|
return i18n( "%1 has delegated this invitation" ).arg( attendeeName );
|
|
}
|
|
}
|
|
case Attendee::Completed:
|
|
return i18n( "This invitation is now completed" );
|
|
case Attendee::InProcess:
|
|
return i18n( "%1 is still processing the invitation" ).
|
|
arg( attendeeName );
|
|
default:
|
|
return i18n( "Unknown response to this invitation" );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Scheduler::Counter:
|
|
return i18n( "%1 makes this counter proposal" ).
|
|
arg( firstAttendeeName( event, i18n( "Sender" ) ) );
|
|
|
|
case Scheduler::Declinecounter:
|
|
return i18n( "%1 declines the counter proposal" ).
|
|
arg( firstAttendeeName( event, i18n( "Sender" ) ) );
|
|
|
|
case Scheduler::NoMethod:
|
|
return i18n("Error: iMIP message with unknown method: '%1'").
|
|
arg( msg->method() );
|
|
}
|
|
return TQString();
|
|
}
|
|
|
|
static TQString invitationHeaderTodo( Todo *todo, Incidence *existingIncidence,
|
|
ScheduleMessage *msg, const TQString &sender )
|
|
{
|
|
if ( !msg || !todo ) {
|
|
return TQString();
|
|
}
|
|
|
|
switch ( msg->method() ) {
|
|
case Scheduler::Publish:
|
|
return i18n("This task has been published");
|
|
case Scheduler::Request:
|
|
if ( existingIncidence && todo->revision() > 0 ) {
|
|
return i18n( "This task has been updated by the organizer %1" ).
|
|
arg( todo->organizer().fullName() );
|
|
} else {
|
|
if ( iamOrganizer( todo ) ) {
|
|
return i18n( "I created this task" );
|
|
} else {
|
|
TQString orgStr;
|
|
if ( !todo->organizer().fullName().isEmpty() ) {
|
|
orgStr = todo->organizer().fullName();
|
|
} else if ( !todo->organizer().email().isEmpty() ) {
|
|
orgStr = todo->organizer().email();
|
|
}
|
|
if ( senderIsOrganizer( todo, sender ) ) {
|
|
if ( !orgStr.isEmpty() ) {
|
|
return i18n( "You have been assigned this task by %1" ).arg( orgStr );
|
|
} else {
|
|
return i18n( "You have been assigned this task" );
|
|
}
|
|
} else {
|
|
if ( !orgStr.isEmpty() ) {
|
|
return i18n( "You have been assigned this task by %1 as a representative of %2" ).
|
|
arg( sender, orgStr );
|
|
} else {
|
|
return i18n( "You have been assigned this task by %1 as the organizer's representative" ).
|
|
arg( sender );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case Scheduler::Refresh:
|
|
return i18n( "This task was refreshed" );
|
|
case Scheduler::Cancel:
|
|
return i18n( "This task was canceled" );
|
|
case Scheduler::Add:
|
|
return i18n( "Addition to the task" );
|
|
case Scheduler::Reply:
|
|
{
|
|
if ( replyMeansCounter( todo ) ) {
|
|
return i18n( "%1 makes this counter proposal" ).
|
|
arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
|
|
}
|
|
|
|
Attendee::List attendees = todo->attendees();
|
|
if( attendees.count() == 0 ) {
|
|
kdDebug(5850) << "No attendees in the iCal reply!" << endl;
|
|
return TQString();
|
|
}
|
|
if( attendees.count() != 1 ) {
|
|
kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
|
|
<< "but is " << attendees.count() << endl;
|
|
}
|
|
TQString attendeeName = firstAttendeeName( todo, i18n( "Sender" ) );
|
|
|
|
TQString delegatorName, dummy;
|
|
Attendee* attendee = *attendees.begin();
|
|
KPIM::getNameAndMail( attendee->delegator(), delegatorName, dummy );
|
|
if ( delegatorName.isEmpty() ) {
|
|
delegatorName = attendee->delegator();
|
|
}
|
|
|
|
switch( attendee->status() ) {
|
|
case Attendee::NeedsAction:
|
|
return i18n( "%1 indicates this task assignment still needs some action" ).arg( attendeeName );
|
|
case Attendee::Accepted:
|
|
if ( todo->revision() > 0 ) {
|
|
if ( !sender.isEmpty() ) {
|
|
if ( todo->isCompleted() ) {
|
|
return i18n( "This task has been completed by assignee %1" ).arg( sender );
|
|
} else {
|
|
return i18n( "This task has been updated by assignee %1" ).arg( sender );
|
|
}
|
|
} else {
|
|
if ( todo->isCompleted() ) {
|
|
return i18n( "This task has been completed by an assignee" );
|
|
} else {
|
|
return i18n( "This task has been updated by an assignee" );
|
|
}
|
|
}
|
|
} else {
|
|
if ( delegatorName.isEmpty() ) {
|
|
return i18n( "%1 accepts this task" ).arg( attendeeName );
|
|
} else {
|
|
return i18n( "%1 accepts this task on behalf of %2" ).
|
|
arg( attendeeName ).arg( delegatorName );
|
|
}
|
|
}
|
|
case Attendee::Tentative:
|
|
if ( delegatorName.isEmpty() ) {
|
|
return i18n( "%1 tentatively accepts this task" ).
|
|
arg( attendeeName );
|
|
} else {
|
|
return i18n( "%1 tentatively accepts this task on behalf of %2" ).
|
|
arg( attendeeName ).arg( delegatorName );
|
|
}
|
|
case Attendee::Declined:
|
|
if ( delegatorName.isEmpty() ) {
|
|
return i18n( "%1 declines this task" ).arg( attendeeName );
|
|
} else {
|
|
return i18n( "%1 declines this task on behalf of %2" ).
|
|
arg( attendeeName ).arg( delegatorName );
|
|
}
|
|
case Attendee::Delegated: {
|
|
TQString delegate, dummy;
|
|
KPIM::getNameAndMail( attendee->delegate(), delegate, dummy );
|
|
if ( delegate.isEmpty() ) {
|
|
delegate = attendee->delegate();
|
|
}
|
|
if ( !delegate.isEmpty() ) {
|
|
return i18n( "%1 has delegated this request for the task to %2" ).
|
|
arg( attendeeName ).arg( delegate );
|
|
} else {
|
|
return i18n( "%1 has delegated this request for the task" ).
|
|
arg( attendeeName );
|
|
}
|
|
}
|
|
case Attendee::Completed:
|
|
return i18n( "The request for this task is now completed" );
|
|
case Attendee::InProcess:
|
|
return i18n( "%1 is still processing the task" ).
|
|
arg( attendeeName );
|
|
default:
|
|
return i18n( "Unknown response to this task" );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Scheduler::Counter:
|
|
return i18n( "%1 makes this counter proposal" ).
|
|
arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
|
|
|
|
case Scheduler::Declinecounter:
|
|
return i18n( "%1 declines the counter proposal" ).
|
|
arg( firstAttendeeName( todo, i18n( "Sender" ) ) );
|
|
|
|
case Scheduler::NoMethod:
|
|
return i18n( "Error: iMIP message with unknown method: '%1'" ).
|
|
arg( msg->method() );
|
|
}
|
|
return TQString();
|
|
}
|
|
|
|
static TQString invitationHeaderJournal( Journal *journal, ScheduleMessage *msg )
|
|
{
|
|
if ( !msg || !journal ) {
|
|
return TQString();
|
|
}
|
|
|
|
switch ( msg->method() ) {
|
|
case Scheduler::Publish:
|
|
return i18n("This journal has been published");
|
|
case Scheduler::Request:
|
|
return i18n( "You have been assigned this journal" );
|
|
case Scheduler::Refresh:
|
|
return i18n( "This journal was refreshed" );
|
|
case Scheduler::Cancel:
|
|
return i18n( "This journal was canceled" );
|
|
case Scheduler::Add:
|
|
return i18n( "Addition to the journal" );
|
|
case Scheduler::Reply:
|
|
{
|
|
if ( replyMeansCounter( journal ) ) {
|
|
return i18n( "Sender makes this counter proposal" );
|
|
}
|
|
|
|
Attendee::List attendees = journal->attendees();
|
|
if( attendees.count() == 0 ) {
|
|
kdDebug(5850) << "No attendees in the iCal reply!" << endl;
|
|
return TQString();
|
|
}
|
|
if( attendees.count() != 1 ) {
|
|
kdDebug(5850) << "Warning: attendeecount in the reply should be 1 "
|
|
<< "but is " << attendees.count() << endl;
|
|
}
|
|
Attendee* attendee = *attendees.begin();
|
|
|
|
switch( attendee->status() ) {
|
|
case Attendee::NeedsAction:
|
|
return i18n( "Sender indicates this journal assignment still needs some action" );
|
|
case Attendee::Accepted:
|
|
return i18n( "Sender accepts this journal" );
|
|
case Attendee::Tentative:
|
|
return i18n( "Sender tentatively accepts this journal" );
|
|
case Attendee::Declined:
|
|
return i18n( "Sender declines this journal" );
|
|
case Attendee::Delegated:
|
|
return i18n( "Sender has delegated this request for the journal" );
|
|
case Attendee::Completed:
|
|
return i18n( "The request for this journal is now completed" );
|
|
case Attendee::InProcess:
|
|
return i18n( "Sender is still processing the invitation" );
|
|
default:
|
|
return i18n( "Unknown response to this journal" );
|
|
}
|
|
break;
|
|
}
|
|
case Scheduler::Counter:
|
|
return i18n( "Sender makes this counter proposal" );
|
|
case Scheduler::Declinecounter:
|
|
return i18n( "Sender declines the counter proposal" );
|
|
case Scheduler::NoMethod:
|
|
return i18n("Error: iMIP message with unknown method: '%1'").
|
|
arg( msg->method() );
|
|
}
|
|
return TQString();
|
|
}
|
|
|
|
static TQString invitationHeaderFreeBusy( FreeBusy *fb, ScheduleMessage *msg )
|
|
{
|
|
if ( !msg || !fb ) {
|
|
return TQString();
|
|
}
|
|
|
|
switch ( msg->method() ) {
|
|
case Scheduler::Publish:
|
|
return i18n("This free/busy list has been published");
|
|
case Scheduler::Request:
|
|
return i18n( "The free/busy list has been requested" );
|
|
case Scheduler::Refresh:
|
|
return i18n( "This free/busy list was refreshed" );
|
|
case Scheduler::Cancel:
|
|
return i18n( "This free/busy list was canceled" );
|
|
case Scheduler::Add:
|
|
return i18n( "Addition to the free/busy list" );
|
|
case Scheduler::NoMethod:
|
|
default:
|
|
return i18n("Error: Free/Busy iMIP message with unknown method: '%1'").
|
|
arg( msg->method() );
|
|
}
|
|
}
|
|
|
|
static TQString invitationAttendees( Incidence *incidence )
|
|
{
|
|
TQString tmpStr;
|
|
if ( !incidence ) {
|
|
return tmpStr;
|
|
}
|
|
|
|
if ( incidence->type() == "Todo" ) {
|
|
tmpStr += htmlAddTag( "u", i18n( "Assignees" ) );
|
|
} else {
|
|
tmpStr += htmlAddTag( "u", i18n( "Attendees" ) );
|
|
}
|
|
tmpStr += "<br/>";
|
|
|
|
int count=0;
|
|
Attendee::List attendees = incidence->attendees();
|
|
if ( !attendees.isEmpty() ) {
|
|
|
|
Attendee::List::ConstIterator it;
|
|
for( it = attendees.begin(); it != attendees.end(); ++it ) {
|
|
Attendee *a = *it;
|
|
if ( !iamAttendee( a ) ) {
|
|
count++;
|
|
if ( count == 1 ) {
|
|
tmpStr += "<table border=\"1\" cellpadding=\"1\" cellspacing=\"0\" columns=\"2\">";
|
|
}
|
|
tmpStr += "<tr>";
|
|
tmpStr += "<td>";
|
|
tmpStr += invitationPerson( a->email(), a->name(), TQString() );
|
|
if ( !a->delegator().isEmpty() ) {
|
|
tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
|
|
}
|
|
if ( !a->delegate().isEmpty() ) {
|
|
tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
|
|
}
|
|
tmpStr += "</td>";
|
|
tmpStr += "<td>" + a->statusStr() + "</td>";
|
|
tmpStr += "</tr>";
|
|
}
|
|
}
|
|
}
|
|
if ( count ) {
|
|
tmpStr += "</table>";
|
|
} else {
|
|
tmpStr += "<i>" + i18n( "No attendee", "None" ) + "</i>";
|
|
}
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString invitationAttachments( InvitationFormatterHelper *helper, Incidence *incidence )
|
|
{
|
|
TQString tmpStr;
|
|
if ( !incidence ) {
|
|
return tmpStr;
|
|
}
|
|
|
|
Attachment::List attachments = incidence->attachments();
|
|
if ( !attachments.isEmpty() ) {
|
|
tmpStr += i18n( "Attached Documents:" ) + "<ol>";
|
|
|
|
Attachment::List::ConstIterator it;
|
|
for( it = attachments.begin(); it != attachments.end(); ++it ) {
|
|
Attachment *a = *it;
|
|
tmpStr += "<li>";
|
|
// Attachment icon
|
|
KMimeType::Ptr mimeType = KMimeType::mimeType( a->mimeType() );
|
|
const TQString iconStr = mimeType ? mimeType->icon( a->uri(), false ) : TQString( "application-octet-stream" );
|
|
const TQString iconPath = TDEGlobal::iconLoader()->iconPath( iconStr, KIcon::Small );
|
|
if ( !iconPath.isEmpty() ) {
|
|
tmpStr += "<img valign=\"top\" src=\"" + iconPath + "\">";
|
|
}
|
|
tmpStr += helper->makeLink( "ATTACH:" + a->label(), a->label() );
|
|
tmpStr += "</li>";
|
|
}
|
|
tmpStr += "</ol>";
|
|
}
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
class IncidenceFormatter::ScheduleMessageVisitor
|
|
: public IncidenceBase::Visitor
|
|
{
|
|
public:
|
|
ScheduleMessageVisitor() : mExistingIncidence( 0 ), mMessage( 0 ) { mResult = ""; }
|
|
bool act( IncidenceBase *incidence, Incidence *existingIncidence, ScheduleMessage *msg,
|
|
const TQString &sender )
|
|
{
|
|
mExistingIncidence = existingIncidence;
|
|
mMessage = msg;
|
|
mSender = sender;
|
|
return incidence->accept( *this );
|
|
}
|
|
TQString result() const { return mResult; }
|
|
|
|
protected:
|
|
TQString mResult;
|
|
Incidence *mExistingIncidence;
|
|
ScheduleMessage *mMessage;
|
|
TQString mSender;
|
|
};
|
|
|
|
class IncidenceFormatter::InvitationHeaderVisitor
|
|
: public IncidenceFormatter::ScheduleMessageVisitor
|
|
{
|
|
protected:
|
|
bool visit( Event *event )
|
|
{
|
|
mResult = invitationHeaderEvent( event, mExistingIncidence, mMessage, mSender );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( Todo *todo )
|
|
{
|
|
mResult = invitationHeaderTodo( todo, mExistingIncidence, mMessage, mSender );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( Journal *journal )
|
|
{
|
|
mResult = invitationHeaderJournal( journal, mMessage );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( FreeBusy *fb )
|
|
{
|
|
mResult = invitationHeaderFreeBusy( fb, mMessage );
|
|
return !mResult.isEmpty();
|
|
}
|
|
};
|
|
|
|
class IncidenceFormatter::InvitationBodyVisitor
|
|
: public IncidenceFormatter::ScheduleMessageVisitor
|
|
{
|
|
public:
|
|
InvitationBodyVisitor( bool noHtmlMode )
|
|
: ScheduleMessageVisitor(), mNoHtmlMode( noHtmlMode ) {}
|
|
|
|
protected:
|
|
bool visit( Event *event )
|
|
{
|
|
mResult = invitationDetailsEvent( event, mNoHtmlMode );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( Todo *todo )
|
|
{
|
|
mResult = invitationDetailsTodo( todo, mNoHtmlMode );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( Journal *journal )
|
|
{
|
|
mResult = invitationDetailsJournal( journal, mNoHtmlMode );
|
|
return !mResult.isEmpty();
|
|
}
|
|
bool visit( FreeBusy *fb )
|
|
{
|
|
mResult = invitationDetailsFreeBusy( fb, mNoHtmlMode );
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
private:
|
|
bool mNoHtmlMode;
|
|
};
|
|
|
|
class IncidenceFormatter::IncidenceCompareVisitor
|
|
: public IncidenceBase::Visitor
|
|
{
|
|
public:
|
|
IncidenceCompareVisitor() : mExistingIncidence(0) {}
|
|
bool act( IncidenceBase *incidence, Incidence *existingIncidence, int method )
|
|
{
|
|
Incidence *inc = dynamic_cast<Incidence*>( incidence );
|
|
if ( !inc || !existingIncidence || inc->revision() <= existingIncidence->revision() )
|
|
return false;
|
|
mExistingIncidence = existingIncidence;
|
|
mMethod = method;
|
|
return incidence->accept( *this );
|
|
}
|
|
|
|
TQString result() const
|
|
{
|
|
if ( mChanges.isEmpty() ) {
|
|
return TQString();
|
|
}
|
|
TQString html = "<div align=\"left\"><ul><li>";
|
|
html += mChanges.join( "</li><li>" );
|
|
html += "</li><ul></div>";
|
|
return html;
|
|
}
|
|
|
|
protected:
|
|
bool visit( Event *event )
|
|
{
|
|
compareEvents( event, dynamic_cast<Event*>( mExistingIncidence ) );
|
|
compareIncidences( event, mExistingIncidence, mMethod );
|
|
return !mChanges.isEmpty();
|
|
}
|
|
bool visit( Todo *todo )
|
|
{
|
|
compareTodos( todo, dynamic_cast<Todo*>( mExistingIncidence ) );
|
|
compareIncidences( todo, mExistingIncidence, mMethod );
|
|
return !mChanges.isEmpty();
|
|
}
|
|
bool visit( Journal *journal )
|
|
{
|
|
compareIncidences( journal, mExistingIncidence, mMethod );
|
|
return !mChanges.isEmpty();
|
|
}
|
|
bool visit( FreeBusy *fb )
|
|
{
|
|
Q_UNUSED( fb );
|
|
return !mChanges.isEmpty();
|
|
}
|
|
|
|
private:
|
|
void compareEvents( Event *newEvent, Event *oldEvent )
|
|
{
|
|
if ( !oldEvent || !newEvent )
|
|
return;
|
|
if ( oldEvent->dtStart() != newEvent->dtStart() || oldEvent->doesFloat() != newEvent->doesFloat() )
|
|
mChanges += i18n( "The invitation starting time has been changed from %1 to %2" )
|
|
.arg( eventStartTimeStr( oldEvent ) ).arg( eventStartTimeStr( newEvent ) );
|
|
if ( oldEvent->dtEnd() != newEvent->dtEnd() || oldEvent->doesFloat() != newEvent->doesFloat() )
|
|
mChanges += i18n( "The invitation ending time has been changed from %1 to %2" )
|
|
.arg( eventEndTimeStr( oldEvent ) ).arg( eventEndTimeStr( newEvent ) );
|
|
}
|
|
|
|
void compareTodos( Todo *newTodo, Todo *oldTodo )
|
|
{
|
|
if ( !oldTodo || !newTodo ) {
|
|
return;
|
|
}
|
|
|
|
if ( !oldTodo->isCompleted() && newTodo->isCompleted() ) {
|
|
mChanges += i18n( "The task has been completed" );
|
|
}
|
|
if ( oldTodo->isCompleted() && !newTodo->isCompleted() ) {
|
|
mChanges += i18n( "The task is no longer completed" );
|
|
}
|
|
if ( oldTodo->percentComplete() != newTodo->percentComplete() ) {
|
|
const TQString oldPer = i18n( "%1%" ).arg( oldTodo->percentComplete() );
|
|
const TQString newPer = i18n( "%1%" ).arg( newTodo->percentComplete() );
|
|
mChanges += i18n( "The task completed percentage has changed from %1 to %2" ).
|
|
arg( oldPer, newPer );
|
|
}
|
|
|
|
if ( !oldTodo->hasStartDate() && newTodo->hasStartDate() ) {
|
|
mChanges += i18n( "A task starting time has been added" );
|
|
}
|
|
if ( oldTodo->hasStartDate() && !newTodo->hasStartDate() ) {
|
|
mChanges += i18n( "The task starting time has been removed" );
|
|
}
|
|
if ( oldTodo->hasStartDate() && newTodo->hasStartDate() &&
|
|
oldTodo->dtStart() != newTodo->dtStart() ) {
|
|
mChanges += i18n( "The task starting time has been changed from %1 to %2" ).
|
|
arg( dateTimeToString( oldTodo->dtStart(), oldTodo->doesFloat(), false ),
|
|
dateTimeToString( newTodo->dtStart(), newTodo->doesFloat(), false ) );
|
|
}
|
|
|
|
if ( !oldTodo->hasDueDate() && newTodo->hasDueDate() ) {
|
|
mChanges += i18n( "A task due time has been added" );
|
|
}
|
|
if ( oldTodo->hasDueDate() && !newTodo->hasDueDate() ) {
|
|
mChanges += i18n( "The task due time has been removed" );
|
|
}
|
|
if ( oldTodo->hasDueDate() && newTodo->hasDueDate() &&
|
|
oldTodo->dtDue() != newTodo->dtDue() ) {
|
|
mChanges += i18n( "The task due time has been changed from %1 to %2" ).
|
|
arg( dateTimeToString( oldTodo->dtDue(), oldTodo->doesFloat(), false ),
|
|
dateTimeToString( newTodo->dtDue(), newTodo->doesFloat(), false ) );
|
|
}
|
|
}
|
|
|
|
void compareIncidences( Incidence *newInc, Incidence *oldInc, int method )
|
|
{
|
|
if ( !oldInc || !newInc )
|
|
return;
|
|
if ( oldInc->summary() != newInc->summary() )
|
|
mChanges += i18n( "The summary has been changed to: \"%1\"" ).arg( newInc->summary() );
|
|
if ( oldInc->location() != newInc->location() )
|
|
mChanges += i18n( "The location has been changed to: \"%1\"" ).arg( newInc->location() );
|
|
if ( oldInc->description() != newInc->description() )
|
|
mChanges += i18n( "The description has been changed to: \"%1\"" ).arg( newInc->description() );
|
|
Attendee::List oldAttendees = oldInc->attendees();
|
|
Attendee::List newAttendees = newInc->attendees();
|
|
for ( Attendee::List::ConstIterator it = newAttendees.constBegin();
|
|
it != newAttendees.constEnd(); ++it ) {
|
|
Attendee *oldAtt = oldInc->attendeeByMail( (*it)->email() );
|
|
if ( !oldAtt ) {
|
|
mChanges += i18n( "Attendee %1 has been added" ).arg( (*it)->fullName() );
|
|
} else {
|
|
if ( oldAtt->status() != (*it)->status() )
|
|
mChanges += i18n( "The status of attendee %1 has been changed to: %2" ).
|
|
arg( (*it)->fullName() ).arg( (*it)->statusStr() );
|
|
}
|
|
}
|
|
if ( method == Scheduler::Request ) {
|
|
for ( Attendee::List::ConstIterator it = oldAttendees.constBegin();
|
|
it != oldAttendees.constEnd(); ++it ) {
|
|
if ( (*it)->email() != oldInc->organizer().email() ) {
|
|
Attendee *newAtt = newInc->attendeeByMail( (*it)->email() );
|
|
if ( !newAtt ) {
|
|
mChanges += i18n( "Attendee %1 has been removed" ).arg( (*it)->fullName() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
Incidence *mExistingIncidence;
|
|
int mMethod;
|
|
TQStringList mChanges;
|
|
};
|
|
|
|
|
|
TQString InvitationFormatterHelper::makeLink( const TQString &id, const TQString &text )
|
|
{
|
|
if ( !id.startsWith( "ATTACH:" ) ) {
|
|
TQString res = TQString( "<a href=\"%1\"><b>%2</b></a>" ).
|
|
arg( generateLinkURL( id ), text );
|
|
return res;
|
|
} else {
|
|
// draw the attachment links in non-bold face
|
|
TQString res = TQString( "<a href=\"%1\">%2</a>" ).
|
|
arg( generateLinkURL( id ), text );
|
|
return res;
|
|
}
|
|
}
|
|
|
|
// Check if the given incidence is likely one that we own instead one from
|
|
// a shared calendar (Kolab-specific)
|
|
static bool incidenceOwnedByMe( Calendar *calendar, Incidence *incidence )
|
|
{
|
|
CalendarResources *cal = dynamic_cast<CalendarResources*>( calendar );
|
|
if ( !cal || !incidence ) {
|
|
return true;
|
|
}
|
|
ResourceCalendar *res = cal->resource( incidence );
|
|
if ( !res ) {
|
|
return true;
|
|
}
|
|
const TQString subRes = res->subresourceIdentifier( incidence );
|
|
if ( !subRes.contains( "/.INBOX.directory/" ) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// The spacer for the invitation buttons
|
|
static TQString spacer = "<td> </td>";
|
|
// The open & close table cell tags for the invitation buttons
|
|
static TQString tdOpen = "<td>";
|
|
static TQString tdClose = "</td>" + spacer;
|
|
|
|
static TQString responseButtons( Incidence *inc, bool rsvpReq, bool rsvpRec,
|
|
InvitationFormatterHelper *helper )
|
|
{
|
|
TQString html;
|
|
if ( !helper ) {
|
|
return html;
|
|
}
|
|
|
|
if ( !rsvpReq && ( inc && inc->revision() == 0 ) ) {
|
|
// Record only
|
|
html += tdOpen;
|
|
html += helper->makeLink( "record", i18n( "[Record]" ) );
|
|
html += tdClose;
|
|
|
|
// Move to trash
|
|
html += tdOpen;
|
|
html += helper->makeLink( "delete", i18n( "[Move to Trash]" ) );
|
|
html += tdClose;
|
|
|
|
} else {
|
|
|
|
// Accept
|
|
html += tdOpen;
|
|
html += helper->makeLink( "accept", i18n( "[Accept]" ) );
|
|
html += tdClose;
|
|
|
|
// Tentative
|
|
html += tdOpen;
|
|
html += helper->makeLink( "accept_conditionally",
|
|
i18n( "Accept conditionally", "[Accept cond.]" ) );
|
|
html += tdClose;
|
|
|
|
// Counter proposal
|
|
html += tdOpen;
|
|
html += helper->makeLink( "counter", i18n( "[Counter proposal]" ) );
|
|
html += tdClose;
|
|
|
|
// Decline
|
|
html += tdOpen;
|
|
html += helper->makeLink( "decline", i18n( "[Decline]" ) );
|
|
html += tdClose;
|
|
}
|
|
|
|
if ( !rsvpRec || ( inc && inc->revision() > 0 ) ) {
|
|
// Delegate
|
|
html += tdOpen;
|
|
html += helper->makeLink( "delegate", i18n( "[Delegate]" ) );
|
|
html += tdClose;
|
|
|
|
// Forward
|
|
html += tdOpen;
|
|
html += helper->makeLink( "forward", i18n( "[Forward]" ) );
|
|
html += tdClose;
|
|
|
|
// Check calendar
|
|
if ( inc && inc->type() == "Event" ) {
|
|
html += tdOpen;
|
|
html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
|
|
html += tdClose;
|
|
}
|
|
}
|
|
return html;
|
|
}
|
|
|
|
static TQString counterButtons( Incidence *incidence,
|
|
InvitationFormatterHelper *helper )
|
|
{
|
|
TQString html;
|
|
if ( !helper ) {
|
|
return html;
|
|
}
|
|
|
|
// Accept proposal
|
|
html += tdOpen;
|
|
html += helper->makeLink( "accept_counter", i18n("[Accept]") );
|
|
html += tdClose;
|
|
|
|
// Decline proposal
|
|
html += tdOpen;
|
|
html += helper->makeLink( "decline_counter", i18n("[Decline]") );
|
|
html += tdClose;
|
|
|
|
// Check calendar
|
|
if ( incidence && incidence->type() == "Event" ) {
|
|
html += tdOpen;
|
|
html += helper->makeLink( "check_calendar", i18n("[Check my calendar]" ) );
|
|
html += tdClose;
|
|
}
|
|
return html;
|
|
}
|
|
|
|
TQString IncidenceFormatter::formatICalInvitationHelper( TQString invitation,
|
|
Calendar *mCalendar,
|
|
InvitationFormatterHelper *helper,
|
|
bool noHtmlMode,
|
|
const TQString &sender )
|
|
{
|
|
if ( invitation.isEmpty() ) {
|
|
return TQString();
|
|
}
|
|
|
|
ICalFormat format;
|
|
// parseScheduleMessage takes the tz from the calendar, no need to set it manually here for the format!
|
|
ScheduleMessage *msg = format.parseScheduleMessage( mCalendar, invitation );
|
|
|
|
if( !msg ) {
|
|
kdDebug( 5850 ) << "Failed to parse the scheduling message" << endl;
|
|
Q_ASSERT( format.exception() );
|
|
kdDebug( 5850 ) << format.exception()->message() << endl;
|
|
return TQString();
|
|
}
|
|
|
|
IncidenceBase *incBase = msg->event();
|
|
|
|
// Determine if this incidence is in my calendar (and owned by me)
|
|
Incidence *existingIncidence = 0;
|
|
if ( incBase && helper->calendar() ) {
|
|
existingIncidence = helper->calendar()->incidence( incBase->uid() );
|
|
if ( !incidenceOwnedByMe( helper->calendar(), existingIncidence ) ) {
|
|
existingIncidence = 0;
|
|
}
|
|
if ( !existingIncidence ) {
|
|
const Incidence::List list = helper->calendar()->incidences();
|
|
for ( Incidence::List::ConstIterator it = list.begin(), end = list.end(); it != end; ++it ) {
|
|
if ( (*it)->schedulingID() == incBase->uid() &&
|
|
incidenceOwnedByMe( helper->calendar(), *it ) ) {
|
|
existingIncidence = *it;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// First make the text of the message
|
|
TQString html;
|
|
|
|
TQString tableStyle = TQString::fromLatin1(
|
|
"style=\"border: solid 1px; margin: 0em;\"" );
|
|
TQString tableHead = TQString::fromLatin1(
|
|
"<div align=\"center\">"
|
|
"<table width=\"80%\" cellpadding=\"1\" cellspacing=\"0\" %1>"
|
|
"<tr><td>").arg(tableStyle);
|
|
|
|
html += tableHead;
|
|
InvitationHeaderVisitor headerVisitor;
|
|
// The InvitationHeaderVisitor returns false if the incidence is somehow invalid, or not handled
|
|
if ( !headerVisitor.act( incBase, existingIncidence, msg, sender ) )
|
|
return TQString();
|
|
html += "<b>" + headerVisitor.result() + "</b>";
|
|
|
|
InvitationBodyVisitor bodyVisitor( noHtmlMode );
|
|
if ( !bodyVisitor.act( incBase, existingIncidence, msg, sender ) )
|
|
return TQString();
|
|
html += bodyVisitor.result();
|
|
|
|
if ( msg->method() == Scheduler::Request ) {
|
|
IncidenceCompareVisitor compareVisitor;
|
|
if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
|
|
html += "<p align=\"left\">";
|
|
html += i18n( "The following changes have been made by the organizer:" );
|
|
html += "</p>";
|
|
html += compareVisitor.result();
|
|
}
|
|
}
|
|
if ( msg->method() == Scheduler::Reply ) {
|
|
IncidenceCompareVisitor compareVisitor;
|
|
if ( compareVisitor.act( incBase, existingIncidence, msg->method() ) ) {
|
|
html += "<p align=\"left\">";
|
|
if ( !sender.isEmpty() ) {
|
|
html += i18n( "The following changes have been made by %1:" ).arg( sender );
|
|
} else {
|
|
html += i18n( "The following changes have been made by an attendee:" );
|
|
}
|
|
html += "</p>";
|
|
html += compareVisitor.result();
|
|
}
|
|
}
|
|
|
|
Incidence *inc = dynamic_cast<Incidence*>( incBase );
|
|
|
|
// determine if I am the organizer for this invitation
|
|
bool myInc = iamOrganizer( inc );
|
|
|
|
// determine if the invitation response has already been recorded
|
|
bool rsvpRec = false;
|
|
Attendee *ea = 0;
|
|
if ( !myInc ) {
|
|
Incidence *rsvpIncidence = existingIncidence;
|
|
if ( !rsvpIncidence && inc && inc->revision() > 0 ) {
|
|
rsvpIncidence = inc;
|
|
}
|
|
if ( rsvpIncidence ) {
|
|
ea = findMyAttendee( rsvpIncidence );
|
|
}
|
|
if ( ea &&
|
|
( ea->status() == Attendee::Accepted ||
|
|
ea->status() == Attendee::Declined ||
|
|
ea->status() == Attendee::Tentative ) ) {
|
|
rsvpRec = true;
|
|
}
|
|
}
|
|
|
|
// determine invitation role
|
|
TQString role;
|
|
bool isDelegated = false;
|
|
Attendee *a = findMyAttendee( inc );
|
|
if ( !a && inc ) {
|
|
if ( !inc->attendees().isEmpty() ) {
|
|
a = inc->attendees().first();
|
|
}
|
|
}
|
|
if ( a ) {
|
|
isDelegated = ( a->status() == Attendee::Delegated );
|
|
role = Attendee::roleName( a->role() );
|
|
}
|
|
|
|
// determine if RSVP needed, not-needed, or response already recorded
|
|
bool rsvpReq = rsvpRequested( inc );
|
|
if ( !myInc && a ) {
|
|
html += "<br/>";
|
|
html += "<i><u>";
|
|
if ( rsvpRec && inc ) {
|
|
if ( inc->revision() == 0 ) {
|
|
html += i18n( "Your <b>%1</b> response has already been recorded" ).
|
|
arg( ea->statusStr() );
|
|
} else {
|
|
html += i18n( "Your status for this invitation is <b>%1</b>" ).
|
|
arg( ea->statusStr() );
|
|
}
|
|
rsvpReq = false;
|
|
} else if ( msg->method() == Scheduler::Cancel ) {
|
|
html += i18n( "This invitation was declined" );
|
|
} else if ( msg->method() == Scheduler::Add ) {
|
|
html += i18n( "This invitation was accepted" );
|
|
} else {
|
|
if ( !isDelegated ) {
|
|
html += rsvpRequestedStr( rsvpReq, role );
|
|
} else {
|
|
html += i18n( "Awaiting delegation response" );
|
|
}
|
|
}
|
|
html += "</u></i>";
|
|
}
|
|
|
|
// Print if the organizer gave you a preset status
|
|
if ( !myInc ) {
|
|
if ( inc && inc->revision() == 0 ) {
|
|
TQString statStr = myStatusStr( inc );
|
|
if ( !statStr.isEmpty() ) {
|
|
html += "<br/>";
|
|
html += "<i>";
|
|
html += statStr;
|
|
html += "</i>";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add groupware links
|
|
|
|
html += "<br><table border=\"0\" cellspacing=\"0\"><tr><td> </td></tr>";
|
|
|
|
switch ( msg->method() ) {
|
|
case Scheduler::Publish:
|
|
case Scheduler::Request:
|
|
case Scheduler::Refresh:
|
|
case Scheduler::Add:
|
|
{
|
|
if ( inc && inc->revision() > 0 && ( existingIncidence || !helper->calendar() ) ) {
|
|
html += "<tr>";
|
|
if ( inc->type() == "Todo" ) {
|
|
html += "<td colspan=\"9\">";
|
|
html += helper->makeLink( "reply", i18n( "[Record invitation in my task list]" ) );
|
|
} else {
|
|
html += "<td colspan=\"13\">";
|
|
html += helper->makeLink( "reply", i18n( "[Record invitation in my calendar]" ) );
|
|
}
|
|
html += "</td></tr>";
|
|
}
|
|
|
|
if ( !myInc && a ) {
|
|
html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Scheduler::Cancel:
|
|
// Remove invitation
|
|
if ( inc ) {
|
|
html += "<tr>";
|
|
if ( inc->type() == "Todo" ) {
|
|
html += "<td colspan=\"9\">";
|
|
html += helper->makeLink( "cancel", i18n( "[Remove invitation from my task list]" ) );
|
|
} else {
|
|
html += "<td colspan=\"13\">";
|
|
html += helper->makeLink( "cancel", i18n( "[Remove invitation from my calendar]" ) );
|
|
}
|
|
html += "</td></tr>";
|
|
}
|
|
break;
|
|
|
|
case Scheduler::Reply:
|
|
{
|
|
// Record invitation response
|
|
Attendee *a = 0;
|
|
Attendee *ea = 0;
|
|
if ( inc ) {
|
|
// First, determine if this reply is really a counter in disguise.
|
|
if ( replyMeansCounter( inc ) ) {
|
|
html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
|
|
break;
|
|
}
|
|
|
|
// Next, maybe this is a declined reply that was delegated from me?
|
|
// find first attendee who is delegated-from me
|
|
// look a their PARTSTAT response, if the response is declined,
|
|
// then we need to start over which means putting all the action
|
|
// buttons and NOT putting on the [Record response..] button
|
|
a = findDelegatedFromMyAttendee( inc );
|
|
if ( a ) {
|
|
if ( a->status() != Attendee::Accepted ||
|
|
a->status() != Attendee::Tentative ) {
|
|
html += "<tr>" + responseButtons( inc, rsvpReq, rsvpRec, helper ) + "</tr>";
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Finally, simply allow a Record of the reply
|
|
if ( !inc->attendees().isEmpty() ) {
|
|
a = inc->attendees().first();
|
|
}
|
|
if ( a ) {
|
|
ea = findAttendee( existingIncidence, a->email() );
|
|
}
|
|
}
|
|
if ( ea && ( ea->status() != Attendee::NeedsAction ) && ( ea->status() == a->status() ) ) {
|
|
if ( inc && inc->revision() > 0 ) {
|
|
html += "<br><u><i>";
|
|
html += i18n( "The response has been recorded [%1]" ).arg( ea->statusStr() );
|
|
html += "</i></u>";
|
|
}
|
|
} else {
|
|
if ( inc ) {
|
|
html += "<tr><td>";
|
|
if ( inc->type() == "Todo" ) {
|
|
html += helper->makeLink( "reply", i18n( "[Record response in my task list]" ) );
|
|
} else {
|
|
html += helper->makeLink( "reply", i18n( "[Record response in my calendar]" ) );
|
|
}
|
|
html += "</td></tr>";
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case Scheduler::Counter:
|
|
// Counter proposal
|
|
html += "<tr>" + counterButtons( inc, helper ) + "</tr>";
|
|
break;
|
|
|
|
case Scheduler::Declinecounter:
|
|
case Scheduler::NoMethod:
|
|
break;
|
|
}
|
|
|
|
// close the groupware table
|
|
html += "</td></tr></table>";
|
|
|
|
// Add the attendee list if I am the organizer
|
|
if ( myInc && helper->calendar() ) {
|
|
html += invitationAttendees( helper->calendar()->incidence( inc->uid() ) );
|
|
}
|
|
|
|
// close the top-level table
|
|
html += "</td></tr></table><br></div>";
|
|
|
|
// Add the attachment list
|
|
html += invitationAttachments( helper, inc );
|
|
|
|
return html;
|
|
}
|
|
|
|
TQString IncidenceFormatter::formatICalInvitation( TQString invitation,
|
|
Calendar *mCalendar,
|
|
InvitationFormatterHelper *helper )
|
|
{
|
|
return formatICalInvitationHelper( invitation, mCalendar, helper, false, TQString() );
|
|
}
|
|
|
|
TQString IncidenceFormatter::formatICalInvitationNoHtml( TQString invitation,
|
|
Calendar *mCalendar,
|
|
InvitationFormatterHelper *helper )
|
|
{
|
|
return formatICalInvitationHelper( invitation, mCalendar, helper, true, TQString() );
|
|
}
|
|
|
|
TQString IncidenceFormatter::formatICalInvitationNoHtml( TQString invitation,
|
|
Calendar *mCalendar,
|
|
InvitationFormatterHelper *helper,
|
|
const TQString &sender )
|
|
{
|
|
return formatICalInvitationHelper( invitation, mCalendar, helper, true, sender );
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
* Helper functions for the msTNEF -> VPart converter
|
|
*******************************************************************/
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static TQString stringProp( KTNEFMessage* tnefMsg, const TQ_UINT32& key,
|
|
const TQString& fallback = TQString())
|
|
{
|
|
return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16,
|
|
fallback );
|
|
}
|
|
|
|
static TQString sNamedProp( KTNEFMessage* tnefMsg, const TQString& name,
|
|
const TQString& fallback = TQString() )
|
|
{
|
|
return tnefMsg->findNamedProp( name, fallback );
|
|
}
|
|
|
|
struct save_tz { char* old_tz; char* tz_env_str; };
|
|
|
|
/* temporarily go to a different timezone */
|
|
static struct save_tz set_tz( const char* _tc )
|
|
{
|
|
const char *tc = _tc?_tc:"UTC";
|
|
|
|
struct save_tz rv;
|
|
|
|
rv.old_tz = 0;
|
|
rv.tz_env_str = 0;
|
|
|
|
//kdDebug(5006) << "set_tz(), timezone before = " << timezone << endl;
|
|
|
|
char* tz_env = 0;
|
|
if( getenv( "TZ" ) ) {
|
|
tz_env = strdup( getenv( "TZ" ) );
|
|
rv.old_tz = tz_env;
|
|
}
|
|
char* tmp_env = (char*)malloc( strlen( tc ) + 4 );
|
|
strcpy( tmp_env, "TZ=" );
|
|
strcpy( tmp_env+3, tc );
|
|
putenv( tmp_env );
|
|
|
|
rv.tz_env_str = tmp_env;
|
|
|
|
/* tmp_env is not free'ed -- it is part of the environment */
|
|
|
|
tzset();
|
|
//kdDebug(5006) << "set_tz(), timezone after = " << timezone << endl;
|
|
|
|
return rv;
|
|
}
|
|
|
|
/* restore previous timezone */
|
|
static void unset_tz( struct save_tz old_tz )
|
|
{
|
|
if( old_tz.old_tz ) {
|
|
char* tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 );
|
|
strcpy( tmp_env, "TZ=" );
|
|
strcpy( tmp_env+3, old_tz.old_tz );
|
|
putenv( tmp_env );
|
|
/* tmp_env is not free'ed -- it is part of the environment */
|
|
free( old_tz.old_tz );
|
|
} else {
|
|
/* clear TZ from env */
|
|
putenv( strdup("TZ") );
|
|
}
|
|
tzset();
|
|
|
|
/* is this OK? */
|
|
if( old_tz.tz_env_str ) free( old_tz.tz_env_str );
|
|
}
|
|
|
|
static TQDateTime utc2Local( const TQDateTime& utcdt )
|
|
{
|
|
struct tm tmL;
|
|
|
|
save_tz tmp_tz = set_tz("UTC");
|
|
time_t utc = utcdt.toTime_t();
|
|
unset_tz( tmp_tz );
|
|
|
|
localtime_r( &utc, &tmL );
|
|
return TQDateTime( TQDate( tmL.tm_year+1900, tmL.tm_mon+1, tmL.tm_mday ),
|
|
TQTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) );
|
|
}
|
|
|
|
|
|
static TQDateTime pureISOToLocalTQDateTime( const TQString& dtStr,
|
|
bool bDateOnly = false )
|
|
{
|
|
TQDate tmpDate;
|
|
TQTime tmpTime;
|
|
int year, month, day, hour, minute, second;
|
|
|
|
if( bDateOnly ) {
|
|
year = dtStr.left( 4 ).toInt();
|
|
month = dtStr.mid( 4, 2 ).toInt();
|
|
day = dtStr.mid( 6, 2 ).toInt();
|
|
hour = 0;
|
|
minute = 0;
|
|
second = 0;
|
|
} else {
|
|
year = dtStr.left( 4 ).toInt();
|
|
month = dtStr.mid( 4, 2 ).toInt();
|
|
day = dtStr.mid( 6, 2 ).toInt();
|
|
hour = dtStr.mid( 9, 2 ).toInt();
|
|
minute = dtStr.mid( 11, 2 ).toInt();
|
|
second = dtStr.mid( 13, 2 ).toInt();
|
|
}
|
|
tmpDate.setYMD( year, month, day );
|
|
tmpTime.setHMS( hour, minute, second );
|
|
|
|
if( tmpDate.isValid() && tmpTime.isValid() ) {
|
|
TQDateTime dT = TQDateTime( tmpDate, tmpTime );
|
|
|
|
if( !bDateOnly ) {
|
|
// correct for GMT ( == Zulu time == UTC )
|
|
if (dtStr.at(dtStr.length()-1) == 'Z') {
|
|
//dT = dT.addSecs( 60 * KRFCDate::localUTCOffset() );
|
|
//localUTCOffset( dT ) );
|
|
dT = utc2Local( dT );
|
|
}
|
|
}
|
|
return dT;
|
|
} else
|
|
return TQDateTime();
|
|
}
|
|
|
|
|
|
|
|
TQString IncidenceFormatter::msTNEFToVPart( const TQByteArray& tnef )
|
|
{
|
|
bool bOk = false;
|
|
|
|
KTNEFParser parser;
|
|
TQBuffer buf( tnef );
|
|
CalendarLocal cal ( TQString::fromLatin1( "UTC" ) );
|
|
KABC::Addressee addressee;
|
|
KABC::VCardConverter cardConv;
|
|
ICalFormat calFormat;
|
|
Event* event = new Event();
|
|
|
|
if( parser.openDevice( &TQT_TQIODEVICE_OBJECT(buf) ) ) {
|
|
KTNEFMessage* tnefMsg = parser.message();
|
|
//TQMap<int,KTNEFProperty*> props = parser.message()->properties();
|
|
|
|
// Everything depends from property PR_MESSAGE_CLASS
|
|
// (this is added by KTNEFParser):
|
|
TQString msgClass = tnefMsg->findProp( 0x001A, TQString(), true )
|
|
.upper();
|
|
if( !msgClass.isEmpty() ) {
|
|
// Match the old class names that might be used by Outlook for
|
|
// compatibility with Microsoft Mail for Windows for Workgroups 3.1.
|
|
bool bCompatClassAppointment = false;
|
|
bool bCompatMethodRequest = false;
|
|
bool bCompatMethodCancled = false;
|
|
bool bCompatMethodAccepted = false;
|
|
bool bCompatMethodAcceptedCond = false;
|
|
bool bCompatMethodDeclined = false;
|
|
if( msgClass.startsWith( "IPM.MICROSOFT SCHEDULE." ) ) {
|
|
bCompatClassAppointment = true;
|
|
if( msgClass.endsWith( ".MTGREQ" ) )
|
|
bCompatMethodRequest = true;
|
|
if( msgClass.endsWith( ".MTGCNCL" ) )
|
|
bCompatMethodCancled = true;
|
|
if( msgClass.endsWith( ".MTGRESPP" ) )
|
|
bCompatMethodAccepted = true;
|
|
if( msgClass.endsWith( ".MTGRESPA" ) )
|
|
bCompatMethodAcceptedCond = true;
|
|
if( msgClass.endsWith( ".MTGRESPN" ) )
|
|
bCompatMethodDeclined = true;
|
|
}
|
|
bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" );
|
|
|
|
if( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) {
|
|
// Compose a vCal
|
|
bool bIsReply = false;
|
|
TQString prodID = "-//Microsoft Corporation//Outlook ";
|
|
prodID += tnefMsg->findNamedProp( "0x8554", "9.0" );
|
|
prodID += "MIMEDIR/EN\n";
|
|
prodID += "VERSION:2.0\n";
|
|
calFormat.setApplication( "Outlook", prodID );
|
|
|
|
Scheduler::Method method;
|
|
if( bCompatMethodRequest )
|
|
method = Scheduler::Request;
|
|
else if( bCompatMethodCancled )
|
|
method = Scheduler::Cancel;
|
|
else if( bCompatMethodAccepted || bCompatMethodAcceptedCond ||
|
|
bCompatMethodDeclined ) {
|
|
method = Scheduler::Reply;
|
|
bIsReply = true;
|
|
} else {
|
|
// pending(khz): verify whether "0x0c17" is the right tag ???
|
|
//
|
|
// at the moment we think there are REQUESTS and UPDATES
|
|
//
|
|
// but WHAT ABOUT REPLIES ???
|
|
//
|
|
//
|
|
|
|
if( tnefMsg->findProp(0x0c17) == "1" )
|
|
bIsReply = true;
|
|
method = Scheduler::Request;
|
|
}
|
|
|
|
/// ### FIXME Need to get this attribute written
|
|
ScheduleMessage schedMsg(event, method, ScheduleMessage::Unknown );
|
|
|
|
TQString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) );
|
|
|
|
if( !sSenderSearchKeyEmail.isEmpty() ) {
|
|
int colon = sSenderSearchKeyEmail.find( ':' );
|
|
// May be e.g. "SMTP:KHZ@KDE.ORG"
|
|
if( sSenderSearchKeyEmail.find( ':' ) == -1 )
|
|
sSenderSearchKeyEmail.remove( 0, colon+1 );
|
|
}
|
|
|
|
TQString s( tnefMsg->findProp( 0x0e04 ) );
|
|
TQStringList attendees = TQStringList::split( ';', s );
|
|
if( attendees.count() ) {
|
|
for( TQStringList::Iterator it = attendees.begin();
|
|
it != attendees.end(); ++it ) {
|
|
// Skip all entries that have no '@' since these are
|
|
// no mail addresses
|
|
if( (*it).find('@') == -1 ) {
|
|
s = (*it).stripWhiteSpace();
|
|
|
|
Attendee *attendee = new Attendee( s, s, true );
|
|
if( bIsReply ) {
|
|
if( bCompatMethodAccepted )
|
|
attendee->setStatus( Attendee::Accepted );
|
|
if( bCompatMethodDeclined )
|
|
attendee->setStatus( Attendee::Declined );
|
|
if( bCompatMethodAcceptedCond )
|
|
attendee->setStatus(Attendee::Tentative);
|
|
} else {
|
|
attendee->setStatus( Attendee::NeedsAction );
|
|
attendee->setRole( Attendee::ReqParticipant );
|
|
}
|
|
event->addAttendee(attendee);
|
|
}
|
|
}
|
|
} else {
|
|
// Oops, no attendees?
|
|
// This must be old style, let us use the PR_SENDER_SEARCH_KEY.
|
|
s = sSenderSearchKeyEmail;
|
|
if( !s.isEmpty() ) {
|
|
Attendee *attendee = new Attendee( TQString(), TQString(),
|
|
true );
|
|
if( bIsReply ) {
|
|
if( bCompatMethodAccepted )
|
|
attendee->setStatus( Attendee::Accepted );
|
|
if( bCompatMethodAcceptedCond )
|
|
attendee->setStatus( Attendee::Declined );
|
|
if( bCompatMethodDeclined )
|
|
attendee->setStatus( Attendee::Tentative );
|
|
} else {
|
|
attendee->setStatus(Attendee::NeedsAction);
|
|
attendee->setRole(Attendee::ReqParticipant);
|
|
}
|
|
event->addAttendee(attendee);
|
|
}
|
|
}
|
|
s = tnefMsg->findProp( 0x0c1f ); // look for organizer property
|
|
if( s.isEmpty() && !bIsReply )
|
|
s = sSenderSearchKeyEmail;
|
|
// TODO: Use the common name?
|
|
if( !s.isEmpty() )
|
|
event->setOrganizer( s );
|
|
|
|
s = tnefMsg->findProp( 0x8516 ).replace( TQChar( '-' ), TQString() )
|
|
.replace( TQChar( ':' ), TQString() );
|
|
event->setDtStart( TQDateTime::fromString( s ) ); // ## Format??
|
|
|
|
s = tnefMsg->findProp( 0x8517 ).replace( TQChar( '-' ), TQString() )
|
|
.replace( TQChar( ':' ), TQString() );
|
|
event->setDtEnd( TQDateTime::fromString( s ) );
|
|
|
|
s = tnefMsg->findProp( 0x8208 );
|
|
event->setLocation( s );
|
|
|
|
// is it OK to set this to OPAQUE always ??
|
|
//vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme!
|
|
//vPart += "SEQUENCE:0\n";
|
|
|
|
// is "0x0023" OK - or should we look for "0x0003" ??
|
|
s = tnefMsg->findProp( 0x0023 );
|
|
event->setUid( s );
|
|
|
|
// PENDING(khz): is this value in local timezone? Must it be
|
|
// adjusted? Most likely this is a bug in the server or in
|
|
// Outlook - we ignore it for now.
|
|
s = tnefMsg->findProp( 0x8202 ).replace( TQChar( '-' ), TQString() )
|
|
.replace( TQChar( ':' ), TQString() );
|
|
// ### libkcal always uses currentDateTime()
|
|
// event->setDtStamp(TQDateTime::fromString(s));
|
|
|
|
s = tnefMsg->findNamedProp( "Keywords" );
|
|
event->setCategories( s );
|
|
|
|
s = tnefMsg->findProp( 0x1000 );
|
|
event->setDescription( s );
|
|
|
|
s = tnefMsg->findProp( 0x0070 );
|
|
event->setSummary( s );
|
|
|
|
s = tnefMsg->findProp( 0x0026 );
|
|
event->setPriority( s.toInt() );
|
|
|
|
// is reminder flag set ?
|
|
if(!tnefMsg->findProp(0x8503).isEmpty()) {
|
|
Alarm *alarm = new Alarm(event);
|
|
TQDateTime highNoonTime =
|
|
pureISOToLocalTQDateTime( tnefMsg->findProp( 0x8502 )
|
|
.replace( TQChar( '-' ), "" )
|
|
.replace( TQChar( ':' ), "" ) );
|
|
TQDateTime wakeMeUpTime =
|
|
pureISOToLocalTQDateTime( tnefMsg->findProp( 0x8560, "" )
|
|
.replace( TQChar( '-' ), "" )
|
|
.replace( TQChar( ':' ), "" ) );
|
|
alarm->setTime(wakeMeUpTime);
|
|
|
|
if( highNoonTime.isValid() && wakeMeUpTime.isValid() )
|
|
alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) );
|
|
else
|
|
// default: wake them up 15 minutes before the appointment
|
|
alarm->setStartOffset( Duration( 15*60 ) );
|
|
alarm->setDisplayAlarm( i18n( "Reminder" ) );
|
|
|
|
// Sorry: the different action types are not known (yet)
|
|
// so we always set 'DISPLAY' (no sounds, no images...)
|
|
event->addAlarm( alarm );
|
|
}
|
|
cal.addEvent( event );
|
|
bOk = true;
|
|
// we finished composing a vCal
|
|
} else if( bCompatClassNote || "IPM.CONTACT" == msgClass ) {
|
|
addressee.setUid( stringProp( tnefMsg, attMSGID ) );
|
|
addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) );
|
|
addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true );
|
|
addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false );
|
|
addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-IMAddress", sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-SpousesName", stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-ManagersName", stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-AssistantsName", stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-Department", stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-Office", stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) );
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-Profession", stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) );
|
|
|
|
TQString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY )
|
|
.replace( TQChar( '-' ), TQString() )
|
|
.replace( TQChar( ':' ), TQString() );
|
|
if( !s.isEmpty() )
|
|
addressee.insertCustom( "KADDRESSBOOK", "X-Anniversary", s );
|
|
|
|
addressee.setUrl( KURL( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) );
|
|
|
|
// collect parts of Name entry
|
|
addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) );
|
|
addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) );
|
|
addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) );
|
|
addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) );
|
|
addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) );
|
|
|
|
addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) );
|
|
addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) );
|
|
addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) );
|
|
/*
|
|
the MAPI property ID of this (multiline) )field is unknown:
|
|
vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" );
|
|
*/
|
|
|
|
KABC::Address adr;
|
|
adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) );
|
|
adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) );
|
|
adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) );
|
|
adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) );
|
|
adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) );
|
|
adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) );
|
|
adr.setType(KABC::Address::Home);
|
|
addressee.insertAddress(adr);
|
|
|
|
adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) );
|
|
adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) );
|
|
adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) );
|
|
adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) );
|
|
adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) );
|
|
adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) );
|
|
adr.setType( KABC::Address::Work );
|
|
addressee.insertAddress( adr );
|
|
|
|
adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) );
|
|
adr.setStreet( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) );
|
|
adr.setLocality( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) );
|
|
adr.setRegion( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) );
|
|
adr.setPostalCode( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) );
|
|
adr.setCountry( stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) );
|
|
adr.setType( KABC::Address::Dom );
|
|
addressee.insertAddress(adr);
|
|
|
|
// problem: the 'other' address was stored by KOrganizer in
|
|
// a line looking like the following one:
|
|
// 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
|
|
|
|
TQString nr;
|
|
nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER );
|
|
addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) );
|
|
nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER );
|
|
addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) );
|
|
nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER );
|
|
addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) );
|
|
nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER );
|
|
addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) );
|
|
nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER );
|
|
addressee.insertPhoneNumber( KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) );
|
|
|
|
s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY )
|
|
.replace( TQChar( '-' ), TQString() )
|
|
.replace( TQChar( ':' ), TQString() );
|
|
if( !s.isEmpty() )
|
|
addressee.setBirthday( TQDateTime::fromString( s ) );
|
|
|
|
bOk = ( !addressee.isEmpty() );
|
|
} else if( "IPM.NOTE" == msgClass ) {
|
|
|
|
} // else if ... and so on ...
|
|
}
|
|
}
|
|
|
|
// Compose return string
|
|
TQString iCal = calFormat.toString( &cal );
|
|
if( !iCal.isEmpty() )
|
|
// This was an iCal
|
|
return iCal;
|
|
|
|
// Not an iCal - try a vCard
|
|
KABC::VCardConverter converter;
|
|
return converter.createVCard( addressee );
|
|
}
|
|
|
|
|
|
TQString IncidenceFormatter::formatTNEFInvitation( const TQByteArray& tnef,
|
|
Calendar *mCalendar, InvitationFormatterHelper *helper )
|
|
{
|
|
TQString vPart = IncidenceFormatter::msTNEFToVPart( tnef );
|
|
TQString iCal = IncidenceFormatter::formatICalInvitation( vPart, mCalendar, helper );
|
|
if( !iCal.isEmpty() )
|
|
return iCal;
|
|
return vPart;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*******************************************************************
|
|
* Helper functions for the Incidence tooltips
|
|
*******************************************************************/
|
|
|
|
class IncidenceFormatter::ToolTipVisitor : public IncidenceBase::Visitor
|
|
{
|
|
public:
|
|
ToolTipVisitor()
|
|
: mCalendar( 0 ), mRichText( true ), mResult( "" ) {}
|
|
|
|
bool act( Calendar *calendar, IncidenceBase *incidence,
|
|
const TQDate &date=TQDate(), bool richText=true )
|
|
{
|
|
mCalendar = calendar;
|
|
mDate = date;
|
|
mRichText = richText;
|
|
mResult = "";
|
|
return incidence ? incidence->accept( *this ) : false;
|
|
}
|
|
TQString result() const { return mResult; }
|
|
|
|
protected:
|
|
bool visit( Event *event );
|
|
bool visit( Todo *todo );
|
|
bool visit( Journal *journal );
|
|
bool visit( FreeBusy *fb );
|
|
|
|
TQString dateRangeText( Event *event, const TQDate &date );
|
|
TQString dateRangeText( Todo *todo, const TQDate &date );
|
|
TQString dateRangeText( Journal *journal );
|
|
TQString dateRangeText( FreeBusy *fb );
|
|
|
|
TQString generateToolTip( Incidence* incidence, TQString dtRangeText );
|
|
|
|
protected:
|
|
Calendar *mCalendar;
|
|
TQDate mDate;
|
|
bool mRichText;
|
|
TQString mResult;
|
|
};
|
|
|
|
TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Event *event, const TQDate &date )
|
|
{
|
|
TQString ret;
|
|
TQString tmp;
|
|
|
|
TQDateTime startDt = event->dtStart();
|
|
TQDateTime endDt = event->dtEnd();
|
|
if ( event->doesRecur() ) {
|
|
if ( date.isValid() ) {
|
|
TQDateTime dt( date, TQTime( 0, 0, 0 ) );
|
|
int diffDays = startDt.daysTo( dt );
|
|
dt = dt.addSecs( -1 );
|
|
startDt.setDate( event->recurrence()->getNextDateTime( dt ).date() );
|
|
if ( event->hasEndDate() ) {
|
|
endDt = endDt.addDays( diffDays );
|
|
if ( startDt > endDt ) {
|
|
startDt.setDate( event->recurrence()->getPreviousDateTime( dt ).date() );
|
|
endDt = startDt.addDays( event->dtStart().daysTo( event->dtEnd() ) );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( event->isMultiDay() ) {
|
|
|
|
tmp = "<br>" + i18n("Event start", "<i>From:</i> %1");
|
|
if (event->doesFloat())
|
|
ret += tmp.arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", " ") );
|
|
else
|
|
ret += tmp.arg( IncidenceFormatter::dateToString( startDt ).replace(" ", " ") );
|
|
|
|
tmp = "<br>" + i18n("Event end","<i>To:</i> %1");
|
|
if (event->doesFloat())
|
|
ret += tmp.arg( IncidenceFormatter::dateToString( endDt, false ).replace(" ", " ") );
|
|
else
|
|
ret += tmp.arg( IncidenceFormatter::dateToString( endDt ).replace(" ", " ") );
|
|
|
|
} else {
|
|
|
|
ret += "<br>"+i18n("<i>Date:</i> %1").
|
|
arg( IncidenceFormatter::dateToString( startDt, false ).replace(" ", " ") );
|
|
if ( !event->doesFloat() ) {
|
|
const TQString dtStartTime =
|
|
IncidenceFormatter::timeToString( startDt, true ).replace( " ", " " );
|
|
const TQString dtEndTime =
|
|
IncidenceFormatter::timeToString( endDt, true ).replace( " ", " " );
|
|
if ( dtStartTime == dtEndTime ) { // to prevent 'Time: 17:00 - 17:00'
|
|
tmp = "<br>" + i18n("time for event, to prevent ugly line breaks",
|
|
"<i>Time:</i> %1").
|
|
arg( dtStartTime );
|
|
} else {
|
|
tmp = "<br>" + i18n("time range for event, to prevent ugly line breaks",
|
|
"<i>Time:</i> %1 - %2").
|
|
arg( dtStartTime, dtEndTime );
|
|
}
|
|
ret += tmp;
|
|
}
|
|
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Todo *todo, const TQDate &date )
|
|
{
|
|
TQString ret;
|
|
bool floats( todo->doesFloat() );
|
|
|
|
if ( todo->hasStartDate() && todo->dtStart().isValid() ) {
|
|
TQDateTime startDt = todo->dtStart();
|
|
if ( todo->doesRecur() ) {
|
|
if ( date.isValid() ) {
|
|
startDt.setDate( date );
|
|
}
|
|
}
|
|
ret += "<br>" +
|
|
i18n("<i>Start:</i> %1").
|
|
arg( IncidenceFormatter::dateTimeToString( startDt, floats, false ).
|
|
replace( " ", " " ) );
|
|
}
|
|
|
|
if ( todo->hasDueDate() && todo->dtDue().isValid() ) {
|
|
TQDateTime dueDt = todo->dtDue();
|
|
if ( todo->doesRecur() ) {
|
|
if ( date.isValid() ) {
|
|
TQDateTime dt( date, TQTime( 0, 0, 0 ) );
|
|
dt = dt.addSecs( -1 );
|
|
dueDt.setDate( todo->recurrence()->getNextDateTime( dt ).date() );
|
|
}
|
|
}
|
|
ret += "<br>" +
|
|
i18n("<i>Due:</i> %1").
|
|
arg( IncidenceFormatter::dateTimeToString( dueDt, floats, false ).
|
|
replace( " ", " " ) );
|
|
}
|
|
|
|
// Print priority and completed info here, for lack of a better place
|
|
|
|
if ( todo->priority() > 0 ) {
|
|
ret += "<br>";
|
|
ret += "<i>" + i18n( "Priority:" ) + "</i>" + " ";
|
|
ret += TQString::number( todo->priority() );
|
|
}
|
|
|
|
ret += "<br>";
|
|
if ( todo->isCompleted() ) {
|
|
ret += "<i>" + i18n( "Completed:" ) + "</i>" + " ";
|
|
ret += todo->completedStr().replace( " ", " " );
|
|
} else {
|
|
ret += "<i>" + i18n( "Percent Done:" ) + "</i>" + " ";
|
|
ret += i18n( "%1%" ).arg( todo->percentComplete() );
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( Journal*journal )
|
|
{
|
|
TQString ret;
|
|
if (journal->dtStart().isValid() ) {
|
|
ret += "<br>" +
|
|
i18n("<i>Date:</i> %1").
|
|
arg( IncidenceFormatter::dateToString( journal->dtStart(), false ) );
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
TQString IncidenceFormatter::ToolTipVisitor::dateRangeText( FreeBusy *fb )
|
|
{
|
|
TQString tmp( "<br>" + i18n("<i>Period start:</i> %1") );
|
|
TQString ret = tmp.arg( TDEGlobal::locale()->formatDateTime( fb->dtStart() ) );
|
|
tmp = "<br>" + i18n("<i>Period start:</i> %1");
|
|
ret += tmp.arg( TDEGlobal::locale()->formatDateTime( fb->dtEnd() ) );
|
|
return ret;
|
|
}
|
|
|
|
|
|
|
|
bool IncidenceFormatter::ToolTipVisitor::visit( Event *event )
|
|
{
|
|
mResult = generateToolTip( event, dateRangeText( event, mDate ) );
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
bool IncidenceFormatter::ToolTipVisitor::visit( Todo *todo )
|
|
{
|
|
mResult = generateToolTip( todo, dateRangeText( todo, mDate ) );
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
bool IncidenceFormatter::ToolTipVisitor::visit( Journal *journal )
|
|
{
|
|
mResult = generateToolTip( journal, dateRangeText( journal ) );
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
bool IncidenceFormatter::ToolTipVisitor::visit( FreeBusy *fb )
|
|
{
|
|
mResult = "<qt><b>" + i18n("Free/Busy information for %1")
|
|
.arg(fb->organizer().fullName()) + "</b>";
|
|
mResult += dateRangeText( fb );
|
|
mResult += "</qt>";
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
static TQString tooltipPerson( const TQString& email, TQString name )
|
|
{
|
|
// Make the search, if there is an email address to search on,
|
|
// and name is missing
|
|
if ( name.isEmpty() && !email.isEmpty() ) {
|
|
KABC::AddressBook *add_book = KABC::StdAddressBook::self( true );
|
|
KABC::Addressee::List addressList = add_book->findByEmail( email );
|
|
if ( !addressList.isEmpty() ) {
|
|
KABC::Addressee o = addressList.first();
|
|
if ( !o.isEmpty() && addressList.size() < 2 ) {
|
|
// use the name from the addressbook
|
|
name = o.formattedName();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Show the attendee
|
|
TQString tmpString = ( name.isEmpty() ? email : name );
|
|
|
|
return tmpString;
|
|
}
|
|
|
|
static TQString etc = i18n( "elipsis", "..." );
|
|
static TQString tooltipFormatAttendeeRoleList( Incidence *incidence, Attendee::Role role )
|
|
{
|
|
int maxNumAtts = 8; // maximum number of people to print per attendee role
|
|
TQString sep = i18n( "separator for lists of people names", ", " );
|
|
int sepLen = sep.length();
|
|
|
|
int i = 0;
|
|
TQString tmpStr;
|
|
Attendee::List::ConstIterator it;
|
|
Attendee::List attendees = incidence->attendees();
|
|
|
|
for( it = attendees.begin(); it != attendees.end(); ++it ) {
|
|
Attendee *a = *it;
|
|
if ( a->role() != role ) {
|
|
// skip not this role
|
|
continue;
|
|
}
|
|
if ( a->email() == incidence->organizer().email() ) {
|
|
// skip attendee that is also the organizer
|
|
continue;
|
|
}
|
|
if ( i == maxNumAtts ) {
|
|
tmpStr += etc;
|
|
break;
|
|
}
|
|
tmpStr += tooltipPerson( a->email(), a->name() );
|
|
if ( !a->delegator().isEmpty() ) {
|
|
tmpStr += i18n(" (delegated by %1)" ).arg( a->delegator() );
|
|
}
|
|
if ( !a->delegate().isEmpty() ) {
|
|
tmpStr += i18n(" (delegated to %1)" ).arg( a->delegate() );
|
|
}
|
|
tmpStr += sep;
|
|
i++;
|
|
}
|
|
if ( tmpStr.endsWith( sep ) ) {
|
|
tmpStr.truncate( tmpStr.length() - sepLen );
|
|
}
|
|
return tmpStr;
|
|
}
|
|
|
|
static TQString tooltipFormatAttendees( Incidence *incidence )
|
|
{
|
|
TQString tmpStr, str;
|
|
|
|
// Add organizer link
|
|
int attendeeCount = incidence->attendees().count();
|
|
if ( attendeeCount > 1 ||
|
|
( attendeeCount == 1 &&
|
|
incidence->organizer().email() != incidence->attendees().first()->email() ) ) {
|
|
tmpStr += "<i>" + i18n( "Organizer:" ) + "</i>" + " ";
|
|
tmpStr += tooltipPerson( incidence->organizer().email(),
|
|
incidence->organizer().name() );
|
|
}
|
|
|
|
// Add "chair"
|
|
str = tooltipFormatAttendeeRoleList( incidence, Attendee::Chair );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<br><i>" + i18n( "Chair:" ) + "</i>" + " ";
|
|
tmpStr += str;
|
|
}
|
|
|
|
// Add required participants
|
|
str = tooltipFormatAttendeeRoleList( incidence, Attendee::ReqParticipant );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<br><i>" + i18n( "Required Participants:" ) + "</i>" + " ";
|
|
tmpStr += str;
|
|
}
|
|
|
|
// Add optional participants
|
|
str = tooltipFormatAttendeeRoleList( incidence, Attendee::OptParticipant );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<br><i>" + i18n( "Optional Participants:" ) + "</i>" + " ";
|
|
tmpStr += str;
|
|
}
|
|
|
|
// Add observers
|
|
str = tooltipFormatAttendeeRoleList( incidence, Attendee::NonParticipant );
|
|
if ( !str.isEmpty() ) {
|
|
tmpStr += "<br><i>" + i18n( "Observers:" ) + "</i>" + " ";
|
|
tmpStr += str;
|
|
}
|
|
|
|
return tmpStr;
|
|
}
|
|
|
|
TQString IncidenceFormatter::ToolTipVisitor::generateToolTip( Incidence* incidence, TQString dtRangeText )
|
|
{
|
|
uint maxDescLen = 120; // maximum description chars to print (before elipsis)
|
|
|
|
if ( !incidence ) {
|
|
return TQString();
|
|
}
|
|
|
|
TQString tmp = "<qt>";
|
|
|
|
// header
|
|
tmp += "<b>" + incidence->summary().replace( "\n", "<br>" ) + "</b>";
|
|
//NOTE: using <hr> seems to confuse TQt3 tooltips in some cases so use "-----"
|
|
tmp += "<br>----------<br>";
|
|
|
|
if ( mCalendar ) {
|
|
TQString calStr = IncidenceFormatter::resourceString( mCalendar, incidence );
|
|
if ( !calStr.isEmpty() ) {
|
|
tmp += "<i>" + i18n( "Calendar:" ) + "</i>" + " ";
|
|
tmp += calStr;
|
|
}
|
|
}
|
|
|
|
tmp += dtRangeText;
|
|
|
|
if ( !incidence->location().isEmpty() ) {
|
|
tmp += "<br>";
|
|
tmp += "<i>" + i18n( "Location:" ) + "</i>" + " ";
|
|
tmp += incidence->location().replace( "\n", "<br>" );
|
|
}
|
|
|
|
TQString durStr = IncidenceFormatter::durationString( incidence );
|
|
if ( !durStr.isEmpty() ) {
|
|
tmp += "<br>";
|
|
tmp += "<i>" + i18n( "Duration:" ) + "</i>" + " ";
|
|
tmp += durStr;
|
|
}
|
|
|
|
if ( incidence->doesRecur() ) {
|
|
tmp += "<br>";
|
|
tmp += "<i>" + i18n( "Recurrence:" ) + "</i>" + " ";
|
|
tmp += IncidenceFormatter::recurrenceString( incidence );
|
|
}
|
|
|
|
if ( !incidence->description().isEmpty() ) {
|
|
TQString desc( incidence->description() );
|
|
if ( desc.length() > maxDescLen ) {
|
|
desc = desc.left( maxDescLen ) + etc;
|
|
}
|
|
tmp += "<br>----------<br>";
|
|
tmp += "<i>" + i18n( "Description:" ) + "</i>" + "<br>";
|
|
tmp += desc.replace( "\n", "<br>" );
|
|
tmp += "<br>----------";
|
|
}
|
|
|
|
int reminderCount = incidence->alarms().count();
|
|
if ( reminderCount > 0 && incidence->isAlarmEnabled() ) {
|
|
tmp += "<br>";
|
|
tmp += "<i>" + i18n( "Reminder:", "%n Reminders:", reminderCount ) + "</i>" + " ";
|
|
tmp += IncidenceFormatter::reminderStringList( incidence ).join( ", " );
|
|
}
|
|
|
|
tmp += "<br>";
|
|
tmp += tooltipFormatAttendees( incidence );
|
|
|
|
int categoryCount = incidence->categories().count();
|
|
if ( categoryCount > 0 ) {
|
|
tmp += "<br>";
|
|
tmp += "<i>" + i18n( "Category:", "%n Categories:", categoryCount ) + "</i>" + " ";
|
|
tmp += incidence->categories().join( ", " );
|
|
}
|
|
|
|
tmp += "</qt>";
|
|
return tmp;
|
|
}
|
|
|
|
TQString IncidenceFormatter::toolTipString( IncidenceBase *incidence, bool richText )
|
|
{
|
|
return toolTipStr( 0, incidence, TQDate(), richText );
|
|
}
|
|
|
|
TQString IncidenceFormatter::toolTipStr( Calendar *calendar,
|
|
IncidenceBase *incidence,
|
|
const TQDate &date,
|
|
bool richText )
|
|
{
|
|
ToolTipVisitor v;
|
|
if ( v.act( calendar, incidence, date, richText ) ) {
|
|
return v.result();
|
|
} else {
|
|
return TQString();
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
* Helper functions for the Incidence tooltips
|
|
*******************************************************************/
|
|
|
|
class IncidenceFormatter::MailBodyVisitor : public IncidenceBase::Visitor
|
|
{
|
|
public:
|
|
MailBodyVisitor() : mResult( "" ) {}
|
|
|
|
bool act( IncidenceBase *incidence )
|
|
{
|
|
mResult = "";
|
|
return incidence ? incidence->accept( *this ) : false;
|
|
}
|
|
TQString result() const { return mResult; }
|
|
|
|
protected:
|
|
bool visit( Event *event );
|
|
bool visit( Todo *todo );
|
|
bool visit( Journal *journal );
|
|
bool visit( FreeBusy * ) { mResult = i18n("This is a Free Busy Object"); return !mResult.isEmpty(); }
|
|
protected:
|
|
TQString mResult;
|
|
};
|
|
|
|
|
|
static TQString mailBodyIncidence( Incidence *incidence )
|
|
{
|
|
TQString body;
|
|
if ( !incidence->summary().isEmpty() ) {
|
|
body += i18n("Summary: %1\n").arg( incidence->summary() );
|
|
}
|
|
if ( !incidence->organizer().isEmpty() ) {
|
|
body += i18n("Organizer: %1\n").arg( incidence->organizer().fullName() );
|
|
}
|
|
if ( !incidence->location().isEmpty() ) {
|
|
body += i18n("Location: %1\n").arg( incidence->location() );
|
|
}
|
|
return body;
|
|
}
|
|
|
|
bool IncidenceFormatter::MailBodyVisitor::visit( Event *event )
|
|
{
|
|
TQString recurrence[]= {i18n("no recurrence", "None"),
|
|
i18n("Minutely"), i18n("Hourly"), i18n("Daily"),
|
|
i18n("Weekly"), i18n("Monthly Same Day"), i18n("Monthly Same Position"),
|
|
i18n("Yearly"), i18n("Yearly"), i18n("Yearly")};
|
|
|
|
mResult = mailBodyIncidence( event );
|
|
mResult += i18n("Start Date: %1\n").
|
|
arg( IncidenceFormatter::dateToString( event->dtStart(), true ) );
|
|
if ( !event->doesFloat() ) {
|
|
mResult += i18n("Start Time: %1\n").
|
|
arg( IncidenceFormatter::timeToString( event->dtStart(), true ) );
|
|
}
|
|
if ( event->dtStart() != event->dtEnd() ) {
|
|
mResult += i18n("End Date: %1\n").
|
|
arg( IncidenceFormatter::dateToString( event->dtEnd(), true ) );
|
|
}
|
|
if ( !event->doesFloat() ) {
|
|
mResult += i18n("End Time: %1\n").
|
|
arg( IncidenceFormatter::timeToString( event->dtEnd(), true ) );
|
|
}
|
|
if ( event->doesRecur() ) {
|
|
Recurrence *recur = event->recurrence();
|
|
// TODO: Merge these two to one of the form "Recurs every 3 days"
|
|
mResult += i18n("Recurs: %1\n")
|
|
.arg( recurrence[ recur->recurrenceType() ] );
|
|
mResult += i18n("Frequency: %1\n")
|
|
.arg( event->recurrence()->frequency() );
|
|
|
|
if ( recur->duration() > 0 ) {
|
|
mResult += i18n ("Repeats once", "Repeats %n times", recur->duration());
|
|
mResult += '\n';
|
|
} else {
|
|
if ( recur->duration() != -1 ) {
|
|
// TODO_Recurrence: What to do with floating
|
|
TQString endstr;
|
|
if ( event->doesFloat() ) {
|
|
endstr = TDEGlobal::locale()->formatDate( recur->endDate() );
|
|
} else {
|
|
endstr = TDEGlobal::locale()->formatDateTime( recur->endDateTime() );
|
|
}
|
|
mResult += i18n("Repeat until: %1\n").arg( endstr );
|
|
} else {
|
|
mResult += i18n("Repeats forever\n");
|
|
}
|
|
}
|
|
|
|
DateList exceptions = recur->exDates();
|
|
if (exceptions.isEmpty() == false) {
|
|
mResult += i18n("This recurring meeting has been cancelled on the following days:\n");
|
|
DateList::ConstIterator ex_iter;
|
|
for ( ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter ) {
|
|
mResult += i18n(" %1\n").arg( TDEGlobal::locale()->formatDate(* ex_iter ) );
|
|
}
|
|
}
|
|
}
|
|
TQString details = event->description();
|
|
if ( !details.isEmpty() ) {
|
|
mResult += i18n("Details:\n%1\n").arg( details );
|
|
}
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
bool IncidenceFormatter::MailBodyVisitor::visit( Todo *todo )
|
|
{
|
|
mResult = mailBodyIncidence( todo );
|
|
|
|
if ( todo->hasStartDate() ) {
|
|
mResult += i18n("Start Date: %1\n").
|
|
arg( IncidenceFormatter::dateToString( todo->dtStart( false ), true ) );
|
|
if ( !todo->doesFloat() ) {
|
|
mResult += i18n("Start Time: %1\n").
|
|
arg( IncidenceFormatter::timeToString( todo->dtStart( false ),true ) );
|
|
}
|
|
}
|
|
if ( todo->hasDueDate() ) {
|
|
mResult += i18n("Due Date: %1\n").
|
|
arg( IncidenceFormatter::dateToString( todo->dtDue(), true ) );
|
|
if ( !todo->doesFloat() ) {
|
|
mResult += i18n("Due Time: %1\n").
|
|
arg( IncidenceFormatter::timeToString( todo->dtDue(), true ) );
|
|
}
|
|
}
|
|
TQString details = todo->description();
|
|
if ( !details.isEmpty() ) {
|
|
mResult += i18n("Details:\n%1\n").arg( details );
|
|
}
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
bool IncidenceFormatter::MailBodyVisitor::visit( Journal *journal )
|
|
{
|
|
mResult = mailBodyIncidence( journal );
|
|
mResult += i18n("Date: %1\n").
|
|
arg( IncidenceFormatter::dateToString( journal->dtStart(), true ) );
|
|
if ( !journal->doesFloat() ) {
|
|
mResult += i18n("Time: %1\n").
|
|
arg( IncidenceFormatter::timeToString( journal->dtStart(), true ) );
|
|
}
|
|
if ( !journal->description().isEmpty() )
|
|
mResult += i18n("Text of the journal:\n%1\n").arg( journal->description() );
|
|
return !mResult.isEmpty();
|
|
}
|
|
|
|
|
|
|
|
TQString IncidenceFormatter::mailBodyString( IncidenceBase *incidence )
|
|
{
|
|
if ( !incidence )
|
|
return TQString();
|
|
|
|
MailBodyVisitor v;
|
|
if ( v.act( incidence ) ) {
|
|
return v.result();
|
|
}
|
|
return TQString();
|
|
}
|
|
|
|
static TQString recurEnd( Incidence *incidence )
|
|
{
|
|
TQString endstr;
|
|
if ( incidence->doesFloat() ) {
|
|
endstr = TDEGlobal::locale()->formatDate( incidence->recurrence()->endDate() );
|
|
} else {
|
|
endstr = TDEGlobal::locale()->formatDateTime( incidence->recurrence()->endDateTime() );
|
|
}
|
|
return endstr;
|
|
}
|
|
|
|
/************************************
|
|
* More static formatting functions
|
|
************************************/
|
|
TQString IncidenceFormatter::recurrenceString( Incidence *incidence )
|
|
{
|
|
if ( !incidence->doesRecur() ) {
|
|
return i18n( "No recurrence" );
|
|
}
|
|
TQStringList dayList;
|
|
dayList.append( i18n( "31st Last" ) );
|
|
dayList.append( i18n( "30th Last" ) );
|
|
dayList.append( i18n( "29th Last" ) );
|
|
dayList.append( i18n( "28th Last" ) );
|
|
dayList.append( i18n( "27th Last" ) );
|
|
dayList.append( i18n( "26th Last" ) );
|
|
dayList.append( i18n( "25th Last" ) );
|
|
dayList.append( i18n( "24th Last" ) );
|
|
dayList.append( i18n( "23rd Last" ) );
|
|
dayList.append( i18n( "22nd Last" ) );
|
|
dayList.append( i18n( "21st Last" ) );
|
|
dayList.append( i18n( "20th Last" ) );
|
|
dayList.append( i18n( "19th Last" ) );
|
|
dayList.append( i18n( "18th Last" ) );
|
|
dayList.append( i18n( "17th Last" ) );
|
|
dayList.append( i18n( "16th Last" ) );
|
|
dayList.append( i18n( "15th Last" ) );
|
|
dayList.append( i18n( "14th Last" ) );
|
|
dayList.append( i18n( "13th Last" ) );
|
|
dayList.append( i18n( "12th Last" ) );
|
|
dayList.append( i18n( "11th Last" ) );
|
|
dayList.append( i18n( "10th Last" ) );
|
|
dayList.append( i18n( "9th Last" ) );
|
|
dayList.append( i18n( "8th Last" ) );
|
|
dayList.append( i18n( "7th Last" ) );
|
|
dayList.append( i18n( "6th Last" ) );
|
|
dayList.append( i18n( "5th Last" ) );
|
|
dayList.append( i18n( "4th Last" ) );
|
|
dayList.append( i18n( "3rd Last" ) );
|
|
dayList.append( i18n( "2nd Last" ) );
|
|
dayList.append( i18n( "last day of the month", "Last" ) );
|
|
dayList.append( i18n( "unknown day of the month", "unknown" ) ); //#31 - zero offset from UI
|
|
dayList.append( i18n( "1st" ) );
|
|
dayList.append( i18n( "2nd" ) );
|
|
dayList.append( i18n( "3rd" ) );
|
|
dayList.append( i18n( "4th" ) );
|
|
dayList.append( i18n( "5th" ) );
|
|
dayList.append( i18n( "6th" ) );
|
|
dayList.append( i18n( "7th" ) );
|
|
dayList.append( i18n( "8th" ) );
|
|
dayList.append( i18n( "9th" ) );
|
|
dayList.append( i18n( "10th" ) );
|
|
dayList.append( i18n( "11th" ) );
|
|
dayList.append( i18n( "12th" ) );
|
|
dayList.append( i18n( "13th" ) );
|
|
dayList.append( i18n( "14th" ) );
|
|
dayList.append( i18n( "15th" ) );
|
|
dayList.append( i18n( "16th" ) );
|
|
dayList.append( i18n( "17th" ) );
|
|
dayList.append( i18n( "18th" ) );
|
|
dayList.append( i18n( "19th" ) );
|
|
dayList.append( i18n( "20th" ) );
|
|
dayList.append( i18n( "21st" ) );
|
|
dayList.append( i18n( "22nd" ) );
|
|
dayList.append( i18n( "23rd" ) );
|
|
dayList.append( i18n( "24th" ) );
|
|
dayList.append( i18n( "25th" ) );
|
|
dayList.append( i18n( "26th" ) );
|
|
dayList.append( i18n( "27th" ) );
|
|
dayList.append( i18n( "28th" ) );
|
|
dayList.append( i18n( "29th" ) );
|
|
dayList.append( i18n( "30th" ) );
|
|
dayList.append( i18n( "31st" ) );
|
|
int weekStart = TDEGlobal::locale()->weekStartDay();
|
|
TQString dayNames;
|
|
TQString recurStr, txt;
|
|
const KCalendarSystem *calSys = TDEGlobal::locale()->calendar();
|
|
Recurrence *recur = incidence->recurrence();
|
|
switch ( recur->recurrenceType() ) {
|
|
case Recurrence::rNone:
|
|
return i18n( "No recurrence" );
|
|
|
|
case Recurrence::rMinutely:
|
|
recurStr = i18n( "Recurs every minute", "Recurs every %n minutes", recur->frequency() );
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
return recurStr;
|
|
|
|
case Recurrence::rHourly:
|
|
recurStr = i18n( "Recurs hourly", "Recurs every %n hours", recur->frequency() );
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
return recurStr;
|
|
|
|
case Recurrence::rDaily:
|
|
recurStr = i18n( "Recurs daily", "Recurs every %n days", recur->frequency() );
|
|
if ( recur->duration() != -1 ) {
|
|
|
|
txt = i18n( "%1 until %2" ).arg( recurStr ).arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
return recurStr;
|
|
|
|
case Recurrence::rWeekly:
|
|
{
|
|
recurStr = i18n( "Recurs weekly", "Recurs every %n weeks", recur->frequency() );
|
|
|
|
bool addSpace = false;
|
|
for ( int i = 0; i < 7; ++i ) {
|
|
if ( recur->days().testBit( ( i + weekStart + 6 ) % 7 ) ) {
|
|
if ( addSpace ) {
|
|
dayNames.append( i18n( "separator for list of days", ", " ) );
|
|
}
|
|
dayNames.append( calSys->weekDayName( ( ( i + weekStart + 6 ) % 7 ) + 1, true ) );
|
|
addSpace = true;
|
|
}
|
|
}
|
|
if ( dayNames.isEmpty() ) {
|
|
dayNames = i18n( "Recurs weekly on no days", "no days" );
|
|
}
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 on %2 until %3" ).
|
|
arg( recurStr ).arg( dayNames ).arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
txt = i18n( "%1 on %2" ).arg( recurStr ).arg( dayNames );
|
|
return txt;
|
|
}
|
|
case Recurrence::rMonthlyPos:
|
|
{
|
|
recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
|
|
|
|
if ( !recur->monthPositions().isEmpty() ) {
|
|
KCal::RecurrenceRule::WDayPos rule = recur->monthPositions()[0];
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 on the %2 %3 until %4" ).
|
|
arg( recurStr ).
|
|
arg( dayList[rule.pos() + 31] ).
|
|
arg( calSys->weekDayName( rule.day(), false ) ).
|
|
arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
txt = i18n( "%1 on the %2 %3" ).
|
|
arg( recurStr ).
|
|
arg( dayList[rule.pos() + 31] ).
|
|
arg( calSys->weekDayName( rule.day(), false ) );
|
|
return txt;
|
|
} else {
|
|
return recurStr;
|
|
}
|
|
break;
|
|
}
|
|
case Recurrence::rMonthlyDay:
|
|
{
|
|
recurStr = i18n( "Recurs monthly", "Recurs every %n months", recur->frequency() );
|
|
|
|
if ( !recur->monthDays().isEmpty() ) {
|
|
int days = recur->monthDays()[0];
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 on the %2 day until %3" ).
|
|
arg( recurStr ).
|
|
arg( dayList[days + 31] ).
|
|
arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
txt = i18n( "%1 on the %2 day" ).arg( recurStr ).arg( dayList[days + 31] );
|
|
return txt;
|
|
} else {
|
|
return recurStr;
|
|
}
|
|
break;
|
|
}
|
|
case Recurrence::rYearlyMonth:
|
|
{
|
|
recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
|
|
|
|
if ( recur->duration() != -1 ) {
|
|
if ( !recur->yearDates().isEmpty() ) {
|
|
txt = i18n( "%1 on %2 %3 until %4" ).
|
|
arg( recurStr ).
|
|
arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
|
|
arg( dayList[ recur->yearDates()[0] + 31 ] ).
|
|
arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
}
|
|
if ( !recur->yearDates().isEmpty() ) {
|
|
txt = i18n( "%1 on %2 %3" ).
|
|
arg( recurStr ).
|
|
arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
|
|
arg( dayList[ recur->yearDates()[0] + 31 ] );
|
|
return txt;
|
|
} else {
|
|
if ( !recur->yearMonths().isEmpty() ) {
|
|
txt = i18n( "Recurs yearly on %1 %2" ).
|
|
arg( calSys->monthName( recur->yearMonths()[0],
|
|
recur->startDate().year() ) ).
|
|
arg( dayList[ recur->startDate().day() + 31 ] );
|
|
} else {
|
|
txt = i18n( "Recurs yearly on %1 %2" ).
|
|
arg( calSys->monthName( recur->startDate().month(),
|
|
recur->startDate().year() ) ).
|
|
arg( dayList[ recur->startDate().day() + 31 ] );
|
|
}
|
|
return txt;
|
|
}
|
|
break;
|
|
}
|
|
case Recurrence::rYearlyDay:
|
|
{
|
|
recurStr = i18n( "Recurs yearly", "Recurs every %n years", recur->frequency() );
|
|
if ( !recur->yearDays().isEmpty() ) {
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 on day %2 until %3" ).
|
|
arg( recurStr ).
|
|
arg( recur->yearDays()[0] ).
|
|
arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
txt = i18n( "%1 on day %2" ).arg( recurStr ).arg( recur->yearDays()[0] );
|
|
return txt;
|
|
} else {
|
|
return recurStr;
|
|
}
|
|
break;
|
|
}
|
|
case Recurrence::rYearlyPos:
|
|
{
|
|
recurStr = i18n( "Every year", "Every %n years", recur->frequency() );
|
|
if ( !recur->yearPositions().isEmpty() && !recur->yearMonths().isEmpty() ) {
|
|
KCal::RecurrenceRule::WDayPos rule = recur->yearPositions()[0];
|
|
if ( recur->duration() != -1 ) {
|
|
txt = i18n( "%1 on the %2 %3 of %4 until %5" ).
|
|
arg( recurStr ).
|
|
arg( dayList[rule.pos() + 31] ).
|
|
arg( calSys->weekDayName( rule.day(), false ) ).
|
|
arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) ).
|
|
arg( recurEnd( incidence ) );
|
|
if ( recur->duration() > 0 ) {
|
|
txt += i18n( " (%1 occurrences)" ).arg( recur->duration() );
|
|
}
|
|
return txt;
|
|
}
|
|
txt = i18n( "%1 on the %2 %3 of %4" ).
|
|
arg( recurStr ).
|
|
arg( dayList[rule.pos() + 31] ).
|
|
arg( calSys->weekDayName( rule.day(), false ) ).
|
|
arg( calSys->monthName( recur->yearMonths()[0], recur->startDate().year() ) );
|
|
return txt;
|
|
} else {
|
|
return recurStr;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return i18n( "Incidence recurs" );
|
|
}
|
|
|
|
TQString IncidenceFormatter::timeToString( const TQDateTime &date, bool shortfmt )
|
|
{
|
|
return TDEGlobal::locale()->formatTime( date.time(), !shortfmt );
|
|
}
|
|
|
|
TQString IncidenceFormatter::dateToString( const TQDateTime &date, bool shortfmt )
|
|
{
|
|
return
|
|
TDEGlobal::locale()->formatDate( date.date(), shortfmt );
|
|
}
|
|
|
|
TQString IncidenceFormatter::dateTimeToString( const TQDateTime &date,
|
|
bool allDay, bool shortfmt )
|
|
{
|
|
if ( allDay ) {
|
|
return dateToString( date, shortfmt );
|
|
}
|
|
|
|
return TDEGlobal::locale()->formatDateTime( date, shortfmt );
|
|
}
|
|
|
|
TQString IncidenceFormatter::resourceString( Calendar *calendar, Incidence *incidence )
|
|
{
|
|
if ( !calendar || !incidence ) {
|
|
return TQString();
|
|
}
|
|
|
|
CalendarResources *calendarResource = dynamic_cast<CalendarResources*>( calendar );
|
|
if ( !calendarResource ) {
|
|
return TQString();
|
|
}
|
|
|
|
ResourceCalendar *resourceCalendar = calendarResource->resource( incidence );
|
|
if ( resourceCalendar ) {
|
|
if ( !resourceCalendar->subresources().isEmpty() ) {
|
|
TQString subRes = resourceCalendar->subresourceIdentifier( incidence );
|
|
if ( subRes.isEmpty() ) {
|
|
return resourceCalendar->resourceName();
|
|
} else {
|
|
return resourceCalendar->labelForSubresource( subRes );
|
|
}
|
|
}
|
|
return resourceCalendar->resourceName();
|
|
}
|
|
|
|
return TQString();
|
|
}
|
|
|
|
static TQString secs2Duration( int secs )
|
|
{
|
|
TQString tmp;
|
|
int days = secs / 86400;
|
|
if ( days > 0 ) {
|
|
tmp += i18n( "1 day", "%n days", days );
|
|
tmp += ' ';
|
|
secs -= ( days * 86400 );
|
|
}
|
|
int hours = secs / 3600;
|
|
if ( hours > 0 ) {
|
|
tmp += i18n( "1 hour", "%n hours", hours );
|
|
tmp += ' ';
|
|
secs -= ( hours * 3600 );
|
|
}
|
|
int mins = secs / 60;
|
|
if ( mins > 0 ) {
|
|
tmp += i18n( "1 minute", "%n minutes", mins );
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
TQString IncidenceFormatter::durationString( Incidence *incidence )
|
|
{
|
|
TQString tmp;
|
|
if ( incidence->type() == "Event" ) {
|
|
Event *event = static_cast<Event *>( incidence );
|
|
if ( event->hasEndDate() ) {
|
|
if ( !event->doesFloat() ) {
|
|
tmp = secs2Duration( event->dtStart().secsTo( event->dtEnd() ) );
|
|
} else {
|
|
tmp = i18n( "1 day", "%n days",
|
|
event->dtStart().date().daysTo( event->dtEnd().date() ) + 1 );
|
|
}
|
|
} else {
|
|
tmp = i18n( "forever" );
|
|
}
|
|
} else if ( incidence->type() == "Todo" ) {
|
|
Todo *todo = static_cast<Todo *>( incidence );
|
|
if ( todo->hasDueDate() ) {
|
|
if ( todo->hasStartDate() ) {
|
|
if ( !todo->doesFloat() ) {
|
|
tmp = secs2Duration( todo->dtStart().secsTo( todo->dtDue() ) );
|
|
} else {
|
|
tmp = i18n( "1 day", "%n days",
|
|
todo->dtStart().date().daysTo( todo->dtDue().date() ) + 1 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return tmp;
|
|
}
|
|
|
|
TQStringList IncidenceFormatter::reminderStringList( Incidence *incidence, bool shortfmt )
|
|
{
|
|
//TODO: implement shortfmt=false
|
|
Q_UNUSED( shortfmt );
|
|
|
|
TQStringList reminderStringList;
|
|
|
|
if ( incidence ) {
|
|
Alarm::List alarms = incidence->alarms();
|
|
Alarm::List::ConstIterator it;
|
|
for ( it = alarms.begin(); it != alarms.end(); ++it ) {
|
|
Alarm *alarm = *it;
|
|
int offset = 0;
|
|
TQString remStr, atStr, offsetStr;
|
|
if ( alarm->hasTime() ) {
|
|
offset = 0;
|
|
if ( alarm->time().isValid() ) {
|
|
atStr = TDEGlobal::locale()->formatDateTime( alarm->time() );
|
|
}
|
|
} else if ( alarm->hasStartOffset() ) {
|
|
offset = alarm->startOffset().asSeconds();
|
|
if ( offset < 0 ) {
|
|
offset = -offset;
|
|
offsetStr = i18n( "N days/hours/minutes before the start datetime",
|
|
"%1 before the start" );
|
|
} else if ( offset > 0 ) {
|
|
offsetStr = i18n( "N days/hours/minutes after the start datetime",
|
|
"%1 after the start" );
|
|
} else { //offset is 0
|
|
if ( incidence->dtStart().isValid() ) {
|
|
atStr = TDEGlobal::locale()->formatDateTime( incidence->dtStart() );
|
|
}
|
|
}
|
|
} else if ( alarm->hasEndOffset() ) {
|
|
offset = alarm->endOffset().asSeconds();
|
|
if ( offset < 0 ) {
|
|
offset = -offset;
|
|
if ( incidence->type() == "Todo" ) {
|
|
offsetStr = i18n( "N days/hours/minutes before the due datetime",
|
|
"%1 before the to-do is due" );
|
|
} else {
|
|
offsetStr = i18n( "N days/hours/minutes before the end datetime",
|
|
"%1 before the end" );
|
|
}
|
|
} else if ( offset > 0 ) {
|
|
if ( incidence->type() == "Todo" ) {
|
|
offsetStr = i18n( "N days/hours/minutes after the due datetime",
|
|
"%1 after the to-do is due" );
|
|
} else {
|
|
offsetStr = i18n( "N days/hours/minutes after the end datetime",
|
|
"%1 after the end" );
|
|
}
|
|
} else { //offset is 0
|
|
if ( incidence->type() == "Todo" ) {
|
|
Todo *t = static_cast<Todo *>( incidence );
|
|
if ( t->dtDue().isValid() ) {
|
|
atStr = TDEGlobal::locale()->formatDateTime( t->dtDue() );
|
|
}
|
|
} else {
|
|
Event *e = static_cast<Event *>( incidence );
|
|
if ( e->dtEnd().isValid() ) {
|
|
atStr = TDEGlobal::locale()->formatDateTime( e->dtEnd() );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( offset == 0 ) {
|
|
if ( !atStr.isEmpty() ) {
|
|
remStr = i18n( "reminder occurs at datetime", "at %1" ).arg( atStr );
|
|
}
|
|
} else {
|
|
remStr = offsetStr.arg( secs2Duration( offset ) );
|
|
}
|
|
|
|
if ( alarm->repeatCount() > 0 ) {
|
|
TQString countStr = i18n( "repeats once", "repeats %n times", alarm->repeatCount() );
|
|
TQString intervalStr = i18n( "interval is N days/hours/minutes", "interval is %1" ).
|
|
arg( secs2Duration( alarm->snoozeTime().asSeconds() ) );
|
|
TQString repeatStr = i18n( "(repeat string, interval string)", "(%1, %2)" ).
|
|
arg( countStr, intervalStr );
|
|
remStr = remStr + ' ' + repeatStr;
|
|
|
|
}
|
|
reminderStringList << remStr;
|
|
}
|
|
}
|
|
|
|
return reminderStringList;
|
|
}
|