Better wording
[kdepim.git] / templateparser / customtemplates.cpp
blob7ce0cd17a7f41ac8983f8f6682f668fc3e9cc7a7
1 /*
2 * Copyright (C) 2006 Dmitry Morozhnikov <dmiceman@mail.ru>
3 * Copyright (C) 2011,2012 Laurent Montel <montel@kde.org>
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 "customtemplates.h"
21 #include "customtemplates_kfg.h"
22 #include "globalsettings_base.h"
23 #include "ui_customtemplates_base.h"
25 #include <KIconLoader>
26 #include <KLocale>
27 #include <KMessageBox>
29 #include <QWhatsThis>
31 using namespace TemplateParser;
33 CustomTemplates::CustomTemplates( const QList<KActionCollection*> &actionCollection,
34 QWidget *parent )
35 : QWidget( parent ),
36 mBlockChangeSignal( false )
38 mUi = new Ui_CustomTemplatesBase;
39 mUi->setupUi( this );
41 mUi->mAdd->setIcon( KIcon( "list-add" ) );
42 mUi->mAdd->setEnabled( false );
43 mUi->mRemove->setIcon( KIcon( "list-remove" ) );
44 mUi->mDuplicate->setIcon( KIcon( "edit-copy" ) );
46 mUi->mList->setColumnWidth( 0, 100 );
47 mUi->mList->header()->setStretchLastSection( true );
48 mUi->mList->setItemDelegate( new CustomTemplateItemDelegate( this ) );
49 mUi->mEditFrame->setEnabled( false );
51 mUi->mName->setTrapReturnKey( true );
52 connect( mUi->mEdit, SIGNAL(textChanged()),
53 this, SLOT(slotTextChanged()) );
54 connect( mUi->mToEdit, SIGNAL(textChanged()),
55 this, SLOT(slotTextChanged()) );
56 connect( mUi->mCCEdit, SIGNAL(textChanged()),
57 this, SLOT(slotTextChanged()) );
59 connect( mUi->mName, SIGNAL(textChanged(QString)),
60 this, SLOT(slotNameChanged(QString)) );
62 connect( mUi->mName, SIGNAL(returnPressed()),
63 this, SLOT(slotAddClicked()) );
65 connect( mUi->mInsertCommand, SIGNAL(insertCommand(QString,int)),
66 this, SLOT(slotInsertCommand(QString,int)) );
68 connect( mUi->mAdd, SIGNAL(clicked()),
69 this, SLOT(slotAddClicked()) );
70 connect( mUi->mRemove, SIGNAL(clicked()),
71 this, SLOT(slotRemoveClicked()) );
72 connect( mUi->mDuplicate, SIGNAL(clicked()),
73 this, SLOT(slotDuplicateClicked()) );
74 connect( mUi->mList, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
75 this, SLOT(slotListSelectionChanged()) );
76 connect( mUi->mList, SIGNAL(itemChanged(QTreeWidgetItem*,int)),
77 this, SLOT(slotItemChanged(QTreeWidgetItem*,int)) );
78 connect( mUi->mType, SIGNAL(activated(int)),
79 this, SLOT(slotTypeActivated(int)) );
81 connect( mUi->mKeySequenceWidget, SIGNAL(keySequenceChanged(QKeySequence)),
82 this, SLOT(slotShortcutChanged(QKeySequence)) );
84 mUi->mKeySequenceWidget->setCheckActionCollections( actionCollection );
86 mReplyPix = KIconLoader().loadIcon( "mail-reply-sender", KIconLoader::Small );
87 mReplyAllPix = KIconLoader().loadIcon( "mail-reply-all", KIconLoader::Small );
88 mForwardPix = KIconLoader().loadIcon( "mail-forward", KIconLoader::Small );
90 mUi->mType->clear();
91 mUi->mType->addItem( QPixmap(), i18nc( "Message->", "Universal" ) );
92 mUi->mType->addItem( mReplyPix, i18nc( "Message->", "Reply" ) );
93 mUi->mType->addItem( mReplyAllPix, i18nc( "Message->", "Reply to All" ) );
94 mUi->mType->addItem( mForwardPix, i18nc( "Message->", "Forward" ) );
96 mUi->mHelp->setText( i18n( "<a href=\"whatsthis\">How does this work?</a>" ) );
97 connect( mUi->mHelp, SIGNAL(linkActivated(QString)),
98 SLOT(slotHelpLinkClicked(QString)) );
100 slotNameChanged( mUi->mName->text() );
103 void CustomTemplates::slotHelpLinkClicked( const QString & )
105 const QString help =
106 i18n( "<qt>"
107 "<p>Here you can add, edit, and delete custom message "
108 "templates to use when you compose a reply or forwarding message. "
109 "Create the custom template by typing the name into the input box "
110 "and press the '+' button. Also, you can bind a keyboard "
111 "combination to the template for faster operations.</p>"
112 "<p>Message templates support substitution commands, "
113 "by simply typing them or selecting them from the "
114 "<i>Insert command</i> menu.</p>"
115 "<p>There are four types of custom templates: used to "
116 "<i>Reply</i>, <i>Reply to All</i>, <i>Forward</i>, and "
117 "<i>Universal</i> which can be used for all kinds of operations. "
118 "You cannot bind a keyboard shortcut to <i>Universal</i> templates.</p>"
119 "</qt>" );
121 QWhatsThis::showText( QCursor::pos(), help );
124 CustomTemplates::~CustomTemplates()
126 delete mUi;
127 mUi = 0;
130 void CustomTemplates::slotNameChanged( const QString &text )
132 mUi->mAdd->setEnabled( !text.isEmpty() );
135 QString CustomTemplates::indexToType( int index )
137 QString typeStr;
138 switch ( index ) {
139 case TUniversal:
140 typeStr = i18nc( "Message->", "Universal" );
141 break;
142 /* case TNewMessage:
143 typeStr = i18n( "New Message" );
144 break; */
145 case TReply:
146 typeStr = i18nc( "Message->", "Reply" );
147 break;
148 case TReplyAll:
149 typeStr = i18nc( "Message->", "Reply to All" );
150 break;
151 case TForward:
152 typeStr = i18nc( "Message->", "Forward" );
153 break;
154 default:
155 typeStr = i18nc( "Message->", "Unknown" );
156 break;
158 return typeStr;
161 void CustomTemplates::slotTextChanged()
163 QTreeWidgetItem *item = mUi->mList->currentItem();
164 if ( item ) {
165 CustomTemplateItem *vitem = static_cast<CustomTemplateItem*>( item );
166 vitem->setContent( mUi->mEdit->toPlainText() );
167 if ( !mBlockChangeSignal ) {
168 vitem->setTo( mUi->mToEdit->text() );
169 vitem->setCc( mUi->mCCEdit->text() );
173 if ( !mBlockChangeSignal ) {
174 emit changed();
178 void CustomTemplates::iconFromType( CustomTemplates::Type type, CustomTemplateItem *item )
180 switch ( type ) {
181 case TReply:
182 item->setIcon( 0, mReplyPix );
183 break;
184 case TReplyAll:
185 item->setIcon( 0, mReplyAllPix );
186 break;
187 case TForward:
188 item->setIcon( 0, mForwardPix );
189 break;
190 default:
191 item->setIcon( 0, QPixmap() );
192 break;
197 void CustomTemplates::load()
199 const QStringList list = GlobalSettings::self()->customTemplates();
200 mUi->mList->clear();
201 QStringList::const_iterator end( list.constEnd() );
202 for ( QStringList::const_iterator it = list.constBegin(); it != end; ++it ) {
203 CTemplates t(*it);
204 QKeySequence shortcut( t.shortcut() );
205 CustomTemplates::Type type = static_cast<Type>( t.type() );
206 CustomTemplateItem *item = new CustomTemplateItem( mUi->mList, *it, t.content(),
207 shortcut, type, t.to(), t.cC() );
208 item->setText( 1, *it );
209 item->setText( 0, indexToType( type ) );
210 iconFromType( type, item );
213 mUi->mRemove->setEnabled( mUi->mList->topLevelItemCount() > 0 && mUi->mList->currentItem() );
214 mUi->mDuplicate->setEnabled( mUi->mList->topLevelItemCount() > 0 && mUi->mList->currentItem() );
217 void CustomTemplates::save()
219 // Before saving the new templates, delete the old ones. That needs to be done before
220 // saving, since otherwise a new template with the new name wouldn't get saved.
221 KSharedConfig::Ptr config = KSharedConfig::openConfig( "customtemplatesrc", KConfig::NoGlobals );
222 foreach ( const QString &item, mItemsToDelete ) {
223 CTemplates t( item );
224 const QString configGroup = t.currentGroup();
225 config->deleteGroup( configGroup );
228 QStringList list;
229 QTreeWidgetItemIterator lit( mUi->mList );
230 while ( *lit ) {
231 CustomTemplateItem * it = static_cast<CustomTemplateItem*>( *lit );
232 const QString name = it->text( 1 );
233 list.append(name);
235 CTemplates t(name);
236 QString content = it->content();
237 if ( content.trimmed().isEmpty() ) {
238 content = "%BLANK";
241 t.setContent( content );
242 t.setShortcut( it->shortcut().toString() );
243 t.setType( it->customType() );
244 t.setTo( it->to() );
245 t.setCC( it->cc() );
246 t.writeConfig();
247 ++lit;
250 GlobalSettings::self()->setCustomTemplates( list );
251 GlobalSettings::self()->writeConfig();
253 emit templatesUpdated();
256 void CustomTemplates::slotInsertCommand( const QString &cmd, int adjustCursor )
258 QTextCursor cursor = mUi->mEdit->textCursor();
259 cursor.insertText( cmd );
260 cursor.setPosition( cursor.position() + adjustCursor );
261 mUi->mEdit->setTextCursor( cursor );
262 mUi->mEdit->setFocus();
265 bool CustomTemplates::nameAlreadyExists( const QString &str, QTreeWidgetItem *item )
267 QTreeWidgetItemIterator lit( mUi->mList );
268 while ( *lit ) {
269 const QString name = ( *lit )->text( 1 );
270 if ( ( name == str ) && ( (*lit) != item ) ) {
271 KMessageBox::error(
272 this,
273 i18n( "A template with same name already exists." ),
274 i18n( "Can not create template" ) );
275 return true;
277 ++lit;
279 return false;
282 void CustomTemplates::slotAddClicked()
284 const QString str = mUi->mName->text();
285 if ( !str.isEmpty() ) {
286 if ( nameAlreadyExists( str ) ) {
287 return;
290 // KShortcut::null() doesn't seem to be present, although documented
291 // see slotShortcutChanged(). oh, and you should look up documentation on the EBN!
292 // FIXME There must be a better way of doing this...
293 QKeySequence nullShortcut;
294 CustomTemplateItem *item =
295 new CustomTemplateItem( mUi->mList, str, "", nullShortcut, TUniversal,
296 QString(), QString() );
297 item->setText( 0, indexToType( TUniversal ) );
298 item->setText( 1, str );
299 mUi->mList->setCurrentItem( item );
300 mUi->mRemove->setEnabled( true );
301 mUi->mDuplicate->setEnabled( true );
302 mUi->mName->clear();
303 mUi->mKeySequenceWidget->setEnabled( false );
304 if ( !mBlockChangeSignal ) {
305 emit changed();
310 QString CustomTemplates::createUniqueName( const QString &name ) const
312 QString uniqueName = name;
314 int counter = 0;
315 bool found = true;
317 while ( found ) {
318 found = false;
320 QTreeWidgetItemIterator lit( mUi->mList );
321 while ( *lit ) {
322 const QString itemName = ( *lit )->text( 1 );
323 if ( !itemName.compare( uniqueName ) ) {
324 found = true;
325 ++counter;
326 uniqueName = name;
327 uniqueName += QString( " (" ) + QString::number( counter ) + QString( ")" );
328 break;
330 lit++;
334 return uniqueName;
337 void CustomTemplates::slotDuplicateClicked()
339 QTreeWidgetItem *currentItem = mUi->mList->currentItem();
340 if ( !currentItem ) {
341 return;
343 CustomTemplateItem * origItem = static_cast<CustomTemplateItem*>( currentItem );
344 const QString templateName = createUniqueName( origItem->text( 1 ) );
345 // KShortcut::null() doesn't seem to be present, although documented
346 // see slotShortcutChanged(). oh, and you should look up documentation on the EBN!
347 // FIXME There must be a better way of doing this...
348 QKeySequence nullShortcut;
349 CustomTemplates::Type type = origItem->customType();
350 CustomTemplateItem *item =
351 new CustomTemplateItem( mUi->mList, templateName, origItem->content(), nullShortcut, type,
352 origItem->to(), origItem->cc() );
353 item->setText( 0, indexToType( type ) );
354 item->setText( 1, templateName );
355 iconFromType( type, item );
357 mUi->mList->setCurrentItem( item );
358 mUi->mRemove->setEnabled( true );
359 mUi->mDuplicate->setEnabled( true );
360 mUi->mName->clear();
361 mUi->mKeySequenceWidget->setEnabled( type != TUniversal );
363 emit changed();
366 void CustomTemplates::slotRemoveClicked()
368 QTreeWidgetItem *item = mUi->mList->currentItem();
369 if ( !item ) {
370 return;
373 const QString templateName = item->text( 1 );
375 if ( KMessageBox::warningContinueCancel(
376 this,
377 i18nc( "@info", "Do you really want to remove template \"%1\"?", templateName ),
378 i18nc( "@title:window", "Remove Template?" ),
379 KStandardGuiItem::remove(),
380 KStandardGuiItem::cancel() ) == KMessageBox::Continue ) {
381 mItemsToDelete.append( templateName );
382 delete mUi->mList->takeTopLevelItem( mUi->mList->indexOfTopLevelItem( item ) );
383 mUi->mRemove->setEnabled( mUi->mList->topLevelItemCount() > 0 );
384 mUi->mDuplicate->setEnabled( mUi->mList->topLevelItemCount() > 0 );
385 if ( !mBlockChangeSignal ) {
386 emit changed();
391 void CustomTemplates::slotListSelectionChanged()
393 QTreeWidgetItem *item = mUi->mList->currentItem();
394 if ( item ) {
395 mUi->mEditFrame->setEnabled( true );
396 mUi->mRemove->setEnabled(true);
397 mUi->mDuplicate->setEnabled(true);
398 CustomTemplateItem *vitem = static_cast<CustomTemplateItem*>( item );
399 mBlockChangeSignal = true;
400 mUi->mEdit->setText( vitem->content() );
401 mUi->mKeySequenceWidget->setKeySequence( vitem->shortcut(),
402 KKeySequenceWidget::NoValidate );
403 CustomTemplates::Type type = vitem->customType();
405 mUi->mType->setCurrentIndex( mUi->mType->findText( indexToType ( type ) ) );
406 mUi->mToEdit->setText( vitem->to() );
407 mUi->mCCEdit->setText( vitem->cc() );
408 mBlockChangeSignal = false;
410 // I think the logic (originally 'vitem->mType==TUniversal') was inverted here:
411 // a key shortcut is only allowed for a specific type of template and not for
412 // a universal, as otherwise we won't know what sort of action to do when the
413 // key sequence is activated!
414 // This agrees with KMMainWidget::updateCustomTemplateMenus() -- marten
415 mUi->mKeySequenceWidget->setEnabled( type != TUniversal );
416 } else {
417 mUi->mEditFrame->setEnabled( false );
418 mUi->mEdit->clear();
419 // see above
420 mUi->mKeySequenceWidget->clearKeySequence();
421 mUi->mType->setCurrentIndex( 0 );
422 mUi->mToEdit->clear();
423 mUi->mCCEdit->clear();
427 void CustomTemplates::slotTypeActivated( int index )
429 QTreeWidgetItem *item = mUi->mList->currentItem();
430 if ( item ) {
431 CustomTemplateItem *vitem = static_cast<CustomTemplateItem*>( item );
432 CustomTemplates::Type customtype = static_cast<Type>(index);
433 vitem->setCustomType( customtype );
434 vitem->setText( 0, indexToType( customtype ) );
436 iconFromType( customtype, vitem );
438 // see slotListSelectionChanged() above
439 mUi->mKeySequenceWidget->setEnabled( customtype != TUniversal );
441 if ( !mBlockChangeSignal ) {
442 emit changed();
447 void CustomTemplates::slotShortcutChanged( const QKeySequence &newSeq )
449 QTreeWidgetItem *item = mUi->mList->currentItem();
450 if ( item ) {
451 CustomTemplateItem * vitem = static_cast<CustomTemplateItem*>( item );
452 vitem->setShortcut( newSeq );
453 mUi->mKeySequenceWidget->applyStealShortcut();
456 if ( !mBlockChangeSignal ) {
457 emit changed();
461 void CustomTemplates::slotItemChanged( QTreeWidgetItem *item, int column )
463 if ( item ) {
464 CustomTemplateItem * vitem = static_cast<CustomTemplateItem*>( item );
465 if ( column == 1 ) {
466 const QString newName = vitem->text( 1 );
467 if( !newName.isEmpty() ) {
468 const QString oldName = vitem->oldName();
469 if ( nameAlreadyExists( newName, item ) ) {
470 vitem->setText( 1, oldName );
471 return;
473 if ( newName != oldName ) {
474 mItemsToDelete.append( oldName );
475 vitem->setOldName( newName );
476 if ( !mBlockChangeSignal ) {
477 emit changed();
485 CustomTemplateItemDelegate::CustomTemplateItemDelegate( QObject *parent )
486 : QStyledItemDelegate( parent )
490 CustomTemplateItemDelegate::~CustomTemplateItemDelegate()
494 void CustomTemplateItemDelegate::setModelData( QWidget *editor, QAbstractItemModel *model,
495 const QModelIndex &index ) const
497 KLineEdit *lineEdit = static_cast<KLineEdit*>( editor );
498 const QString text = lineEdit->text();
499 if( !text.isEmpty() ) {
500 model->setData( index, text, Qt::EditRole );
504 QWidget *CustomTemplateItemDelegate::createEditor( QWidget *parent,
505 const QStyleOptionViewItem &option,
506 const QModelIndex &index ) const
508 if ( index.column() == 1 ) {
509 return QStyledItemDelegate::createEditor( parent, option, index );
511 return 0;
514 CustomTemplateItem::CustomTemplateItem( QTreeWidget *parent,
515 const QString &name,
516 const QString &content,
517 const QKeySequence &shortcut,
518 CustomTemplates::Type type,
519 const QString &to,
520 const QString &cc )
521 : QTreeWidgetItem( parent ),
522 mName( name ),
523 mContent( content ),
524 mShortcut(shortcut),
525 mType( type ),
526 mTo( to ),
527 mCC( cc )
529 setFlags( flags() | Qt::ItemIsEditable );
532 CustomTemplateItem::~CustomTemplateItem()
536 void CustomTemplateItem::setCustomType( CustomTemplates::Type type )
538 mType = type;
541 CustomTemplates::Type CustomTemplateItem::customType() const
543 return mType;
546 QString CustomTemplateItem::to() const
548 return mTo;
551 QString CustomTemplateItem::cc() const
553 return mCC;
556 QString CustomTemplateItem::content() const
558 return mContent;
561 void CustomTemplateItem::setContent( const QString &content )
563 mContent = content;
566 void CustomTemplateItem::setTo( const QString &to )
568 mTo = to;
571 void CustomTemplateItem::setCc( const QString &cc )
573 mCC = cc;
576 QKeySequence CustomTemplateItem::shortcut() const
578 return mShortcut;
581 void CustomTemplateItem::setShortcut( const QKeySequence &shortcut )
583 mShortcut = shortcut;
586 QString CustomTemplateItem::oldName() const
588 return mName;
591 void CustomTemplateItem::setOldName( const QString &name )
593 mName = name;
596 #include "customtemplates.moc"