You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
490 lines
15 KiB
490 lines
15 KiB
// -*- mode: C++; c-file-style: "gnu" -*-
|
|
// kmsearchpatternedit.cpp
|
|
// Author: Marc Mutz <Marc@Mutz.com>
|
|
// This code is under GPL
|
|
|
|
#include <config.h>
|
|
#include "kmsearchpatternedit.h"
|
|
|
|
#include "kmsearchpattern.h"
|
|
#include "rulewidgethandlermanager.h"
|
|
using KMail::RuleWidgetHandlerManager;
|
|
|
|
#include <klocale.h>
|
|
#include <kdialog.h>
|
|
#include <kdebug.h>
|
|
|
|
#include <tqradiobutton.h>
|
|
#include <tqcombobox.h>
|
|
#include <tqbuttongroup.h>
|
|
#include <tqwidgetstack.h>
|
|
#include <tqlayout.h>
|
|
|
|
#include <assert.h>
|
|
|
|
// 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[] = {
|
|
{ "<message>", I18N_NOOP( "Complete Message" ) },
|
|
{ "<body>", I18N_NOOP( "Body of Message" ) },
|
|
{ "<any header>", I18N_NOOP( "Anywhere in Headers" ) },
|
|
{ "<recipients>", I18N_NOOP( "All Recipients" ) },
|
|
{ "<size>", I18N_NOOP( "Size in Bytes" ) },
|
|
{ "<age in days>", I18N_NOOP( "Age in Days" ) },
|
|
{ "<status>", 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 != "<message>") &&
|
|
( currentText != "<body>"))
|
|
mRuleField->changeItem( TQString::fromAscii( currentText ), 0 );
|
|
else
|
|
mRuleField->changeItem( TQString::null, 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,
|
|
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::null, 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<KMSearchRule> *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 Qt 3.1.3 and Qt 3.2.0 (fixes bug #63537)
|
|
setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets)+1 );
|
|
// set the right number of widgets
|
|
setNumberOfShownWidgetsTo( QMAX((int)mRuleList->count(),mMinWidgets) );
|
|
|
|
// load the actions into the widgets
|
|
TQPtrListIterator<KMSearchRule> rIt( *mRuleList );
|
|
TQPtrListIterator<TQWidget> wIt( mWidgetList );
|
|
for ( rIt.toFirst(), wIt.toFirst() ;
|
|
rIt.current() && wIt.current() ; ++rIt, ++wIt ) {
|
|
static_cast<KMSearchRuleWidget*>(*wIt)->setRule( (*rIt) );
|
|
}
|
|
for ( ; wIt.current() ; ++wIt )
|
|
((KMSearchRuleWidget*)(*wIt))->reset();
|
|
|
|
assert( mWidgetList.first() );
|
|
mWidgetList.first()->blockSignals(false);
|
|
}
|
|
|
|
void KMSearchRuleWidgetLister::setHeadersOnly( bool headersOnly )
|
|
{
|
|
TQPtrListIterator<TQWidget> wIt( mWidgetList );
|
|
for ( wIt.toFirst() ; wIt.current() ; ++wIt ) {
|
|
(static_cast<KMSearchRuleWidget*>(*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<TQWidget> 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*/, 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*/, 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"
|