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 ),
00322     mLineHeight( 0 ), mFirstColumnWidth( 0 ),
00323     mModified( false )
00324 {
00325   mCompletionMode = KGlobalSettings::completionMode();
00326   setHScrollBarMode( AlwaysOff );
00327   setLineWidth( 0 );
00328 
00329   addLine();
00330   setResizePolicy( QScrollView::Manual );
00331   setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
00332 }
00333 
00334 RecipientLine *RecipientsView::activeLine()
00335 {
00336   return mLines.last();
00337 }
00338 
00339 RecipientLine *RecipientsView::emptyLine()
00340 {
00341   RecipientLine *line;
00342   for( line = mLines.first(); line; line = mLines.next() ) {
00343     if ( line->isEmpty() ) return line;
00344   }
00345 
00346   return 0;
00347 }
00348 
00349 RecipientLine *RecipientsView::addLine()
00350 {
00351   RecipientLine *line = new RecipientLine( viewport() );
00352   addChild( line, 0, mLines.count() * mLineHeight );
00353   line->mEdit->setCompletionMode( mCompletionMode );
00354   line->show();
00355   connect( line, SIGNAL( returnPressed( RecipientLine * ) ),
00356     SLOT( slotReturnPressed( RecipientLine * ) ) );
00357   connect( line, SIGNAL( upPressed( RecipientLine * ) ),
00358     SLOT( slotUpPressed( RecipientLine * ) ) );
00359   connect( line, SIGNAL( downPressed( RecipientLine * ) ),
00360     SLOT( slotDownPressed( RecipientLine * ) ) );
00361   connect( line, SIGNAL( rightPressed() ), SIGNAL( focusRight() ) );
00362   connect( line, SIGNAL( deleteLine( RecipientLine * ) ),
00363     SLOT( slotDecideLineDeletion( RecipientLine * ) ) );
00364   connect( line, SIGNAL( countChanged() ), SLOT( calculateTotal() ) );
00365   connect( line, SIGNAL( typeModified( RecipientLine * ) ),
00366     SLOT( slotTypeModified( RecipientLine * ) ) );
00367   connect( line->mEdit, SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ),
00368     SLOT( setCompletionMode( KGlobalSettings::Completion ) ) );
00369 
00370   if ( mLines.last() ) {
00371     if ( mLines.count() == 1 ) {
00372       if ( GlobalSettings::self()->secondRecipientTypeDefault() ==
00373          GlobalSettings::EnumSecondRecipientTypeDefault::To ) {
00374         line->setRecipientType( Recipient::To );
00375       } else {
00376         if ( mLines.last()->recipientType() == Recipient::Bcc ) {
00377           line->setRecipientType( Recipient::To );
00378         } else {
00379           line->setRecipientType( Recipient::Cc );
00380         }
00381       }
00382     } else {
00383       line->setRecipientType( mLines.last()->recipientType() );
00384     }
00385     line->fixTabOrder( mLines.last()->tabOut() );
00386   }
00387 
00388   mLines.append( line );
00389   // If there is only one line, removing it makes no sense
00390   if ( mLines.count() == 1 ) {
00391     mLines.first()->setRemoveLineButtonEnabled( false );
00392   } else {
00393     mLines.first()->setRemoveLineButtonEnabled( true );
00394   }
00395 
00396   mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth );
00397 
00398   mLineHeight = line->minimumSizeHint().height();
00399 
00400   line->resize( viewport()->width(), mLineHeight );
00401 
00402   resizeView();
00403 
00404   calculateTotal();
00405 
00406   ensureVisible( 0, mLines.count() * mLineHeight );
00407 
00408   return line;
00409 }
00410 
00411 void RecipientsView::slotTypeModified( RecipientLine *line )
00412 {
00413   if ( mLines.count() == 2 ||
00414        ( mLines.count() == 3 && mLines.at( 2 )->isEmpty() ) ) {
00415     if ( mLines.at( 1 ) == line ) {
00416       if ( line->recipientType() == Recipient::To ) {
00417         GlobalSettings::self()->setSecondRecipientTypeDefault(
00418           GlobalSettings::EnumSecondRecipientTypeDefault::To );
00419       } else if ( line->recipientType() == Recipient::Cc ) {
00420         GlobalSettings::self()->setSecondRecipientTypeDefault(
00421           GlobalSettings::EnumSecondRecipientTypeDefault::Cc );
00422       }
00423     }
00424   }
00425 }
00426 
00427 void RecipientsView::calculateTotal()
00428 {
00429   int count = 0;
00430   int empty = 0;
00431 
00432   RecipientLine *line;
00433   for( line = mLines.first(); line; line = mLines.next() ) {
00434     if ( line->isEmpty() ) ++empty;
00435     else count += line->recipientsCount();
00436   }
00437 
00438   if ( empty == 0 ) addLine();
00439 
00440   emit totalChanged( count, mLines.count() );
00441 }
00442 
00443 void RecipientsView::slotReturnPressed( RecipientLine *line )
00444 {
00445   if ( !line->recipient().isEmpty() ) {
00446     RecipientLine *empty = emptyLine();
00447     if ( !empty ) empty = addLine();
00448     activateLine( empty );
00449   }
00450 }
00451 
00452 void RecipientsView::slotDownPressed( RecipientLine *line )
00453 {
00454   int pos = mLines.find( line );
00455   if ( pos >= (int)mLines.count() - 1 ) {
00456     emit focusDown();
00457   } else if ( pos >= 0 ) {
00458     activateLine( mLines.at( pos + 1 ) );
00459   }
00460 }
00461 
00462 void RecipientsView::slotUpPressed( RecipientLine *line )
00463 {
00464   int pos = mLines.find( line );
00465   if ( pos > 0 ) {
00466     activateLine( mLines.at( pos - 1 ) );
00467   } else {
00468     emit focusUp();
00469   }
00470 }
00471 
00472 void RecipientsView::slotDecideLineDeletion( RecipientLine *line )
00473 {
00474   if ( !line->isEmpty() )
00475     mModified = true;
00476   if ( mLines.count() == 1 ) {
00477     line->clear();
00478   } else {
00479     mCurDelLine = line;
00480     QTimer::singleShot( 0, this, SLOT( slotDeleteLine( ) ) );
00481   }
00482 }
00483 
00484 void RecipientsView::slotDeleteLine()
00485 {
00486   if ( !mCurDelLine )
00487     return;
00488 
00489   RecipientLine *line = mCurDelLine;
00490   int pos = mLines.find( line );
00491 
00492   int newPos;
00493   if ( pos == 0 ) newPos = pos + 1;
00494   else newPos = pos - 1;
00495 
00496   // if there is something left to activate, do so
00497   if ( mLines.at( newPos ) )
00498     mLines.at( newPos )->activate();
00499 
00500   mLines.remove( line );
00501   removeChild( line );
00502   delete line;
00503 
00504   bool atLeastOneToLine = false;
00505   unsigned int firstCC = 0;
00506   for( uint i = pos; i < mLines.count(); ++i ) {
00507     RecipientLine *line = mLines.at( i );
00508     moveChild( line, childX( line ), childY( line ) - mLineHeight );
00509     if ( line->recipientType() == Recipient::To )
00510       atLeastOneToLine = true;
00511     else if ( ( line->recipientType() == Recipient::Cc ) && ( i == 0 ) )
00512       firstCC = i;
00513   }
00514   // only one left, can't remove that one
00515   if ( mLines.count() == 1 )
00516     mLines.first()->setRemoveLineButtonEnabled( false );
00517 
00518   if ( !atLeastOneToLine )
00519     mLines.at( firstCC )->setRecipientType( Recipient::To );
00520 
00521   calculateTotal();
00522 
00523   resizeView();
00524 }
00525 
00526 void RecipientsView::resizeView()
00527 {
00528   resizeContents( width(), mLines.count() * mLineHeight );
00529 
00530   if ( mLines.count() < 6 ) {
00531     setFixedHeight( mLineHeight * mLines.count() );
00532   }
00533 }
00534 
00535 void RecipientsView::activateLine( RecipientLine *line )
00536 {
00537   line->activate();
00538   ensureVisible( 0, childY( line ) );
00539 }
00540 
00541 void RecipientsView::viewportResizeEvent ( QResizeEvent *ev )
00542 {
00543   for( uint i = 0; i < mLines.count(); ++i ) {
00544     mLines.at( i )->resize( ev->size().width(), mLineHeight );
00545   }
00546 }
00547 
00548 QSize RecipientsView::sizeHint() const
00549 {
00550   return QSize( 200, mLineHeight * mLines.count() );
00551 }
00552 
00553 QSize RecipientsView::minimumSizeHint() const
00554 {
00555   int height;
00556 
00557   uint numLines = 5;
00558 
00559   if ( mLines.count() < numLines ) height = mLineHeight * mLines.count();
00560   else height = mLineHeight * numLines;
00561 
00562   return QSize( 200, height );
00563 }
00564 
00565 Recipient::List RecipientsView::recipients() const
00566 {
00567   Recipient::List recipients;
00568 
00569   QPtrListIterator<RecipientLine> it( mLines );
00570   RecipientLine *line;
00571   while( ( line = it.current() ) ) {
00572     if ( !line->recipient().isEmpty() ) {
00573       recipients.append( line->recipient() );
00574     }
00575 
00576     ++it;
00577   }
00578 
00579   return recipients;
00580 }
00581 
00582 void RecipientsView::setCompletionMode ( KGlobalSettings::Completion mode )
00583 {
00584   if ( mCompletionMode == mode )
00585     return;
00586   mCompletionMode = mode;
00587 
00588   QPtrListIterator<RecipientLine> it( mLines );
00589   RecipientLine *line;
00590   while( ( line = it.current() ) ) {
00591     line->mEdit->blockSignals( true );
00592     line->mEdit->setCompletionMode( mode );
00593     line->mEdit->blockSignals( false );
00594     ++it;
00595   }
00596   emit completionModeChanged( mode ); //report change to RecipientsEditor
00597 }
00598 
00599 void RecipientsView::removeRecipient( const QString & recipient,
00600                                       Recipient::Type type )
00601 {
00602   // search a line which matches recipient and type
00603   QPtrListIterator<RecipientLine> it( mLines );
00604   RecipientLine *line;
00605   while( ( line = it.current() ) ) {
00606     if ( ( line->recipient().email() == recipient ) &&
00607          ( line->recipientType() == type ) ) {
00608       break;
00609     }
00610     ++it;
00611   }
00612   if ( line )
00613     line->slotPropagateDeletion();
00614 }
00615 
00616 bool RecipientsView::isModified()
00617 {
00618   if ( mModified )
00619     return true;
00620 
00621   QPtrListIterator<RecipientLine> it( mLines );
00622   RecipientLine *line;
00623   while( ( line = it.current() ) ) {
00624     if ( line->isModified() ) {
00625       return true;
00626     }
00627     ++it;
00628   }
00629 
00630   return false;
00631 }
00632 
00633 void RecipientsView::clearModified()
00634 {
00635   mModified = false;
00636 
00637   QPtrListIterator<RecipientLine> it( mLines );
00638   RecipientLine *line;
00639   while( ( line = it.current() ) ) {
00640     line->clearModified();
00641     ++it;
00642   }
00643 }
00644 
00645 void RecipientsView::setFocus()
00646 {
00647   if ( mLines.last()->isActive() ) setFocusBottom();
00648   else setFocusTop();
00649 }
00650 
00651 void RecipientsView::setFocusTop()
00652 {
00653   RecipientLine *line = mLines.first();
00654   if ( line ) line->activate();
00655   else kdWarning() << "No first" << endl;
00656 }
00657 
00658 void RecipientsView::setFocusBottom()
00659 {
00660   RecipientLine *line = mLines.last();
00661   if ( line ) line->activate();
00662   else  kdWarning() << "No last" << endl;
00663 }
00664 
00665 int RecipientsView::setFirstColumnWidth( int w )
00666 {
00667   mFirstColumnWidth = w;
00668 
00669   QPtrListIterator<RecipientLine> it( mLines );
00670   RecipientLine *line;
00671   while( ( line = it.current() ) ) {
00672     mFirstColumnWidth = line->setComboWidth( mFirstColumnWidth );
00673     ++it;
00674   }
00675 
00676   resizeView();
00677   return mFirstColumnWidth;
00678 }
00679 
00680 RecipientsToolTip::RecipientsToolTip( RecipientsView *view, QWidget *parent )
00681   : QToolTip( parent ), mView( view )
00682 {
00683 }
00684 
00685 QString RecipientsToolTip::line( const Recipient &r )
00686 {
00687   QString txt = r.email();
00688 
00689   return "&nbsp;&nbsp;" + QStyleSheet::escape( txt ) + "<br/>";
00690 }
00691 
00692 void RecipientsToolTip::maybeTip( const QPoint & p )
00693 {
00694   QString text = "<qt>";
00695 
00696   QString to;
00697   QString cc;
00698   QString bcc;
00699 
00700   Recipient::List recipients = mView->recipients();
00701   Recipient::List::ConstIterator it;
00702   for( it = recipients.begin(); it != recipients.end(); ++it ) {
00703     switch( (*it).type() ) {
00704       case Recipient::To:
00705         to += line( *it );
00706         break;
00707       case Recipient::Cc:
00708         cc += line( *it );
00709         break;
00710       case Recipient::Bcc:
00711         bcc += line( *it );
00712         break;
00713       default:
00714         break;
00715     }
00716   }
00717 
00718   text += i18n("<b>To:</b><br/>") + to;
00719   if ( !cc.isEmpty() ) text += i18n("<b>CC:</b><br/>") + cc;
00720   if ( !bcc.isEmpty() ) text += i18n("<b>BCC:</b><br/>") + bcc;
00721 
00722   text.append( "</qt>" );
00723 
00724   QRect geometry( p + QPoint( 2, 2 ), QPoint( 400, 100 ) );
00725 
00726   tip( QRect( p.x() - 20, p.y() - 20, 40, 40 ), text, geometry );
00727 }
00728 
00729 
00730 SideWidget::SideWidget( RecipientsView *view, QWidget *parent )
00731   : QWidget( parent ), mView( view ), mRecipientPicker( 0 )
00732 {
00733   QBoxLayout *topLayout = new QVBoxLayout( this );
00734 
00735   topLayout->setSpacing( KDialog::spacingHint() );
00736   topLayout->addStretch( 1 );
00737 
00738   mTotalLabel = new QLabel( this );
00739   mTotalLabel->setAlignment( AlignCenter );
00740   topLayout->addWidget( mTotalLabel );
00741   mTotalLabel->hide();
00742 
00743   topLayout->addStretch( 1 );
00744 
00745   new RecipientsToolTip( view, mTotalLabel );
00746 
00747   mDistributionListButton = new QPushButton( i18n("Save List..."), this );
00748   topLayout->addWidget( mDistributionListButton );
00749   mDistributionListButton->hide();
00750   connect( mDistributionListButton, SIGNAL( clicked() ),
00751     SIGNAL( saveDistributionList() ) );
00752   QToolTip::add( mDistributionListButton,
00753     i18n("Save recipients as distribution list") );
00754 
00755   mSelectButton = new QPushButton( i18n("Se&lect..."), this );
00756   topLayout->addWidget( mSelectButton );
00757   connect( mSelectButton, SIGNAL( clicked() ), SLOT( pickRecipient() ) );
00758   QToolTip::add( mSelectButton, i18n("Select recipients from address book") );
00759 }
00760 
00761 SideWidget::~SideWidget()
00762 {
00763 }
00764 
00765 RecipientsPicker* SideWidget::picker() const
00766 {
00767   if ( !mRecipientPicker ) {
00768     // hacks to allow picker() to be const in the presence of lazy loading
00769     SideWidget *non_const_this = const_cast<SideWidget*>( this );
00770     mRecipientPicker = new RecipientsPicker( non_const_this );
00771     connect( mRecipientPicker, SIGNAL( pickedRecipient( const Recipient & ) ),
00772              non_const_this, SIGNAL( pickedRecipient( const Recipient & ) ) );
00773     mPickerPositioner = new KWindowPositioner( non_const_this, mRecipientPicker );
00774   }
00775   return mRecipientPicker;
00776 }
00777 
00778 void SideWidget::setFocus()
00779 {
00780   mSelectButton->setFocus();
00781 }
00782 
00783 void SideWidget::setTotal( int recipients, int lines )
00784 {
00785 #if 0
00786   kdDebug() << "SideWidget::setTotal() recipients: " << recipients <<
00787     "  lines: " << lines << endl;
00788 #endif
00789 
00790   QString labelText;
00791   if ( recipients == 0 ) labelText = i18n("No recipients");
00792   else labelText = i18n("1 recipient","%n recipients", recipients );
00793   mTotalLabel->setText( labelText );
00794 
00795   if ( lines > 3 ) mTotalLabel->show();
00796   else mTotalLabel->hide();
00797 
00798   if ( lines > 2 ) mDistributionListButton->show();
00799   else mDistributionListButton->hide();
00800 }
00801 
00802 void SideWidget::pickRecipient()
00803 {
00804 #if 0
00805   QString rec = KInputDialog::getText( "Pick Recipient",
00806     "Email address of recipient" );
00807   if ( !rec.isEmpty() ) emit pickedRecipient( rec );
00808 #else
00809   RecipientsPicker *p = picker();
00810   p->setDefaultType( mView->activeLine()->recipientType() );
00811   p->setRecipients( mView->recipients() );
00812   p->show();
00813   mPickerPositioner->reposition();
00814   p->raise();
00815 #endif
00816 }
00817 
00818 
00819 RecipientsEditor::RecipientsEditor( QWidget *parent )
00820   : QWidget( parent ), mModified( false )
00821 {
00822   QBoxLayout *topLayout = new QHBoxLayout( this );
00823   topLayout->setSpacing( KDialog::spacingHint() );
00824 
00825   mRecipientsView = new RecipientsView( this );
00826   topLayout->addWidget( mRecipientsView );
00827   connect( mRecipientsView, SIGNAL( focusUp() ), SIGNAL( focusUp() ) );
00828   connect( mRecipientsView, SIGNAL( focusDown() ), SIGNAL( focusDown() ) );
00829   connect( mRecipientsView, SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ),
00830     SIGNAL( completionModeChanged( KGlobalSettings::Completion ) ) );
00831 
00832   mSideWidget = new SideWidget( mRecipientsView, this );
00833   topLayout->addWidget( mSideWidget );
00834   connect( mSideWidget, SIGNAL( pickedRecipient( const Recipient & ) ),
00835     SLOT( slotPickedRecipient( const Recipient & ) ) );
00836   connect( mSideWidget, SIGNAL( saveDistributionList() ),
00837     SLOT( saveDistributionList() ) );
00838 
00839   connect( mRecipientsView, SIGNAL( totalChanged( int, int ) ),
00840     mSideWidget, SLOT( setTotal( int, int ) ) );
00841   connect( mRecipientsView, SIGNAL( focusRight() ),
00842     mSideWidget, SLOT( setFocus() ) );
00843 }
00844 
00845 RecipientsEditor::~RecipientsEditor()
00846 {
00847 }
00848 
00849 RecipientsPicker* RecipientsEditor::picker() const
00850 {
00851   return mSideWidget->picker();
00852 }
00853 
00854 void RecipientsEditor::slotPickedRecipient( const Recipient &rec )
00855 {
00856   RecipientLine *line = mRecipientsView->activeLine();
00857   if ( !line->isEmpty() ) line = mRecipientsView->addLine();
00858 
00859   Recipient r = rec;
00860   if ( r.type() == Recipient::Undefined ) {
00861     r.setType( line->recipientType() );
00862   }
00863 
00864   line->setRecipient( r );
00865   mModified = true;
00866 }
00867 
00868 void RecipientsEditor::saveDistributionList()
00869 {
00870   DistributionListDialog *dlg = new DistributionListDialog( this );
00871   dlg->setRecipients( mRecipientsView->recipients() );
00872   dlg->show();
00873 }
00874 
00875 Recipient::List RecipientsEditor::recipients() const
00876 {
00877   return mRecipientsView->recipients();
00878 }
00879 
00880 void RecipientsEditor::setRecipientString( const QString &str,
00881   Recipient::Type type )
00882 {
00883   clear();
00884 
00885   int count = 1;
00886 
00887   QStringList r = KPIM::splitEmailAddrList( str );
00888   QStringList::ConstIterator it;
00889   for( it = r.begin(); it != r.end(); ++it ) {
00890     if ( count++ > GlobalSettings::self()->maximumRecipients() ) {
00891       KMessageBox::sorry( this,
00892         i18n("Truncating recipients list to %1 of %2 entries.")
00893         .arg( GlobalSettings::self()->maximumRecipients() )
00894         .arg( r.count() ) );
00895       break;
00896     }
00897     addRecipient( *it, type );
00898   }
00899 }
00900 
00901 QString RecipientsEditor::recipientString( Recipient::Type type )
00902 {
00903   QString str;
00904 
00905   Recipient::List recipients = mRecipientsView->recipients();
00906   Recipient::List::ConstIterator it;
00907   for( it = recipients.begin(); it != recipients.end(); ++it ) {
00908     if ( (*it).type() == type ) {
00909       if ( !str.isEmpty() ) str += ", ";
00910       str.append( (*it).email() );
00911     }
00912   }
00913 
00914   return str;
00915 }
00916 
00917 void RecipientsEditor::addRecipient( const QString & recipient,
00918                                      Recipient::Type type )
00919 {
00920   RecipientLine *line = mRecipientsView->emptyLine();
00921   if ( !line ) line = mRecipientsView->addLine();
00922   line->setRecipient( Recipient( recipient, type ) );
00923 }
00924 
00925 void RecipientsEditor::removeRecipient( const QString & recipient,
00926                                         Recipient::Type type )
00927 {
00928   mRecipientsView->removeRecipient( recipient, type );
00929 }
00930 
00931 bool RecipientsEditor::isModified()
00932 {
00933   return mModified || mRecipientsView->isModified();
00934 }
00935 
00936 void RecipientsEditor::clearModified()
00937 {
00938   mModified = false;
00939   mRecipientsView->clearModified();
00940 }
00941 
00942 void RecipientsEditor::clear()
00943 {
00944 }
00945 
00946 void RecipientsEditor::setFocus()
00947 {
00948   mRecipientsView->setFocus();
00949 }
00950 
00951 void RecipientsEditor::setFocusTop()
00952 {
00953   mRecipientsView->setFocusTop();
00954 }
00955 
00956 void RecipientsEditor::setFocusBottom()
00957 {
00958   mRecipientsView->setFocusBottom();
00959 }
00960 
00961 int RecipientsEditor::setFirstColumnWidth( int w )
00962 {
00963   return mRecipientsView->setFirstColumnWidth( w );
00964 }
00965 
00966 void RecipientsEditor::selectRecipients()
00967 {
00968   mSideWidget->pickRecipient();
00969 }
00970 
00971 void RecipientsEditor::setCompletionMode( KGlobalSettings::Completion mode )
00972 {
00973   mRecipientsView->setCompletionMode( mode );
00974 }
00975 #include "recipientseditor.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys