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