korganizer

incidencechanger.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005 
00006     This program is free software; you can redistribute it and/or modify
00007     it under the terms of the GNU General Public License as published by
00008     the Free Software Foundation; either version 2 of the License, or
00009     (at your option) any later version.
00010 
00011     This program is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00014     GNU General Public License for more details.
00015 
00016     You should have received a copy of the GNU General Public License
00017     along with this program; if not, write to the Free Software
00018     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019 
00020     As a special exception, permission is given to link this program
00021     with any edition of Qt, and distribute the resulting executable,
00022     without including the source code for Qt in the source distribution.
00023 */
00024 
00025 #include "incidencechanger.h"
00026 #include "koglobals.h"
00027 #include "koprefs.h"
00028 #include "kogroupware.h"
00029 #include "mailscheduler.h"
00030 
00031 #include <libkcal/freebusy.h>
00032 #include <libkcal/dndfactory.h>
00033 #include <kdebug.h>
00034 #include <kmessagebox.h>
00035 #include <klocale.h>
00036 
00037 bool IncidenceChanger::beginChange( Incidence *incidence,
00038                                     ResourceCalendar *res, const QString &subRes )
00039 {
00040   if ( !incidence ) {
00041     return false;
00042   }
00043 
00044   kdDebug(5850) << "IncidenceChanger::beginChange for incidence \""
00045                 << incidence->summary() << "\"" << endl;
00046 
00047   CalendarResources *calRes = dynamic_cast<CalendarResources*>( mCalendar );
00048   if ( !calRes ) {
00049     return false;
00050   }
00051 
00052   return calRes->beginChange( incidence, res, subRes );
00053 }
00054 
00055 bool IncidenceChanger::sendGroupwareMessage( Incidence *incidence,
00056                                              KCal::Scheduler::Method method,
00057                                              KOGlobals::HowChanged action,
00058                                              QWidget *parent )
00059 {
00060   if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) && incidence->attendeeCount()>0
00061       && !KOPrefs::instance()->mUseGroupwareCommunication ) {
00062     emit schedule( method, incidence );
00063     return true;
00064   } else if( KOPrefs::instance()->mUseGroupwareCommunication ) {
00065     return
00066       KOGroupware::instance()->sendICalMessage( parent, method, incidence, action, false );
00067   }
00068   return true;
00069 }
00070 
00071 void IncidenceChanger::cancelAttendees( Incidence *incidence )
00072 {
00073   if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00074     if ( KMessageBox::questionYesNo( 0, i18n("Some attendees were removed "
00075        "from the incidence. Shall cancel messages be sent to these attendees?"),
00076        i18n( "Attendees Removed" ), i18n("Send Messages"), i18n("Do Not Send") ) == KMessageBox::Yes ) {
00077       // don't use KOGroupware::sendICalMessage here, because that asks just
00078       // a very general question "Other people are involved, send message to
00079       // them?", which isn't helpful at all in this situation. Afterwards, it
00080       // would only call the MailScheduler::performTransaction, so do this
00081       // manually.
00082       // FIXME: Groupware scheduling should be factored out to it's own class
00083       //        anyway
00084       KCal::MailScheduler scheduler( mCalendar );
00085       scheduler.performTransaction( incidence, Scheduler::Cancel );
00086     }
00087   }
00088 }
00089 
00090 bool IncidenceChanger::endChange( Incidence *incidence,
00091                                   ResourceCalendar *res, const QString &subRes )
00092 {
00093   // FIXME: if that's a groupware incidence, and I'm not the organizer,
00094   // send out a mail to the organizer with a counterproposal instead
00095   // of actually changing the incidence. Then no locking is needed.
00096   // FIXME: if that's a groupware incidence, and the incidence was
00097   // never locked, we can't unlock it with endChange().
00098 
00099   if ( !incidence ) {
00100     return false;
00101   }
00102 
00103   kdDebug(5850) << "IncidenceChanger::endChange for incidence \""
00104                 << incidence->summary() << "\"" << endl;
00105 
00106   CalendarResources *calRes = dynamic_cast<CalendarResources*>( mCalendar );
00107   if ( !calRes ) {
00108     return false;
00109   }
00110 
00111   return calRes->endChange( incidence, res, subRes );
00112 }
00113 
00114 bool IncidenceChanger::deleteIncidence( Incidence *incidence, QWidget *parent )
00115 {
00116   if ( !incidence ) return true;
00117 kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
00118   bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel,
00119                                         KOGlobals::INCIDENCEDELETED, parent );
00120   if( doDelete ) {
00121     // @TODO: let Calendar::deleteIncidence do the locking...
00122     Incidence* tmp = incidence->clone();
00123     emit incidenceToBeDeleted( incidence );
00124     doDelete = mCalendar->deleteIncidence( incidence );
00125     if ( !KOPrefs::instance()->thatIsMe( tmp->organizer().email() ) ) {
00126       const QStringList myEmails = KOPrefs::instance()->allEmails();
00127       bool notifyOrganizer = false;
00128       for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
00129         QString email = *it;
00130         Attendee *me = tmp->attendeeByMail(email);
00131         if ( me ) {
00132           if ( me->status() == KCal::Attendee::Accepted || me->status() == KCal::Attendee::Delegated )
00133             notifyOrganizer = true;
00134           Attendee *newMe = new Attendee( *me );
00135           newMe->setStatus( KCal::Attendee::Declined );
00136           tmp->clearAttendees();
00137           tmp->addAttendee( newMe );
00138           break;
00139         }
00140       }
00141 
00142       if ( !KOGroupware::instance()->doNotNotify() && notifyOrganizer ) {
00143           KCal::MailScheduler scheduler( mCalendar );
00144           scheduler.performTransaction( tmp, Scheduler::Reply );
00145       }
00146       //reset the doNotNotify flag
00147       KOGroupware::instance()->setDoNotNotify( false );
00148     }
00149     emit incidenceDeleted( incidence );
00150   }
00151   return doDelete;
00152 }
00153 
00154 bool IncidenceChanger::cutIncidence( Incidence *incidence, QWidget *parent )
00155 {
00156   if ( !incidence ) return true;
00157 kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
00158   bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel,
00159                                         KOGlobals::INCIDENCEDELETED, parent );
00160   if( doDelete ) {
00161     // @TODO: the factory needs to do the locking!
00162     DndFactory factory( mCalendar );
00163     emit incidenceToBeDeleted( incidence );
00164     factory.cutIncidence( incidence );
00165     emit incidenceDeleted( incidence );
00166   }
00167   return doDelete;
00168 }
00169 
00170 class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor
00171 {
00172   public:
00173     ComparisonVisitor() {}
00174     bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
00175     {
00176       mIncidence2 = inc2;
00177       if ( incidence )
00178         return incidence->accept( *this );
00179       else
00180         return (inc2 == 0);
00181     }
00182   protected:
00183     bool visit( Event *event )
00184     {
00185       Event *ev2 = dynamic_cast<Event*>(mIncidence2);
00186       if ( event && ev2 ) {
00187         return *event == *ev2;
00188       } else {
00189         // either both 0, or return false;
00190         return ( ev2 == event );
00191       }
00192     }
00193     bool visit( Todo *todo )
00194     {
00195       Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
00196       if ( todo && to2 ) {
00197         return *todo == *to2;
00198       } else {
00199         // either both 0, or return false;
00200         return ( todo == to2 );
00201       }
00202     }
00203     bool visit( Journal *journal )
00204     {
00205       Journal *j2 = dynamic_cast<Journal*>( mIncidence2 );
00206       if ( journal && j2 ) {
00207         return *journal == *j2;
00208       } else {
00209         // either both 0, or return false;
00210         return ( journal == j2 );
00211       }
00212     }
00213     bool visit( FreeBusy *fb )
00214     {
00215       FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
00216       if ( fb && fb2 ) {
00217         return *fb == *fb2;
00218       } else {
00219         // either both 0, or return false;
00220         return ( fb2 == fb );
00221       }
00222     }
00223 
00224   protected:
00225     IncidenceBase *mIncidence2;
00226 };
00227 
00228 class IncidenceChanger::AssignmentVisitor : public IncidenceBase::Visitor
00229 {
00230   public:
00231     AssignmentVisitor() {}
00232     bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
00233     {
00234       mIncidence2 = inc2;
00235       if ( incidence )
00236         return incidence->accept( *this );
00237       else
00238         return false;
00239     }
00240   protected:
00241     bool visit( Event *event )
00242     {
00243       Event *ev2 = dynamic_cast<Event*>( mIncidence2 );
00244       if ( event && ev2 ) {
00245         *event = *ev2;
00246         return true;
00247       } else {
00248         return false;
00249       }
00250     }
00251     bool visit( Todo *todo )
00252     {
00253       Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
00254       if ( todo && to2 ) {
00255         *todo = *to2;
00256         return true;
00257       } else {
00258         return false;
00259       }
00260     }
00261     bool visit( Journal *journal )
00262     {
00263       Journal *j2 = dynamic_cast<Journal*>(mIncidence2);
00264       if ( journal && j2 ) {
00265         *journal = *j2;
00266         return true;
00267       } else {
00268         return false;
00269       }
00270     }
00271     bool visit( FreeBusy *fb )
00272     {
00273       FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
00274       if ( fb && fb2 ) {
00275         *fb = *fb2;
00276         return true;
00277       } else {
00278         return false;
00279       }
00280     }
00281 
00282   protected:
00283     IncidenceBase *mIncidence2;
00284 };
00285 
00286 bool IncidenceChanger::incidencesEqual( Incidence *inc1, Incidence *inc2 )
00287 {
00288   ComparisonVisitor v;
00289   return ( v.act( inc1, inc2 ) );
00290 }
00291 
00292 bool IncidenceChanger::assignIncidence( Incidence *inc1, Incidence *inc2 )
00293 {
00294   AssignmentVisitor v;
00295   return v.act( inc1, inc2 );
00296 }
00297 
00298 bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc )
00299 {
00300   Attendee *oldMe = oldInc->attendeeByMails( KOPrefs::instance()->allEmails() );
00301   Attendee *newMe = newInc->attendeeByMails( KOPrefs::instance()->allEmails() );
00302   if ( oldMe && newMe && ( oldMe->status() != newMe->status() ) )
00303     return true;
00304 
00305   return false;
00306 }
00307 
00308 bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
00309                                         KOGlobals::WhatChanged action,
00310                                         QWidget *parent )
00311 {
00312 kdDebug(5850)<<"IncidenceChanger::changeIncidence for incidence \""<<newinc->summary()<<"\" ( old one was \""<<oldinc->summary()<<"\")"<<endl;
00313   if ( incidencesEqual( newinc, oldinc ) ) {
00314     // Don't do anything
00315     kdDebug(5850) << "Incidence not changed\n";
00316   } else {
00317     kdDebug(5850) << "Incidence changed\n";
00318     bool attendeeStatusChanged = myAttendeeStatusChanged( oldinc, newinc );
00319     int revision = newinc->revision();
00320     newinc->setRevision( revision + 1 );
00321     // FIXME: Use a generic method for this! Ideally, have an interface class
00322     //        for group cheduling. Each implementation could then just do what
00323     //        it wants with the event. If no groupware is used,use the null
00324     //        pattern...
00325     bool success = true;
00326     if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00327       success = KOGroupware::instance()->sendICalMessage(
00328         parent,
00329         KCal::Scheduler::Request,
00330         newinc, KOGlobals::INCIDENCEEDITED, attendeeStatusChanged );
00331     }
00332 
00333     if ( success ) {
00334       // Accept the event changes
00335       emit incidenceChanged( oldinc, newinc, action );
00336     } else {
00337       // revert changes
00338       assignIncidence( newinc, oldinc );
00339       return false;
00340     }
00341   }
00342   return true;
00343 }
00344 
00345 bool IncidenceChanger::addIncidence( Incidence *incidence,
00346                                      ResourceCalendar *res, const QString &subRes,
00347                                      QWidget *parent )
00348 {
00349   CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
00350   if( stdcal && !stdcal->hasCalendarResources() ) {
00351     KMessageBox::sorry(
00352       parent,
00353       i18n( "No calendars found, unable to save %1 \"%2\"." ).
00354       arg( i18n( incidence->type() ) ).
00355       arg( incidence->summary() ) );
00356     return false;
00357   }
00358 
00359   // FIXME: This is a nasty hack, since we need to set a parent for the
00360   //        resource selection dialog. However, we don't have any UI methods
00361   //        in the calendar, only in the CalendarResources::DestinationPolicy
00362   //        So we need to type-cast it and extract it from the CalendarResources
00363   QWidget *tmpparent = 0;
00364   if ( stdcal ) {
00365     tmpparent = stdcal->dialogParentWidget();
00366     stdcal->setDialogParentWidget( parent );
00367   }
00368 
00369   // If a ResourceCalendar isn't provided, then try to compute one
00370   // along with any subResource from the incidence.
00371   ResourceCalendar *pRes = res;
00372   QString pSubRes = subRes;
00373   QString pResName;
00374   if ( !pRes ) {
00375     if ( stdcal ) {
00376       pRes = stdcal->resource( incidence );
00377       if ( pRes ) {
00378         pResName = pRes->resourceName();
00379         if ( pRes->canHaveSubresources() ) {
00380           pSubRes = pRes->subresourceIdentifier( incidence );
00381           pResName = pRes->labelForSubresource( pSubRes );
00382         }
00383       }
00384     }
00385   }
00386 
00387   bool success = false;
00388   if ( stdcal && pRes ) {
00389     success = stdcal->addIncidence( incidence, pRes, pSubRes );
00390   } else {
00391     success = mCalendar->addIncidence( incidence );
00392   }
00393 
00394   if ( !success ) {
00395     // We can have a failure if the user pressed [cancel] in the resource
00396     // selectdialog, so check the exception.
00397     ErrorFormat *e = stdcal ? stdcal->exception() : 0;
00398     if ( !e ||
00399          ( e && ( e->errorCode() != KCal::ErrorFormat::UserCancel &&
00400                   e->errorCode() != KCal::ErrorFormat::NoWritableFound ) ) ) {
00401       QString errMessage;
00402       if ( pResName.isEmpty() ) {
00403         errMessage = i18n( "Unable to save %1 \"%2\"." ).
00404                      arg( i18n( incidence->type() ) ).
00405                      arg( incidence->summary() );
00406       } else {
00407         errMessage = i18n( "Unable to save %1 \"%2\" to calendar %3." ).
00408                      arg( i18n( incidence->type() ) ).
00409                      arg( incidence->summary() ).
00410                      arg( pResName );
00411       }
00412       KMessageBox::sorry( parent, errMessage );
00413     }
00414     return false;
00415   }
00416 
00417   if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00418     if ( !KOGroupware::instance()->sendICalMessage(
00419            parent,
00420            KCal::Scheduler::Request,
00421            incidence, KOGlobals::INCIDENCEADDED, false ) ) {
00422       KMessageBox::sorry(
00423         parent,
00424         i18n( "Attempt to send the scheduling message failed. "
00425               "Please check your Group Scheduling settings. "
00426               "Contact your system administrator for more help.") );
00427     }
00428   }
00429 
00430   emit incidenceAdded( incidence );
00431   return true;
00432 }
00433 
00434 
00435 #include "incidencechanger.moc"
00436 #include "incidencechangerbase.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys