kmail

recipientseditor.cpp
1/*
2 This file is part of KMail.
3
4 Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
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 "recipientseditor.h"
26
27#include "recipientspicker.h"
28#include "twindowpositioner.h"
29#include "distributionlistdialog.h"
30#include "globalsettings.h"
31
32#include <libemailfunctions/email.h>
33
34#include <tdeapplication.h>
35#include <tdecompletionbox.h>
36#include <kdebug.h>
37#include <kinputdialog.h>
38#include <tdelocale.h>
39#include <kiconloader.h>
40#include <tdemessagebox.h>
41
42#include <tqlayout.h>
43#include <tqlabel.h>
44#include <tqscrollview.h>
45#include <tqcombobox.h>
46#include <tqhbox.h>
47#include <tqtimer.h>
48#include <tqpushbutton.h>
49#include <tqstylesheet.h>
50
51Recipient::Recipient( const TQString &email, Recipient::Type type )
52 : mEmail( email ), mType( type )
53{
54}
55
56void Recipient::setType( Type type )
57{
58 mType = type;
59}
60
61Recipient::Type Recipient::type() const
62{
63 return mType;
64}
65
66void Recipient::setEmail( const TQString &email )
67{
68 mEmail = email;
69}
70
71TQString Recipient::email() const
72{
73 return mEmail;
74}
75
76bool Recipient::isEmpty() const
77{
78 return mEmail.isEmpty();
79}
80
81int Recipient::typeToId( Recipient::Type type )
82{
83 return static_cast<int>( type );
84}
85
86Recipient::Type Recipient::idToType( int id )
87{
88 return static_cast<Type>( id );
89}
90
91TQString Recipient::typeLabel() const
92{
93 return typeLabel( mType );
94}
95
96TQString Recipient::typeLabel( Recipient::Type type )
97{
98 switch( type ) {
99 case To:
100 return i18n("To");
101 case Cc:
102 return i18n("CC");
103 case Bcc:
104 return i18n("BCC");
105 case Undefined:
106 break;
107 }
108
109 return i18n("<Undefined RecipientType>");
110}
111
112TQStringList Recipient::allTypeLabels()
113{
114 TQStringList types;
115 types.append( typeLabel( To ) );
116 types.append( typeLabel( Cc ) );
117 types.append( typeLabel( Bcc ) );
118 return types;
119}
120
121
122RecipientComboBox::RecipientComboBox( TQWidget *parent )
123 : TQComboBox( parent )
124{
125}
126
127void RecipientComboBox::keyPressEvent( TQKeyEvent *ev )
128{
129 if ( ev->key() == Key_Right ) emit rightPressed();
130 else TQComboBox::keyPressEvent( ev );
131}
132
133
134void RecipientLineEdit::keyPressEvent( TQKeyEvent *ev )
135{
136 if ( ev->key() == Key_Backspace && text().isEmpty() ) {
137 ev->accept();
138 emit deleteMe();
139 } else if ( ev->key() == Key_Left && cursorPosition() == 0 ) {
140 emit leftPressed();
141 } else if ( ev->key() == Key_Right && cursorPosition() == (int)text().length() ) {
142 emit rightPressed();
143 } else {
144 KMLineEdit::keyPressEvent( ev );
145 }
146}
147
148RecipientLine::RecipientLine( TQWidget *parent )
149 : TQWidget( parent ), mRecipientsCount( 0 ), mModified( false )
150{
151 TQBoxLayout *topLayout = new TQHBoxLayout( this );
152 topLayout->setSpacing( KDialog::spacingHint() );
153
154 TQStringList recipientTypes = Recipient::allTypeLabels();
155
156 mCombo = new RecipientComboBox( this );
157 mCombo->insertStringList( recipientTypes );
158 topLayout->addWidget( mCombo );
159 TQToolTip::add( mCombo, i18n("Select type of recipient") );
160
161 mEdit = new RecipientLineEdit( this );
162 TQToolTip::add( mEdit,
163 i18n( "Set the list of email addresses to receive this message" ) );
164 topLayout->addWidget( mEdit );
165 connect( mEdit, TQ_SIGNAL( returnPressed() ), TQ_SLOT( slotReturnPressed() ) );
166 connect( mEdit, TQ_SIGNAL( deleteMe() ), TQ_SLOT( slotPropagateDeletion() ) );
167 connect( mEdit, TQ_SIGNAL( textChanged( const TQString & ) ),
168 TQ_SLOT( analyzeLine( const TQString & ) ) );
169 connect( mEdit, TQ_SIGNAL( focusUp() ), TQ_SLOT( slotFocusUp() ) );
170 connect( mEdit, TQ_SIGNAL( focusDown() ), TQ_SLOT( slotFocusDown() ) );
171 connect( mEdit, TQ_SIGNAL( rightPressed() ), TQ_SIGNAL( rightPressed() ) );
172
173 connect( mEdit, TQ_SIGNAL( leftPressed() ), mCombo, TQ_SLOT( setFocus() ) );
174 connect( mCombo, TQ_SIGNAL( rightPressed() ), mEdit, TQ_SLOT( setFocus() ) );
175
176 connect( mCombo, TQ_SIGNAL( activated ( int ) ),
177 this, TQ_SLOT( slotTypeModified() ) );
178
179 mRemoveButton = new TQPushButton( this );
180 mRemoveButton->setIconSet( TDEApplication::reverseLayout() ? SmallIconSet("locationbar_erase") : SmallIconSet( "clear_left" ) );
181 topLayout->addWidget( mRemoveButton );
182 connect( mRemoveButton, TQ_SIGNAL( clicked() ), TQ_SLOT( slotPropagateDeletion() ) );
183 TQToolTip::add( mRemoveButton, i18n("Remove recipient line") );
184}
185
186void RecipientLine::slotFocusUp()
187{
188 emit upPressed( this );
189}
190
191void RecipientLine::slotFocusDown()
192{
193 emit downPressed( this );
194}
195
196void RecipientLine::slotTypeModified()
197{
198 mModified = true;
199
200 emit typeModified( this );
201}
202
203void RecipientLine::analyzeLine( const TQString &text )
204{
205 TQStringList r = KPIM::splitEmailAddrList( text );
206 if ( int( r.count() ) != mRecipientsCount ) {
207 mRecipientsCount = r.count();
208 emit countChanged();
209 }
210}
211
212int RecipientLine::recipientsCount()
213{
214 return mRecipientsCount;
215}
216
217void RecipientLine::setRecipient( const Recipient &rec )
218{
219 mEdit->setText( rec.email() );
220 mCombo->setCurrentItem( Recipient::typeToId( rec.type() ) );
221}
222
223void RecipientLine::setRecipient( const TQString &email )
224{
225 setRecipient( Recipient( email ) );
226}
227
228Recipient RecipientLine::recipient() const
229{
230 return Recipient( mEdit->text(),
231 Recipient::idToType( mCombo->currentItem() ) );
232}
233
234void RecipientLine::setRecipientType( Recipient::Type type )
235{
236 mCombo->setCurrentItem( Recipient::typeToId( type ) );
237}
238
239Recipient::Type RecipientLine::recipientType() const
240{
241 return Recipient::idToType( mCombo->currentItem() );
242}
243
244void RecipientLine::activate()
245{
246 mEdit->setFocus();
247}
248
249bool RecipientLine::isActive()
250{
251 return mEdit->hasFocus();
252}
253
254bool RecipientLine::isEmpty()
255{
256 return mEdit->text().isEmpty();
257}
258
259bool RecipientLine::isModified()
260{
261 return mModified || mEdit->isModified();
262}
263
264void RecipientLine::clearModified()
265{
266 mModified = false;
267 mEdit->clearModified();
268}
269
270void RecipientLine::slotReturnPressed()
271{
272 emit returnPressed( this );
273}
274
275void RecipientLine::slotPropagateDeletion()
276{
277 emit deleteLine( this );
278}
279
280void RecipientLine::keyPressEvent( TQKeyEvent *ev )
281{
282 if ( ev->key() == Key_Up ) {
283 emit upPressed( this );
284 } else if ( ev->key() == Key_Down ) {
285 emit downPressed( this );
286 }
287}
288
289int RecipientLine::setComboWidth( int w )
290{
291 w = TQMAX( w, mCombo->sizeHint().width() );
292 mCombo->setFixedWidth( w );
293 mCombo->updateGeometry();
294 parentWidget()->updateGeometry();
295 return w;
296}
297
298void RecipientLine::fixTabOrder( TQWidget *previous )
299{
300 setTabOrder( previous, mCombo );
301 setTabOrder( mCombo, mEdit );
302 setTabOrder( mEdit, mRemoveButton );
303}
304
305TQWidget *RecipientLine::tabOut() const
306{
307 return mRemoveButton;
308}
309
310void RecipientLine::clear()
311{
312 mEdit->clear();
313}
314
315void RecipientLine::setRemoveLineButtonEnabled( bool b )
316{
317 mRemoveButton->setEnabled( b );
318}
319
320
321// ------------ RecipientsView ---------------------
322
323RecipientsView::RecipientsView( TQWidget *parent )
324 : TQScrollView( parent ), mCurDelLine( 0 ),
325 mLineHeight( 0 ), mFirstColumnWidth( 0 ),
326 mModified( false )
327{
328 mCompletionMode = TDEGlobalSettings::completionMode();
329 setHScrollBarMode( AlwaysOff );
330 setLineWidth( 0 );
331
332 addLine();
333 setResizePolicy( TQScrollView::Manual );
334 setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding );
335
336 viewport()->setPaletteBackgroundColor( paletteBackgroundColor() );
337}
338
339RecipientLine *RecipientsView::activeLine()
340{
341 return mLines.last();
342}
343
344RecipientLine *RecipientsView::emptyLine()
345{
346 RecipientLine *line;
347 for( line = mLines.first(); line; line = mLines.next() ) {
348 if ( line->isEmpty() ) return line;
349 }
350
351 return 0;
352}
353
354RecipientLine *RecipientsView::addLine()
355{
356 RecipientLine *line = new RecipientLine( viewport() );
357 addChild( line, 0, mLines.count() * mLineHeight );
358 line->mEdit->setCompletionMode( mCompletionMode );
359 line->show();
360 connect( line, TQ_SIGNAL( returnPressed( RecipientLine * ) ),
361 TQ_SLOT( slotReturnPressed( RecipientLine * ) ) );
362 connect( line, TQ_SIGNAL( upPressed( RecipientLine * ) ),
363 TQ_SLOT( slotUpPressed( RecipientLine * ) ) );
364 connect( line, TQ_SIGNAL( downPressed( RecipientLine * ) ),
365 TQ_SLOT( slotDownPressed( RecipientLine * ) ) );
366 connect( line, TQ_SIGNAL( rightPressed() ), TQ_SIGNAL( focusRight() ) );
367 connect( line, TQ_SIGNAL( deleteLine( RecipientLine * ) ),
368 TQ_SLOT( slotDecideLineDeletion( RecipientLine * ) ) );
369 connect( line, TQ_SIGNAL( countChanged() ), TQ_SLOT( calculateTotal() ) );
370 connect( line, TQ_SIGNAL( typeModified( RecipientLine * ) ),
371 TQ_SLOT( slotTypeModified( RecipientLine * ) ) );
372 connect( line->mEdit, TQ_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ),
373 TQ_SLOT( setCompletionMode( TDEGlobalSettings::Completion ) ) );
374
375 if ( mLines.last() ) {
376 if ( mLines.count() == 1 ) {
377 if ( GlobalSettings::self()->secondRecipientTypeDefault() ==
378 GlobalSettings::EnumSecondRecipientTypeDefault::To ) {
379 line->setRecipientType( Recipient::To );
380 } else {
381 if ( mLines.last()->recipientType() == Recipient::Bcc ) {
382 line->setRecipientType( Recipient::To );
383 } else {
384 line->setRecipientType( Recipient::Cc );
385 }
386 }
387 } else {
388 line->setRecipientType( mLines.last()->recipientType() );
389 }
390 line->fixTabOrder( mLines.last()->tabOut() );
391 }
392
393 mLines.append( line );
394 // If there is only one line, removing it makes no sense
395 if ( mLines.count() == 1 ) {
396 mLines.first()->setRemoveLineButtonEnabled( false );
397 } else {
398 mLines.first()->setRemoveLineButtonEnabled( true );
399 }
400
401 mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth );
402
403 mLineHeight = line->minimumSizeHint().height();
404
405 line->resize( viewport()->width(), mLineHeight );
406
407 resizeView();
408
409 calculateTotal();
410
411 ensureVisible( 0, mLines.count() * mLineHeight );
412
413 return line;
414}
415
416void RecipientsView::slotTypeModified( RecipientLine *line )
417{
418 if ( mLines.count() == 2 ||
419 ( mLines.count() == 3 && mLines.at( 2 )->isEmpty() ) ) {
420 if ( mLines.at( 1 ) == line ) {
421 if ( line->recipientType() == Recipient::To ) {
422 GlobalSettings::self()->setSecondRecipientTypeDefault(
423 GlobalSettings::EnumSecondRecipientTypeDefault::To );
424 } else if ( line->recipientType() == Recipient::Cc ) {
425 GlobalSettings::self()->setSecondRecipientTypeDefault(
426 GlobalSettings::EnumSecondRecipientTypeDefault::Cc );
427 }
428 }
429 }
430}
431
432void RecipientsView::calculateTotal()
433{
434 int count = 0;
435 int empty = 0;
436
437 RecipientLine *line;
438 for( line = mLines.first(); line; line = mLines.next() ) {
439 if ( line->isEmpty() ) ++empty;
440 else count += line->recipientsCount();
441 }
442
443 if ( empty == 0 ) addLine();
444
445 emit totalChanged( count, mLines.count() );
446}
447
448void RecipientsView::slotReturnPressed( RecipientLine *line )
449{
450 if ( !line->recipient().isEmpty() ) {
451 RecipientLine *empty = emptyLine();
452 if ( !empty ) empty = addLine();
453 activateLine( empty );
454 }
455}
456
457void RecipientsView::slotDownPressed( RecipientLine *line )
458{
459 int pos = mLines.find( line );
460 if ( pos >= (int)mLines.count() - 1 ) {
461 emit focusDown();
462 } else if ( pos >= 0 ) {
463 activateLine( mLines.at( pos + 1 ) );
464 }
465}
466
467void RecipientsView::slotUpPressed( RecipientLine *line )
468{
469 int pos = mLines.find( line );
470 if ( pos > 0 ) {
471 activateLine( mLines.at( pos - 1 ) );
472 } else {
473 emit focusUp();
474 }
475}
476
477void RecipientsView::slotDecideLineDeletion( RecipientLine *line )
478{
479 if ( !line->isEmpty() )
480 mModified = true;
481 if ( mLines.count() == 1 ) {
482 line->clear();
483 } else {
484 mCurDelLine = line;
485 TQTimer::singleShot( 0, this, TQ_SLOT( slotDeleteLine( ) ) );
486 }
487}
488
489void RecipientsView::slotDeleteLine()
490{
491 if ( !mCurDelLine )
492 return;
493
494 RecipientLine *line = mCurDelLine;
495 int pos = mLines.find( line );
496
497 int newPos;
498 if ( pos == 0 ) newPos = pos + 1;
499 else newPos = pos - 1;
500
501 // if there is something left to activate, do so
502 if ( mLines.at( newPos ) )
503 mLines.at( newPos )->activate();
504
505 mLines.remove( line );
506 removeChild( line );
507 delete line;
508
509 bool atLeastOneToLine = false;
510 unsigned int firstCC = 0;
511 for( uint i = pos; i < mLines.count(); ++i ) {
512 RecipientLine *line = mLines.at( i );
513 moveChild( line, childX( line ), childY( line ) - mLineHeight );
514 if ( line->recipientType() == Recipient::To )
515 atLeastOneToLine = true;
516 else if ( ( line->recipientType() == Recipient::Cc ) && ( i == 0 ) )
517 firstCC = i;
518 }
519 // only one left, can't remove that one
520 if ( mLines.count() == 1 )
521 mLines.first()->setRemoveLineButtonEnabled( false );
522
523 if ( !atLeastOneToLine )
524 mLines.at( firstCC )->setRecipientType( Recipient::To );
525
526 calculateTotal();
527
528 resizeView();
529}
530
531void RecipientsView::resizeView()
532{
533 resizeContents( width(), mLines.count() * mLineHeight );
534
535 if ( mLines.count() < 6 ) {
536// setFixedHeight( mLineHeight * mLines.count() );
537 }
538
539 parentWidget()->layout()->activate();
540 emit sizeHintChanged();
541 TQTimer::singleShot( 0, this, TQ_SLOT(moveCompletionPopup()) );
542}
543
544void RecipientsView::activateLine( RecipientLine *line )
545{
546 line->activate();
547 ensureVisible( 0, childY( line ) );
548}
549
550void RecipientsView::viewportResizeEvent ( TQResizeEvent *ev )
551{
552 for( uint i = 0; i < mLines.count(); ++i ) {
553 mLines.at( i )->resize( ev->size().width(), mLineHeight );
554 }
555 ensureVisible( 0, mLines.count() * mLineHeight );
556}
557
558TQSize RecipientsView::sizeHint() const
559{
560 return TQSize( 200, mLineHeight * mLines.count() );
561}
562
563TQSize RecipientsView::minimumSizeHint() const
564{
565 int height;
566 uint numLines = 5;
567 if ( mLines.count() < numLines ) height = mLineHeight * mLines.count();
568 else height = mLineHeight * numLines;
569 return TQSize( 200, height );
570}
571
572Recipient::List RecipientsView::recipients() const
573{
574 Recipient::List recipients;
575
576 TQPtrListIterator<RecipientLine> it( mLines );
577 RecipientLine *line;
578 while( ( line = it.current() ) ) {
579 if ( !line->recipient().isEmpty() ) {
580 recipients.append( line->recipient() );
581 }
582
583 ++it;
584 }
585
586 return recipients;
587}
588
589void RecipientsView::setCompletionMode ( TDEGlobalSettings::Completion mode )
590{
591 if ( mCompletionMode == mode )
592 return;
593 mCompletionMode = mode;
594
595 TQPtrListIterator<RecipientLine> it( mLines );
596 RecipientLine *line;
597 while( ( line = it.current() ) ) {
598 line->mEdit->blockSignals( true );
599 line->mEdit->setCompletionMode( mode );
600 line->mEdit->blockSignals( false );
601 ++it;
602 }
603 emit completionModeChanged( mode ); //report change to RecipientsEditor
604}
605
606void RecipientsView::removeRecipient( const TQString & recipient,
607 Recipient::Type type )
608{
609 // search a line which matches recipient and type
610 TQPtrListIterator<RecipientLine> it( mLines );
611 RecipientLine *line;
612 while( ( line = it.current() ) ) {
613 if ( ( line->recipient().email() == recipient ) &&
614 ( line->recipientType() == type ) ) {
615 break;
616 }
617 ++it;
618 }
619 if ( line )
620 line->slotPropagateDeletion();
621}
622
623bool RecipientsView::isModified()
624{
625 if ( mModified )
626 return true;
627
628 TQPtrListIterator<RecipientLine> it( mLines );
629 RecipientLine *line;
630 while( ( line = it.current() ) ) {
631 if ( line->isModified() ) {
632 return true;
633 }
634 ++it;
635 }
636
637 return false;
638}
639
640void RecipientsView::clearModified()
641{
642 mModified = false;
643
644 TQPtrListIterator<RecipientLine> it( mLines );
645 RecipientLine *line;
646 while( ( line = it.current() ) ) {
647 line->clearModified();
648 ++it;
649 }
650}
651
652void RecipientsView::setFocus()
653{
654 if ( mLines.last()->isActive() ) setFocusBottom();
655 else setFocusTop();
656}
657
658void RecipientsView::setFocusTop()
659{
660 RecipientLine *line = mLines.first();
661 if ( line ) line->activate();
662 else kdWarning() << "No first" << endl;
663}
664
665void RecipientsView::setFocusBottom()
666{
667 RecipientLine *line = mLines.last();
668 if ( line ) line->activate();
669 else kdWarning() << "No last" << endl;
670}
671
672int RecipientsView::setFirstColumnWidth( int w )
673{
674 mFirstColumnWidth = w;
675
676 TQPtrListIterator<RecipientLine> it( mLines );
677 RecipientLine *line;
678 while( ( line = it.current() ) ) {
679 mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth );
680 ++it;
681 }
682
683 resizeView();
684 return mFirstColumnWidth;
685}
686
687void RecipientsView::moveCompletionPopup()
688{
689 for( RecipientLine* line = mLines.first(); line; line = mLines.next() ) {
690 if ( line->lineEdit()->completionBox( false ) ) {
691 if ( line->lineEdit()->completionBox()->isVisible() ) {
692 // ### trigger moving, is there a nicer way to do that?
693 line->lineEdit()->completionBox()->hide();
694 line->lineEdit()->completionBox()->show();
695 }
696 }
697 }
698
699}
700
701RecipientsToolTip::RecipientsToolTip( RecipientsView *view, TQWidget *parent )
702 : TQToolTip( parent ), mView( view )
703{
704}
705
706TQString RecipientsToolTip::line( const Recipient &r )
707{
708 TQString txt = r.email();
709
710 return "&nbsp;&nbsp;" + TQStyleSheet::escape( txt ) + "<br/>";
711}
712
713void RecipientsToolTip::maybeTip( const TQPoint & p )
714{
715 TQString text = "<qt>";
716
717 TQString to;
718 TQString cc;
719 TQString bcc;
720
721 Recipient::List recipients = mView->recipients();
722 Recipient::List::ConstIterator it;
723 for( it = recipients.begin(); it != recipients.end(); ++it ) {
724 switch( (*it).type() ) {
725 case Recipient::To:
726 to += line( *it );
727 break;
728 case Recipient::Cc:
729 cc += line( *it );
730 break;
731 case Recipient::Bcc:
732 bcc += line( *it );
733 break;
734 default:
735 break;
736 }
737 }
738
739 text += i18n("<b>To:</b><br/>") + to;
740 if ( !cc.isEmpty() ) text += i18n("<b>CC:</b><br/>") + cc;
741 if ( !bcc.isEmpty() ) text += i18n("<b>BCC:</b><br/>") + bcc;
742
743 text.append( "</qt>" );
744
745 TQRect geometry( p + TQPoint( 2, 2 ), TQPoint( 400, 100 ) );
746
747 tip( TQRect( p.x() - 20, p.y() - 20, 40, 40 ), text, geometry );
748}
749
750
751SideWidget::SideWidget( RecipientsView *view, TQWidget *parent )
752 : TQWidget( parent ), mView( view ), mRecipientPicker( 0 )
753{
754 TQBoxLayout *topLayout = new TQVBoxLayout( this );
755
756 topLayout->setSpacing( KDialog::spacingHint() );
757 topLayout->addStretch( 1 );
758
759 mTotalLabel = new TQLabel( this );
760 mTotalLabel->setAlignment( AlignCenter );
761 topLayout->addWidget( mTotalLabel );
762 mTotalLabel->hide();
763
764 topLayout->addStretch( 1 );
765
766 new RecipientsToolTip( view, mTotalLabel );
767
768 mDistributionListButton = new TQPushButton( i18n("Save List..."), this );
769 topLayout->addWidget( mDistributionListButton );
770 mDistributionListButton->hide();
771 connect( mDistributionListButton, TQ_SIGNAL( clicked() ),
772 TQ_SIGNAL( saveDistributionList() ) );
773 TQToolTip::add( mDistributionListButton,
774 i18n("Save recipients as distribution list") );
775
776 mSelectButton = new TQPushButton( i18n("Se&lect..."), this );
777 topLayout->addWidget( mSelectButton );
778 connect( mSelectButton, TQ_SIGNAL( clicked() ), TQ_SLOT( pickRecipient() ) );
779 TQToolTip::add( mSelectButton, i18n("Select recipients from address book") );
780}
781
782SideWidget::~SideWidget()
783{
784}
785
786RecipientsPicker* SideWidget::picker() const
787{
788 if ( !mRecipientPicker ) {
789 // hacks to allow picker() to be const in the presence of lazy loading
790 SideWidget *non_const_this = const_cast<SideWidget*>( this );
791 mRecipientPicker = new RecipientsPicker( non_const_this );
792 connect( mRecipientPicker, TQ_SIGNAL( pickedRecipient( const Recipient & ) ),
793 non_const_this, TQ_SIGNAL( pickedRecipient( const Recipient & ) ) );
794 mPickerPositioner = new KWindowPositioner( non_const_this, mRecipientPicker );
795 }
796 return mRecipientPicker;
797}
798
799void SideWidget::setFocus()
800{
801 mSelectButton->setFocus();
802}
803
804void SideWidget::setTotal( int recipients, int lines )
805{
806#if 0
807 kdDebug() << "SideWidget::setTotal() recipients: " << recipients <<
808 " lines: " << lines << endl;
809#endif
810
811 TQString labelText;
812 if ( recipients == 0 ) labelText = i18n("No recipients");
813 else labelText = i18n("1 recipient","%n recipients", recipients );
814 mTotalLabel->setText( labelText );
815
816 if ( lines > 3 ) mTotalLabel->show();
817 else mTotalLabel->hide();
818
819 if ( lines > 2 ) mDistributionListButton->show();
820 else mDistributionListButton->hide();
821}
822
823void SideWidget::pickRecipient()
824{
825#if 0
826 TQString rec = KInputDialog::getText( "Pick Recipient",
827 "Email address of recipient" );
828 if ( !rec.isEmpty() ) emit pickedRecipient( rec );
829#else
830 RecipientsPicker *p = picker();
831 p->setDefaultType( mView->activeLine()->recipientType() );
832 p->setRecipients( mView->recipients() );
833 p->show();
834 mPickerPositioner->reposition();
835 p->raise();
836#endif
837}
838
839
840RecipientsEditor::RecipientsEditor( TQWidget *parent )
841 : TQWidget( parent ), mModified( false )
842{
843 TQBoxLayout *topLayout = new TQHBoxLayout( this );
844 topLayout->setSpacing( KDialog::spacingHint() );
845
846 mRecipientsView = new RecipientsView( this );
847 topLayout->addWidget( mRecipientsView );
848 connect( mRecipientsView, TQ_SIGNAL( focusUp() ), TQ_SIGNAL( focusUp() ) );
849 connect( mRecipientsView, TQ_SIGNAL( focusDown() ), TQ_SIGNAL( focusDown() ) );
850 connect( mRecipientsView, TQ_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ),
851 TQ_SIGNAL( completionModeChanged( TDEGlobalSettings::Completion ) ) );
852
853 mSideWidget = new SideWidget( mRecipientsView, this );
854 topLayout->addWidget( mSideWidget );
855 connect( mSideWidget, TQ_SIGNAL( pickedRecipient( const Recipient & ) ),
856 TQ_SLOT( slotPickedRecipient( const Recipient & ) ) );
857 connect( mSideWidget, TQ_SIGNAL( saveDistributionList() ),
858 TQ_SLOT( saveDistributionList() ) );
859
860 connect( mRecipientsView, TQ_SIGNAL( totalChanged( int, int ) ),
861 mSideWidget, TQ_SLOT( setTotal( int, int ) ) );
862 connect( mRecipientsView, TQ_SIGNAL( focusRight() ),
863 mSideWidget, TQ_SLOT( setFocus() ) );
864
865 connect( mRecipientsView, TQ_SIGNAL(sizeHintChanged()),
866 TQ_SIGNAL(sizeHintChanged()) );
867}
868
869RecipientsEditor::~RecipientsEditor()
870{
871}
872
873RecipientsPicker* RecipientsEditor::picker() const
874{
875 return mSideWidget->picker();
876}
877
878void RecipientsEditor::slotPickedRecipient( const Recipient &rec )
879{
880 RecipientLine *line = mRecipientsView->activeLine();
881 if ( !line->isEmpty() ) line = mRecipientsView->addLine();
882
883 Recipient r = rec;
884 if ( r.type() == Recipient::Undefined ) {
885 r.setType( line->recipientType() );
886 }
887
888 line->setRecipient( r );
889 mModified = true;
890}
891
892void RecipientsEditor::saveDistributionList()
893{
894 DistributionListDialog *dlg = new DistributionListDialog( this );
895 dlg->setRecipients( mRecipientsView->recipients() );
896 dlg->exec();
897 delete dlg;
898}
899
900Recipient::List RecipientsEditor::recipients() const
901{
902 return mRecipientsView->recipients();
903}
904
905void RecipientsEditor::setRecipientString( const TQString &str,
906 Recipient::Type type )
907{
908 clear();
909
910 int count = 1;
911
912 TQStringList r = KPIM::splitEmailAddrList( str );
913 TQStringList::ConstIterator it;
914 for( it = r.begin(); it != r.end(); ++it ) {
915 if ( count++ > GlobalSettings::self()->maximumRecipients() ) {
916 KMessageBox::sorry( this,
917 i18n("Truncating recipients list to %1 of %2 entries.")
918 .arg( GlobalSettings::self()->maximumRecipients() )
919 .arg( r.count() ) );
920 break;
921 }
922 addRecipient( *it, type );
923 }
924}
925
926TQString RecipientsEditor::recipientString( Recipient::Type type )
927{
928 TQString str;
929
930 Recipient::List recipients = mRecipientsView->recipients();
931 Recipient::List::ConstIterator it;
932 for( it = recipients.begin(); it != recipients.end(); ++it ) {
933 if ( (*it).type() == type ) {
934 if ( !str.isEmpty() ) str += ", ";
935 str.append( (*it).email() );
936 }
937 }
938
939 return str;
940}
941
942void RecipientsEditor::addRecipient( const TQString & recipient,
943 Recipient::Type type )
944{
945 RecipientLine *line = mRecipientsView->emptyLine();
946 if ( !line ) line = mRecipientsView->addLine();
947 line->setRecipient( Recipient( recipient, type ) );
948}
949
950void RecipientsEditor::removeRecipient( const TQString & recipient,
951 Recipient::Type type )
952{
953 mRecipientsView->removeRecipient( recipient, type );
954}
955
956bool RecipientsEditor::isModified()
957{
958 return mModified || mRecipientsView->isModified();
959}
960
961void RecipientsEditor::clearModified()
962{
963 mModified = false;
964 mRecipientsView->clearModified();
965}
966
967void RecipientsEditor::clear()
968{
969}
970
971void RecipientsEditor::setFocus()
972{
973 mRecipientsView->setFocus();
974}
975
976void RecipientsEditor::setFocusTop()
977{
978 mRecipientsView->setFocusTop();
979}
980
981void RecipientsEditor::setFocusBottom()
982{
983 mRecipientsView->setFocusBottom();
984}
985
986int RecipientsEditor::setFirstColumnWidth( int w )
987{
988 return mRecipientsView->setFirstColumnWidth( w );
989}
990
991void RecipientsEditor::selectRecipients()
992{
993 mSideWidget->pickRecipient();
994}
995
996void RecipientsEditor::setCompletionMode( TDEGlobalSettings::Completion mode )
997{
998 mRecipientsView->setCompletionMode( mode );
999}
1000
1001#include "recipientseditor.moc"