/***************************************************************************
 *   snippet feature from kdevelop/plugins/snippet/                        *
 *                                                                         *
 *   Copyright (C) 2007 by Robert Gruber                                   *
 *   rgruber@users.sourceforge.net                                         *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "snippetwidget.h"
#include "snippetitem.h"
#include "snippetdlg.h"
#include "autoqpointer.h"

#include <kdebug.h>
#include <klocale.h>
#include <kpushbutton.h>
#include <kmessagebox.h>
#include <ktexteditor/editor.h>
#include <ktexteditor/view.h>
#include <ktexteditor/document.h>
#include <kconfig.h>
#include <kmenu.h>
#include <kcombobox.h>
#include <kiconloader.h>
#include <kshortcut.h>
#include <kaction.h>
#include <kactioncollection.h>
#include <kkeysequencewidget.h>

#include <qlayout.h>
#include <qheaderview.h>
#include <qtooltip.h>
#include <qregexp.h>
#include <qlabel.h>
#include <qcheckbox.h>
#include <qwhatsthis.h>
#include <qdrag.h>
#include <QContextMenuEvent>
#include <qtimer.h>

#include <cassert>

SnippetWidget::SnippetWidget(KMeditor* editor, KActionCollection* actionCollection, QWidget* parent)
 : QTreeWidget( parent ),
   mEditor( editor ),
   mActionCollection( actionCollection )
{
    setObjectName("snippet widget");
    // init the QTreeWidget
    //setSorting( -1 );
    //setFullWidth(true);
    header()->hide();
    setAcceptDrops(true);
    setDragEnabled(true);
    //setDropVisualizer(false);
    setRootIsDecorated(true);
    setAlternatingRowColors( true );

    connect( this, SIGNAL( itemActivated (QTreeWidgetItem *, int) ),
             this, SLOT( slotEdit( QTreeWidgetItem *) ) );

//### in KDE 3 the enter key used to insert the snippet in the editor
//    (slotExecute()) but the enterPressed signal is gone. It is also a problem
//    that pressing enter on an item and double-clicking is supposed have the
//    exact same effect.

    connect( editor, SIGNAL( insertSnippet() ), this, SLOT( slotExecute() ));

    QTimer::singleShot(0, this, SLOT(readConfig()));
}

SnippetWidget::~SnippetWidget()
{
  writeConfig();

  /* We need to delete the child items before the parent items
     otherwise KMail would crash on exiting */
  int itemsLeft = _list.count();
  while (itemsLeft) {
    for (int i = 0; i < _list.count(); i++) {
      if (_list[i] && _list[i]->childCount() == 0) {
        delete _list[i];
        _list[i] = 0;
        itemsLeft--;
      }
    }
  }
}


/*!
    Opens the dialog to add a snippet
 */
void SnippetWidget::slotAdd()
{
  //kDebug() << "Ender slotAdd()";
  AutoQPointer<SnippetDlg> dlg( new SnippetDlg( mActionCollection, this ) );
  dlg->setObjectName( "SnippetDlg" );

  /*check if the user clicked a SnippetGroup
    If not, we set the group variable to the SnippetGroup
    which the selected item is a child of*/
  SnippetGroup * group = dynamic_cast<SnippetGroup*>(selectedItem());
  if ( !group && selectedItem() )
    group = dynamic_cast<SnippetGroup*>(selectedItem()->parent());

  /* still no group, let's make a default one */
  if (!group ) {
    if ( _list.isEmpty() ) {
      group = new SnippetGroup(this
        , i18nc( "@label:listbox General group for often used snippets in mail.", "General")
        , SnippetGroup::getMaxId() );
      _list.append( group );
    } else {
      group = dynamic_cast<SnippetGroup*>( _list.first() );
    }
  }
  assert( group );

  /*fill the combobox with the names of all SnippetGroup entries*/
  foreach (SnippetItem *item, _list) {
    if (dynamic_cast<SnippetGroup*>(item)) {
      dlg->cbGroup->addItem(item->getName());
    }
  }
  dlg->cbGroup->setCurrentIndex( dlg->cbGroup->findText( group->getName() ) );

  if ( dlg->exec() == KDialog::Accepted && dlg ) {
      group = dynamic_cast<SnippetGroup*>(SnippetItem::findItemByName(dlg->cbGroup->currentText(), _list));
      _list.append( makeItem( group, dlg->snippetName->text(),
                              dlg->snippetText->toPlainText(),
                              dlg->keyWidget->keySequence() ) );
  }
}

SnippetItem* SnippetWidget::makeItem( SnippetItem *parent, const QString &name,
                                      const QString &text, const QKeySequence &keySeq )
{
  SnippetItem *item = new SnippetItem( parent, name, text );
  const QString actionName = i18n( "Snippet %1", name );
  const QString normalizedName = QString( actionName ).replace( ' ', '_' );
  item->setToolTip( 0, text );
  if ( !mActionCollection->action( normalizedName ) ) {
    KAction *action = mActionCollection->addAction( normalizedName,
                                                        item, SLOT( slotExecute() ) );
    action->setText( actionName );
    action->setShortcut( keySeq );
    item->setAction( action );
    connect( item, SIGNAL( execute( QTreeWidgetItem* ) ),
             this, SLOT( slotExecuted( QTreeWidgetItem* ) ) );
  }
  return item;
}

/*!
    Opens the dialog to add a snippet
 */
void SnippetWidget::slotAddGroup()
{
  //kDebug() << "Ender slotAddGroup()";
  AutoQPointer<SnippetDlg> dlg( new SnippetDlg( mActionCollection, this ) );
  dlg->setObjectName( "SnippetDlg" );
  dlg->setGroupMode( true );
  dlg->setWindowTitle( i18n("Add Group") );

  if ( dlg->exec() == KDialog::Accepted && dlg ) {
    _list.append( new SnippetGroup(this, dlg->snippetName->text(), SnippetGroup::getMaxId() ) );
  }
}


/*!
    Removes the selected snippet
 */
void SnippetWidget::slotRemove()
{
  //get current data
  QTreeWidgetItem * item = currentItem();
  SnippetItem *snip = dynamic_cast<SnippetItem*>( item );
  if (!snip)
    return;
  SnippetGroup *group = dynamic_cast<SnippetGroup*>( item );
  if (group) {
    if (group->childCount() > 0 &&
        KMessageBox::warningContinueCancel(this, i18n("Do you really want to remove this group and all its snippets?"),QString(), KStandardGuiItem::del())
        == KMessageBox::Cancel)
      return;

    for ( int i = 0; i < _list.size(); i++ ) {
      if (_list[i]->getParent() == group->getId()) {
        delete _list.takeAt( i-- );
      }
    }
  }

  //kDebug() << "remove " << snip->getName();
  int snipIndex = _list.indexOf(snip);
  if (snipIndex > -1)
    delete _list.takeAt(snipIndex);
}



/*!
    Opens the dialog of editing the selected snippet
 */
void SnippetWidget::slotEdit( QTreeWidgetItem* item )
{
  if( item == 0 ) {
    item = currentItem();
  }

  SnippetGroup *pGroup = dynamic_cast<SnippetGroup*>(item);
  SnippetItem *pSnippet = dynamic_cast<SnippetItem*>( item );
  if (!pSnippet || pGroup) /*selected item must be a SnippetItem but MUST not be a SnippetGroup*/
    return;

  //init the dialog
  AutoQPointer<SnippetDlg> dlg( new SnippetDlg( mActionCollection, this ) );
  dlg->setObjectName( "SnippetDlg" );
  dlg->snippetName->setText(pSnippet->getName());
  dlg->snippetText->setText(pSnippet->getText());
  dlg->btnAdd->setText(i18n("&Apply"));
  if ( pSnippet->getAction() )
    dlg->keyWidget->setKeySequence( pSnippet->getAction()->shortcut().primary() );

  dlg->setWindowTitle(i18n("Edit Snippet"));
  /*fill the combobox with the names of all SnippetGroup entries*/
  foreach (SnippetItem *item, _list) {
    if (dynamic_cast<SnippetGroup*>(item)) {
      dlg->cbGroup->addItem( item->getName() );
    }
  }
  QString parentGroupText =
      SnippetItem::findGroupById( pSnippet->getParent(), _list )->getName();
  dlg->cbGroup->setCurrentIndex( dlg->cbGroup->findText( parentGroupText ) );

  if ( dlg->exec() == KDialog::Accepted && dlg ) {
    //update the QListView and the SnippetItem
    item->setText( 0, dlg->snippetName->text() );
    pSnippet->setName( dlg->snippetName->text() );
    pSnippet->setText( dlg->snippetText->toPlainText() );
    pSnippet->setToolTip( 0, pSnippet->getText() );
    if ( pSnippet->getAction() )
      pSnippet->getAction()->setShortcut( dlg->keyWidget->keySequence());

    /* if the user changed the parent we need to move the snippet */
    if ( SnippetItem::findGroupById(pSnippet->getParent(), _list)->getName() != dlg->cbGroup->currentText() ) {
      SnippetGroup * newGroup = dynamic_cast<SnippetGroup*>(SnippetItem::findItemByName(dlg->cbGroup->currentText(), _list));
      pSnippet->parent()->removeChild(pSnippet);
      newGroup->addChild(pSnippet);
      pSnippet->resetParent();
    }

    item->setSelected( true );
  }
}

/*!
    Opens the dialog of editing the selected snippet-group
 */
void SnippetWidget::slotEditGroup()
{
  //get current data
  QTreeWidgetItem * item = currentItem();

  SnippetGroup *pGroup = dynamic_cast<SnippetGroup*>( item );
  if (!pGroup) /*selected item MUST be a SnippetGroup*/
    return;

  //init the dialog
  AutoQPointer<SnippetDlg> dlg( new SnippetDlg( mActionCollection, this ) );
  dlg->setObjectName( "SnippetDlg" );
  dlg->setGroupMode( true );
  dlg->snippetName->setText(pGroup->getName());
  dlg->btnAdd->setText(i18n("&Apply"));
  dlg->setWindowTitle(i18n("Edit Group"));

  if ( dlg->exec() == KDialog::Accepted && dlg ) {
    //update the QListView and the SnippetGroup
    item->setText( 0, dlg->snippetName->text() );
    pGroup->setName( dlg->snippetName->text() );

    item->setSelected( true );
  }
}

void SnippetWidget::slotExecuted(QTreeWidgetItem * item)
{
  if( item == 0 ) {
    item = currentItem();
  }

  SnippetItem *pSnippet = dynamic_cast<SnippetItem*>( item );
  if (!pSnippet || dynamic_cast<SnippetGroup*>(item))
      return;

  //process variables if any, then insert into the active view
  insertIntoActiveView( parseText( pSnippet->getText() ) );
}


/*!
    Inserts the parameter text into the active view
 */
void SnippetWidget::insertIntoActiveView( const QString &text )
{
  mEditor->insertPlainText( text );
}


/*!
    Write the config file
 */
void SnippetWidget::writeConfig()
{
  if( !_cfg )
    return;
  _cfg->deleteGroup("SnippetPart");  //this is necessary otherwise delete entries will stay in list until
                                     //they get overwritten by a more recent entry
  KConfigGroup kcg = _cfg->group("SnippetPart");

  QString strKeyName="";
  QString strKeyText="";
  QString strKeyId="";

  int iSnipCount = 0;
  int iGroupCount = 0;

  foreach ( SnippetItem *const item, _list ) {  //write the snippet-list
    SnippetGroup * group = dynamic_cast<SnippetGroup*>(item);
    if (group) {
      strKeyName=QString("snippetGroupName_%1").arg(iGroupCount);
      strKeyId=QString("snippetGroupId_%1").arg(iGroupCount);

      kcg.writeEntry(strKeyName, group->getName());
      kcg.writeEntry(strKeyId, group->getId());

      iGroupCount++;
    } else if (dynamic_cast<SnippetItem*>(item)) {
      strKeyName=QString("snippetName_%1").arg(iSnipCount);
      strKeyText=QString("snippetText_%1").arg(iSnipCount);
      strKeyId=QString("snippetParent_%1").arg(iSnipCount);

      kcg.writeEntry(strKeyName, item->getName());
      kcg.writeEntry(strKeyText, item->getText());
      kcg.writeEntry(strKeyId, item->getParent());

      KAction * action = item->getAction();
      if ( action ) {
        const KShortcut& sc = action->shortcut();
        if (!sc.isEmpty() ) {
          kcg.writeEntry( QString("snippetShortcut_%1").arg(iSnipCount), sc.toString() );
        }
      }
      iSnipCount++;
    } else {
    }
  }
  kcg.writeEntry("snippetCount", iSnipCount);
  kcg.writeEntry("snippetGroupCount", iGroupCount);

  int iCount = 1;
  QMap<QString, QString>::Iterator it;
  for ( it = _mapSaved.begin(); it != _mapSaved.end(); ++it ) {  //write the saved variable values
    if (it.value().length()<=0) continue;  //is the saved value has no length -> no need to save it

    strKeyName=QString("snippetSavedName_%1").arg(iCount);
    strKeyText=QString("snippetSavedVal_%1").arg(iCount);

    kcg.writeEntry(strKeyName, it.key());
    kcg.writeEntry(strKeyText, it.value());

    iCount++;
  }
  kcg.writeEntry("snippetSavedCount", iCount-1);
  kcg.sync();
}

/*!
    Initial read the config file
 */
void SnippetWidget::readConfig()
{
  if ( !_cfg )
    _cfg = KSharedConfig::openConfig( "kmailsnippetrc", KConfig::NoGlobals );

  KConfigGroup kcg = _cfg->group("SnippetPart");

  QString strKeyName;
  QString strKeyText;
  QString strKeyId;
  SnippetItem *item;
  SnippetGroup *group;

  //kDebug();

  //if entry doesn't get found, this will return -1 which we will need a bit later
  int iCount = kcg.readEntry("snippetGroupCount", -1);

  for ( int i=0; i<iCount; i++) {  //read the group-list
    strKeyName=QString("snippetGroupName_%1").arg(i);
    strKeyId=QString("snippetGroupId_%1").arg(i);

    QString strNameVal;
    int iIdVal=-1;

    strNameVal = kcg.readEntry(strKeyName, "");
    iIdVal = kcg.readEntry(strKeyId, -1);
    //kDebug() << "Read group "  << " " << iIdVal;

    if ( !strNameVal.isEmpty() && iIdVal != -1 ) {
      group = new SnippetGroup(this, strNameVal, iIdVal);
      //kDebug() << "Created group " << group->getName() << " " << group->getId();
      _list.append(group);

      // the assumption is that there are usually only a few groups/snippets, so better
      // show them directly which makes accessing them simpler
      group->setExpanded(true);
    }
  }

  /* Check if the snippetGroupCount property has been found
     if iCount is -1 this means, that the user has his snippets
     stored without groups.
     Should only happen with an empty config file.
  */

  if (iCount != -1) {
    iCount = kcg.readEntry("snippetCount", 0);
    for ( int i=0; i<iCount; i++) {  //read the snippet-list
        strKeyName=QString("snippetName_%1").arg(i);
        strKeyText=QString("snippetText_%1").arg(i);
        strKeyId=QString("snippetParent_%1").arg(i);

        QString strNameVal;
        QString strTextVal;
        int iParentVal = -1;

        strNameVal = kcg.readEntry(strKeyName, "");
        strTextVal = kcg.readEntry(strKeyText, "");
        iParentVal = kcg.readEntry(strKeyId, -1);
        //kDebug() << "Read item " << strNameVal << " " << iParentVal;

        if ( !strNameVal.isEmpty() && !strTextVal.isEmpty() && iParentVal != -1) {
            KShortcut shortcut( kcg.readEntry( QString("snippetShortcut_%1").arg(i), QString() ) );
            item = makeItem( SnippetItem::findGroupById( iParentVal, _list ), strNameVal, strTextVal, shortcut.primary() );
            //kDebug() << "Created item " << item->getName() << " " << item->getParent();
            _list.append(item);
        }
    }
  } else {
  }

  iCount = kcg.readEntry("snippetSavedCount", 0);

  for ( int i=1; i<=iCount; i++) {  //read the saved-values and store in QMap
    strKeyName=QString("snippetSavedName_%1").arg(i);
    strKeyText=QString("snippetSavedVal_%1").arg(i);

    QString strNameVal="";
    QString strTextVal="";

    strNameVal = kcg.readEntry(strKeyName, "");
    strTextVal = kcg.readEntry(strKeyText, "");

    if (!strNameVal.isEmpty() && !strTextVal.isEmpty()) {
      _mapSaved[strNameVal] = strTextVal;
    }
  }
}


/*!
 * Shows the Popup-Menu if there is an item where the event occurred
*/
void SnippetWidget::contextMenuEvent( QContextMenuEvent *e )
{
    KMenu popup;

    SnippetItem *item = static_cast<SnippetItem *>(itemAt(e->pos()));
    if ( item ) {
        popup.addTitle( item->getName() );
        if (dynamic_cast<SnippetGroup*>(item)) {
            popup.addAction( i18n("Edit &group..."), this, SLOT( slotEditGroup() ) );
        } else {
            popup.addAction( KIcon("edit-paste"), i18n("&Paste"),
                             this, SLOT( slotExecuted() ) );
            popup.addAction( KIcon("document-properties"), i18n("&Edit..."),
                             this, SLOT( slotEdit() ) );
        }
        popup.addAction( KIcon("edit-delete"), i18n("&Remove"),
                         this, SLOT( slotRemove() ) );
        popup.addSeparator();
    } else {
        popup.addTitle(i18n("Text Snippets"));
    }
    popup.addAction( i18n("&Add Snippet..."), this, SLOT( slotAdd() ) );
    popup.addAction( i18n("Add G&roup..."), this, SLOT( slotAddGroup() ) );

    popup.exec(e->globalPos());
}

/*!
    This function is used to parse the given QString for variables. If found the user will be prompted
    for a replacement value. It returns the string text with all replacements made
 */
QString SnippetWidget::parseText( const QString &text )
{
  QString str = text;
  QString strName;
  QString strNew;
  QString strMsg;
  int iFound = -1;
  int iEnd = -1;
  QMap<QString, QString> mapVar;

  do {
    iFound = text.indexOf(QRegExp("\\$[A-Za-z-_0-9\\s]*\\$"), iEnd+1);  //find the next variable by this QRegExp
    if (iFound >= 0) {
      iEnd = text.indexOf('$', iFound+1)+1;
      strName = text.mid(iFound, iEnd-iFound);

      if ( strName != QString('$') + QString('$') ) {  //if not doubel-delimiter
        if ( mapVar[strName].length() <= 0 ) {  // and not already in map
          strMsg = i18n( "Please enter the value for <b>%1</b>:", strName );
          strNew = showSingleVarDialog( strName, &_mapSaved );
          if ( strNew.isEmpty() )
            return QString(); //user clicked Cancel
        } else {
          continue; //we have already handled this variable
        }
      }
      else {
        strNew = '$'; //if double-delimiter -> replace by single character
      }

      str.replace(strName, strNew);
      mapVar[strName] = strNew;
    }
  } while ( iFound != -1 );

  return str;
}

/*!
    This function constructs a dialog which contains a label and a linedit for the given variable
    It return either the entered value or an empty string if the user hit cancel
 */
QString SnippetWidget::showSingleVarDialog( const QString &var, QMap<QString, QString> *mapSave )
{
  // --BEGIN-- building a dynamic dialog
  AutoQPointer<QDialog> dlg( new QDialog( this ) );  // don't fix this krazy issues without actually trying the code!
  dlg->setWindowTitle(i18n("Enter Values for Variables"));

  QGridLayout * layout = new QGridLayout( dlg );
  QGridLayout * layoutTop = new QGridLayout();
  QGridLayout * layoutVar = new QGridLayout();
  QGridLayout * layoutBtn = new QGridLayout();
  layout->setMargin( 11 );
  layout->setSpacing( 6 );
  layoutTop->setMargin( 0 );
  layoutTop->setSpacing( 6 );
  layoutVar->setMargin( 0 );
  layoutVar->setSpacing( 6 );
  layoutBtn->setMargin( 0 );
  layoutBtn->setSpacing( 6 );
  layout->setObjectName( "layout" );
  layoutTop->setObjectName( "layoutTop" );
  layoutVar->setObjectName( "layoutVar" );
  layoutBtn->setObjectName( "layoutBtn" );

  KTextEdit * te = NULL;
  QLabel * labTop = NULL;
  QCheckBox * cb = NULL;

  labTop = new QLabel( dlg );
  labTop->setObjectName( "label" );
  layoutTop->addWidget(labTop, 0, 0);
  labTop->setText( i18n("Enter the replacement values for %1:", var) );
  layout->addLayout( layoutTop, 0, 0, 1, 2 );


  cb = new QCheckBox( dlg );
  cb->setObjectName( "cbVar" );
  cb->setChecked( false );
  cb->setText(i18n( "Make value &default" ));

  te = new KTextEdit( dlg );
  te->setObjectName( "teVar" );
  layoutVar->addWidget( te, 0, 1, Qt::AlignTop);
  layoutVar->addWidget( cb, 1, 1, Qt::AlignTop);
  if ((*mapSave)[var].length() > 0) {
    cb->setChecked( true );
    te->setText((*mapSave)[var]);
  }

  cb->setToolTip( i18n("Enable this to save the value entered to the right as the default value for this variable") );
  cb->setWhatsThis( i18n("If you enable this option, the value entered to the right will be saved. "
                         "If you use the same variable later, even in another snippet, the value entered to the right "
                         "will be the default value for that variable.") );

  layout->addLayout( layoutVar, 1, 0, 1, 2 );

  KPushButton * btn1 = new KPushButton( KStandardGuiItem::cancel(), dlg );
  btn1->setObjectName( "pushButton1") ;
  layoutBtn->addWidget( btn1, 0, 0 );

  KPushButton * btn2 = new KPushButton( KStandardGuiItem::apply(), dlg );
  btn2->setObjectName( "pushButton2") ;
  btn2->setDefault( true );
  layoutBtn->addWidget( btn2, 0, 1 );

  layout->addLayout( layoutBtn, 2, 0, 1, 2 );
  te->setFocus();
  // --END-- building a dynamic dialog

  //connect the buttons to the KDialog default slots
  connect(btn1, SIGNAL(clicked()), dlg, SLOT(reject()) );
  connect(btn2, SIGNAL(clicked()), dlg, SLOT(accept()) );

  //execute the dialog
  QString strReturn = "";
  if ( dlg->exec() == KDialog::Accepted && dlg ) {
    if (cb->isChecked())     //if the checkbox is on; save the values for later
      (*mapSave)[var] = te->toPlainText();
    else
      (*mapSave).remove(var);

    strReturn = te->toPlainText();    //copy the entered values back to the given map
  }

  // AutoQPointer will delete dlg when it goes out of scope.
  // Previously all widgets were deleted here but this should be enough.
  // - all widgets as well as the main layout are child to the dialog and
  //   get deleted automatically
  // - all sub-layouts are child to the main layout and get deleted
  //   automatically.

  return strReturn;
}


/*!
    Emulate Qt3's selectedItem() because it does exactly what we need here.
*/
QTreeWidgetItem * SnippetWidget::selectedItem() const
{
  if ( selectedItems().isEmpty() )
    return 0;
  return currentItem();
}


/*!
    Check here if the data the user is about to drop fits our restrictions.
    We only accept dropps of plaintext, because from the dropped text
    we will create a snippet.
 */
void SnippetWidget::dragMoveEvent( QDragMoveEvent * event )
{
  QTreeWidgetItem * item = itemAt(event->pos());

  if (item &&
      event->mimeData()->hasText() &&
      static_cast<SnippetWidget *>(event->source()) != this) {
    event->setDropAction( Qt::CopyAction );
    event->accept();
  } else {
    event->ignore();
  }
}

void SnippetWidget::dragEnterEvent( QDragEnterEvent * event )
{
  if ( event->mimeData()->hasFormat("text/x-kmail-textsnippet") ||
       event->mimeData()->hasText() ) {
    event->setDropAction( Qt::CopyAction );
    event->accept();
  }
}

void SnippetWidget::dropEvent( QDropEvent * event )
{
  QTreeWidgetItem * item = itemAt( event->pos() );
  if ( !item || !event->mimeData()->hasText() ) {
    event->ignore();
    return;
  }
  else {
    event->setDropAction( Qt::CopyAction );
    event->accept();
  }

  SnippetItem *snippet = dynamic_cast<SnippetItem *>( item );
  SnippetGroup *group = dynamic_cast<SnippetGroup *>( item );
  SnippetGroup *parent = 0;
  if ( group )
    parent = group;
  else {
    assert( dynamic_cast<SnippetGroup*>( snippet->parent() ) );
    parent = static_cast<SnippetGroup*>( snippet->parent() );
  }

  // fill the dialog with the given data
  AutoQPointer<SnippetDlg> dlg( new SnippetDlg( mActionCollection, this ) );
  dlg->setObjectName( "SnippetDlg" );
  dlg->snippetName->clear();
  dlg->snippetText->setText( event->mimeData()->text() );

  /*fill the combobox with the names of all SnippetGroup entries*/
  foreach ( SnippetItem *const si, _list ) {
    if ( dynamic_cast<SnippetGroup*>( si ) ) {
      dlg->cbGroup->addItem( si->getName() );
    }
  }
  dlg->cbGroup->setCurrentIndex( dlg->cbGroup->findText( parent->getName() ) );

  if ( dlg->exec() == KDialog::Accepted && dlg ) {
    /* get the group that the user selected with the combobox */
    group = dynamic_cast<SnippetGroup*>(
             SnippetItem::findItemByName( dlg->cbGroup->currentText(), _list ) );
    _list.append( makeItem( group, dlg->snippetName->text(),
                  dlg->snippetText->toPlainText(), dlg->keyWidget->keySequence() ) );
  }
}

void SnippetWidget::startDrag( Qt::DropActions supportedActions )
{
  Q_UNUSED( supportedActions );

  // Don't allow to drag groups around
  if ( dynamic_cast<SnippetGroup*>( currentItem() ) )
    return;

  QString text = static_cast<SnippetItem*>( currentItem() )->getText();
  if( text.isEmpty() )
    return;
  QDrag *drag = new QDrag( this );
  QMimeData *mimeData = new QMimeData();
  mimeData->setData( "text/x-kmail-textsnippet", text.toUtf8() );
  drag->setMimeData( mimeData );
  drag->exec();
}

void SnippetWidget::slotExecute()
{
  slotExecuted(currentItem());
}

#include "snippetwidget.moc"
