1
/* -*- mode: C++; c-file-style: "gnu" -*-
2
kmsearchpatternedit.cpp
3
Author: Marc Mutz <Marc@Mutz.com>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License along
16
with this program; if not, write to the Free Software Foundation, Inc.,
17
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
#include "kmsearchpatternedit.h"
22
#include <QStackedWidget>
23
#include "kmsearchpattern.h"
24
#include "rulewidgethandlermanager.h"
25
using KMail::RuleWidgetHandlerManager;
27
#include <kcombobox.h>
32
#include <QButtonGroup>
34
#include <QHBoxLayout>
35
#include <QRadioButton>
39
// Definition of special rule field strings
40
// Note: Also see KMSearchRule::matches() and ruleFieldToEnglish() if
41
// you change the following i18n-ized strings!
42
// Note: The index of the values in the following array has to correspond to
43
// the value of the entries in the enum in KMSearchRuleWidget.
46
#define I18N_NOOP(t) 0, t
48
#define I18N_NOOP2(c,t) c, t
51
const char *internalName;
53
const char *displayName;
55
QString getLocalizedDisplayName() const { return i18nc(context, displayName); };
57
} SpecialRuleFields[] = {
58
{ "<message>", I18N_NOOP( "Complete Message" ) },
59
{ "<body>", I18N_NOOP( "Body of Message" ) },
60
{ "<any header>", I18N_NOOP( "Anywhere in Headers" ) },
61
{ "<recipients>", I18N_NOOP( "All Recipients" ) },
62
{ "<size>", I18N_NOOP( "Size in Bytes" ) },
63
{ "<age in days>", I18N_NOOP( "Age in Days" ) },
64
{ "<status>", I18N_NOOP( "Message Status" ) },
65
{ "<tag>", I18N_NOOP( "Message Tag" ) },
66
{ "Subject", I18N_NOOP2( "Subject of an email.", "Subject" ) },
67
{ "From", I18N_NOOP( "From" ) },
68
{ "To", I18N_NOOP2( "Receiver of an email.", "To" ) },
69
{ "CC", I18N_NOOP( "CC" ) }
71
static const int SpecialRuleFieldsCount =
72
sizeof( SpecialRuleFields ) / sizeof( *SpecialRuleFields );
74
//=============================================================================
76
// class KMSearchRuleWidget
78
//=============================================================================
80
KMSearchRuleWidget::KMSearchRuleWidget( QWidget *parent, KMSearchRule *aRule,
87
mAbsoluteDates( absoluteDates )
89
initFieldList( headersOnly, absoluteDates );
98
void KMSearchRuleWidget::setHeadersOnly( bool headersOnly )
100
KMSearchRule* srule = rule();
101
QByteArray currentText = srule->field();
103
initFieldList( headersOnly, mAbsoluteDates );
106
mRuleField->addItems( mFilterFieldList );
107
mRuleField->setMaxCount( mRuleField->count() );
108
mRuleField->adjustSize();
110
if (( currentText != "<message>") &&
111
( currentText != "<body>"))
112
mRuleField->setItemText( 0, QString::fromAscii( currentText ) );
114
mRuleField->setItemText( 0, QString() );
117
void KMSearchRuleWidget::initWidget()
119
QHBoxLayout * hlay = new QHBoxLayout( this );
120
hlay->setSpacing( KDialog::spacingHint() );
121
hlay->setMargin( 0 );
123
// initialize the header field combo box
124
mRuleField = new KComboBox( this );
125
mRuleField->setObjectName( "mRuleField" );
126
mRuleField->setEditable( true );
127
mRuleField->addItems( mFilterFieldList );
128
// don't show sliders when popping up this menu
129
mRuleField->setMaxCount( mRuleField->count() );
130
mRuleField->adjustSize();
131
hlay->addWidget( mRuleField );
133
// initialize the function/value widget stack
134
mFunctionStack = new QStackedWidget( this );
135
//Don't expand the widget in vertical direction
136
mFunctionStack->setSizePolicy( QSizePolicy::Preferred,QSizePolicy::Fixed );
138
hlay->addWidget( mFunctionStack );
140
mValueStack = new QStackedWidget( this );
141
mValueStack->setSizePolicy( QSizePolicy::Preferred,QSizePolicy::Fixed );
142
hlay->addWidget( mValueStack );
143
hlay->setStretchFactor( mValueStack, 10 );
145
RuleWidgetHandlerManager::instance()->createWidgets( mFunctionStack,
149
// redirect focus to the header field combo box
150
setFocusProxy( mRuleField );
152
connect( mRuleField, SIGNAL( activated( const QString & ) ),
153
this, SLOT( slotRuleFieldChanged( const QString & ) ) );
154
connect( mRuleField, SIGNAL(editTextChanged( const QString & ) ),
155
this, SLOT( slotRuleFieldChanged( const QString & ) ) );
156
connect( mRuleField, SIGNAL(editTextChanged( const QString & ) ),
157
this, SIGNAL( fieldChanged( const QString & ) ) );
160
void KMSearchRuleWidget::setRule( KMSearchRule *aRule )
164
// kDebug() << "(" << aRule->asString() << ")";
166
//--------------set the field
167
int i = indexOfRuleField( aRule->field() );
169
mRuleField->blockSignals( true );
171
if ( i < 0 ) { // not found -> user defined field
172
mRuleField->setItemText( 0, QString::fromLatin1( aRule->field() ) );
174
} else { // found in the list of predefined fields
175
mRuleField->setItemText( 0, QString() );
178
mRuleField->setCurrentIndex( i );
179
mRuleField->blockSignals( false );
181
RuleWidgetHandlerManager::instance()->setRule( mFunctionStack, mValueStack,
185
KMSearchRule* KMSearchRuleWidget::rule() const {
186
const QByteArray ruleField = ruleFieldToEnglish( mRuleField->currentText() );
187
const KMSearchRule::Function function =
188
RuleWidgetHandlerManager::instance()->function( ruleField,
190
const QString value =
191
RuleWidgetHandlerManager::instance()->value( ruleField, mFunctionStack,
194
return KMSearchRule::createInstance( ruleField, function, value );
197
void KMSearchRuleWidget::reset()
199
mRuleField->blockSignals( true );
200
mRuleField->setItemText( 0, "" );
201
mRuleField->setCurrentIndex( 0 );
202
mRuleField->blockSignals( false );
204
RuleWidgetHandlerManager::instance()->reset( mFunctionStack, mValueStack );
207
void KMSearchRuleWidget::slotFunctionChanged()
209
const QByteArray ruleField = ruleFieldToEnglish( mRuleField->currentText() );
210
RuleWidgetHandlerManager::instance()->update( ruleField,
215
void KMSearchRuleWidget::slotValueChanged()
217
const QByteArray ruleField = ruleFieldToEnglish( mRuleField->currentText() );
218
const QString prettyValue =
219
RuleWidgetHandlerManager::instance()->prettyValue( ruleField,
222
emit contentsChanged( prettyValue );
225
QByteArray KMSearchRuleWidget::ruleFieldToEnglish( const QString & i18nVal )
227
for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) {
228
if ( i18nVal == SpecialRuleFields[i].getLocalizedDisplayName() )
229
return SpecialRuleFields[i].internalName;
231
return i18nVal.toLatin1();
234
int KMSearchRuleWidget::ruleFieldToId( const QString & i18nVal )
236
for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) {
237
if ( i18nVal == SpecialRuleFields[i].getLocalizedDisplayName() )
240
return -1; // no pseudo header
243
static QString displayNameFromInternalName( const QString & internal )
245
for ( int i = 0; i < SpecialRuleFieldsCount; ++i ) {
246
if ( internal == SpecialRuleFields[i].internalName )
247
return SpecialRuleFields[i].getLocalizedDisplayName();
249
return internal.toLatin1();
254
int KMSearchRuleWidget::indexOfRuleField( const QByteArray & aName ) const
256
if ( aName.isEmpty() )
259
QString i18n_aName = displayNameFromInternalName( aName );
261
for ( int i = 1; i < mRuleField->count(); ++i ) {
262
if ( mRuleField->itemText( i ) == i18n_aName )
269
void KMSearchRuleWidget::initFieldList( bool headersOnly, bool absoluteDates )
271
mFilterFieldList.clear();
272
mFilterFieldList.append(""); // empty entry for user input
274
mFilterFieldList.append( SpecialRuleFields[Message].getLocalizedDisplayName() );
275
mFilterFieldList.append( SpecialRuleFields[Body].getLocalizedDisplayName() );
277
mFilterFieldList.append( SpecialRuleFields[AnyHeader].getLocalizedDisplayName() );
278
mFilterFieldList.append( SpecialRuleFields[Recipients].getLocalizedDisplayName() );
279
mFilterFieldList.append( SpecialRuleFields[Size].getLocalizedDisplayName() );
280
if ( !absoluteDates )
281
mFilterFieldList.append( SpecialRuleFields[AgeInDays].getLocalizedDisplayName() );
282
mFilterFieldList.append( SpecialRuleFields[Subject].getLocalizedDisplayName() );
283
mFilterFieldList.append( SpecialRuleFields[From].getLocalizedDisplayName() );
284
mFilterFieldList.append( SpecialRuleFields[To].getLocalizedDisplayName() );
285
mFilterFieldList.append( SpecialRuleFields[CC].getLocalizedDisplayName() );
286
mFilterFieldList.append( SpecialRuleFields[Status].getLocalizedDisplayName() );
287
mFilterFieldList.append( SpecialRuleFields[Tag].getLocalizedDisplayName() );
289
// these others only represent message headers and you can add to
291
mFilterFieldList.append("Reply-To");
292
mFilterFieldList.append("List-Id");
293
mFilterFieldList.append("Organization");
294
mFilterFieldList.append("Resent-From");
295
mFilterFieldList.append("X-Loop");
296
mFilterFieldList.append("X-Mailing-List");
297
mFilterFieldList.append("X-Spam-Flag");
300
void KMSearchRuleWidget::slotRuleFieldChanged( const QString & field )
302
RuleWidgetHandlerManager::instance()->update( ruleFieldToEnglish( field ),
307
//=============================================================================
309
// class KMFilterActionWidgetLister (the filter action editor)
311
//=============================================================================
313
KMSearchRuleWidgetLister::KMSearchRuleWidgetLister( QWidget *parent, const char* name, bool headersOnly, bool absoluteDates )
314
: KWidgetLister( 2, FILTER_MAX_RULES, parent, name )
317
mHeadersOnly = headersOnly;
318
mAbsoluteDates = absoluteDates;
321
KMSearchRuleWidgetLister::~KMSearchRuleWidgetLister()
325
void KMSearchRuleWidgetLister::setRuleList( QList<KMSearchRule*> *aList )
329
if ( mRuleList && mRuleList != aList )
330
regenerateRuleListFromWidgets();
334
if ( !mWidgetList.isEmpty() ) // move this below next 'if'?
335
mWidgetList.first()->blockSignals(true);
337
if ( aList->count() == 0 ) {
339
mWidgetList.first()->blockSignals(false);
343
int superfluousItems = (int)mRuleList->count() - mMaxWidgets ;
344
if ( superfluousItems > 0 ) {
345
kDebug() << "Clipping rule list to" << mMaxWidgets << "items!";
347
for ( ; superfluousItems ; superfluousItems-- )
348
mRuleList->removeLast();
351
// HACK to workaround regression in Qt 3.1.3 and Qt 3.2.0 (fixes bug #63537)
352
setNumberOfShownWidgetsTo( qMax((int)mRuleList->count(),mMinWidgets)+1 );
353
// set the right number of widgets
354
setNumberOfShownWidgetsTo( qMax((int)mRuleList->count(),mMinWidgets) );
356
// load the actions into the widgets
357
QList<KMSearchRule*>::const_iterator rIt;
358
QList<QWidget*>::const_iterator wIt = mWidgetList.constBegin();
359
for ( rIt = mRuleList->constBegin();
360
rIt != mRuleList->constEnd() && wIt != mWidgetList.constEnd(); ++rIt, ++wIt ) {
361
static_cast<KMSearchRuleWidget*>( *wIt )->setRule( (*rIt) );
363
for ( ; wIt != mWidgetList.constEnd() ; ++wIt )
364
static_cast<KMSearchRuleWidget*>( *wIt )->reset();
366
assert( !mWidgetList.isEmpty() );
367
mWidgetList.first()->blockSignals(false);
370
void KMSearchRuleWidgetLister::setHeadersOnly( bool headersOnly )
372
foreach ( QWidget *w, mWidgetList ) {
373
static_cast<KMSearchRuleWidget*>( w )->setHeadersOnly( headersOnly );
377
void KMSearchRuleWidgetLister::reset()
380
regenerateRuleListFromWidgets();
386
QWidget* KMSearchRuleWidgetLister::createWidget( QWidget *parent )
388
return new KMSearchRuleWidget(parent, 0, mHeadersOnly, mAbsoluteDates);
391
void KMSearchRuleWidgetLister::clearWidget( QWidget *aWidget )
394
((KMSearchRuleWidget*)aWidget)->reset();
397
void KMSearchRuleWidgetLister::regenerateRuleListFromWidgets()
399
if ( !mRuleList ) return;
403
foreach ( const QWidget *w, mWidgetList ) {
404
KMSearchRule *r = static_cast<const KMSearchRuleWidget*>( w )->rule();
406
mRuleList->append( r );
413
//=============================================================================
415
// class KMSearchPatternEdit
417
//=============================================================================
419
KMSearchPatternEdit::KMSearchPatternEdit( QWidget *parent, bool headersOnly,
421
: QGroupBox( parent )
423
setObjectName( "KMSearchPatternEdit" );
424
setTitle( i18n("Search Criteria") );
425
initLayout( headersOnly, absoluteDates );
428
KMSearchPatternEdit::KMSearchPatternEdit( const QString &title, QWidget *parent,
429
bool headersOnly, bool absoluteDates )
430
: QGroupBox( title, parent )
432
setObjectName( "KMSearchPatternEdit" );
433
initLayout( headersOnly, absoluteDates );
436
KMSearchPatternEdit::~KMSearchPatternEdit()
440
void KMSearchPatternEdit::initLayout(bool headersOnly, bool absoluteDates)
442
QVBoxLayout *layout = new QVBoxLayout( this );
444
//------------the radio buttons
445
mAllRBtn = new QRadioButton( i18n("Match a&ll of the following"), this );
446
mAnyRBtn = new QRadioButton( i18n("Match an&y of the following"), this );
448
mAllRBtn->setObjectName( "mAllRBtn" );
449
mAllRBtn->setChecked(true);
450
mAnyRBtn->setObjectName( "mAnyRBtn" );
451
mAnyRBtn->setChecked(false);
453
layout->addWidget( mAllRBtn );
454
layout->addWidget( mAnyRBtn );
456
QButtonGroup *bg = new QButtonGroup( this );
457
bg->addButton( mAllRBtn );
458
bg->addButton( mAnyRBtn );
460
//------------connect a few signals
461
connect( bg, SIGNAL(buttonClicked(QAbstractButton *)),
462
this, SLOT(slotRadioClicked(QAbstractButton *)) );
464
//------------the list of KMSearchRuleWidget's
465
mRuleLister = new KMSearchRuleWidgetLister( this, "swl", headersOnly, absoluteDates );
466
mRuleLister->slotClear();
468
if ( !mRuleLister->mWidgetList.isEmpty() ) {
469
KMSearchRuleWidget *srw = static_cast<KMSearchRuleWidget*>( mRuleLister->mWidgetList.first() );
470
connect( srw, SIGNAL(fieldChanged(const QString &)),
471
this, SLOT(slotAutoNameHack()) );
472
connect( srw, SIGNAL(contentsChanged(const QString &)),
473
this, SLOT(slotAutoNameHack()) );
475
kDebug() << "No first KMSearchRuleWidget, though slotClear() has been called!";
477
layout->addWidget( mRuleLister );
480
void KMSearchPatternEdit::setSearchPattern( KMSearchPattern *aPattern )
484
mRuleLister->setRuleList( aPattern );
489
if ( mPattern->op() == KMSearchPattern::OpOr )
490
mAnyRBtn->setChecked(true);
492
mAllRBtn->setChecked(true);
498
void KMSearchPatternEdit::setHeadersOnly( bool headersOnly )
500
mRuleLister->setHeadersOnly( headersOnly );
503
void KMSearchPatternEdit::reset()
505
mRuleLister->reset();
508
mAllRBtn->setChecked( true );
514
void KMSearchPatternEdit::slotRadioClicked(QAbstractButton *aRBtn)
517
if ( aRBtn == mAllRBtn )
518
mPattern->setOp( KMSearchPattern::OpAnd );
520
mPattern->setOp( KMSearchPattern::OpOr );
524
void KMSearchPatternEdit::slotAutoNameHack()
526
mRuleLister->regenerateRuleListFromWidgets();
527
emit maybeNameChanged();
530
#include "kmsearchpatternedit.moc"