kmail

snippetwidget.cpp

00001 /***************************************************************************
00002  *   snippet feature from kdevelop/plugins/snippet/                        *
00003  *                                                                         *
00004  *   Copyright (C) 2007 by Robert Gruber                                   *
00005  *   rgruber@users.sourceforge.net                                         *
00006  *                                                                         *
00007  *   This program is free software; you can redistribute it and/or modify  *
00008  *   it under the terms of the GNU General Public License as published by  *
00009  *   the Free Software Foundation; either version 2 of the License, or     *
00010  *   (at your option) any later version.                                   *
00011  *                                                                         *
00012  ***************************************************************************/
00013 
00014 #include <kurl.h>
00015 #include <kdebug.h>
00016 #include <klocale.h>
00017 #include <qlayout.h>
00018 #include <kpushbutton.h>
00019 #include <klistview.h>
00020 #include <qheader.h>
00021 #include <klineedit.h>
00022 #include <ktextedit.h>
00023 #include <kmessagebox.h>
00024 #include <kconfig.h>
00025 #include <qtooltip.h>
00026 #include <kpopupmenu.h>
00027 #include <qregexp.h>
00028 #include <qinputdialog.h>
00029 #include <qlabel.h>
00030 #include <qcheckbox.h>
00031 #include <qwhatsthis.h>
00032 #include <qdragobject.h>
00033 #include <qtimer.h>
00034 #include <kcombobox.h>
00035 #include <kmedit.h>
00036 #include <kiconloader.h>
00037 #include <kshortcut.h>
00038 #include <kaction.h>
00039 #include <kkeybutton.h>
00040 
00041 #include "snippetdlg.h"
00042 #include "snippetitem.h"
00043 #include "snippetwidget.h"
00044 
00045 #include <cassert>
00046 
00047 SnippetWidget::SnippetWidget( KMEdit *editor, KActionCollection *actionCollection, QWidget *parent )
00048   : KListView( parent, "snippet widget" ), QToolTip( viewport() ),
00049     mEditor( editor ), mActionCollection( actionCollection )
00050 {
00051   // init the QPtrList
00052   _list.setAutoDelete( true );
00053 
00054   // init the KListView
00055   setSorting( -1 );
00056   addColumn( "" );
00057   setFullWidth( true );
00058   header()->hide();
00059   setAcceptDrops( true );
00060   setDragEnabled( true );
00061   setDropVisualizer( false );
00062   setRootIsDecorated( true );
00063 
00064   //connect the signals
00065   connect( this, SIGNAL(contextMenuRequested (QListViewItem *,const QPoint &,int)),
00066            this, SLOT(showPopupMenu(QListViewItem *,const QPoint &,int)) );
00067 
00068   connect( this, SIGNAL(doubleClicked (QListViewItem *)),
00069            this, SLOT(slotEdit( QListViewItem *)) );
00070   connect( this, SIGNAL(returnPressed (QListViewItem *)),
00071            this, SLOT(slotExecuted( QListViewItem *)) );
00072 
00073   connect( this, SIGNAL(dropped(QDropEvent *,QListViewItem *)),
00074            this, SLOT(slotDropped(QDropEvent *,QListViewItem *)) );
00075 
00076   connect( editor, SIGNAL(insertSnippet()), this, SLOT(slotExecute()) );
00077 
00078   _cfg = 0;
00079 
00080   QTimer::singleShot( 0, this, SLOT(initConfig()) );
00081 }
00082 
00083 SnippetWidget::~SnippetWidget()
00084 {
00085   writeConfig();
00086   delete _cfg;
00087 
00088   /* We need to delete the child items before the parent items
00089      otherwise KDevelop would crash on exiting */
00090   SnippetItem *item;
00091   while ( _list.count() > 0 ) {
00092     for ( item=_list.first(); item; item=_list.next() ) {
00093       if ( item->childCount() == 0 ) {
00094           _list.remove( item );
00095       }
00096     }
00097   }
00098 }
00099 
00104 void SnippetWidget::slotAdd()
00105 {
00106   //kdDebug(5006) << "Ender slotAdd()" << endl;
00107   SnippetDlg dlg( mActionCollection, this, "SnippetDlg" );
00108 
00109   /*check if the user clicked a SnippetGroup
00110     If not, we set the group variable to the SnippetGroup
00111     which the selected item is a child of*/
00112   SnippetGroup *group = dynamic_cast<SnippetGroup*>( selectedItem() );
00113   if ( !group && selectedItem() ) {
00114     group = dynamic_cast<SnippetGroup*>( selectedItem()->parent() );
00115   }
00116 
00117   /* still no group, let's make a default one */
00118   if ( !group ) {
00119     if ( _list.isEmpty() ) {
00120       group = new SnippetGroup( this, i18n( "General" ), SnippetGroup::getMaxId() );
00121       _list.append( group );
00122     } else {
00123       group = dynamic_cast<SnippetGroup*>( _list.first() );
00124     }
00125   }
00126   assert( group );
00127 
00128   /*fill the combobox with the names of all SnippetGroup entries*/
00129   for ( SnippetItem *it=_list.first(); it; it=_list.next() ) {
00130     if ( dynamic_cast<SnippetGroup*>( it ) ) {
00131       dlg.cbGroup->insertItem( it->getName() );
00132     }
00133   }
00134   dlg.cbGroup->setCurrentText( group->getName() );
00135 
00136   if ( dlg.exec() == QDialog::Accepted ) {
00137     group = dynamic_cast<SnippetGroup*>(
00138       SnippetItem::findItemByName( dlg.cbGroup->currentText(), _list ) );
00139     _list.append( makeItem( group, dlg.snippetName->text(), dlg.snippetText->text(),
00140                             dlg.shortcutButton->shortcut() ) );
00141   }
00142 }
00143 
00148 SnippetItem *SnippetWidget::makeItem( SnippetItem *parent, const QString &name, const QString &text,
00149                                       const KShortcut &shortcut )
00150 {
00151   SnippetItem *item = new SnippetItem( parent, name, text );
00152   const QString actionName = i18n( "Snippet %1" ).arg( name );
00153   const QString normalizedName = QString(actionName).replace( " ", "_" );
00154   if ( !mActionCollection->action( normalizedName.utf8() ) ) {
00155     KAction * action = new KAction( actionName, shortcut, item,
00156                                     SLOT(slotExecute()), mActionCollection,
00157                                     normalizedName.utf8() );
00158     item->setAction( action );
00159     connect( item, SIGNAL(execute(QListViewItem *)),
00160              this, SLOT(slotExecuted(QListViewItem *)) );
00161   }
00162   return item;
00163 }
00164 
00169 void SnippetWidget::slotAddGroup()
00170 {
00171   //kdDebug(5006) << "Ender slotAddGroup()" << endl;
00172   SnippetDlg dlg( mActionCollection, this, "SnippetDlg" );
00173   dlg.setGroupMode( true );
00174   dlg.setCaption( i18n( "Add Group" ) );
00175 
00176   if ( dlg.exec() == QDialog::Accepted ) {
00177     _list.append( new SnippetGroup( this, dlg.snippetName->text(), SnippetGroup::getMaxId() ) );
00178   }
00179 }
00180 
00185 void SnippetWidget::slotRemove()
00186 {
00187   //get current data
00188   QListViewItem *item = currentItem();
00189   SnippetItem *snip = dynamic_cast<SnippetItem*>( item );
00190   SnippetGroup *group = dynamic_cast<SnippetGroup*>( item );
00191   if ( !snip ) {
00192     return;
00193   }
00194 
00195   if ( group ) {
00196     if ( group->childCount() > 0 ) {
00197       if ( KMessageBox::warningContinueCancel(
00198              this,
00199              i18n( "<qt>Do you really want to remove group \"%1\" along with all its snippets?"
00200                    "<p><b>There is no way to undo the removal.</b></qt>" ).arg( group->getName() ),
00201              QString::null,
00202              KStdGuiItem::remove() ) == KMessageBox::Cancel ) {
00203         return;
00204       }
00205     } else {
00206       if ( KMessageBox::warningContinueCancel(
00207              this,
00208              i18n( "Do you really want to remove group \"%1\"?" ).arg( group->getName() ),
00209              QString::null,
00210              KStdGuiItem::remove() ) == KMessageBox::Cancel ) {
00211         return;
00212       }
00213     }
00214 
00215     SnippetItem *it = _list.first();
00216     while ( it ) {
00217       if ( it->getParent() == group->getId() ) {
00218         SnippetItem *doomed = it;
00219         it = _list.next();
00220         //kdDebug(5006) << "remove " << doomed->getName() << endl;
00221         _list.remove( doomed );
00222       } else {
00223         it = _list.next();
00224       }
00225     }
00226   } else {
00227     if ( KMessageBox::warningContinueCancel(
00228            this,
00229            i18n( "<qt>Do you really want to remove snippet \"%1\"?"
00230                  "<p><b>There is no way to undo the removal.</b></qt>" ).arg( snip->getName() ),
00231            QString::null,
00232            KStdGuiItem::remove() ) == KMessageBox::Cancel ) {
00233       return;
00234     }
00235   }
00236 
00237   //kdDebug(5006) << "remove " << snip->getName() << endl;
00238   _list.remove( snip );
00239 }
00240 
00245 void SnippetWidget::slotEdit( QListViewItem *item )
00246 {
00247   if ( item == 0 ) {
00248     item = currentItem();
00249   }
00250 
00251   SnippetGroup *pGroup = dynamic_cast<SnippetGroup*>( item );
00252   SnippetItem *pSnippet = dynamic_cast<SnippetItem*>( item );
00253   if ( !pSnippet || pGroup ) { //selected item must be a SnippetItem but MUST not be a SnippetGroup
00254     return;
00255   }
00256 
00257   //init the dialog
00258   SnippetDlg dlg( mActionCollection, this, "SnippetDlg" );
00259   dlg.snippetName->setText( pSnippet->getName() );
00260   dlg.snippetText->setText( pSnippet->getText() );
00261   dlg.shortcutButton->setShortcut( pSnippet->getAction()->shortcut(), false );
00262   dlg.btnAdd->setText( i18n( "&Apply" ) );
00263   dlg.setCaption( i18n( "Edit Snippet" ) );
00264 
00265   /*fill the combobox with the names of all SnippetGroup entries*/
00266   for ( SnippetItem *it=_list.first(); it; it=_list.next() ) {
00267     if ( dynamic_cast<SnippetGroup*>( it ) ) {
00268       dlg.cbGroup->insertItem( it->getName() );
00269     }
00270   }
00271   dlg.cbGroup->setCurrentText(
00272     SnippetItem::findGroupById( pSnippet->getParent(), _list )->getName() );
00273 
00274   if ( dlg.exec() == QDialog::Accepted ) {
00275     //update the KListView and the SnippetItem
00276     item->setText( 0, dlg.snippetName->text() );
00277     pSnippet->setName( dlg.snippetName->text() );
00278     pSnippet->setText( dlg.snippetText->text() );
00279     pSnippet->getAction()->setShortcut( dlg.shortcutButton->shortcut() );
00280 
00281     /* if the user changed the parent we need to move the snippet */
00282     if ( SnippetItem::findGroupById( pSnippet->getParent(), _list )->getName() != dlg.cbGroup->currentText() ) {
00283       SnippetGroup *newGroup = dynamic_cast<SnippetGroup*>(
00284         SnippetItem::findItemByName( dlg.cbGroup->currentText(), _list ) );
00285       pSnippet->parent()->takeItem( pSnippet );
00286       newGroup->insertItem( pSnippet );
00287       pSnippet->resetParent();
00288     }
00289 
00290     setSelected( item, true );
00291   }
00292 }
00293 
00298 void SnippetWidget::slotEditGroup()
00299 {
00300   //get current data
00301   QListViewItem *item = currentItem();
00302 
00303   SnippetGroup *pGroup = dynamic_cast<SnippetGroup*>( item );
00304   if ( !pGroup ) { /*selected item MUST be a SnippetGroup*/
00305     return;
00306   }
00307 
00308   //init the dialog
00309   SnippetDlg dlg( mActionCollection, this, "SnippetDlg" );
00310   dlg.setGroupMode( true );
00311   dlg.snippetName->setText( pGroup->getName() );
00312   dlg.btnAdd->setText( i18n( "&Apply" ) );
00313   dlg.setCaption( i18n( "Edit Group" ) );
00314 
00315   if ( dlg.exec() == QDialog::Accepted ) {
00316     //update the KListView and the SnippetGroup
00317     item->setText( 0, dlg.snippetName->text() );
00318     pGroup->setName( dlg.snippetName->text() );
00319 
00320     setSelected( item, true );
00321   }
00322 }
00323 
00324 void SnippetWidget::slotExecuted( QListViewItem *item )
00325 {
00326   if ( item == 0 ) {
00327     item = currentItem();
00328   }
00329 
00330   SnippetItem *pSnippet = dynamic_cast<SnippetItem*>( item );
00331   if ( !pSnippet || dynamic_cast<SnippetGroup*>( item ) ) {
00332     return;
00333   }
00334 
00335   //process variables if any, then insert into the active view
00336   insertIntoActiveView( parseText( pSnippet->getText(), _SnippetConfig.getDelimiter() ) );
00337 }
00338 
00343 void SnippetWidget::insertIntoActiveView( const QString &text )
00344 {
00345   mEditor->insert( text );
00346 }
00347 
00352 void SnippetWidget::writeConfig()
00353 {
00354   if( !_cfg ) {
00355     return;
00356   }
00357   _cfg->deleteGroup( "SnippetPart" ); //otherwise delete entries will stay in list until
00358                                       //they get overwritten by a more recent entry
00359   _cfg->setGroup( "SnippetPart" );
00360 
00361   QString strKeyName = "";
00362   QString strKeyText = "";
00363   QString strKeyId = "";
00364 
00365   int iSnipCount = 0;
00366   int iGroupCount = 0;
00367 
00368   SnippetItem *item = _list.first();
00369   while ( item != 0 ) {
00370     //kdDebug(5006) << "-->ERROR " << item->getName() << endl;
00371     //kdDebug(5006) << "SnippetWidget::writeConfig() " << item->getName() << endl;
00372     SnippetGroup *group = dynamic_cast<SnippetGroup*>( item );
00373     if ( group ) {
00374       //kdDebug(5006) << "-->GROUP "
00375       //              << item->getName() << group->getId() << " " << iGroupCount<< endl;
00376       strKeyName = QString( "snippetGroupName_%1" ).arg( iGroupCount );
00377       strKeyId = QString( "snippetGroupId_%1" ).arg( iGroupCount );
00378 
00379       _cfg->writeEntry( strKeyName, group->getName() );
00380       _cfg->writeEntry( strKeyId, group->getId() );
00381 
00382       iGroupCount++;
00383     } else if ( dynamic_cast<SnippetItem*>( item ) ) {
00384       //kdDebug(5006) << "-->ITEM "
00385       //              << item->getName() << item->getParent() << " " << iSnipCount << endl;
00386       strKeyName=QString( "snippetName_%1" ).arg( iSnipCount );
00387       strKeyText=QString( "snippetText_%1" ).arg( iSnipCount );
00388       strKeyId=QString( "snippetParent_%1" ).arg( iSnipCount );
00389 
00390       _cfg->writeEntry( strKeyName, item->getName() );
00391       _cfg->writeEntry( strKeyText, item->getText() );
00392       _cfg->writeEntry( strKeyId, item->getParent() );
00393 
00394       KAction *action = item->getAction();
00395       assert( action );
00396       const KShortcut &sc = action->shortcut();
00397       if (!sc.isNull() ) {
00398           _cfg->writeEntry( QString( "snippetShortcut_%1" ).arg( iSnipCount ), sc.toString() );
00399       }
00400       iSnipCount++;
00401     } else {
00402       //kdDebug(5006) << "-->ERROR " << item->getName() << endl;
00403     }
00404     item = _list.next();
00405   }
00406   _cfg->writeEntry( "snippetCount", iSnipCount );
00407   _cfg->writeEntry( "snippetGroupCount", iGroupCount );
00408 
00409   int iCount = 1;
00410   QMap<QString, QString>::Iterator it;
00411   for ( it = _mapSaved.begin(); it != _mapSaved.end(); ++it ) {  //write the saved variable values
00412     if ( it.data().length() <= 0 ) {  //is the saved value has no length -> no need to save it
00413       continue;
00414     }
00415 
00416     strKeyName=QString( "snippetSavedName_%1" ).arg( iCount );
00417     strKeyText=QString( "snippetSavedVal_%1" ).arg( iCount );
00418 
00419     _cfg->writeEntry( strKeyName, it.key() );
00420     _cfg->writeEntry( strKeyText, it.data() );
00421 
00422     iCount++;
00423   }
00424   _cfg->writeEntry( "snippetSavedCount", iCount - 1 );
00425 
00426   _cfg->writeEntry( "snippetDelimiter", _SnippetConfig.getDelimiter() );
00427   _cfg->writeEntry( "snippetVarInput", _SnippetConfig.getInputMethod() );
00428   _cfg->writeEntry( "snippetToolTips", _SnippetConfig.useToolTips() );
00429   _cfg->writeEntry( "snippetGroupAutoOpen", _SnippetConfig.getAutoOpenGroups() );
00430 
00431   _cfg->writeEntry( "snippetSingleRect", _SnippetConfig.getSingleRect() );
00432   _cfg->writeEntry( "snippetMultiRect", _SnippetConfig.getMultiRect() );
00433 
00434   _cfg->sync();
00435 }
00436 
00441 void SnippetWidget::initConfig()
00442 {
00443   if (!_cfg ) {
00444     _cfg = new KConfig( "kmailsnippetrc", false, false );
00445   }
00446 
00447   _cfg->setGroup( "SnippetPart" );
00448 
00449   QString strKeyName = "";
00450   QString strKeyText = "";
00451   QString strKeyId = "";
00452   SnippetItem *item;
00453   SnippetGroup *group;
00454 
00455   //kdDebug(5006) << "SnippetWidget::initConfig() " << endl;
00456 
00457   //if entry doesn't get found, this will return -1 which we will need a bit later
00458   int iCount = _cfg->readNumEntry( "snippetGroupCount", -1 );
00459 
00460   for ( int i=0; i<iCount; i++) {  //read the group-list
00461     strKeyName=QString( "snippetGroupName_%1" ).arg( i );
00462     strKeyId=QString( "snippetGroupId_%1" ).arg( i );
00463 
00464     QString strNameVal = "";
00465     int iIdVal = -1;
00466 
00467     strNameVal = _cfg->readEntry( strKeyName, "" );
00468     iIdVal = _cfg->readNumEntry( strKeyId, -1 );
00469     //kdDebug(5006) << "Read group "  << " " << iIdVal << endl;
00470 
00471     if ( strNameVal != "" && iIdVal != -1 ) {
00472       group = new SnippetGroup( this, strNameVal, iIdVal );
00473       //kdDebug(5006) << "Created group " << group->getName() << " " << group->getId() << endl;
00474       _list.append( group );
00475     }
00476   }
00477 
00478   /* Check if the snippetGroupCount property has been found
00479      if iCount is -1 this means, that the user has his snippets
00480      stored without groups. Therefore we will call the
00481      initConfigOldVersion() function below */
00482   // should not happen since this function has been removed
00483 
00484   if ( iCount != -1 ) {
00485     iCount = _cfg->readNumEntry( "snippetCount", 0 );
00486     for ( int i=0; i<iCount; i++ ) {  //read the snippet-list
00487       strKeyName=QString( "snippetName_%1" ).arg( i );
00488       strKeyText=QString( "snippetText_%1" ).arg( i );
00489       strKeyId=QString( "snippetParent_%1" ).arg( i );
00490 
00491       QString strNameVal = "";
00492       QString strTextVal = "";
00493       int iParentVal = -1;
00494 
00495       strNameVal = _cfg->readEntry( strKeyName, "" );
00496       strTextVal = _cfg->readEntry( strKeyText, "" );
00497       iParentVal = _cfg->readNumEntry( strKeyId, -1 );
00498       //kdDebug(5006) << "Read item " << strNameVal << " " << iParentVal << endl;
00499 
00500       if ( strNameVal != "" && strTextVal != "" && iParentVal != -1 ) {
00501         KShortcut shortcut(
00502           _cfg->readEntry( QString( "snippetShortcut_%1" ).arg( i ), QString() ) );
00503         item = makeItem( SnippetItem::findGroupById(
00504                            iParentVal, _list ), strNameVal, strTextVal, shortcut );
00505         //kdDebug(5006) << "Created item " << item->getName() << " " << item->getParent() << endl;
00506         _list.append( item );
00507       }
00508     }
00509   } else {
00510     //kdDebug() << "iCount is not -1";
00511   }
00512 
00513   iCount = _cfg->readNumEntry( "snippetSavedCount", 0 );
00514 
00515   for ( int i=1; i<=iCount; i++ ) {  //read the saved-values and store in QMap
00516     strKeyName = QString( "snippetSavedName_%1" ).arg( i );
00517     strKeyText = QString( "snippetSavedVal_%1" ).arg( i );
00518 
00519     QString strNameVal = "";
00520     QString strTextVal = "";
00521 
00522     strNameVal = _cfg->readEntry( strKeyName, "" );
00523     strTextVal = _cfg->readEntry( strKeyText, "" );
00524 
00525     if ( strNameVal != "" && strTextVal != "" ) {
00526       _mapSaved[strNameVal] = strTextVal;
00527     }
00528   }
00529 
00530   _SnippetConfig.setDelimiter( _cfg->readEntry( "snippetDelimiter", "$" ) );
00531   _SnippetConfig.setInputMethod( _cfg->readNumEntry( "snippetVarInput", 0 ) );
00532   _SnippetConfig.setToolTips( _cfg->readBoolEntry( "snippetToolTips", true ) );
00533   _SnippetConfig.setAutoOpenGroups( _cfg->readNumEntry( "snippetGroupAutoOpen", 1 ) );
00534 
00535   _SnippetConfig.setSingleRect( _cfg->readRectEntry( "snippetSingleRect", 0L ) );
00536   _SnippetConfig.setMultiRect( _cfg->readRectEntry( "snippetMultiRect", 0L ) );
00537 }
00538 
00543 void SnippetWidget::maybeTip( const QPoint &p )
00544 {
00545   SnippetItem *item = dynamic_cast<SnippetItem*>( itemAt( p ) );
00546   if ( !item ) {
00547     return;
00548   }
00549   SnippetGroup *group = dynamic_cast<SnippetGroup *>(item);
00550   if ( group ) { // only show tooltips for snippets.
00551     return;
00552   }
00553 
00554   QRect r = itemRect( item );
00555 
00556   if ( r.isValid() && _SnippetConfig.useToolTips() ) {
00557     tip( r, item->getText() );  //show the snippet's text
00558   }
00559 }
00560 
00565 void SnippetWidget::showPopupMenu( QListViewItem *item, const QPoint &p, int )
00566 {
00567   KPopupMenu popup;
00568 
00569   SnippetItem * selectedItem = static_cast<SnippetItem *>(item);
00570   bool canAddGroup = true;
00571   bool canAddSnippet = true;
00572   if ( item ) {
00573     canAddGroup = false;  // subgroups are not permitted
00574     popup.insertTitle( selectedItem->getName() );
00575     if ( dynamic_cast<SnippetGroup*>( item ) ) {
00576       popup.insertItem( SmallIconSet( "edit" ), i18n( "Rename &Group..." ),
00577                         this, SLOT(slotEditGroup()) );
00578       popup.insertItem( SmallIconSet( "editdelete" ), i18n( "&Remove Group" ),
00579                         this, SLOT(slotRemove()) );
00580     } else {
00581       canAddSnippet = false; // subsnippets are not permitted
00582       popup.insertItem( SmallIconSet( "editpaste" ), i18n( "&Insert Snippet" ),
00583                         this, SLOT(slotExecuted()) );
00584       popup.insertSeparator();
00585       popup.insertItem( SmallIconSet( "edit" ), i18n( "&Edit Snippet..." ),
00586                         this, SLOT(slotEdit()) );
00587       popup.insertItem( SmallIconSet( "editdelete" ), i18n( "&Remove Snippet" ),
00588                         this, SLOT(slotRemove()) );
00589     }
00590     popup.insertSeparator();
00591   } else {
00592     popup.insertTitle( i18n( "Text Snippets" ) );
00593   }
00594   if ( canAddSnippet ) {
00595     popup.insertItem( i18n( "&Add Snippet..." ), this, SLOT(slotAdd()) );
00596   }
00597   if ( canAddGroup ) {
00598     popup.insertItem( i18n( "Add G&roup..." ), this, SLOT(slotAddGroup()) );
00599   }
00600 
00601   popup.exec( p );
00602 }
00603 
00604 //  fn SnippetWidget::parseText(QString text, QString del)
00609 QString SnippetWidget::parseText( QString text, QString del )
00610 {
00611   QString str = text;
00612   QString strName = "";
00613   QString strNew = "";
00614   QString strMsg="";
00615   int iFound = -1;
00616   int iEnd = -1;
00617   QMap<QString, QString> mapVar;
00618   int iInMeth = _SnippetConfig.getInputMethod();
00619   QRect rSingle = _SnippetConfig.getSingleRect();
00620   QRect rMulti = _SnippetConfig.getMultiRect();
00621 
00622   do {
00623     iFound = text.find( QRegExp( "\\" + del + "[A-Za-z-_0-9\\s]*\\" + del ), iEnd + 1 );
00624     if ( iFound >= 0 ) {
00625       iEnd = text.find( del, iFound + 1 ) + 1;
00626       strName = text.mid( iFound, iEnd - iFound );
00627 
00628       if ( strName != del + del ) {  //if not doubel-delimiter
00629         if ( iInMeth == 0 ) { //if input-method "single" is selected
00630           if ( mapVar[strName].length() <= 0 ) {  // and not already in map
00631             strMsg = i18n( "Please enter the value for <b>%1</b>:" ).arg( strName );
00632             strNew = showSingleVarDialog( strName, &_mapSaved, rSingle );
00633             if ( strNew == "" ) {
00634               return ""; //user clicked Cancel
00635             }
00636           } else {
00637             continue; //we have already handled this variable
00638           }
00639         } else {
00640           strNew = ""; //for inputmode "multi" just reset new valaue
00641         }
00642       } else {
00643         strNew = del; //if double-delimiter -> replace by single character
00644       }
00645 
00646       if ( iInMeth == 0 ) {  //if input-method "single" is selected
00647         str.replace( strName, strNew );
00648       }
00649 
00650       mapVar[strName] = strNew;
00651     }
00652   } while ( iFound != -1 );
00653 
00654   if ( iInMeth == 1 ) {  //check config, if input-method "multi" is selected
00655     int w, bh, oh;
00656     w = rMulti.width();
00657     bh = rMulti.height();
00658     oh = rMulti.top();
00659     if ( showMultiVarDialog( &mapVar, &_mapSaved, w, bh, oh ) ) {  //generate and show the dialog
00660       QMap<QString, QString>::Iterator it;
00661       for ( it = mapVar.begin(); it != mapVar.end(); ++it ) {
00662         //walk through the map and do the replacement
00663         str.replace( it.key(), it.data() );
00664       }
00665     } else {
00666       return "";
00667     }
00668 
00669     rMulti.setWidth( w );   //this is a hack to save the dialog's dimensions in only one QRect
00670     rMulti.setHeight( bh );
00671     rMulti.setTop( oh );
00672     rMulti.setLeft( 0 );
00673     _SnippetConfig.setMultiRect( rMulti );
00674   }
00675 
00676   _SnippetConfig.setSingleRect( rSingle );
00677 
00678   return str;
00679 }
00680 
00681 //  fn SnippetWidget::showMultiVarDialog()
00687 bool SnippetWidget::showMultiVarDialog( QMap<QString,QString> *map, QMap<QString,QString> *mapSave,
00688                                         int &iWidth, int &iBasicHeight, int &iOneHeight )
00689 {
00690   //if no var -> no need to show
00691   if ( map->count() == 0 ) {
00692     return true;
00693   }
00694 
00695   //if only var is the double-delimiter -> no need to show
00696   QMap<QString, QString>::Iterator it = map->begin();
00697   if ( map->count() == 1 &&
00698        it.data() == _SnippetConfig.getDelimiter() + _SnippetConfig.getDelimiter() ) {
00699     return true;
00700   }
00701 
00702   QMap<QString, KTextEdit *> mapVar2Te;  // track which TEXTEDIT goes with which variable
00703   QMap<QString, QCheckBox *> mapVar2Cb;  // track which CHECKBOX goes with which variable
00704 
00705   // --BEGIN-- building a dynamic dialog
00706   QDialog dlg( this );
00707   dlg.setCaption( i18n( "Enter Values for Variables" ) );
00708 
00709   QGridLayout *layout = new QGridLayout( &dlg, 1, 1, 11, 6, "layout" );
00710   QGridLayout *layoutTop = new QGridLayout( 0, 1, 1, 0, 6, "layoutTop" );
00711   QGridLayout *layoutVar = new QGridLayout( 0, 1, 1, 0, 6, "layoutVar" );
00712   QGridLayout *layoutBtn = new QGridLayout( 0, 1, 1, 0, 6, "layoutBtn" );
00713 
00714   KTextEdit *te = NULL;
00715   QLabel *labTop = NULL;
00716   QCheckBox *cb = NULL;
00717 
00718   labTop = new QLabel( &dlg, "label" );
00719   labTop->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0,
00720                                       labTop->sizePolicy().hasHeightForWidth() ) );
00721   labTop->setText( i18n( "Enter the replacement values for these variables:" ) );
00722   layoutTop->addWidget( labTop, 0, 0 );
00723   layout->addMultiCellLayout( layoutTop, 0, 0, 0, 1 );
00724 
00725   int i = 0;
00726   for ( it = map->begin(); it != map->end(); ++it ) {
00727     if ( it.key() == _SnippetConfig.getDelimiter() + _SnippetConfig.getDelimiter() ) {
00728       continue;
00729     }
00730 
00731     cb = new QCheckBox( &dlg, "cbVar" );
00732     cb->setChecked( FALSE );
00733     cb->setText( it.key() );
00734     layoutVar->addWidget( cb, i, 0, Qt::AlignTop );
00735 
00736     te = new KTextEdit( &dlg, "teVar" );
00737     layoutVar->addWidget( te, i, 1, Qt::AlignTop );
00738 
00739     if ( (*mapSave)[it.key()].length() > 0 ) {
00740       cb->setChecked( TRUE );
00741       te->setText( (*mapSave)[it.key()] );
00742     }
00743 
00744     mapVar2Te[it.key()] = te;
00745     mapVar2Cb[it.key()] = cb;
00746 
00747     QToolTip::add(
00748       cb,
00749       i18n( "Enable this to save the value entered to the right "
00750             "as the default value for this variable" ) );
00751     QWhatsThis::add(
00752       cb,
00753       i18n( "If you enable this option, the value entered to the right will be saved. "
00754             "If you use the same variable later, even in another snippet, the value entered "
00755             "to the right will be the default value for that variable." ) );
00756 
00757     i++;
00758   }
00759   layout->addMultiCellLayout( layoutVar, 1, 1, 0, 1 );
00760 
00761   KPushButton * btn1 = new KPushButton( KStdGuiItem::cancel(), &dlg, "pushButton1" );
00762   btn1->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0,
00763                                     btn1->sizePolicy().hasHeightForWidth() ) );
00764   layoutBtn->addWidget( btn1, 0, 0 );
00765 
00766   KPushButton * btn2 = new KPushButton( KStdGuiItem::apply(), &dlg, "pushButton2" );
00767   btn2->setDefault( TRUE );
00768   btn2->setSizePolicy( QSizePolicy( (QSizePolicy::SizeType)1, (QSizePolicy::SizeType)0, 0, 0,
00769                                     btn2->sizePolicy().hasHeightForWidth() ) );
00770   layoutBtn->addWidget( btn2, 0, 1 );
00771 
00772   layout->addMultiCellLayout( layoutBtn, 2, 2, 0, 1 );
00773   // --END-- building a dynamic dialog
00774 
00775   //connect the buttons to the QDialog default slots
00776   connect( btn1, SIGNAL(clicked()), &dlg, SLOT(reject()) );
00777   connect( btn2, SIGNAL(clicked()), &dlg, SLOT(accept()) );
00778 
00779   //prepare to execute the dialog
00780   bool bReturn = false;
00781   //resize the textedits
00782   if ( iWidth > 1 ) {
00783     QRect r = dlg.geometry();
00784     r.setHeight( iBasicHeight + iOneHeight * mapVar2Te.count() );
00785     r.setWidth( iWidth );
00786     dlg.setGeometry( r );
00787   }
00788   if ( i > 0 && // only if there are any variables
00789     dlg.exec() == QDialog::Accepted ) {
00790 
00791     QMap<QString, KTextEdit *>::Iterator it2;
00792     for ( it2 = mapVar2Te.begin(); it2 != mapVar2Te.end(); ++it2 ) {
00793       if ( it2.key() == _SnippetConfig.getDelimiter() + _SnippetConfig.getDelimiter() ) {
00794         continue;
00795       }
00796       (*map)[it2.key()] = it2.data()->text();    //copy the entered values back to the given map
00797 
00798       if ( mapVar2Cb[it2.key()]->isChecked() ) { //if the checkbox is on; save the values for later
00799         (*mapSave)[it2.key()] = it2.data()->text();
00800       } else {
00801         (*mapSave).erase( it2.key() );
00802       }
00803     }
00804     bReturn = true;
00805 
00806     iBasicHeight = dlg.geometry().height() - layoutVar->geometry().height();
00807     iOneHeight = layoutVar->geometry().height() / mapVar2Te.count();
00808     iWidth = dlg.geometry().width();
00809   }
00810 
00811   //do some cleanup
00812   QMap<QString, KTextEdit *>::Iterator it1;
00813   for ( it1 = mapVar2Te.begin(); it1 != mapVar2Te.end(); ++it1 ) {
00814     delete it1.data();
00815   }
00816   mapVar2Te.clear();
00817   QMap<QString, QCheckBox *>::Iterator it2;
00818   for ( it2 = mapVar2Cb.begin(); it2 != mapVar2Cb.end(); ++it2 ) {
00819     delete it2.data();
00820   }
00821   mapVar2Cb.clear();
00822   delete layoutTop;
00823   delete layoutVar;
00824   delete layoutBtn;
00825   delete layout;
00826 
00827   if ( i == 0 ) { //if nothing happened this means, that there are no variables to translate
00828     return true; //.. so just return OK
00829   }
00830   return bReturn;
00831 //  return true;
00832 }
00833 
00834 //  fn SnippetWidget::showSingleVarDialog(QString var, QMap<QString, QString> * mapSave)
00839 QString SnippetWidget::showSingleVarDialog( QString var, QMap<QString, QString> *mapSave,
00840                                             QRect &dlgSize )
00841 {
00842   // --BEGIN-- building a dynamic dialog
00843   QDialog dlg( this );
00844   dlg.setCaption( i18n( "Enter Values for Variables" ) );
00845 
00846   QGridLayout *layout = new QGridLayout( &dlg, 1, 1, 11, 6, "layout" );
00847   QGridLayout *layoutTop = new QGridLayout( 0, 1, 1, 0, 6, "layoutTop" );
00848   QGridLayout *layoutVar = new QGridLayout( 0, 1, 1, 0, 6, "layoutVar" );
00849   QGridLayout *layoutBtn = new QGridLayout( 0, 2, 1, 0, 6, "layoutBtn" );
00850 
00851   KTextEdit *te = NULL;
00852   QLabel * labTop = NULL;
00853   QCheckBox * cb = NULL;
00854 
00855   labTop = new QLabel( &dlg, "label" );
00856   layoutTop->addWidget( labTop, 0, 0 );
00857   labTop->setText( i18n( "Enter the replacement values for %1:" ).arg( var ) );
00858   layout->addMultiCellLayout( layoutTop, 0, 0, 0, 1 );
00859 
00860   cb = new QCheckBox( &dlg, "cbVar" );
00861   cb->setChecked( FALSE );
00862   cb->setText( i18n( "Make value &default" ) );
00863 
00864   te = new KTextEdit( &dlg, "teVar" );
00865   layoutVar->addWidget( te, 0, 1, Qt::AlignTop );
00866   layoutVar->addWidget( cb, 1, 1, Qt::AlignTop );
00867   if ( (*mapSave)[var].length() > 0 ) {
00868     cb->setChecked( TRUE );
00869     te->setText((*mapSave)[var]);
00870   }
00871 
00872   QToolTip::add(
00873     cb,
00874     i18n( "Enable this to save the value entered to the right "
00875           "as the default value for this variable" ) );
00876   QWhatsThis::add(
00877     cb,
00878     i18n( "If you enable this option, the value entered to the right will be saved. "
00879           "If you use the same variable later, even in another snippet, the value entered "
00880           "to the right will be the default value for that variable." ) );
00881 
00882   layout->addMultiCellLayout( layoutVar, 1, 1, 0, 1 );
00883 
00884   KPushButton * btn1 = new KPushButton( KStdGuiItem::cancel(), &dlg, "pushButton1" );
00885   layoutBtn->addWidget( btn1, 0, 0 );
00886 
00887   KPushButton * btn2 = new KPushButton( KStdGuiItem::apply(), &dlg, "pushButton2" );
00888   btn2->setDefault( TRUE );
00889   layoutBtn->addWidget( btn2, 0, 1 );
00890 
00891   layout->addMultiCellLayout( layoutBtn, 2, 2, 0, 1 );
00892   te->setFocus();
00893   // --END-- building a dynamic dialog
00894 
00895   //connect the buttons to the QDialog default slots
00896   connect( btn1, SIGNAL(clicked()), &dlg, SLOT(reject()) );
00897   connect( btn2, SIGNAL(clicked()), &dlg, SLOT(accept()) );
00898 
00899   //execute the dialog
00900   QString strReturn = "";
00901   if ( dlgSize.isValid() ) {
00902     dlg.setGeometry( dlgSize );
00903   }
00904   if ( dlg.exec() == QDialog::Accepted ) {
00905     if ( cb->isChecked() ) {
00906       //if the checkbox is on; save the values for later
00907       (*mapSave)[var] = te->text();
00908     } else {
00909       (*mapSave).erase(var);
00910     }
00911     strReturn = te->text();    //copy the entered values back the the given map
00912     dlgSize = dlg.geometry();
00913   }
00914 
00915   //do some cleanup
00916   delete cb;
00917   delete te;
00918   delete labTop;
00919   delete btn1;
00920   delete btn2;
00921   delete layoutTop;
00922   delete layoutVar;
00923   delete layoutBtn;
00924   delete layout;
00925 
00926   return strReturn;
00927 }
00928 
00929 //  fn SnippetWidget::acceptDrag (QDropEvent *event) const
00936 bool SnippetWidget::acceptDrag( QDropEvent *event ) const
00937 {
00938   //kdDebug(5006) << "Format: " << event->format() << "" << event->pos() << endl;
00939 
00940   QListViewItem *item = itemAt( event->pos() );
00941 
00942   if ( item &&
00943        QString( event->format() ).startsWith( "text/plain" ) &&
00944        static_cast<SnippetWidget *>( event->source() ) != this ) {
00946     return TRUE;
00947   } else if ( item &&
00948               QString( event->format() ).startsWith( "x-kmailsnippet" ) &&
00949               static_cast<SnippetWidget *>( event->source() ) != this ) {
00950     //kdDebug(5006) << "returning TRUE " << endl;
00951     return TRUE;
00952   } else {
00953     //kdDebug(5006) << "returning FALSE" << endl;
00954     event->acceptAction( FALSE );
00955     return FALSE;
00956   }
00957 }
00958 
00959 //  fn SnippetWidget::slotDropped(QDropEvent *e, QListViewItem *after)
00965 void SnippetWidget::slotDropped( QDropEvent *e, QListViewItem * )
00966 {
00967   QListViewItem *item2 = itemAt( e->pos() );
00968 
00969   SnippetGroup *group = dynamic_cast<SnippetGroup *>( item2 );
00970   if ( !group ) {
00971     group = dynamic_cast<SnippetGroup *>( item2->parent() );
00972   }
00973 
00974   QCString dropped;
00975   QByteArray data = e->encodedData( "text/plain" );
00976   if ( e->provides( "text/plain" ) && data.size() > 0 ) {
00977     //get the data from the event...
00978     QString encData( data.data() );
00979     //kdDebug(5006) << "encData: " << encData << endl;
00980 
00981     //... then fill the dialog with the given data
00982     SnippetDlg dlg( mActionCollection, this, "SnippetDlg" );
00983     dlg.snippetName->clear();
00984     dlg.snippetText->setText( encData );
00985 
00986     /*fill the combobox with the names of all SnippetGroup entries*/
00987     for ( SnippetItem *it=_list.first(); it; it=_list.next() ) {
00988       if ( dynamic_cast<SnippetGroup*>( it ) ) {
00989         dlg.cbGroup->insertItem( it->getName() );
00990       }
00991     }
00992     dlg.cbGroup->setCurrentText( group->getName() );
00993 
00994     if ( dlg.exec() == QDialog::Accepted ) {
00995       /* get the group that the user selected with the combobox */
00996       group = dynamic_cast<SnippetGroup*>(
00997         SnippetItem::findItemByName( dlg.cbGroup->currentText(), _list ) );
00998       _list.append( makeItem( group, dlg.snippetName->text(), dlg.snippetText->text(),
00999                               dlg.shortcutButton->shortcut() ) );
01000     }
01001   }
01002 }
01003 
01004 void SnippetWidget::startDrag()
01005 {
01006   QString text = dynamic_cast<SnippetItem*>( currentItem() )->getText();
01007   QTextDrag *drag = new QTextDrag( text, this );
01008   drag->setSubtype( "x-textsnippet" );
01009   drag->drag();
01010 }
01011 
01012 void SnippetWidget::slotExecute()
01013 {
01014   slotExecuted( currentItem() );
01015 }
01016 
01017 #include "snippetwidget.moc"
01018 
KDE Home | KDE Accessibility Home | Description of Access Keys