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 {
00039   if ( !incidence ) return false;
00040 kdDebug(5850)<<"IncidenceChanger::beginChange for incidence \""<<incidence->summary()<<"\""<<endl;
00041   return mCalendar->beginChange( incidence );
00042 }
00043 
00044 bool IncidenceChanger::sendGroupwareMessage( Incidence *incidence,
00045                                              KCal::Scheduler::Method method,
00046                                              KOGlobals::HowChanged action,
00047                                              QWidget *parent )
00048 {
00049   if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) && incidence->attendeeCount()>0
00050       && !KOPrefs::instance()->mUseGroupwareCommunication ) {
00051     emit schedule( method, incidence );
00052     return true;
00053   } else if( KOPrefs::instance()->mUseGroupwareCommunication ) {
00054     return
00055       KOGroupware::instance()->sendICalMessage( parent, method, incidence, action, false );
00056   }
00057   return true;
00058 }
00059 
00060 void IncidenceChanger::cancelAttendees( Incidence *incidence )
00061 {
00062   if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00063     if ( KMessageBox::questionYesNo( 0, i18n("Some attendees were removed "
00064        "from the incidence. Shall cancel messages be sent to these attendees?"),
00065        i18n( "Attendees Removed" ), i18n("Send Messages"), i18n("Do Not Send") ) == KMessageBox::Yes ) {
00066       // don't use KOGroupware::sendICalMessage here, because that asks just
00067       // a very general question "Other people are involved, send message to
00068       // them?", which isn't helpful at all in this situation. Afterwards, it
00069       // would only call the MailScheduler::performTransaction, so do this
00070       // manually.
00071       // FIXME: Groupware scheduling should be factored out to it's own class
00072       //        anyway
00073       KCal::MailScheduler scheduler( mCalendar );
00074       scheduler.performTransaction( incidence, Scheduler::Cancel );
00075     }
00076   }
00077 }
00078 
00079 bool IncidenceChanger::endChange( Incidence *incidence )
00080 {
00081   // FIXME: if that's a groupware incidence, and I'm not the organizer,
00082   // send out a mail to the organizer with a counterproposal instead
00083   // of actually changing the incidence. Then no locking is needed.
00084   // FIXME: if that's a groupware incidence, and the incidence was
00085   // never locked, we can't unlock it with endChange().
00086   if ( !incidence ) return false;
00087 kdDebug(5850)<<"IncidenceChanger::endChange for incidence \""<<incidence->summary()<<"\""<<endl;
00088   return mCalendar->endChange( incidence );
00089 }
00090 
00091 bool IncidenceChanger::deleteIncidence( Incidence *incidence, QWidget *parent )
00092 {
00093   if ( !incidence ) return true;
00094 kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
00095   bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel,
00096                                         KOGlobals::INCIDENCEDELETED, parent );
00097   if( doDelete ) {
00098     // @TODO: let Calendar::deleteIncidence do the locking...
00099     Incidence* tmp = incidence->clone();
00100     emit incidenceToBeDeleted( incidence );
00101     doDelete = mCalendar->deleteIncidence( incidence );
00102     if ( !KOPrefs::instance()->thatIsMe( tmp->organizer().email() ) ) {
00103       const QStringList myEmails = KOPrefs::instance()->allEmails();
00104       bool notifyOrganizer = false;
00105       for ( QStringList::ConstIterator it = myEmails.begin(); it != myEmails.end(); ++it ) {
00106         QString email = *it;
00107         Attendee *me = tmp->attendeeByMail(email);
00108         if ( me ) {
00109           if ( me->status() == KCal::Attendee::Accepted || me->status() == KCal::Attendee::Delegated )
00110             notifyOrganizer = true;
00111           Attendee *newMe = new Attendee( *me );
00112           newMe->setStatus( KCal::Attendee::Declined );
00113           tmp->clearAttendees();
00114           tmp->addAttendee( newMe );
00115           break;
00116         }
00117       }
00118 
00119       if ( !KOGroupware::instance()->doNotNotify() && notifyOrganizer ) {
00120           KCal::MailScheduler scheduler( mCalendar );
00121           scheduler.performTransaction( tmp, Scheduler::Reply );
00122       }
00123       //reset the doNotNotify flag
00124       KOGroupware::instance()->setDoNotNotify( false );
00125     }
00126     emit incidenceDeleted( incidence );
00127   }
00128   return doDelete;
00129 }
00130 
00131 bool IncidenceChanger::cutIncidence( Incidence *incidence, QWidget *parent )
00132 {
00133   if ( !incidence ) return true;
00134 kdDebug(5850)<<"IncidenceChanger::deleteIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
00135   bool doDelete = sendGroupwareMessage( incidence, KCal::Scheduler::Cancel,
00136                                         KOGlobals::INCIDENCEDELETED, parent );
00137   if( doDelete ) {
00138     // @TODO: the factory needs to do the locking!
00139     DndFactory factory( mCalendar );
00140     emit incidenceToBeDeleted( incidence );
00141     factory.cutIncidence( incidence );
00142     emit incidenceDeleted( incidence );
00143   }
00144   return doDelete;
00145 }
00146 
00147 class IncidenceChanger::ComparisonVisitor : public IncidenceBase::Visitor
00148 {
00149   public:
00150     ComparisonVisitor() {}
00151     bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
00152     {
00153       mIncidence2 = inc2;
00154       if ( incidence )
00155         return incidence->accept( *this );
00156       else
00157         return (inc2 == 0);
00158     }
00159   protected:
00160     bool visit( Event *event )
00161     {
00162       Event *ev2 = dynamic_cast<Event*>(mIncidence2);
00163       if ( event && ev2 ) {
00164         return *event == *ev2;
00165       } else {
00166         // either both 0, or return false;
00167         return ( ev2 == event );
00168       }
00169     }
00170     bool visit( Todo *todo )
00171     {
00172       Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
00173       if ( todo && to2 ) {
00174         return *todo == *to2;
00175       } else {
00176         // either both 0, or return false;
00177         return ( todo == to2 );
00178       }
00179     }
00180     bool visit( Journal *journal )
00181     {
00182       Journal *j2 = dynamic_cast<Journal*>( mIncidence2 );
00183       if ( journal && j2 ) {
00184         return *journal == *j2;
00185       } else {
00186         // either both 0, or return false;
00187         return ( journal == j2 );
00188       }
00189     }
00190     bool visit( FreeBusy *fb )
00191     {
00192       FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
00193       if ( fb && fb2 ) {
00194         return *fb == *fb2;
00195       } else {
00196         // either both 0, or return false;
00197         return ( fb2 == fb );
00198       }
00199     }
00200 
00201   protected:
00202     IncidenceBase *mIncidence2;
00203 };
00204 
00205 class IncidenceChanger::AssignmentVisitor : public IncidenceBase::Visitor
00206 {
00207   public:
00208     AssignmentVisitor() {}
00209     bool act( IncidenceBase *incidence, IncidenceBase *inc2 )
00210     {
00211       mIncidence2 = inc2;
00212       if ( incidence )
00213         return incidence->accept( *this );
00214       else
00215         return false;
00216     }
00217   protected:
00218     bool visit( Event *event )
00219     {
00220       Event *ev2 = dynamic_cast<Event*>( mIncidence2 );
00221       if ( event && ev2 ) {
00222         *event = *ev2;
00223         return true;
00224       } else {
00225         return false;
00226       }
00227     }
00228     bool visit( Todo *todo )
00229     {
00230       Todo *to2 = dynamic_cast<Todo*>( mIncidence2 );
00231       if ( todo && to2 ) {
00232         *todo = *to2;
00233         return true;
00234       } else {
00235         return false;
00236       }
00237     }
00238     bool visit( Journal *journal )
00239     {
00240       Journal *j2 = dynamic_cast<Journal*>(mIncidence2);
00241       if ( journal && j2 ) {
00242         *journal = *j2;
00243         return true;
00244       } else {
00245         return false;
00246       }
00247     }
00248     bool visit( FreeBusy *fb )
00249     {
00250       FreeBusy *fb2 = dynamic_cast<FreeBusy*>( mIncidence2 );
00251       if ( fb && fb2 ) {
00252         *fb = *fb2;
00253         return true;
00254       } else {
00255         return false;
00256       }
00257     }
00258 
00259   protected:
00260     IncidenceBase *mIncidence2;
00261 };
00262 
00263 bool IncidenceChanger::incidencesEqual( Incidence *inc1, Incidence *inc2 )
00264 {
00265   ComparisonVisitor v;
00266   return ( v.act( inc1, inc2 ) );
00267 }
00268 
00269 bool IncidenceChanger::assignIncidence( Incidence *inc1, Incidence *inc2 )
00270 {
00271   AssignmentVisitor v;
00272   return v.act( inc1, inc2 );
00273 }
00274 
00275 bool IncidenceChanger::myAttendeeStatusChanged( Incidence *oldInc, Incidence *newInc )
00276 {
00277   Attendee *oldMe = oldInc->attendeeByMails( KOPrefs::instance()->allEmails() );
00278   Attendee *newMe = newInc->attendeeByMails( KOPrefs::instance()->allEmails() );
00279   if ( oldMe && newMe && ( oldMe->status() != newMe->status() ) )
00280     return true;
00281 
00282   return false;
00283 }
00284 
00285 bool IncidenceChanger::changeIncidence( Incidence *oldinc, Incidence *newinc,
00286                                         KOGlobals::WhatChanged action,
00287                                         QWidget *parent )
00288 {
00289 kdDebug(5850)<<"IncidenceChanger::changeIncidence for incidence \""<<newinc->summary()<<"\" ( old one was \""<<oldinc->summary()<<"\")"<<endl;
00290   if ( incidencesEqual( newinc, oldinc ) ) {
00291     // Don't do anything
00292     kdDebug(5850) << "Incidence not changed\n";
00293   } else {
00294     kdDebug(5850) << "Incidence changed\n";
00295     bool attendeeStatusChanged = myAttendeeStatusChanged( oldinc, newinc );
00296     int revision = newinc->revision();
00297     newinc->setRevision( revision + 1 );
00298     // FIXME: Use a generic method for this! Ideally, have an interface class
00299     //        for group cheduling. Each implementation could then just do what
00300     //        it wants with the event. If no groupware is used,use the null
00301     //        pattern...
00302     bool success = true;
00303     if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00304       success = KOGroupware::instance()->sendICalMessage(
00305         parent,
00306         KCal::Scheduler::Request,
00307         newinc, KOGlobals::INCIDENCEEDITED, attendeeStatusChanged );
00308     }
00309 
00310     if ( success ) {
00311       // Accept the event changes
00312       emit incidenceChanged( oldinc, newinc, action );
00313     } else {
00314       // revert changes
00315       assignIncidence( newinc, oldinc );
00316       return false;
00317     }
00318   }
00319   return true;
00320 }
00321 
00322 bool IncidenceChanger::addIncidence( Incidence *incidence, ResourceCalendar *res, const QString &subRes, QWidget *parent )
00323 {
00324   CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
00325   if( stdcal && !stdcal->hasCalendarResources() ) {
00326     KMessageBox::sorry(
00327       parent,
00328       i18n( "No resources found. We can not add event." ) );
00329     return false;
00330   }
00331 
00332   // FIXME: This is a nasty hack, since we need to set a parent for the
00333   //        resource selection dialog. However, we don't have any UI methods
00334   //        in the calendar, only in the CalendarResources::DestinationPolicy
00335   //        So we need to type-cast it and extract it from the CalendarResources
00336   QWidget *tmpparent = 0;
00337   if ( stdcal ) {
00338     tmpparent = stdcal->dialogParentWidget();
00339     stdcal->setDialogParentWidget( parent );
00340   }
00341 
00342   // If a ResourceCalendar isn't provided, then try to compute one
00343   // along with any subResource from the incidence.
00344   ResourceCalendar *pRes = res;
00345   QString pSubRes = subRes;
00346   QString pResName = i18n( "the selected calendar", "selected" );
00347   if ( !pRes ) {
00348     if ( stdcal ) {
00349       pRes = stdcal->resource( incidence );
00350       if ( pRes ) {
00351         pResName = pRes->resourceName();
00352         if ( pRes->canHaveSubresources() ) {
00353           pSubRes = pRes->subresourceIdentifier( incidence );
00354           pResName = pRes->labelForSubresource( pSubRes );
00355         }
00356       }
00357     }
00358   }
00359 
00360   bool success = false;
00361   if ( stdcal && pRes ) {
00362     success = stdcal->addIncidence( incidence, pRes, pSubRes );
00363   } else {
00364     success = mCalendar->addIncidence( incidence );
00365   }
00366 
00367   if ( !success ) {
00368     KMessageBox::sorry(
00369       parent,
00370       i18n( "Unable to save %1 \"%2\" to calendar %3." ).
00371       arg( i18n( incidence->type() ) ).
00372       arg( incidence->summary() ).
00373       arg( pResName ) );
00374     return false;
00375   }
00376 
00377   if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00378     if ( !KOGroupware::instance()->sendICalMessage(
00379            parent,
00380            KCal::Scheduler::Request,
00381            incidence, KOGlobals::INCIDENCEADDED, false ) ) {
00382       KMessageBox::sorry(
00383         parent,
00384         i18n( "Attempt to send the scheduling message failed. "
00385               "Please check your Group Scheduling settings. "
00386               "Contact your system administrator for more help.") );
00387     }
00388   }
00389 
00390   emit incidenceAdded( incidence );
00391   return true;
00392 }
00393 
00394 
00395 #include "incidencechanger.moc"
00396 #include "incidencechangerbase.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys