korganizer

koincidenceeditor.cpp
1/*
2 This file is part of KOrganizer.
3
4 Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org>
5 Copyright (C) 2003-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 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
20 As a special exception, permission is given to link this program
21 with any edition of TQt, and distribute the resulting executable,
22 without including the source code for TQt in the source distribution.
23*/
24
25#include <tqtooltip.h>
26#include <tqframe.h>
27#include <tqguardedptr.h>
28#include <tqpixmap.h>
29#include <tqlayout.h>
30#include <tqwidgetstack.h>
31#include <tqdatetime.h>
32#include <tqwhatsthis.h>
33
34#include <kdebug.h>
35#include <tdelocale.h>
36#include <tdestandarddirs.h>
37#include <tdemessagebox.h>
38#include <kinputdialog.h>
39#include <tdeio/netaccess.h>
40#include <tdeabc/addressee.h>
41
42#include <libtdepim/designerfields.h>
43#include <libtdepim/embeddedurlpage.h>
44
45#include <libkcal/calendarlocal.h>
46#include <libkcal/incidence.h>
47#include <libkcal/icalformat.h>
48#include <libkcal/resourcecalendar.h>
49
50#include "koprefs.h"
51#include "koglobals.h"
52#include "koeditordetails.h"
53#include "koeditoralarms.h"
54#include "urihandler.h"
55#include "koincidenceeditor.h"
56#include "templatemanagementdialog.h"
57
58KOIncidenceEditor::KOIncidenceEditor( const TQString &caption,
59 Calendar *calendar, TQWidget *parent )
60 : KDialogBase( Tabbed, caption, Ok | Apply | Cancel | Default, Ok,
61 parent, 0, false, false ),
62 mAttendeeEditor( 0 ), mResource( 0 ), mIsCounter( false ), mIsCreateTask( false ),
63 mRecurIncidence( 0 ), mRecurIncidenceAfterDissoc( 0 )
64{
65 // Set this to be the group leader for all subdialogs - this means
66 // modal subdialogs will only affect this dialog, not the other windows
67 setWFlags( getWFlags() | WGroupLeader );
68
69 mCalendar = calendar;
70
71 if ( KOPrefs::instance()->mCompactDialogs ) {
72 showButton( Apply, false );
73 showButton( Default, false );
74 } else {
75 setButtonText( Default, i18n("&Templates...") );
76 }
77
78 connect( this, TQ_SIGNAL( defaultClicked() ), TQ_SLOT( slotManageTemplates() ) );
79 connect( this, TQ_SIGNAL( finished() ), TQ_SLOT( delayedDestruct() ) );
80}
81
82KOIncidenceEditor::~KOIncidenceEditor()
83{
84}
85
86void KOIncidenceEditor::setupAttendeesTab()
87{
88 TQFrame *topFrame = addPage( i18n("Atte&ndees") );
89 TQWhatsThis::add( topFrame,
90 i18n("The Attendees tab allows you to Add or Remove "
91 "Attendees to/from this event or to-do.") );
92
93 TQBoxLayout *topLayout = new TQVBoxLayout( topFrame );
94
95 mAttendeeEditor = mDetails = new KOEditorDetails( spacingHint(), topFrame );
96 topLayout->addWidget( mDetails );
97}
98
99void KOIncidenceEditor::slotApply()
100{
101 processInput();
102}
103
104void KOIncidenceEditor::slotOk()
105{
106 // "this" can be deleted before processInput() returns (processInput() opens
107 // a non-modal dialog when Kolab is used). So accept should only be executed
108 // when "this" is still valid
109 TQGuardedPtr<TQWidget> ptr( this );
110 if ( processInput() && ptr ) accept();
111}
112
113void KOIncidenceEditor::slotCancel()
114{
115 processCancel();
116 reject();
117}
118
119void KOIncidenceEditor::cancelRemovedAttendees( Incidence *incidence )
120{
121 if ( !incidence ) return;
122
123 // cancelAttendeeEvent removes all attendees from the incidence,
124 // and then only adds those that need to be cancelled (i.e. a mail needs to be sent to them).
125 if ( KOPrefs::instance()->thatIsMe( incidence->organizer().email() ) ) {
126 Incidence *ev = incidence->clone();
127 ev->registerObserver( 0 );
128 mAttendeeEditor->cancelAttendeeEvent( ev );
129 if ( ev->attendeeCount() > 0 ) {
130 emit deleteAttendee( ev );
131 }
132 delete( ev );
133 }
134
135}
136
137void KOIncidenceEditor::slotManageTemplates()
138{
139 kdDebug(5850) << "KOIncidenceEditor::manageTemplates()" << endl;
140
141 TemplateManagementDialog * const d = new TemplateManagementDialog( this, templates() );
142 connect( d, TQ_SIGNAL( loadTemplate( const TQString& ) ),
143 this, TQ_SLOT( slotLoadTemplate( const TQString& ) ) );
144 connect( d, TQ_SIGNAL( templatesChanged( const TQStringList& ) ),
145 this, TQ_SLOT( slotTemplatesChanged( const TQStringList& ) ) );
146 connect( d, TQ_SIGNAL( saveTemplate( const TQString& ) ),
147 this, TQ_SLOT( slotSaveTemplate( const TQString& ) ) );
148 d->exec();
149 return;
150}
151
152void KOIncidenceEditor::saveAsTemplate( Incidence *incidence,
153 const TQString &templateName )
154{
155 if ( !incidence || templateName.isEmpty() ) return;
156
157 TQString fileName = "templates/" + incidence->type();
158 fileName.append( "/" + templateName );
159 fileName = locateLocal( "data", "korganizer/" + fileName );
160
161 CalendarLocal cal( KOPrefs::instance()->mTimeZoneId );
162 cal.addIncidence( incidence );
163 ICalFormat format;
164 format.save( &cal, fileName );
165}
166
167void KOIncidenceEditor::slotLoadTemplate( const TQString& templateName )
168{
169 CalendarLocal cal( KOPrefs::instance()->mTimeZoneId );
170 TQString fileName = locateLocal( "data", "korganizer/templates/" + type() + "/" +
171 templateName );
172
173 if ( fileName.isEmpty() ) {
174 KMessageBox::error( this, i18n("Unable to find template '%1'.")
175 .arg( fileName ) );
176 } else {
177 ICalFormat format;
178 if ( !format.load( &cal, fileName ) ) {
179 KMessageBox::error( this, i18n("Error loading template file '%1'.")
180 .arg( fileName ) );
181 return;
182 }
183 }
184 loadTemplate( cal );
185}
186
187void KOIncidenceEditor::slotTemplatesChanged( const TQStringList& newTemplates )
188{
189 templates() = newTemplates;
190}
191
192void KOIncidenceEditor::setupDesignerTabs( const TQString &type )
193{
194 TQStringList activePages = KOPrefs::instance()->activeDesignerFields();
195
196 TQStringList list = TDEGlobal::dirs()->findAllResources( "data",
197 "korganizer/designer/" + type + "/*.ui", true, true );
198 for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it ) {
199 const TQString &fn = (*it).mid( (*it).findRev('/') + 1 );
200 if ( activePages.find( fn ) != activePages.end() ) {
201 addDesignerTab( *it );
202 }
203 }
204}
205
206TQWidget *KOIncidenceEditor::addDesignerTab( const TQString &uifile )
207{
208 kdDebug(5850) << "Designer tab: " << uifile << endl;
209
210 KPIM::DesignerFields *wid = new KPIM::DesignerFields( uifile, 0 );
211 mDesignerFields.append( wid );
212
213 TQFrame *topFrame = addPage( wid->title() );
214
215 TQBoxLayout *topLayout = new TQVBoxLayout( topFrame );
216
217 wid->reparent( topFrame, 0, TQPoint() );
218 topLayout->addWidget( wid );
219 mDesignerFieldForWidget[ topFrame ] = wid;
220
221 return topFrame;
222}
223
224class KCalStorage : public KPIM::DesignerFields::Storage
225{
226 public:
227 KCalStorage( Incidence *incidence )
228 : mIncidence( incidence )
229 {
230 }
231
232 TQStringList keys()
233 {
234 TQStringList keys;
235
236 TQMap<TQCString, TQString> props = mIncidence->customProperties();
237 TQMap<TQCString, TQString>::ConstIterator it;
238 for( it = props.begin(); it != props.end(); ++it ) {
239 TQString customKey = it.key();
240 TQStringList parts = TQStringList::split( "-", customKey );
241 if ( parts.count() != 4 ) continue;
242 if ( parts[ 2 ] != "KORGANIZER" ) continue;
243 keys.append( parts[ 3 ] );
244 }
245
246 return keys;
247 }
248
249 TQString read( const TQString &key )
250 {
251 return mIncidence->customProperty( "KORGANIZER", key.utf8() );
252 }
253
254 void write( const TQString &key, const TQString &value )
255 {
256 mIncidence->setCustomProperty( "KORGANIZER", key.utf8(), value );
257 }
258
259 private:
260 Incidence *mIncidence;
261};
262
263void KOIncidenceEditor::readDesignerFields( Incidence *i )
264{
265 KCalStorage storage( i );
266 KPIM::DesignerFields *fields;
267 for( fields = mDesignerFields.first(); fields;
268 fields = mDesignerFields.next() ) {
269 fields->load( &storage );
270 }
271}
272
273void KOIncidenceEditor::writeDesignerFields( Incidence *i )
274{
275 kdDebug(5850) << "KOIncidenceEditor::writeDesignerFields()" << endl;
276
277 KCalStorage storage( i );
278 KPIM::DesignerFields *fields;
279 for( fields = mDesignerFields.first(); fields;
280 fields = mDesignerFields.next() ) {
281 kdDebug(5850) << "Write Field " << fields->title() << endl;
282 fields->save( &storage );
283 }
284}
285
286
287void KOIncidenceEditor::setupEmbeddedURLPage( const TQString &label,
288 const TQString &url, const TQString &mimetype )
289{
290 kdDebug(5850) << "KOIncidenceEditor::setupEmbeddedURLPage()" << endl;
291 kdDebug(5850) << "label=" << label << ", url=" << url << ", mimetype=" << mimetype << endl;
292 TQFrame *topFrame = addPage( label );
293 TQBoxLayout *topLayout = new TQVBoxLayout( topFrame );
294
295 KPIM::EmbeddedURLPage *wid = new KPIM::EmbeddedURLPage( url, mimetype,
296 topFrame );
297 topLayout->addWidget( wid );
298 mEmbeddedURLPages.append( topFrame );
299 connect( wid, TQ_SIGNAL( openURL( const KURL & ) ) ,
300 this, TQ_SLOT( openURL( const KURL & ) ) );
301 // TODO: Call this method only when the tab is actually activated!
302 wid->loadContents();
303}
304
305void KOIncidenceEditor::createEmbeddedURLPages( Incidence *i )
306{
307 kdDebug(5850) << "KOIncidenceEditor::createEmbeddedURLPages()" << endl;
308
309 if ( !i ) return;
310 if ( !mEmbeddedURLPages.isEmpty() ) {
311 kdDebug(5850) << "mEmbeddedURLPages are not empty, clearing it!" << endl;
312 mEmbeddedURLPages.setAutoDelete( true );
313 mEmbeddedURLPages.clear();
314 mEmbeddedURLPages.setAutoDelete( false );
315 }
316 if ( !mAttachedDesignerFields.isEmpty() ) {
317 for ( TQPtrList<TQWidget>::Iterator it = mAttachedDesignerFields.begin();
318 it != mAttachedDesignerFields.end(); ++it ) {
319 if ( mDesignerFieldForWidget.contains( *it ) ) {
320 mDesignerFields.remove( mDesignerFieldForWidget[ *it ] );
321 }
322 }
323 mAttachedDesignerFields.setAutoDelete( true );
324 mAttachedDesignerFields.clear();
325 mAttachedDesignerFields.setAutoDelete( false );
326 }
327
328 Attachment::List att = i->attachments();
329 for ( Attachment::List::Iterator it = att.begin(); it != att.end(); ++it ) {
330 Attachment *a = (*it);
331 kdDebug(5850) << "Iterating over the attachments " << endl;
332 kdDebug(5850) << "label=" << a->label() << ", url=" << a->uri() << ", mimetype=" << a->mimeType() << endl;
333 if ( a && a->showInline() && a->isUri() ) {
334 // TODO: Allow more mime-types, but add security checks!
335/* if ( a->mimeType() == "application/x-designer" ) {
336 TQString tmpFile;
337 if ( TDEIO::NetAccess::download( a->uri(), tmpFile, this ) ) {
338 mAttachedDesignerFields.append( addDesignerTab( tmpFile ) );
339 TDEIO::NetAccess::removeTempFile( tmpFile );
340 }
341 } else*/
342 // TODO: Enable that check again!
343 if ( a->mimeType() == "text/html" )
344 {
345 setupEmbeddedURLPage( a->label(), a->uri(), a->mimeType() );
346 }
347 }
348 }
349}
350
351void KOIncidenceEditor::openURL( const KURL &url )
352{
353 TQString uri = url.url();
354 UriHandler::process( this, uri );
355}
356
357void KOIncidenceEditor::addAttachments( const TQStringList &attachments,
358 const TQStringList &mimeTypes,
359 bool inlineAttachments )
360{
361 emit signalAddAttachments( attachments, mimeTypes, inlineAttachments );
362}
363
364void KOIncidenceEditor::addAttendees( const TQStringList &attendees )
365{
366 TQStringList::ConstIterator it;
367 for ( it = attendees.begin(); it != attendees.end(); ++it ) {
368 TQString name, email;
369 TDEABC::Addressee::parseEmailAddress( *it, name, email );
370 mAttendeeEditor->insertAttendee( new Attendee( name, email, true, Attendee::NeedsAction ) );
371 }
372}
373
374void KOIncidenceEditor::setResource( ResourceCalendar *res, const TQString &subRes )
375{
376 TQString label;
377 if ( res ) {
378 if ( !res->subresources().isEmpty() && !subRes.isEmpty() ) {
379 label = res->labelForSubresource( subRes );
380 } else {
381 label = res->resourceName();
382 }
383 }
384
385 mResource = res;
386 mSubResource = subRes;
387}
388
389
390void KOIncidenceEditor::selectCreateTask( bool enable )
391{
392 mIsCreateTask = enable;
393 if ( mIsCreateTask ) {
394 setCaption( i18n( "Create to-do" ) );
395 setButtonOK( i18n( "Create to-do" ) );
396 showButtonApply( false );
397 }
398}
399
400void KOIncidenceEditor::selectInvitationCounterProposal(bool enable)
401{
402 mIsCounter = enable;
403 if ( mIsCounter ) {
404 setCaption( i18n( "Counter proposal" ) );
405 setButtonOK( i18n( "Counter proposal" ) );
406 showButtonApply( false );
407 }
408}
409
411 Incidence *incAfterDissociation )
412{
413 mRecurIncidence = originalIncidence;
414 mRecurIncidenceAfterDissoc = incAfterDissociation;
415}
416
417
418#include "koincidenceeditor.moc"
bool load(Calendar *calendar, const TQString &fileName)
bool save(Calendar *calendar, const TQString &fileName)
int attendeeCount() const
void registerObserver(Observer *)
virtual Incidence * clone()=0
Attachment::List attachments() const
virtual TQStringList subresources() const
virtual const TQString labelForSubresource(const TQString &resource) const
void cancelAttendeeEvent(KCal::Incidence *incidence)
return a clone of the event with attendees to be canceld
KOIncidenceEditor(const TQString &caption, Calendar *calendar, TQWidget *parent)
Construct new IncidenceEditor.
void setRecurringIncidence(Incidence *originalIncidence, Incidence *incAfterDissociation)
This should be called when editing only one occurrence of a recurring incidence, before showing the e...
void addAttendees(const TQStringList &attendees)
Adds attendees to the editor.
void addAttachments(const TQStringList &attachments, const TQStringList &mimeTypes=TQStringList(), bool inlineAttachment=false)
Adds attachments to the editor.
virtual bool processInput()
Process user input and create or update event.