/* This file is part of KOrganizer. Copyright (c) 2000,2001 Cornelius Schumacher Copyright (c) 2004 David Faure Copyright (C) 2004 Reinhold Kainhofer 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 TQt, and distribute the resulting executable, without including the source code for TQt in the source distribution. */ #include "eventarchiver.h" #include #include #include #include #include #include #include #include #include #include #include "koprefs.h" EventArchiver::EventArchiver( TQObject* tqparent, const char* name ) : TQObject( tqparent, name ) { } EventArchiver::~EventArchiver() { } void EventArchiver::runOnce( Calendar* calendar, const TQDate& limitDate, TQWidget* widget ) { run( calendar, limitDate, widget, true, true ); } void EventArchiver::runAuto( Calendar* calendar, TQWidget* widget, bool withGUI ) { TQDate limitDate( TQDate::tqcurrentDate() ); int expiryTime = KOPrefs::instance()->mExpiryTime; switch (KOPrefs::instance()->mExpiryUnit) { case KOPrefs::UnitDays: // Days limitDate = limitDate.addDays( -expiryTime ); break; case KOPrefs::UnitWeeks: // Weeks limitDate = limitDate.addDays( -expiryTime*7 ); break; case KOPrefs::UnitMonths: // Months limitDate = limitDate.addMonths( -expiryTime ); break; default: return; } run( calendar, limitDate, widget, withGUI, false ); } void EventArchiver::run( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, bool withGUI, bool errorIfNone ) { // We need to use rawEvents, otherwise events hidden by filters will not be archived. Incidence::List incidences; Event::List events; Todo::List todos; Journal::List journals; if ( KOPrefs::instance()->mArchiveEvents ) { events = calendar->rawEvents( TQDate( 1769, 12, 1 ), // #29555, also advertised by the "limitDate not included" in the class docu limitDate.addDays( -1 ), true ); } if ( KOPrefs::instance()->mArchiveTodos ) { Todo::List t = calendar->rawTodos(); Todo::List::ConstIterator it; for( it = t.begin(); it != t.end(); ++it ) { const bool todoComplete = (*it) && (*it)->isCompleted() && ( (*it)->completed().date() < limitDate ); if ( todoComplete && !isSubTreeComplete( *it, limitDate ) ) { // The to-do is complete but some sub-todos are not. KMessageBox::information( widget, i18n( "Unable to archive to-do \"%1\" because at least one of its " "sub-to-dos does not meet the archival requirements." ).arg( (*it)->summary() ), i18n( "Archive To-do" ), "UncompletedChildrenArchiveTodos" ); } else if ( todoComplete ) { todos.append( *it ); } } } incidences = Calendar::mergeIncidenceList( events, todos, journals ); kdDebug(5850) << "EventArchiver: archiving incidences before " << limitDate << " -> " << incidences.count() << " incidences found." << endl; if ( incidences.isEmpty() ) { if ( withGUI && errorIfNone ) { KMessageBox::information( widget, i18n( "There are no incidences available to archive before the specified cut-off date %1. " "Archiving will not be performed." ).arg( KGlobal::locale()->formatDate( limitDate ) ), "ArchiverNoIncidences" ); } return; } switch ( KOPrefs::instance()->mArchiveAction ) { case KOPrefs::actionDelete: deleteIncidences( calendar, limitDate, widget, incidences, withGUI ); break; case KOPrefs::actionArchive: archiveIncidences( calendar, limitDate, widget, incidences, withGUI ); break; } } void EventArchiver::deleteIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, const Incidence::List& incidences, bool withGUI ) { TQStringList incidenceStrs; Incidence::List::ConstIterator it; for( it = incidences.begin(); it != incidences.end(); ++it ) { incidenceStrs.append( (*it)->summary() ); } if ( withGUI ) { int result = KMessageBox::warningContinueCancelList( widget, i18n("Delete all items before %1 without saving?\n" "The following items will be deleted:") .arg(KGlobal::locale()->formatDate(limitDate)), incidenceStrs, i18n("Delete Old Items"),KStdGuiItem::del()); if (result != KMessageBox::Continue) return; } for( it = incidences.begin(); it != incidences.end(); ++it ) { calendar->deleteIncidence( *it ); } emit eventsDeleted(); } void EventArchiver::archiveIncidences( Calendar* calendar, const TQDate& /*limitDate*/, TQWidget* widget, const Incidence::List& incidences, bool /*withGUI*/) { FileStorage storage( calendar ); // Save current calendar to disk KTempFile tmpFile; tmpFile.setAutoDelete(true); storage.setFileName( tmpFile.name() ); if ( !storage.save() ) { kdDebug(5850) << "EventArchiver::archiveEvents(): Can't save calendar to temp file" << endl; return; } // Duplicate current calendar by loading in new calendar object CalendarLocal archiveCalendar( KOPrefs::instance()->mTimeZoneId ); FileStorage archiveStore( &archiveCalendar ); archiveStore.setFileName( tmpFile.name() ); if (!archiveStore.load()) { kdDebug(5850) << "EventArchiver::archiveEvents(): Can't load calendar from temp file" << endl; return; } // Strip active events from calendar so that only events to be archived // remain. This is not really efficient, but there is no other easy way. TQStringList uids; Incidence::List allIncidences = archiveCalendar.rawIncidences(); Incidence::List::ConstIterator it; for( it = incidences.begin(); it != incidences.end(); ++it ) { uids << (*it)->uid(); } for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) { if ( !uids.tqcontains( (*it)->uid() ) ) { archiveCalendar.deleteIncidence( *it ); } } // Get or create the archive file KURL archiveURL( KOPrefs::instance()->mArchiveFile ); TQString archiveFile; if ( KIO::NetAccess::exists( archiveURL, true, widget ) ) { if( !KIO::NetAccess::download( archiveURL, archiveFile, widget ) ) { kdDebug(5850) << "EventArchiver::archiveEvents(): Can't download archive file" << endl; return; } // Merge with events to be archived. archiveStore.setFileName( archiveFile ); if ( !archiveStore.load() ) { kdDebug(5850) << "EventArchiver::archiveEvents(): Can't merge with archive file" << endl; return; } } else { archiveFile = tmpFile.name(); } // Save archive calendar if ( !archiveStore.save() ) { KMessageBox::error(widget,i18n("Cannot write archive file %1.").arg( archiveStore.fileName() )); return; } // Upload if necessary KURL srcUrl; srcUrl.setPath(archiveFile); if (srcUrl != archiveURL) { if ( !KIO::NetAccess::upload( archiveFile, archiveURL, widget ) ) { KMessageBox::error(widget,i18n("Cannot write archive to final destination.")); return; } } KIO::NetAccess::removeTempFile(archiveFile); // Delete archived events from calendar for( it = incidences.begin(); it != incidences.end(); ++it ) { calendar->deleteIncidence( *it ); } emit eventsDeleted(); } bool EventArchiver::isSubTreeComplete( const Todo *todo, const TQDate &limitDate, TQStringList checkedUids ) const { if ( !todo || !todo->isCompleted() || todo->completed().date() >= limitDate ) { return false; } // This TQList is only to prevent infinit recursion if ( checkedUids.tqcontains( todo->uid() ) ) { // Probably will never happen, calendar.cpp checks for this kdWarning() << "To-do hierarchy loop detected!"; return false; } checkedUids.append( todo->uid() ); Incidence::List::ConstIterator it; const Incidence::List relations = todo->relations(); for( it = relations.begin(); it != relations.end(); ++it ) { if ( (*it)->type() == "Todo" ) { const Todo *t = static_cast( *it ); if ( !isSubTreeComplete( t, limitDate, checkedUids ) ) { return false; } } } return true; } #include "eventarchiver.moc"