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