korganizer

eventarchiver.cpp

00001 /*
00002     This file is part of KOrganizer.
00003     Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
00004     Copyright (c) 2004 David Faure <faure@kde.org>
00005     Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020 
00021     As a special exception, permission is given to link this program
00022     with any edition of Qt, and distribute the resulting executable,
00023     without including the source code for Qt in the source distribution.
00024 */
00025 
00026 #include "eventarchiver.h"
00027 #include <kglobal.h>
00028 #include <klocale.h>
00029 #include <ktempfile.h>
00030 #include <kio/netaccess.h>
00031 #include <kglobal.h>
00032 #include <libkcal/filestorage.h>
00033 #include <libkcal/calendarlocal.h>
00034 #include <libkcal/calendar.h>
00035 #include <libkcal/calhelper.h>
00036 #include <kmessagebox.h>
00037 #include <kdebug.h>
00038 #include "koprefs.h"
00039 
00040 EventArchiver::EventArchiver( QObject* parent, const char* name )
00041  : QObject( parent, name )
00042 {
00043 }
00044 
00045 EventArchiver::~EventArchiver()
00046 {
00047 }
00048 
00049 void EventArchiver::runOnce( Calendar* calendar, const QDate& limitDate, QWidget* widget )
00050 {
00051   run( calendar, limitDate, widget, true, true );
00052 }
00053 
00054 void EventArchiver::runAuto( Calendar* calendar, QWidget* widget, bool withGUI )
00055 {
00056   QDate limitDate( QDate::currentDate() );
00057   int expiryTime = KOPrefs::instance()->mExpiryTime;
00058   switch (KOPrefs::instance()->mExpiryUnit) {
00059   case KOPrefs::UnitDays: // Days
00060     limitDate = limitDate.addDays( -expiryTime );
00061     break;
00062   case KOPrefs::UnitWeeks: // Weeks
00063     limitDate = limitDate.addDays( -expiryTime*7 );
00064     break;
00065   case KOPrefs::UnitMonths: // Months
00066     limitDate = limitDate.addMonths( -expiryTime );
00067     break;
00068   default:
00069     return;
00070   }
00071   run( calendar, limitDate, widget, withGUI, false );
00072 }
00073 
00074 void EventArchiver::run( Calendar* calendar, const QDate& limitDate, QWidget* widget, bool withGUI,
00075                          bool errorIfNone )
00076 {
00077   // We need to use rawEvents, otherwise events hidden by filters will not be archived.
00078   Incidence::List incidences;
00079   Event::List events;
00080   Todo::List todos;
00081   Journal::List journals;
00082 
00083   if ( KOPrefs::instance()->mArchiveEvents ) {
00084     events = calendar->rawEvents(
00085       QDate( 1769, 12, 1 ),
00086       // #29555, also advertised by the "limitDate not included" in the class docu
00087       limitDate.addDays( -1 ),
00088       true );
00089   }
00090   if ( KOPrefs::instance()->mArchiveTodos ) {
00091     Todo::List t = calendar->rawTodos();
00092     Todo::List::ConstIterator it;
00093     for( it = t.begin(); it != t.end(); ++it ) {
00094       const bool todoComplete = (*it) &&
00095                                 (*it)->isCompleted() &&
00096                                 ( (*it)->completed().date() < limitDate );
00097 
00098       if ( todoComplete && !isSubTreeComplete( *it, limitDate ) ) {
00099         // The to-do is complete but some sub-todos are not.
00100         KMessageBox::information(
00101           widget,
00102           i18n( "Unable to archive to-do \"%1\" because at least one of its "
00103                 "sub-to-dos does not meet the archival requirements." ).arg( (*it)->summary() ),
00104           i18n( "Archive To-do" ),
00105           "UncompletedChildrenArchiveTodos" );
00106       } else if ( todoComplete ) {
00107         todos.append( *it );
00108       }
00109     }
00110   }
00111 
00112   const Incidence::List allIncidences = Calendar::mergeIncidenceList( events, todos, journals );
00113 
00114   if (KOPrefs::instance()->mArchiveOwnFoldersOnly) {
00115     for (int i = 0; i < allIncidences.count(); ++i) {
00116       Incidence *incidence = allIncidences[i];
00117       if (CalHelper::isMyCalendarIncidence( calendar, incidence ) )
00118         incidences.append( incidence );
00119     }
00120   } else {
00121     incidences = allIncidences;
00122   }
00123 
00124   kdDebug(5850) << "EventArchiver: archiving incidences before " << limitDate << " -> "
00125                 << incidences.count() << " incidences found." << endl;
00126   if ( incidences.isEmpty() ) {
00127     if ( withGUI && errorIfNone ) {
00128       KMessageBox::information(
00129         widget,
00130         i18n( "There are no incidences available to archive before the specified cut-off date %1. "
00131               "Archiving will not be performed." ).arg( KGlobal::locale()->formatDate( limitDate ) ),
00132         "ArchiverNoIncidences" );
00133     }
00134     return;
00135   }
00136 
00137 
00138   switch ( KOPrefs::instance()->mArchiveAction ) {
00139   case KOPrefs::actionDelete:
00140     deleteIncidences( calendar, limitDate, widget, incidences, withGUI );
00141     break;
00142   case KOPrefs::actionArchive:
00143     archiveIncidences( calendar, limitDate, widget, incidences, withGUI );
00144     break;
00145   }
00146 }
00147 
00148 void EventArchiver::deleteIncidences( Calendar* calendar, const QDate& limitDate, QWidget* widget, const Incidence::List& incidences, bool withGUI )
00149 {
00150   QStringList incidenceStrs;
00151   Incidence::List::ConstIterator it;
00152   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00153     incidenceStrs.append( (*it)->summary() );
00154   }
00155 
00156   if ( withGUI ) {
00157     int result = KMessageBox::warningContinueCancelList(
00158       widget, i18n("Delete all items before %1 without saving?\n"
00159                  "The following items will be deleted:")
00160       .arg(KGlobal::locale()->formatDate(limitDate)), incidenceStrs,
00161          i18n("Delete Old Items"),KStdGuiItem::del());
00162     if (result != KMessageBox::Continue)
00163       return;
00164   }
00165   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00166     calendar->deleteIncidence( *it );
00167   }
00168   emit eventsDeleted();
00169 }
00170 
00171 void EventArchiver::archiveIncidences( Calendar* calendar, const QDate& /*limitDate*/, QWidget* widget, const Incidence::List& incidences, bool /*withGUI*/)
00172 {
00173   FileStorage storage( calendar );
00174 
00175   // Save current calendar to disk
00176   KTempFile tmpFile;
00177   tmpFile.setAutoDelete(true);
00178   storage.setFileName( tmpFile.name() );
00179   if ( !storage.save() ) {
00180     kdDebug(5850) << "EventArchiver::archiveEvents(): Can't save calendar to temp file" << endl;
00181     return;
00182   }
00183 
00184   // Duplicate current calendar by loading in new calendar object
00185   CalendarLocal archiveCalendar( KOPrefs::instance()->mTimeZoneId );
00186 
00187   FileStorage archiveStore( &archiveCalendar );
00188   archiveStore.setFileName( tmpFile.name() );
00189   if (!archiveStore.load()) {
00190     kdDebug(5850) << "EventArchiver::archiveEvents(): Can't load calendar from temp file" << endl;
00191     return;
00192   }
00193 
00194   // Strip active events from calendar so that only events to be archived
00195   // remain. This is not really efficient, but there is no other easy way.
00196   QStringList uids;
00197   Incidence::List allIncidences = archiveCalendar.rawIncidences();
00198   Incidence::List::ConstIterator it;
00199   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00200     uids << (*it)->uid();
00201   }
00202   for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) {
00203     if ( !uids.contains( (*it)->uid() ) ) {
00204       archiveCalendar.deleteIncidence( *it );
00205     }
00206   }
00207 
00208   // Get or create the archive file
00209   KURL archiveURL( KOPrefs::instance()->mArchiveFile );
00210   QString archiveFile;
00211 
00212   if ( KIO::NetAccess::exists( archiveURL, true, widget ) ) {
00213     if( !KIO::NetAccess::download( archiveURL, archiveFile, widget ) ) {
00214       kdDebug(5850) << "EventArchiver::archiveEvents(): Can't download archive file" << endl;
00215       return;
00216     }
00217     // Merge with events to be archived.
00218     archiveStore.setFileName( archiveFile );
00219     if ( !archiveStore.load() ) {
00220       kdDebug(5850) << "EventArchiver::archiveEvents(): Can't merge with archive file" << endl;
00221       return;
00222     }
00223   } else {
00224     archiveFile = tmpFile.name();
00225   }
00226 
00227   // Save archive calendar
00228   if ( !archiveStore.save() ) {
00229     KMessageBox::error(widget,i18n("Cannot write archive file %1.").arg( archiveStore.fileName() ));
00230     return;
00231   }
00232 
00233   // Upload if necessary
00234   KURL srcUrl;
00235   srcUrl.setPath(archiveFile);
00236   if (srcUrl != archiveURL) {
00237     if ( !KIO::NetAccess::upload( archiveFile, archiveURL, widget ) ) {
00238       KMessageBox::error(widget,i18n("Cannot write archive to final destination."));
00239       return;
00240     }
00241   }
00242 
00243   KIO::NetAccess::removeTempFile(archiveFile);
00244 
00245   // Delete archived events from calendar
00246   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00247     calendar->deleteIncidence( *it );
00248   }
00249   emit eventsDeleted();
00250 }
00251 
00252 bool EventArchiver::isSubTreeComplete( const Todo *todo, const QDate &limitDate,
00253                                        QStringList checkedUids ) const
00254 {
00255   if ( !todo || !todo->isCompleted() || todo->completed().date() >= limitDate ) {
00256     return false;
00257   }
00258 
00259   // This QList is only to prevent infinit recursion
00260   if ( checkedUids.contains( todo->uid() ) ) {
00261     // Probably will never happen, calendar.cpp checks for this
00262     kdWarning() << "To-do hierarchy loop detected!";
00263     return false;
00264   }
00265 
00266   checkedUids.append( todo->uid() );
00267 
00268   Incidence::List::ConstIterator it;
00269   const Incidence::List relations = todo->relations();
00270 
00271   for( it = relations.begin(); it != relations.end(); ++it ) {
00272     if ( (*it)->type() == "Todo" ) {
00273       const Todo *t = static_cast<const Todo*>( *it );
00274       if ( !isSubTreeComplete( t, limitDate, checkedUids ) ) {
00275         return false;
00276       }
00277     }
00278   }
00279 
00280   return true;
00281 }
00282 
00283 #include "eventarchiver.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys