// -*- mode: C++; c-file-style: "gnu" -*- // kmsearchpatternedit.cpp // Author: Marc Mutz // This code is under GPL #include #include "kmsearchpatternedit.h" #include "kmsearchpattern.h" #include "rulewidgethandlermanager.h" using KMail::RuleWidgetHandlerManager; #include #include #include #include #include #include #include #include #include // Definition of special rule field strings // Note: Also see KMSearchRule::matches() and ruleFieldToEnglish() if // you change the following i18n-ized strings! // Note: The index of the values in the following array has to correspond to // the value of the entries in the enum in KMSearchRuleWidget. static const struct { const char *internalName; const char *displayName; } SpecialRuleFields[] = { { "", I18N_NOOP( "Complete Message" ) }, { "", I18N_NOOP( "Body of Message" ) }, { "", I18N_NOOP( "Anywhere in Headers" ) }, { "", I18N_NOOP( "All Recipients" ) }, { "", I18N_NOOP( "Size in Bytes" ) }, { "", I18N_NOOP( "Age in Days" ) }, { "", I18N_NOOP( "Message Status" ) }, { "Subject", I18N_NOOP( "Subject" ) }, { "From", I18N_NOOP( "From" ) }, { "To", I18N_NOOP( "To" ) }, { "CC", I18N_NOOP( "CC" ) }, { "Reply-To", I18N_NOOP( "Reply To" ) }, { "Organization", I18N_NOOP( "Organization" ) } }; static const int SpecialRuleFieldsCount = sizeof( SpecialRuleFields ) / sizeof( *SpecialRuleFields ); //============================================================================= // // class KMSearchRuleWidget // //============================================================================= KMSearchRuleWidget::KMSearchRuleWidget( TQWidget *parent, KMSearchRule *aRule, const char *name, bool headersOnly, bool absoluteDates ) : TQWidget( parent, name ), mRuleField( 0 ), mFunctionStack( 0 ), mValueStack( 0 ), mAbsoluteDates( absoluteDates ) { initFieldList( headersOnly, absoluteDates ); initWidget(); if ( aRule ) setRule( aRule ); else reset(); } void KMSearchRuleWidget::setHeadersOnly( bool headersOnly ) { KMSearchRule* srule = rule(); TQCString currentText = srule->field(); delete srule; initFieldList( headersOnly, mAbsoluteDates ); mRuleField->clear(); mRuleField->insertStringList( mFilterFieldList ); mRuleField->setSizeLimit( mRuleField->count() ); mRuleField->adjustSize(); if (( currentText != "") && ( currentText != "")) mRuleField->changeItem( TQString(TQString::fromAscii( currentText )), 0 ); else mRuleField->changeItem( TQString(), 0 ); } void KMSearchRuleWidget::initWidget() { TQHBoxLayout * hlay = new TQHBoxLayout( this, 0, KDialog::spacingHint() ); // initialize the header field combo box mRuleField = new TQComboBox( true, this, "mRuleField" ); mRuleField->insertStringList( mFilterFieldList ); // don't show sliders when popping up this menu mRuleField->setSizeLimit( mRuleField->count() ); mRuleField->adjustSize(); hlay->addWidget( mRuleField ); // initialize the function/value widget stack mFunctionStack = new TQWidgetStack( this, "mFunctionStack" ); //Don't expand the widget in vertical direction mFunctionStack->setSizePolicy( TQSizePolicy::Preferred,TQSizePolicy::Fixed ); hlay->addWidget( mFunctionStack ); mValueStack = new TQWidgetStack( this, "mValueStack" ); mValueStack->setSizePolicy( TQSizePolicy::Preferred,TQSizePolicy::Fixed ); hlay->addWidget( mValueStack ); hlay->setStretchFactor( mValueStack, 10 ); RuleWidgetHandlerManager::instance()->createWidgets( mFunctionStack, mValueStack, TQT_TQOBJECT(this) ); // redirect focus to the header field combo box setFocusProxy( mRuleField ); connect( mRuleField, TQT_SIGNAL( activated( const TQString & ) ), this, TQT_SLOT( slotRuleFieldChanged( const TQString & ) ) ); connect( mRuleField, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SLOT( slotRuleFieldChanged( const TQString & ) ) ); connect( mRuleField, TQT_SIGNAL( textChanged( const TQString & ) ), this, TQT_SIGNAL( fieldChanged( const TQString & ) ) ); } void KMSearchRuleWidget::setRule( KMSearchRule *aRule ) { assert ( aRule ); // kdDebug(5006) << "KMSearchRuleWidget::setRule( " // << aRule->asString() << " )" << endl; //--------------set the field int i = indexOfRuleField( aRule->field() ); mRuleField->blockSignals( true ); if ( i < 0 ) { // not found -> user defined field mRuleField->changeItem( TQString::fromLatin1( aRule->field() ), 0 ); i = 0; } else { // found in the list of predefined fields mRuleField->changeItem( TQString(), 0 ); } mRuleField->setCurrentItem( i ); mRuleField->blockSignals( false ); RuleWidgetHandlerManager::instance()->setRule( mFunctionStack, mValueStack, aRule ); } KMSearchRule* KMSearchRuleWidget::rule() const { const TQCString ruleField = ruleFieldToEnglish( mRuleField->currentText() ); const KMSearchRule::Function function = RuleWidgetHandlerManager::instance()->function( ruleField, mFunctionStack ); const TQString value = RuleWidgetHandlerManager::instance()->value( ruleField, mFunctionStack, mValueStack ); return KMSearchRule::createInstance( ruleField, function, value ); } void KMSearchRuleWidget::reset() { mRuleField->blockSignals( true ); mRuleField->changeItem( "", 0 ); mRuleField->setCurrentItem( 0 ); mRuleField->blockSignals( false ); RuleWidgetHandlerManager::instance()->reset( mFunctionStack, mValueStack ); } void KMSearchRuleWidget::slotFunctionChanged() { const TQCString ruleField = ruleFieldToEnglish( mRuleField->currentText() ); RuleWidgetHandlerManager::instance()->update( ruleField, mFunctionStack, mValueStack ); } void KMSearchRuleWidget::slotValueChanged() { const TQCString ruleField = ruleFieldToEnglish( mRuleField->currentText() ); const TQString prettyValue = RuleWidgetHandlerManager::instance()->prettyValue( ruleField, mFunctionStack, mValueStack ); emit contentsChanged( prettyValue ); } TQCString KMSearchRuleWidget::ruleFieldToEnglish( const TQString & i18nVal ) { for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) { if ( i18nVal == i18n( SpecialRuleFields[i].displayName ) ) return SpecialRuleFields[i].internalName; } return i18nVal.latin1(); } int KMSearchRuleWidget::ruleFieldToId( const TQString & i18nVal ) { for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) { if ( i18nVal == i18n( SpecialRuleFields[i].displayName ) ) return i; } return -1; // no pseudo header } static TQString displayNameFromInternalName( const TQString & internal ) { for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) { if ( internal == SpecialRuleFields[i].internalName ) return i18n(SpecialRuleFields[i].displayName); } return internal.latin1(); } int KMSearchRuleWidget::indexOfRuleField( const TQCString & aName ) const { if ( aName.isEmpty() ) return -1; TQString i18n_aName = displayNameFromInternalName( aName ); for ( int i = 1; i < mRuleField->count(); ++i ) { if ( mRuleField->text( i ) == i18n_aName ) return i; } return -1; } void KMSearchRuleWidget::initFieldList( bool headersOnly, bool absoluteDates ) { mFilterFieldList.clear(); mFilterFieldList.append(""); // empty entry for user input if( !headersOnly ) { mFilterFieldList.append( i18n( SpecialRuleFields[Message].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[Body].displayName ) ); } mFilterFieldList.append( i18n( SpecialRuleFields[AnyHeader].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[Recipients].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[Size].displayName ) ); if ( !absoluteDates ) mFilterFieldList.append( i18n( SpecialRuleFields[AgeInDays].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[Subject].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[From].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[To].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[CC].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[ReplyTo].displayName ) ); mFilterFieldList.append( i18n( SpecialRuleFields[Organization].displayName ) ); // these others only represent message headers and you can add to // them as you like mFilterFieldList.append("List-Id"); mFilterFieldList.append("Resent-From"); mFilterFieldList.append("X-Loop"); mFilterFieldList.append("X-Mailing-List"); mFilterFieldList.append("X-Spam-Flag"); } void KMSearchRuleWidget::slotRuleFieldChanged( const TQString & field ) { RuleWidgetHandlerManager::instance()->update( ruleFieldToEnglish( field ), mFunctionStack, mValueStack ); } //============================================================================= // // class KMFilterActionWidgetLister (the filter action editor) // //============================================================================= KMSearchRuleWidgetLister::KMSearchRuleWidgetLister( TQWidget *parent, const char* name, bool headersOnly, bool absoluteDates ) : KWidgetLister( 2, FILTER_MAX_RULES, parent, name ) { mRuleList = 0; mHeadersOnly = headersOnly; mAbsoluteDates = absoluteDates; } KMSearchRuleWidgetLister::~KMSearchRuleWidgetLister() { } void KMSearchRuleWidgetLister::setRuleList( TQPtrList *aList ) { assert ( aList ); if ( mRuleList && mRuleList != aList ) regenerateRuleListFromWidgets(); mRuleList = aList; if ( mWidgetList.first() ) // move this below next 'if'? mWidgetList.first()->blockSignals(true); if ( aList->count() == 0 ) { slotClear(); mWidgetList.first()->blockSignals(false); return; } int superfluousItems = (int)mRuleList->count() - mMaxWidgets ; if ( superfluousItems > 0 ) { kdDebug(5006) << "KMSearchRuleWidgetLister: Clipping rule list to " << mMaxWidgets << " items!" << endl; for ( ; superfluousItems ; superfluousItems-- ) mRuleList->removeLast(); } // HACK to workaround regression in TQt 3.1.3 and TQt 3.2.0 (fixes bug #63537) setNumberOfShownWidgetsTo( TQMAX((int)mRuleList->count(),mMinWidgets)+1 ); // set the right number of widgets setNumberOfShownWidgetsTo( TQMAX((int)mRuleList->count(),mMinWidgets) ); // load the actions into the widgets TQPtrListIterator rIt( *mRuleList ); TQPtrListIterator wIt( mWidgetList ); for ( rIt.toFirst(), wIt.toFirst() ; rIt.current() && wIt.current() ; ++rIt, ++wIt ) { static_cast(*wIt)->setRule( (*rIt) ); } for ( ; wIt.current() ; ++wIt ) ((KMSearchRuleWidget*)(*wIt))->reset(); assert( mWidgetList.first() ); mWidgetList.first()->blockSignals(false); } void KMSearchRuleWidgetLister::setHeadersOnly( bool headersOnly ) { TQPtrListIterator wIt( mWidgetList ); for ( wIt.toFirst() ; wIt.current() ; ++wIt ) { (static_cast(*wIt))->setHeadersOnly( headersOnly ); } } void KMSearchRuleWidgetLister::reset() { if ( mRuleList ) regenerateRuleListFromWidgets(); mRuleList = 0; slotClear(); } TQWidget* KMSearchRuleWidgetLister::createWidget( TQWidget *parent ) { return new KMSearchRuleWidget(parent, 0, 0, mHeadersOnly, mAbsoluteDates); } void KMSearchRuleWidgetLister::clearWidget( TQWidget *aWidget ) { if ( aWidget ) ((KMSearchRuleWidget*)aWidget)->reset(); } void KMSearchRuleWidgetLister::regenerateRuleListFromWidgets() { if ( !mRuleList ) return; mRuleList->clear(); TQPtrListIterator it( mWidgetList ); for ( it.toFirst() ; it.current() ; ++it ) { KMSearchRule *r = ((KMSearchRuleWidget*)(*it))->rule(); if ( r ) mRuleList->append( r ); } } //============================================================================= // // class KMSearchPatternEdit // //============================================================================= KMSearchPatternEdit::KMSearchPatternEdit(TQWidget *parent, const char *name, bool headersOnly, bool absoluteDates ) : TQGroupBox( 1/*columns*/, Qt::Horizontal, parent, name ) { setTitle( i18n("Search Criteria") ); initLayout( headersOnly, absoluteDates ); } KMSearchPatternEdit::KMSearchPatternEdit(const TQString & title, TQWidget *parent, const char *name, bool headersOnly, bool absoluteDates) : TQGroupBox( 1/*column*/, Qt::Horizontal, title, parent, name ) { initLayout( headersOnly, absoluteDates ); } KMSearchPatternEdit::~KMSearchPatternEdit() { } void KMSearchPatternEdit::initLayout(bool headersOnly, bool absoluteDates) { //------------the radio buttons mAllRBtn = new TQRadioButton( i18n("Match a&ll of the following"), this, "mAllRBtn" ); mAnyRBtn = new TQRadioButton( i18n("Match an&y of the following"), this, "mAnyRBtn" ); mAllRBtn->setChecked(true); mAnyRBtn->setChecked(false); TQButtonGroup *bg = new TQButtonGroup( this ); bg->hide(); bg->insert( mAllRBtn, (int)KMSearchPattern::OpAnd ); bg->insert( mAnyRBtn, (int)KMSearchPattern::OpOr ); //------------the list of KMSearchRuleWidget's mRuleLister = new KMSearchRuleWidgetLister( this, "swl", headersOnly, absoluteDates ); mRuleLister->slotClear(); //------------connect a few signals connect( bg, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(slotRadioClicked(int)) ); KMSearchRuleWidget *srw = (KMSearchRuleWidget*)mRuleLister->mWidgetList.first(); if ( srw ) { connect( srw, TQT_SIGNAL(fieldChanged(const TQString &)), this, TQT_SLOT(slotAutoNameHack()) ); connect( srw, TQT_SIGNAL(contentsChanged(const TQString &)), this, TQT_SLOT(slotAutoNameHack()) ); } else kdDebug(5006) << "KMSearchPatternEdit: no first KMSearchRuleWidget, though slotClear() has been called!" << endl; } void KMSearchPatternEdit::setSearchPattern( KMSearchPattern *aPattern ) { assert( aPattern ); mRuleLister->setRuleList( aPattern ); mPattern = aPattern; blockSignals(true); if ( mPattern->op() == KMSearchPattern::OpOr ) mAnyRBtn->setChecked(true); else mAllRBtn->setChecked(true); blockSignals(false); setEnabled( true ); } void KMSearchPatternEdit::setHeadersOnly( bool headersOnly ) { mRuleLister->setHeadersOnly( headersOnly ); } void KMSearchPatternEdit::reset() { mRuleLister->reset(); blockSignals(true); mAllRBtn->setChecked( true ); blockSignals(false); setEnabled( false ); } void KMSearchPatternEdit::slotRadioClicked(int aIdx) { if ( mPattern ) mPattern->setOp( (KMSearchPattern::Operator)aIdx ); } void KMSearchPatternEdit::slotAutoNameHack() { mRuleLister->regenerateRuleListFromWidgets(); emit maybeNameChanged(); } #include "kmsearchpatternedit.moc"