kmail

kmsearchpatternedit.cpp

Go to the documentation of this file.
00001 // -*- mode: C++; c-file-style: "gnu" -*-
00002 // kmsearchpatternedit.cpp
00003 // Author: Marc Mutz <Marc@Mutz.com>
00004 // This code is under GPL
00005 
00006 #include <config.h>
00007 #include "kmsearchpatternedit.h"
00008 
00009 #include "kmsearchpattern.h"
00010 #include "rulewidgethandlermanager.h"
00011 using KMail::RuleWidgetHandlerManager;
00012 
00013 #include <klocale.h>
00014 #include <kdialog.h>
00015 #include <kdebug.h>
00016 
00017 #include <qradiobutton.h>
00018 #include <qcombobox.h>
00019 #include <qbuttongroup.h>
00020 #include <qwidgetstack.h>
00021 #include <qlayout.h>
00022 
00023 #include <assert.h>
00024 
00025 // Definition of special rule field strings
00026 // Note: Also see KMSearchRule::matches() and ruleFieldToEnglish() if
00027 //       you change the following i18n-ized strings!
00028 // Note: The index of the values in the following array has to correspond to
00029 //       the value of the entries in the enum in KMSearchRuleWidget.
00030 static const struct {
00031   const char *internalName;
00032   const char *displayName;
00033 } SpecialRuleFields[] = {
00034   { "<message>",     I18N_NOOP( "Complete Message" )       },
00035   { "<body>",        I18N_NOOP( "Body of Message" )          },
00036   { "<any header>",  I18N_NOOP( "Anywhere in Headers" )    },
00037   { "<recipients>",  I18N_NOOP( "All Recipients" )    },
00038   { "<size>",        I18N_NOOP( "Size in Bytes" ) },
00039   { "<age in days>", I18N_NOOP( "Age in Days" )   },
00040   { "<status>",      I18N_NOOP( "Message Status" )        }
00041 };
00042 static const int SpecialRuleFieldsCount =
00043   sizeof( SpecialRuleFields ) / sizeof( *SpecialRuleFields );
00044 
00045 //=============================================================================
00046 //
00047 // class KMSearchRuleWidget
00048 //
00049 //=============================================================================
00050 
00051 KMSearchRuleWidget::KMSearchRuleWidget( QWidget *parent, KMSearchRule *aRule,
00052                                         const char *name, bool headersOnly,
00053                                         bool absoluteDates )
00054   : QWidget( parent, name ),
00055     mRuleField( 0 ),
00056     mFunctionStack( 0 ),
00057     mValueStack( 0 ),
00058     mAbsoluteDates( absoluteDates )
00059 {
00060   initFieldList( headersOnly, absoluteDates );
00061   initWidget();
00062 
00063   if ( aRule )
00064     setRule( aRule );
00065   else
00066     reset();
00067 }
00068 
00069 void KMSearchRuleWidget::setHeadersOnly( bool headersOnly )
00070 {
00071   KMSearchRule* srule = rule();
00072   QCString currentText = srule->field();
00073   delete srule;
00074   initFieldList( headersOnly, mAbsoluteDates );
00075 
00076   mRuleField->clear();
00077   mRuleField->insertStringList( mFilterFieldList );
00078   mRuleField->setSizeLimit( mRuleField->count() );
00079   mRuleField->adjustSize();
00080 
00081   if (( currentText != "<message>") &&
00082       ( currentText != "<body>"))
00083     mRuleField->changeItem( QString::fromAscii( currentText ), 0 );
00084   else
00085     mRuleField->changeItem( QString::null, 0 );
00086 }
00087 
00088 void KMSearchRuleWidget::initWidget()
00089 {
00090   QHBoxLayout * hlay = new QHBoxLayout( this, 0, KDialog::spacingHint() );
00091 
00092   // initialize the header field combo box
00093   mRuleField = new QComboBox( true, this, "mRuleField" );
00094   mRuleField->insertStringList( mFilterFieldList );
00095   // don't show sliders when popping up this menu
00096   mRuleField->setSizeLimit( mRuleField->count() );
00097   mRuleField->adjustSize();
00098   hlay->addWidget( mRuleField );
00099 
00100   // initialize the function/value widget stack
00101   mFunctionStack = new QWidgetStack( this, "mFunctionStack" );
00102   //Don't expand the widget in vertical direction
00103   mFunctionStack->setSizePolicy( QSizePolicy::Preferred,QSizePolicy::Fixed );
00104 
00105   hlay->addWidget( mFunctionStack );
00106 
00107   mValueStack = new QWidgetStack( this, "mValueStack" );
00108   mValueStack->setSizePolicy( QSizePolicy::Preferred,QSizePolicy::Fixed );
00109   hlay->addWidget( mValueStack );
00110   hlay->setStretchFactor( mValueStack, 10 );
00111 
00112   RuleWidgetHandlerManager::instance()->createWidgets( mFunctionStack,
00113                                                        mValueStack,
00114                                                        this );
00115 
00116   // redirect focus to the header field combo box
00117   setFocusProxy( mRuleField );
00118 
00119   connect( mRuleField, SIGNAL( activated( const QString & ) ),
00120        this, SLOT( slotRuleFieldChanged( const QString & ) ) );
00121   connect( mRuleField, SIGNAL( textChanged( const QString & ) ),
00122        this, SLOT( slotRuleFieldChanged( const QString & ) ) );
00123   connect( mRuleField, SIGNAL( textChanged( const QString & ) ),
00124            this, SIGNAL( fieldChanged( const QString & ) ) );
00125 }
00126 
00127 void KMSearchRuleWidget::setRule( KMSearchRule *aRule )
00128 {
00129   assert ( aRule );
00130 
00131 //  kdDebug(5006) << "KMSearchRuleWidget::setRule( "
00132 //                << aRule->asString() << " )" << endl;
00133 
00134   //--------------set the field
00135   int i = indexOfRuleField( aRule->field() );
00136 
00137   mRuleField->blockSignals( true );
00138 
00139   if ( i < 0 ) { // not found -> user defined field
00140     mRuleField->changeItem( QString::fromLatin1( aRule->field() ), 0 );
00141     i = 0;
00142   } else { // found in the list of predefined fields
00143     mRuleField->changeItem( QString::null, 0 );
00144   }
00145 
00146   mRuleField->setCurrentItem( i );
00147   mRuleField->blockSignals( false );
00148 
00149   RuleWidgetHandlerManager::instance()->setRule( mFunctionStack, mValueStack,
00150                                                  aRule );
00151 }
00152 
00153 KMSearchRule* KMSearchRuleWidget::rule() const {
00154   const QCString ruleField = ruleFieldToEnglish( mRuleField->currentText() );
00155   const KMSearchRule::Function function =
00156     RuleWidgetHandlerManager::instance()->function( ruleField,
00157                                                     mFunctionStack );
00158   const QString value =
00159     RuleWidgetHandlerManager::instance()->value( ruleField, mFunctionStack,
00160                                                  mValueStack );
00161 
00162   return KMSearchRule::createInstance( ruleField, function, value );
00163 }
00164 
00165 void KMSearchRuleWidget::reset()
00166 {
00167   mRuleField->blockSignals( true );
00168   mRuleField->changeItem( "", 0 );
00169   mRuleField->setCurrentItem( 0 );
00170   mRuleField->blockSignals( false );
00171 
00172   RuleWidgetHandlerManager::instance()->reset( mFunctionStack, mValueStack );
00173 }
00174 
00175 void KMSearchRuleWidget::slotFunctionChanged()
00176 {
00177   const QCString ruleField = ruleFieldToEnglish( mRuleField->currentText() );
00178   RuleWidgetHandlerManager::instance()->update( ruleField,
00179                                                 mFunctionStack,
00180                                                 mValueStack );
00181 }
00182 
00183 void KMSearchRuleWidget::slotValueChanged()
00184 {
00185   const QCString ruleField = ruleFieldToEnglish( mRuleField->currentText() );
00186   const QString prettyValue =
00187     RuleWidgetHandlerManager::instance()->prettyValue( ruleField,
00188                                                        mFunctionStack,
00189                                                        mValueStack );
00190   emit contentsChanged( prettyValue );
00191 }
00192 
00193 QCString KMSearchRuleWidget::ruleFieldToEnglish( const QString & i18nVal )
00194 {
00195   for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) {
00196     if ( i18nVal == i18n( SpecialRuleFields[i].displayName ) )
00197       return SpecialRuleFields[i].internalName;
00198   }
00199   return i18nVal.latin1();
00200 }
00201 
00202 int KMSearchRuleWidget::ruleFieldToId( const QString & i18nVal )
00203 {
00204   for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) {
00205     if ( i18nVal == i18n( SpecialRuleFields[i].displayName ) )
00206       return i;
00207   }
00208   return -1; // no pseudo header
00209 }
00210 
00211 static QString displayNameFromInternalName( const QString & internal )
00212 {
00213   for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) {
00214     if ( internal == SpecialRuleFields[i].internalName )
00215       return i18n(SpecialRuleFields[i].displayName);
00216   }
00217   return internal.latin1();
00218 }
00219 
00220 
00221 
00222 int KMSearchRuleWidget::indexOfRuleField( const QCString & aName ) const
00223 {
00224   if ( aName.isEmpty() )
00225     return -1;
00226 
00227   QString i18n_aName = displayNameFromInternalName( aName );
00228 
00229   for ( int i = 1; i < mRuleField->count(); ++i ) {
00230     if ( mRuleField->text( i ) == i18n_aName )
00231       return i;
00232   }
00233 
00234   return -1;
00235 }
00236 
00237 void KMSearchRuleWidget::initFieldList( bool headersOnly, bool absoluteDates )
00238 {
00239   mFilterFieldList.clear();
00240   mFilterFieldList.append(""); // empty entry for user input
00241   if( !headersOnly ) {
00242     mFilterFieldList.append( i18n( SpecialRuleFields[Message].displayName ) );
00243     mFilterFieldList.append( i18n( SpecialRuleFields[Body].displayName ) );
00244   }
00245   mFilterFieldList.append( i18n( SpecialRuleFields[AnyHeader].displayName ) );
00246   mFilterFieldList.append( i18n( SpecialRuleFields[Recipients].displayName ) );
00247   mFilterFieldList.append( i18n( SpecialRuleFields[Size].displayName ) );
00248   if ( !absoluteDates )
00249     mFilterFieldList.append( i18n( SpecialRuleFields[AgeInDays].displayName ) );
00250   mFilterFieldList.append( i18n( SpecialRuleFields[Status].displayName ) );
00251   // these others only represent message headers and you can add to
00252   // them as you like
00253   mFilterFieldList.append("Subject");
00254   mFilterFieldList.append("From");
00255   mFilterFieldList.append("To");
00256   mFilterFieldList.append("CC");
00257   mFilterFieldList.append("Reply-To");
00258   mFilterFieldList.append("List-Id");
00259   mFilterFieldList.append("Organization");
00260   mFilterFieldList.append("Resent-From");
00261   mFilterFieldList.append("X-Loop");
00262   mFilterFieldList.append("X-Mailing-List");
00263   mFilterFieldList.append("X-Spam-Flag");
00264 }
00265 
00266 void KMSearchRuleWidget::slotRuleFieldChanged( const QString & field )
00267 {
00268   RuleWidgetHandlerManager::instance()->update( ruleFieldToEnglish( field ),
00269                                                 mFunctionStack,
00270                                                 mValueStack );
00271 }
00272 
00273 //=============================================================================
00274 //
00275 // class KMFilterActionWidgetLister (the filter action editor)
00276 //
00277 //=============================================================================
00278 
00279 KMSearchRuleWidgetLister::KMSearchRuleWidgetLister( QWidget *parent, const char* name, bool headersOnly, bool absoluteDates )
00280   : KWidgetLister( 2, FILTER_MAX_RULES, parent, name )
00281 {
00282   mRuleList = 0;
00283   mHeadersOnly = headersOnly;
00284   mAbsoluteDates = absoluteDates;
00285 }
00286 
00287 KMSearchRuleWidgetLister::~KMSearchRuleWidgetLister()
00288 {
00289 }
00290 
00291 void KMSearchRuleWidgetLister::setRuleList( QPtrList<KMSearchRule> *aList )
00292 {
00293   assert ( aList );
00294 
00295   if ( mRuleList && mRuleList != aList )
00296     regenerateRuleListFromWidgets();
00297 
00298   mRuleList = aList;
00299 
00300   if ( mWidgetList.first() ) // move this below next 'if'?
00301     mWidgetList.first()->blockSignals(true);
00302 
00303   if ( aList->count() == 0 ) {
00304     slotClear();
00305     mWidgetList.first()->blockSignals(false);
00306     return;
00307   }
00308 
00309   int superfluousItems = (int)mRuleList->count() - mMaxWidgets ;
00310   if ( superfluousItems > 0 ) {
00311     kdDebug(5006) << "KMSearchRuleWidgetLister: Clipping rule list to "
00312           << mMaxWidgets << " items!" << endl;
00313 
00314     for ( ; superfluousItems ; superfluousItems-- )
00315       mRuleList->removeLast();
00316   }
00317 
00318   // HACK to workaround regression in Qt 3.1.3 and Qt 3.2.0 (fixes bug #63537)
00319   setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets)+1 );
00320   // set the right number of widgets
00321   setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets) );
00322 
00323   // load the actions into the widgets
00324   QPtrListIterator<KMSearchRule> rIt( *mRuleList );
00325   QPtrListIterator<QWidget> wIt( mWidgetList );
00326   for ( rIt.toFirst(), wIt.toFirst() ;
00327     rIt.current() && wIt.current() ; ++rIt, ++wIt ) {
00328     static_cast<KMSearchRuleWidget*>(*wIt)->setRule( (*rIt) );
00329   }
00330   for ( ; wIt.current() ; ++wIt )
00331     ((KMSearchRuleWidget*)(*wIt))->reset();
00332 
00333   assert( mWidgetList.first() );
00334   mWidgetList.first()->blockSignals(false);
00335 }
00336 
00337 void KMSearchRuleWidgetLister::setHeadersOnly( bool headersOnly )
00338 {
00339   QPtrListIterator<QWidget> wIt( mWidgetList );
00340   for ( wIt.toFirst() ; wIt.current() ; ++wIt ) {
00341     (static_cast<KMSearchRuleWidget*>(*wIt))->setHeadersOnly( headersOnly );
00342   }
00343 }
00344 
00345 void KMSearchRuleWidgetLister::reset()
00346 {
00347   if ( mRuleList )
00348     regenerateRuleListFromWidgets();
00349 
00350   mRuleList = 0;
00351   slotClear();
00352 }
00353 
00354 QWidget* KMSearchRuleWidgetLister::createWidget( QWidget *parent )
00355 {
00356   return new KMSearchRuleWidget(parent, 0, 0, mHeadersOnly, mAbsoluteDates);
00357 }
00358 
00359 void KMSearchRuleWidgetLister::clearWidget( QWidget *aWidget )
00360 {
00361   if ( aWidget )
00362     ((KMSearchRuleWidget*)aWidget)->reset();
00363 }
00364 
00365 void KMSearchRuleWidgetLister::regenerateRuleListFromWidgets()
00366 {
00367   if ( !mRuleList ) return;
00368 
00369   mRuleList->clear();
00370 
00371   QPtrListIterator<QWidget> it( mWidgetList );
00372   for ( it.toFirst() ; it.current() ; ++it ) {
00373     KMSearchRule *r = ((KMSearchRuleWidget*)(*it))->rule();
00374     if ( r )
00375       mRuleList->append( r );
00376   }
00377 }
00378 
00379 
00380 
00381 
00382 //=============================================================================
00383 //
00384 // class KMSearchPatternEdit
00385 //
00386 //=============================================================================
00387 
00388 KMSearchPatternEdit::KMSearchPatternEdit(QWidget *parent, const char *name, bool headersOnly, bool absoluteDates )
00389   : QGroupBox( 1/*columns*/, Horizontal, parent, name )
00390 {
00391   setTitle( i18n("Search Criteria") );
00392   initLayout( headersOnly, absoluteDates );
00393 }
00394 
00395 KMSearchPatternEdit::KMSearchPatternEdit(const QString & title, QWidget *parent, const char *name, bool headersOnly, bool absoluteDates)
00396   : QGroupBox( 1/*column*/, Horizontal, title, parent, name )
00397 {
00398   initLayout( headersOnly, absoluteDates );
00399 }
00400 
00401 KMSearchPatternEdit::~KMSearchPatternEdit()
00402 {
00403 }
00404 
00405 void KMSearchPatternEdit::initLayout(bool headersOnly, bool absoluteDates)
00406 {
00407   //------------the radio buttons
00408   mAllRBtn = new QRadioButton( i18n("Match a&ll of the following"), this, "mAllRBtn" );
00409   mAnyRBtn = new QRadioButton( i18n("Match an&y of the following"), this, "mAnyRBtn" );
00410 
00411   mAllRBtn->setChecked(true);
00412   mAnyRBtn->setChecked(false);
00413 
00414   QButtonGroup *bg = new QButtonGroup( this );
00415   bg->hide();
00416   bg->insert( mAllRBtn, (int)KMSearchPattern::OpAnd );
00417   bg->insert( mAnyRBtn, (int)KMSearchPattern::OpOr );
00418 
00419   //------------the list of KMSearchRuleWidget's
00420   mRuleLister = new KMSearchRuleWidgetLister( this, "swl", headersOnly, absoluteDates );
00421   mRuleLister->slotClear();
00422 
00423   //------------connect a few signals
00424   connect( bg, SIGNAL(clicked(int)),
00425        this, SLOT(slotRadioClicked(int)) );
00426 
00427   KMSearchRuleWidget *srw = (KMSearchRuleWidget*)mRuleLister->mWidgetList.first();
00428   if ( srw ) {
00429     connect( srw, SIGNAL(fieldChanged(const QString &)),
00430          this, SLOT(slotAutoNameHack()) );
00431     connect( srw, SIGNAL(contentsChanged(const QString &)),
00432          this, SLOT(slotAutoNameHack()) );
00433   } else
00434     kdDebug(5006) << "KMSearchPatternEdit: no first KMSearchRuleWidget, though slotClear() has been called!" << endl;
00435 }
00436 
00437 void KMSearchPatternEdit::setSearchPattern( KMSearchPattern *aPattern )
00438 {
00439   assert( aPattern );
00440 
00441   mRuleLister->setRuleList( aPattern );
00442 
00443   mPattern = aPattern;
00444 
00445   blockSignals(true);
00446   if ( mPattern->op() == KMSearchPattern::OpOr )
00447     mAnyRBtn->setChecked(true);
00448   else
00449     mAllRBtn->setChecked(true);
00450   blockSignals(false);
00451 
00452   setEnabled( true );
00453 }
00454 
00455 void KMSearchPatternEdit::setHeadersOnly( bool headersOnly )
00456 {
00457   mRuleLister->setHeadersOnly( headersOnly );
00458 }
00459 
00460 void KMSearchPatternEdit::reset()
00461 {
00462   mRuleLister->reset();
00463 
00464   blockSignals(true);
00465   mAllRBtn->setChecked( true );
00466   blockSignals(false);
00467 
00468   setEnabled( false );
00469 }
00470 
00471 void KMSearchPatternEdit::slotRadioClicked(int aIdx)
00472 {
00473   if ( mPattern )
00474     mPattern->setOp( (KMSearchPattern::Operator)aIdx );
00475 }
00476 
00477 void KMSearchPatternEdit::slotAutoNameHack()
00478 {
00479   mRuleLister->regenerateRuleListFromWidgets();
00480   emit maybeNameChanged();
00481 }
00482 
00483 #include "kmsearchpatternedit.moc"