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