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 <kstandarddirs.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 
58 KOIncidenceEditor::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 
82 KOIncidenceEditor::~KOIncidenceEditor()
83 {
84 }
85 
86 void 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 
99 void KOIncidenceEditor::slotApply()
100 {
101  processInput();
102 }
103 
104 void 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 
113 void KOIncidenceEditor::slotCancel()
114 {
115  processCancel();
116  reject();
117 }
118 
119 void 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 
137 void 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 
152 void 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 
167 void 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 
187 void KOIncidenceEditor::slotTemplatesChanged( const TQStringList& newTemplates )
188 {
189  templates() = newTemplates;
190 }
191 
192 void 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 
206 TQWidget *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 
224 class 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 
263 void 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 
273 void 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 
287 void 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 
305 void 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 
351 void KOIncidenceEditor::openURL( const KURL &url )
352 {
353  TQString uri = url.url();
354  UriHandler::process( this, uri );
355 }
356 
357 void KOIncidenceEditor::addAttachments( const TQStringList &attachments,
358  const TQStringList &mimeTypes,
359  bool inlineAttachments )
360 {
361  emit signalAddAttachments( attachments, mimeTypes, inlineAttachments );
362 }
363 
364 void 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 
374 void 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 
390 void 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 
400 void 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.