recipientseditor.cpp
00001 /* 00002 This file is part of KMail. 00003 00004 Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org> 00005 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; if not, write to the Free Software 00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00019 00020 As a special exception, permission is given to link this program 00021 with any edition of TQt, and distribute the resulting executable, 00022 without including the source code for TQt in the source distribution. 00023 */ 00024 00025 #include "recipientseditor.h" 00026 00027 #include "recipientspicker.h" 00028 #include "kwindowpositioner.h" 00029 #include "distributionlistdialog.h" 00030 #include "globalsettings.h" 00031 00032 #include <libemailfunctions/email.h> 00033 00034 #include <kapplication.h> 00035 #include <kcompletionbox.h> 00036 #include <kdebug.h> 00037 #include <kinputdialog.h> 00038 #include <klocale.h> 00039 #include <kiconloader.h> 00040 #include <kmessagebox.h> 00041 00042 #include <tqlayout.h> 00043 #include <tqlabel.h> 00044 #include <tqscrollview.h> 00045 #include <tqcombobox.h> 00046 #include <tqhbox.h> 00047 #include <tqtimer.h> 00048 #include <tqpushbutton.h> 00049 #include <tqstylesheet.h> 00050 00051 Recipient::Recipient( const TQString &email, Recipient::Type type ) 00052 : mEmail( email ), mType( type ) 00053 { 00054 } 00055 00056 void Recipient::setType( Type type ) 00057 { 00058 mType = type; 00059 } 00060 00061 Recipient::Type Recipient::type() const 00062 { 00063 return mType; 00064 } 00065 00066 void Recipient::setEmail( const TQString &email ) 00067 { 00068 mEmail = email; 00069 } 00070 00071 TQString Recipient::email() const 00072 { 00073 return mEmail; 00074 } 00075 00076 bool Recipient::isEmpty() const 00077 { 00078 return mEmail.isEmpty(); 00079 } 00080 00081 int Recipient::typeToId( Recipient::Type type ) 00082 { 00083 return static_cast<int>( type ); 00084 } 00085 00086 Recipient::Type Recipient::idToType( int id ) 00087 { 00088 return static_cast<Type>( id ); 00089 } 00090 00091 TQString Recipient::typeLabel() const 00092 { 00093 return typeLabel( mType ); 00094 } 00095 00096 TQString Recipient::typeLabel( Recipient::Type type ) 00097 { 00098 switch( type ) { 00099 case To: 00100 return i18n("To"); 00101 case Cc: 00102 return i18n("CC"); 00103 case Bcc: 00104 return i18n("BCC"); 00105 case Undefined: 00106 break; 00107 } 00108 00109 return i18n("<Undefined RecipientType>"); 00110 } 00111 00112 TQStringList Recipient::allTypeLabels() 00113 { 00114 TQStringList types; 00115 types.append( typeLabel( To ) ); 00116 types.append( typeLabel( Cc ) ); 00117 types.append( typeLabel( Bcc ) ); 00118 return types; 00119 } 00120 00121 00122 RecipientComboBox::RecipientComboBox( TQWidget *parent ) 00123 : TQComboBox( parent ) 00124 { 00125 } 00126 00127 void RecipientComboBox::keyPressEvent( TQKeyEvent *ev ) 00128 { 00129 if ( ev->key() == Key_Right ) emit rightPressed(); 00130 else TQComboBox::keyPressEvent( ev ); 00131 } 00132 00133 00134 void RecipientLineEdit::keyPressEvent( TQKeyEvent *ev ) 00135 { 00136 if ( ev->key() == Key_Backspace && text().isEmpty() ) { 00137 ev->accept(); 00138 emit deleteMe(); 00139 } else if ( ev->key() == Key_Left && cursorPosition() == 0 ) { 00140 emit leftPressed(); 00141 } else if ( ev->key() == Key_Right && cursorPosition() == (int)text().length() ) { 00142 emit rightPressed(); 00143 } else { 00144 KMLineEdit::keyPressEvent( ev ); 00145 } 00146 } 00147 00148 RecipientLine::RecipientLine( TQWidget *parent ) 00149 : TQWidget( parent ), mRecipientsCount( 0 ), mModified( false ) 00150 { 00151 TQBoxLayout *topLayout = new TQHBoxLayout( this ); 00152 topLayout->setSpacing( KDialog::spacingHint() ); 00153 00154 TQStringList recipientTypes = Recipient::allTypeLabels(); 00155 00156 mCombo = new RecipientComboBox( this ); 00157 mCombo->insertStringList( recipientTypes ); 00158 topLayout->addWidget( mCombo ); 00159 TQToolTip::add( mCombo, i18n("Select type of recipient") ); 00160 00161 mEdit = new RecipientLineEdit( this ); 00162 TQToolTip::add( mEdit, 00163 i18n( "Set the list of email addresses to receive this message" ) ); 00164 topLayout->addWidget( mEdit ); 00165 connect( mEdit, TQT_SIGNAL( returnPressed() ), TQT_SLOT( slotReturnPressed() ) ); 00166 connect( mEdit, TQT_SIGNAL( deleteMe() ), TQT_SLOT( slotPropagateDeletion() ) ); 00167 connect( mEdit, TQT_SIGNAL( textChanged( const TQString & ) ), 00168 TQT_SLOT( analyzeLine( const TQString & ) ) ); 00169 connect( mEdit, TQT_SIGNAL( focusUp() ), TQT_SLOT( slotFocusUp() ) ); 00170 connect( mEdit, TQT_SIGNAL( focusDown() ), TQT_SLOT( slotFocusDown() ) ); 00171 connect( mEdit, TQT_SIGNAL( rightPressed() ), TQT_SIGNAL( rightPressed() ) ); 00172 00173 connect( mEdit, TQT_SIGNAL( leftPressed() ), mCombo, TQT_SLOT( setFocus() ) ); 00174 connect( mCombo, TQT_SIGNAL( rightPressed() ), mEdit, TQT_SLOT( setFocus() ) ); 00175 00176 connect( mCombo, TQT_SIGNAL( activated ( int ) ), 00177 this, TQT_SLOT( slotTypeModified() ) ); 00178 00179 mRemoveButton = new TQPushButton( this ); 00180 mRemoveButton->setIconSet( KApplication::reverseLayout() ? SmallIconSet("locationbar_erase") : SmallIconSet( "clear_left" ) ); 00181 topLayout->addWidget( mRemoveButton ); 00182 connect( mRemoveButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotPropagateDeletion() ) ); 00183 TQToolTip::add( mRemoveButton, i18n("Remove recipient line") ); 00184 } 00185 00186 void RecipientLine::slotFocusUp() 00187 { 00188 emit upPressed( this ); 00189 } 00190 00191 void RecipientLine::slotFocusDown() 00192 { 00193 emit downPressed( this ); 00194 } 00195 00196 void RecipientLine::slotTypeModified() 00197 { 00198 mModified = true; 00199 00200 emit typeModified( this ); 00201 } 00202 00203 void RecipientLine::analyzeLine( const TQString &text ) 00204 { 00205 TQStringList r = KPIM::splitEmailAddrList( text ); 00206 if ( int( r.count() ) != mRecipientsCount ) { 00207 mRecipientsCount = r.count(); 00208 emit countChanged(); 00209 } 00210 } 00211 00212 int RecipientLine::recipientsCount() 00213 { 00214 return mRecipientsCount; 00215 } 00216 00217 void RecipientLine::setRecipient( const Recipient &rec ) 00218 { 00219 mEdit->setText( rec.email() ); 00220 mCombo->setCurrentItem( Recipient::typeToId( rec.type() ) ); 00221 } 00222 00223 void RecipientLine::setRecipient( const TQString &email ) 00224 { 00225 setRecipient( Recipient( email ) ); 00226 } 00227 00228 Recipient RecipientLine::recipient() const 00229 { 00230 return Recipient( mEdit->text(), 00231 Recipient::idToType( mCombo->currentItem() ) ); 00232 } 00233 00234 void RecipientLine::setRecipientType( Recipient::Type type ) 00235 { 00236 mCombo->setCurrentItem( Recipient::typeToId( type ) ); 00237 } 00238 00239 Recipient::Type RecipientLine::recipientType() const 00240 { 00241 return Recipient::idToType( mCombo->currentItem() ); 00242 } 00243 00244 void RecipientLine::activate() 00245 { 00246 mEdit->setFocus(); 00247 } 00248 00249 bool RecipientLine::isActive() 00250 { 00251 return mEdit->hasFocus(); 00252 } 00253 00254 bool RecipientLine::isEmpty() 00255 { 00256 return mEdit->text().isEmpty(); 00257 } 00258 00259 bool RecipientLine::isModified() 00260 { 00261 return mModified || mEdit->isModified(); 00262 } 00263 00264 void RecipientLine::clearModified() 00265 { 00266 mModified = false; 00267 mEdit->clearModified(); 00268 } 00269 00270 void RecipientLine::slotReturnPressed() 00271 { 00272 emit returnPressed( this ); 00273 } 00274 00275 void RecipientLine::slotPropagateDeletion() 00276 { 00277 emit deleteLine( this ); 00278 } 00279 00280 void RecipientLine::keyPressEvent( TQKeyEvent *ev ) 00281 { 00282 if ( ev->key() == Key_Up ) { 00283 emit upPressed( this ); 00284 } else if ( ev->key() == Key_Down ) { 00285 emit downPressed( this ); 00286 } 00287 } 00288 00289 int RecipientLine::setComboWidth( int w ) 00290 { 00291 w = TQMAX( w, mCombo->sizeHint().width() ); 00292 mCombo->setFixedWidth( w ); 00293 mCombo->updateGeometry(); 00294 parentWidget()->updateGeometry(); 00295 return w; 00296 } 00297 00298 void RecipientLine::fixTabOrder( TQWidget *previous ) 00299 { 00300 setTabOrder( previous, mCombo ); 00301 setTabOrder( mCombo, mEdit ); 00302 setTabOrder( mEdit, mRemoveButton ); 00303 } 00304 00305 TQWidget *RecipientLine::tabOut() const 00306 { 00307 return mRemoveButton; 00308 } 00309 00310 void RecipientLine::clear() 00311 { 00312 mEdit->clear(); 00313 } 00314 00315 void RecipientLine::setRemoveLineButtonEnabled( bool b ) 00316 { 00317 mRemoveButton->setEnabled( b ); 00318 } 00319 00320 00321 // ------------ RecipientsView --------------------- 00322 00323 RecipientsView::RecipientsView( TQWidget *parent ) 00324 : TQScrollView( parent ), mCurDelLine( 0 ), 00325 mLineHeight( 0 ), mFirstColumnWidth( 0 ), 00326 mModified( false ) 00327 { 00328 mCompletionMode = KGlobalSettings::completionMode(); 00329 setHScrollBarMode( AlwaysOff ); 00330 setLineWidth( 0 ); 00331 00332 addLine(); 00333 setResizePolicy( TQScrollView::Manual ); 00334 setSizePolicy( TQSizePolicy::Expanding, TQSizePolicy::Expanding ); 00335 00336 viewport()->setPaletteBackgroundColor( paletteBackgroundColor() ); 00337 } 00338 00339 RecipientLine *RecipientsView::activeLine() 00340 { 00341 return mLines.last(); 00342 } 00343 00344 RecipientLine *RecipientsView::emptyLine() 00345 { 00346 RecipientLine *line; 00347 for( line = mLines.first(); line; line = mLines.next() ) { 00348 if ( line->isEmpty() ) return line; 00349 } 00350 00351 return 0; 00352 } 00353 00354 RecipientLine *RecipientsView::addLine() 00355 { 00356 RecipientLine *line = new RecipientLine( viewport() ); 00357 addChild( line, 0, mLines.count() * mLineHeight ); 00358 line->mEdit->setCompletionMode( mCompletionMode ); 00359 line->show(); 00360 connect( line, TQT_SIGNAL( returnPressed( RecipientLine * ) ), 00361 TQT_SLOT( slotReturnPressed( RecipientLine * ) ) ); 00362 connect( line, TQT_SIGNAL( upPressed( RecipientLine * ) ), 00363 TQT_SLOT( slotUpPressed( RecipientLine * ) ) ); 00364 connect( line, TQT_SIGNAL( downPressed( RecipientLine * ) ), 00365 TQT_SLOT( slotDownPressed( RecipientLine * ) ) ); 00366 connect( line, TQT_SIGNAL( rightPressed() ), TQT_SIGNAL( focusRight() ) ); 00367 connect( line, TQT_SIGNAL( deleteLine( RecipientLine * ) ), 00368 TQT_SLOT( slotDecideLineDeletion( RecipientLine * ) ) ); 00369 connect( line, TQT_SIGNAL( countChanged() ), TQT_SLOT( calculateTotal() ) ); 00370 connect( line, TQT_SIGNAL( typeModified( RecipientLine * ) ), 00371 TQT_SLOT( slotTypeModified( RecipientLine * ) ) ); 00372 connect( line->mEdit, TQT_SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ), 00373 TQT_SLOT( setCompletionMode( KGlobalSettings::Completion ) ) ); 00374 00375 if ( mLines.last() ) { 00376 if ( mLines.count() == 1 ) { 00377 if ( GlobalSettings::self()->secondRecipientTypeDefault() == 00378 GlobalSettings::EnumSecondRecipientTypeDefault::To ) { 00379 line->setRecipientType( Recipient::To ); 00380 } else { 00381 if ( mLines.last()->recipientType() == Recipient::Bcc ) { 00382 line->setRecipientType( Recipient::To ); 00383 } else { 00384 line->setRecipientType( Recipient::Cc ); 00385 } 00386 } 00387 } else { 00388 line->setRecipientType( mLines.last()->recipientType() ); 00389 } 00390 line->fixTabOrder( mLines.last()->tabOut() ); 00391 } 00392 00393 mLines.append( line ); 00394 // If there is only one line, removing it makes no sense 00395 if ( mLines.count() == 1 ) { 00396 mLines.first()->setRemoveLineButtonEnabled( false ); 00397 } else { 00398 mLines.first()->setRemoveLineButtonEnabled( true ); 00399 } 00400 00401 mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth ); 00402 00403 mLineHeight = line->minimumSizeHint().height(); 00404 00405 line->resize( viewport()->width(), mLineHeight ); 00406 00407 resizeView(); 00408 00409 calculateTotal(); 00410 00411 ensureVisible( 0, mLines.count() * mLineHeight ); 00412 00413 return line; 00414 } 00415 00416 void RecipientsView::slotTypeModified( RecipientLine *line ) 00417 { 00418 if ( mLines.count() == 2 || 00419 ( mLines.count() == 3 && mLines.at( 2 )->isEmpty() ) ) { 00420 if ( mLines.at( 1 ) == line ) { 00421 if ( line->recipientType() == Recipient::To ) { 00422 GlobalSettings::self()->setSecondRecipientTypeDefault( 00423 GlobalSettings::EnumSecondRecipientTypeDefault::To ); 00424 } else if ( line->recipientType() == Recipient::Cc ) { 00425 GlobalSettings::self()->setSecondRecipientTypeDefault( 00426 GlobalSettings::EnumSecondRecipientTypeDefault::Cc ); 00427 } 00428 } 00429 } 00430 } 00431 00432 void RecipientsView::calculateTotal() 00433 { 00434 int count = 0; 00435 int empty = 0; 00436 00437 RecipientLine *line; 00438 for( line = mLines.first(); line; line = mLines.next() ) { 00439 if ( line->isEmpty() ) ++empty; 00440 else count += line->recipientsCount(); 00441 } 00442 00443 if ( empty == 0 ) addLine(); 00444 00445 emit totalChanged( count, mLines.count() ); 00446 } 00447 00448 void RecipientsView::slotReturnPressed( RecipientLine *line ) 00449 { 00450 if ( !line->recipient().isEmpty() ) { 00451 RecipientLine *empty = emptyLine(); 00452 if ( !empty ) empty = addLine(); 00453 activateLine( empty ); 00454 } 00455 } 00456 00457 void RecipientsView::slotDownPressed( RecipientLine *line ) 00458 { 00459 int pos = mLines.find( line ); 00460 if ( pos >= (int)mLines.count() - 1 ) { 00461 emit focusDown(); 00462 } else if ( pos >= 0 ) { 00463 activateLine( mLines.at( pos + 1 ) ); 00464 } 00465 } 00466 00467 void RecipientsView::slotUpPressed( RecipientLine *line ) 00468 { 00469 int pos = mLines.find( line ); 00470 if ( pos > 0 ) { 00471 activateLine( mLines.at( pos - 1 ) ); 00472 } else { 00473 emit focusUp(); 00474 } 00475 } 00476 00477 void RecipientsView::slotDecideLineDeletion( RecipientLine *line ) 00478 { 00479 if ( !line->isEmpty() ) 00480 mModified = true; 00481 if ( mLines.count() == 1 ) { 00482 line->clear(); 00483 } else { 00484 mCurDelLine = line; 00485 TQTimer::singleShot( 0, this, TQT_SLOT( slotDeleteLine( ) ) ); 00486 } 00487 } 00488 00489 void RecipientsView::slotDeleteLine() 00490 { 00491 if ( !mCurDelLine ) 00492 return; 00493 00494 RecipientLine *line = mCurDelLine; 00495 int pos = mLines.find( line ); 00496 00497 int newPos; 00498 if ( pos == 0 ) newPos = pos + 1; 00499 else newPos = pos - 1; 00500 00501 // if there is something left to activate, do so 00502 if ( mLines.at( newPos ) ) 00503 mLines.at( newPos )->activate(); 00504 00505 mLines.remove( line ); 00506 removeChild( line ); 00507 delete line; 00508 00509 bool atLeastOneToLine = false; 00510 unsigned int firstCC = 0; 00511 for( uint i = pos; i < mLines.count(); ++i ) { 00512 RecipientLine *line = mLines.at( i ); 00513 moveChild( line, childX( line ), childY( line ) - mLineHeight ); 00514 if ( line->recipientType() == Recipient::To ) 00515 atLeastOneToLine = true; 00516 else if ( ( line->recipientType() == Recipient::Cc ) && ( i == 0 ) ) 00517 firstCC = i; 00518 } 00519 // only one left, can't remove that one 00520 if ( mLines.count() == 1 ) 00521 mLines.first()->setRemoveLineButtonEnabled( false ); 00522 00523 if ( !atLeastOneToLine ) 00524 mLines.at( firstCC )->setRecipientType( Recipient::To ); 00525 00526 calculateTotal(); 00527 00528 resizeView(); 00529 } 00530 00531 void RecipientsView::resizeView() 00532 { 00533 resizeContents( width(), mLines.count() * mLineHeight ); 00534 00535 if ( mLines.count() < 6 ) { 00536 // setFixedHeight( mLineHeight * mLines.count() ); 00537 } 00538 00539 parentWidget()->layout()->activate(); 00540 emit sizeHintChanged(); 00541 TQTimer::singleShot( 0, this, TQT_SLOT(moveCompletionPopup()) ); 00542 } 00543 00544 void RecipientsView::activateLine( RecipientLine *line ) 00545 { 00546 line->activate(); 00547 ensureVisible( 0, childY( line ) ); 00548 } 00549 00550 void RecipientsView::viewportResizeEvent ( TQResizeEvent *ev ) 00551 { 00552 for( uint i = 0; i < mLines.count(); ++i ) { 00553 mLines.at( i )->resize( ev->size().width(), mLineHeight ); 00554 } 00555 ensureVisible( 0, mLines.count() * mLineHeight ); 00556 } 00557 00558 TQSize RecipientsView::sizeHint() const 00559 { 00560 return TQSize( 200, mLineHeight * mLines.count() ); 00561 } 00562 00563 TQSize RecipientsView::minimumSizeHint() const 00564 { 00565 int height; 00566 uint numLines = 5; 00567 if ( mLines.count() < numLines ) height = mLineHeight * mLines.count(); 00568 else height = mLineHeight * numLines; 00569 return TQSize( 200, height ); 00570 } 00571 00572 Recipient::List RecipientsView::recipients() const 00573 { 00574 Recipient::List recipients; 00575 00576 TQPtrListIterator<RecipientLine> it( mLines ); 00577 RecipientLine *line; 00578 while( ( line = it.current() ) ) { 00579 if ( !line->recipient().isEmpty() ) { 00580 recipients.append( line->recipient() ); 00581 } 00582 00583 ++it; 00584 } 00585 00586 return recipients; 00587 } 00588 00589 void RecipientsView::setCompletionMode ( KGlobalSettings::Completion mode ) 00590 { 00591 if ( mCompletionMode == mode ) 00592 return; 00593 mCompletionMode = mode; 00594 00595 TQPtrListIterator<RecipientLine> it( mLines ); 00596 RecipientLine *line; 00597 while( ( line = it.current() ) ) { 00598 line->mEdit->blockSignals( true ); 00599 line->mEdit->setCompletionMode( mode ); 00600 line->mEdit->blockSignals( false ); 00601 ++it; 00602 } 00603 emit completionModeChanged( mode ); //report change to RecipientsEditor 00604 } 00605 00606 void RecipientsView::removeRecipient( const TQString & recipient, 00607 Recipient::Type type ) 00608 { 00609 // search a line which matches recipient and type 00610 TQPtrListIterator<RecipientLine> it( mLines ); 00611 RecipientLine *line; 00612 while( ( line = it.current() ) ) { 00613 if ( ( line->recipient().email() == recipient ) && 00614 ( line->recipientType() == type ) ) { 00615 break; 00616 } 00617 ++it; 00618 } 00619 if ( line ) 00620 line->slotPropagateDeletion(); 00621 } 00622 00623 bool RecipientsView::isModified() 00624 { 00625 if ( mModified ) 00626 return true; 00627 00628 TQPtrListIterator<RecipientLine> it( mLines ); 00629 RecipientLine *line; 00630 while( ( line = it.current() ) ) { 00631 if ( line->isModified() ) { 00632 return true; 00633 } 00634 ++it; 00635 } 00636 00637 return false; 00638 } 00639 00640 void RecipientsView::clearModified() 00641 { 00642 mModified = false; 00643 00644 TQPtrListIterator<RecipientLine> it( mLines ); 00645 RecipientLine *line; 00646 while( ( line = it.current() ) ) { 00647 line->clearModified(); 00648 ++it; 00649 } 00650 } 00651 00652 void RecipientsView::setFocus() 00653 { 00654 if ( mLines.last()->isActive() ) setFocusBottom(); 00655 else setFocusTop(); 00656 } 00657 00658 void RecipientsView::setFocusTop() 00659 { 00660 RecipientLine *line = mLines.first(); 00661 if ( line ) line->activate(); 00662 else kdWarning() << "No first" << endl; 00663 } 00664 00665 void RecipientsView::setFocusBottom() 00666 { 00667 RecipientLine *line = mLines.last(); 00668 if ( line ) line->activate(); 00669 else kdWarning() << "No last" << endl; 00670 } 00671 00672 int RecipientsView::setFirstColumnWidth( int w ) 00673 { 00674 mFirstColumnWidth = w; 00675 00676 TQPtrListIterator<RecipientLine> it( mLines ); 00677 RecipientLine *line; 00678 while( ( line = it.current() ) ) { 00679 mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth ); 00680 ++it; 00681 } 00682 00683 resizeView(); 00684 return mFirstColumnWidth; 00685 } 00686 00687 void RecipientsView::moveCompletionPopup() 00688 { 00689 for( RecipientLine* line = mLines.first(); line; line = mLines.next() ) { 00690 if ( line->lineEdit()->completionBox( false ) ) { 00691 if ( line->lineEdit()->completionBox()->isVisible() ) { 00692 // ### trigger moving, is there a nicer way to do that? 00693 line->lineEdit()->completionBox()->hide(); 00694 line->lineEdit()->completionBox()->show(); 00695 } 00696 } 00697 } 00698 00699 } 00700 00701 RecipientsToolTip::RecipientsToolTip( RecipientsView *view, TQWidget *parent ) 00702 : TQToolTip( parent ), mView( view ) 00703 { 00704 } 00705 00706 TQString RecipientsToolTip::line( const Recipient &r ) 00707 { 00708 TQString txt = r.email(); 00709 00710 return " " + TQStyleSheet::escape( txt ) + "<br/>"; 00711 } 00712 00713 void RecipientsToolTip::maybeTip( const TQPoint & p ) 00714 { 00715 TQString text = "<qt>"; 00716 00717 TQString to; 00718 TQString cc; 00719 TQString bcc; 00720 00721 Recipient::List recipients = mView->recipients(); 00722 Recipient::List::ConstIterator it; 00723 for( it = recipients.begin(); it != recipients.end(); ++it ) { 00724 switch( (*it).type() ) { 00725 case Recipient::To: 00726 to += line( *it ); 00727 break; 00728 case Recipient::Cc: 00729 cc += line( *it ); 00730 break; 00731 case Recipient::Bcc: 00732 bcc += line( *it ); 00733 break; 00734 default: 00735 break; 00736 } 00737 } 00738 00739 text += i18n("<b>To:</b><br/>") + to; 00740 if ( !cc.isEmpty() ) text += i18n("<b>CC:</b><br/>") + cc; 00741 if ( !bcc.isEmpty() ) text += i18n("<b>BCC:</b><br/>") + bcc; 00742 00743 text.append( "</qt>" ); 00744 00745 TQRect geometry( p + TQPoint( 2, 2 ), TQPoint( 400, 100 ) ); 00746 00747 tip( TQRect( p.x() - 20, p.y() - 20, 40, 40 ), text, geometry ); 00748 } 00749 00750 00751 SideWidget::SideWidget( RecipientsView *view, TQWidget *parent ) 00752 : TQWidget( parent ), mView( view ), mRecipientPicker( 0 ) 00753 { 00754 TQBoxLayout *topLayout = new TQVBoxLayout( this ); 00755 00756 topLayout->setSpacing( KDialog::spacingHint() ); 00757 topLayout->addStretch( 1 ); 00758 00759 mTotalLabel = new TQLabel( this ); 00760 mTotalLabel->setAlignment( AlignCenter ); 00761 topLayout->addWidget( mTotalLabel ); 00762 mTotalLabel->hide(); 00763 00764 topLayout->addStretch( 1 ); 00765 00766 new RecipientsToolTip( view, mTotalLabel ); 00767 00768 mDistributionListButton = new TQPushButton( i18n("Save List..."), this ); 00769 topLayout->addWidget( mDistributionListButton ); 00770 mDistributionListButton->hide(); 00771 connect( mDistributionListButton, TQT_SIGNAL( clicked() ), 00772 TQT_SIGNAL( saveDistributionList() ) ); 00773 TQToolTip::add( mDistributionListButton, 00774 i18n("Save recipients as distribution list") ); 00775 00776 mSelectButton = new TQPushButton( i18n("Se&lect..."), this ); 00777 topLayout->addWidget( mSelectButton ); 00778 connect( mSelectButton, TQT_SIGNAL( clicked() ), TQT_SLOT( pickRecipient() ) ); 00779 TQToolTip::add( mSelectButton, i18n("Select recipients from address book") ); 00780 } 00781 00782 SideWidget::~SideWidget() 00783 { 00784 } 00785 00786 RecipientsPicker* SideWidget::picker() const 00787 { 00788 if ( !mRecipientPicker ) { 00789 // hacks to allow picker() to be const in the presence of lazy loading 00790 SideWidget *non_const_this = const_cast<SideWidget*>( this ); 00791 mRecipientPicker = new RecipientsPicker( non_const_this ); 00792 connect( mRecipientPicker, TQT_SIGNAL( pickedRecipient( const Recipient & ) ), 00793 non_const_this, TQT_SIGNAL( pickedRecipient( const Recipient & ) ) ); 00794 mPickerPositioner = new KWindowPositioner( non_const_this, mRecipientPicker ); 00795 } 00796 return mRecipientPicker; 00797 } 00798 00799 void SideWidget::setFocus() 00800 { 00801 mSelectButton->setFocus(); 00802 } 00803 00804 void SideWidget::setTotal( int recipients, int lines ) 00805 { 00806 #if 0 00807 kdDebug() << "SideWidget::setTotal() recipients: " << recipients << 00808 " lines: " << lines << endl; 00809 #endif 00810 00811 TQString labelText; 00812 if ( recipients == 0 ) labelText = i18n("No recipients"); 00813 else labelText = i18n("1 recipient","%n recipients", recipients ); 00814 mTotalLabel->setText( labelText ); 00815 00816 if ( lines > 3 ) mTotalLabel->show(); 00817 else mTotalLabel->hide(); 00818 00819 if ( lines > 2 ) mDistributionListButton->show(); 00820 else mDistributionListButton->hide(); 00821 } 00822 00823 void SideWidget::pickRecipient() 00824 { 00825 #if 0 00826 TQString rec = KInputDialog::getText( "Pick Recipient", 00827 "Email address of recipient" ); 00828 if ( !rec.isEmpty() ) emit pickedRecipient( rec ); 00829 #else 00830 RecipientsPicker *p = picker(); 00831 p->setDefaultType( mView->activeLine()->recipientType() ); 00832 p->setRecipients( mView->recipients() ); 00833 p->show(); 00834 mPickerPositioner->reposition(); 00835 p->raise(); 00836 #endif 00837 } 00838 00839 00840 RecipientsEditor::RecipientsEditor( TQWidget *parent ) 00841 : TQWidget( parent ), mModified( false ) 00842 { 00843 TQBoxLayout *topLayout = new TQHBoxLayout( this ); 00844 topLayout->setSpacing( KDialog::spacingHint() ); 00845 00846 mRecipientsView = new RecipientsView( this ); 00847 topLayout->addWidget( mRecipientsView ); 00848 connect( mRecipientsView, TQT_SIGNAL( focusUp() ), TQT_SIGNAL( focusUp() ) ); 00849 connect( mRecipientsView, TQT_SIGNAL( focusDown() ), TQT_SIGNAL( focusDown() ) ); 00850 connect( mRecipientsView, TQT_SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ), 00851 TQT_SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ) ); 00852 00853 mSideWidget = new SideWidget( mRecipientsView, this ); 00854 topLayout->addWidget( mSideWidget ); 00855 connect( mSideWidget, TQT_SIGNAL( pickedRecipient( const Recipient & ) ), 00856 TQT_SLOT( slotPickedRecipient( const Recipient & ) ) ); 00857 connect( mSideWidget, TQT_SIGNAL( saveDistributionList() ), 00858 TQT_SLOT( saveDistributionList() ) ); 00859 00860 connect( mRecipientsView, TQT_SIGNAL( totalChanged( int, int ) ), 00861 mSideWidget, TQT_SLOT( setTotal( int, int ) ) ); 00862 connect( mRecipientsView, TQT_SIGNAL( focusRight() ), 00863 mSideWidget, TQT_SLOT( setFocus() ) ); 00864 00865 connect( mRecipientsView, TQT_SIGNAL(sizeHintChanged()), 00866 TQT_SIGNAL(sizeHintChanged()) ); 00867 } 00868 00869 RecipientsEditor::~RecipientsEditor() 00870 { 00871 } 00872 00873 RecipientsPicker* RecipientsEditor::picker() const 00874 { 00875 return mSideWidget->picker(); 00876 } 00877 00878 void RecipientsEditor::slotPickedRecipient( const Recipient &rec ) 00879 { 00880 RecipientLine *line = mRecipientsView->activeLine(); 00881 if ( !line->isEmpty() ) line = mRecipientsView->addLine(); 00882 00883 Recipient r = rec; 00884 if ( r.type() == Recipient::Undefined ) { 00885 r.setType( line->recipientType() ); 00886 } 00887 00888 line->setRecipient( r ); 00889 mModified = true; 00890 } 00891 00892 void RecipientsEditor::saveDistributionList() 00893 { 00894 DistributionListDialog *dlg = new DistributionListDialog( this ); 00895 dlg->setRecipients( mRecipientsView->recipients() ); 00896 dlg->exec(); 00897 delete dlg; 00898 } 00899 00900 Recipient::List RecipientsEditor::recipients() const 00901 { 00902 return mRecipientsView->recipients(); 00903 } 00904 00905 void RecipientsEditor::setRecipientString( const TQString &str, 00906 Recipient::Type type ) 00907 { 00908 clear(); 00909 00910 int count = 1; 00911 00912 TQStringList r = KPIM::splitEmailAddrList( str ); 00913 TQStringList::ConstIterator it; 00914 for( it = r.begin(); it != r.end(); ++it ) { 00915 if ( count++ > GlobalSettings::self()->maximumRecipients() ) { 00916 KMessageBox::sorry( this, 00917 i18n("Truncating recipients list to %1 of %2 entries.") 00918 .arg( GlobalSettings::self()->maximumRecipients() ) 00919 .arg( r.count() ) ); 00920 break; 00921 } 00922 addRecipient( *it, type ); 00923 } 00924 } 00925 00926 TQString RecipientsEditor::recipientString( Recipient::Type type ) 00927 { 00928 TQString str; 00929 00930 Recipient::List recipients = mRecipientsView->recipients(); 00931 Recipient::List::ConstIterator it; 00932 for( it = recipients.begin(); it != recipients.end(); ++it ) { 00933 if ( (*it).type() == type ) { 00934 if ( !str.isEmpty() ) str += ", "; 00935 str.append( (*it).email() ); 00936 } 00937 } 00938 00939 return str; 00940 } 00941 00942 void RecipientsEditor::addRecipient( const TQString & recipient, 00943 Recipient::Type type ) 00944 { 00945 RecipientLine *line = mRecipientsView->emptyLine(); 00946 if ( !line ) line = mRecipientsView->addLine(); 00947 line->setRecipient( Recipient( recipient, type ) ); 00948 } 00949 00950 void RecipientsEditor::removeRecipient( const TQString & recipient, 00951 Recipient::Type type ) 00952 { 00953 mRecipientsView->removeRecipient( recipient, type ); 00954 } 00955 00956 bool RecipientsEditor::isModified() 00957 { 00958 return mModified || mRecipientsView->isModified(); 00959 } 00960 00961 void RecipientsEditor::clearModified() 00962 { 00963 mModified = false; 00964 mRecipientsView->clearModified(); 00965 } 00966 00967 void RecipientsEditor::clear() 00968 { 00969 } 00970 00971 void RecipientsEditor::setFocus() 00972 { 00973 mRecipientsView->setFocus(); 00974 } 00975 00976 void RecipientsEditor::setFocusTop() 00977 { 00978 mRecipientsView->setFocusTop(); 00979 } 00980 00981 void RecipientsEditor::setFocusBottom() 00982 { 00983 mRecipientsView->setFocusBottom(); 00984 } 00985 00986 int RecipientsEditor::setFirstColumnWidth( int w ) 00987 { 00988 return mRecipientsView->setFirstColumnWidth( w ); 00989 } 00990 00991 void RecipientsEditor::selectRecipients() 00992 { 00993 mSideWidget->pickRecipient(); 00994 } 00995 00996 void RecipientsEditor::setCompletionMode( KGlobalSettings::Completion mode ) 00997 { 00998 mRecipientsView->setCompletionMode( mode ); 00999 } 01000 01001 #include "recipientseditor.moc"