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 )
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   } else {
00264     kdDebug(5850) << "Incidence changed\n";
00265     bool statusChanged = myAttendeeStatusChanged( oldinc, newinc );
00266     int revision = newinc->revision();
00267     newinc->setRevision( revision + 1 );
00268     // FIXME: Use a generic method for this! Ideally, have an interface class
00269     //        for group cheduling. Each implementation could then just do what
00270     //        it wants with the event. If no groupware is used,use the null
00271     //        pattern...
00272     if( !KOPrefs::instance()->mUseGroupwareCommunication ||
00273         KOGroupware::instance()->sendICalMessage( 0,
00274                                                   KCal::Scheduler::Request,
00275                                                   newinc, false, statusChanged ) ) {
00276       // Accept the event changes
00277       if ( action<0 ) {
00278         emit incidenceChanged( oldinc, newinc );
00279       } else {
00280         emit incidenceChanged( oldinc, newinc, action );
00281       }
00282     } else {
00283       // FIXME: Revert the changes
00284 //      assignIncidence( newinc, oldinc );
00285       return false;
00286     }
00287   }
00288   return true;
00289 }
00290 
00291 bool IncidenceChanger::addIncidence( Incidence *incidence, QWidget *parent )
00292 {
00293 kdDebug(5850)<<"IncidenceChanger::addIncidence for incidence \""<<incidence->summary()<<"\""<<endl;
00294   if ( KOPrefs::instance()->mUseGroupwareCommunication ) {
00295     if ( !KOGroupware::instance()->sendICalMessage( parent,
00296                                                     KCal::Scheduler::Request,
00297                                                     incidence ) ) {
00298       kdError() << "sendIcalMessage failed." << endl;
00299     }
00300   }
00301   // FIXME: This is a nasty hack, since we need to set a parent for the 
00302   //        resource selection dialog. However, we don't have any UI methods
00303   //        in the calendar, only in the CalendarResources::DestinationPolicy
00304   //        So we need to type-cast it and extract it from the CalendarResources
00305   CalendarResources *stdcal = dynamic_cast<CalendarResources*>(mCalendar);
00306   QWidget *tmpparent = 0;
00307   if ( stdcal ) {
00308     tmpparent = stdcal->dialogParentWidget();
00309     stdcal->setDialogParentWidget( parent );
00310   }
00311   bool success = mCalendar->addIncidence( incidence );
00312   if ( stdcal ) {
00313     // Reset the parent widget, otherwise we'll end up with pointers to deleted 
00314     // widgets sooner or later
00315     stdcal->setDialogParentWidget( tmpparent );
00316   }
00317   if ( !success ) {
00318     KMessageBox::sorry( parent, i18n("Unable to save %1 \"%2\".")
00319                         .arg( i18n( incidence->type() ) )
00320                         .arg( incidence->summary() ) );
00321     return false;
00322   }
00323   emit incidenceAdded( incidence );
00324   return true;
00325 }
00326 
00327 #include "incidencechanger.moc"
00328 #include "incidencechangerbase.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys