korganizer

calendarview.cpp

00001 /*
00002     This file is part of KOrganizer.
00003 
00004     Copyright (c) 1997, 1998, 1999
00005     Preston Brown (preston.brown@yale.edu)
00006     Fester Zigterman (F.J.F.ZigtermanRustenburg@student.utwente.nl)
00007     Ian Dawes (iadawes@globalserve.net)
00008     Laszlo Boloni (boloni@cs.purdue.edu)
00009 
00010     Copyright (c) 2000, 2001, 2002, 2003, 2004
00011     Cornelius Schumacher <schumacher@kde.org>
00012     Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00013 
00014     This program is free software; you can redistribute it and/or modify
00015     it under the terms of the GNU General Public License as published by
00016     the Free Software Foundation; either version 2 of the License, or
00017     (at your option) any later version.
00018 
00019     This program is distributed in the hope that it will be useful,
00020     but WITHOUT ANY WARRANTY; without even the implied warranty of
00021     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00022     GNU General Public License for more details.
00023 
00024     You should have received a copy of the GNU General Public License
00025     along with this program; if not, write to the Free Software
00026     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00027 
00028     As a special exception, permission is given to link this program
00029     with any edition of Qt, and distribute the resulting executable,
00030     without including the source code for Qt in the source distribution.
00031 */
00032 
00033 #include "calendarview.h"
00034 
00035 #ifndef KORG_NOPRINTER
00036 #include "calprinter.h"
00037 #endif
00038 #include "koeventeditor.h"
00039 #include "kotodoeditor.h"
00040 #include "kojournaleditor.h"
00041 #include "koprefs.h"
00042 #include "koeventviewerdialog.h"
00043 #include "publishdialog.h"
00044 #include "koglobals.h"
00045 #include "koviewmanager.h"
00046 #include "koagendaview.h"
00047 #include "kodialogmanager.h"
00048 #include "statusdialog.h"
00049 #include "datenavigatorcontainer.h"
00050 #include "kotodoview.h"
00051 #include "datenavigator.h"
00052 #include "resourceview.h"
00053 #include "navigatorbar.h"
00054 #include "history.h"
00055 #include "kogroupware.h"
00056 #include "freebusymanager.h"
00057 #include "komonthview.h"
00058 #include "datechecker.h"
00059 #include "komessagebox.h"
00060 #include "exportwebdialog.h"
00061 #include "kocorehelper.h"
00062 #include "incidencechanger.h"
00063 #include "kholidays.h"
00064 #include "mailscheduler.h"
00065 #include "komailclient.h"
00066 #include "multiagendaview.h"
00067 
00068 #include <libkcal/calhelper.h>
00069 #include <libkcal/vcaldrag.h>
00070 #include <libkcal/icaldrag.h>
00071 #include <libkcal/icalformat.h>
00072 #include <libkcal/vcalformat.h>
00073 #include <libkcal/scheduler.h>
00074 #include <libkcal/calendarlocal.h>
00075 #include <libkcal/journal.h>
00076 #include <libkcal/calfilter.h>
00077 #include <libkcal/attendee.h>
00078 #include <libkcal/dndfactory.h>
00079 #include <libkcal/freebusy.h>
00080 #include <libkcal/filestorage.h>
00081 #include <libkcal/calendarresources.h>
00082 #include <libkcal/calendarnull.h>
00083 #include <libkcal/htmlexportsettings.h>
00084 
00085 #include <kglobal.h>
00086 #include <kdebug.h>
00087 #include <kstandarddirs.h>
00088 #include <kfiledialog.h>
00089 #include <kmessagebox.h>
00090 #include <knotifyclient.h>
00091 #include <kconfig.h>
00092 #include <krun.h>
00093 #include <kdirwatch.h>
00094 
00095 #include <qapplication.h>
00096 #include <qclipboard.h>
00097 #include <qcursor.h>
00098 #include <qmultilineedit.h>
00099 #include <qtimer.h>
00100 #include <qwidgetstack.h>
00101 #include <qptrlist.h>
00102 #include <qfile.h>
00103 #include <qlayout.h>
00104 #ifndef KORG_NOSPLITTER
00105 #include <qsplitter.h>
00106 #endif
00107 #include <qvbox.h>
00108 #include <qwhatsthis.h>
00109 
00110 #include <stdlib.h>
00111 #include <assert.h>
00112 
00113 using namespace KOrg;
00114 
00115 CalendarView::CalendarView( QWidget *parent, const char *name )
00116   : CalendarViewBase( parent, name ),
00117     mHistory( 0 ),
00118     mCalendar( CalendarNull::self() ),
00119     mChanger( 0 )
00120 {
00121   kdDebug(5850) << "CalendarView::CalendarView( Calendar )" << endl;
00122 
00123   mViewManager = new KOViewManager( this );
00124   mDialogManager = new KODialogManager( this );
00125 
00126   mModified = false;
00127   mReadOnly = false;
00128   mSelectedIncidence = 0;
00129 
00130   mFilters.setAutoDelete( true );
00131 
00132   mExtensions.setAutoDelete( true );
00133 
00134   mDateNavigator = new DateNavigator( this );
00135   mDateChecker = new DateChecker( this );
00136 
00137   QBoxLayout *topLayout = new QVBoxLayout( this );
00138 
00139 #ifndef KORG_NOSPLITTER
00140   // create the main layout frames.
00141   mPanner = new QSplitter( QSplitter::Horizontal, this,
00142                            "CalendarView::Panner" );
00143   topLayout->addWidget( mPanner );
00144 
00145   mLeftSplitter = new QSplitter( QSplitter::Vertical, mPanner,
00146                                  "CalendarView::LeftFrame" );
00147 //  mPanner->setResizeMode( mLeftSplitter, QSplitter::Stretch );
00148 
00149   mDateNavigatorContainer = new DateNavigatorContainer( mLeftSplitter,
00150                                                "CalendarView::DateNavigator" );
00151 
00152 //  mLeftSplitter->setResizeMode( mDateNavigatorContainer, QSplitter::Stretch );
00153   mLeftSplitter->setCollapsible( mDateNavigatorContainer, true );
00154   mTodoList = new KOTodoView( CalendarNull::self(), mLeftSplitter, "todolist" );
00155 
00156   mEventViewer = new KOEventViewer( CalendarNull::self(), mLeftSplitter,"EventViewer" );
00157 
00158   QVBox *rightBox = new QVBox( mPanner );
00159   mNavigatorBar = new NavigatorBar( rightBox );
00160   mRightFrame = new QWidgetStack( rightBox );
00161   rightBox->setStretchFactor( mRightFrame, 1 );
00162 
00163   mLeftFrame = mLeftSplitter;
00164 #else
00165   QWidget *mainBox;
00166   QWidget *leftFrame;
00167 
00168   if ( KOPrefs::instance()->mVerticalScreen ) {
00169     mainBox = new QVBox( this );
00170     leftFrame = new QHBox( mainBox );
00171   } else {
00172     mainBox = new QHBox( this );
00173     leftFrame = new QVBox( mainBox );
00174   }
00175 
00176   topLayout->addWidget( mainBox );
00177 
00178   mDateNavigatorContainer = new KDateNavigator( leftFrame, true,
00179                                        "CalendarView::DateNavigator",
00180                                        QDate::currentDate() );
00181   mTodoList = new KOTodoView( CalendarNull::self(), leftFrame, "todolist" );
00182 
00183   mEventViewer = new KOEventViewer ( CalendarNull::self(), leftFrame, "EventViewer" );
00184 
00185   QWidget *rightBox = new QWidget( mainBox );
00186   QBoxLayout *rightLayout = new QVBoxLayout( rightBox );
00187 
00188   mNavigatorBar = new NavigatorBar( QDate::currentDate(), rightBox );
00189   rightLayout->addWidget( mNavigatorBar );
00190 
00191   mRightFrame = new QWidgetStack( rightBox );
00192   rightLayout->addWidget( mRightFrame );
00193 
00194   mLeftFrame = leftFrame;
00195 
00196   if ( KOPrefs::instance()->mVerticalScreen ) {
00197     // mTodoList->setFixedHeight( 60 );
00198     mTodoList->setFixedHeight( mDateNavigatorContainer->sizeHint().height() );
00199   }
00200 #endif
00201 
00202   // Signals emited by mDateNavigator
00203   connect( mDateNavigator, SIGNAL( datesSelected( const KCal::DateList &, const QDate & ) ),
00204            SLOT( showDates( const KCal::DateList &, const QDate & ) ) );
00205 
00206   // Signals emited by mNavigatorBar
00207   connect( mNavigatorBar, SIGNAL( prevYearClicked() ),
00208            mDateNavigator, SLOT( selectPreviousYear() ) );
00209   connect( mNavigatorBar, SIGNAL( nextYearClicked() ),
00210            mDateNavigator, SLOT( selectNextYear() ) );
00211   connect( mNavigatorBar, SIGNAL( prevMonthClicked() ),
00212            mDateNavigator, SLOT( selectPreviousMonth() ) );
00213   connect( mNavigatorBar, SIGNAL( nextMonthClicked() ),
00214            mDateNavigator, SLOT( selectNextMonth() ) );
00215   connect( mNavigatorBar, SIGNAL( monthSelected(int) ),
00216            mDateNavigator, SLOT( selectMonth(int) ) );
00217   connect( mNavigatorBar, SIGNAL( yearSelected(int)),
00218            mDateNavigator, SLOT(selectYear(int)) );
00219 
00220 
00221   // Signals emited by mDateNavigatorContainer
00222   connect( mDateNavigatorContainer, SIGNAL( weekClicked( const QDate & ) ),
00223            this, SLOT( selectWeek( const QDate & ) ) );
00224   connect( mDateNavigatorContainer, SIGNAL( prevMonthClicked(const QDate &, const QDate &, const QDate &) ),
00225            mDateNavigator, SLOT( selectPreviousMonth(const QDate &, const QDate &, const QDate &) ) );
00226   connect( mDateNavigatorContainer, SIGNAL( nextMonthClicked(const QDate &, const QDate &, const QDate &) ),
00227            mDateNavigator, SLOT( selectNextMonth(const QDate &, const QDate &, const QDate &) ) );
00228   connect( mDateNavigatorContainer, SIGNAL( prevYearClicked() ),
00229            mDateNavigator, SLOT( selectPreviousYear() ) );
00230   connect( mDateNavigatorContainer, SIGNAL( nextYearClicked() ),
00231            mDateNavigator, SLOT( selectNextYear() ) );
00232   connect( mDateNavigatorContainer, SIGNAL( monthSelected(int) ),
00233            mDateNavigator, SLOT( selectMonth(int) ) );
00234   connect( mDateNavigatorContainer, SIGNAL(yearSelected(int)),
00235            mDateNavigator, SLOT(selectYear(int)) );
00236   connect( mDateNavigatorContainer, SIGNAL( goPrevious() ),
00237            mDateNavigator, SLOT( selectPrevious() ) );
00238   connect( mDateNavigatorContainer, SIGNAL( goNext() ),
00239            mDateNavigator, SLOT( selectNext() ) );
00240 
00241   connect( mDateNavigatorContainer, SIGNAL( datesSelected( const KCal::DateList & ) ),
00242            mDateNavigator, SLOT( selectDates( const KCal::DateList & ) ) );
00243 
00244   connect( mDateNavigatorContainer, SIGNAL(incidenceDropped(Incidence*, const QDate&)),
00245            SLOT( addIncidenceOn( Incidence *, const QDate & ) ) );
00246   connect( mDateNavigatorContainer, SIGNAL(incidenceDroppedMove(Incidence*,const QDate&)),
00247            SLOT( moveIncidenceTo( Incidence *, const QDate & ) ) );
00248 
00249   connect( mDateChecker, SIGNAL( dayPassed( const QDate & ) ),
00250            mTodoList, SLOT( dayPassed( const QDate & ) ) );
00251   connect( mDateChecker, SIGNAL( dayPassed( const QDate & ) ),
00252            SIGNAL( dayPassed( const QDate & ) ) );
00253   connect( mDateChecker, SIGNAL( dayPassed( const QDate & ) ),
00254            mDateNavigatorContainer, SLOT( updateToday() ) );
00255 
00256   connect( this, SIGNAL( configChanged() ),
00257            mDateNavigatorContainer, SLOT( updateConfig() ) );
00258 
00259   connect( this, SIGNAL( incidenceSelected(Incidence *, const QDate &) ),
00260            mEventViewer, SLOT ( setIncidence (Incidence *, const QDate &) ) );
00261 
00262   //TODO: do a pretty Summary,
00263   QString s;
00264   s = i18n( "<p><em>No Item Selected</em></p>"
00265            "<p>Select an event, to-do or journal entry to view its details "
00266            "here.</p>");
00267 
00268   mEventViewer->setDefaultText( s );
00269   QWhatsThis::add( mEventViewer,
00270                    i18n( "View the details of events, journal entries or to-dos "
00271                          "selected in KOrganizer's main view here." ) );
00272   mEventViewer->setIncidence( 0, QDate() );
00273 
00274   mViewManager->connectTodoView( mTodoList );
00275   mViewManager->connectView( mTodoList );
00276 
00277   KOGlobals::self()->
00278       setHolidays( new KHolidays( KOPrefs::instance()->mHolidays ) );
00279 
00280   connect( QApplication::clipboard(), SIGNAL( dataChanged() ),
00281            SLOT( checkClipboard() ) );
00282 
00283   connect( mTodoList, SIGNAL( incidenceSelected( Incidence *,const QDate & ) ),
00284            SLOT( processTodoListSelection( Incidence *,const QDate & ) ) );
00285   disconnect( mTodoList, SIGNAL( incidenceSelected( Incidence *,const QDate & ) ),
00286            this, SLOT( processMainViewSelection( Incidence *,const QDate & ) ) );
00287 
00288   kdDebug(5850) << "CalendarView::CalendarView() done" << endl;
00289 }
00290 
00291 CalendarView::~CalendarView()
00292 {
00293   kdDebug(5850) << "~CalendarView()" << endl;
00294 
00295   mCalendar->unregisterObserver( this );
00296 
00297   delete mDialogManager;
00298   delete mViewManager;
00299   delete mEventViewer;
00300   kdDebug(5850) << "~CalendarView() done" << endl;
00301 }
00302 
00303 void CalendarView::setCalendar( Calendar *cal )
00304 {
00305   kdDebug(5850)<<"CalendarView::setCalendar"<<endl;
00306   mCalendar = cal;
00307 
00308   delete mHistory;
00309   mHistory = new History( mCalendar );
00310   connect( mHistory, SIGNAL( undone() ), SLOT( updateView() ) );
00311   connect( mHistory, SIGNAL( redone() ), SLOT( updateView() ) );
00312 
00313   if ( mChanger ) delete mChanger;
00314   setIncidenceChanger( new IncidenceChanger( mCalendar, this ) );
00315 
00316   mCalendar->registerObserver( this );
00317 
00318   mDateNavigatorContainer->setCalendar( mCalendar );
00319 
00320   mTodoList->setCalendar( mCalendar );
00321 
00322   mEventViewer->setCalendar( mCalendar );
00323 }
00324 
00325 void CalendarView::setIncidenceChanger( IncidenceChangerBase *changer )
00326 {
00327   mChanger = changer;
00328   emit newIncidenceChanger( mChanger );
00329   connect( mChanger, SIGNAL( incidenceAdded( Incidence* ) ),
00330            this, SLOT( incidenceAdded( Incidence* ) ) );
00331   connect( mChanger, SIGNAL( incidenceChanged( Incidence*, Incidence*, KOGlobals::WhatChanged ) ),
00332            this, SLOT( incidenceChanged( Incidence*, Incidence*, KOGlobals::WhatChanged ) ) );
00333   connect( mChanger, SIGNAL( incidenceToBeDeleted( Incidence * ) ),
00334            this, SLOT( incidenceToBeDeleted( Incidence * ) ) );
00335   connect( mChanger, SIGNAL( incidenceDeleted( Incidence * ) ),
00336            this, SLOT( incidenceDeleted( Incidence * ) ) );
00337 
00338   connect( mChanger, SIGNAL( schedule( Scheduler::Method, Incidence*) ),
00339            this, SLOT( schedule( Scheduler::Method, Incidence*) ) );
00340 
00341 
00342   connect( this, SIGNAL( cancelAttendees( Incidence * ) ),
00343            mChanger, SLOT( cancelAttendees( Incidence * ) ) );
00344 }
00345 
00346 Calendar *CalendarView::calendar()
00347 {
00348   if ( mCalendar ) return mCalendar;
00349   else return CalendarNull::self();
00350 }
00351 
00352 QPair<ResourceCalendar *, QString> CalendarView::viewSubResourceCalendar()
00353 {
00354   QPair<ResourceCalendar *, QString> p( 0, QString() );
00355   KOrg::BaseView *cV = mViewManager->currentView();
00356   if ( cV && cV == mViewManager->multiAgendaView() ) {
00357     cV = mViewManager->multiAgendaView()->selectedAgendaView();
00358   }
00359   if ( cV ) {
00360     p = qMakePair( cV->resourceCalendar(), cV->subResourceCalendar() );
00361   }
00362   return p;
00363 }
00364 
00365 KOIncidenceEditor *CalendarView::editorDialog( Incidence *incidence ) const
00366 {
00367   if (mDialogList.find(incidence) != mDialogList.end ())
00368     return mDialogList[incidence];
00369   else return 0;
00370 }
00371 
00372 QDate CalendarView::activeDate( bool fallbackToToday )
00373 {
00374   KOrg::BaseView *curView = mViewManager->currentView();
00375   if ( curView ) {
00376     if ( curView->selectionStart().isValid() ) {
00377       return curView->selectionStart().date();
00378     }
00379 
00380     // Try the view's selectedDates()
00381     if ( !curView->selectedIncidenceDates().isEmpty() ) {
00382       if ( curView->selectedIncidenceDates().first().isValid() ) {
00383         return curView->selectedIncidenceDates().first();
00384       }
00385     }
00386   }
00387 
00388   // When all else fails, use the navigator start date, or today.
00389   if ( fallbackToToday ) {
00390     return QDate::currentDate();
00391   } else {
00392     return mDateNavigator->selectedDates().first();
00393   }
00394 }
00395 
00396 QDate CalendarView::activeIncidenceDate()
00397 {
00398   KOrg::BaseView *curView = mViewManager->currentView();
00399   if ( curView ) {
00400     DateList dates = curView->selectedIncidenceDates();
00401     if ( !dates.isEmpty() ) {
00402       return dates.first();
00403     }
00404   }
00405 
00406   return QDate();
00407 }
00408 
00409 QDate CalendarView::startDate()
00410 {
00411   DateList dates = mDateNavigator->selectedDates();
00412 
00413   return dates.first();
00414 }
00415 
00416 QDate CalendarView::endDate()
00417 {
00418   DateList dates = mDateNavigator->selectedDates();
00419 
00420   return dates.last();
00421 }
00422 
00423 
00424 bool CalendarView::openCalendar(const QString& filename, bool merge)
00425 {
00426   kdDebug(5850) << "CalendarView::openCalendar(): " << filename << endl;
00427 
00428   if (filename.isEmpty()) {
00429     kdDebug(5850) << "CalendarView::openCalendar(): Error! Empty filename." << endl;
00430     return false;
00431   }
00432 
00433   if (!QFile::exists(filename)) {
00434     kdDebug(5850) << "CalendarView::openCalendar(): Error! File '" << filename
00435               << "' doesn't exist." << endl;
00436   }
00437 
00438   bool loadedSuccesfully = true;
00439   if ( !merge ) {
00440     mCalendar->close();
00441     CalendarLocal *cl = dynamic_cast<CalendarLocal*>( mCalendar );
00442     if ( cl ) {
00443       loadedSuccesfully = cl->load( filename );
00444     } else {
00445       CalendarResources *cr = dynamic_cast<CalendarResources*>( mCalendar );
00446       assert( cr ); // otherwise something is majorly wrong
00447       // openCalendar called without merge and a filename, what should we do?
00448       return false;
00449     }
00450   } else {
00451     // merge in a file
00452     CalendarResources *cl = dynamic_cast<CalendarResources *>( mCalendar );
00453     if ( cl && !cl->hasCalendarResources() ) {
00454       KMessageBox::sorry(
00455         this,
00456         i18n( "No calendars found, unable to merge the file into your calendar." ) );
00457       return false;
00458     }
00459     // FIXME: This is a nasty hack, since we need to set a parent for the
00460     //        resource selection dialog. However, we don't have any UI methods
00461     //        in the calendar, only in the CalendarResources::DestinationPolicy
00462     //        So we need to type-cast it and extract it from the CalendarResources
00463     QWidget *tmpparent = 0;
00464     if ( cl ) {
00465       tmpparent = cl->dialogParentWidget();
00466       cl->setDialogParentWidget( this );
00467     }
00468 
00469     FileStorage storage( mCalendar );
00470     storage.setFileName( filename );
00471     loadedSuccesfully = storage.load();
00472   }
00473 
00474   if ( loadedSuccesfully ) {
00475     if ( merge )
00476       setModified( true );
00477     else {
00478       setModified( false );
00479       mViewManager->setDocumentId( filename );
00480       mTodoList->setDocumentId( filename );
00481     }
00482     updateCategories();
00483     updateView();
00484     return true;
00485   } else {
00486     // while failing to load, the calendar object could
00487     // have become partially populated.  Clear it out.
00488     if ( !merge ) mCalendar->close();
00489 
00490     KMessageBox::error(this,i18n("Could not load calendar '%1'.").arg(filename));
00491 
00492     return false;
00493   }
00494 }
00495 
00496 bool CalendarView::saveCalendar( const QString& filename )
00497 {
00498   kdDebug(5850) << "CalendarView::saveCalendar(): " << filename << endl;
00499 
00500   // Store back all unsaved data into calendar object
00501   mViewManager->currentView()->flushView();
00502 
00503   FileStorage storage( mCalendar );
00504   storage.setFileName( filename );
00505   storage.setSaveFormat( new ICalFormat );
00506 
00507   bool success = storage.save();
00508 
00509   if ( !success ) {
00510     return false;
00511   }
00512 
00513   return true;
00514 }
00515 
00516 void CalendarView::closeCalendar()
00517 {
00518   kdDebug(5850) << "CalendarView::closeCalendar()" << endl;
00519 
00520   // child windows no longer valid
00521   emit closingDown();
00522 
00523   mCalendar->close();
00524   setModified( false );
00525   updateView();
00526 }
00527 
00528 void CalendarView::archiveCalendar()
00529 {
00530   mDialogManager->showArchiveDialog();
00531 }
00532 
00533 
00534 void CalendarView::readSettings()
00535 {
00536 //  kdDebug(5850) << "CalendarView::readSettings()" << endl;
00537 
00538   QString str;
00539 
00540   // read settings from the KConfig, supplying reasonable
00541   // defaults where none are to be found
00542 
00543   KConfig *config = KOGlobals::self()->config();
00544 
00545 #ifndef KORG_NOSPLITTER
00546   config->setGroup( "KOrganizer Geometry" );
00547 
00548   QValueList<int> sizes = config->readIntListEntry( "Separator1" );
00549   if ( sizes.count() != 2 ) {
00550     sizes << mDateNavigatorContainer->minimumSizeHint().width();
00551     sizes << 300;
00552   }
00553   mPanner->setSizes( sizes );
00554 
00555   sizes = config->readIntListEntry( "Separator2" );
00556   mLeftSplitter->setSizes( sizes );
00557 #endif
00558 
00559   mEventViewer->readSettings( config );
00560 
00561   mViewManager->readSettings( config );
00562   mTodoList->restoreLayout( config, QString( "Todo Layout" ) );
00563 
00564   readFilterSettings( config );
00565 
00566   config->setGroup( "Views" );
00567   const int dateCount = config->readNumEntry( "ShownDatesCount", 7 );
00568   if ( dateCount == 7 ) {
00569     mDateNavigator->selectWeek();
00570   } else {
00571     mDateNavigator->selectDates( mDateNavigator->selectedDates().first(), dateCount );
00572   }
00573 }
00574 
00575 
00576 void CalendarView::writeSettings()
00577 {
00578 //  kdDebug(5850) << "CalendarView::writeSettings" << endl;
00579 
00580   KConfig *config = KOGlobals::self()->config();
00581 
00582 #ifndef KORG_NOSPLITTER
00583   config->setGroup( "KOrganizer Geometry" );
00584 
00585   QValueList<int> list = mPanner->sizes();
00586   config->writeEntry( "Separator1", list );
00587 
00588   list = mLeftSplitter->sizes();
00589   config->writeEntry( "Separator2", list );
00590 #endif
00591   mEventViewer->writeSettings( config );
00592   mViewManager->writeSettings( config );
00593   mTodoList->saveLayout( config, QString( "Todo Layout" ) );
00594 
00595   KOPrefs::instance()->writeConfig();
00596 
00597   writeFilterSettings( config );
00598 
00599   config->setGroup( "Views" );
00600   config->writeEntry( "ShownDatesCount", mDateNavigator->selectedDates().count() );
00601 
00602   config->sync();
00603 }
00604 
00605 void CalendarView::readFilterSettings( KConfig *config )
00606 {
00607 //  kdDebug(5850) << "CalendarView::readFilterSettings()" << endl;
00608 
00609   mFilters.clear();
00610 
00611   config->setGroup( "General" );
00612   // FIXME: Move the filter loading and saving to the CalFilter class in libkcal
00613   QStringList filterList = config->readListEntry ("CalendarFilters" );
00614   QString currentFilter = config->readEntry( "Current Filter" );
00615 
00616   QStringList::ConstIterator it = filterList.begin();
00617   QStringList::ConstIterator end = filterList.end();
00618   while( it != end ) {
00619 //    kdDebug(5850) << "  filter: " << (*it) << endl;
00620     CalFilter *filter;
00621     filter = new CalFilter( *it );
00622     config->setGroup( "Filter_" + (*it) );
00623     filter->setCriteria( config->readNumEntry( "Criteria", 0 ) );
00624     filter->setCategoryList( config->readListEntry( "CategoryList" ) );
00625     if ( filter->criteria() & KCal::CalFilter::HideTodosWithoutAttendeeInEmailList )
00626       filter->setEmailList( KOPrefs::instance()->allEmails() );
00627     filter->setCompletedTimeSpan( config->readNumEntry( "HideTodoDays", 0 ) );
00628     mFilters.append( filter );
00629 
00630     ++it;
00631   }
00632 
00633   config->setGroup( "General" );
00634   int pos = filterList.findIndex( currentFilter );
00635   mCurrentFilter = 0;
00636   if ( pos>=0 ) {
00637     mCurrentFilter = mFilters.at( pos );
00638   }
00639   updateFilter();
00640 }
00641 
00642 void CalendarView::writeFilterSettings( KConfig *config )
00643 {
00644 //  kdDebug(5850) << "CalendarView::writeFilterSettings()" << endl;
00645 
00646   QStringList filterList;
00647 
00648   CalFilter *filter = mFilters.first();
00649   while( filter ) {
00650 //    kdDebug(5850) << " fn: " << filter->name() << endl;
00651     filterList << filter->name();
00652     config->setGroup( "Filter_" + filter->name() );
00653     config->writeEntry( "Criteria", filter->criteria() );
00654     config->writeEntry( "CategoryList", filter->categoryList() );
00655     config->writeEntry( "HideTodoDays", filter->completedTimeSpan() );
00656     filter = mFilters.next();
00657   }
00658   config->setGroup( "General" );
00659   config->writeEntry( "CalendarFilters", filterList );
00660   if ( mCurrentFilter ) {
00661     config->writeEntry( "Current Filter", mCurrentFilter->name() );
00662   } else {
00663     config->writeEntry( "Current Filter", QString::null );
00664   }
00665 }
00666 
00667 
00668 void CalendarView::goDate( const QDate &date )
00669 {
00670   mDateNavigator->selectDate( date );
00671 }
00672 
00673 void CalendarView::showDate( const QDate &date )
00674 {
00675   int dateCount = mDateNavigator->datesCount();
00676   if ( dateCount == 7 ) {
00677     mDateNavigator->selectWeek( date );
00678   } else {
00679     mDateNavigator->selectDates( date, dateCount );
00680   }
00681 }
00682 
00683 void CalendarView::goToday()
00684 {
00685   mDateNavigator->selectToday();
00686 }
00687 
00688 void CalendarView::goNext()
00689 {
00690   if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) ) {
00691     mDateNavigator->selectNextMonth();
00692   } else {
00693     mDateNavigator->selectNext();
00694   }
00695 }
00696 
00697 void CalendarView::goPrevious()
00698 {
00699   if ( dynamic_cast<KOMonthView*>( mViewManager->currentView() ) ) {
00700     mDateNavigator->selectPreviousMonth();
00701   } else {
00702     mDateNavigator->selectPrevious();
00703   }
00704 }
00705 
00706 void CalendarView::updateConfig( const QCString& receiver)
00707 {
00708   if ( receiver != "korganizer" ) return;
00709   kdDebug(5850) << "CalendarView::updateConfig()" << endl;
00710 
00711   KOGlobals::self()->
00712     setHolidays( new KHolidays( KOPrefs::instance()->mHolidays ) );
00713 
00714   QString tz(  mCalendar->timeZoneId() );
00715   // Only set a new time zone if it changed. This prevents the window
00716   // from being modified on start
00717   if ( tz != KOPrefs::instance()->mTimeZoneId ) {
00718 
00719     const QString question( i18n("The timezone setting was changed. Do you want to keep the absolute time of "
00720                                 "the items in your calendar, which will show them to be at a different time than "
00721                                 "before, or move them to be at the old time also in the new timezone?") );
00722     int rc = KMessageBox::questionYesNo( this, question,
00723                               i18n("Keep Absolute Times?"),
00724                               KGuiItem(i18n("Keep Times")),
00725                               KGuiItem(i18n("Move Times")),
00726                               "calendarKeepAbsoluteTimes");
00727     if ( rc == KMessageBox::Yes ) {
00728       // user wants us to shift
00729       mCalendar->setTimeZoneIdViewOnly( KOPrefs::instance()->mTimeZoneId );
00730     } else {
00731       // only set the new timezone, wihtout shifting events, they will be
00732       // interpreted as being in the new timezone now
00733       mCalendar->setTimeZoneId( KOPrefs::instance()->mTimeZoneId );
00734     }
00735   }
00736   emit configChanged();
00737 
00738   //switch beetween merged, side by side and tabbed agenda if needed
00739   mViewManager->updateMultiCalendarDisplay();
00740 
00741   // To make the "fill window" configurations work
00742   mViewManager->raiseCurrentView();
00743 }
00744 
00745 
00746 void CalendarView::incidenceAdded( Incidence *incidence )
00747 {
00748   setModified( true );
00749   history()->recordAdd( incidence );
00750   changeIncidenceDisplay( incidence, KOGlobals::INCIDENCEADDED );
00751   updateUnmanagedViews();
00752   checkForFilteredChange( incidence );
00753 }
00754 
00755 void CalendarView::incidenceChanged( Incidence *oldIncidence,
00756                                      Incidence *newIncidence,
00757                                      KOGlobals::WhatChanged modification )
00758 {
00759   KOIncidenceEditor *tmp = editorDialog( newIncidence );
00760   if ( tmp ) {
00761     kdDebug(5850) << "Incidence modified and open" << endl;
00762     tmp->modified();
00763   }
00764   setModified( true );
00765   history()->recordEdit( oldIncidence, newIncidence );
00766 
00767   // Record completed todos in journals, if enabled. we should to this here in
00768   // favour of the todolist. users can mark a task as completed in an editor
00769   // as well.
00770   if ( newIncidence->type() == "Todo" &&
00771        KOPrefs::instance()->recordTodosInJournals() &&
00772        ( modification == KOGlobals::COMPLETION_MODIFIED ||
00773          modification == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) ) {
00774 
00775       Todo *todo = static_cast<Todo *>(newIncidence);
00776       if ( todo->isCompleted() ||
00777            modification == KOGlobals::COMPLETION_MODIFIED_WITH_RECURRENCE ) {
00778         QString timeStr = KGlobal::locale()->formatTime( QTime::currentTime() );
00779         QString description = i18n( "To-do completed: %1 (%2)" ).arg(
00780           newIncidence->summary() ).arg( timeStr );
00781 
00782         Journal::List journals = calendar()->journals( QDate::currentDate() );
00783         Journal *journal;
00784 
00785         if ( journals.isEmpty() ) {
00786           journal = new Journal();
00787           journal->setDtStart( QDateTime::currentDateTime() );
00788 
00789           QString dateStr = KGlobal::locale()->formatDate( QDate::currentDate() );
00790           journal->setSummary( i18n("Journal of %1").arg( dateStr ) );
00791           journal->setDescription( description );
00792 
00793           //TODO: recorded to-dos should save into the standard resource always
00794           if ( !mChanger->addIncidence( journal, 0, QString(), this ) ) {
00795             KODialogManager::errorSaveIncidence( this, journal );
00796             delete journal;
00797             return;
00798           }
00799 
00800         } else { // journal list is not empty
00801           journal = *(journals.at(0));
00802           Journal *oldJournal = journal->clone();
00803           journal->setDescription( journal->description().append( "\n" + description ) );
00804 
00805           if ( !mChanger->changeIncidence( oldJournal, journal,
00806                                            KOGlobals::DESCRIPTION_MODIFIED, this ) ) {
00807             KODialogManager::errorSaveIncidence( this, journal );
00808             delete journal;
00809             return;
00810           }
00811         }
00812       }
00813   }
00814 
00815   changeIncidenceDisplay( newIncidence, KOGlobals::INCIDENCEEDITED );
00816   updateUnmanagedViews();
00817   checkForFilteredChange( newIncidence );
00818 }
00819 
00820 void CalendarView::incidenceToBeDeleted( Incidence *incidence )
00821 {
00822   KOIncidenceEditor *tmp = editorDialog( incidence );
00823   if (tmp) {
00824     kdDebug(5850) << "Incidence to be deleted and open in editor" << endl;
00825     tmp->delayedDestruct();
00826   }
00827   setModified( true );
00828   history()->recordDelete( incidence );
00829 //  changeIncidenceDisplay( incidence, KOGlobals::INCIDENCEDELETED );
00830   updateUnmanagedViews();
00831 }
00832 
00833 void CalendarView::incidenceDeleted( Incidence *incidence )
00834 {
00835   changeIncidenceDisplay( incidence, KOGlobals::INCIDENCEDELETED );
00836   updateUnmanagedViews();
00837 }
00838 
00839 void CalendarView::checkForFilteredChange( Incidence *incidence )
00840 {
00841   CalFilter *filter = calendar()->filter();
00842   if ( filter && !filter->filterIncidence( incidence ) ) {
00843     // Incidence is filtered and thus not shown in the view, tell the
00844     // user so that he isn't surprised if his new event doesn't show up
00845     KMessageBox::information( this, i18n("The item \"%1\" is filtered by "
00846                  "your current filter rules, so it will be hidden and not "
00847                  "appear in the view.").arg( incidence->summary() ),
00848                  i18n("Filter Applied"), "ChangedIncidenceFiltered" );
00849   }
00850 }
00851 
00852 void CalendarView::startMultiModify( const QString &text )
00853 {
00854   history()->startMultiModify( text );
00855 }
00856 
00857 void CalendarView::endMultiModify()
00858 {
00859   history()->endMultiModify();
00860 }
00861 
00862 
00863 void CalendarView::changeIncidenceDisplay( Incidence *incidence, int action )
00864 {
00865   mDateNavigatorContainer->updateView();
00866   mDialogManager->updateSearchDialog();
00867 
00868   if ( incidence ) {
00869     // If there is an event view visible update the display
00870     mViewManager->currentView()->changeIncidenceDisplay( incidence, action );
00871     if ( mTodoList ) mTodoList->changeIncidenceDisplay( incidence, action );
00872     mEventViewer->changeIncidenceDisplay( incidence, activeDate( true ), action );
00873   } else {
00874     mViewManager->currentView()->updateView();
00875     if ( mTodoList ) mTodoList->updateView();
00876   }
00877 }
00878 
00879 
00880 void CalendarView::updateView(const QDate &start, const QDate &end)
00881 {
00882   mTodoList->updateView();
00883   mViewManager->updateView(start, end);
00884   mDateNavigatorContainer->updateView();
00885 }
00886 
00887 void CalendarView::updateView()
00888 {
00889   DateList tmpList = mDateNavigator->selectedDates();
00890 
00891   // We assume that the navigator only selects consecutive days.
00892   updateView( tmpList.first(), tmpList.last() );
00893 }
00894 
00895 void CalendarView::updateUnmanagedViews()
00896 {
00897   mDateNavigatorContainer->updateDayMatrix();
00898 }
00899 
00900 int CalendarView::msgItemDelete( Incidence *incidence )
00901 {
00902   return KMessageBox::warningContinueCancel(this,
00903       i18n("The item \"%1\" will be permanently deleted.").arg( incidence->summary() ),
00904       i18n("KOrganizer Confirmation"), KGuiItem(i18n("&Delete"),"editdelete"));
00905 }
00906 
00907 
00908 void CalendarView::edit_cut()
00909 {
00910   Incidence *incidence = incToSendToClipboard( true );
00911 
00912   if ( !incidence || !mChanger ) {
00913     KNotifyClient::beep();
00914     return;
00915   }
00916 
00917   Incidence::List incidences;
00918   int km = KMessageBox::Yes;
00919 
00920   if ( !incidence->relations().isEmpty() &&
00921        incidence->type() == "Todo" ) { // Only todos (yet?)
00922     km = KMessageBox::questionYesNoCancel( this,
00923                                            i18n("The item \"%1\" has sub-to-dos. "
00924                                                 "Do you want to cut just this item and "
00925                                                 "make all its sub-to-dos independent, or "
00926                                                 "cut the to-do with all its sub-to-dos?"
00927                                              ).arg( incidence->summary() ),
00928                                            i18n("KOrganizer Confirmation"),
00929                                            i18n("Cut Only This"),
00930                                            i18n("Cut All"));
00931   }
00932 
00933   if ( km == KMessageBox::Yes ) { // only one
00934     incidences.append( incidence );
00935     makeChildrenIndependent( incidence );
00936   } else if ( km == KMessageBox::No ) { // all
00937     // load incidence + children + grandchildren...
00938     getIncidenceHierarchy( incidence, incidences );
00939   }
00940 
00941   if ( km != KMessageBox::Cancel ) {
00942     mChanger->cutIncidences( incidences, this );
00943   }
00944 }
00945 
00946 void CalendarView::edit_copy()
00947 {
00948   Incidence *incidence = incToSendToClipboard( false );
00949 
00950   if ( !incidence ) {
00951     KNotifyClient::beep();
00952     return;
00953   }
00954 
00955   Incidence::List incidences;
00956   int km = KMessageBox::Yes;
00957 
00958   if ( !incidence->relations().isEmpty() &&
00959        incidence->type() == "Todo" ) { // only todos.
00960     km = KMessageBox::questionYesNoCancel( this,
00961                                            i18n("The item \"%1\" has sub-to-dos. "
00962                                                 "Do you want to copy just this item or "
00963                                                 "copy the to-do with all its sub-to-dos?"
00964                                              ).arg( incidence->summary() ),
00965                                            i18n("KOrganizer Confirmation"),
00966                                            i18n("Copy Only This"),
00967                                            i18n("Copy All"));
00968   }
00969 
00970   if ( km == KMessageBox::Yes ) { // only one
00971     incidences.append( incidence );
00972   } else if ( km == KMessageBox::No ) { // all
00973     // load incidence + children + grandchildren...
00974     getIncidenceHierarchy( incidence, incidences );
00975   }
00976 
00977   if ( km != KMessageBox::Cancel ) {
00978     DndFactory factory( mCalendar );
00979     if ( !factory.copyIncidences( incidences ) ) {
00980       KNotifyClient::beep();
00981     }
00982   }
00983 }
00984 
00985 Incidence* CalendarView::incToSendToClipboard( bool cut )
00986 {
00987   Incidence *originalInc = selectedIncidence();
00988 
00989   if ( originalInc && originalInc->doesRecur() &&
00990        originalInc->type() == "Event" ) { // temporary, until recurring to-dos are fixed
00991 
00992     Incidence *inc;
00993     KOGlobals::WhichOccurrences chosenOption;
00994     if ( cut ) {
00995       inc = singleOccurrenceOrAll( originalInc, KOGlobals::CUT, chosenOption, QDate(), true );
00996     } else {
00997       // The user is copying, the original incidence can't be changed
00998       // we can only dissociate a copy
00999       Incidence *originalIncSaved = originalInc->clone();
01000       inc = singleOccurrenceOrAll( originalIncSaved, KOGlobals::COPY, chosenOption, QDate(), false );
01001 
01002       // no dissociation, no need to leak our clone
01003       if ( chosenOption == KOGlobals::ALL ) {
01004         inc = originalInc;
01005         delete originalIncSaved;
01006       }
01007 
01008       // no need to leak our clone
01009       if ( chosenOption == KOGlobals::NONE ) {
01010         delete originalIncSaved;
01011       }
01012     }
01013 
01014     return inc;
01015   } else {
01016     return originalInc;
01017   }
01018 }
01019 
01020 void CalendarView::edit_paste()
01021 {
01022 // If in agenda and month view, use the selected time and date from there.
01023 // In all other cases, use the navigator's selected date.
01024 
01025   QDate date;          // null dates are invalid, that's what we want
01026   bool timeSet = false;// flag denoting if the time has been set.
01027   QTime time;          // null dates are valid, so rely on the timeSet flag
01028   QDateTime endDT;     // null datetimes are invalid, that's what we want
01029   bool useEndTime = false;
01030 
01031   KOrg::BaseView *curView = mViewManager->currentView();
01032   if ( !curView ) {
01033     return;
01034   }
01035 
01036   KOAgendaView *aView = mViewManager->agendaView();
01037   KOMonthView *mView = mViewManager->monthView();
01038   if ( curView == mViewManager->multiAgendaView() ) {
01039     aView = mViewManager->multiAgendaView()->selectedAgendaView();
01040     curView = aView;
01041   }
01042 
01043   if ( curView == aView && aView->selectionStart().isValid() ) {
01044     date = aView->selectionStart().date();
01045     endDT = aView->selectionEnd();
01046     useEndTime = !aView->selectedIsSingleCell();
01047     if ( !aView->selectedIsAllDay() ) {
01048       time = aView->selectionStart().time();
01049       timeSet = true;
01050     }
01051   } else if ( curView == mView && mView->selectionStart().isValid() ) {
01052     date = mView->selectionStart().date();
01053   } else if ( !mDateNavigator->selectedDates().isEmpty() &&
01054               curView->supportsDateNavigation() ) {
01055     // default to the selected date from the navigator
01056     date = mDateNavigator->selectedDates().first();
01057   }
01058 
01059   if ( !date.isValid() && curView->supportsDateNavigation() ) {
01060     KMessageBox::sorry(
01061       this,
01062       i18n( "Paste failed: unable to determine a valid target date." ) );
01063     return;
01064   }
01065 
01066   DndFactory factory( mCalendar );
01067   Incidence::List pastedIncidences;
01068   if ( timeSet && time.isValid() ) {
01069     pastedIncidences = factory.pasteIncidences( date, &time );
01070   } else {
01071     pastedIncidences = factory.pasteIncidences( date );
01072   }
01073 
01074   Incidence::List::Iterator it;
01075   for ( it = pastedIncidences.begin(); it != pastedIncidences.end(); ++it ) {
01076     QPair<ResourceCalendar *, QString>p = viewSubResourceCalendar();
01077 
01078     // FIXME: use a visitor here
01079     if ( ( *it )->type() == "Event" ) {
01080       Event *pastedEvent = static_cast<Event*>( *it );
01081       // only use selected area if event is of the same type
01082       // (all-day or non-all-day) as the current selection is
01083       if ( aView && endDT.isValid() && useEndTime ) {
01084         if ( ( pastedEvent->doesFloat() && aView->selectedIsAllDay() ) ||
01085              ( !pastedEvent->doesFloat() && !aView->selectedIsAllDay() ) ) {
01086           pastedEvent->setDtEnd( endDT );
01087         }
01088       }
01089 
01090       // KCal supports events with relations, but korganizer doesn't
01091       // so unset it. It can even come from other application.
01092       pastedEvent->setRelatedTo( 0 );
01093       pastedEvent->setRelatedToUid( QString() );
01094 
01095       mChanger->addIncidence( pastedEvent, p.first, p.second, this );
01096 
01097     } else if ( ( *it )->type() == "Todo" ) {
01098       Todo *pastedTodo = static_cast<Todo*>( *it );
01099       Todo *_selectedTodo = selectedTodo();
01100 
01101       // if we are cutting a hierarchy only the root
01102       // should be son of _selectedTodo
01103       if ( _selectedTodo && !pastedTodo->relatedTo() ) {
01104         pastedTodo->setRelatedTo( _selectedTodo );
01105       }
01106       mChanger->addIncidence( pastedTodo, p.first, p.second, this );
01107     }
01108   }
01109 }
01110 
01111 void CalendarView::edit_options()
01112 {
01113   mDialogManager->showOptionsDialog();
01114 }
01115 
01116 void CalendarView::dateTimesForNewEvent( QDateTime &startDt, QDateTime &endDt, bool &allDay )
01117 {
01118   mViewManager->currentView()->eventDurationHint( startDt, endDt, allDay );
01119 
01120   if ( !startDt.isValid() || !endDt.isValid() ) {
01121     startDt.setDate( activeDate( true ) );
01122     startDt.setTime( KOPrefs::instance()->mStartTime.time() );
01123 
01124     int addSecs = ( KOPrefs::instance()->mDefaultDuration.time().hour() * 3600 ) +
01125                   ( KOPrefs::instance()->mDefaultDuration.time().minute() * 60 );
01126 
01127     endDt = startDt.addSecs( addSecs );
01128   }
01129 }
01130 
01131 KOEventEditor *CalendarView::newEventEditor( ResourceCalendar *res, const QString &subRes,
01132                                              const QDateTime &startDtParam,
01133                                              const QDateTime &endDtParam, bool allDayParam )
01134 {
01135   // let the current view change the default start/end datetime
01136   bool allDay = allDayParam;
01137   QDateTime startDt( startDtParam ), endDt( endDtParam );
01138   // Adjust the start/end date times (i.e. replace invalid values by defaults,
01139   // and let the view adjust the type.
01140   dateTimesForNewEvent( startDt, endDt, allDay );
01141 
01142   KOEventEditor *eventEditor = mDialogManager->getEventEditor();
01143   eventEditor->newEvent();
01144   connectIncidenceEditor( eventEditor );
01145   eventEditor->setResource( res, subRes );
01146   eventEditor->setDates( startDt, endDt, allDay );
01147   mDialogManager->connectTypeAhead( eventEditor, dynamic_cast<KOrg::AgendaView*>(viewManager()->currentView()) );
01148   return eventEditor;
01149 }
01150 
01151 void CalendarView::newEvent()
01152 {
01153   KOrg::BaseView *currentView = mViewManager->currentView();
01154   if ( currentView == mViewManager->multiAgendaView() ) {
01155     currentView = mViewManager->multiAgendaView()->selectedAgendaView();
01156   }
01157 
01158   newEvent( currentView->resourceCalendar(),
01159             currentView->subResourceCalendar() );
01160 }
01161 
01162 void CalendarView::newEvent( ResourceCalendar *res, const QString &subRes )
01163 {
01164   kdDebug(5850) << "CalendarView::newEvent()" << endl;
01165   newEvent( res, subRes, QDateTime(), QDateTime() );
01166 }
01167 
01168 void CalendarView::newEvent( ResourceCalendar *res, const QString &subRes,
01169                              const QDate &dt )
01170 {
01171   QDateTime startDt( dt, KOPrefs::instance()->mStartTime.time() );
01172   newEvent( res, subRes, QDateTime( dt ), QDateTime() );
01173 }
01174 
01175 void CalendarView::newEvent( ResourceCalendar *res, const QString &subRes,
01176                              const QDateTime &startDt )
01177 {
01178   newEvent( res, subRes, startDt, QDateTime() );
01179 }
01180 
01181 void CalendarView::newEvent( ResourceCalendar *res, const QString &subRes,
01182                              const QDateTime &startDt, const QDateTime &endDt,
01183                              bool allDay )
01184 {
01185   KOEventEditor *eventEditor = newEventEditor( res, subRes,
01186                                                startDt, endDt, allDay );
01187   eventEditor->show();
01188 }
01189 
01190 void CalendarView::newEvent( ResourceCalendar *res, const QString &subRes,
01191                              const QString &summary, const QString &description,
01192                              const QStringList &attachments, const QStringList &attendees,
01193                              const QStringList &attachmentMimetypes, bool inlineAttachment )
01194 {
01195   KOEventEditor *eventEditor = newEventEditor( res, subRes );
01196   eventEditor->setTexts( summary, description );
01197   // if attach or attendee list is empty, these methods don't do anything, so
01198   // it's safe to call them in every case
01199   eventEditor->addAttachments( attachments, attachmentMimetypes, inlineAttachment );
01200   eventEditor->addAttendees( attendees );
01201   eventEditor->show();
01202 }
01203 
01204 void CalendarView::newTodo( ResourceCalendar *res, const QString &subRes,
01205                             const QString &summary, const QString &description,
01206                             const QStringList &attachments, const QStringList &attendees,
01207                             const QStringList &attachmentMimetypes,
01208                             bool inlineAttachment, bool isTask )
01209 {
01210   kdDebug(5850) << k_funcinfo << endl;
01211   KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
01212   connectIncidenceEditor( todoEditor );
01213   todoEditor->newTodo();
01214   todoEditor->setResource( res, subRes );
01215   todoEditor->setTexts( summary, description );
01216   todoEditor->addAttachments( attachments, attachmentMimetypes, inlineAttachment );
01217   todoEditor->addAttendees( attendees );
01218   todoEditor->selectCreateTask( isTask );
01219   todoEditor->show();
01220 }
01221 
01222 void CalendarView::newTodo()
01223 {
01224   KOrg::BaseView *currentView = mViewManager->currentView();
01225   if ( currentView == mViewManager->multiAgendaView() ) {
01226     currentView = mViewManager->multiAgendaView()->selectedAgendaView();
01227   }
01228 
01229   newTodo( currentView->resourceCalendar(),
01230            currentView->subResourceCalendar() );
01231 }
01232 
01233 void CalendarView::newTodo( ResourceCalendar *res, const QString &subRes )
01234 {
01235   kdDebug(5850) << k_funcinfo << endl;
01236   QDateTime dtDue;
01237   bool allday = true;
01238   KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
01239   connectIncidenceEditor( todoEditor );
01240   todoEditor->newTodo();
01241   todoEditor->setResource( res, subRes );
01242   if ( mViewManager->currentView()->isEventView() ) {
01243     dtDue.setDate( mDateNavigator->selectedDates().first() );
01244     QDateTime dtDummy = QDateTime::currentDateTime();
01245     mViewManager->currentView()->eventDurationHint( dtDue, dtDummy, allday );
01246     todoEditor->setDates( dtDue, allday );
01247   }
01248   todoEditor->show();
01249 }
01250 
01251 void CalendarView::newTodo( ResourceCalendar *res, const QString &subRes,
01252                             const QDate &date )
01253 {
01254   KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
01255   connectIncidenceEditor( todoEditor );
01256   todoEditor->newTodo();
01257   todoEditor->setResource( res, subRes );
01258   todoEditor->setDates( QDateTime( date, QTime::currentTime() ), true );
01259   todoEditor->show();
01260 }
01261 
01262 void CalendarView::newJournal()
01263 {
01264   KOrg::BaseView *currentView = mViewManager->currentView();
01265   if ( currentView == mViewManager->multiAgendaView() ) {
01266     currentView = mViewManager->multiAgendaView()->selectedAgendaView();
01267   }
01268 
01269   newJournal( currentView->resourceCalendar(),
01270               currentView->subResourceCalendar() );
01271 }
01272 
01273 void CalendarView::newJournal( ResourceCalendar *res, const QString &subRes )
01274 {
01275   kdDebug(5850) << "CalendarView::newJournal()" << endl;
01276   newJournal( res, subRes, QString::null, QDate() );
01277 }
01278 
01279 void CalendarView::newJournal( ResourceCalendar *res, const QString &subRes,
01280                                const QDate &date)
01281 {
01282   newJournal( res, subRes, QString::null, date );
01283 }
01284 
01285 void CalendarView::newJournal( ResourceCalendar *res, const QString &subRes,
01286                                const QString &text, const QDate &date )
01287 {
01288   KOJournalEditor *journalEditor = mDialogManager->getJournalEditor();
01289   connectIncidenceEditor( journalEditor );
01290   journalEditor->newJournal();
01291   journalEditor->setResource( res, subRes );
01292   journalEditor->setTexts( text );
01293   if ( !date.isValid() ) {
01294     journalEditor->setDate( mDateNavigator->selectedDates().first() );
01295   } else {
01296     journalEditor->setDate( date );
01297   }
01298   journalEditor->show();
01299 }
01300 
01301 void CalendarView::newSubTodo()
01302 {
01303   Todo *todo = selectedTodo();
01304   if ( todo ) newSubTodo( todo );
01305 }
01306 
01307 void CalendarView::newSubTodo(Todo *parentEvent)
01308 {
01309   KOTodoEditor *todoEditor = mDialogManager->getTodoEditor();
01310   connectIncidenceEditor( todoEditor );
01311   todoEditor->newTodo();
01312   todoEditor->setDates( QDateTime(), false, parentEvent );
01313   todoEditor->show();
01314 }
01315 
01316 bool CalendarView::addIncidence( const QString &ical )
01317 {
01318   kdDebug(5850) << "CalendarView::addIncidence:\n" << ical << endl;
01319   ICalFormat format;
01320   format.setTimeZone( mCalendar->timeZoneId(), true );
01321   Incidence *incidence = format.fromString( ical );
01322   if ( !incidence ) return false;
01323   if ( !mChanger->addIncidence( incidence, 0, QString(), this ) ) {
01324     delete incidence;
01325     return false;
01326   }
01327   return true;
01328 }
01329 
01330 void CalendarView::appointment_show()
01331 {
01332   Incidence *incidence = selectedIncidence();
01333   if ( incidence ) {
01334     showIncidence( incidence, activeIncidenceDate() );
01335   } else {
01336     KNotifyClient::beep();
01337   }
01338 }
01339 
01340 void CalendarView::appointment_edit()
01341 {
01342   Incidence *incidence = selectedIncidence();
01343   if ( incidence ) {
01344     editIncidence( incidence, activeIncidenceDate() );
01345   } else {
01346     KNotifyClient::beep();
01347   }
01348 }
01349 
01350 void CalendarView::appointment_delete()
01351 {
01352   Incidence *incidence = selectedIncidence();
01353   if (incidence)
01354     deleteIncidence( incidence );
01355   else
01356     KNotifyClient::beep();
01357 }
01358 
01359 void CalendarView::todo_unsub()
01360 {
01361   Todo *anTodo = selectedTodo();
01362   if( incidence_unsub ( anTodo ) ) {
01363     updateView();
01364   }
01365 }
01366 
01367 bool CalendarView::incidence_unsub( Incidence *inc )
01368 {
01369   bool status = false;
01370   if ( !inc || !inc->relatedTo() ) {
01371     return false;
01372   }
01373 
01374   if ( mChanger->beginChange( inc, 0, QString() ) ) {
01375       Incidence *oldInc = inc->clone();
01376       inc->setRelatedTo( 0 );
01377       mChanger->changeIncidence( oldInc, inc, KOGlobals::RELATION_MODIFIED, this );
01378       mChanger->endChange( inc, 0, QString() );
01379       delete oldInc;
01380       setModified(true);
01381       status = true;
01382   }
01383   if ( ! status ) {
01384     KMessageBox::sorry( this, i18n("Unable to turn sub-to-do into a top-level "
01385         "to-do, because it cannot be locked.") );
01386   }
01387 
01388   return status;
01389 }
01390 
01391 bool CalendarView::makeSubTodosIndependent ( )
01392 {
01393   bool  status = false;
01394   Todo *aTodo = selectedTodo();
01395 
01396   if ( makeChildrenIndependent( aTodo ) ) {
01397     updateView();
01398     status = true;
01399   }
01400   return status;
01401 }
01402 
01403 bool CalendarView::makeChildrenIndependent ( Incidence *inc )
01404 {
01405   if ( !inc || inc->relations().isEmpty() ) {
01406     return false;
01407   }
01408 
01409   startMultiModify ( i18n( "Make sub-to-dos independent" ) );
01410   Incidence::List subIncs( inc->relations() );
01411   Incidence::List::Iterator it;
01412 
01413   for ( it= subIncs.begin(); it != subIncs.end(); ++it ) {
01414     incidence_unsub ( *it );
01415   }
01416   endMultiModify();
01417   return true;
01418 }
01419 
01420 bool CalendarView::deleteIncidence( const QString &uid, bool force )
01421 {
01422   Incidence *inc = mCalendar->incidence( uid );
01423   if ( inc ) {
01424     deleteIncidence( inc, force );
01425     return true;
01426   } else {
01427     return false;
01428   }
01429 }
01430 
01431 void CalendarView::toggleAlarm( Incidence *incidence )
01432 {
01433   if ( !incidence || !mChanger ) {
01434     kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl;
01435     return;
01436   }
01437   Incidence*oldincidence = incidence->clone();
01438   if ( !mChanger->beginChange( incidence, 0, QString() ) ) {
01439     kdDebug(5850) << "Unable to lock incidence " << endl;
01440     delete oldincidence;
01441     return;
01442   }
01443 
01444   Alarm::List alarms = incidence->alarms();
01445   Alarm::List::ConstIterator it;
01446   for ( it = alarms.begin(); it != alarms.end(); ++it ) {
01447     (*it)->toggleAlarm();
01448   }
01449   if ( alarms.isEmpty() ) {
01450     // Add an alarm if it didn't have one
01451     Alarm *alm = incidence->newAlarm();
01452     alm->setType( Alarm::Display );
01453     alm->setEnabled( true );
01454     int duration; // in secs
01455     switch( KOPrefs::instance()->mReminderTimeUnits ) {
01456     default:
01457     case 0: // mins
01458       duration = KOPrefs::instance()->mReminderTime * 60;
01459       break;
01460     case 1: // hours
01461       duration = KOPrefs::instance()->mReminderTime * 60 * 60;
01462       break;
01463     case 2: // days
01464       duration = KOPrefs::instance()->mReminderTime * 60 * 60 * 24;
01465       break;
01466     }
01467     if ( incidence->type() == "Event" ) {
01468       alm->setStartOffset( KCal::Duration( -duration ) );
01469     } else {
01470       alm->setEndOffset( KCal::Duration( -duration ) );
01471     }
01472   }
01473   mChanger->changeIncidence( oldincidence, incidence, KOGlobals::ALARM_MODIFIED, this );
01474   mChanger->endChange( incidence, 0, QString() );
01475   delete oldincidence;
01476 
01477 //  mClickedItem->updateIcons();
01478 }
01479 
01480 void CalendarView::dissociateOccurrence( Incidence *incidence, const QDate &date )
01481 {
01482   if ( !incidence || !mChanger ) {
01483     kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl;
01484     return;
01485   }
01486 
01487   QPair<ResourceCalendar *, QString>p =
01488     CalHelper::incSubResourceCalendar( calendar(), incidence );
01489 
01490   if ( !mChanger->beginChange( incidence, p.first, p.second ) ) {
01491     kdDebug(5850) << "Unable to lock incidence " << endl;
01492     return;
01493   }
01494   startMultiModify( i18n("Dissociate occurrence") );
01495   Incidence*oldincidence = incidence->clone();
01496 
01497   Incidence* newInc = mCalendar->dissociateOccurrence( incidence, date, true );
01498 
01499   if ( newInc ) {
01500     mChanger->changeIncidence( oldincidence, incidence, KOGlobals::NOTHING_MODIFIED, this );
01501     mChanger->addIncidence( newInc, p.first, p.second, this );
01502   } else {
01503     KMessageBox::sorry( this, i18n("Dissociating the occurrence failed."),
01504       i18n("Dissociating Failed") );
01505   }
01506   mChanger->endChange( incidence, p.first, p.second );
01507   endMultiModify();
01508   delete oldincidence;
01509 }
01510 
01511 void CalendarView::dissociateFutureOccurrence( Incidence *incidence, const QDate &date )
01512 {
01513   if ( !incidence || !mChanger ) {
01514     kdDebug(5850) << "CalendarView::toggleAlarm() called without having a clicked item" << endl;
01515     return;
01516   }
01517 
01518   QPair<ResourceCalendar *, QString>p =
01519     CalHelper::incSubResourceCalendar( calendar(), incidence );
01520 
01521   if ( !mChanger->beginChange( incidence, p.first, p.second ) ) {
01522     kdDebug(5850) << "Unable to lock incidence " << endl;
01523     return;
01524   }
01525   startMultiModify( i18n("Dissociate future occurrences") );
01526   Incidence*oldincidence = incidence->clone();
01527 
01528   Incidence* newInc = mCalendar->dissociateOccurrence( incidence, date, true );
01529   if ( newInc ) {
01530     mChanger->changeIncidence( oldincidence, incidence, KOGlobals::NOTHING_MODIFIED, this );
01531     mChanger->addIncidence( newInc, p.first, p.second, this );
01532   } else {
01533     KMessageBox::sorry( this, i18n("Dissociating the future occurrences failed."),
01534       i18n("Dissociating Failed") );
01535   }
01536   endMultiModify();
01537   mChanger->endChange( incidence, p.first, p.second );
01538   delete oldincidence;
01539 }
01540 
01541 
01542 /*****************************************************************************/
01543 
01544 
01545 void CalendarView::schedule_publish(Incidence *incidence)
01546 {
01547   if (incidence == 0)
01548     incidence = selectedIncidence();
01549 
01550   if (!incidence) {
01551     KMessageBox::information( this, i18n("No item selected."),
01552                               "PublishNoEventSelected" );
01553     return;
01554   }
01555 
01556   PublishDialog *publishdlg = new PublishDialog();
01557   if (incidence->attendeeCount()>0) {
01558     Attendee::List attendees = incidence->attendees();
01559     Attendee::List::ConstIterator it;
01560     for( it = attendees.begin(); it != attendees.end(); ++it ) {
01561       publishdlg->addAttendee( *it );
01562     }
01563   }
01564   if ( publishdlg->exec() == QDialog::Accepted ) {
01565     Incidence *inc = incidence->clone();
01566     inc->registerObserver( 0 );
01567     inc->clearAttendees();
01568 
01569     // Send the mail
01570     KCal::MailScheduler scheduler( mCalendar );
01571     if ( scheduler.publish( incidence, publishdlg->addresses() ) ) {
01572       KMessageBox::information( this, i18n("The item information was successfully sent."),
01573                                 i18n("Publishing"), "IncidencePublishSuccess" );
01574     } else {
01575       KMessageBox::error( this, i18n("Unable to publish the item '%1'").arg( incidence->summary() ) );
01576     }
01577   }
01578   delete publishdlg;
01579 }
01580 
01581 void CalendarView::schedule_request(Incidence *incidence)
01582 {
01583   schedule(Scheduler::Request,incidence);
01584 }
01585 
01586 void CalendarView::schedule_refresh(Incidence *incidence)
01587 {
01588   schedule(Scheduler::Refresh,incidence);
01589 }
01590 
01591 void CalendarView::schedule_cancel(Incidence *incidence)
01592 {
01593   schedule(Scheduler::Cancel,incidence);
01594 }
01595 
01596 void CalendarView::schedule_add(Incidence *incidence)
01597 {
01598   schedule(Scheduler::Add,incidence);
01599 }
01600 
01601 void CalendarView::schedule_reply(Incidence *incidence)
01602 {
01603   schedule(Scheduler::Reply,incidence);
01604 }
01605 
01606 void CalendarView::schedule_counter(Incidence *incidence)
01607 {
01608   schedule(Scheduler::Counter,incidence);
01609 }
01610 
01611 void CalendarView::schedule_declinecounter(Incidence *incidence)
01612 {
01613   schedule(Scheduler::Declinecounter,incidence);
01614 }
01615 
01616 void CalendarView::schedule_forward( Incidence *incidence )
01617 {
01618   if ( !incidence ) {
01619     incidence = selectedIncidence();
01620   }
01621 
01622   if ( !incidence ) {
01623     KMessageBox::information(
01624       this,
01625       i18n( "No item selected." ),
01626       i18n( "Forwarding" ),
01627       "ForwardNoEventSelected" );
01628     return;
01629   }
01630 
01631   PublishDialog publishdlg;
01632   if ( publishdlg.exec() == QDialog::Accepted ) {
01633     QString recipients = publishdlg.addresses();
01634     if ( incidence->organizer().isEmpty() ) {
01635       incidence->setOrganizer( Person( KOPrefs::instance()->fullName(),
01636                                        KOPrefs::instance()->email() ) );
01637     }
01638 
01639     ICalFormat format;
01640     QString messageText = format.createScheduleMessage( incidence, Scheduler::Request );
01641     KOMailClient mailer;
01642     if ( mailer.mailTo( incidence, recipients, messageText ) ) {
01643       KMessageBox::information(
01644         this,
01645         i18n( "The item information was successfully sent." ),
01646         i18n( "Forwarding" ),
01647         "IncidenceForwardSuccess" );
01648     } else {
01649       KMessageBox::error(
01650         this,
01651         i18n( "Unable to forward the item '%1'" ).arg( incidence->summary() ),
01652         i18n( "Forwarding Error" ) );
01653     }
01654   }
01655 }
01656 
01657 void CalendarView::mailFreeBusy( int daysToPublish )
01658 {
01659   QDateTime start = QDateTime::currentDateTime();
01660   QDateTime end = start.addDays(daysToPublish);
01661 
01662   FreeBusy *freebusy = new FreeBusy(mCalendar, start, end);
01663   freebusy->setOrganizer( Person( KOPrefs::instance()->fullName(),
01664                       KOPrefs::instance()->email() ) );
01665 
01666   kdDebug(5850) << "calendarview: schedule_publish_freebusy: startDate: "
01667      << KGlobal::locale()->formatDateTime( start ) << " End Date: "
01668      << KGlobal::locale()->formatDateTime( end ) << endl;
01669 
01670   PublishDialog *publishdlg = new PublishDialog();
01671   if ( publishdlg->exec() == QDialog::Accepted ) {
01672     // Send the mail
01673     KCal::MailScheduler scheduler( mCalendar );
01674     if ( scheduler.publish( freebusy, publishdlg->addresses() ) ) {
01675       KMessageBox::information( this, i18n("The free/busy information was successfully sent."),
01676                                 i18n("Sending Free/Busy"), "FreeBusyPublishSuccess" );
01677     } else {
01678       KMessageBox::error( this, i18n("Unable to publish the free/busy data.") );
01679     }
01680   }
01681   delete freebusy;
01682   delete publishdlg;
01683 }
01684 
01685 void CalendarView::uploadFreeBusy()
01686 {
01687   KOGroupware::instance()->freeBusyManager()->publishFreeBusy();
01688 }
01689 
01690 void CalendarView::schedule(Scheduler::Method method, Incidence *incidence)
01691 {
01692   if ( !incidence ) {
01693     incidence = selectedIncidence();
01694   }
01695 
01696   if ( !incidence ) {
01697     KMessageBox::sorry( this, i18n("No item selected."),
01698                         "ScheduleNoEventSelected" );
01699     return;
01700   }
01701 
01702   if( incidence->attendeeCount() == 0 && method != Scheduler::Publish ) {
01703     KMessageBox::information( this, i18n("The item has no attendees."),
01704                               "ScheduleNoIncidences" );
01705     return;
01706   }
01707 
01708   Incidence *inc = incidence->clone();
01709   inc->registerObserver( 0 );
01710   inc->clearAttendees();
01711 
01712   // Send the mail
01713   KCal::MailScheduler scheduler( mCalendar );
01714   if ( scheduler.performTransaction( incidence, method ) ) {
01715     KMessageBox::information( this, i18n("The groupware message for item '%1'"
01716                                 "was successfully sent.\nMethod: %2")
01717                                 .arg( incidence->summary() )
01718                                 .arg( Scheduler::methodName( method ) ),
01719                               i18n("Sending Free/Busy"),
01720                               "FreeBusyPublishSuccess" );
01721   } else {
01722     KMessageBox::error( this, i18n("Groupware message sending failed. "
01723                         "%2 is request/reply/add/cancel/counter/etc.",
01724                         "Unable to send the item '%1'.\nMethod: %2")
01725                         .arg( incidence->summary() )
01726                         .arg( Scheduler::methodName( method ) ) );
01727   }
01728 }
01729 
01730 void CalendarView::openAddressbook()
01731 {
01732   KRun::runCommand("kaddressbook");
01733 }
01734 
01735 void CalendarView::setModified(bool modified)
01736 {
01737   if (mModified != modified) {
01738     mModified = modified;
01739     emit modifiedChanged(mModified);
01740   }
01741 }
01742 
01743 bool CalendarView::isReadOnly()
01744 {
01745   return mReadOnly;
01746 }
01747 
01748 void CalendarView::setReadOnly(bool readOnly)
01749 {
01750   if (mReadOnly != readOnly) {
01751     mReadOnly = readOnly;
01752     emit readOnlyChanged(mReadOnly);
01753   }
01754 }
01755 
01756 bool CalendarView::isModified()
01757 {
01758   return mModified;
01759 }
01760 
01761 void CalendarView::print()
01762 {
01763 #ifndef KORG_NOPRINTER
01764   KOCoreHelper helper;
01765   CalPrinter printer( this, mCalendar, &helper );
01766   connect( this, SIGNAL(configChanged()), &printer, SLOT(updateConfig()) );
01767 
01768   KOrg::BaseView *currentView = mViewManager->currentView();
01769 
01770   CalPrinterBase::PrintType printType = CalPrinterBase::Month;
01771   if ( currentView ) printType = currentView->printType();
01772 
01773   DateList tmpDateList = mDateNavigator->selectedDates();
01774   Incidence::List selectedIncidences;
01775   if ( mViewManager->currentView() ) {
01776     selectedIncidences = mViewManager->currentView()->selectedIncidences();
01777   }
01778   printer.print( printType, tmpDateList.first(), tmpDateList.last(), selectedIncidences );
01779 #endif
01780 }
01781 
01782 void CalendarView::exportWeb()
01783 {
01784   // FIXME: Get rid of the settings object. When can I delete it???
01785   HTMLExportSettings *settings = new HTMLExportSettings( "KOrganizer" );
01786   // Manually read in the config, because parametrized kconfigxt objects don't
01787   // seem to load the config theirselves
01788   if ( settings ) settings->readConfig();
01789   ExportWebDialog *dlg = new ExportWebDialog( settings, this );
01790   connect( dlg,  SIGNAL( exportHTML( HTMLExportSettings* ) ),
01791            this, SIGNAL( exportHTML( HTMLExportSettings* ) ) );
01792   dlg->show();
01793 }
01794 
01795 void CalendarView::exportICalendar()
01796 {
01797   QString filename = KFileDialog::getSaveFileName("icalout.ics",i18n("*.ics|ICalendars"),this);
01798   if ( !filename.isEmpty() )
01799   {
01800     // Force correct extension
01801     if (filename.right(4) != ".ics") filename += ".ics";
01802     if ( QFile( filename ).exists() ) {
01803       if ( KMessageBox::No == KMessageBox::warningYesNo(
01804              this,
01805              i18n( "Do you want to overwrite %1?").arg(filename) ) ) {
01806           return;
01807       }
01808     }
01809     FileStorage storage( mCalendar, filename, new ICalFormat );
01810     storage.save();
01811   }
01812 }
01813 
01814 void CalendarView::exportVCalendar()
01815 {
01816   if (mCalendar->journals().count() > 0) {
01817     int result = KMessageBox::warningContinueCancel(this,
01818         i18n("The journal entries can not be exported to a vCalendar file."),
01819         i18n("Data Loss Warning"),i18n("Proceed"),"dontaskVCalExport",
01820         true);
01821     if (result != KMessageBox::Continue) return;
01822   }
01823 
01824   QString filename = KFileDialog::getSaveFileName("vcalout.vcs",i18n("*.vcs|vCalendars"),this);
01825   if ( !filename.isEmpty() )
01826   {
01827     // TODO: I don't like forcing extensions:
01828     // Force correct extension
01829     if (filename.right(4) != ".vcs") filename += ".vcs";
01830     if ( QFile( filename ).exists() ) {
01831       if ( KMessageBox::No == KMessageBox::warningYesNo(
01832              this,
01833              i18n( "Do you want to overwrite %1?").arg(filename ) ) ) {
01834              return;
01835       }
01836     }
01837     FileStorage storage( mCalendar, filename, new VCalFormat );
01838     storage.save();
01839   }
01840 }
01841 
01842 void CalendarView::eventUpdated(Incidence *)
01843 {
01844   setModified();
01845   // Don't call updateView here. The code, which has caused the update of the
01846   // event is responsible for updating the view.
01847 //  updateView();
01848 }
01849 
01850 void CalendarView::adaptNavigationUnits()
01851 {
01852   if (mViewManager->currentView()->isEventView()) {
01853     int days = mViewManager->currentView()->currentDateCount();
01854     if (days == 1) {
01855       emit changeNavStringPrev(i18n("&Previous Day"));
01856       emit changeNavStringNext(i18n("&Next Day"));
01857     } else {
01858       emit changeNavStringPrev(i18n("&Previous Week"));
01859       emit changeNavStringNext(i18n("&Next Week"));
01860     }
01861   }
01862 }
01863 
01864 void CalendarView::processMainViewSelection( Incidence *incidence, const QDate &date )
01865 {
01866   if ( incidence ) mTodoList->clearSelection();
01867   processIncidenceSelection( incidence, date );
01868 }
01869 
01870 void CalendarView::processTodoListSelection( Incidence *incidence, const QDate &date )
01871 {
01872   if ( incidence && mViewManager->currentView() ) {
01873     mViewManager->currentView()->clearSelection();
01874   }
01875   processIncidenceSelection( incidence, date );
01876 }
01877 
01878 void CalendarView::processIncidenceSelection( Incidence *incidence, const QDate &date )
01879 {
01880   if ( incidence != mSelectedIncidence ) {
01881     // This signal also must be emitted if incidence is 0
01882     emit incidenceSelected( incidence, date );
01883   }
01884 
01885   if ( !incidence ) {
01886    mSelectedIncidence = incidence;
01887    return;
01888   }
01889   if ( incidence == mSelectedIncidence ) {
01890     if ( !incidence->doesRecur() || mSaveDate == date ) {
01891       return;
01892     }
01893   }
01894 
01895   mSelectedIncidence = incidence;
01896   mSaveDate = date;
01897 
01898   emit incidenceSelected( mSelectedIncidence, date );
01899   bool organizerEvents = false;
01900   bool groupEvents = false;
01901   bool todo = false;
01902   bool subtodo = false;
01903 
01904   organizerEvents = KOPrefs::instance()->thatIsMe( incidence->organizer().email() );
01905   groupEvents = incidence->attendeeByMails( KOPrefs::instance()->allEmails() );
01906 
01907   if ( incidence->type() == "Todo" ) {
01908     todo = true;
01909     subtodo = ( incidence->relatedTo() != 0 );
01910   }
01911 
01912   emit todoSelected( todo );
01913   emit subtodoSelected( subtodo );
01914   emit organizerEventsSelected( organizerEvents );
01915   emit groupEventsSelected( groupEvents );
01916 }
01917 
01918 
01919 void CalendarView::checkClipboard()
01920 {
01921 #ifndef KORG_NODND
01922   if (ICalDrag::canDecode(QApplication::clipboard()->data())) {
01923     kdDebug(5850) << "CalendarView::checkClipboard() true" << endl;
01924     emit pasteEnabled(true);
01925   } else {
01926     kdDebug(5850) << "CalendarView::checkClipboard() false" << endl;
01927     emit pasteEnabled(false);
01928   }
01929 #endif
01930 }
01931 
01932 void CalendarView::showDates( const DateList &selectedDates, const QDate &preferredMonth )
01933 {
01934   mDateNavigatorContainer->selectDates( selectedDates, preferredMonth );
01935   mNavigatorBar->selectDates( selectedDates );
01936 
01937   if ( mViewManager->currentView() ) {
01938     updateView( selectedDates.first(), selectedDates.last() );
01939   } else {
01940     mViewManager->showAgendaView();
01941   }
01942 }
01943 
01944 void CalendarView::editFilters()
01945 {
01946   kdDebug(5850) << "CalendarView::editFilters()" << endl;
01947 
01948   CalFilter *filter = mFilters.first();
01949   while( filter ) {
01950     kdDebug(5850) << " Filter: " << filter->name() << endl;
01951     filter = mFilters.next();
01952   }
01953 
01954   mDialogManager->showFilterEditDialog(&mFilters);
01955 }
01956 
01959 void CalendarView::updateFilter()
01960 {
01961   QStringList filters;
01962   CalFilter *filter;
01963 
01964   int pos = mFilters.find( mCurrentFilter );
01965   if ( pos < 0 ) {
01966     mCurrentFilter = 0;
01967   }
01968 
01969   filters << i18n("No filter");
01970   for ( filter = mFilters.first(); filter; filter = mFilters.next() ) {
01971     filters << filter->name();
01972   }
01973 
01974   emit newFilterListSignal( filters );
01975   // account for the additional "No filter" at the beginning! if the
01976   // filter is not in the list, pos == -1...
01977   emit selectFilterSignal( pos+1 );
01978   mCalendar->setFilter( mCurrentFilter );
01979   updateView();
01980 }
01981 
01984 void CalendarView::filterActivated( int filterNo )
01985 {
01986   CalFilter *newFilter = 0;
01987   if ( filterNo > 0 && filterNo <= int(mFilters.count()) ) {
01988     newFilter = mFilters.at( filterNo-1 );
01989   }
01990   if ( newFilter != mCurrentFilter ) {
01991     mCurrentFilter = newFilter;
01992     mCalendar->setFilter( mCurrentFilter );
01993     updateView();
01994   }
01995   emit filterChanged();
01996 }
01997 
01998 QString CalendarView::currentFilterName() const
01999 {
02000   if ( mCurrentFilter) {
02001     return mCurrentFilter->name();
02002   } else return i18n("No filter");
02003 }
02004 
02005 void CalendarView::takeOverEvent()
02006 {
02007   Incidence *incidence = currentSelection();
02008 
02009   if (!incidence) return;
02010 
02011   incidence->setOrganizer( Person( KOPrefs::instance()->fullName(),
02012                            KOPrefs::instance()->email() ) );
02013   incidence->recreate();
02014   incidence->setReadOnly(false);
02015 
02016   updateView();
02017 }
02018 
02019 void CalendarView::takeOverCalendar()
02020 {
02021   Incidence::List incidences = mCalendar->rawIncidences();
02022   Incidence::List::Iterator it;
02023 
02024   for ( it = incidences.begin(); it != incidences.end(); ++it ) {
02025     (*it)->setOrganizer( Person( KOPrefs::instance()->fullName(),
02026                          KOPrefs::instance()->email() ) );
02027     (*it)->recreate();
02028     (*it)->setReadOnly(false);
02029   }
02030   updateView();
02031 }
02032 
02033 void CalendarView::showIntro()
02034 {
02035   kdDebug(5850) << "To be implemented." << endl;
02036 }
02037 
02038 void CalendarView::showDateNavigator( bool show )
02039 {
02040   if( show )
02041     mDateNavigatorContainer->show();
02042   else
02043     mDateNavigatorContainer->hide();
02044 }
02045 
02046 void CalendarView::showTodoView( bool show )
02047 {
02048   if( show )
02049     mTodoList->show();
02050   else
02051     mTodoList->hide();
02052 }
02053 
02054 void CalendarView::showEventViewer( bool show )
02055 {
02056   if( show )
02057     mEventViewer->show();
02058   else
02059     mEventViewer->hide();
02060 }
02061 
02062 
02063 void CalendarView::addView(KOrg::BaseView *view)
02064 {
02065   mViewManager->addView(view);
02066 }
02067 
02068 void CalendarView::showView(KOrg::BaseView *view)
02069 {
02070   mViewManager->showView(view);
02071 }
02072 
02073 void CalendarView::addExtension( CalendarViewExtension::Factory *factory )
02074 {
02075   CalendarViewExtension *extension = factory->create( mLeftSplitter );
02076 
02077   mExtensions.append( extension );
02078 }
02079 
02080 void CalendarView::toggleExpand()
02081 {
02082   showLeftFrame( mLeftFrame->isHidden() );
02083 }
02084 
02085 void CalendarView::showLeftFrame(bool show)
02086 {
02087   if (show) {
02088     mLeftFrame->show();
02089     emit calendarViewExpanded( false );
02090   } else {
02091     mLeftFrame->hide();
02092     emit calendarViewExpanded( true );
02093   }
02094 }
02095 
02096 void CalendarView::calendarModified( bool modified, Calendar * )
02097 {
02098   setModified( modified );
02099 }
02100 
02101 Todo *CalendarView::selectedTodo()
02102 {
02103   Incidence *incidence = currentSelection();
02104   if ( incidence && incidence->type() == "Todo" ) {
02105     return static_cast<Todo *>( incidence );
02106   }
02107   incidence = 0;
02108 
02109   Incidence::List selectedIncidences = mTodoList->selectedIncidences();
02110   if ( !selectedIncidences.isEmpty() ) incidence = selectedIncidences.first();
02111   if ( incidence && incidence->type() == "Todo" ) {
02112     return static_cast<Todo *>( incidence );
02113   }
02114 
02115   return 0;
02116 }
02117 
02118 void CalendarView::dialogClosing( Incidence *in )
02119 {
02120   // FIXME: this doesn't work, because if it's a new incidence, it's not locked!
02121   mChanger->endChange( in, 0, QString() );
02122   mDialogList.remove( in );
02123 }
02124 
02125 Incidence *CalendarView::currentSelection()
02126 {
02127   return mViewManager->currentSelection();
02128 }
02129 
02130 Incidence* CalendarView::selectedIncidence()
02131 {
02132   Incidence *incidence = currentSelection();
02133   if ( !incidence ) {
02134     Incidence::List selectedIncidences = mTodoList->selectedIncidences();
02135     if ( !selectedIncidences.isEmpty() )
02136       incidence = selectedIncidences.first();
02137   }
02138   return incidence;
02139 }
02140 
02141 void CalendarView::showIncidence()
02142 {
02143   showIncidence( selectedIncidence(), activeIncidenceDate() );
02144 }
02145 
02146 void CalendarView::editIncidence()
02147 {
02148   editIncidence( selectedIncidence(), activeIncidenceDate() );
02149 }
02150 
02151 bool CalendarView::editIncidence( const QString &uid )
02152 {
02153   return editIncidence( mCalendar->incidence( uid ), QDate() );
02154 }
02155 
02156 bool CalendarView::editIncidence( const QString &uid, const QDate &date )
02157 {
02158   return editIncidence( mCalendar->incidence( uid ), date );
02159 }
02160 
02161 void CalendarView::deleteIncidence()
02162 {
02163   deleteIncidence( selectedIncidence() );
02164 }
02165 
02166 void CalendarView::cutIncidence(Incidence *)
02167 {
02168   edit_cut();
02169 }
02170 
02171 void CalendarView::copyIncidence(Incidence *)
02172 {
02173   edit_copy();
02174 }
02175 
02176 void CalendarView::pasteIncidence()
02177 {
02178   edit_paste();
02179 }
02180 
02181 void CalendarView::showIncidence( Incidence *incidence, const QDate &date )
02182 {
02183   if ( !incidence ) {
02184     return;
02185   }
02186 
02187   KOEventViewerDialog *eventViewer = new KOEventViewerDialog( calendar(), this );
02188   eventViewer->setIncidence( incidence, date );
02189   eventViewer->show();
02190 }
02191 
02192 bool CalendarView::editIncidence( Incidence *incidence, const QDate &date, bool isCounter )
02193 {
02194   kdDebug(5850) << "CalendarView::editEvent()" << endl;
02195 
02196   CalendarResources *stdcal = dynamic_cast<CalendarResources *>( mCalendar );
02197   if( stdcal && !stdcal->hasCalendarResources() ) {
02198     KMessageBox::sorry(
02199       this,
02200       i18n( "No resources found. We can not edit the item." ) );
02201     return false;
02202   }
02203 
02204   // FIXME: This is a nasty hack, since we need to set a parent for the
02205   //        resource selection dialog. However, we don't have any UI methods
02206   //        in the calendar, only in the CalendarResources::DestinationPolicy
02207   //        So we need to type-cast it and extract it from the CalendarResources
02208   QWidget *tmpparent = 0;
02209   if ( stdcal ) {
02210     tmpparent = stdcal->dialogParentWidget();
02211     stdcal->setDialogParentWidget( this );
02212   }
02213 
02214   if ( !incidence ) {
02215     kdDebug(5850) << "Empty Incidence" << endl;
02216     KNotifyClient::beep();
02217     return false;
02218   }
02219 
02220   if ( !mChanger ) {
02221     kdDebug(5850) << "Empty Changer" << endl;
02222     KNotifyClient::beep();
02223     return false;
02224   }
02225 
02226   KOIncidenceEditor *tmp = editorDialog( incidence );
02227   if ( tmp ) {
02228     kdDebug(5850) << "CalendarView::editIncidence() in List" << endl;
02229     tmp->reload();
02230     tmp->raise();
02231     tmp->show();
02232     return true;
02233   }
02234 
02235   if ( incidence->isReadOnly() ) {
02236     showIncidence( incidence, date );
02237     return true;
02238   }
02239 
02240   QPair<ResourceCalendar *, QString>p =
02241     CalHelper::incSubResourceCalendar( calendar(), incidence );
02242 
02243   Incidence *savedIncidence = incidence->clone();
02244   Incidence *incToChange;
02245 
02246   if ( incidence->doesRecur() ) {
02247     KOGlobals::WhichOccurrences chosenOption;
02248     incToChange = singleOccurrenceOrAll( incidence, KOGlobals::EDIT, chosenOption, date );
02249   } else {
02250     incToChange = incidence;
02251   }
02252 
02253   // If the user pressed cancel incToChange is 0
02254   if ( incToChange ) {
02255     if ( !isCounter && !mChanger->beginChange( incToChange, p.first, p.second ) ) {
02256       warningChangeFailed( incToChange );
02257       showIncidence( incToChange, date );
02258 
02259       return false;
02260     }
02261 
02262     kdDebug(5850) << "CalendarView::editIncidence() new IncidenceEditor" << endl;
02263     KOIncidenceEditor *incidenceEditor = mDialogManager->getEditor( incToChange );
02264     connectIncidenceEditor( incidenceEditor );
02265 
02266     mDialogList.insert( incToChange, incidenceEditor );
02267     if ( incidence != incToChange ) {
02268       incidenceEditor->setRecurringIncidence( savedIncidence, incidence );
02269     }
02270     incidenceEditor->setResource( p.first, p.second );
02271     incidenceEditor->editIncidence( incToChange, date, mCalendar );
02272     incidenceEditor->show();
02273     return true;
02274   } else {
02275     return false;
02276   }
02277 }
02278 
02279 void CalendarView::deleteSubTodosIncidence ( Todo *todo )
02280 {
02281   if( !todo ) return;
02282 
02283   Incidence::List subTodos( todo->relations() );
02284   Incidence::List::Iterator it;
02285   Incidence *aIncidence;
02286   Todo *aTodo;
02287 
02288   for ( it= subTodos.begin(); it != subTodos.end(); ++it ) {
02289     aIncidence = *it;
02290     if( aIncidence && aIncidence->type() == "Todo" ) {
02291       aTodo = static_cast<Todo*>( aIncidence );
02292       deleteSubTodosIncidence ( aTodo );
02293     }
02294   }
02295   mChanger->deleteIncidence ( todo, this );
02296 }
02297 
02298 void CalendarView::deleteTodoIncidence ( Todo *todo, bool force )
02299 {
02300   if ( !todo ) return ;
02301 
02302   // it a simple todo, ask and delete it.
02303   if (todo->relations().isEmpty() ) {
02304     bool doDelete = true;
02305     if ( !force && KOPrefs::instance()->mConfirm ) {
02306       doDelete = ( msgItemDelete( todo ) == KMessageBox::Continue );
02307     }
02308     if ( doDelete )
02309       mChanger->deleteIncidence( todo, this );
02310     return;
02311   }
02312 
02313   /* Ok, this to-do has sub-to-dos, ask what to do */
02314   int km = KMessageBox::No;
02315   if ( !force ) {
02316     km = KMessageBox::questionYesNoCancel(
02317       this,
02318       i18n("The item \"%1\" has sub-to-dos. "
02319            "Do you want to delete just this item and "
02320            "make all its sub-to-dos independent, or "
02321            "delete the to-do with all its sub-to-dos?"
02322         ).arg( todo->summary() ),
02323       i18n("KOrganizer Confirmation"),
02324       i18n("Delete Only This"),
02325       i18n("Delete All"));
02326   }
02327   startMultiModify( i18n("Deleting sub-to-dos" ) );
02328   // Delete only the father
02329   if( km == KMessageBox::Yes ) {
02330     // Instead of making a subto-do independent, why not relate
02331     // it to it's dead father's parent?
02332     makeChildrenIndependent ( todo );
02333     mChanger->deleteIncidence( todo, this );
02334   } else if ( km == KMessageBox::No ) {
02335     // Delete all
02336     // we have to hide the delete confirmation for each itemDate
02337     deleteSubTodosIncidence ( todo );
02338   }
02339   endMultiModify();
02340 }
02341 
02342 void CalendarView::deleteIncidence(Incidence *incidence, bool force)
02343 {
02344   if ( !incidence || !mChanger ) {
02345     if ( !force ) {
02346       KNotifyClient::beep();
02347     }
02348     return;
02349   }
02350   if ( incidence->isReadOnly() ) {
02351     if ( !force ) {
02352       KMessageBox::information( this, i18n("The item \"%1\" is marked read-only "
02353                                 "and cannot be deleted; it probably belongs to "
02354                                 "a read-only calendar resource.")
02355                                 .arg(incidence->summary()),
02356                                 i18n("Removing not possible"),
02357                                 "deleteReadOnlyIncidence" );
02358     }
02359     return;
02360   }
02361 
02362   CanDeleteIncidenceVisitor v;
02363 
02364   // Let the visitor do special things for special incidence types.
02365   // e.g. todos with children cannot be deleted, so act(..) returns false
02366   if ( !v.act( incidence, this ) )
02367     return;
02368   //If it is a todo, there are specific delete function
02369 
02370   if ( incidence && incidence->type()=="Todo" ) {
02371     deleteTodoIncidence( static_cast<Todo*>(incidence), force );
02372     return;
02373   }
02374 
02375   if ( incidence->doesRecur() ) {
02376     QDate itemDate = mViewManager->currentSelectionDate();
02377     kdDebug(5850) << "Recurrence-Date: " << itemDate.toString() << endl;
02378     int km = KMessageBox::Ok;
02379     if ( !force ) {
02380       if ( !itemDate.isValid() ) {
02381         kdDebug(5850) << "Date Not Valid" << endl;
02382         km = KMessageBox::warningContinueCancel(this,
02383           i18n("The calendar item \"%1\" recurs over multiple dates; "
02384                "are you sure you want to delete it "
02385                "and all its recurrences?").arg( incidence->summary() ),
02386                i18n("KOrganizer Confirmation"), i18n("Delete All") );
02387       } else {
02388         km = KOMessageBox::fourBtnMsgBox( this, QMessageBox::Warning,
02389           i18n("The calendar item \"%1\" recurs over multiple dates. "
02390                "Do you want to delete only the current one on %2, only all "
02391                "future recurrences, or all its recurrences?" )
02392                .arg( incidence->summary() )
02393                .arg( KGlobal::locale()->formatDate(itemDate)),
02394                i18n("KOrganizer Confirmation"), i18n("Delete C&urrent"),
02395                i18n("Delete &Future"),
02396                i18n("Delete &All"));
02397       }
02398     }
02399 
02400     QPair<ResourceCalendar *, QString>p =
02401       CalHelper::incSubResourceCalendar( calendar(), incidence );
02402 
02403     switch(km) {
02404       case KMessageBox::Ok: // Continue // all
02405       case KMessageBox::Continue:
02406         mChanger->deleteIncidence( incidence, this );
02407         break;
02408 
02409       case KMessageBox::Yes: // just this one
02410         if ( mChanger->beginChange( incidence, p.first, p.second ) ) {
02411           Incidence *oldIncidence = incidence->clone();
02412           incidence->recurrence()->addExDate( itemDate );
02413           mChanger->changeIncidence( oldIncidence, incidence,
02414                                      KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY, this );
02415           mChanger->endChange( incidence, p.first, p.second );
02416           delete oldIncidence;
02417         }
02418         break;
02419       case KMessageBox::No: // all future items
02420         if ( mChanger->beginChange( incidence, p.first, p.second ) ) {
02421           Incidence *oldIncidence = incidence->clone();
02422           Recurrence *recur = incidence->recurrence();
02423           recur->setEndDate( itemDate.addDays(-1) );
02424           mChanger->changeIncidence( oldIncidence, incidence,
02425                                      KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE,  this );
02426           mChanger->endChange( incidence, p.first, p.second );
02427           delete oldIncidence;
02428         }
02429         break;
02430     }
02431   } else {
02432     bool doDelete = true;
02433     if ( !force && KOPrefs::instance()->mConfirm ) {
02434       doDelete = ( msgItemDelete( incidence ) == KMessageBox::Continue );
02435     }
02436     if ( doDelete ) {
02437       mChanger->deleteIncidence( incidence, this );
02438       processIncidenceSelection( 0, QDate() );
02439     }
02440   }
02441 }
02442 
02443 void CalendarView::connectIncidenceEditor( KOIncidenceEditor *editor )
02444 {
02445   connect( this, SIGNAL( newIncidenceChanger( IncidenceChangerBase* ) ),
02446            editor, SLOT( setIncidenceChanger( IncidenceChangerBase* ) ) );
02447   editor->setIncidenceChanger( mChanger );
02448 }
02449 
02450 bool CalendarView::purgeCompletedSubTodos( Todo* todo, bool &allPurged )
02451 {
02452   if ( !todo ) return true;
02453   bool deleteThisTodo = true;
02454   Incidence::List subTodos( todo->relations() );
02455   Incidence *aIncidence;
02456   Todo *aTodo;
02457   Incidence::List::Iterator it;
02458   for ( it = subTodos.begin(); it != subTodos.end(); ++it ) {
02459     aIncidence = *it;
02460     if ( aIncidence && aIncidence->type()=="Todo" ) {
02461       aTodo = static_cast<Todo*>( aIncidence );
02462       deleteThisTodo &= purgeCompletedSubTodos( aTodo, allPurged );
02463     }
02464   }
02465 
02466   if ( deleteThisTodo ) {
02467     if ( todo->isCompleted() ) {
02468       if ( !mChanger->deleteIncidence( todo, this ) )
02469         allPurged = false;
02470     } else {
02471       deleteThisTodo = false;
02472     }
02473   } else {
02474     if ( todo->isCompleted() ) {
02475       allPurged = false;
02476     }
02477   }
02478   return deleteThisTodo;
02479 }
02480 
02481 void CalendarView::purgeCompleted()
02482 {
02483   int result = KMessageBox::warningContinueCancel(this,
02484       i18n("Delete all completed to-dos?"),i18n("Purge To-dos"),i18n("Purge"));
02485 
02486   if (result == KMessageBox::Continue) {
02487     bool allDeleted = true;
02488     startMultiModify( i18n("Purging completed to-dos") );
02489     Todo::List todos = calendar()->rawTodos();
02490     Todo::List rootTodos;
02491     Todo::List::ConstIterator it;
02492     for ( it = todos.begin(); it != todos.end(); ++it ) {
02493       Todo *aTodo = *it;
02494       if ( aTodo && !aTodo->relatedTo() )
02495         rootTodos.append( aTodo );
02496     }
02497     // now that we have a list of all root todos, check them and their children
02498     for ( it = rootTodos.begin(); it != rootTodos.end(); ++it ) {
02499       purgeCompletedSubTodos( *it, allDeleted );
02500     }
02501     endMultiModify();
02502     if ( !allDeleted ) {
02503       KMessageBox::information( this, i18n("Unable to purge to-dos with "
02504                                 "uncompleted children."), i18n("Delete To-do"),
02505                                 "UncompletedChildrenPurgeTodos" );
02506     }
02507   }
02508 }
02509 
02510 void CalendarView::warningChangeFailed( Incidence *incidence )
02511 {
02512   if ( incidence ) {
02513     KMessageBox::sorry(
02514       this,
02515       i18n( "Unable to edit \"%1\" because it is locked by another process." ).
02516       arg( incidence->summary() ) );
02517   }
02518 }
02519 
02520 void CalendarView::editCanceled( Incidence *incidence )
02521 {
02522   mCalendar->endChange( incidence );
02523 }
02524 
02525 void CalendarView::showErrorMessage( const QString &msg )
02526 {
02527   KMessageBox::error( this, msg );
02528 }
02529 
02530 void CalendarView::updateCategories()
02531 {
02532   QStringList allCats( calendar()->categories() );
02533   allCats.sort();
02534   QStringList categories( KOPrefs::instance()->mCustomCategories );
02535   for ( QStringList::ConstIterator si = allCats.constBegin(); si != allCats.constEnd(); ++si ) {
02536     if ( categories.find( *si ) == categories.end() ) {
02537       categories.append( *si );
02538     }
02539   }
02540   KOPrefs::instance()->mCustomCategories = categories;
02541   KOPrefs::instance()->writeConfig();
02542   // Make the category editor update the list!
02543   emit categoriesChanged();
02544 }
02545 
02546 void CalendarView::addIncidenceOn( Incidence *incadd, const QDate &dt )
02547 {
02548   if ( !incadd || !mChanger ) {
02549     KMessageBox::sorry(this, i18n("Unable to copy the item to %1.")
02550                        .arg( dt.toString() ), i18n("Copying Failed") );
02551     return;
02552   }
02553   Incidence *incidence = mCalendar->incidence( incadd->uid() );
02554   if ( !incidence ) incidence = incadd;
02555   // Create a copy of the incidence, since the incadd doesn't belong to us.
02556   incidence = incidence->clone();
02557   incidence->recreate();
02558 
02559   if ( incidence->type() == "Event" ) {
02560     Event *event = static_cast<Event*>(incidence);
02561 
02562     // Adjust date
02563     QDateTime start = event->dtStart();
02564     QDateTime end = event->dtEnd();
02565 
02566     int duration = start.daysTo( end );
02567     start.setDate( dt );
02568     end.setDate( dt.addDays( duration ) );
02569 
02570     event->setDtStart( start );
02571     event->setDtEnd( end );
02572 
02573   } else if ( incidence->type() == "Todo" ) {
02574     Todo *todo = static_cast<Todo*>(incidence);
02575     QDateTime due = todo->dtDue();
02576     due.setDate( dt );
02577 
02578     todo->setDtDue( due );
02579     todo->setHasDueDate( true );
02580   }
02581 
02582   QPair<ResourceCalendar *, QString>p = viewSubResourceCalendar();
02583 
02584   if ( !mChanger->addIncidence( incidence, p.first, p.second, this ) ) {
02585     KODialogManager::errorSaveIncidence( this, incidence );
02586     delete incidence;
02587   }
02588 }
02589 
02590 void CalendarView::moveIncidenceTo( Incidence *incmove, const QDate &dt )
02591 {
02592   if ( !incmove || !mChanger ) {
02593     KMessageBox::sorry( this, i18n("Unable to move the item to %1.")
02594                         .arg( dt.toString() ), i18n("Moving Failed") );
02595     return;
02596   }
02597   Incidence *incidence = mCalendar->incidence( incmove->uid() );
02598   if ( !incidence ) {
02599     addIncidenceOn( incidence, dt );
02600     return;
02601   }
02602 
02603   Incidence *oldIncidence = incidence->clone();
02604   QPair<ResourceCalendar *, QString>p = viewSubResourceCalendar();
02605 
02606   if ( !mChanger->beginChange( incidence, p.first, p.second ) ) {
02607     delete oldIncidence;
02608     return;
02609   }
02610 
02611   if ( incidence->type() == "Event" ) {
02612     Event *event = static_cast<Event*>(incidence);
02613 
02614     // Adjust date
02615     QDateTime start = event->dtStart();
02616     QDateTime end = event->dtEnd();
02617 
02618     int duration = start.daysTo( end );
02619     start.setDate( dt );
02620     end.setDate( dt.addDays( duration ) );
02621 
02622     event->setDtStart( start );
02623     event->setDtEnd( end );
02624 
02625   } else if ( incidence->type() == "Todo" ) {
02626     Todo *todo = static_cast<Todo*>(incidence);
02627     QDateTime due = todo->dtDue();
02628     due.setDate( dt );
02629 
02630     todo->setDtDue( due );
02631     todo->setHasDueDate( true );
02632   }
02633   mChanger->changeIncidence( oldIncidence, incidence, KOGlobals::DATE_MODIFIED,this );
02634   mChanger->endChange( incidence, p.first, p.second );
02635   delete oldIncidence;
02636 }
02637 
02638 void CalendarView::resourcesChanged()
02639 {
02640   mViewManager->resourcesChanged();
02641   mDateNavigatorContainer->setUpdateNeeded();
02642   updateView();
02643 }
02644 
02645 Incidence* CalendarView::singleOccurrenceOrAll( Incidence *inc,
02646                                                 KOGlobals::OccurrenceAction userAction,
02647                                                 KOGlobals::WhichOccurrences &chosenOption,
02648                                                 const QDate &itemDate,
02649                                                 const bool commitToCalendar )
02650 {
02651 
02652   // temporary, until recurring to-dos are fixed
02653   if ( inc->type() != "Event" ) {
02654     chosenOption = KOGlobals::ALL;
02655     return inc;
02656   }
02657 
02658   Incidence *incToReturn = 0;
02659   Incidence *incSaved = 0;
02660   KOGlobals::WhatChanged whatChanged;
02661 
02662   bool dissociationOccurred = false;
02663   const QDate &dt = itemDate.isValid() ? itemDate : activeIncidenceDate();
02664 
02665   QString dialogTitle;
02666   QString dialogText;
02667 
02668   if ( userAction == KOGlobals::CUT ) {
02669     dialogTitle = i18n( "Cutting Recurring Item" );
02670 
02671     dialogText = i18n("The item you try to cut is a recurring item. Do you want to cut "
02672                        "only this single occurrence, only future items, "
02673                        "or all items in the recurrence?");
02674 
02675   } else if ( userAction == KOGlobals::COPY ) {
02676     dialogTitle = i18n( "Copying Recurring Item" );
02677 
02678     dialogText = i18n("The item you try to copy is a recurring item. Do you want to copy "
02679                        "only this single occurrence, only future items, "
02680                        "or all items in the recurrence?");
02681   } else {
02682     dialogTitle = i18n( "Changing Recurring Item" );
02683 
02684     dialogText = i18n( "The item you try to change is a recurring item. Shall the changes "
02685                        "be applied only to this single occurrence, only to the future items, "
02686                        "or to all items in the recurrence?" );
02687   }
02688 
02689   int res = KOMessageBox::fourBtnMsgBox( this, QMessageBox::Question,
02690             dialogText,
02691             dialogTitle,
02692             i18n("Only &This Item"), i18n("Only &Future Items"), i18n("&All Occurrences") );
02693   switch ( res ) {
02694     case KMessageBox::Ok: // All occurrences
02695       incToReturn = inc;
02696       chosenOption = KOGlobals::ALL;
02697       break;
02698     case KMessageBox::Yes: { // Just this occurrence
02699       // Dissociate this occurrence:
02700       // create clone of event, set relation to old event, set cloned event
02701       // for mActionItem, add exception date to old event, changeIncidence
02702       // for the old event, remove the recurrence from the new copy and then just
02703       // go on with the newly adjusted mActionItem and let the usual code take
02704       // care of the new time!
02705 
02706       chosenOption = KOGlobals::ONLY_THIS_ONE;
02707       whatChanged  = KOGlobals::RECURRENCE_MODIFIED_ONE_ONLY;
02708       startMultiModify( i18n("Dissociate event from recurrence") );
02709       incSaved = inc->clone();
02710       incToReturn = mCalendar->dissociateOccurrence( inc, dt );
02711       if ( incToReturn ) {
02712         dissociationOccurred = true;
02713       } else {
02714         KMessageBox::sorry( this, i18n("Unable to add the exception item to the "
02715             "calendar. No change will be done."), i18n("Error Occurred") );
02716         incToReturn = 0;
02717       }
02718 
02719       break; }
02720     case KMessageBox::No/*Future*/: { // All future occurrences
02721       // Dissociate this occurrence:
02722       // create clone of event, set relation to old event, set cloned event
02723       // for mActionItem, add recurrence end date to old event, changeIncidence
02724       // for the old event, adjust the recurrence for the new copy and then just
02725       // go on with the newly adjusted mActionItem and let the usual code take
02726       // care of the new time!
02727       chosenOption = KOGlobals::ONLY_FUTURE;
02728       whatChanged  = KOGlobals::RECURRENCE_MODIFIED_ALL_FUTURE;
02729       startMultiModify( i18n("Split future recurrences") );
02730       incSaved = inc->clone();
02731       incToReturn = mCalendar->dissociateOccurrence( inc, dt, false );
02732       if ( incToReturn ) {
02733         dissociationOccurred = true;
02734       } else {
02735         KMessageBox::sorry( this, i18n("Unable to add the future items to the "
02736             "calendar. No change will be done."), i18n("Error Occurred") );
02737 
02738         incToReturn = 0;
02739       }
02740 
02741       break; }
02742     default:
02743       chosenOption = KOGlobals::NONE;
02744   }
02745 
02746   if ( dissociationOccurred && commitToCalendar ) {
02747     QPair<ResourceCalendar *, QString>p = viewSubResourceCalendar();
02748     mChanger->addIncidence( incToReturn, p.first, p.second, this );
02749     mChanger->changeIncidence( incSaved, inc, whatChanged, this );
02750   }
02751 
02752   return incToReturn;
02753 }
02754 
02755 void CalendarView::selectWeek( const QDate &date )
02756 {
02757   if ( KOPrefs::instance()->mWeekNumbersShowWork    &&
02758        mViewManager->agendaIsSelected()             &&
02759        mViewManager->agendaMode()  == KOViewManager::AGENDA_WORK_WEEK ) {
02760     mDateNavigator->selectWorkWeek( date );
02761   } else {
02762     mDateNavigator->selectWeek( date );
02763   }
02764 }
02765 
02766 void CalendarView::getIncidenceHierarchy( Incidence *inc,
02767                                           Incidence::List &children )
02768 {
02769   // protecion against looping hierarchies
02770   if ( inc && !children.contains( inc ) ) {
02771     Incidence::List::ConstIterator it;
02772     Incidence::List immediateChildren = inc->relations();
02773     for ( it = immediateChildren.constBegin(); it != immediateChildren.constEnd(); ++it ) {
02774       getIncidenceHierarchy( *it, children );
02775     }
02776     children.append( inc );
02777   }
02778 }
02779 
02780 #include "calendarview.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys