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