kmail

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