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   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 int KMSearchRuleWidget::indexOfRuleField( const QCString & aName ) const
00212 {
00213   if ( aName.isEmpty() )
00214     return -1;
00215 
00216   QString i18n_aName = i18n( aName );
00217 
00218   for ( int i = 1; i < mRuleField->count(); ++i ) {
00219     if ( mRuleField->text( i ) == i18n_aName )
00220       return i;
00221   }
00222 
00223   return -1;
00224 }
00225 
00226 void KMSearchRuleWidget::initFieldList( bool headersOnly, bool absoluteDates )
00227 {
00228   mFilterFieldList.clear();
00229   mFilterFieldList.append(""); // empty entry for user input
00230   if( !headersOnly ) {
00231     mFilterFieldList.append( i18n( SpecialRuleFields[Message].displayName ) );
00232     mFilterFieldList.append( i18n( SpecialRuleFields[Body].displayName ) );
00233   }
00234   mFilterFieldList.append( i18n( SpecialRuleFields[AnyHeader].displayName ) );
00235   mFilterFieldList.append( i18n( SpecialRuleFields[Recipients].displayName ) );
00236   mFilterFieldList.append( i18n( SpecialRuleFields[Size].displayName ) );
00237   if ( !absoluteDates )
00238     mFilterFieldList.append( i18n( SpecialRuleFields[AgeInDays].displayName ) );
00239   mFilterFieldList.append( i18n( SpecialRuleFields[Status].displayName ) );
00240   // these others only represent message headers and you can add to
00241   // them as you like
00242   mFilterFieldList.append("Subject");
00243   mFilterFieldList.append("From");
00244   mFilterFieldList.append("To");
00245   mFilterFieldList.append("CC");
00246   mFilterFieldList.append("Reply-To");
00247   mFilterFieldList.append("List-Id");
00248   mFilterFieldList.append("Organization");
00249   mFilterFieldList.append("Resent-From");
00250   mFilterFieldList.append("X-Loop");
00251   mFilterFieldList.append("X-Mailing-List");
00252   mFilterFieldList.append("X-Spam-Flag");
00253 }
00254 
00255 void KMSearchRuleWidget::slotRuleFieldChanged( const QString & field )
00256 {
00257   RuleWidgetHandlerManager::instance()->update( ruleFieldToEnglish( field ),
00258                                                 mFunctionStack,
00259                                                 mValueStack );
00260 }
00261 
00262 //=============================================================================
00263 //
00264 // class KMFilterActionWidgetLister (the filter action editor)
00265 //
00266 //=============================================================================
00267 
00268 KMSearchRuleWidgetLister::KMSearchRuleWidgetLister( QWidget *parent, const char* name, bool headersOnly, bool absoluteDates )
00269   : KWidgetLister( 2, FILTER_MAX_RULES, parent, name )
00270 {
00271   mRuleList = 0;
00272   mHeadersOnly = headersOnly;
00273   mAbsoluteDates = absoluteDates;
00274 }
00275 
00276 KMSearchRuleWidgetLister::~KMSearchRuleWidgetLister()
00277 {
00278 }
00279 
00280 void KMSearchRuleWidgetLister::setRuleList( QPtrList<KMSearchRule> *aList )
00281 {
00282   assert ( aList );
00283 
00284   if ( mRuleList )
00285     regenerateRuleListFromWidgets();
00286 
00287   mRuleList = aList;
00288 
00289   if ( mWidgetList.first() ) // move this below next 'if'?
00290     mWidgetList.first()->blockSignals(TRUE);
00291 
00292   if ( aList->count() == 0 ) {
00293     slotClear();
00294     mWidgetList.first()->blockSignals(FALSE);
00295     return;
00296   }
00297 
00298   int superfluousItems = (int)mRuleList->count() - mMaxWidgets ;
00299   if ( superfluousItems > 0 ) {
00300     kdDebug(5006) << "KMSearchRuleWidgetLister: Clipping rule list to "
00301           << mMaxWidgets << " items!" << endl;
00302 
00303     for ( ; superfluousItems ; superfluousItems-- )
00304       mRuleList->removeLast();
00305   }
00306 
00307   // HACK to workaround regression in Qt 3.1.3 and Qt 3.2.0 (fixes bug #63537)
00308   setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets)+1 );
00309   // set the right number of widgets
00310   setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets) );
00311 
00312   // load the actions into the widgets
00313   QPtrListIterator<KMSearchRule> rIt( *mRuleList );
00314   QPtrListIterator<QWidget> wIt( mWidgetList );
00315   for ( rIt.toFirst(), wIt.toFirst() ;
00316     rIt.current() && wIt.current() ; ++rIt, ++wIt ) {
00317     (static_cast<KMSearchRuleWidget*>(*wIt))->setRule( (*rIt) );
00318   }
00319   for ( ; wIt.current() ; ++wIt )
00320     ((KMSearchRuleWidget*)(*wIt))->reset();
00321 
00322   assert( mWidgetList.first() );
00323   mWidgetList.first()->blockSignals(FALSE);
00324 }
00325 
00326 void KMSearchRuleWidgetLister::setHeadersOnly( bool headersOnly )
00327 {
00328   QPtrListIterator<QWidget> wIt( mWidgetList );
00329   for ( wIt.toFirst() ; wIt.current() ; ++wIt ) {
00330     (static_cast<KMSearchRuleWidget*>(*wIt))->setHeadersOnly( headersOnly );
00331   }
00332 }
00333 
00334 void KMSearchRuleWidgetLister::reset()
00335 {
00336   if ( mRuleList )
00337     regenerateRuleListFromWidgets();
00338 
00339   mRuleList = 0;
00340   slotClear();
00341 }
00342 
00343 QWidget* KMSearchRuleWidgetLister::createWidget( QWidget *parent )
00344 {
00345   return new KMSearchRuleWidget(parent, 0, 0, mHeadersOnly, mAbsoluteDates);
00346 }
00347 
00348 void KMSearchRuleWidgetLister::clearWidget( QWidget *aWidget )
00349 {
00350   if ( aWidget )
00351     ((KMSearchRuleWidget*)aWidget)->reset();
00352 }
00353 
00354 void KMSearchRuleWidgetLister::regenerateRuleListFromWidgets()
00355 {
00356   if ( !mRuleList ) return;
00357 
00358   mRuleList->clear();
00359 
00360   QPtrListIterator<QWidget> it( mWidgetList );
00361   for ( it.toFirst() ; it.current() ; ++it ) {
00362     KMSearchRule *r = ((KMSearchRuleWidget*)(*it))->rule();
00363     if ( r )
00364       mRuleList->append( r );
00365   }
00366 }
00367 
00368 
00369 
00370 
00371 //=============================================================================
00372 //
00373 // class KMSearchPatternEdit
00374 //
00375 //=============================================================================
00376 
00377 KMSearchPatternEdit::KMSearchPatternEdit(QWidget *parent, const char *name, bool headersOnly, bool absoluteDates )
00378   : QGroupBox( 1/*columns*/, Horizontal, parent, name )
00379 {
00380   setTitle( i18n("Search Criteria") );
00381   initLayout( headersOnly, absoluteDates );
00382 }
00383 
00384 KMSearchPatternEdit::KMSearchPatternEdit(const QString & title, QWidget *parent, const char *name, bool headersOnly, bool absoluteDates)
00385   : QGroupBox( 1/*column*/, Horizontal, title, parent, name )
00386 {
00387   initLayout( headersOnly, absoluteDates );
00388 }
00389 
00390 KMSearchPatternEdit::~KMSearchPatternEdit()
00391 {
00392 }
00393 
00394 void KMSearchPatternEdit::initLayout(bool headersOnly, bool absoluteDates)
00395 {
00396   //------------the radio buttons
00397   mAllRBtn = new QRadioButton( i18n("Match a&ll of the following"), this, "mAllRBtn" );
00398   mAnyRBtn = new QRadioButton( i18n("Match an&y of the following"), this, "mAnyRBtn" );
00399 
00400   mAllRBtn->setChecked(TRUE);
00401   mAnyRBtn->setChecked(FALSE);
00402 
00403   QButtonGroup *bg = new QButtonGroup( this );
00404   bg->hide();
00405   bg->insert( mAllRBtn, (int)KMSearchPattern::OpAnd );
00406   bg->insert( mAnyRBtn, (int)KMSearchPattern::OpOr );
00407 
00408   //------------the list of KMSearchRuleWidget's
00409   mRuleLister = new KMSearchRuleWidgetLister( this, "swl", headersOnly, absoluteDates );
00410   mRuleLister->slotClear();
00411 
00412   //------------connect a few signals
00413   connect( bg, SIGNAL(clicked(int)),
00414        this, SLOT(slotRadioClicked(int)) );
00415 
00416   KMSearchRuleWidget *srw = (KMSearchRuleWidget*)mRuleLister->mWidgetList.first();
00417   if ( srw ) {
00418     connect( srw, SIGNAL(fieldChanged(const QString &)),
00419          this, SLOT(slotAutoNameHack()) );
00420     connect( srw, SIGNAL(contentsChanged(const QString &)),
00421          this, SLOT(slotAutoNameHack()) );
00422   } else
00423     kdDebug(5006) << "KMSearchPatternEdit: no first KMSearchRuleWidget, though slotClear() has been called!" << endl;
00424 }
00425 
00426 void KMSearchPatternEdit::setSearchPattern( KMSearchPattern *aPattern )
00427 {
00428   assert( aPattern );
00429 
00430   mRuleLister->setRuleList( aPattern );
00431 
00432   mPattern = aPattern;
00433 
00434   blockSignals(TRUE);
00435   if ( mPattern->op() == KMSearchPattern::OpOr )
00436     mAnyRBtn->setChecked(TRUE);
00437   else
00438     mAllRBtn->setChecked(TRUE);
00439   blockSignals(FALSE);
00440 
00441   setEnabled( TRUE );
00442 }
00443 
00444 void KMSearchPatternEdit::setHeadersOnly( bool headersOnly )
00445 {
00446   mRuleLister->setHeadersOnly( headersOnly );
00447 }
00448 
00449 void KMSearchPatternEdit::reset()
00450 {
00451   mRuleLister->reset();
00452 
00453   blockSignals(TRUE);
00454   mAllRBtn->setChecked( TRUE );
00455   blockSignals(FALSE);
00456 
00457   setEnabled( FALSE );
00458 }
00459 
00460 void KMSearchPatternEdit::slotRadioClicked(int aIdx)
00461 {
00462   if ( mPattern )
00463     mPattern->setOp( (KMSearchPattern::Operator)aIdx );
00464 }
00465 
00466 void KMSearchPatternEdit::slotAutoNameHack()
00467 {
00468   mRuleLister->regenerateRuleListFromWidgets();
00469   emit maybeNameChanged();
00470 }
00471 
00472 #include "kmsearchpatternedit.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys