kmail

kmsearchpatternedit.cpp

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