korganizer

calendarview.cpp

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