kmail

customtemplates.cpp
00001 /*   -*- mode: C++; c-file-style: "gnu" -*-
00002  *   kmail: KDE mail client
00003  *   This file: Copyright (C) 2006 Dmitry Morozhnikov
00004  *
00005  *   This program is free software; you can redistribute it and/or modify
00006  *   it under the terms of the GNU General Public License as published by
00007  *   the Free Software Foundation; either version 2 of the License, or
00008  *   (at your option) any later version.
00009  *
00010  *   This program is distributed in the hope that it will be useful,
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *   GNU General Public License for more details.
00014  *
00015  *   You should have received a copy of the GNU General Public License
00016  *   along with this program; if not, write to the Free Software
00017  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018  *
00019  */
00020 
00021 #include <config.h>
00022 
00023 #include <tqpopupmenu.h>
00024 #include <tqpushbutton.h>
00025 #include <tqtextedit.h>
00026 #include <tqlabel.h>
00027 #include <tqlineedit.h>
00028 #include <tqtoolbox.h>
00029 #include <tqtooltip.h>
00030 #include <tqwhatsthis.h>
00031 #include <tqfont.h>
00032 
00033 #include <kdebug.h>
00034 #include <tdelocale.h>
00035 #include <tdeglobal.h>
00036 #include <kiconloader.h>
00037 #include <kpushbutton.h>
00038 #include <tdelistview.h>
00039 #include <klineedit.h>
00040 #include <tqcombobox.h>
00041 #include <tdeshortcut.h>
00042 #include <tdemessagebox.h>
00043 #include <kkeybutton.h>
00044 #include <kactivelabel.h>
00045 
00046 #include "customtemplates_base.h"
00047 #include "customtemplates_kfg.h"
00048 #include "globalsettings.h"
00049 #include "kmkernel.h"
00050 #include "kmmainwidget.h"
00051 #include "kmfawidgets.h"
00052 
00053 #include "customtemplates.h"
00054 
00055 CustomTemplates::CustomTemplates( TQWidget *parent, const char *name )
00056   :CustomTemplatesBase( parent, name ),
00057    mCurrentItem( 0 ),
00058    mBlockChangeSignal( false )
00059 {
00060   TQFont f = TDEGlobalSettings::fixedFont();
00061   mEdit->setFont( f );
00062 
00063   mAdd->setIconSet( BarIconSet( "add", TDEIcon::SizeSmall ) );
00064   mRemove->setIconSet( BarIconSet( "remove", TDEIcon::SizeSmall ) );
00065 
00066   mList->setColumnWidth( 0, 50 );
00067   mList->setColumnWidth( 1, 100 );
00068 
00069   mEditFrame->setEnabled( false );
00070 
00071   connect( mName, TQT_SIGNAL( textChanged ( const TQString &) ),
00072            this, TQT_SLOT( slotNameChanged( const TQString & ) ) );
00073   connect( mEdit, TQT_SIGNAL( textChanged() ),
00074            this, TQT_SLOT( slotTextChanged( void ) ) );
00075   connect( mToEdit, TQT_SIGNAL( textChanged(const TQString&) ),
00076            this, TQT_SLOT( slotTextChanged( void ) ) );
00077   connect( mCCEdit, TQT_SIGNAL( textChanged(const TQString&) ),
00078            this, TQT_SLOT( slotTextChanged( void ) ) );
00079 
00080   connect( mInsertCommand, TQT_SIGNAL( insertCommand(TQString, int) ),
00081            this, TQT_SLOT( slotInsertCommand(TQString, int) ) );
00082 
00083   connect( mAdd, TQT_SIGNAL( clicked() ),
00084            this, TQT_SLOT( slotAddClicked() ) );
00085   connect( mRemove, TQT_SIGNAL( clicked() ),
00086            this, TQT_SLOT( slotRemoveClicked() ) );
00087   connect( mList, TQT_SIGNAL( selectionChanged() ),
00088            this, TQT_SLOT( slotListSelectionChanged() ) );
00089   connect( mType, TQT_SIGNAL( activated( int ) ),
00090            this, TQT_SLOT( slotTypeActivated( int ) ) );
00091 
00092   connect( mKeyButton, TQT_SIGNAL( capturedShortcut( const TDEShortcut& ) ),
00093            this, TQT_SLOT( slotShortcutCaptured( const TDEShortcut& ) ) );
00094 
00095   mReplyPix = TDEIconLoader().loadIcon( "mail-reply-sender", TDEIcon::Small );
00096   mReplyAllPix = TDEIconLoader().loadIcon( "mail-reply-all", TDEIcon::Small );
00097   mForwardPix = TDEIconLoader().loadIcon( "mail-forward", TDEIcon::Small );
00098 
00099   mType->clear();
00100   mType->insertItem( TQPixmap(), i18n( "Message->", "Universal" ), TUniversal );
00101   mType->insertItem( mReplyPix, i18n( "Message->", "Reply" ), TReply );
00102   mType->insertItem( mReplyAllPix, i18n( "Message->", "Reply to All" ), TReplyAll );
00103   mType->insertItem( mForwardPix, i18n( "Message->", "Forward" ), TForward );
00104 
00105   TQString help =
00106       i18n( "<qt>"
00107             "<p>Here you can add, edit, and delete custom message "
00108             "templates to use when you compose a reply or forwarding message. "
00109             "Create the custom template by selecting it using the right mouse "
00110             " button menu or toolbar menu. Also, you can bind a keyboard "
00111             "combination to the template for faster operations.</p>"
00112             "<p>Message templates support substitution commands "
00113             "by simple typing them or selecting them from menu "
00114             "<i>Insert command</i>.</p>"
00115             "<p>There are four types of custom templates: used to "
00116             "<i>Reply</i>, <i>Reply to All</i>, <i>Forward</i>, and "
00117             "<i>Universal</i> which can be used for all kind of operations. "
00118             "You cannot bind keyboard shortcut to <i>Universal</i> templates.</p>"
00119             "</qt>" );
00120   mHelp->setText( i18n( "<a href=\"whatsthis:%1\">How does this work?</a>" ).arg( help ) );
00121 
00122   const TQString toToolTip = i18n( "Additional recipients of the message when forwarding" );
00123   const TQString ccToolTip = i18n( "Additional recipients who get a copy of the message when forwarding" );
00124   const TQString toWhatsThis = i18n( "When using this template for forwarding, the default recipients are those you enter here. This is a comma-separated list of mail addresses." );
00125   const TQString ccWhatsThis = i18n( "When using this template for forwarding, the recipients you enter here will by default get a copy of this message. This is a comma-separated list of mail addresses." );
00126 
00127   // We only want to set the tooltip/whatsthis to the lineedit, not the complete widget,
00128   // so we use the name here to find the lineedit. This is similar to what KMFilterActionForward
00129   // does.
00130   KLineEdit *ccLineEdit = dynamic_cast<KLineEdit*>( mCCEdit->child( "addressEdit" ) );
00131   KLineEdit *toLineEdit = dynamic_cast<KLineEdit*>( mToEdit->child( "addressEdit" ) );
00132   Q_ASSERT( ccLineEdit && toLineEdit );
00133 
00134   TQToolTip::add( mCCLabel, ccToolTip );
00135   TQToolTip::add( ccLineEdit, ccToolTip );
00136   TQToolTip::add( mToLabel, toToolTip );
00137   TQToolTip::add( toLineEdit, toToolTip );
00138   TQWhatsThis::add( mCCLabel, ccWhatsThis );
00139   TQWhatsThis::add( ccLineEdit, ccWhatsThis );
00140   TQWhatsThis::add( mToLabel, toWhatsThis );
00141   TQWhatsThis::add( toLineEdit, toWhatsThis );
00142 
00143   slotNameChanged( mName->text() );
00144 }
00145 
00146 CustomTemplates::~CustomTemplates()
00147 {
00148   TQDictIterator<CustomTemplateItem> it(mItemList);
00149   for ( ; it.current() ; ++it ) {
00150     CustomTemplateItem *vitem = mItemList.take( it.currentKey() );
00151     if ( vitem ) {
00152       delete vitem;
00153     }
00154   }
00155 }
00156 
00157 void CustomTemplates::setRecipientsEditsEnabled( bool enabled )
00158 {
00159   mToEdit->setHidden( !enabled );
00160   mCCEdit->setHidden( !enabled );
00161   mToLabel->setHidden( !enabled );
00162   mCCLabel->setHidden( !enabled );
00163 }
00164 
00165 void CustomTemplates::slotNameChanged( const TQString& text )
00166 {
00167   mAdd->setEnabled( !text.isEmpty() );
00168 }
00169 
00170 TQString CustomTemplates::indexToType( int index )
00171 {
00172   TQString typeStr;
00173   switch ( index ) {
00174   case TUniversal:
00175     // typeStr = i18n( "Any" ); break;
00176     break;
00177 /*  case TNewMessage:
00178     typeStr = i18n( "New Message" ); break;*/
00179   case TReply:
00180     typeStr = i18n( "Message->", "Reply" ); break;
00181   case TReplyAll:
00182     typeStr = i18n( "Message->", "Reply to All" ); break;
00183   case TForward:
00184     typeStr = i18n( "Message->", "Forward" ); break;
00185   default:
00186     typeStr = i18n( "Message->", "Unknown" ); break;
00187   }
00188   return typeStr;
00189 }
00190 
00191 void CustomTemplates::slotTextChanged()
00192 {
00193   if ( !mBlockChangeSignal )
00194     emit changed();
00195 }
00196 
00197 void CustomTemplates::load()
00198 {
00199   TQStringList list = GlobalSettings::self()->customTemplates();
00200   for ( TQStringList::iterator it = list.begin(); it != list.end(); ++it ) {
00201     CTemplates t(*it);
00202     // TQString typeStr = indexToType( t.type() );
00203     TQString typeStr;
00204     TDEShortcut shortcut( t.shortcut() );
00205     CustomTemplateItem *vitem =
00206       new CustomTemplateItem( *it, t.content(),
00207         shortcut,
00208         static_cast<Type>( t.type() ), t.to(), t.cC() );
00209     mItemList.insert( *it, vitem );
00210     TQListViewItem *item = new TQListViewItem( mList, typeStr, *it, t.content() );
00211     switch ( t.type() ) {
00212     case TReply:
00213       item->setPixmap( 0, mReplyPix );
00214       break;
00215     case TReplyAll:
00216       item->setPixmap( 0, mReplyAllPix );
00217       break;
00218     case TForward:
00219       item->setPixmap( 0, mForwardPix );
00220       break;
00221     default:
00222       item->setPixmap( 0, TQPixmap() );
00223       item->setText( 0, indexToType( t.type() ) );
00224       break;
00225     };
00226   }
00227 }
00228 
00229 void CustomTemplates::save()
00230 {
00231   // Before saving the new templates, delete the old ones. That needs to be done before
00232   // saving, since otherwise a new template with the new name wouldn't get saved.
00233   for ( TQStringList::const_iterator it = mItemsToDelete.constBegin();
00234         it != mItemsToDelete.constEnd(); ++it ) {
00235     CTemplates t( (*it) );
00236     const TQString configGroup = t.currentGroup();
00237     kmkernel->config()->deleteGroup( configGroup );
00238   }
00239 
00240   if ( mCurrentItem ) {
00241     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00242     if ( vitem ) {
00243       vitem->mContent = mEdit->text();
00244       vitem->mShortcut = mKeyButton->shortcut();
00245       vitem->mTo = mToEdit->text();
00246       vitem->mCC = mCCEdit->text();
00247     }
00248   }
00249   TQStringList list;
00250   TQListViewItemIterator lit( mList );
00251   while ( lit.current() ) {
00252     list.append( (*lit)->text( 1 ) );
00253     ++lit;
00254   }
00255   for ( TQDictIterator<CustomTemplateItem> it( mItemList ); it.current() ; ++it ) {
00256     // list.append( (*it)->mName );
00257     CTemplates t( (*it)->mName );
00258     TQString &content = (*it)->mContent;
00259     if ( content.stripWhiteSpace().isEmpty() ) {
00260       content = "%BLANK";
00261     }
00262     t.setContent( content );
00263     t.setShortcut( (*it)->mShortcut.toString() );
00264     t.setType( (*it)->mType );
00265     t.setTo( (*it)->mTo );
00266     t.setCC( (*it)->mCC );
00267     t.writeConfig();
00268   }
00269   GlobalSettings::self()->setCustomTemplates( list );
00270   GlobalSettings::self()->writeConfig();
00271 
00272   // update kmail menus related to custom templates
00273   if ( kmkernel->getKMMainWidget() )
00274     kmkernel->getKMMainWidget()->updateCustomTemplateMenus();
00275 }
00276 
00277 void CustomTemplates::slotInsertCommand( TQString cmd, int adjustCursor )
00278 {
00279   int para, index;
00280   mEdit->getCursorPosition( &para, &index );
00281   mEdit->insertAt( cmd, para, index );
00282 
00283   index += adjustCursor;
00284 
00285   mEdit->setCursorPosition( para, index + cmd.length() );
00286 }
00287 
00288 void CustomTemplates::slotAddClicked()
00289 {
00290   TQString str = mName->text();
00291   if ( !str.isEmpty() ) {
00292     CustomTemplateItem *vitem = mItemList[ str ];
00293     if ( !vitem ) {
00294       vitem = new CustomTemplateItem( str, "", TDEShortcut::null(), TUniversal,
00295                                       TQString(), TQString() );
00296       mItemList.insert( str, vitem );
00297       TQListViewItem *item =
00298         new TQListViewItem( mList, indexToType( TUniversal ), str, "" );
00299       mList->setSelected( item, true );
00300       mKeyButton->setEnabled( false );
00301       if ( !mBlockChangeSignal )
00302         emit changed();
00303     }
00304   }
00305 }
00306 
00307 void CustomTemplates::slotRemoveClicked()
00308 {
00309   if ( mCurrentItem ) {
00310     const TQString templateName = mCurrentItem->text( 1 );
00311     mItemsToDelete.append( templateName );
00312     CustomTemplateItem *vitem = mItemList.take( templateName );
00313     delete vitem;
00314     delete mCurrentItem;
00315     mCurrentItem = 0;
00316     if ( !mBlockChangeSignal )
00317       emit changed();
00318   }
00319 }
00320 
00321 void CustomTemplates::slotListSelectionChanged()
00322 {
00323   if ( mCurrentItem ) {
00324     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00325     if ( vitem ) {
00326       vitem->mContent = mEdit->text();
00327       vitem->mShortcut = mKeyButton->shortcut();
00328     }
00329   }
00330   TQListViewItem *item = mList->selectedItem();
00331   if ( item ) {
00332     mEditFrame->setEnabled( true );
00333     mCurrentItem = item;
00334     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00335     if ( vitem ) {
00336 
00337       mBlockChangeSignal = true;
00338       mEdit->setText( vitem->mContent );
00339       mKeyButton->setShortcut( vitem->mShortcut, false );
00340       mType->setCurrentItem( vitem->mType );
00341       mToEdit->setText( vitem->mTo );
00342       mCCEdit->setText( vitem->mCC );
00343       mBlockChangeSignal = false;
00344 
00345       if ( vitem->mType == TUniversal )
00346       {
00347         mKeyButton->setEnabled( false );
00348       } else {
00349         mKeyButton->setEnabled( true );
00350       }
00351       setRecipientsEditsEnabled( vitem->mType == TForward ||
00352                                  vitem->mType == TUniversal );
00353     }
00354   } else {
00355     mEditFrame->setEnabled( false );
00356     mCurrentItem = 0;
00357     mEdit->clear();
00358     mToEdit->clear();
00359     mCCEdit->clear();
00360     mKeyButton->setShortcut( TDEShortcut::null(), false );
00361     mType->setCurrentItem( 0 );
00362   }
00363 }
00364 
00365 void CustomTemplates::slotTypeActivated( int index )
00366 {
00367   if ( mCurrentItem ) {
00368     // mCurrentItem->setText( 0, indexToType( index ) );
00369     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00370     if ( !vitem ) {
00371       return;
00372     }
00373     vitem->mType = static_cast<Type>(index);
00374     switch ( vitem->mType ) {
00375     case TReply:
00376       mCurrentItem->setPixmap( 0, mReplyPix );
00377       break;
00378     case TReplyAll:
00379       mCurrentItem->setPixmap( 0, mReplyAllPix );
00380       break;
00381     case TForward:
00382       mCurrentItem->setPixmap( 0, mForwardPix );
00383       break;
00384     default:
00385       mCurrentItem->setPixmap( 0, TQPixmap() );
00386       break;
00387     };
00388     if ( index == TUniversal )
00389     {
00390       mKeyButton->setEnabled( false );
00391     } else {
00392       mKeyButton->setEnabled( true );
00393     }
00394 
00395     setRecipientsEditsEnabled( vitem->mType == TForward ||
00396                                vitem->mType == TUniversal );
00397     if ( !mBlockChangeSignal )
00398       emit changed();
00399   }
00400   else
00401     setRecipientsEditsEnabled( false );
00402 }
00403 
00404 void CustomTemplates::slotShortcutCaptured( const TDEShortcut &shortcut )
00405 {
00406   TDEShortcut sc( shortcut );
00407   if ( sc == mKeyButton->shortcut() )
00408     return;
00409   if ( sc.isNull() || sc.toString().isEmpty() )
00410     sc.clear();
00411   bool assign = true;
00412   bool customused = false;
00413   // check if shortcut is already used for custom templates
00414   TQDictIterator<CustomTemplateItem> it(mItemList);
00415   for ( ; it.current() ; ++it ) {
00416     if ( !mCurrentItem || (*it)->mName != mCurrentItem->text( 1 ) )
00417     {
00418       if ( (*it)->mShortcut == sc )
00419       {
00420         TQString title( I18N_NOOP("Key Conflict") );
00421         TQString msg( I18N_NOOP("The selected shortcut is already used "
00422               "for another custom template, "
00423               "would you still like to continue with the assignment?" ) );
00424         assign = ( KMessageBox::warningYesNo( this, msg, title )
00425                     == KMessageBox::Yes );
00426         if ( assign )
00427         {
00428           (*it)->mShortcut = TDEShortcut::null();
00429         }
00430         customused = true;
00431       }
00432     }
00433   }
00434   // check if shortcut is used somewhere else
00435   if ( !customused && !sc.isNull() &&
00436        !( kmkernel->getKMMainWidget()->shortcutIsValid( sc ) ) ) {
00437     TQString title( I18N_NOOP("Key Conflict") );
00438     TQString msg( I18N_NOOP("The selected shortcut is already used, "
00439           "would you still like to continue with the assignment?" ) );
00440     assign = ( KMessageBox::warningYesNo( this, msg, title )
00441                 == KMessageBox::Yes );
00442   }
00443   if ( assign ) {
00444     mKeyButton->setShortcut( sc, false );
00445     if ( !mBlockChangeSignal )
00446       emit changed();
00447   }
00448 }
00449 
00450 #include "customtemplates.moc"