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