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 <klocale.h>
00024 #include <kglobal.h>
00025 #include <qpopupmenu.h>
00026 #include <qpushbutton.h>
00027 #include <qtextedit.h>
00028 #include <qlineedit.h>
00029 #include <qtoolbox.h>
00030 #include <kdebug.h>
00031 #include <qfont.h>
00032 #include <kiconloader.h>
00033 #include <kpushbutton.h>
00034 #include <klistview.h>
00035 #include <klineedit.h>
00036 #include <qcombobox.h>
00037 #include <kshortcut.h>
00038 #include <kmessagebox.h>
00039 #include <kkeybutton.h>
00040 #include <kactivelabel.h>
00041 
00042 #include "customtemplates_base.h"
00043 #include "customtemplates_kfg.h"
00044 #include "globalsettings.h"
00045 #include "kmkernel.h"
00046 #include "kmmainwidget.h"
00047 
00048 #include "customtemplates.h"
00049 
00050 CustomTemplates::CustomTemplates( QWidget *parent, const char *name )
00051   :CustomTemplatesBase( parent, name ), mCurrentItem( 0 )
00052 {
00053   QFont f = KGlobalSettings::fixedFont();
00054   mEdit->setFont( f );
00055 
00056   mAdd->setIconSet( BarIconSet( "add", KIcon::SizeSmall ) );
00057   mRemove->setIconSet( BarIconSet( "remove", KIcon::SizeSmall ) );
00058 
00059   mList->setColumnWidth( 0, 50 );
00060   mList->setColumnWidth( 1, 100 );
00061 
00062   mEditFrame->setEnabled( false );
00063 
00064   connect( mName, SIGNAL( textChanged ( const QString &) ),
00065            this, SLOT( slotNameChanged( const QString & ) ) );
00066   connect( mEdit, SIGNAL( textChanged() ),
00067            this, SLOT( slotTextChanged( void ) ) );
00068 
00069   connect( mInsertCommand, SIGNAL( insertCommand(QString, int) ),
00070            this, SLOT( slotInsertCommand(QString, int) ) );
00071 
00072   connect( mAdd, SIGNAL( clicked() ),
00073            this, SLOT( slotAddClicked() ) );
00074   connect( mRemove, SIGNAL( clicked() ),
00075            this, SLOT( slotRemoveClicked() ) );
00076   connect( mList, SIGNAL( selectionChanged() ),
00077            this, SLOT( slotListSelectionChanged() ) );
00078   connect( mType, SIGNAL( activated( int ) ),
00079            this, SLOT( slotTypeActivated( int ) ) );
00080 
00081   connect( mKeyButton, SIGNAL( capturedShortcut( const KShortcut& ) ),
00082            this, SLOT( slotShortcutCaptured( const KShortcut& ) ) );
00083 
00084   mReplyPix = KIconLoader().loadIcon( "mail_reply", KIcon::Small );
00085   mReplyAllPix = KIconLoader().loadIcon( "mail_replyall", KIcon::Small );
00086   mForwardPix = KIconLoader().loadIcon( "mail_forward", KIcon::Small );
00087 
00088   mType->clear();
00089   mType->insertItem( QPixmap(), i18n( "Message->", "Universal" ), TUniversal );
00090   mType->insertItem( mReplyPix, i18n( "Message->", "Reply" ), TReply );
00091   mType->insertItem( mReplyAllPix, i18n( "Message->", "Reply to All" ), TReplyAll );
00092   mType->insertItem( mForwardPix, i18n( "Message->", "Forward" ), TForward );
00093 
00094   QString help =
00095       i18n( "<qt>"
00096             "<p>Here you can add, edit, and delete custom message "
00097             "templates to use when you compose a reply or forwarding message. "
00098             "Create the custom template by selecting it using the right mouse "
00099             " button menu or toolbar menu. Also, you can bind a keyboard "
00100             "combination to the template for faster operations.</p>"
00101             "<p>Message templates support substitution commands "
00102             "by simple typing them or selecting them from menu "
00103             "<i>Insert command</i>.</p>"
00104             "<p>There are four types of custom templates: used to "
00105             "<i>Reply</i>, <i>Reply to All</i>, <i>Forward</i>, and "
00106             "<i>Universal</i> which can be used for all kind of operations. "
00107             "You cannot bind keyboard shortcut to <i>Universal</i> templates.</p>"
00108             "</qt>" );
00109   mHelp->setText( i18n( "<a href=\"whatsthis:%1\">How does this work?</a>" ).arg( help ) );
00110   slotNameChanged( mName->text() );
00111 }
00112 
00113 CustomTemplates::~CustomTemplates()
00114 {
00115   QDictIterator<CustomTemplateItem> it(mItemList);
00116   for ( ; it.current() ; ++it ) {
00117     CustomTemplateItem *vitem = mItemList.take( it.currentKey() );
00118     if ( vitem ) {
00119       delete vitem;
00120     }
00121   }
00122 }
00123 
00124 void CustomTemplates::slotNameChanged( const QString& text )
00125 {
00126   mAdd->setEnabled( !text.isEmpty() );
00127 }
00128 
00129 QString CustomTemplates::indexToType( int index )
00130 {
00131   QString typeStr;
00132   switch ( index ) {
00133   case TUniversal:
00134     // typeStr = i18n( "Any" ); break;
00135     break;
00136 /*  case TNewMessage:
00137     typeStr = i18n( "New Message" ); break;*/
00138   case TReply:
00139     typeStr = i18n( "Message->", "Reply" ); break;
00140   case TReplyAll:
00141     typeStr = i18n( "Message->", "Reply to All" ); break;
00142   case TForward:
00143     typeStr = i18n( "Message->", "Forward" ); break;
00144   default:
00145     typeStr = i18n( "Message->", "Unknown" ); break;
00146   }
00147   return typeStr;
00148 }
00149 
00150 void CustomTemplates::slotTextChanged()
00151 {
00152   emit changed();
00153 }
00154 
00155 void CustomTemplates::load()
00156 {
00157   QStringList list = GlobalSettings::self()->customTemplates();
00158   for ( QStringList::iterator it = list.begin(); it != list.end(); ++it ) {
00159     CTemplates t(*it);
00160     // QString typeStr = indexToType( t.type() );
00161     QString typeStr;
00162     KShortcut shortcut( t.shortcut() );
00163     CustomTemplateItem *vitem =
00164       new CustomTemplateItem( *it, t.content(),
00165         shortcut,
00166         static_cast<Type>( t.type() ) );
00167     mItemList.insert( *it, vitem );
00168     QListViewItem *item = new QListViewItem( mList, typeStr, *it, t.content() );
00169     switch ( t.type() ) {
00170     case TReply:
00171       item->setPixmap( 0, mReplyPix );
00172       break;
00173     case TReplyAll:
00174       item->setPixmap( 0, mReplyAllPix );
00175       break;
00176     case TForward:
00177       item->setPixmap( 0, mForwardPix );
00178       break;
00179     default:
00180       item->setPixmap( 0, QPixmap() );
00181       item->setText( 0, indexToType( t.type() ) );
00182       break;
00183     };
00184   }
00185 }
00186 
00187 void CustomTemplates::save()
00188 {
00189   if ( mCurrentItem ) {
00190     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00191     if ( vitem ) {
00192       vitem->mContent = mEdit->text();
00193       vitem->mShortcut = mKeyButton->shortcut();
00194     }
00195   }
00196   QStringList list;
00197   QListViewItemIterator lit( mList );
00198   while ( lit.current() ) {
00199     list.append( (*lit)->text( 1 ) );
00200     ++lit;
00201   }
00202   QDictIterator<CustomTemplateItem> it( mItemList );
00203   for ( ; it.current() ; ++it ) {
00204     // list.append( (*it)->mName );
00205     CTemplates t( (*it)->mName );
00206     QString &content = (*it)->mContent;
00207     if ( content.stripWhiteSpace().isEmpty() ) {
00208       content = "%BLANK";
00209     }
00210     t.setContent( content );
00211     t.setShortcut( (*it)->mShortcut.toString() );
00212     t.setType( (*it)->mType );
00213     t.writeConfig();
00214   }
00215   GlobalSettings::self()->setCustomTemplates( list );
00216   GlobalSettings::self()->writeConfig();
00217 
00218   // update kmail menus related to custom templates
00219   if ( kmkernel->getKMMainWidget() )
00220     kmkernel->getKMMainWidget()->updateCustomTemplateMenus();
00221 }
00222 
00223 void CustomTemplates::slotInsertCommand( QString cmd, int adjustCursor )
00224 {
00225   int para, index;
00226   mEdit->getCursorPosition( &para, &index );
00227   mEdit->insertAt( cmd, para, index );
00228 
00229   index += adjustCursor;
00230 
00231   mEdit->setCursorPosition( para, index + cmd.length() );
00232 }
00233 
00234 void CustomTemplates::slotAddClicked()
00235 {
00236   QString str = mName->text();
00237   if ( !str.isEmpty() ) {
00238     CustomTemplateItem *vitem = mItemList[ str ];
00239     if ( !vitem ) {
00240       vitem = new CustomTemplateItem( str, "", KShortcut::null(), TUniversal );
00241       mItemList.insert( str, vitem );
00242       QListViewItem *item =
00243         new QListViewItem( mList, indexToType( TUniversal ), str, "" );
00244       mList->setSelected( item, true );
00245       mKeyButton->setEnabled( false );
00246       emit changed();
00247     }
00248   }
00249 }
00250 
00251 void CustomTemplates::slotRemoveClicked()
00252 {
00253   if ( mCurrentItem ) {
00254     CustomTemplateItem *vitem = mItemList.take( mCurrentItem->text( 1 ) );
00255     if ( vitem ) {
00256       delete vitem;
00257     }
00258     delete mCurrentItem;
00259     mCurrentItem = 0;
00260     emit changed();
00261   }
00262 }
00263 
00264 void CustomTemplates::slotListSelectionChanged()
00265 {
00266   if ( mCurrentItem ) {
00267     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00268     if ( vitem ) {
00269       vitem->mContent = mEdit->text();
00270       vitem->mShortcut = mKeyButton->shortcut();
00271     }
00272   }
00273   QListViewItem *item = mList->selectedItem();
00274   if ( item ) {
00275     mEditFrame->setEnabled( true );
00276     mCurrentItem = item;
00277     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00278     if ( vitem ) {
00279       // avoid emit changed()
00280       disconnect( mEdit, SIGNAL( textChanged() ),
00281                   this, SLOT( slotTextChanged( void ) ) );
00282 
00283       mEdit->setText( vitem->mContent );
00284       mKeyButton->setShortcut( vitem->mShortcut, false );
00285       mType->setCurrentItem( vitem->mType );
00286 
00287       connect( mEdit, SIGNAL( textChanged() ),
00288               this, SLOT( slotTextChanged( void ) ) );
00289 
00290       if ( vitem->mType == TUniversal )
00291       {
00292         mKeyButton->setEnabled( false );
00293       } else {
00294         mKeyButton->setEnabled( true );
00295       }
00296     }
00297   } else {
00298     mEditFrame->setEnabled( false );
00299     mCurrentItem = 0;
00300     mEdit->clear();
00301     mKeyButton->setShortcut( KShortcut::null(), false );
00302     mType->setCurrentItem( 0 );
00303   }
00304 }
00305 
00306 void CustomTemplates::slotTypeActivated( int index )
00307 {
00308   if ( mCurrentItem ) {
00309     // mCurrentItem->setText( 0, indexToType( index ) );
00310     CustomTemplateItem *vitem = mItemList[ mCurrentItem->text( 1 ) ];
00311     if ( !vitem ) {
00312       return;
00313     }
00314     vitem->mType = static_cast<Type>(index);
00315     switch ( vitem->mType ) {
00316     case TReply:
00317       mCurrentItem->setPixmap( 0, mReplyPix );
00318       break;
00319     case TReplyAll:
00320       mCurrentItem->setPixmap( 0, mReplyAllPix );
00321       break;
00322     case TForward:
00323       mCurrentItem->setPixmap( 0, mForwardPix );
00324       break;
00325     default:
00326       mCurrentItem->setPixmap( 0, QPixmap() );
00327       break;
00328     };
00329     if ( index == TUniversal )
00330     {
00331       mKeyButton->setEnabled( false );
00332     } else {
00333       mKeyButton->setEnabled( true );
00334     }
00335     emit changed();
00336   }
00337 }
00338 
00339 void CustomTemplates::slotShortcutCaptured( const KShortcut &shortcut )
00340 {
00341   KShortcut sc( shortcut );
00342   if ( sc == mKeyButton->shortcut() )
00343     return;
00344   if ( sc.isNull() || sc.toString().isEmpty() )
00345     sc.clear();
00346   bool assign = true;
00347   bool customused = false;
00348   // check if shortcut is already used for custom templates
00349   QDictIterator<CustomTemplateItem> it(mItemList);
00350   for ( ; it.current() ; ++it ) {
00351     if ( !mCurrentItem || (*it)->mName != mCurrentItem->text( 1 ) )
00352     {
00353       if ( (*it)->mShortcut == sc )
00354       {
00355         QString title( I18N_NOOP("Key Conflict") );
00356         QString msg( I18N_NOOP("The selected shortcut is already used "
00357               "for another custom template, "
00358               "would you still like to continue with the assignment?" ) );
00359         assign = ( KMessageBox::warningYesNo( this, msg, title )
00360                     == KMessageBox::Yes );
00361         if ( assign )
00362         {
00363           (*it)->mShortcut = KShortcut::null();
00364         }
00365         customused = true;
00366       }
00367     }
00368   }
00369   // check if shortcut is used somewhere else
00370   if ( !customused && !sc.isNull() &&
00371        !( kmkernel->getKMMainWidget()->shortcutIsValid( sc ) ) ) {
00372     QString title( I18N_NOOP("Key Conflict") );
00373     QString msg( I18N_NOOP("The selected shortcut is already used, "
00374           "would you still like to continue with the assignment?" ) );
00375     assign = ( KMessageBox::warningYesNo( this, msg, title )
00376                 == KMessageBox::Yes );
00377   }
00378   if ( assign ) {
00379     mKeyButton->setShortcut( sc, false );
00380     emit changed();
00381   }
00382 }
00383 
00384 #include "customtemplates.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys