/*
  This file is part of KOrganizer.

  Copyright (c) 1997, 1998, 1999 Preston Brown <preston.brown@yale.edu>
  Fester Zigterman <F.J.F.ZigtermanRustenburg@student.utwente.nl>
  Ian Dawes <iadawes@globalserve.net>
  Laszlo Boloni <boloni@cs.purdue.edu>

  Copyright (C) 2000-2004 Cornelius Schumacher <schumacher@kde.org>
  Copyright (C) 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
  Copyright (C) 2005 Rafal Rzepecki <divide@users.sourceforge.net>

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License along
  with this program; if not, write to the Free Software Foundation, Inc.,
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

  As a special exception, permission is given to link this program
  with any edition of Qt, and distribute the resulting executable,
  without including the source code for Qt in the source distribution.
*/

#include "calendarview.h"
#include "datechecker.h"
#include "datenavigator.h"
#include "datenavigatorcontainer.h"
#include "dialog/exportwebdialog.h"
#include "kocorehelper.h"
#include "kodaymatrix.h"
#include "kodialogmanager.h"
#include "dialog/koeventviewerdialog.h"
#include "koglobals.h"
#include "kohelper.h"
#include "prefs/koprefs.h"
#include "koviewmanager.h"
#include "htmlexportsettings.h"
#include "widgets/navigatorbar.h"
#include "views/agendaview/koagendaview.h"
#include "views/monthview/monthview.h"
#include "views/multiagendaview/multiagendaview.h"
#include "views/todoview/kotodoview.h"
#include "kocheckableproxymodel.h"
#include "akonadicollectionview.h"
#include <incidenceeditor-ng/globalsettings.h>

#include <KHolidays/Holidays>

#include <calendarsupport/collectiongeneralpage.h>
#include <calendarsupport/collectionselection.h>
#include <calendarsupport/kcalprefs.h>
#include <calendarsupport/utils.h>
#include <calendarsupport/next/incidenceviewer.h>
#include <calendarsupport/printing/calprinter.h>
#include <calendarsupport/calendarsingleton.h>

#include <incidenceeditor-ng/incidencedefaults.h>
#include <incidenceeditor-ng/incidencedialog.h>
#include <incidenceeditor-ng/incidencedialogfactory.h>

#include <libkdepim/widgets/pimmessagebox.h>
#include <akonadi/calendar/freebusymanager.h>
#include <akonadi/calendar/history.h>
#include <Akonadi/Calendar/IncidenceChanger>
#include <Akonadi/Calendar/CalendarSettings>
#include <Akonadi/Calendar/CalendarClipboard>

#include <pimcommon/acl/collectionaclpage.h>
#include <pimcommon/acl/imapaclattribute.h>

#include <Akonadi/CollectionPropertiesDialog>
#include <Akonadi/Control>
#include <Akonadi/AttributeFactory>
#include <Akonadi/Calendar/TodoPurger>

#include <KCalCore/CalFilter>
#include <KCalCore/FileStorage>
#include <KCalCore/ICalFormat>
#include <KCalCore/VCalFormat>

#include <KCalUtils/ICalDrag>
#include <KCalUtils/Stringify>
#include <KCalUtils/DndFactory>


#include <KFileDialog>
#include <KNotification>
#include <KRun>
#include <KVBox>

#include <QApplication>
#include <QClipboard>
#include <QSplitter>
#include <QStackedWidget>
#include <QVBoxLayout>

CalendarView::CalendarView( QWidget *parent ) : CalendarViewBase( parent ),
                                                mCheckableProxyModel( 0 ),
                                                mETMCollectionView( 0 )
{
  Akonadi::Control::widgetNeedsAkonadi( this );
  mChanger = new Akonadi::IncidenceChanger( this );
  mChanger->setDefaultCollection( Akonadi::Collection( CalendarSupport::KCalPrefs::instance()->defaultCalendarId() ) );

  mChanger->setDestinationPolicy( static_cast<Akonadi::IncidenceChanger::DestinationPolicy>( KOPrefs::instance()->destination() ) );

  // We reuse the EntityTreeModel from the calendar singleton to save memory.
  // We don't reuse the entire ETMCalendar because we want a different selection model. Checking/unchecking
  // calendars in korganizer shouldn't affect kontact's summary view
  mCalendar = Akonadi::ETMCalendar::Ptr( new Akonadi::ETMCalendar( CalendarSupport::calendarSingleton().data() ) );

  mCalendar->setObjectName( QLatin1String("KOrg Calendar") );
  mCalendarClipboard = new Akonadi::CalendarClipboard( mCalendar, mChanger, this );
  mITIPHandler = new Akonadi::ITIPHandler( this );
  mITIPHandler->setCalendar( mCalendar );
  connect( mCalendarClipboard, SIGNAL(cutFinished(bool,QString)), SLOT(onCutFinished()) );

  Akonadi::AttributeFactory::registerAttribute<PimCommon::ImapAclAttribute>();

  mViewManager = new KOViewManager( this );
  mDialogManager = new KODialogManager( this );
  mTodoPurger = new Akonadi::TodoPurger( this );
  mTodoPurger->setCalendar( mCalendar );
  mTodoPurger->setIncidenceChager( mChanger );
  connect(mTodoPurger, SIGNAL(todosPurged(bool,int,int)),
          SLOT(onTodosPurged(bool,int,int)));

  mReadOnly = false;
  mSplitterSizesValid = false;

  mCalPrinter = 0;

  mDateNavigator = new DateNavigator( this );
  mDateChecker = new DateChecker( this );

  QVBoxLayout *topLayout = new QVBoxLayout( this );
  topLayout->setMargin( 0 );

  // create the main layout frames.
  mPanner = new QSplitter( Qt::Horizontal, this );
  mPanner->setObjectName( QLatin1String("CalendarView::Panner") );
  topLayout->addWidget( mPanner );

  mLeftSplitter = new QSplitter( Qt::Vertical, mPanner );
  mLeftSplitter->setObjectName( QLatin1String("CalendarView::LeftFrame") );
  // The GUI checkboxes of "show widget XYZ" are confusing when the QSplitter
  // hides the widget magically. I know I blamed Akonadi for not showing my
  // calendar more than once.
  mLeftSplitter->setChildrenCollapsible( false );

  mDateNavigatorContainer = new DateNavigatorContainer( mLeftSplitter );
  mDateNavigatorContainer->setObjectName( QLatin1String("CalendarView::DateNavigator") );

  mTodoList = new KOTodoView( true/*sidebar*/, mLeftSplitter );
  mTodoList->setObjectName(QLatin1String( "todolist") );

  mEventViewerBox = new KVBox( mLeftSplitter );
  mEventViewerBox->setMargin( 0 );
  mEventViewer = new CalendarSupport::IncidenceViewer( mCalendar.data(), mEventViewerBox );
  mEventViewer->setObjectName( QLatin1String("EventViewer") );

  KVBox *rightBox = new KVBox( mPanner );
  rightBox->layout()->setMargin( 0 );
  mNavigatorBar = new NavigatorBar( rightBox );
  mRightFrame = new QStackedWidget( rightBox );
  mMessageWidget = new CalendarSupport::MessageWidget( rightBox );

  rightBox->setStretchFactor( mRightFrame, 1 );

  mLeftFrame = mLeftSplitter;
  mLeftFrame->installEventFilter( this );

  mChanger->setGroupwareCommunication( CalendarSupport::KCalPrefs::instance()->useGroupwareCommunication() );
  connect( mChanger,
           SIGNAL(createFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
           SLOT(slotCreateFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) );

  connect( mChanger,
           SIGNAL(deleteFinished(int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)),
           SLOT(slotDeleteFinished(int,QVector<Akonadi::Item::Id>,Akonadi::IncidenceChanger::ResultCode,QString)) );

  connect( mChanger,
           SIGNAL(modifyFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)),
           SLOT(slotModifyFinished(int,Akonadi::Item,Akonadi::IncidenceChanger::ResultCode,QString)) );

  // Signals emitted by mDateNavigator
  connect( mDateNavigator, SIGNAL(datesSelected(KCalCore::DateList,QDate)),
           SLOT(showDates(KCalCore::DateList,QDate)) );

  connect( mDateNavigatorContainer, SIGNAL(newEventSignal(QDate)),
           SLOT(newEvent(QDate)) );
  connect( mDateNavigatorContainer, SIGNAL(newTodoSignal(QDate)),
           SLOT(newTodo(QDate)) );
  connect( mDateNavigatorContainer, SIGNAL(newJournalSignal(QDate)),
           SLOT(newJournal(QDate)) );

  // Signals emitted by mNavigatorBar
  connect( mNavigatorBar, SIGNAL(prevYearClicked()),
           mDateNavigator, SLOT(selectPreviousYear()) );
  connect( mNavigatorBar, SIGNAL(nextYearClicked()),
           mDateNavigator, SLOT(selectNextYear()) );
  connect( mNavigatorBar, SIGNAL(prevMonthClicked()),
           mDateNavigator, SLOT(selectPreviousMonth()) );
  connect( mNavigatorBar, SIGNAL(nextMonthClicked()),
           mDateNavigator, SLOT(selectNextMonth()) );
  connect( mNavigatorBar, SIGNAL(monthSelected(int)),
           mDateNavigator, SLOT(selectMonth(int)) );
  connect( mNavigatorBar, SIGNAL(yearSelected(int)),
           mDateNavigator, SLOT(selectYear(int)) );

  // Signals emitted by mDateNavigatorContainer
  connect( mDateNavigatorContainer, SIGNAL(weekClicked(QDate,QDate)),
           SLOT(selectWeek(QDate,QDate)) );

  connect( mDateNavigatorContainer, SIGNAL(prevMonthClicked(QDate,QDate,QDate)),
           mDateNavigator, SLOT(selectPreviousMonth(QDate,QDate,QDate)) );
  connect( mDateNavigatorContainer, SIGNAL(nextMonthClicked(QDate,QDate,QDate)),
           mDateNavigator, SLOT(selectNextMonth(QDate,QDate,QDate)) );
  connect( mDateNavigatorContainer, SIGNAL(prevYearClicked()),
           mDateNavigator, SLOT(selectPreviousYear()) );
  connect( mDateNavigatorContainer, SIGNAL(nextYearClicked()),
           mDateNavigator, SLOT(selectNextYear()) );
  connect( mDateNavigatorContainer, SIGNAL(monthSelected(int)),
           mDateNavigator, SLOT(selectMonth(int)) );
  connect( mDateNavigatorContainer, SIGNAL(yearSelected(int)),
           mDateNavigator, SLOT(selectYear(int)) );
  connect( mDateNavigatorContainer, SIGNAL(goPrevious()),
           mDateNavigator, SLOT(selectPrevious()) );
  connect( mDateNavigatorContainer, SIGNAL(goNext()),
           mDateNavigator, SLOT(selectNext()) );

  connect( mDateNavigatorContainer, SIGNAL(datesSelected(KCalCore::DateList,QDate)),
           mDateNavigator, SLOT(selectDates(KCalCore::DateList,QDate)) );

  connect( mViewManager, SIGNAL(datesSelected(KCalCore::DateList)),
           mDateNavigator, SLOT(selectDates(KCalCore::DateList)) );

  connect( mDateNavigatorContainer, SIGNAL(incidenceDropped(Akonadi::Item,QDate)),
           SLOT(addIncidenceOn(Akonadi::Item,QDate)) );
  connect( mDateNavigatorContainer, SIGNAL(incidenceDroppedMove(Akonadi::Item,QDate)),
           SLOT(moveIncidenceTo(Akonadi::Item,QDate)) );

  connect( mDateChecker, SIGNAL(dayPassed(QDate)),
           mTodoList, SLOT(dayPassed(QDate)) );
  connect( mDateChecker, SIGNAL(dayPassed(QDate)),
           SIGNAL(dayPassed(QDate)) );
  connect( mDateChecker, SIGNAL(dayPassed(QDate)),
           mDateNavigatorContainer, SLOT(updateToday()) );

  connect( this, SIGNAL(configChanged()),
           mDateNavigatorContainer, SLOT(updateConfig()) );

  connect( this, SIGNAL(incidenceSelected(Akonadi::Item,QDate)),
           mEventViewer, SLOT(setIncidence(Akonadi::Item,QDate)) );

  //TODO: do a pretty Summary,
  QString s;
  s = i18n( "<p><em>No Item Selected</em></p>"
            "<p>Select an event, to-do or journal entry to view its details "
            "here.</p>" );

  mEventViewer->setDefaultMessage( s );
  mEventViewer->setWhatsThis(
                   i18n( "View the details of events, journal entries or to-dos "
                         "selected in KOrganizer's main view here." ) );
  mEventViewer->setIncidence( Akonadi::Item(), QDate() );

  mViewManager->connectTodoView( mTodoList );
  mViewManager->connectView( mTodoList );

  KOGlobals::self()->setHolidays( new KHolidays::HolidayRegion( KOPrefs::instance()->mHolidays ) );

  connect( QApplication::clipboard(), SIGNAL(dataChanged()), SLOT(checkClipboard()) );

  connect( mTodoList, SIGNAL(incidenceSelected(Akonadi::Item,QDate)),
           this, SLOT(processTodoListSelection(Akonadi::Item,QDate)) );
  disconnect( mTodoList, SIGNAL(incidenceSelected(Akonadi::Item,QDate)),
              this, SLOT(processMainViewSelection(Akonadi::Item,QDate)) );

  {
    static bool pageRegistered = false;

    if ( !pageRegistered ) {
      Akonadi::CollectionPropertiesDialog::registerPage(
        new CalendarSupport::CollectionGeneralPageFactory );
      Akonadi::CollectionPropertiesDialog::registerPage( new PimCommon::CollectionAclPageFactory );
      pageRegistered = true;
    }
  }

  Akonadi::FreeBusyManager::self()->setCalendar( mCalendar );

  mCalendar->registerObserver( this );
  mDateNavigatorContainer->setCalendar( mCalendar );
  mTodoList->setCalendar( mCalendar );
  mEventViewer->setCalendar( mCalendar.data() );
}

CalendarView::~CalendarView()
{
  mCalendar->unregisterObserver( this );
  mCalendar->setFilter( 0 ); // So calendar doesn't deleted it twice
  qDeleteAll( mFilters );
  qDeleteAll( mExtensions );

  delete mDialogManager;
  delete mViewManager;
  delete mEventViewer;
}

Akonadi::ETMCalendar::Ptr CalendarView::calendar() const
{
  return mCalendar;
}

QDate CalendarView::activeDate( bool fallbackToToday )
{
  KOrg::BaseView *curView = mViewManager->currentView();
  if ( curView ) {
    if ( curView->selectionStart().isValid() ) {
      return curView->selectionStart().date();
    }

    // Try the view's selectedIncidenceDates()
    if ( !curView->selectedIncidenceDates().isEmpty() ) {
      if ( curView->selectedIncidenceDates().first().isValid() ) {
        return curView->selectedIncidenceDates().first();
      }
    }
  }

  // When all else fails, use the navigator start date, or today.
  if ( fallbackToToday ) {
    return QDate::currentDate();
  } else {
    return mDateNavigator->selectedDates().first();
  }
}

QDate CalendarView::activeIncidenceDate()
{
  KOrg::BaseView *curView = mViewManager->currentView();
  if ( curView ) {
    KCalCore::DateList dates = curView->selectedIncidenceDates();
    if ( !dates.isEmpty() ) {
      return dates.first();
    }
  }

  return QDate();
}

QDate CalendarView::startDate()
{
  KCalCore::DateList dates = mDateNavigator->selectedDates();
  return dates.first();
}

QDate CalendarView::endDate()
{
  KCalCore::DateList dates = mDateNavigator->selectedDates();
  return dates.last();
}

void CalendarView::createPrinter()
{
  if ( !mCalPrinter ) {
    mCalPrinter = new CalendarSupport::CalPrinter( this, mCalendar );
    connect( this, SIGNAL(configChanged()), mCalPrinter, SLOT(updateConfig()) );
  }
}

bool CalendarView::saveCalendar( const QString &filename )
{
  // Store back all unsaved data into calendar object
  mViewManager->currentView()->flushView();

  KCalCore::FileStorage storage( mCalendar );
  storage.setFileName( filename );
  storage.setSaveFormat( new KCalCore::ICalFormat );

  return storage.save();
}

void CalendarView::archiveCalendar()
{
  mDialogManager->showArchiveDialog();
}

void CalendarView::readSettings()
{
  QString str;

  // read settings from the KConfig, supplying reasonable
  // defaults where none are to be found

  KConfig *config = KOGlobals::self()->config();

  KConfigGroup geometryConfig( config, "KOrganizer Geometry" );

  QList<int> sizes = geometryConfig.readEntry( "Separator1",QList<int>() );
  if ( sizes.count() != 2 || sizes.count() == sizes.count( 0 ) ) {
    sizes << mDateNavigatorContainer->minimumSizeHint().width();
    sizes << 300;
  }
  mPanner->setSizes( sizes );

  sizes = geometryConfig.readEntry( "Separator2", QList<int>() );
  if ( !sizes.isEmpty() && sizes.count() != sizes.count( 0 ) ) {
     mLeftSplitter->setSizes( sizes );
  }

  mViewManager->readSettings( config );
  mTodoList->restoreLayout( config, QLatin1String( "Sidebar Todo View" ), true );

  readFilterSettings( config );

  KConfigGroup viewConfig( config, "Views" );
  int dateCount = viewConfig.readEntry( "ShownDatesCount", 7 );
  if ( dateCount == 7 ) {
    mDateNavigator->selectWeek();
  } else {
    mDateNavigator->selectDates( mDateNavigator->selectedDates().first(), dateCount );
  }
}

void CalendarView::writeSettings()
{
  KConfig *config = KOGlobals::self()->config();

  KConfigGroup geometryConfig( config, "KOrganizer Geometry" );

  QList<int> list = mMainSplitterSizes.isEmpty() ? mPanner->sizes() : mMainSplitterSizes;
  // splitter sizes are invalid (all zero) unless we have been shown once
  if ( list.count() != list.count( 0 ) && mSplitterSizesValid ) {
    geometryConfig.writeEntry( "Separator1", list );
  }

  list = mLeftSplitter->sizes();
  if ( list.count() != list.count( 0 ) && mSplitterSizesValid ) {
    geometryConfig.writeEntry( "Separator2", list );
  }

  mViewManager->writeSettings( config );
  mTodoList->saveLayout( config, QLatin1String( "Sidebar Todo View" ) );

  Akonadi::CalendarSettings::self()->writeConfig();
  KOPrefs::instance()->writeConfig();
  CalendarSupport::KCalPrefs::instance()->writeConfig();

  writeFilterSettings( config );

  KConfigGroup viewConfig( config, "Views" );
  viewConfig.writeEntry( "ShownDatesCount", mDateNavigator->selectedDates().count() );

  config->sync();
}

void CalendarView::readFilterSettings( KConfig *config )
{
  qDeleteAll( mFilters );
  mFilters.clear();

  KConfigGroup generalConfig( config, "General" );
  // FIXME: Move the filter loading and saving to the CalFilter class in libkcal
  QStringList filterList = generalConfig.readEntry( "CalendarFilters", QStringList() );
  QString currentFilter = generalConfig.readEntry( "Current Filter" );

  QStringList::ConstIterator it = filterList.constBegin();
  QStringList::ConstIterator end = filterList.constEnd();
  while ( it != end ) {
    KCalCore::CalFilter *filter = new KCalCore::CalFilter( *it );
    KConfigGroup filterConfig( config, QLatin1String("Filter_") + (*it) );
    filter->setCriteria( filterConfig.readEntry( "Criteria", 0 ) );
    filter->setCategoryList( filterConfig.readEntry( "CategoryList", QStringList() ) );
    if ( filter->criteria() & KCalCore::CalFilter::HideNoMatchingAttendeeTodos ) {
      filter->setEmailList( CalendarSupport::KCalPrefs::instance()->allEmails() );
    }
    filter->setCompletedTimeSpan( filterConfig.readEntry( "HideTodoDays", 0 ) );
    mFilters.append( filter );

    ++it;
  }

  int pos = filterList.indexOf( currentFilter );
  mCurrentFilter = 0;
  if ( pos >= 0 ) {
    mCurrentFilter = mFilters.at( pos );
  }
  updateFilter();
}

void CalendarView::writeFilterSettings( KConfig *config )
{
  QStringList filterList;

  const QStringList oldFilterList = config->groupList().filter( QRegExp( QLatin1String("^Filter_.*") ) );
  //Delete Old Group
  Q_FOREACH (const QString &conf, oldFilterList) {
      KConfigGroup group = config->group(conf);
      group.deleteGroup();
  }


  foreach ( KCalCore::CalFilter *filter, mFilters ) {
    filterList << filter->name();
    KConfigGroup filterConfig( config, QLatin1String("Filter_") + filter->name() );
    filterConfig.writeEntry( "Criteria", filter->criteria() );
    filterConfig.writeEntry( "CategoryList", filter->categoryList() );
    filterConfig.writeEntry( "HideTodoDays", filter->completedTimeSpan() );
  }
  KConfigGroup generalConfig( config, "General" );
  generalConfig.writeEntry( "CalendarFilters", filterList );
  if ( mCurrentFilter ) {
    generalConfig.writeEntry( "Current Filter", mCurrentFilter->name() );
  } else {
    generalConfig.writeEntry( "Current Filter", QString() );
  }
}

void CalendarView::goDate( const QDate &date )
{
  mDateNavigator->selectDate( date );
}

void CalendarView::showDate( const QDate &date )
{
  int dateCount = mDateNavigator->datesCount();
  if ( dateCount == 7 ) {
    mDateNavigator->selectWeek( date );
  } else {
    mDateNavigator->selectDates( date, dateCount );
  }
}

void CalendarView::goToday()
{
  mDateNavigator->selectToday();
}

void CalendarView::goNext()
{
  if ( dynamic_cast<MonthView*>( mViewManager->currentView() ) ) {
    const QDate month = mDateNavigatorContainer->monthOfNavigator( 0 );
    QPair<QDate,QDate> limits = KODayMatrix::matrixLimits( month );
    mDateNavigator->selectNextMonth( month, limits.first, limits.second );
  } else {
    mDateNavigator->selectNext();
  }
}

void CalendarView::goPrevious()
{
  if ( dynamic_cast<MonthView*>( mViewManager->currentView() ) ) {
    const QDate month = mDateNavigatorContainer->monthOfNavigator( 0 );
    QPair<QDate,QDate> limits = KODayMatrix::matrixLimits( month );
    mDateNavigator->selectPreviousMonth( month, limits.first, limits.second );
  } else {
    mDateNavigator->selectPrevious();
  }
}

void CalendarView::updateConfig()
{
  updateConfig( QByteArray( "korganizer" ) );
}

void CalendarView::updateConfig( const QByteArray &receiver )
{
  if ( receiver != "korganizer" ) {
    return;
  }

  if ( mCalPrinter ) {
    mCalPrinter->deleteLater();
    mCalPrinter = 0;
  }

  KOGlobals::self()->setHolidays( new KHolidays::HolidayRegion( KOPrefs::instance()->mHolidays ) );

  // Only set a new time zone if it changed. This prevents the window
  // from being modified on start
  KDateTime::Spec newTimeSpec = CalendarSupport::KCalPrefs::instance()->timeSpec();
  if ( mCalendar->viewTimeSpec() != newTimeSpec ) {

    const QString question( i18n( "The time zone setting was changed. "
                                  "Do you want to keep the absolute time of "
                                  "the items in your calendar, which will show "
                                  "them to be at a different time than "
                                  "before, or move them to be at the old time "
                                  "also in the new time zone?" ) );
    int rc = KMessageBox::questionYesNo( this, question,
                                         i18n( "Keep Absolute Times?" ),
                                         KGuiItem( i18n( "Keep Times" ) ),
                                         KGuiItem( i18n( "Move Times" ) ),
                                         QLatin1String("calendarKeepAbsoluteTimes") );
    if ( rc == KMessageBox::Yes ) {
      // keep the absolute time - note the new viewing time zone in the calendar
      mCalendar->setViewTimeSpec( newTimeSpec );
    } else {
      // only set the new timezone, wihtout shifting events, they will be
      // interpreted as being in the new timezone now
      mCalendar->shiftTimes( mCalendar->viewTimeSpec(), newTimeSpec );
    }
  }

  // config changed lets tell the date navigator the new modes
  // if there weren't changed they are ignored
  updateHighlightModes();

  emit configChanged();

  //switch beetween merged, side by side and tabbed agenda if needed
  mViewManager->updateMultiCalendarDisplay();

  // To make the "fill window" configurations work
  mViewManager->raiseCurrentView();

  mChanger->setDestinationPolicy(
    static_cast<Akonadi::IncidenceChanger::DestinationPolicy>(
      KOPrefs::instance()->destination() ) );

  mChanger->setGroupwareCommunication( CalendarSupport::KCalPrefs::instance()->useGroupwareCommunication() );
}

void CalendarView::slotCreateFinished( int changeId,
                                       const Akonadi::Item &item,
                                       Akonadi::IncidenceChanger::ResultCode resultCode,
                                       const QString &errorString )
{
  Q_UNUSED( changeId );
  if ( resultCode == Akonadi::IncidenceChanger::ResultCodeSuccess ) {
    changeIncidenceDisplay( item, Akonadi::IncidenceChanger::ChangeTypeCreate );
    updateUnmanagedViews();
    checkForFilteredChange( item );
  } else if (!errorString.isEmpty()){
    kError() << "Incidence not added, job reported error: " << errorString;
  }
}

void CalendarView::slotModifyFinished( int changeId,
                                       const Akonadi::Item &item,
                                       Akonadi::IncidenceChanger::ResultCode resultCode,
                                       const QString &errorString )
{
  Q_UNUSED( changeId );
  if ( resultCode != Akonadi::IncidenceChanger::ResultCodeSuccess ) {
    kError() << "Incidence not modified, job reported error: " << errorString;
    return;
  }

  Q_ASSERT( item.isValid() );
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  Q_ASSERT( incidence );
  QSet<KCalCore::IncidenceBase::Field> dirtyFields = incidence->dirtyFields();
  incidence->resetDirtyFields();
  // Record completed todos in journals, if enabled. we should to this here in
  // favor of the todolist. users can mark a task as completed in an editor
  // as well.
  if ( incidence->type() == KCalCore::Incidence::TypeTodo &&
       KOPrefs::instance()->recordTodosInJournals() &&
       ( dirtyFields.contains( KCalCore::Incidence::FieldCompleted ) ) ) {
    KCalCore::Todo::Ptr todo = incidence.dynamicCast<KCalCore::Todo>();
    if ( todo->isCompleted() || todo->recurs() ) {
      QString timeStr = KGlobal::locale()->formatTime( QTime::currentTime() );
      QString description = i18n( "Todo completed: %1 (%2)", incidence->summary(), timeStr );

      KCalCore::Journal::List journals = calendar()->journals( QDate::currentDate() );

      if ( journals.isEmpty() ) {
        KCalCore::Journal::Ptr journal( new KCalCore::Journal );
        journal->setDtStart(
          KDateTime::currentDateTime( CalendarSupport::KCalPrefs::instance()->timeSpec() ) );

        QString dateStr = KGlobal::locale()->formatDate( QDate::currentDate() );
        journal->setSummary( i18n( "Journal of %1", dateStr ) );
        journal->setDescription( description );

        if ( mChanger->createIncidence( journal, item.parentCollection(), this ) == -1 ) {
          kError() << "Unable to add Journal";
          return;
        }

      } else { // journal list is not empty
        Akonadi::Item journalItem = mCalendar->item( journals.first()->uid() );
        KCalCore::Journal::Ptr journal = CalendarSupport::journal( journalItem );
        KCalCore::Journal::Ptr oldJournal( journal->clone() );
        journal->setDescription( journal->description().append( QLatin1Char('\n') + description ) );
        mChanger->modifyIncidence( journalItem, oldJournal, this );

      }
    }
  }

  changeIncidenceDisplay( item, Akonadi::IncidenceChanger::ChangeTypeCreate );
  updateUnmanagedViews();
  checkForFilteredChange( item );
}

void CalendarView::slotDeleteFinished( int changeId,
                                       const QVector<Akonadi::Item::Id> &itemIdList,
                                       Akonadi::IncidenceChanger::ResultCode resultCode,
                                       const QString &errorString )
{
  Q_UNUSED( changeId );
  if ( resultCode == Akonadi::IncidenceChanger::ResultCodeSuccess ) {
    foreach( Akonadi::Item::Id id, itemIdList ) {
      Akonadi::Item item = mCalendar->item( id );
      if ( item.isValid() )
        changeIncidenceDisplay( item, Akonadi::IncidenceChanger::ChangeTypeDelete );
    }
    updateUnmanagedViews();
  } else {
    kError() << "Incidence not deleted, job reported error: " << errorString;
  }
}

void CalendarView::checkForFilteredChange( const Akonadi::Item &item )
{
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  KCalCore::CalFilter *filter = calendar()->filter();
  if ( filter && !filter->filterIncidence( incidence ) ) {
    // Incidence is filtered and thus not shown in the view, tell the
    // user so that he isn't surprised if his new event doesn't show up
    mMessageWidget->setText( i18n( "The item \"%1\" is filtered by your current filter rules, "
                                   "so it will be hidden and not appear in the view.",
                                   incidence->summary() ) );
    mMessageWidget->show();
  }
}

void CalendarView::startMultiModify( const QString &text )
{
  mChanger->startAtomicOperation( text );
}

void CalendarView::endMultiModify()
{
  mChanger->endAtomicOperation();
}

void CalendarView::changeIncidenceDisplay( const Akonadi::Item &item,
                                           Akonadi::IncidenceChanger::ChangeType changeType )
{
  if ( mDateNavigatorContainer->isVisible() ) {
    mDateNavigatorContainer->updateView();
  }

  mDialogManager->updateSearchDialog();

  if ( CalendarSupport::hasIncidence( item ) ) {
    // If there is an event view visible update the display
    mViewManager->currentView()->changeIncidenceDisplay( item, changeType );
  } else {
    mViewManager->currentView()->updateView();
  }
}

void CalendarView::updateView( const QDate &start, const QDate &end,
                               const QDate &preferredMonth,
                               const bool updateTodos )
{
  const bool currentViewIsTodoView = mViewManager->currentView()->identifier() == "DefaultTodoView";

  if ( updateTodos && !currentViewIsTodoView && mTodoList->isVisible() ) {
    // Update the sidepane todoView
    mTodoList->updateView();
  }

  if ( start.isValid() && end.isValid() && !( currentViewIsTodoView && !updateTodos ) ) {
    mViewManager->updateView( start, end, preferredMonth );
  }

  if ( mDateNavigatorContainer->isVisible() ) {
    mDateNavigatorContainer->updateView();
  }
}

void CalendarView::updateView()
{
  const KCalCore::DateList tmpList = mDateNavigator->selectedDates();
  const QDate month = mDateNavigatorContainer->monthOfNavigator();

  // We assume that the navigator only selects consecutive days.
  updateView( tmpList.first(), tmpList.last(), month/**preferredMonth*/ );
}

void CalendarView::updateUnmanagedViews()
{
  if ( mDateNavigatorContainer->isVisible() ) {
    mDateNavigatorContainer->updateDayMatrix();
  }
}

int CalendarView::msgItemDelete( const Akonadi::Item &item )
{
  return KMessageBox::warningContinueCancel(
    this,
    i18nc( "@info",
           "Do you really want to permanently remove the item \"%1\"?",
           CalendarSupport::incidence( item )->summary() ),
    i18nc( "@title:window", "Delete Item?" ),
    KStandardGuiItem::del() );
}

void CalendarView::edit_cut()
{
  const Akonadi::Item item = selectedIncidence();
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( !incidence ) {
    kError() << "Null incidence";
    return;
  }

  mCalendarClipboard->cutIncidence( incidence, Akonadi::CalendarClipboard::AskMode );
}

void CalendarView::edit_copy()
{
  const Akonadi::Item item = selectedIncidence();

  if ( !item.isValid() ) {
    KNotification::beep();
    kError() << "Invalid item";
    return;
  }

  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  Q_ASSERT( incidence );
  if ( !mCalendarClipboard->copyIncidence( incidence, Akonadi::CalendarClipboard::AskMode ) )
    kError() << "Error copying incidence";

  checkClipboard();
}

void CalendarView::edit_paste()
{
// If in agenda and month view, use the selected time and date from there.
// In all other cases, use the navigator's selected date.

  QDateTime endDT;
  KDateTime finalDateTime;
  bool useEndTime = false;
  KCalUtils::DndFactory::PasteFlags pasteFlags = 0;

  KOrg::BaseView *curView = mViewManager->currentView();
  KOAgendaView *agendaView = mViewManager->agendaView();
  MonthView *monthView = mViewManager->monthView();

  if ( !curView ) {
    kWarning() << "No view is selected, can't paste";
    return;
  }

  if ( curView == agendaView && agendaView->selectionStart().isValid() ) {
    const QDate date = agendaView->selectionStart().date();
    endDT = agendaView->selectionEnd();
    useEndTime = !agendaView->selectedIsSingleCell();
    if ( agendaView->selectedIsAllDay() ) {
      finalDateTime = KDateTime( date );
    } else {
      finalDateTime = KDateTime( date, agendaView->selectionStart().time() );
    }
  } else if ( curView == monthView && monthView->selectionStart().isValid() ) {
    finalDateTime = KDateTime( monthView->selectionStart().date() );
    pasteFlags = KCalUtils::DndFactory::FlagPasteAtOriginalTime;
  } else if ( !mDateNavigator->selectedDates().isEmpty() &&
              curView->supportsDateNavigation() ) {
    // default to the selected date from the navigator
    finalDateTime = KDateTime( mDateNavigator->selectedDates().first() );
    pasteFlags = KCalUtils::DndFactory::FlagPasteAtOriginalTime;
  }

  if ( !finalDateTime.isValid() && curView->supportsDateNavigation() ) {
    KMessageBox::sorry(
      this,
      i18n( "Paste failed: unable to determine a valid target date." ) );
    return;
  }

  KCalUtils::DndFactory factory( mCalendar );

  KCalCore::Incidence::List pastedIncidences = factory.pasteIncidences( finalDateTime, pasteFlags );
  KCalCore::Incidence::List::Iterator it;

  for ( it = pastedIncidences.begin(); it != pastedIncidences.end(); ++it ) {
    // FIXME: use a visitor here
    if ( ( *it )->type() == KCalCore::Incidence::TypeEvent ) {
      KCalCore::Event::Ptr pastedEvent = ( *it ).staticCast<KCalCore::Event>();
      // only use selected area if event is of the same type (all-day or non-all-day
      // as the current selection is
      if ( agendaView && endDT.isValid() && useEndTime ) {
        if ( ( pastedEvent->allDay() && agendaView->selectedIsAllDay() ) ||
             ( !pastedEvent->allDay() && !agendaView->selectedIsAllDay() ) ) {
          KDateTime kdt( endDT, CalendarSupport::KCalPrefs::instance()->timeSpec() );
          pastedEvent->setDtEnd( kdt.toTimeSpec( pastedEvent->dtEnd().timeSpec() ) );
        }
      }

      pastedEvent->setRelatedTo( QString() );
      mChanger->createIncidence( KCalCore::Event::Ptr( pastedEvent->clone() ),
                                 Akonadi::Collection(), this );
    } else if ( ( *it )->type() == KCalCore::Incidence::TypeTodo ) {
      KCalCore::Todo::Ptr pastedTodo = ( *it ).staticCast<KCalCore::Todo>();
      Akonadi::Item _selectedTodoItem = selectedTodo();

      // if we are cutting a hierarchy only the root
      // should be son of _selectedTodo
      KCalCore::Todo::Ptr _selectedTodo = CalendarSupport::todo( _selectedTodoItem );
      if ( _selectedTodo && pastedTodo->relatedTo().isEmpty() ) {
        pastedTodo->setRelatedTo( _selectedTodo->uid() );
      }

      // When pasting multiple incidences, don't ask which collection to use, for each one
      mChanger->createIncidence( KCalCore::Todo::Ptr( pastedTodo->clone() ),
                                 Akonadi::Collection(), this );
    } else if ( ( *it )->type() == KCalCore::Incidence::TypeJournal ) {
      // When pasting multiple incidences, don't ask which collection to use, for each one
      mChanger->createIncidence( KCalCore::Incidence::Ptr( ( *it )->clone() ),
                                 Akonadi::Collection(), this );
    }
  }
}

void CalendarView::edit_options()
{
  mDialogManager->showOptionsDialog();
}

void CalendarView::dateTimesForNewEvent( QDateTime &startDt, QDateTime &endDt,
                                         bool &allDay )
{
  mViewManager->currentView()->eventDurationHint( startDt, endDt, allDay );

  if ( !startDt.isValid() || !endDt.isValid() ) {
    startDt.setDate( activeDate( true ) );
    startDt.setTime( CalendarSupport::KCalPrefs::instance()->mStartTime.time() );

    int addSecs =
      ( CalendarSupport::KCalPrefs::instance()->mDefaultDuration.time().hour() * 3600 ) +
      ( CalendarSupport::KCalPrefs::instance()->mDefaultDuration.time().minute() * 60 );
    endDt = startDt.addSecs( addSecs );
  }
}

IncidenceEditorNG::IncidenceDialog *CalendarView::incidenceDialog(const Akonadi::Item &item)
{
    IncidenceEditorNG::IncidenceDialog *dialog = mDialogManager->createDialog(item);
    connect(dialog, SIGNAL(incidenceCreated(Akonadi::Item)), SLOT(handleIncidenceCreated(Akonadi::Item)));
    return dialog;
}

IncidenceEditorNG::IncidenceDialog *CalendarView::newEventEditor( const KCalCore::Event::Ptr &event )
{
  Akonadi::Item item;
  item.setPayload( event );
  IncidenceEditorNG::IncidenceDialog *dialog = incidenceDialog( item );

  dialog->load( item );

  mDialogManager->connectTypeAhead(
    dialog, qobject_cast<KOEventView*>( viewManager()->currentView() ) );

  return dialog;
}

void CalendarView::newEvent()
{
  newEvent( QDateTime(), QDateTime() );
}

void CalendarView::newEvent( const QDate &dt )
{
  QDateTime startDt( dt, CalendarSupport::KCalPrefs::instance()->mStartTime.time() );
  QTime duration = CalendarSupport::KCalPrefs::instance()->defaultDuration().time();
  QTime time = startDt.time();

  time = time.addSecs( duration.hour() * 3600 +
                        duration.minute() * 60 +
                        duration.second() );
  QDateTime endDt( startDt );
  endDt.setTime( time );
  newEvent( startDt, endDt );
}

void CalendarView::newEvent( const QDateTime &startDt )
{
  newEvent( startDt, startDt );
}

void CalendarView::newEvent( const QDateTime &startDtParam, const QDateTime &endDtParam,
                             bool allDay )
{
  // Let the current view change the default start/end datetime
  QDateTime startDt( startDtParam );
  QDateTime endDt( endDtParam );

  // Adjust the start/end date times (i.e. replace invalid values by defaults,
  // and let the view adjust the type.
  dateTimesForNewEvent( startDt, endDt, allDay );

  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();
  defaults.setStartDateTime( KDateTime( startDt ) );
  defaults.setEndDateTime( KDateTime( endDt ) );

  KCalCore::Event::Ptr event( new KCalCore::Event );
  defaults.setDefaults( event );
  event->setAllDay( allDay );

  IncidenceEditorNG::IncidenceDialog *eventEditor = newEventEditor( event );
  Q_ASSERT( eventEditor );

  // Fallsback to the default collection defined in config
  eventEditor->selectCollection( defaultCollection( KCalCore::Event::eventMimeType() ) );
}

void CalendarView::newEvent( const QString &summary, const QString &description,
                             const QStringList &attachments, const QStringList &attendees,
                             const QStringList &attachmentMimetypes, bool inlineAttachment )
{
  // Adjust the start/end date times (i.e. replace invalid values by defaults,
  // and let the view adjust the type.
  QDateTime startDt;
  QDateTime endDt;
  bool allDay = false;
  dateTimesForNewEvent( startDt, endDt, allDay );

  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();
  defaults.setStartDateTime( KDateTime( startDt ) );
  defaults.setEndDateTime( KDateTime( endDt ) );
  // if attach or attendee list is empty, these methods don't do anything, so
  // it's safe to call them in every case
  defaults.setAttachments( attachments, attachmentMimetypes, QStringList(), inlineAttachment );
  defaults.setAttendees( attendees );

  KCalCore::Event::Ptr event( new KCalCore::Event );
  defaults.setDefaults( event );

  event->setSummary( summary );
  event->setDescription( description );
  event->setAllDay( allDay );
  newEventEditor( event );
}

void CalendarView::newTodo( const QString &summary, const QString &description,
                            const QStringList &attachments, const QStringList &attendees,
                            const QStringList &attachmentMimetypes,
                            bool inlineAttachment )
{
  Akonadi::Collection defaultCol = defaultCollection( KCalCore::Todo::todoMimeType() );

  IncidenceEditorNG::IncidenceDialogFactory::createTodoEditor(
    summary, description, attachments,
    attendees, attachmentMimetypes,
    QStringList()/* attachment labels */,
    inlineAttachment, defaultCol,
    this/* parent */ );
}

void CalendarView::newTodo()
{
  newTodo( Akonadi::Collection() );
}

void CalendarView::newTodo( const Akonadi::Collection &collection )
{
  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();

  bool allDay = true;
  if ( mViewManager->currentView()->isEventView() ) {
    QDateTime startDt;
    QDateTime endDt;
    dateTimesForNewEvent( startDt, endDt, allDay );

    defaults.setStartDateTime( KDateTime( startDt ) );
    defaults.setEndDateTime( KDateTime( endDt ) );
  }

  KCalCore::Todo::Ptr todo( new KCalCore::Todo );
  defaults.setDefaults( todo );
  todo->setAllDay( allDay );

  Akonadi::Item item;
  item.setPayload( todo );

  IncidenceEditorNG::IncidenceDialog *dialog = createIncidenceEditor( item, collection );

  dialog->load( item );
}

void CalendarView::newTodo( const QDate &date )
{
  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();
  defaults.setEndDateTime( KDateTime( date, QTime::currentTime() ) );

  KCalCore::Todo::Ptr todo( new KCalCore::Todo );
  defaults.setDefaults( todo );
  todo->setAllDay( true );

  Akonadi::Item item;
  item.setPayload( todo );

  IncidenceEditorNG::IncidenceDialog *dialog = createIncidenceEditor( item );
  dialog->load( item );
}

void CalendarView::newJournal()
{
  newJournal( QString(), activeDate( true ) );
}

void CalendarView::newJournal( const QDate &date )
{
  newJournal( QString(), date.isValid() ? date : activeDate( true ) );
}

void CalendarView::newJournal( const Akonadi::Collection &collection )
{
  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();

  if ( mViewManager->currentView()->isEventView() ) {
    QDateTime startDt;
    QDateTime endDt;
    bool allDay = true;
    dateTimesForNewEvent( startDt, endDt, allDay );

    defaults.setStartDateTime( KDateTime( startDt ) );
    defaults.setEndDateTime( KDateTime( endDt ) );
  }

  KCalCore::Journal::Ptr journal( new KCalCore::Journal );
  defaults.setDefaults( journal );

  Akonadi::Item item;
  item.setPayload( journal );
  IncidenceEditorNG::IncidenceDialog *dialog = createIncidenceEditor( item, collection );
  dialog->load( item );
}

void CalendarView::newJournal( const QString &text, const QDate &date )
{
  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();

  KCalCore::Journal::Ptr journal( new KCalCore::Journal );
  defaults.setStartDateTime( KDateTime( date ) );
  defaults.setDefaults( journal );

  journal->setSummary( text );

  Akonadi::Item item;
  item.setPayload( journal );

  IncidenceEditorNG::IncidenceDialog *dialog = createIncidenceEditor( item );
  dialog->load( item );
}

KOrg::BaseView *CalendarView::currentView() const
{
  return mViewManager->currentView();
}

void CalendarView::configureCurrentView()
{
  KOrg::BaseView *const view = currentView();
  if ( view && view->hasConfigurationDialog() ) {
    view->showConfigurationDialog( this );
  }
}

void CalendarView::newSubTodo()
{
  const Akonadi::Item item = selectedTodo();
  if ( CalendarSupport::hasTodo( item ) ) {
    newSubTodo( item );
  }
}

void CalendarView::newSubTodo( const Akonadi::Collection &collection )
{
  if ( !CalendarSupport::hasTodo( selectedTodo() ) ) {
    kWarning() << "CalendarSupport::hasTodo() is false";
    return;
  }

  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();
  defaults.setRelatedIncidence( CalendarSupport::incidence( selectedTodo() ) );

  KCalCore::Todo::Ptr todo( new KCalCore::Todo );
  defaults.setDefaults( todo );

  Akonadi::Item item;
  item.setPayload( todo );

  IncidenceEditorNG::IncidenceDialog *dialog = createIncidenceEditor( item, collection );
  dialog->load( item );
}

void CalendarView::newSubTodo( const Akonadi::Item &parentTodo )
{
  IncidenceEditorNG::IncidenceDefaults defaults =
    IncidenceEditorNG::IncidenceDefaults::minimalIncidenceDefaults();
  defaults.setRelatedIncidence( CalendarSupport::incidence( parentTodo ) );

  KCalCore::Todo::Ptr todo( new KCalCore::Todo );
  defaults.setDefaults( todo );

  Q_ASSERT( !todo->relatedTo().isEmpty() );

  Akonadi::Item item;
  item.setPayload( todo );

  // Don't use parentTodo.parentCollection() because that can be a search folder.
  Akonadi::Collection collection = mCalendar->collection( parentTodo.storageCollectionId() );
  IncidenceEditorNG::IncidenceDialog *dialog = createIncidenceEditor( item, collection );
  dialog->load( item );
}

void CalendarView::newFloatingEvent()
{
  const QDate date = activeDate();
  newEvent( QDateTime( date, QTime( 12, 0, 0 ) ),
            QDateTime( date, QTime( 12, 0, 0 ) ), true );
}

bool CalendarView::addIncidence( const QString &ical )
{
  KCalCore::ICalFormat format;
  format.setTimeSpec( mCalendar->timeSpec() );
  KCalCore::Incidence::Ptr incidence( format.fromString( ical ) );
  return addIncidence( incidence );
}

bool CalendarView::addIncidence( const KCalCore::Incidence::Ptr &incidence )
{
  return incidence ? mChanger->createIncidence( incidence, Akonadi::Collection(), this ) != -1 : false;
}

void CalendarView::appointment_show()
{
  const Akonadi::Item item  = selectedIncidence();
  if ( CalendarSupport::hasIncidence( item ) ) {
    showIncidence( item );
  } else {
    KNotification::beep();
  }
}

void CalendarView::appointment_edit()
{
  const Akonadi::Item item = selectedIncidence();
  if ( CalendarSupport::hasIncidence( item ) ) {
    editIncidence( item );
  } else {
    KNotification::beep();
  }
}

void CalendarView::appointment_delete()
{
  const Akonadi::Item item = selectedIncidence();
  if ( CalendarSupport::hasIncidence( item ) ) {
    deleteIncidence( item );
  } else {
    KNotification::beep();
  }
}

void CalendarView::todo_unsub()
{
  const Akonadi::Item aTodo = selectedTodo();
  if ( incidence_unsub( aTodo ) ) {
    updateView();
  }
}

bool CalendarView::incidence_unsub( const Akonadi::Item &item )
{
  const KCalCore::Incidence::Ptr inc = CalendarSupport::incidence( item );

  if ( !inc || inc->relatedTo().isEmpty() ) {
    kDebug() << "Refusing to unparent this to-do" << inc;
    return false;
  }

  KCalCore::Incidence::Ptr oldInc( inc->clone() );
  inc->setRelatedTo( QString() );
  mChanger->modifyIncidence( item, oldInc, this );

  return true;
}

bool CalendarView::makeSubTodosIndependent( )
{
  bool  status = false;
  const Akonadi::Item aTodo = selectedTodo();

  if( makeChildrenIndependent( aTodo ) ) {
    updateView();
    status = true;
  }
  return status;
}

bool CalendarView::makeChildrenIndependent( const Akonadi::Item &item )
{
  const KCalCore::Incidence::Ptr inc = CalendarSupport::incidence( item );

  Akonadi::Item::List subIncs = mCalendar->childItems( item.id() );

  if ( !inc || subIncs.isEmpty() ) {
    kDebug() << "Refusing to  make children independent" << inc;
    return false;
  }
  startMultiModify ( i18n( "Make sub-to-dos independent" ) );

  foreach ( const Akonadi::Item &item, subIncs ) {
    incidence_unsub( item );
  }

  endMultiModify();
  return true;
}

bool CalendarView::deleteIncidence( Akonadi::Item::Id id, bool force )
{
  Akonadi::Item item = mCalendar->item( id );
  if ( !CalendarSupport::hasIncidence( item ) ) {
    kError() << "CalendarView::deleteIncidence(): Item does not contain incidence.";
    return false;
  }
  return deleteIncidence( item, force );
}

void CalendarView::toggleAlarm( const Akonadi::Item &item )
{
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( !incidence ) {
    kError() << "Null incidence";
    return;
  }
  KCalCore::Incidence::Ptr oldincidence( incidence->clone() );

  KCalCore::Alarm::List alarms = incidence->alarms();
  KCalCore::Alarm::List::ConstIterator it;
  for ( it = alarms.constBegin(); it != alarms.constEnd(); ++it ) {
    (*it)->toggleAlarm();
  }
  if ( alarms.isEmpty() ) {
    // Add an alarm if it didn't have one
    KCalCore::Alarm::Ptr alm = incidence->newAlarm();
    alm->setType( KCalCore::Alarm::Display );
    alm->setEnabled( true );
    int duration; // in secs
    switch( CalendarSupport::KCalPrefs::instance()->mReminderTimeUnits ) {
    default:
    case 0: // mins
      duration = CalendarSupport::KCalPrefs::instance()->mReminderTime * 60;
      break;
    case 1: // hours
      duration = CalendarSupport::KCalPrefs::instance()->mReminderTime * 60 * 60;
      break;
    case 2: // days
      duration = CalendarSupport::KCalPrefs::instance()->mReminderTime * 60 * 60 * 24;
      break;
    }
    if ( incidence->type() == KCalCore::Incidence::TypeEvent ) {
      alm->setStartOffset( KCalCore::Duration( -duration ) );
    } else {
      alm->setEndOffset( KCalCore::Duration( -duration ) );
    }
  }
  mChanger->startAtomicOperation( i18n( "Toggle Reminder" ) );
  mChanger->modifyIncidence( item, oldincidence, this );
  mChanger->endAtomicOperation();
}

void CalendarView::toggleTodoCompleted( const Akonadi::Item &todoItem )
{
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( todoItem );

  if ( !incidence ) {
    kError() << "Null incidence";
    return;
  }
  if ( incidence->type() != KCalCore::Incidence::TypeTodo ) {
    kDebug() << "called for a non-Todo incidence";
    return;
  }

  KCalCore::Todo::Ptr todo = CalendarSupport::todo( todoItem );
  Q_ASSERT( todo );
  KCalCore::Todo::Ptr oldtodo( todo->clone() );

  if ( todo->isCompleted() ) {
    todo->setPercentComplete( 0 );
  } else {
    todo->setCompleted( KDateTime::currentDateTime(
                          CalendarSupport::KCalPrefs::instance()->timeSpec() ) );
  }

  mChanger->startAtomicOperation( i18n( "Toggle To-do Completed") );
  mChanger->modifyIncidence( todoItem, oldtodo, this );
  mChanger->endAtomicOperation();
}

void CalendarView::copyIncidenceToResource( const Akonadi::Item &item, const Akonadi::Collection &col )
{
#ifdef AKONADI_PORT_DISABLED
  if ( !incidence ) {
    kError() << "Null incidence";
    return;
  }

  KCalCore::CalendarResources *const resources = KOrg::StdCalendar::self();
  KCalCore::CalendarResourceManager *const manager = resources->resourceManager();

  // Find the resource the incidence should be copied to
  ResourceCalendar *newCal = 0;
  KCalCore::CalendarResourceManager::iterator it;
  for ( it = manager->begin(); it != manager->end(); ++it ) {
    ResourceCalendar *const resource = *it;
    if ( resource->identifier() == resourceId ) {
      newCal = resource;
      break;
    }
  }
  if ( !newCal ) {
    return;
  }

  // Clone a new Incidence from the selected Incidence and give it a new Uid.
  KCalCore::Incidence::Ptr newInc;
  if ( incidence->type() == KCalCore::Incidence::TypeEvent ) {
    KCalCore::Event::Ptr nEvent( static_cast<KCalCore::Event::Ptr >( incidence )->clone() );
    nEvent->setUid( KCalCore::CalFormat::createUniqueId() );
    newInc = nEvent;
  } else if ( incidence->type() == KCalCore::Incidence::TypeTodo ) {
    KCalCore::Todo::Ptr nTodo( static_cast<KCalCore::Todo::Ptr >( incidence )->clone() );
    nTodo->setUid( KCalCore::CalFormat::createUniqueId() );
    newInc = nTodo;
  } else if ( incidence->type() == KCalCore::Incidence::TypeJournal ) {
    KCalCore::Journal::Ptr nJournal( static_cast<KCalCore::Journal::Ptr >( incidence )->clone() );
    nJournal->setUid( KCalCore::CalFormat::createUniqueId() );
    newInc = nJournal;
  } else {
    kWarning() << "Trying to copy an incidence type that cannot be copied";
    return;
  }

  if ( resources->addIncidence( newInc, newCal ) ) {
    incidenceAddFinished( newInc, true );
    KMessageBox::information(
      this,
      i18nc( "@info",
             "\"%1\" was successfully copied to %2.",
             incidence->summary(),
             newCal->resourceName() ),
      i18nc( "@title:window", "Copying Succeeded" ),
      "CalendarIncidenceCopy" );
  } else {
    KMessageBox::error(
      this,
      i18nc( "@info",
             "Unable to copy the item \"%1\" to %2.",
             incidence->summary(),
             newCal->resourceName() ),
      i18nc( "@title:window", "Copying Failed" ) );
  }
#else
  Q_UNUSED( col );
  Q_UNUSED( item );
  kDebug() << "AKONADI PORT: Disabled code in  " << Q_FUNC_INFO;
#endif
}

void CalendarView::moveIncidenceToResource( const Akonadi::Item &item, const Akonadi::Collection &col )
{
#ifdef AKONADI_PORT_DISABLED
  if ( !incidence ) {
    kError() << "Null incidence";
    return;
  }

  KCalCore::CalendarResources *const resources = KOrg::StdCalendar::self();
  KCalCore::CalendarResourceManager *const manager = resources->resourceManager();

  // Find the resource the incidence should be moved to
  ResourceCalendar *newCal = 0;
  KCalCore::CalendarResourceManager::iterator it;
  for ( it = manager->begin(); it != manager->end(); ++it ) {
    ResourceCalendar *const resource = *it;
    if ( resource->identifier() == resourceId ) {
      newCal = resource;
      break;
    }
  }
  if ( !newCal ) {
    return;
  }

  // Clone a new Incidence from the selected Incidence and give it a new Uid.
  KCalCore::Incidence *newInc;
  if ( incidence->type() == KCalCore::Incidence::TypeEvent ) {
    KCalCore::Event::Ptr nEvent = static_cast<KCalCore::Event::Ptr >( incidence )->clone();
    nEvent->setUid( KCalCore::CalFormat::createUniqueId() );
    newInc = nEvent;
  } else if ( incidence->type() == KCalCore::Incidence::TypeTodo ) {
    KCalCore::Todo::Ptr nTodo = static_cast<KCalCore::Todo::Ptr >( incidence )->clone();
    nTodo->setUid( KCalCore::CalFormat::createUniqueId() );
    newInc = nTodo;
  } else if ( incidence->type() == KCalCore::Incidence::TypeJournal ) {
    KCalCore::Journal::Ptr nJournal = static_cast<KCalCore::Journal::Ptr >( incidence )->clone();
    nJournal->setUid( KCalCore::CalFormat::createUniqueId() );
    newInc = nJournal;
  } else {
    kWarning() << "Trying to move an incidence type that cannot be moved";
    return;
  }

  if ( resources->addIncidence( newInc, newCal ) ) {
    incidenceAddFinished( newInc, true );
    ResourceCalendar *const oldCal = resources->resource( incidence );
    if ( !oldCal || resources->deleteIncidence( incidence ) ) {
      KMessageBox::error(
        this,
        i18nc( "@info",
               "Unable to remove the item \"%1\" from %2. "
               "However, a copy of this item has been put into %3.",
               incidence->summary(),
               oldCal->resourceName(),
               newCal->resourceName() ),
        i18nc( "@title:window", "Moving Failed" ) );
    } else {
      incidenceDeleteFinished( incidence, true );
      KMessageBox::information(
        this,
        i18nc( "@info",
               "\"%1\" was successfully moved from %2 to %3.",
               incidence->summary(),
               oldCal->resourceName(),
               newCal->resourceName() ),
        i18nc( "@title:window", "Moving Succeeded" ),
        "CalendarIncidenceMove" );
    }
  } else {
    KMessageBox::error(
      this,
      i18nc( "@info",
             "Unable to add the item \"%1\" into %2. "
             "This item has not been moved.",
             incidence->summary(),
             newCal->resourceName() ),
      i18nc( "@title:window", "Moving Failed" ) );
  }
#else
  Q_UNUSED( col );
  Q_UNUSED( item );
  kDebug() << "AKONADI PORT: Disabled code in  " << Q_FUNC_INFO;
#endif
}

void CalendarView::dissociateOccurrences( const Akonadi::Item &item, const QDate &date )
{
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );

  if ( !incidence ) {
    kError() << "Null incidence";
    return;
  }

  KDateTime thisDateTime( date, CalendarSupport::KCalPrefs::instance()->timeSpec() );
  bool isFirstOccurrence = !incidence->recurrence()->getPreviousDateTime( thisDateTime ).isValid();

  int answer;
  bool doOnlyThis = false;
  bool doFuture   = false;

  if ( isFirstOccurrence ) {
    answer = KMessageBox::questionYesNo(
      this,
      i18n( "Do you want to dissociate "
            "the occurrence on %1 "
            "from the recurrence?",
            KGlobal::locale()->formatDate( date ) ),
      i18n( "KOrganizer Confirmation" ),
      KGuiItem( i18n( "&Dissociate" ) ),
      KStandardGuiItem::cancel() );

    doOnlyThis = ( answer == KMessageBox::Yes );
  } else {
    answer = KMessageBox::questionYesNoCancel(
      this,
      i18n( "Do you want to dissociate "
            "the occurrence on %1 "
            "from the recurrence or also "
            "dissociate future ones?",
            KGlobal::locale()->formatDate( date ) ),
      i18n( "KOrganizer Confirmation" ),
      KGuiItem( i18n( "&Only Dissociate This One" ) ),
      KGuiItem( i18n( "&Also Dissociate Future Ones" ) ) );

    doOnlyThis = ( answer == KMessageBox::Yes );
    doFuture   = ( answer == KMessageBox::No );
  }

  if ( doOnlyThis ) {
    dissociateOccurrence( item, date, false );
  } else if ( doFuture ) {
    dissociateOccurrence( item, date, true );
  }
}
void CalendarView::dissociateOccurrence( const Akonadi::Item &item, const QDate &date, bool thisAndFuture )
{
  const KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );

  if ( thisAndFuture ) {
    startMultiModify( i18n( "Dissociate future occurrences" ) );
  } else {
    startMultiModify( i18n( "Dissociate occurrence" ) );
  }
  KDateTime occurrenceDate( incidence->dtStart() );
  occurrenceDate.setDate(date);
  kDebug() << "create exception: " << occurrenceDate;
  KCalCore::Incidence::Ptr newInc( KCalCore::Calendar::createException(
      incidence, occurrenceDate, thisAndFuture) );
  if ( newInc ) {
    mChanger->createIncidence( newInc, item.parentCollection(), this );
  } else {
    if ( thisAndFuture ) {
      KMessageBox::sorry(
        this,
        i18n( "Dissociating the future occurrences failed." ),
        i18n( "Dissociating Failed" ) );
    } else {
      KMessageBox::sorry(
        this,
        i18n( "Dissociating the occurrence failed." ),
        i18n( "Dissociating Failed" ) );
    }
  }
  endMultiModify();
}

void CalendarView::schedule_publish( const Akonadi::Item &item )
{
  Akonadi::Item selectedItem = item;
  if ( !item.hasPayload<KCalCore::Incidence::Ptr>() ) {
    selectedItem = selectedIncidence();
  }

  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( selectedItem );
  if ( incidence )
    mITIPHandler->publishInformation( incidence, this );
}

void CalendarView::schedule_request( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPRequest, incidence );
}

void CalendarView::schedule_refresh( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPRefresh, incidence );
}

void CalendarView::schedule_cancel( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPCancel, incidence );
}

void CalendarView::schedule_add( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPAdd, incidence );
}

void CalendarView::schedule_reply( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPReply, incidence );
}

void CalendarView::schedule_counter( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPCounter, incidence );
}

void CalendarView::schedule_declinecounter( const Akonadi::Item &incidence )
{
  schedule( KCalCore::iTIPDeclineCounter, incidence );
}

void CalendarView::schedule_forward( const Akonadi::Item &item )
{
  Akonadi::Item selectedItem = item;
  if ( !item.hasPayload<KCalCore::Incidence::Ptr>() ) {
    selectedItem = selectedIncidence();
  }

  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( selectedItem );

  if ( incidence )
    mITIPHandler->sendAsICalendar( incidence, this );
}

void CalendarView::mailFreeBusy( int daysToPublish )
{
  Akonadi::FreeBusyManager::self()->mailFreeBusy( daysToPublish, this );
}

void CalendarView::uploadFreeBusy()
{
  Akonadi::FreeBusyManager::self()->publishFreeBusy( this );
}

void CalendarView::schedule( KCalCore::iTIPMethod method, const Akonadi::Item &item )
{
  Akonadi::Item selectedItem = item;
  if ( !item.hasPayload<KCalCore::Incidence::Ptr>() ) {
    selectedItem = selectedIncidence();
  }

  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( selectedItem );

  if ( incidence )
    mITIPHandler->sendiTIPMessage( method, incidence, this );
}

void CalendarView::openAddressbook()
{
  KRun::runCommand( QLatin1String("kaddressbook"), topLevelWidget() );
}

bool CalendarView::isReadOnly() const
{
  return mReadOnly;
}

void CalendarView::setReadOnly( bool readOnly )
{
  if ( mReadOnly != readOnly ) {
    mReadOnly = readOnly;
    emit readOnlyChanged( mReadOnly );
  }
}

void CalendarView::print()
{
  createPrinter();

  KOrg::BaseView *currentView = mViewManager->currentView();

  CalendarSupport::CalPrinter::PrintType printType = CalendarSupport::CalPrinter::Month;

  KCalCore::Incidence::List selectedIncidences;
  if ( currentView ) {
    printType = currentView->printType();
    Akonadi::Item::List selectedViewIncidences = currentView->selectedIncidences();
    foreach ( const Akonadi::Item &item, selectedViewIncidences ) {
      if ( item.hasPayload<KCalCore::Incidence::Ptr>() ) {
        selectedIncidences.append( item.payload<KCalCore::Incidence::Ptr>() );
      }
    }
  }

  KCalCore::DateList tmpDateList = mDateNavigator->selectedDates();
  mCalPrinter->print( printType, tmpDateList.first(), tmpDateList.last(), selectedIncidences );
}

void CalendarView::printPreview()
{
  createPrinter();

  KOrg::BaseView *currentView = mViewManager->currentView();

  CalendarSupport::CalPrinter::PrintType printType = CalendarSupport::CalPrinter::Month;

  KCalCore::Incidence::List selectedIncidences;
  if ( currentView ) {
    printType = currentView->printType();
    Akonadi::Item::List selectedViewIncidences = currentView->selectedIncidences();
    foreach ( const Akonadi::Item &item, selectedViewIncidences ) {
      if ( item.hasPayload<KCalCore::Incidence::Ptr>() ) {
        selectedIncidences.append( item.payload<KCalCore::Incidence::Ptr>() );
      }
    }
  }

  KCalCore::DateList tmpDateList = mDateNavigator->selectedDates();
  mCalPrinter->print( printType, tmpDateList.first(), tmpDateList.last(),
                      selectedIncidences, true );
}

void CalendarView::exportWeb()
{
  KOrg::HTMLExportSettings *settings = new KOrg::HTMLExportSettings( QLatin1String("KOrganizer") );
  Q_ASSERT(settings);
  // Manually read in the config, because parameterized kconfigxt objects don't
  // seem to load the config theirselves
  settings->readConfig();
  ExportWebDialog *dlg = new ExportWebDialog( settings, this );
  connect( dlg, SIGNAL(exportHTML(KOrg::HTMLExportSettings*)),
           this, SIGNAL(exportHTML(KOrg::HTMLExportSettings*)) );
  dlg->show();
}

void CalendarView::exportICalendar()
{
  QString filename =
    KFileDialog::getSaveFileName( KUrl( QLatin1String("icalout.ics") ), i18n( "*.ics|iCalendars" ), this );
  if ( !filename.isEmpty() ) {
    // Force correct extension
    if ( filename.right( 4 ) != QLatin1String(".ics") ) {
      filename += QLatin1String(".ics");
    }

    if ( QFile( filename ).exists() ) {
      if ( KMessageBox::No == KMessageBox::warningYesNo(
             this,
             i18n( "Do you want to overwrite %1?", filename ) ) ) {
        return;
      }
    }
    KCalCore::ICalFormat *format = new KCalCore::ICalFormat;

    KCalCore::FileStorage storage( mCalendar, filename, format );
    if ( !storage.save() ) {
      QString errmess;
      if ( format->exception() ) {
        errmess = KCalUtils::Stringify::errorMessage( *format->exception() );
      } else {
        errmess = i18nc( "save failure cause unknown", "Reason unknown" );
      }
      KMessageBox::error(
        this,
        i18nc( "@info",
               "Cannot write iCalendar file %1. %2",
               filename, errmess ) );
    }
  }
}

void CalendarView::exportVCalendar()
{
  if ( !mCalendar->journals().isEmpty() ) {
    int result = KMessageBox::warningContinueCancel(
      this,
      i18n( "The journal entries cannot be exported to a vCalendar file." ),
      i18n( "Data Loss Warning" ),
      KGuiItem( i18n( "Proceed" ) ),
      KStandardGuiItem::cancel(),
      QLatin1String( "dontaskVCalExport" ),
      KMessageBox::Notify );
    if ( result != KMessageBox::Continue ) {
      return;
    }
  }

  QString filename = KFileDialog::getSaveFileName( KUrl( QLatin1String("vcalout.vcs") ),
                                                   i18n( "*.vcs|vCalendars" ), this, QString(), KFileDialog::ConfirmOverwrite );
  if ( !filename.isEmpty() ) {
    // Force correct extension
    if ( filename.right( 4 ) != QLatin1String(".vcs") ) {
      filename += QLatin1String(".vcs");
    }
    if ( QFile( filename ).exists() ) {
      if ( KMessageBox::No == KMessageBox::warningYesNo(
             this,
             i18n( "Do you want to overwrite %1?", filename ) ) ) {
        return;
      }
    }
    KCalCore::VCalFormat *format = new KCalCore::VCalFormat;

    KCalCore::FileStorage storage( mCalendar, filename, format );
    if ( !storage.save() ) {
      QString errmess;
      if ( format->exception() ) {
        errmess = KCalUtils::Stringify::errorMessage( *format->exception() );
      } else {
        errmess = i18nc( "save failure cause unknown", "Reason unknown" );
      }
      KMessageBox::error(
        this,
        i18nc( "@info",
               "Cannot write vCalendar file %1. %2",
               filename, errmess ) );
    }
  }
}

void CalendarView::eventUpdated( const Akonadi::Item & )
{
  // Don't call updateView here. The code, which has caused the update of the
  // event is responsible for updating the view.
//  updateView();
}

void CalendarView::adaptNavigationUnits()
{
  if ( mViewManager->currentView()->isEventView() ) {
    int days = mViewManager->currentView()->currentDateCount();
    if ( days == 1 ) {
      emit changeNavStringPrev( i18n( "&Previous Day" ) );
      emit changeNavStringNext( i18n( "&Next Day" ) );
    } else {
      emit changeNavStringPrev( i18n( "&Previous Week" ) );
      emit changeNavStringNext( i18n( "&Next Week" ) );
    }
  }
}

void CalendarView::processMainViewSelection( const Akonadi::Item &item, const QDate &date )
{
  if ( CalendarSupport::hasIncidence( item ) ) {
    mTodoList->clearSelection();
  }
  processIncidenceSelection( item, date );
}

void CalendarView::processTodoListSelection( const Akonadi::Item &item, const QDate &date )
{
  if ( CalendarSupport::hasIncidence( item ) && mViewManager->currentView() ) {
    mViewManager->currentView()->clearSelection();
  }
  processIncidenceSelection( item, date );
}

void CalendarView::processIncidenceSelection( const Akonadi::Item &item, const QDate &date )
{
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( item != mSelectedIncidence ) {
    // This signal also must be emitted if incidence is 0
    emit incidenceSelected( item, date );
  }

  if ( !incidence ) {
   mSelectedIncidence = item;
   return;
  }
  if ( item == mSelectedIncidence ) {
    if ( !incidence->recurs() || mSaveDate == date ) {
      return;
    }
  }

  mSelectedIncidence = item;
  mSaveDate = date;

  bool todo = false;
  bool subtodo = false;

  const bool organizerEvents =
    CalendarSupport::KCalPrefs::instance()->thatIsMe( incidence->organizer()->email() );
  const bool groupEvents = incidence->attendeeByMails( CalendarSupport::KCalPrefs::instance()->allEmails() );

  if ( incidence->type() == KCalCore::Incidence::TypeTodo ) {
    todo = true;
    subtodo = ( incidence->relatedTo() != QString() );
  }
  emit todoSelected( todo );
  emit subtodoSelected( subtodo );
  emit organizerEventsSelected( organizerEvents );
  emit groupEventsSelected( groupEvents );
}

void CalendarView::checkClipboard()
{
  emit pasteEnabled( mCalendarClipboard->pasteAvailable() );
}

void CalendarView::showDates( const KCalCore::DateList &selectedDates, const QDate &preferredMonth )
{
  mDateNavigatorContainer->selectDates( selectedDates, preferredMonth );
  mNavigatorBar->selectDates( selectedDates );

  if ( mViewManager->currentView() ) {
    updateView( selectedDates.first(), selectedDates.last(), preferredMonth, false );
  } else {
    mViewManager->showAgendaView();
  }
}

void CalendarView::editFilters()
{
  mDialogManager->showFilterEditDialog( &mFilters );
}

void CalendarView::updateFilter()
{
  QStringList filters;

  int pos = mFilters.indexOf( mCurrentFilter );
  if ( pos < 0 ) {
    mCurrentFilter = 0;
  }

  filters << i18n( "No filter" );
  foreach ( KCalCore::CalFilter *filter, mFilters ) {
    if ( filter ) {
      filters << filter->name();
    }
  }

  // account for the additional "No filter" at the beginning! if the
  // filter is not in the list, pos == -1...
  emit filtersUpdated( filters, pos + 1 );

  mCalendar->setFilter( mCurrentFilter );
}

void CalendarView::filterActivated( int filterNo )
{
  KCalCore::CalFilter *newFilter = 0;
  if ( filterNo > 0 && filterNo <= int( mFilters.count() ) ) {
    newFilter = mFilters.at( filterNo - 1 );
  }
  if ( newFilter != mCurrentFilter ) {
    mCurrentFilter = newFilter;
    mCalendar->setFilter( mCurrentFilter );
    mViewManager->addChange( EventViews::EventView::FilterChanged );
    updateView();
  }
  emit filterChanged();
}

bool CalendarView::isFiltered() const
{
  return mCurrentFilter != 0;
}

QString CalendarView::currentFilterName() const
{
  if ( mCurrentFilter ) {
    return mCurrentFilter->name();
  } else {
    return i18n( "No filter" );
  }
}

void CalendarView::takeOverEvent()
{
  const Akonadi::Item item = currentSelection();
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );

  if ( incidence ) {
    return;
  }

  incidence->setOrganizer(
    KCalCore::Person::Ptr( new KCalCore::Person(
                             CalendarSupport::KCalPrefs::instance()->fullName(),
                             CalendarSupport::KCalPrefs::instance()->email() ) ) );
  incidence->recreate();
  incidence->setReadOnly( false );

  //PENDING(AKONADI_PORT) call mChanger?

  updateView();
}

void CalendarView::showIntro()
{
  kDebug() << "To be implemented.";
}

void CalendarView::showDateNavigator( bool show )
{
  if ( show ) {
    mDateNavigatorContainer->show();
    mDateNavigatorContainer->updateView();
  } else {
    mDateNavigatorContainer->hide();
  }
}

void CalendarView::showTodoView( bool show )
{
  if ( show ) {
    mTodoList->show();
    mTodoList->updateView();
  } else {
    mTodoList->hide();
  }
}

void CalendarView::showEventViewer( bool show )
{
  if ( show ) {
    mEventViewerBox->show();
  } else {
    mEventViewerBox->hide();
  }
}

void CalendarView::addView( KOrg::BaseView *view )
{
  mViewManager->addView( view );
}

void CalendarView::showView( KOrg::BaseView *view )
{
  mViewManager->showView( view );
}

void CalendarView::addExtension( CalendarViewExtension::Factory *factory )
{
  CalendarViewExtension *extension = factory->create( mLeftSplitter );
  mExtensions.append( extension );
  if ( !mETMCollectionView ) {
    mETMCollectionView = qobject_cast<AkonadiCollectionView*>( extension );
  }
}

void CalendarView::showLeftFrame( bool show )
{
  if ( show ) {
    mMainSplitterSizes.clear();
    mLeftFrame->show();
    emit calendarViewExpanded( false );
  } else {
    // mPanner splitter sizes are useless if mLeftFrame is hidden, so remember them beforehand.
    if ( mMainSplitterSizes.isEmpty() ) {
      mMainSplitterSizes = mPanner->sizes();
    }

    mLeftFrame->hide();
    emit calendarViewExpanded( true );
  }
}

Akonadi::Item CalendarView::selectedTodo()
{
  const Akonadi::Item item = currentSelection();
  if ( const KCalCore::Todo::Ptr t = CalendarSupport::todo( item ) ) {
    return item;
  }

  Akonadi::Item incidence;

  const Akonadi::Item::List selectedIncidences = mTodoList->selectedIncidences();
  if ( !selectedIncidences.isEmpty() ) {
    incidence = selectedIncidences.first();
  }
  if ( const KCalCore::Todo::Ptr t = CalendarSupport::todo( item ) ) {
    return item;
  }
  return Akonadi::Item();
}

void CalendarView::dialogClosing( const Akonadi::Item & )
{
}

Akonadi::Item CalendarView::currentSelection()
{
  return mViewManager->currentSelection();
}

Akonadi::Item CalendarView::selectedIncidence()
{
  Akonadi::Item item = currentSelection();
  if ( !item.isValid() ) {
    Akonadi::Item::List selectedIncidences = mTodoList->selectedIncidences();
    if ( !selectedIncidences.isEmpty() ) {
      item = selectedIncidences.first();
    }
  }
  return item;
}

void CalendarView::showIncidence()
{
  showIncidence( selectedIncidence() );
}

void CalendarView::editIncidence()
{
  editIncidence( selectedIncidence() );
}

bool CalendarView::editIncidence( Akonadi::Item::Id id )
{
  Akonadi::Item item = mCalendar->item( id );
  return editIncidence( item );
}

bool CalendarView::showIncidence( Akonadi::Item::Id id )
{
  Akonadi::Item item = mCalendar->item( id );
  if ( !CalendarSupport::hasIncidence( item ) ) {
    return false;
  }
  showIncidence( item );
  return true;
}

bool CalendarView::showIncidenceContext( Akonadi::Item::Id id )
{
  Akonadi::Item item = mCalendar->item( id );
  if ( !CalendarSupport::hasIncidence( item ) ) {
    return false;
  }
  showIncidenceContext( item );
  return true;
}

void CalendarView::deleteIncidence()
{
  deleteIncidence( selectedIncidence() );
}

void CalendarView::cutIncidence( const Akonadi::Item &incidence )
{
  Q_UNUSED( incidence );
  edit_cut();
}

void CalendarView::copyIncidence( const Akonadi::Item &incidence )
{
  Q_UNUSED( incidence );
  edit_copy();
}

void CalendarView::pasteIncidence()
{
  edit_paste();
}

void CalendarView::showIncidence( const Akonadi::Item &item )
{
  KOEventViewerDialog *eventViewer = new KOEventViewerDialog( mCalendar.data(), this );
  eventViewer->setIncidence( item, QDate() );
  // Disable the Edit button for read-only Incidences.
  if ( !mCalendar->hasRight( item, Akonadi::Collection::CanChangeItem ) ) {
    eventViewer->enableButton( KDialog::User1, false );
  }

  eventViewer->show();
}

void CalendarView::showIncidenceContext( const Akonadi::Item &item )
{
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( CalendarSupport::hasEvent( item ) ) {
    if ( !viewManager()->currentView()->inherits( "KOEventView" ) ) {
      viewManager()->showAgendaView();
    }
    // just select the appropriate date
    mDateNavigator->selectWeek(
      incidence->dtStart().toTimeSpec(
        CalendarSupport::KCalPrefs::instance()->timeSpec() ).date() );
    return;
  } else if ( CalendarSupport::hasJournal( item ) ) {
    if ( !viewManager()->currentView()->inherits( "KOJournalView" ) ) {
      viewManager()->showJournalView();
    }
  } else if ( CalendarSupport::hasTodo( item ) ) {
    if ( !viewManager()->currentView()->inherits( "KOTodoView" ) ) {
      viewManager()->showTodoView();
    }
  }
  Akonadi::Item::List list;
  list.append( item );
  viewManager()->currentView()->showIncidences( list, QDate() );
}

bool CalendarView::editIncidence( const Akonadi::Item &item, bool isCounter )
{
  Q_UNUSED( isCounter );
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( !incidence ) {
    kError() << "Null incidence";
    KNotification::beep();
    return false;
  }

  if ( !mCalendar->hasRight( item, Akonadi::Collection::CanChangeItem ) ) {
    showIncidence( item );
    return true;
  }


  IncidenceEditorNG::IncidenceDialog *dialog = incidenceDialog( item );

  // connectIncidenceEditor( dialog );         // TODO: This as well
  dialog->load( item, activeIncidenceDate() ); // Show the dialog as soon as it loads the item.

  return true;
}

void CalendarView::deleteSubTodosIncidence ( const Akonadi::Item &todoItem )
{
  const KCalCore::Todo::Ptr todo = CalendarSupport::todo( todoItem );
  if ( !todo ) {
    return;
  }
  Akonadi::Item::List subTodos = mCalendar->childItems( todoItem.id() );
  foreach ( const Akonadi::Item &item, subTodos ) {
    if ( CalendarSupport::hasTodo( item ) ) {
      deleteSubTodosIncidence ( item );
    }
  }

  if ( !mChanger->deletedRecently( todoItem.id() ) ) {
    mChanger->deleteIncidence( todoItem, this );
  }
}

void CalendarView::deleteTodoIncidence ( const Akonadi::Item &todoItem, bool force )
{
  const KCalCore::Todo::Ptr todo = CalendarSupport::todo( todoItem );
  if ( !todo ) {
    return ;
  }

  // it a simple todo, ask and delete it.
  if ( mCalendar->childItems( todoItem.id() ).isEmpty() ) {
    bool doDelete = true;
    if ( !force && KOPrefs::instance()->mConfirm ) {
      doDelete = ( msgItemDelete( todoItem ) == KMessageBox::Continue );
    }
    if ( doDelete && !mChanger->deletedRecently( todoItem.id() ) ) {
      mChanger->deleteIncidence( todoItem, this );
    }
    return;
  }

  /* Ok, this to-do has sub-to-dos, ask what to do */
  int km = KMessageBox::No;
  if ( !force ) {
    km = KMessageBox::questionYesNoCancel(
      this,
      i18n( "The item \"%1\" has sub-to-dos. "
            "Do you want to delete just this item and "
            "make all its sub-to-dos independent, or "
            "delete the to-do with all its sub-to-dos?",
            todo->summary() ),
      i18n( "KOrganizer Confirmation" ),
      KGuiItem( i18n( "Delete Only This" ) ),
      KGuiItem( i18n( "Delete All" ) ) );
  }
  // Delete only the father
  if ( km == KMessageBox::Yes ) {
    startMultiModify( i18n( "Delete parent to-do" ) );
    makeChildrenIndependent( todoItem );
    if ( !mChanger->deletedRecently( todoItem.id() ) ) {
      mChanger->deleteIncidence( todoItem, this );
    }
  } else if ( km == KMessageBox::No ) {
    startMultiModify( i18n( "Delete parent to-do and sub-to-dos" ) );
    // Delete all
    // we have to hide the delete confirmation for each itemDate
    deleteSubTodosIncidence ( todoItem );
  }
  endMultiModify();
}

bool CalendarView::deleteIncidence( const Akonadi::Item &item, bool force )
{
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( !incidence ) {
    if ( !force ) {
      kError() << "Null incidence";
      KNotification::beep();
    }
    kError() << "CalendarView::deleteIncidence(): Unable do delete, incidence is null.";
    return false;
  }

  if ( mChanger->deletedRecently( item.id() ) ) {
    // it was deleted already but the etm wasn't notified yet
    kWarning() << "CalendarView::deleteIncidence(): item with id" << item.id()
               << "was deleted recently, skipping";
    return true;
  }

  if ( !mCalendar->hasRight( item, Akonadi::Collection::CanDeleteItem ) ) {
    if ( !force ) {
      KMessageBox::information(
        this,
        i18n( "The item \"%1\" is marked read-only "
              "and cannot be deleted; it probably "
              "belongs to a read-only calendar.",
              incidence->summary() ),
        i18n( "Removing not possible" ),
        QLatin1String("deleteReadOnlyIncidence") );
    }
    kWarning() << "CalendarView::deleteIncidence(): No rights to delete item";
    return false;
  }

  //If it is a todo, there are specific delete function

  if ( incidence && incidence->type() == KCalCore::Incidence::TypeTodo ) {
    deleteTodoIncidence( item, force );
    return true;
  }

  if ( incidence->recurs() ) {
    QDate itemDate = mViewManager->currentSelectionDate();
    int km = KMessageBox::Ok;
    if ( !force ) {
      if ( !itemDate.isValid() ) {
        kDebug() << "Date Not Valid";
        km = KMessageBox::warningContinueCancel(
          this,
          i18n( "The calendar item \"%1\" recurs over multiple dates; "
                "are you sure you want to delete it "
                "and all its recurrences?", incidence->summary() ),
          i18n( "KOrganizer Confirmation" ),
          KGuiItem( i18n( "Delete All" ) ) );
      } else {
        KDateTime itemDateTime( itemDate, CalendarSupport::KCalPrefs::instance()->timeSpec() );
        bool isFirst = !incidence->recurrence()->getPreviousDateTime( itemDateTime ).isValid();
        bool isLast  = !incidence->recurrence()->getNextDateTime( itemDateTime ).isValid();

        QString message;
        KGuiItem itemFuture( i18n( "Also Delete &Future" ) );

        if ( !isFirst && !isLast ) {
          itemFuture.setEnabled( true );
          message = i18n( "The calendar item \"%1\" recurs over multiple dates. "
                          "Do you want to delete only the current one on %2, also "
                          "future occurrences, or all its occurrences?",
                          incidence->summary(),
                          KGlobal::locale()->formatDate( itemDate ) );
        } else {
          itemFuture.setEnabled( false );
          message = i18n( "The calendar item \"%1\" recurs over multiple dates. "
                          "Do you want to delete only the current one on %2 "
                          "or all its occurrences?",
                          incidence->summary(),
                          KGlobal::locale()->formatDate( itemDate ) );
        }

        if ( !( isFirst && isLast ) ) {
          km = PIMMessageBox::fourBtnMsgBox(
            this,
            QMessageBox::Warning,
            message,
            i18n( "KOrganizer Confirmation" ),
            KGuiItem ( i18n( "Delete C&urrent" ) ),
            itemFuture,
            KGuiItem( i18n( "Delete &All" ) ) );
        } else {
          km = msgItemDelete( item );
        }
      }
    }
    KCalCore::Incidence::Ptr oldIncidence( incidence->clone() );
    switch( km ) {
    case KMessageBox::Ok: // Continue // all
    case KMessageBox::Continue:
      mChanger->deleteIncidence( item, this );
      break;

    case KMessageBox::Yes: // just this one
      incidence->recurrence()->addExDate( itemDate );
      mChanger->modifyIncidence( item, oldIncidence, this );

      break;
    case KMessageBox::No: // all future items
      KCalCore::Recurrence *recur = incidence->recurrence();
      recur->setEndDate( itemDate.addDays( -1 ) );
      mChanger->modifyIncidence( item, oldIncidence, this );
      break;
    }
  } else {
    bool doDelete = true;
    if ( !force && KOPrefs::instance()->mConfirm ) {
      doDelete = ( msgItemDelete( item ) == KMessageBox::Continue );
    }
    if ( doDelete ) {
      mChanger->deleteIncidence( item, this );
      processIncidenceSelection( Akonadi::Item(), QDate() );
    }
  }
  return true;
}


void CalendarView::purgeCompleted()
{
  if ( checkedCollections().isEmpty() ) {
    showMessage( i18n( "All calendars are unchecked in the Calendar Manager. No to-do was purged." ), KMessageWidget::Warning );
    return;
  }

  if ( mCalendar->rawTodos().isEmpty() ) {
    showMessage( i18n( "There are no completed to-dos to purge." ), KMessageWidget::Information );
    return;
  }

  int result = KMessageBox::warningContinueCancel(
    this,
    i18n( "Delete all completed to-dos from checked calendars?" ),
    i18n( "Purge To-dos" ),
    KGuiItem( i18n( "Purge" ) ) );

  if ( result == KMessageBox::Continue ) {
      mTodoPurger->purgeCompletedTodos();
  }
}

void CalendarView::warningChangeFailed( const Akonadi::Item &item )
{
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  if ( incidence ) {
    KMessageBox::sorry(
      this,
      i18nc( "@info",
             "Unable to edit \"%1\" because it is locked by another process.",
             incidence->summary() ) );
  }
}

void CalendarView::showErrorMessage( const QString &msg )
{
  KMessageBox::error( this, msg );
}

void CalendarView::addIncidenceOn( const Akonadi::Item &itemadd, const QDate &dt )
{
  if ( !CalendarSupport::hasIncidence( itemadd ) ) {
    KMessageBox::sorry(
      this,
      i18n( "Unable to copy the item to %1.", dt.toString() ),
      i18n( "Copying Failed" ) );
    return;
  }
  Akonadi::Item item = mCalendar->item( itemadd.id() );
  if ( !item.isValid() ) {
    item = itemadd;
  }
  // Create a copy of the incidence, since the incadd doesn't belong to us.
  KCalCore::Incidence::Ptr incidence( CalendarSupport::incidence( item )->clone() );
  incidence->recreate();

  if ( const KCalCore::Event::Ptr event = incidence.dynamicCast<KCalCore::Event>() ) {

    // Adjust date
    KDateTime start = event->dtStart();
    KDateTime end = event->dtEnd();

    int duration = start.daysTo( end );
    start.setDate( dt );
    end.setDate( dt.addDays( duration ) );

    event->setDtStart( start );
    event->setDtEnd( end );

  } else if ( const KCalCore::Todo::Ptr todo = incidence.dynamicCast<KCalCore::Todo>() ) {
    KDateTime due = todo->dtDue();
    due.setDate( dt );

    todo->setDtDue( due );
  }

  mChanger->createIncidence( incidence, Akonadi::Collection(), this );
}

void CalendarView::moveIncidenceTo( const Akonadi::Item &itemmove, const QDate &dt )
{
  if ( !CalendarSupport::hasIncidence( itemmove ) ) {
    KMessageBox::sorry(
      this,
      i18n( "Unable to move the item to  %1.", dt.toString() ),
      i18n( "Moving Failed" ) );
    return;
  }
  Akonadi::Item item = mCalendar->item( itemmove.id() );
  if ( !item.isValid() ) {
    addIncidenceOn( itemmove, dt );
    return;
  }
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( itemmove );

  KCalCore::Incidence::Ptr oldIncidence( incidence->clone() );

  if ( const KCalCore::Event::Ptr event = incidence.dynamicCast<KCalCore::Event>() ) {
    // Adjust date
    KDateTime start = event->dtStart();
    KDateTime end = event->dtEnd();

    int duration = start.daysTo( end );
    start.setDate( dt );
    end.setDate( dt.addDays( duration ) );

    event->setDtStart( start );
    event->setDtEnd( end );

  } if ( const KCalCore::Todo::Ptr todo = incidence.dynamicCast<KCalCore::Todo>() ) {
    KDateTime due = todo->dtDue();
    due.setDate( dt );

    todo->setDtDue( due );
  }
  mChanger->modifyIncidence( itemmove, oldIncidence, this );
}

void CalendarView::resourcesChanged()
{
  mViewManager->addChange( EventViews::EventView::ResourcesChanged );
  updateView();
}

bool CalendarView::eventFilter( QObject *watched, QEvent *event )
{
  if ( watched == mLeftFrame && event->type() == QEvent::Show ) {
    mSplitterSizesValid = true;
  }
  return KOrg::CalendarViewBase::eventFilter( watched, event );
}

void CalendarView::updateHighlightModes() {

  KOrg::BaseView *view = mViewManager->currentView();
  if ( view ) {
    bool hiEvents;
    bool hiTodos;
    bool hiJournals;

    view->getHighlightMode( hiEvents, hiTodos, hiJournals );
    mDateNavigatorContainer->setHighlightMode( hiEvents,
                                               hiTodos,
                                               hiJournals );
  }
}

void CalendarView::selectWeek( const QDate &date, const QDate &preferredMonth )
{
  if ( KOPrefs::instance()->mWeekNumbersShowWork  &&
       mViewManager->rangeMode() == KOViewManager::WORK_WEEK_RANGE ) {
    mDateNavigator->selectWorkWeek( date );
  } else {
    mDateNavigator->selectWeek( date, preferredMonth );
  }
}

void CalendarView::changeFullView( bool fullView )
{
  if ( mViewManager->currentView() ) {
    if ( mViewManager->currentView()->identifier() == "DefaultTodoView" ) {
      showLeftFrame( !fullView );
    } else if ( mViewManager->currentView()->identifier() == "DefaultMonthView" ) {
      showLeftFrame( !fullView );
      fullView ? mNavigatorBar->show() : mNavigatorBar->hide();
    }
  }
}

Akonadi::Collection CalendarView::defaultCollection( const QLatin1String &mimeType ) const
{
  // 1. Try the view collection ( used in multi-agenda view )
  Akonadi::Collection collection = mCalendar->collection( mViewManager->currentView()->collectionId() );
  bool supportsMimeType = collection.contentMimeTypes().contains( mimeType ) || mimeType == "";
  bool hasRights = collection.rights() & Akonadi::Collection::CanCreateItem;
  if ( collection.isValid() && supportsMimeType && hasRights )
    return collection;

  // 2. Try the configured default collection
  collection = mCalendar->collection( CalendarSupport::KCalPrefs::instance()->defaultCalendarId() );
  supportsMimeType = collection.contentMimeTypes().contains( mimeType ) || mimeType == "";
  hasRights = collection.rights() & Akonadi::Collection::CanCreateItem;
  if ( collection.isValid() && supportsMimeType && hasRights )
    return collection;

  // 3. Try last selected folder
  collection = mCalendar->collection( IncidenceEditorNG::GlobalSettings::self()->lastSelectedFolder() );
  supportsMimeType = collection.contentMimeTypes().contains( mimeType ) || mimeType == "";
  hasRights = collection.rights() & Akonadi::Collection::CanCreateItem;
  if ( collection.isValid() && supportsMimeType && hasRights )
    return collection;


  // 4. Try the selected collection
  collection = selectedCollection();
  supportsMimeType = collection.contentMimeTypes().contains( mimeType ) || mimeType == "";
  hasRights = collection.rights() & Akonadi::Collection::CanCreateItem;
  if ( collection.isValid() && supportsMimeType && hasRights )
    return collection;

  // 5. Try the checked collections
  Akonadi::Collection::List collections = checkedCollections();
  foreach( const Akonadi::Collection &checkedCollection, collections ) {
    supportsMimeType = checkedCollection.contentMimeTypes().contains( mimeType ) || mimeType == "";
    hasRights = checkedCollection.rights() & Akonadi::Collection::CanCreateItem;
    if ( checkedCollection.isValid() && supportsMimeType && hasRights )
      return checkedCollection;
  }

  // 5. Return a invalid collection, the editor will use the first one in the combo
  return Akonadi::Collection();
}

IncidenceEditorNG::IncidenceDialog *CalendarView::createIncidenceEditor(
  const Akonadi::Item &item, const Akonadi::Collection &collection )
{
  IncidenceEditorNG::IncidenceDialog *dialog = incidenceDialog( item );
  KCalCore::Incidence::Ptr incidence = CalendarSupport::incidence( item );
  Q_ASSERT( incidence );

  if ( collection.isValid() ) {
    dialog->selectCollection( collection );
  } else {
    dialog->selectCollection( defaultCollection( incidence->mimeType() ) );
  }

  return dialog;
}

Akonadi::History *CalendarView::history() const
{
  return mChanger->history();
}

void CalendarView::onCutFinished()
{
  checkClipboard();
}

void CalendarView::setCheckableProxyModel( KOCheckableProxyModel *model )
{
  if ( mCheckableProxyModel )
    mCheckableProxyModel->disconnect( this );

  mCheckableProxyModel = model;
  connect( model, SIGNAL(aboutToToggle(bool)), SLOT(onCheckableProxyAboutToToggle(bool)) );
  connect( model, SIGNAL(toggled(bool)), SLOT(onCheckableProxyToggled(bool)) );
}

void CalendarView::onCheckableProxyAboutToToggle( bool newState )
{
  // Someone unchecked a collection, save the view state now.
  if ( !newState ) {
    mTodoList->saveViewState();
    KOTodoView *todoView = mViewManager->todoView();
    if ( todoView )
      todoView->saveViewState();
  }
}

void CalendarView::onCheckableProxyToggled( bool newState )
{
  // Someone checked a collection, restore the view state now.
  if ( newState ) {
    mTodoList->restoreViewState();
    KOTodoView *todoView = mViewManager->todoView();
    if ( todoView )
      todoView->restoreViewState();
  }
}

void CalendarView::onTodosPurged(bool success, int numDeleted, int numIgnored)
{
    QString message;
    KMessageWidget::MessageType type = KMessageWidget::Information;
    if (success) {
        if (numDeleted == 0 && numIgnored > 0) {
            type = KMessageWidget::Warning;
            message = i18n("0 completed to-dos were purged.") + QLatin1Char('\n') +
                    i18np("%1 to-do was ignored because it has uncompleted or read-only children.",
                          "%1 to-dos were ignored because they have uncompleted or read-only children.", numIgnored);
        } else if (numDeleted > 0 && numIgnored == 0) {
            message = i18np("%1 completed to-do was purged.", "%1 completed to-dos were purged.", numDeleted);
        } else if (numDeleted == 0 && numIgnored == 0) {
            message = i18n("There are no completed to-dos to purge.");
        } else {
            type = KMessageWidget::Warning;
            message = i18np("%1 completed to-do was purged.", "%1 completed to-dos were purged.", numDeleted) + QLatin1Char('\n') +
                    i18np("%1 to-do was ignored because it has uncompleted or read-only children.",
                          "%1 to-dos were ignored because they have uncompleted or read-only children.", numIgnored);
        }
    } else {
        message = i18n("An error occurred while purging completed to-dos: %1", mTodoPurger->lastError());
        type = KMessageWidget::Error;
    }

    showMessage(message, type);
}

void CalendarView::showMessage(const QString &message, KMessageWidget::MessageType type)
{
    mMessageWidget->setText(message);
    mMessageWidget->setMessageType(type);
    mMessageWidget->show();
}

Akonadi::Collection CalendarView::selectedCollection() const
{
  return mETMCollectionView ? mETMCollectionView->selectedCollection() : Akonadi::Collection();
}

Akonadi::Collection::List CalendarView::checkedCollections() const
{
  Akonadi::Collection::List collections;
  if ( mETMCollectionView )
    collections = mETMCollectionView->checkedCollections();

  // If the default calendar is here, it should be first.
  int count = collections.count();
  Akonadi::Collection::Id id = CalendarSupport::KCalPrefs::instance()->defaultCalendarId();
  for( int i=0; i<count; ++i ) {
    if ( id == collections[i].id() ) {
      collections.move( i, 0 );
      break;
    }
  }

  return collections;
}

void CalendarView::handleIncidenceCreated(const Akonadi::Item &item)
{
    Akonadi::Collection collection = item.parentCollection();
    if (!collection.isValid()) {
        kWarning() << "Item was creating in an invalid collection !? item id=" << item.id();
        return;
    }

    const bool collectionIsChecked = mETMCollectionView->isChecked(collection);

    if (!collectionIsChecked) {
        QString message;
        if (mETMCollectionView->isVisible()) {
            message = i18n("You created an incidence in a calendar that is currently filtered out.\n"
                           "On the left sidebar, enable it in the calendar manager to see the incidence.");
        } else {
            message = i18n("You created an incidence in a calendar that is currently filtered out.\n"
                           "You can enable it through the calendar manager (Settings->Sidebar->Show Calendar Manager)");
        }

        mMessageWidget->setText(message);
        mMessageWidget->setMessageType(KMessageWidget::Information);
        mMessageWidget->show();
    }
}

