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 TQt, and distribute the resulting executable, 00023 without including the source code for TQt 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 <kmessagebox.h> 00036 #include <kdebug.h> 00037 #include "koprefs.h" 00038 00039 EventArchiver::EventArchiver( TQObject* parent, const char* name ) 00040 : TQObject( parent, name ) 00041 { 00042 } 00043 00044 EventArchiver::~EventArchiver() 00045 { 00046 } 00047 00048 void EventArchiver::runOnce( Calendar* calendar, const TQDate& limitDate, TQWidget* widget ) 00049 { 00050 run( calendar, limitDate, widget, true, true ); 00051 } 00052 00053 void EventArchiver::runAuto( Calendar* calendar, TQWidget* widget, bool withGUI ) 00054 { 00055 TQDate limitDate( TQDate::currentDate() ); 00056 int expiryTime = KOPrefs::instance()->mExpiryTime; 00057 switch (KOPrefs::instance()->mExpiryUnit) { 00058 case KOPrefs::UnitDays: // Days 00059 limitDate = limitDate.addDays( -expiryTime ); 00060 break; 00061 case KOPrefs::UnitWeeks: // Weeks 00062 limitDate = limitDate.addDays( -expiryTime*7 ); 00063 break; 00064 case KOPrefs::UnitMonths: // Months 00065 limitDate = limitDate.addMonths( -expiryTime ); 00066 break; 00067 default: 00068 return; 00069 } 00070 run( calendar, limitDate, widget, withGUI, false ); 00071 } 00072 00073 void EventArchiver::run( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, bool withGUI, 00074 bool errorIfNone ) 00075 { 00076 // We need to use rawEvents, otherwise events hidden by filters will not be archived. 00077 Incidence::List incidences; 00078 Event::List events; 00079 Todo::List todos; 00080 Journal::List journals; 00081 00082 if ( KOPrefs::instance()->mArchiveEvents ) { 00083 events = calendar->rawEvents( 00084 TQDate( 1769, 12, 1 ), 00085 // #29555, also advertised by the "limitDate not included" in the class docu 00086 limitDate.addDays( -1 ), 00087 true ); 00088 } 00089 if ( KOPrefs::instance()->mArchiveTodos ) { 00090 Todo::List t = calendar->rawTodos(); 00091 Todo::List::ConstIterator it; 00092 for( it = t.begin(); it != t.end(); ++it ) { 00093 const bool todoComplete = (*it) && 00094 (*it)->isCompleted() && 00095 ( (*it)->completed().date() < limitDate ); 00096 00097 if ( todoComplete && !isSubTreeComplete( *it, limitDate ) ) { 00098 // The to-do is complete but some sub-todos are not. 00099 KMessageBox::information( 00100 widget, 00101 i18n( "Unable to archive to-do \"%1\" because at least one of its " 00102 "sub-to-dos does not meet the archival requirements." ).arg( (*it)->summary() ), 00103 i18n( "Archive To-do" ), 00104 "UncompletedChildrenArchiveTodos" ); 00105 } else if ( todoComplete ) { 00106 todos.append( *it ); 00107 } 00108 } 00109 } 00110 00111 incidences = Calendar::mergeIncidenceList( events, todos, journals ); 00112 00113 00114 kdDebug(5850) << "EventArchiver: archiving incidences before " << limitDate << " -> " 00115 << incidences.count() << " incidences found." << endl; 00116 if ( incidences.isEmpty() ) { 00117 if ( withGUI && errorIfNone ) { 00118 KMessageBox::information( 00119 widget, 00120 i18n( "There are no incidences available to archive before the specified cut-off date %1. " 00121 "Archiving will not be performed." ).arg( KGlobal::locale()->formatDate( limitDate ) ), 00122 "ArchiverNoIncidences" ); 00123 } 00124 return; 00125 } 00126 00127 00128 switch ( KOPrefs::instance()->mArchiveAction ) { 00129 case KOPrefs::actionDelete: 00130 deleteIncidences( calendar, limitDate, widget, incidences, withGUI ); 00131 break; 00132 case KOPrefs::actionArchive: 00133 archiveIncidences( calendar, limitDate, widget, incidences, withGUI ); 00134 break; 00135 } 00136 } 00137 00138 void EventArchiver::deleteIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, const Incidence::List& incidences, bool withGUI ) 00139 { 00140 TQStringList incidenceStrs; 00141 Incidence::List::ConstIterator it; 00142 for( it = incidences.begin(); it != incidences.end(); ++it ) { 00143 incidenceStrs.append( (*it)->summary() ); 00144 } 00145 00146 if ( withGUI ) { 00147 int result = KMessageBox::warningContinueCancelList( 00148 widget, i18n("Delete all items before %1 without saving?\n" 00149 "The following items will be deleted:") 00150 .arg(KGlobal::locale()->formatDate(limitDate)), incidenceStrs, 00151 i18n("Delete Old Items"),KStdGuiItem::del()); 00152 if (result != KMessageBox::Continue) 00153 return; 00154 } 00155 for( it = incidences.begin(); it != incidences.end(); ++it ) { 00156 calendar->deleteIncidence( *it ); 00157 } 00158 emit eventsDeleted(); 00159 } 00160 00161 void EventArchiver::archiveIncidences( Calendar* calendar, const TQDate& /*limitDate*/, TQWidget* widget, const Incidence::List& incidences, bool /*withGUI*/) 00162 { 00163 FileStorage storage( calendar ); 00164 00165 // Save current calendar to disk 00166 KTempFile tmpFile; 00167 tmpFile.setAutoDelete(true); 00168 storage.setFileName( tmpFile.name() ); 00169 if ( !storage.save() ) { 00170 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't save calendar to temp file" << endl; 00171 return; 00172 } 00173 00174 // Duplicate current calendar by loading in new calendar object 00175 CalendarLocal archiveCalendar( KOPrefs::instance()->mTimeZoneId ); 00176 00177 FileStorage archiveStore( &archiveCalendar ); 00178 archiveStore.setFileName( tmpFile.name() ); 00179 if (!archiveStore.load()) { 00180 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't load calendar from temp file" << endl; 00181 return; 00182 } 00183 00184 // Strip active events from calendar so that only events to be archived 00185 // remain. This is not really efficient, but there is no other easy way. 00186 TQStringList uids; 00187 Incidence::List allIncidences = archiveCalendar.rawIncidences(); 00188 Incidence::List::ConstIterator it; 00189 for( it = incidences.begin(); it != incidences.end(); ++it ) { 00190 uids << (*it)->uid(); 00191 } 00192 for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) { 00193 if ( !uids.contains( (*it)->uid() ) ) { 00194 archiveCalendar.deleteIncidence( *it ); 00195 } 00196 } 00197 00198 // Get or create the archive file 00199 KURL archiveURL( KOPrefs::instance()->mArchiveFile ); 00200 TQString archiveFile; 00201 00202 if ( KIO::NetAccess::exists( archiveURL, true, widget ) ) { 00203 if( !KIO::NetAccess::download( archiveURL, archiveFile, widget ) ) { 00204 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't download archive file" << endl; 00205 return; 00206 } 00207 // Merge with events to be archived. 00208 archiveStore.setFileName( archiveFile ); 00209 if ( !archiveStore.load() ) { 00210 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't merge with archive file" << endl; 00211 return; 00212 } 00213 } else { 00214 archiveFile = tmpFile.name(); 00215 } 00216 00217 // Save archive calendar 00218 if ( !archiveStore.save() ) { 00219 KMessageBox::error(widget,i18n("Cannot write archive file %1.").arg( archiveStore.fileName() )); 00220 return; 00221 } 00222 00223 // Upload if necessary 00224 KURL srcUrl; 00225 srcUrl.setPath(archiveFile); 00226 if (srcUrl != archiveURL) { 00227 if ( !KIO::NetAccess::upload( archiveFile, archiveURL, widget ) ) { 00228 KMessageBox::error(widget,i18n("Cannot write archive to final destination.")); 00229 return; 00230 } 00231 } 00232 00233 KIO::NetAccess::removeTempFile(archiveFile); 00234 00235 // Delete archived events from calendar 00236 for( it = incidences.begin(); it != incidences.end(); ++it ) { 00237 calendar->deleteIncidence( *it ); 00238 } 00239 emit eventsDeleted(); 00240 } 00241 00242 bool EventArchiver::isSubTreeComplete( const Todo *todo, const TQDate &limitDate, 00243 TQStringList checkedUids ) const 00244 { 00245 if ( !todo || !todo->isCompleted() || todo->completed().date() >= limitDate ) { 00246 return false; 00247 } 00248 00249 // This TQList is only to prevent infinit recursion 00250 if ( checkedUids.contains( todo->uid() ) ) { 00251 // Probably will never happen, calendar.cpp checks for this 00252 kdWarning() << "To-do hierarchy loop detected!"; 00253 return false; 00254 } 00255 00256 checkedUids.append( todo->uid() ); 00257 00258 Incidence::List::ConstIterator it; 00259 const Incidence::List relations = todo->relations(); 00260 00261 for( it = relations.begin(); it != relations.end(); ++it ) { 00262 if ( (*it)->type() == "Todo" ) { 00263 const Todo *t = static_cast<const Todo*>( *it ); 00264 if ( !isSubTreeComplete( t, limitDate, checkedUids ) ) { 00265 return false; 00266 } 00267 } 00268 } 00269 00270 return true; 00271 } 00272 00273 #include "eventarchiver.moc"