diff --git a/kmfilteraction.cpp b/kmfilteraction.cpp index 0ebb1c6a8..0f3aec0a1 100644 --- a/kmfilteraction.cpp +++ b/kmfilteraction.cpp @@ -44,6 +44,9 @@ using KMail::RegExpLineEdit; #include #include #include +#include +#include +#include #ifdef Nepomuk_FOUND #include #endif @@ -2103,6 +2106,275 @@ const QString KMFilterActionWithUrl::displayString() const return label() + " \"" + Qt::escape( argsAsString() ) + "\""; } +//============================================================================= +// KMFilterActionAddToAddressBook +// - add email address from header to address book +//============================================================================= +class KMFilterActionAddToAddressBook: public KMFilterActionWithStringList +{ +public: + KMFilterActionAddToAddressBook(); + virtual ReturnCode process( KMMessage* msg ) const; + static KMFilterAction* newAction(); + + virtual bool isEmpty() const { return false; } + + virtual QWidget* createParamWidget( QWidget* parent ) const; + virtual void setParamWidgetValue( QWidget* paramWidget ) const; + virtual void applyParamWidgetValue( QWidget* paramWidget ); + virtual void clearParamWidget( QWidget* paramWidget ) const; + + virtual const QString argsAsString() const; + virtual void argsFromString( const QString &argsStr ); + +private: + void updateResourceMaps(); + QString mCategory, mResourceName; + QMap mResourceByName, mResourceByID; + const QString mStdResourceStr, mFromStr, mToStr, mCCStr, mBCCStr; +}; + +KMFilterAction* KMFilterActionAddToAddressBook::newAction() +{ + return ( new KMFilterActionAddToAddressBook ); +} + +KMFilterActionAddToAddressBook::KMFilterActionAddToAddressBook() + : KMFilterActionWithStringList( "add to address book", i18n( "Add to Address Book" ) ), + mStdResourceStr( i18n( "Default" ) ), mFromStr( i18nc( "Email sender", "From" ) ), + mToStr( i18nc( "Email recipient", "To" ) ), mCCStr( i18n( "CC" ) ), mBCCStr( i18n( "BCC" ) ) +{ + mParameterList.append( mFromStr ); + mParameterList.append( mToStr ); + mParameterList.append( mCCStr ); + mParameterList.append( mBCCStr ); + + mParameter = mParameterList.at( 0 ); + + updateResourceMaps(); + mResourceName = mStdResourceStr; + mCategory = i18n( "KMail Filter" ); +} + +void KMFilterActionAddToAddressBook::updateResourceMaps() +{ + //find resources in standard addressbook + //and prepare lookups + mResourceByID.clear(); + mResourceByName.clear(); + + const QList list = KABC::StdAddressBook::self()->resources(); + foreach( KABC::Resource* const res, list ) { + if ( !res->readOnly() && res->isOpen() ) { + mResourceByID.insert( res->identifier(), res ); + mResourceByName.insert( res->resourceName(), res ); + } + } +} + +KMFilterAction::ReturnCode KMFilterActionAddToAddressBook::process( KMMessage* msg ) const +{ + QString headerLine; + if ( mParameter == mFromStr ) + headerLine = msg->from(); + else if ( mParameter == mToStr ) + headerLine = msg->to(); + else if ( mParameter == mCCStr ) + headerLine = msg->cc(); + else if ( mParameter == mBCCStr ) + headerLine = msg->bcc(); + + const QStringList emails = KPIMUtils::splitAddressList( headerLine ); + + KABC::AddressBook *ab = KABC::StdAddressBook::self(); + // force a reload of the address book file so that changes that were made + // by other programs are loaded + ab->load(); + + QString email; + QString name; + + QMap::const_iterator it = mResourceByName.find( mResourceName ); + KABC::Resource* res = 0; + //if it==end(), then the resouce has been removed from addressbook + //or default has been selected, in either case store in default resource + if ( it != mResourceByName.end() ) + res = it.value(); + + KABC::Ticket *ticket = ab->requestSaveTicket( res ); + + if ( ticket ) { + foreach ( const QString singleEmail, emails ) { + KABC::Addressee::parseEmailAddress( singleEmail, name, email ); + KABC::Addressee::List addressees = ab->findByEmail( email ); + + if ( addressees.isEmpty() ) { + KABC::Addressee a; + a.setNameFromString( name ); + a.insertEmail( email, true ); + if ( !mCategory.isEmpty() ) + a.insertCategory( mCategory ); + if ( res ) + a.setResource( res ); + + ab->insertAddressee( a ); + } + } + + if ( !ab->save( ticket ) ) { + ab->error( i18n( "Can't save new addresses to address book." ) ); + return ErrorButGoOn; + } + } else { + ab->error( i18n( "Can't save to address book. Address book is locked." ) ); + return ErrorButGoOn; + } + + return GoOn; +} + +QWidget* KMFilterActionAddToAddressBook::createParamWidget( QWidget* parent ) const +{ + QWidget *w = new QWidget( parent ); + QGridLayout *gridlayout = new QGridLayout ( w ); + + KComboBox *cb = new KComboBox( w ); + cb->setObjectName( "FilterTargetCombo" ); + cb->setInsertPolicy( QComboBox::InsertAtBottom ); + gridlayout->addWidget( cb, 0, 0, 2, 1, Qt::AlignVCenter ); + + QLabel *l = new QLabel( i18n( "with category" ), w ); + gridlayout->addWidget( l, 0, 1 ); + + KLineEdit *le = new KLineEdit( w ); + le->setObjectName( "ledit" ); + gridlayout->addWidget( le, 0, 2 ); + + l = new QLabel( i18n( "in addressbook" ), w ); + gridlayout->addWidget( l, 1, 1 ); + + KComboBox *cbAdressBook = new KComboBox( w ); + cbAdressBook->setObjectName( "AddressBookCombo" ); + cbAdressBook->setToolTip( i18n( "

This defines the preferred addressbook.
" + "If it is not accessible, the filter will fallback to the default addressbook.

" ) ); + cbAdressBook->setInsertPolicy( QComboBox::InsertAtBottom ); + gridlayout->addWidget( cbAdressBook, 1, 2 ); + + setParamWidgetValue( w ); + return w; +} + +void KMFilterActionAddToAddressBook::setParamWidgetValue( QWidget* paramWidget ) const +{ + KComboBox *cb = paramWidget->findChild( "FilterTargetCombo" ); + Q_ASSERT( cb ); + cb->clear(); + cb->addItems( mParameterList ); + int idx = mParameterList.indexOf( mParameter ); + if ( idx < 0 ) { + kDebug() << "unknown mParameter. strange???"; + cb->addItem( mParameter ); + cb->setCurrentIndex( cb->count() - 1 ); + } else { + cb->setCurrentIndex( idx ); + } + + KLineEdit *le = paramWidget->findChild( "ledit" ); + Q_ASSERT( le ); + le->setText( mCategory ); + + QStringList list = mResourceByName.keys(); + idx = list.indexOf( mResourceName ); + KComboBox *cbAdressBook = paramWidget->findChild( "AddressBookCombo" ); + Q_ASSERT( cbAdressBook ); + cbAdressBook->clear(); + cbAdressBook->addItem( mStdResourceStr ); + cbAdressBook->addItems( mResourceByName.keys() ); + if ( idx < 0 ) { + cbAdressBook->setCurrentIndex( 0 ); + } else { + cbAdressBook->setCurrentIndex( idx + 1 /*mStdResourceStr is not in keys() */ ); + } +} + +void KMFilterActionAddToAddressBook::applyParamWidgetValue( QWidget* paramWidget ) +{ + KComboBox *cb = paramWidget->findChild( "FilterTargetCombo" ); + Q_ASSERT( cb ); + mParameter = cb->currentText(); + + KLineEdit *le = paramWidget->findChild( "ledit" ); + Q_ASSERT( le ); + mCategory = le->text(); + + KComboBox *cbAdressBook = paramWidget->findChild( "AddressBookCombo" ); + Q_ASSERT( cbAdressBook ); + mResourceName = cbAdressBook->currentText(); +} + +void KMFilterActionAddToAddressBook::clearParamWidget( QWidget* paramWidget ) const +{ + KComboBox *cb = paramWidget->findChild( "FilterTargetCombo" ); + Q_ASSERT( cb ); + cb->setCurrentItem( 0 ); + KLineEdit *le = paramWidget->findChild( "ledit" ); + Q_ASSERT( le ); + le->setText( mCategory ); + KComboBox *cbAdressBook = paramWidget->findChild( "AddressBookCombo" ); + Q_ASSERT( cbAdressBook ); + cbAdressBook->setCurrentItem( 0 ); +} + +const QString KMFilterActionAddToAddressBook::argsAsString() const +{ + QString result; + + if ( mParameter == mFromStr ) + result = "From"; + else if ( mParameter == mToStr ) + result = "To"; + else if ( mParameter == mCCStr ) + result = "CC"; + else if ( mParameter == mBCCStr ) + result = "BCC"; + + result += '\t'; + + QMap::const_iterator it = mResourceByName.find( mResourceName ); + if ( it != mResourceByName.end() ) + result += it.value()->identifier(); + else + result += mStdResourceStr; + + result += '\t'; + + result += mCategory; + + return result; +} + +void KMFilterActionAddToAddressBook::argsFromString( const QString &argsStr ) +{ + updateResourceMaps(); + + QStringList l = argsStr.split( '\t', QString::KeepEmptyParts ); + mParameter = l[0]; + + if ( l.count() >= 2 ) { + QMap::iterator it = mResourceByID.find( l[1] ); + if ( it != mResourceByID.end() ) + mResourceName = it.value()->resourceName(); + else + mResourceName = mStdResourceStr; + } else { + mResourceName = mStdResourceStr; + } + + if ( l.count() < 3 ) + mCategory.clear(); + else + mCategory = l[2]; +} //============================================================================= // @@ -2133,6 +2405,7 @@ void KMFilterActionDict::init(void) insert( KMFilterActionAddHeader::newAction ); insert( KMFilterActionRewriteHeader::newAction ); insert( KMFilterActionExecSound::newAction ); + insert( KMFilterActionAddToAddressBook::newAction ); // Register custom filter actions below this line. } // The int in the QDict constructor (41) must be a prime diff --git a/kmfilterdlg.cpp b/kmfilterdlg.cpp index 19c1941a4..883cd708b 100644 --- a/kmfilterdlg.cpp +++ b/kmfilterdlg.cpp @@ -51,7 +51,6 @@ using KMail::FilterImporterExporter; #include #include #include -#include #include #include @@ -1148,11 +1147,13 @@ KMFilterActionWidget::KMFilterActionWidget( QWidget *parent, const char* name ) int i; - mComboBox = new KComboBox( this ); + QWidget *w = new QWidget( this ); + gl = new QGridLayout( w ); + gl->setContentsMargins( 0, 0, 0, 0 ); + mComboBox = new KComboBox( gl ); mComboBox->setEditable( false ); assert( mComboBox ); - mWidgetStack = new QStackedWidget(this); - assert( mWidgetStack ); + gl->addWidget( mComboBox, 1, 1 ); setSpacing( 4 ); @@ -1163,14 +1164,10 @@ KMFilterActionWidget::KMFilterActionWidget( QWidget *parent, const char* name ) KMFilterAction *a = (*it)->create(); // append to the list of actions: mActionList.append( a ); - // add parameter widget to widget stack: - mWidgetStack->insertWidget( i, a->createParamWidget( mWidgetStack ) ); // add (i18n-ized) name to combo box mComboBox->addItem( (*it)->label ); } // widget for the case where no action is selected. - mWidgetStack->insertWidget( i,new QLabel( i18n("Please select an action."), mWidgetStack ) ); - mWidgetStack->setCurrentIndex(i); mComboBox->addItem( " " ); mComboBox->setCurrentIndex(i); @@ -1189,8 +1186,26 @@ KMFilterActionWidget::KMFilterActionWidget( QWidget *parent, const char* name ) setFocusProxy( mComboBox ); // now connect the combo box and the widget stack - connect( mComboBox, SIGNAL(activated(int)), - mWidgetStack, SLOT(setCurrentIndex (int)) ); + connect( mComboBox, SIGNAL( activated( int ) ), + this, SLOT( slotFilterTypeChanged( int ) ) ); + + setFilterAction(); +} + +void KMFilterActionWidget::setFilterAction( QWidget* w ) +{ + if ( gl->itemAtPosition( 1, 2 ) ) + delete gl->itemAtPosition( 1, 2 )->widget(); + + if ( w ) + gl->addWidget( w, 1, 2/*, Qt::AlignTop*/ ); + else + gl->addWidget( new QLabel( i18n( "Please select an action." ), this ), 1, 2 ); +} + +void KMFilterActionWidget::slotFilterTypeChanged( int newIdx ) +{ + setFilterAction( newIdx < mActionList.count() ? mActionList.at( newIdx )->createParamWidget( this ) : 0 ); } KMFilterActionWidget::~KMFilterActionWidget() @@ -1206,23 +1221,25 @@ void KMFilterActionWidget::setAction( const KMFilterAction* aAction ) // find the index of typeOf(aAction) in mComboBox // and clear the other widgets on the way. - for ( int i = 0; i < count ; i++ ) + for ( int i = 0; i < count ; i++ ) { if ( aAction && mComboBox->itemText(i) == label ) { + setFilterAction( mActionList.at( i )->createParamWidget( this ) ); + //...set the parameter widget to the settings // of aAction... - aAction->setParamWidgetValue( mWidgetStack->widget(i) ); + aAction->setParamWidgetValue( gl->itemAtPosition( 1, 2 )->widget() ); //...and show the correct entry of // the combo box mComboBox->setCurrentIndex(i); // (mm) also raise the widget, but doesn't - mWidgetStack->setCurrentIndex(i); found = true; - } else // clear the parameter widget - mActionList.at(i)->clearParamWidget( mWidgetStack->widget(i) ); + } + } if ( found ) return; // not found, so set the empty widget + setFilterAction(); + mComboBox->setCurrentIndex( count ); // last item - mWidgetStack->setCurrentIndex( count) ; } KMFilterAction * KMFilterActionWidget::action() const @@ -1235,11 +1252,10 @@ KMFilterAction * KMFilterActionWidget::action() const KMFilterAction *fa = desc->create(); if ( fa ) { // ...and apply the setting of the parameter widget. - fa->applyParamWidgetValue( mWidgetStack->currentWidget() ); + fa->applyParamWidgetValue( gl->itemAtPosition( 1, 2 )->widget() ); return fa; } } - return 0; } diff --git a/kmfilterdlg.h b/kmfilterdlg.h index 2858a3946..254b25dcd 100644 --- a/kmfilterdlg.h +++ b/kmfilterdlg.h @@ -33,12 +33,12 @@ #include #include #include +#include class KMSearchPatternEdit; class QLabel; class QListWidget; class QPushButton; -class QStackedWidget; class QCheckBox; class QTreeWidget; class KComboBox; @@ -185,18 +185,14 @@ private: /** This widgets allows to edit a single KMFilterAction (in fact any derived class that is registered in KMFilterActionDict). It consists of a combo box which allows to - select the type of actions this widget should act upon and a - QWidgetStack, which holds the parameter widgets for the different - rule types. + select the type of actions this widget should act upon. You can load a KMFilterAction into this widget with setAction, and retrieve the result of user action with action. The widget will copy it's setting into the corresponding parameter widget. For that, it internally creates an instance of every KMFilterAction in KMFilterActionDict and asks each - one to create a parameter widget. The parameter widgets are put on - the widget stack and are raised when their corresponding action - type is selected in the combo box. + one to create a parameter widget. @short A widget to edit a single KMFilterAction. @author Marc Mutz @@ -221,22 +217,25 @@ public: /** Retrieve the action. This method is necessary because the type of actions can change during editing. Therefore the widget always creates a new action object from the data in the combo - box and the widget stack and returns that. */ + box and returns that. */ KMFilterAction *action() const; +private slots: + void slotFilterTypeChanged( int newIdx ); + private: /** This list holds an instance of every KMFilterAction subclass. The only reason that these 'slave' actions exist is - that they are 'forced' to create parameter widgets for the - widget stack and to clear them on setAction. */ + that they are 'forced' to create parameter widgets + and to clear them on setAction. */ QList mActionList; /** The combo box that contains the labels of all KMFilterActions. It's @p activated(int) signal is internally - connected to the @p raiseWidget(int) slot of @p mWidgetStack. */ + connected to the @p slotCboAction(int) slot of @p KMFilterActionWidget. */ KComboBox *mComboBox; - /** The widget stack that holds all the parameter widgets for the - filter actions. */ - QStackedWidget *mWidgetStack; + + void setFilterAction( QWidget* w=0 ); + QGridLayout *gl; }; class KMPopFilterActionWidget : public QGroupBox