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   // Delete events from calendar
00166   QValueList<Incidence*> deletedIncidences; /* Possible fix for issue4855 */
00167   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00168     if ( !deletedIncidences.contains( *it ) ) {
00169       calendar->deleteIncidence( *it );
00170       deletedIncidences << *it;
00171     } else {
00172       kdWarning(5850) << "EventArchiver::deleteIncidences(): Tried to delete the same incidence twice!" << endl;
00173     }
00174   }
00175   emit eventsDeleted();
00176 }
00177 
00178 void EventArchiver::archiveIncidences( Calendar* calendar, const QDate& /*limitDate*/, QWidget* widget, const Incidence::List& incidences, bool /*withGUI*/)
00179 {
00180   FileStorage storage( calendar );
00181 
00182   // Save current calendar to disk
00183   KTempFile tmpFile;
00184   tmpFile.setAutoDelete(true);
00185   storage.setFileName( tmpFile.name() );
00186   if ( !storage.save() ) {
00187     kdDebug(5850) << "EventArchiver::archiveEvents(): Can't save calendar to temp file" << endl;
00188     return;
00189   }
00190 
00191   // Duplicate current calendar by loading in new calendar object
00192   CalendarLocal archiveCalendar( KOPrefs::instance()->mTimeZoneId );
00193 
00194   FileStorage archiveStore( &archiveCalendar );
00195   archiveStore.setFileName( tmpFile.name() );
00196   if (!archiveStore.load()) {
00197     kdDebug(5850) << "EventArchiver::archiveEvents(): Can't load calendar from temp file" << endl;
00198     return;
00199   }
00200 
00201   // Strip active events from calendar so that only events to be archived
00202   // remain. This is not really efficient, but there is no other easy way.
00203   QStringList uids;
00204   Incidence::List allIncidences = archiveCalendar.rawIncidences();
00205   Incidence::List::ConstIterator it;
00206   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00207     uids << (*it)->uid();
00208   }
00209   for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) {
00210     if ( !uids.contains( (*it)->uid() ) ) {
00211       archiveCalendar.deleteIncidence( *it );
00212     }
00213   }
00214 
00215   // Get or create the archive file
00216   KURL archiveURL( KOPrefs::instance()->mArchiveFile );
00217   QString archiveFile;
00218 
00219   if ( KIO::NetAccess::exists( archiveURL, true, widget ) ) {
00220     if( !KIO::NetAccess::download( archiveURL, archiveFile, widget ) ) {
00221       kdDebug(5850) << "EventArchiver::archiveEvents(): Can't download archive file" << endl;
00222       return;
00223     }
00224     // Merge with events to be archived.
00225     archiveStore.setFileName( archiveFile );
00226     if ( !archiveStore.load() ) {
00227       kdDebug(5850) << "EventArchiver::archiveEvents(): Can't merge with archive file" << endl;
00228       return;
00229     }
00230   } else {
00231     archiveFile = tmpFile.name();
00232   }
00233 
00234   // Save archive calendar
00235   if ( !archiveStore.save() ) {
00236     KMessageBox::error(widget,i18n("Cannot write archive file %1.").arg( archiveStore.fileName() ));
00237     return;
00238   }
00239 
00240   // Upload if necessary
00241   KURL srcUrl;
00242   srcUrl.setPath(archiveFile);
00243   if (srcUrl != archiveURL) {
00244     if ( !KIO::NetAccess::upload( archiveFile, archiveURL, widget ) ) {
00245       KMessageBox::error(widget,i18n("Cannot write archive to final destination."));
00246       return;
00247     }
00248   }
00249 
00250   KIO::NetAccess::removeTempFile(archiveFile);
00251 
00252   // Delete archived events from calendar
00253   QValueList<Incidence*> deletedIncidences; /* Possible fix for issue4855 */
00254   for( it = incidences.begin(); it != incidences.end(); ++it ) {
00255     if ( !deletedIncidences.contains( *it ) ) {
00256       calendar->deleteIncidence( *it );
00257       deletedIncidences << *it;
00258     } else {
00259       kdWarning(5850) << "EventArchiver::archiveEvents(): Tried to delete the same incidence twice!" << endl;
00260     }
00261   }
00262   emit eventsDeleted();
00263 }
00264 
00265 bool EventArchiver::isSubTreeComplete( const Todo *todo, const QDate &limitDate,
00266                                        QStringList checkedUids ) const
00267 {
00268   if ( !todo || !todo->isCompleted() || todo->completed().date() >= limitDate ) {
00269     return false;
00270   }
00271 
00272   // This QList is only to prevent infinit recursion
00273   if ( checkedUids.contains( todo->uid() ) ) {
00274     // Probably will never happen, calendar.cpp checks for this
00275     kdWarning() << "To-do hierarchy loop detected!";
00276     return false;
00277   }
00278 
00279   checkedUids.append( todo->uid() );
00280 
00281   Incidence::List::ConstIterator it;
00282   const Incidence::List relations = todo->relations();
00283 
00284   for( it = relations.begin(); it != relations.end(); ++it ) {
00285     if ( (*it)->type() == "Todo" ) {
00286       const Todo *t = static_cast<const Todo*>( *it );
00287       if ( !isSubTreeComplete( t, limitDate, checkedUids ) ) {
00288         return false;
00289       }
00290     }
00291   }
00292 
00293   return true;
00294 }
00295 
00296 #include "eventarchiver.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys