korganizer

eventarchiver.cpp
1/*
2 This file is part of KOrganizer.
3 Copyright (c) 2000,2001 Cornelius Schumacher <schumacher@kde.org>
4 Copyright (c) 2004 David Faure <faure@kde.org>
5 Copyright (C) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
21 As a special exception, permission is given to link this program
22 with any edition of TQt, and distribute the resulting executable,
23 without including the source code for TQt in the source distribution.
24*/
25
26#include "eventarchiver.h"
27#include <tdeglobal.h>
28#include <tdelocale.h>
29#include <tdetempfile.h>
30#include <tdeio/netaccess.h>
31#include <tdeglobal.h>
32#include <libkcal/filestorage.h>
33#include <libkcal/calendarlocal.h>
34#include <libkcal/calendar.h>
35#include <tdemessagebox.h>
36#include <kdebug.h>
37#include "koprefs.h"
38
39EventArchiver::EventArchiver( TQObject* parent, const char* name )
40 : TQObject( parent, name )
41{
42}
43
44EventArchiver::~EventArchiver()
45{
46}
47
48void EventArchiver::runOnce( Calendar* calendar, const TQDate& limitDate, TQWidget* widget )
49{
50 run( calendar, limitDate, widget, true, true );
51}
52
53void EventArchiver::runAuto( Calendar* calendar, TQWidget* widget, bool withGUI )
54{
55 TQDate limitDate( TQDate::currentDate() );
56 int expiryTime = KOPrefs::instance()->mExpiryTime;
57 switch (KOPrefs::instance()->mExpiryUnit) {
58 case KOPrefs::UnitDays: // Days
59 limitDate = limitDate.addDays( -expiryTime );
60 break;
61 case KOPrefs::UnitWeeks: // Weeks
62 limitDate = limitDate.addDays( -expiryTime*7 );
63 break;
64 case KOPrefs::UnitMonths: // Months
65 limitDate = limitDate.addMonths( -expiryTime );
66 break;
67 default:
68 return;
69 }
70 run( calendar, limitDate, widget, withGUI, false );
71}
72
73void EventArchiver::run( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, bool withGUI,
74 bool errorIfNone )
75{
76 // We need to use rawEvents, otherwise events hidden by filters will not be archived.
77 Incidence::List incidences;
78 Event::List events;
79 Todo::List todos;
80 Journal::List journals;
81
82 if ( KOPrefs::instance()->mArchiveEvents ) {
83 events = calendar->rawEvents(
84 TQDate( 1769, 12, 1 ),
85 // #29555, also advertised by the "limitDate not included" in the class docu
86 limitDate.addDays( -1 ),
87 true );
88 }
89 if ( KOPrefs::instance()->mArchiveTodos ) {
90 Todo::List t = calendar->rawTodos();
91 Todo::List::ConstIterator it;
92 for( it = t.begin(); it != t.end(); ++it ) {
93 const bool todoComplete = (*it) &&
94 (*it)->isCompleted() &&
95 ( (*it)->completed().date() < limitDate );
96
97 if ( todoComplete && !isSubTreeComplete( *it, limitDate ) ) {
98 // The to-do is complete but some sub-todos are not.
99 KMessageBox::information(
100 widget,
101 i18n( "Unable to archive to-do \"%1\" because at least one of its "
102 "sub-to-dos does not meet the archival requirements." ).arg( (*it)->summary() ),
103 i18n( "Archive To-do" ),
104 "UncompletedChildrenArchiveTodos" );
105 } else if ( todoComplete ) {
106 todos.append( *it );
107 }
108 }
109 }
110
111 incidences = Calendar::mergeIncidenceList( events, todos, journals );
112
113
114 kdDebug(5850) << "EventArchiver: archiving incidences before " << limitDate << " -> "
115 << incidences.count() << " incidences found." << endl;
116 if ( incidences.isEmpty() ) {
117 if ( withGUI && errorIfNone ) {
118 KMessageBox::information(
119 widget,
120 i18n( "There are no incidences available to archive before the specified cut-off date %1. "
121 "Archiving will not be performed." ).arg( TDEGlobal::locale()->formatDate( limitDate ) ),
122 "ArchiverNoIncidences" );
123 }
124 return;
125 }
126
127
128 switch ( KOPrefs::instance()->mArchiveAction ) {
129 case KOPrefs::actionDelete:
130 deleteIncidences( calendar, limitDate, widget, incidences, withGUI );
131 break;
132 case KOPrefs::actionArchive:
133 archiveIncidences( calendar, limitDate, widget, incidences, withGUI );
134 break;
135 }
136}
137
138void EventArchiver::deleteIncidences( Calendar* calendar, const TQDate& limitDate, TQWidget* widget, const Incidence::List& incidences, bool withGUI )
139{
140 TQStringList incidenceStrs;
141 Incidence::List::ConstIterator it;
142 for( it = incidences.begin(); it != incidences.end(); ++it ) {
143 incidenceStrs.append( (*it)->summary() );
144 }
145
146 if ( withGUI ) {
147 int result = KMessageBox::warningContinueCancelList(
148 widget, i18n("Delete all items before %1 without saving?\n"
149 "The following items will be deleted:")
150 .arg(TDEGlobal::locale()->formatDate(limitDate)), incidenceStrs,
151 i18n("Delete Old Items"),KStdGuiItem::del());
152 if (result != KMessageBox::Continue)
153 return;
154 }
155 for( it = incidences.begin(); it != incidences.end(); ++it ) {
156 calendar->deleteIncidence( *it );
157 }
158 emit eventsDeleted();
159}
160
161void EventArchiver::archiveIncidences( Calendar* calendar, const TQDate& /*limitDate*/, TQWidget* widget, const Incidence::List& incidences, bool /*withGUI*/)
162{
163 FileStorage storage( calendar );
164
165 // Save current calendar to disk
166 KTempFile tmpFile;
167 tmpFile.setAutoDelete(true);
168 storage.setFileName( tmpFile.name() );
169 if ( !storage.save() ) {
170 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't save calendar to temp file" << endl;
171 return;
172 }
173
174 // Duplicate current calendar by loading in new calendar object
175 CalendarLocal archiveCalendar( KOPrefs::instance()->mTimeZoneId );
176
177 FileStorage archiveStore( &archiveCalendar );
178 archiveStore.setFileName( tmpFile.name() );
179 if (!archiveStore.load()) {
180 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't load calendar from temp file" << endl;
181 return;
182 }
183
184 // Strip active events from calendar so that only events to be archived
185 // remain. This is not really efficient, but there is no other easy way.
186 TQStringList uids;
187 Incidence::List allIncidences = archiveCalendar.rawIncidences();
188 Incidence::List::ConstIterator it;
189 for( it = incidences.begin(); it != incidences.end(); ++it ) {
190 uids << (*it)->uid();
191 }
192 for( it = allIncidences.begin(); it != allIncidences.end(); ++it ) {
193 if ( !uids.contains( (*it)->uid() ) ) {
194 archiveCalendar.deleteIncidence( *it );
195 }
196 }
197
198 // Get or create the archive file
199 KURL archiveURL( KOPrefs::instance()->mArchiveFile );
200 TQString archiveFile;
201
202 if ( TDEIO::NetAccess::exists( archiveURL, true, widget ) ) {
203 if( !TDEIO::NetAccess::download( archiveURL, archiveFile, widget ) ) {
204 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't download archive file" << endl;
205 return;
206 }
207 // Merge with events to be archived.
208 archiveStore.setFileName( archiveFile );
209 if ( !archiveStore.load() ) {
210 kdDebug(5850) << "EventArchiver::archiveEvents(): Can't merge with archive file" << endl;
211 return;
212 }
213 } else {
214 archiveFile = tmpFile.name();
215 }
216
217 // Save archive calendar
218 if ( !archiveStore.save() ) {
219 KMessageBox::error(widget,i18n("Cannot write archive file %1.").arg( archiveStore.fileName() ));
220 return;
221 }
222
223 // Upload if necessary
224 KURL srcUrl;
225 srcUrl.setPath(archiveFile);
226 if (srcUrl != archiveURL) {
227 if ( !TDEIO::NetAccess::upload( archiveFile, archiveURL, widget ) ) {
228 KMessageBox::error(widget,i18n("Cannot write archive to final destination."));
229 return;
230 }
231 }
232
233 TDEIO::NetAccess::removeTempFile(archiveFile);
234
235 // Delete archived events from calendar
236 for( it = incidences.begin(); it != incidences.end(); ++it ) {
237 calendar->deleteIncidence( *it );
238 }
239 emit eventsDeleted();
240}
241
242bool EventArchiver::isSubTreeComplete( const Todo *todo, const TQDate &limitDate,
243 TQStringList checkedUids ) const
244{
245 if ( !todo || !todo->isCompleted() || todo->completed().date() >= limitDate ) {
246 return false;
247 }
248
249 // This TQPtrList is only to prevent infinit recursion
250 if ( checkedUids.contains( todo->uid() ) ) {
251 // Probably will never happen, calendar.cpp checks for this
252 kdWarning() << "To-do hierarchy loop detected!";
253 return false;
254 }
255
256 checkedUids.append( todo->uid() );
257
258 Incidence::List::ConstIterator it;
259 const Incidence::List relations = todo->relations();
260
261 for( it = relations.begin(); it != relations.end(); ++it ) {
262 if ( (*it)->type() == "Todo" ) {
263 const Todo *t = static_cast<const Todo*>( *it );
264 if ( !isSubTreeComplete( t, limitDate, checkedUids ) ) {
265 return false;
266 }
267 }
268 }
269
270 return true;
271}
272
273#include "eventarchiver.moc"
void runOnce(Calendar *calendar, const TQDate &limitDate, TQWidget *widget)
Delete or archive events once.
void runAuto(Calendar *calendar, TQWidget *widget, bool withGUI)
Delete or archive events.
virtual bool deleteIncidence(Incidence *incidence)
virtual Event::List rawEvents(EventSortField sortField=EventSortUnsorted, SortDirection sortDirection=SortDirectionAscending)=0
virtual Todo::List rawTodos(TodoSortField sortField=TodoSortUnsorted, SortDirection sortDirection=SortDirectionAscending)=0
TQString uid() const
Incidence::List relations() const
bool isCompleted() const
TQDateTime completed() const