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 
39 EventArchiver::EventArchiver( TQObject* parent, const char* name )
40  : TQObject( parent, name )
41 {
42 }
43 
44 EventArchiver::~EventArchiver()
45 {
46 }
47 
48 void EventArchiver::runOnce( Calendar* calendar, const TQDate& limitDate, TQWidget* widget )
49 {
50  run( calendar, limitDate, widget, true, true );
51 }
52 
53 void 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 
73 void 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 
138 void 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 
161 void 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 
242 bool 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