/* ****************************************************************************
  This file is part of KBabel

  Copyright (C) 2000 by Matthias Kiefer
                            <matthias.kiefer@gmx.de>
		2003-2005 by Stanislav Visnovsky
			    <visnovsky@kde.org>

  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.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

  In addition, as a special exception, the copyright holders give
  permission to link the code of this program with any edition of
  the TQt library by Trolltech AS, Norway (or with modified versions
  of TQt that use the same license as TQt), and distribute linked
  combinations including the two.  You must obey the GNU General
  Public License in all respects for all of the code used other than
  TQt. If you modify this file, you may extend this exception to
  your version of the file, but you are not obligated to do so.  If
  you do not wish to do so, delete this exception statement from
  your version.

**************************************************************************** */


#include <dcopclient.h>
#include <kaboutapplication.h>

#include "aboutmoduledlg.h"
#include "kbabeldictbox.h"
#include <version.h>
#include <resources.h>

#include <kaboutdata.h>
#include <kaboutdialog.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kcmenumngr.h>
#include <kdialogbase.h>
#include <klibloader.h>
#include <klistview.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kglobal.h>
#include <kdebug.h>
#include <ktrader.h>
#include <kwin.h>

#include <tqclipboard.h>
#include <tqdir.h>
#include <tqlabel.h>
#include <tqlayout.h>
#include <tqpopupmenu.h>
#include <tqpushbutton.h>
#include <tqtextview.h>
#include <tqstylesheet.h>
#include <tqtoolbutton.h>
#include <tqwhatsthis.h>
#include <tqtimer.h>

#define KBABELDICT 5321

using namespace KBabel;

class ResultListItem : public TQListViewItem
{
public:
    ResultListItem(TQListView *parent, const SearchResult& result,bool richText);

    virtual TQString key(int column, bool ascending) const;
    const SearchResult* result() const;
    bool richText() const { return _richText; }

private:
    SearchResult _result;
    bool _richText;
};

ResultListItem::ResultListItem(TQListView *parent, const SearchResult& result
                , bool richText)
        : TQListViewItem(parent)
        , _result(result)
        , _richText(richText)
{
    int score=_result.score;
    if(score<0)
        score=0;
    else if(score>100)
        score=100;
    setText(0,TQString::number(score));
    
    TQString tmp;
    if(richText)
        tmp=_result.plainFound;
    else
	// FIXME: what about plural forms?
        tmp=result.found.first();
    
    bool cutted=false;
    int index=tmp.find('\n');
    if(index > 0)
    {
        tmp=tmp.left(index);
        cutted=true;
    }
    if(tmp.length() > 30)
    {
        tmp=tmp.left(30);
        cutted=true;
    }
    tmp=tmp.stripWhiteSpace();
    if(cutted)
        tmp+="...";

    setText(1,tmp);
    
    if(richText)
        tmp=_result.plainTranslation;
    else
        tmp=result.translation;
    
    cutted=false;
    index=tmp.find('\n');
    if(index > 0)
    {
        tmp=tmp.left(index);
        cutted=true;
    }
    if(tmp.length() > 30)
    {
        tmp=tmp.left(30);
        cutted=true;
    }
    tmp=tmp.stripWhiteSpace();
    if(cutted)
        tmp+="...";
    setText(2,tmp);


    if(!_result.descriptions.isEmpty())
    {
        TranslationInfo *ti = _result.descriptions.first();
        if(ti)
        {
            setText(3,ti->location);
        }
    }

}

TQString ResultListItem::key(int column, bool ascending) const
{
    if(column==0)
    {
        TQString result=TQString::number(_result.score);
        result=result.rightJustify(10,'0');

        return result;
    }
    
    return TQListViewItem::key(column,ascending);
}

const SearchResult *ResultListItem::result() const
{
    return &_result;
}

/* 
 *  Constructs a KBabelDictBox which is a child of 'parent', with the 
 *  name 'name' and widget flags set to 'f' 
 */
KBabelDictBox::KBabelDictBox( TQWidget* parent,  const char* name, WFlags fl )
    : DCOPObject("KBabelDict"), TQWidget( parent, name, fl )
{
   active=-1;
   currentResult=0;
   currentInfo=0;
   moduleList.setAutoDelete(false);


   TQVBoxLayout *mainLayout = new TQVBoxLayout(this);
   mainLayout->setMargin(KDialog::marginHint());
   mainLayout->setSpacing(KDialog::spacingHint());
   
   TQGridLayout *grid = new TQGridLayout(mainLayout);

   TQHBoxLayout *hbox = new TQHBoxLayout;
   TQLabel *label = new TQLabel(i18n("Total:"),this);
   hbox->addWidget(label);
   totalResultsLabel = new TQLabel("0",this);
   hbox->addWidget(totalResultsLabel);
   grid->addLayout(hbox,0,0);  
    
   hbox = new TQHBoxLayout;
   label = new TQLabel(i18n("Current:"), this);
   hbox->addWidget(label);
   currentLabel = new TQLabel("0",this);
   hbox->addWidget(currentLabel);
   grid->addLayout(hbox,1,0);  


   hbox = new TQHBoxLayout;
   label = new TQLabel(i18n("Found in:"), this);
   hbox->addWidget(label);
   locationLabel = new TQLabel(this);
   hbox->addWidget(locationLabel);
   hbox->setStretchFactor(locationLabel,2);
   grid->addLayout(hbox,0,1);  

   hbox = new TQHBoxLayout;
   label = new TQLabel(i18n("Translator:"), this);
   hbox->addWidget(label);
   translatorLabel = new TQLabel(this);
   translatorLabel->setMinimumSize(50,0);
   hbox->addWidget(translatorLabel);
   hbox->setStretchFactor(translatorLabel,2);
   grid->addLayout(hbox,1,1);
   
   grid->setColStretch(1,2);


   hbox = new TQHBoxLayout;
   label = new TQLabel(i18n("Date:"),this);
   hbox->addWidget(label);
   dateLabel = new TQLabel(this);
   dateLabel->setMinimumSize(50,0);
   hbox->addWidget(dateLabel);
   hbox->setStretchFactor(dateLabel,2);

   moreButton = new TQPushButton(this,"moreButton");
   moreButton->setText(i18n("&More"));
   moreButton->setEnabled(false);
   moreButton->setAutoRepeat(true);
   hbox->addWidget(moreButton);

   mainLayout->addLayout(hbox);

   
   hbox = new TQHBoxLayout;
   hbox->addStretch(1);
   listButton = new TQToolButton(TQt::UpArrow,this);
   listButton->setFixedSize(20,15);
   listButton->setAutoRepeat(false);
   connect(listButton,TQT_SIGNAL(clicked()),this,TQT_SLOT(showListOnly()));
   hbox->addWidget(listButton);
   detailButton = new TQToolButton(TQt::DownArrow,this);
   detailButton->setFixedSize(20,15);
   detailButton->setAutoRepeat(false);
   connect(detailButton,TQT_SIGNAL(clicked()),this,TQT_SLOT(showDetailsOnly()));
   hbox->addWidget(detailButton);

   mainLayout->addLayout(hbox);


   resultSplitter = new TQSplitter(Qt::Vertical,this
           ,"resultsplitter");
   mainLayout->addWidget(resultSplitter);
   
   viewContainer = new TQSplitter(Qt::Vertical,resultSplitter, "singleEntrySplitter");
   TQVBoxLayout *vbox = new TQVBoxLayout(viewContainer);
   vbox->setResizeMode(TQLayout::FreeResize);
   origView = new TQTextView(viewContainer,"origView");
   origView->setWordWrap( TQTextEdit::WidgetWidth );
   origView->setMinimumSize(1,1);
   vbox->addWidget(origView);
   translationView = new TQTextView(viewContainer,"translationView");
   origView->setWordWrap( TQTextEdit::WidgetWidth );
   translationView->setMinimumSize(1,1);
   vbox->addWidget(translationView);
   viewContainer->setMinimumSize(1,1);
   
   resultListView = new KListView( resultSplitter, "resultListView" );
   resultListView->setMinimumSize(1,1);
   resultListView->addColumn( i18n( "Score" ) );
   resultListView->addColumn( i18n( "Original" ) );
   resultListView->addColumn( i18n( "Translation" ) );
   resultListView->addColumn( i18n( "Location" ) );

   resultListView->installEventFilter(this);
   connect(resultListView
           , TQT_SIGNAL(doubleClicked(TQListViewItem *,const TQPoint&,int))
           , this, TQT_SLOT(editFile()));
   connect(resultListView, TQT_SIGNAL(returnPressed(TQListViewItem *))
           , this, TQT_SLOT(editFile()));
   connect(resultListView
           , TQT_SIGNAL(contextMenu(KListView *,TQListViewItem *,const TQPoint&))
           , this
           , TQT_SLOT(showContextMenu(KListView *,TQListViewItem *,const TQPoint&)));
   
   resultSplitter->setResizeMode(viewContainer,TQSplitter::KeepSize);
   TQValueList<int> sizes;
   sizes.append(50);
   sizes.append(50);
   resultSplitter->setSizes(sizes);


   hbox = new TQHBoxLayout;
   hbox->addStretch(1);
   
   prevButton = new TQPushButton(i18n("< &Previous"),this);
   prevButton->setEnabled(false);
   prevButton->setAutoRepeat(true);
   hbox->addWidget(prevButton);
   
   nextButton = new TQPushButton(i18n("&Next >"),this);
   nextButton->setEnabled(false);
   nextButton->setAutoRepeat(true);
   hbox->addWidget(nextButton);
   
   hbox->addStretch(1);
   mainLayout->addLayout(hbox);
   
   totalResultsLabel->setNum(100000);
   totalResultsLabel->setFixedSize(totalResultsLabel->sizeHint());
   totalResultsLabel->setNum(0);
   currentLabel->setNum(100000);
   currentLabel->setFixedSize(currentLabel->sizeHint());
   currentLabel->setNum(0);

   setRMBMenu(new TQPopupMenu(this));
   TQStringList fileList;
#if 0
   // try to find installed modules by looking into directories
   // kbabeldict/modules and getting all files *.rc
   TQStringList dirList = KGlobal::dirs()->findDirs("data"
                                    ,"kbabeldict/modules");

   for ( TQStringList::Iterator it = dirList.begin(); it != dirList.end()
                                             ; ++it )
   {
      TQDir dir((*it),"*.rc");
      TQStringList list = dir.entryList(TQDir::Files|TQDir::Readable);
      
      for ( TQStringList::Iterator fit = list.begin(); fit != list.end()
                                             ; ++fit )
      {
         if(!fileList.contains((*fit)))
         {
            fileList.append((*fit));
         }
      }
   }
#endif

   // use locate to locate the actual file, because rcfiles in the users
   // directory is prefered for systemwide rc files
   TQStringList rcList;
   for( TQStringList::Iterator fit = fileList.begin(); fit != fileList.end();
                                             ++fit)
   {
      rcList.append(locate("data","kbabeldict/modules/"+(*fit)));
   }
   
   for( TQStringList::Iterator rit = rcList.begin(); rit != rcList.end();
                                             ++rit)
   {
      KConfig rcConfig((*rit),true,false);
      
      rcConfig.setGroup("SearchEngine");

      TQStringList appList = rcConfig.readListEntry("Applications");
      KInstance *inst = KGlobal::instance();
      if(inst && !appList.isEmpty() && !appList.contains(inst->instanceName()))
      {
          continue;
      }

      TQString libName = rcConfig.readEntry("Lib");

      if(!libName.isNull())
      {
         kdDebug(KBABELDICT) << "loading library " << libName << endl;

         KLibFactory *factory=KLibLoader::self()->factory(libName.latin1());
   
         if(factory)
         {
            SearchEngine *e = (SearchEngine *)factory->create(TQT_TQOBJECT(this)
                  , "searchengine", "SearchEngine");
            if(!e)
            {
               kdError() << "searchengine not initialized" << endl;
            }
            else
            {
		registerModule(e);
            }
         }
         else
         {
            kdError() << "wasn't able to load library" << endl;
         }

      }
   }
   
   kdDebug(KBABEL_SEARCH) << "Now using trader for " << KGlobal::instance()->instanceName() << endl;

   // try to find installed modules by KTrader
   KTrader::OfferList offers = KTrader::self()->query("KBabelDictModule",
	    "('"+KGlobal::instance()->instanceName()+"' in [Applications])");
	    
   for(KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it )
   {
      KLibFactory *factory = KLibLoader::self()->factory( (*it)->library().local8Bit() );
   
      if(factory)
      {
            SearchEngine *e = (SearchEngine *)factory->create(TQT_TQOBJECT(this)
                  , "searchengine", "SearchEngine");
            if(!e)
            {
               kdError() << "searchengine not initialized" << endl;
            }
            else
            {
		registerModule(e);
            }
      }
      else
      {
            kdError() << "wasn't able to load library" << endl;
      }
   }
   
   kdDebug(KBABEL_SEARCH) << "Now for any application" << endl;

   offers = KTrader::self()->query("KBabelDictModule",
	    "not ( exist Applications)");
	    
   for(KTrader::OfferList::ConstIterator it = offers.begin(); it != offers.end(); ++it )
   {
      KLibFactory *factory = KLibLoader::self()->factory( (*it)->library().local8Bit() );
   
      if(factory)
      {
            SearchEngine *e = (SearchEngine *)factory->create(TQT_TQOBJECT(this)
                  , "searchengine", "SearchEngine");
            if(!e)
            {
               kdError() << "searchengine not initialized" << endl;
            }
            else
            {
		registerModule(e);
            }
      }
      else
      {
            kdError() << "wasn't able to load library" << endl;
      }
   }

   connect(nextButton,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotNextResult()));
   connect(prevButton,TQT_SIGNAL(clicked()),this,TQT_SLOT(slotPrevResult()));
   connect(moreButton,TQT_SIGNAL(clicked()),this,TQT_SLOT(nextInfo()));
   

   origView->installEventFilter(this);
   translationView->installEventFilter(this);

   resultListView->setSorting(0,false);
   resultListView->setAllColumnsShowFocus(true);

   connect(resultListView,TQT_SIGNAL(selectionChanged(TQListViewItem*))
           , this, TQT_SLOT(showResult(TQListViewItem*)));
}

/*  
 *  Destroys the object and frees any allocated resources
 */
KBabelDictBox::~KBabelDictBox()
{
}

void KBabelDictBox::registerModule( SearchEngine* e )
{
    active = 0;
    moduleList.append(e);
    connect(e, TQT_SIGNAL(started()),this,TQT_SIGNAL(searchStarted()));
    connect(e, TQT_SIGNAL(finished()),this,TQT_SIGNAL(searchStopped()));
    connect(e, TQT_SIGNAL(finished()),this
        ,TQT_SLOT(clearModuleResults()));
    connect(e, TQT_SIGNAL(progress(int)),this,TQT_SIGNAL(progressed(int)));
    connect(e, TQT_SIGNAL(progressStarts(const TQString&)),this
        , TQT_SIGNAL(progressStarts(const TQString&)));
    connect(e, TQT_SIGNAL(progressEnds()),this,TQT_SIGNAL(progressEnds()));
    connect(e, TQT_SIGNAL(resultFound(const SearchResult*)), this
        , TQT_SLOT(addResult(const SearchResult*)));
    connect(e, TQT_SIGNAL(hasError(const TQString&)), this
        , TQT_SIGNAL(errorInModule(const TQString&)));
}

void KBabelDictBox::saveSettings(KConfigBase *config)
{
   KConfigGroupSaver cs(config,"KBabelDict");

   config->writeEntry("ResultSplitter",resultSplitter->sizes());
   
   SearchEngine *e;

   e = moduleList.at(active);
   if(e)
   {
      config->writeEntry("ActiveModule",e->id());
   }

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      config->setGroup(e->id());
      e->saveSettings(config);
   }


}

void KBabelDictBox::saveSettings(const TQString& moduleId, KConfigBase *config)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      if(e->id() == moduleId)
      {
        e->saveSettings(config);
	break;
      }
   }
}

void KBabelDictBox::readSettings(KConfigBase *config)
{
   SearchEngine *e;
   KConfigGroupSaver cs(config,"KBabelDict");
   TQValueList<int> sizes=config->readIntListEntry("ResultSplitter");
   if(!sizes.isEmpty())
       resultSplitter->setSizes(sizes);
   
   TQString m = config->readEntry("ActiveModule");
   if(!m.isEmpty())
   {
      setActiveModule(m);
   }

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      config->setGroup(e->id());
      e->readSettings(config);
   }
}

void KBabelDictBox::readSettings(const TQString& moduleId, KConfigBase *config)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      if(e->id() == moduleId)
      {
        e->readSettings(config);
	break;
      }
   }
}

void KBabelDictBox::setAutoUpdateOptions(bool on)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      e->setAutoUpdateOptions(on);
   }
}


int KBabelDictBox::activeModule()
{
   return active;
}

/* 
 * public slot
 */
void KBabelDictBox::setActiveModule(int a)
{
   if( a == active)
      return;
      
   if( a < (int)moduleList.count())
   {
      SearchEngine *engine = moduleList.at(active);
   
      if(!engine)
      {
         kdDebug(KBABELDICT) << "no module available" << endl;
      }
      else if(engine->isSearching())
      {
         engine->stopSearch();
         engine->clearResults();
      }
      
      engine = moduleList.at(a);
      if(engine)
      {
          active =  a;
          emit activeModuleChanged(active);   
          emit activeModuleChanged(engine->isEditable());   
      }

      
   }
}

void KBabelDictBox::setActiveModule(TQString id)
{   
   SearchEngine *e;   

   int i=0;
   
   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      if(e->id() == id)
      {
         setActiveModule(i);
         break;
      }

      i++;
   }
}

/* 
 * public slot
 */
void KBabelDictBox::startSearch(const TQString text)
{
   clear();
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      if(engine->isSearching())
      {
         engine->stopSearch();
         connect(this, TQT_SIGNAL(searchStopped()), this
                     , TQT_SLOT(startDelayedSearch()));

         searchText=text;
      }
      else engine->startSearch(text);
   }
}

/* 
 * public slot
 */
void KBabelDictBox::startTranslationSearch(const TQString text)
{
   clear();
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      if(engine->isSearching())
      {
         engine->stopSearch();
         connect(this, TQT_SIGNAL(searchStopped()), this
                     , TQT_SLOT(startDelayedTranslationSearch()));

         searchText=text;
      }
      else engine->startSearchInTranslation(text);
   }
}

void KBabelDictBox::startDelayedSearch(const TQString text)
{
   clear();
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      searchText=text;
      
      if(engine->isSearching())
      {
         engine->stopSearch();
   
         connect(this, TQT_SIGNAL(searchStopped()), this
            , TQT_SLOT(startDelayedSearch()));

      }
      else
      {
         TQTimer::singleShot(5,this,TQT_SLOT(startDelayedSearch()));
      }
   }
}

void KBabelDictBox::startDelayedTranslationSearch(const TQString text)
{
   clear();
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      searchText=text;
      
      if(engine->isSearching())
      {
         engine->stopSearch();
   
         connect(this, TQT_SIGNAL(searchStopped()), this
            , TQT_SLOT(startDelayedTranslationSearch()));

      }
      else
      {
         TQTimer::singleShot(5,this,TQT_SLOT(startDelayedTranslationSearch()));
      }
   }
}

TQString KBabelDictBox::translate(const TQString text)
{
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
      return TQString();
   }
   else 
   {
      if(engine->isSearching())
      {
         engine->stopSearch();
      }

      return engine->translate(text);
   }
}

TQString KBabelDictBox::fuzzyTranslation(const TQString text, int &score)
{
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
      return TQString();
   }
   else 
   {
      if(engine->isSearching())
      {
         engine->stopSearch();
      }

      return engine->fuzzyTranslation(text, score);
   }
}

TQString KBabelDictBox::searchTranslation(const TQString text, int &score)
{
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
      return TQString();
   }
   else 
   {
      if(engine->isSearching())
      {
         engine->stopSearch();
      }

      return engine->searchTranslation(text, score);
   }
}

void KBabelDictBox::startDelayedSearch()
{
   clear();

   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      disconnect(this, TQT_SIGNAL(searchStopped()), this
                     , TQT_SLOT(startDelayedSearch()));


      engine->startSearch(searchText);
   }
}

void KBabelDictBox::startDelayedTranslationSearch()
{
   clear();

   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      disconnect(this, TQT_SIGNAL(searchStopped()), this
                     , TQT_SLOT(startDelayedTranslationSearch()));


      engine->startSearchInTranslation(searchText);
   }
}

/* 
 * public slot
 */
void KBabelDictBox::stopSearch()
{
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
   }
   else 
   {
      engine->stopSearch();
   }

}

bool KBabelDictBox::isSearching() 
{
   SearchEngine *engine = moduleList.at(active);
   
   if(!engine)
   {
      kdDebug(KBABELDICT) << "no module available" << endl;
      return false;
   }

   return engine->isSearching();
}


TQStringList KBabelDictBox::moduleNames()
{
   TQStringList list;
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      list.append(e->name());
   }

   return list;
}

TQStringList KBabelDictBox::modules()
{
   TQStringList list;
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      list.append(e->id());
   }

   return list;
}

TQPtrList<ModuleInfo> KBabelDictBox::moduleInfos()
{
   TQPtrList<ModuleInfo> list;
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      ModuleInfo *info = new ModuleInfo;
      info->id=e->id();
      info->name=e->name();
      info->editable=e->isEditable();

      list.append(info);
   }

   return list;
}


TQPtrList<PrefWidget> KBabelDictBox::modPrefWidgets(TQWidget *parent)
{
   TQPtrList<PrefWidget> list;
   list.setAutoDelete(false);
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      list.append(e->preferencesWidget(parent));
   }

   return list;

}


void KBabelDictBox::showResult(TQListViewItem *item)
{  
   ResultListItem *resultItem = static_cast<ResultListItem*>(item);
   
   if(!item)
   {
      kdError(KBABELDICT) << "no item" << endl;
      if(rmbPopup)
      {
        rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
        rmbPopup->setItemEnabled(editFileIndex,false);
      }
   }
   else
   {
      const SearchResult *result= resultItem->result();
      if(!result)
         return;

      resultListView->ensureItemVisible(item);

      currentResult = resultListView->itemIndex(item);
      currentInfo = 0;

      bool richText=resultItem->richText();
      if(richText)
      {
         // FIXME: what about plural forms?
         origView->setText(result->found.first());
         translationView->setText(result->translation);
      }
      else
      {
         // FIXME: what about plural forms?
         origView->setText(TQStyleSheet::convertFromPlainText(result->found.first()));
         translationView->setText(
               TQStyleSheet::convertFromPlainText(result->translation));
      }

      if(result->descriptions.count() > 0)
      {
         TQPtrListIterator<TranslationInfo> it(result->descriptions);
         TranslationInfo *info=it.current();
         if(info)
         {
            if(info->lastChange.isValid())
            {
               dateLabel->setText(KGlobal::locale()->formatDate(
                    info->lastChange.date(),true));
            }
            else
            {
                dateLabel->setText("");
            }
            locationLabel->setText(info->location);
            translatorLabel->setText(info->translator); 
       
            if(rmbPopup)
            {
                if(!info->filePath.isEmpty())
                {
                    rmbPopup->changeItem(editFileIndex
                        ,i18n("Edit File %1").arg(info->location));
                    rmbPopup->setItemEnabled(editFileIndex,true);
                }
                else
                {
                    rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
                    rmbPopup->setItemEnabled(editFileIndex,false);
                }
             }
         }
      }
      else
      {
         dateLabel->setText("");
         locationLabel->setText("");
         translatorLabel->setText("");

         rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
         rmbPopup->setItemEnabled(editFileIndex,false);
      }

      moreButton->setEnabled((result->descriptions.count() > 1));

      currentLabel->setText(TQString::number(currentResult+1));

      prevButton->setEnabled(currentResult > 0);
      nextButton->setEnabled(currentResult+1 < total);
   }

}

void KBabelDictBox::nextResult()
{
    TQListViewItem *item=resultListView->selectedItem();
    if(item)
    {
        item=item->itemBelow();
        if(item)
        {
            resultListView->setSelected(item,true);
        }
    }
}


void KBabelDictBox::prevResult()
{    
    TQListViewItem *item=resultListView->selectedItem();
    if(item)
    {
        item=item->itemAbove();
        if(item)
        {
            resultListView->setSelected(item,true);
        }
    }

}

void KBabelDictBox::addResult(const SearchResult* result)
{
   SearchEngine *e;

   e = moduleList.at(active);
   if(!e)
   {
       kdError(KBABELDICT) << "no module available" << endl;
       return;
   }

   TQListViewItem *item=resultListView->selectedItem();
   int index=0;
   if(item)
   {
       index=resultListView->itemIndex(item);
   }
  
   new ResultListItem(resultListView, *result,e->usesRichTextResults());
   total++;
   totalResultsLabel->setText(TQString::number(total));

   if(total==1)
   {
      resultListView->setSelected(resultListView->firstChild(),true);
   }
   else
   {
      nextButton->setEnabled((currentResult+1) < total);
      item=resultListView->itemAtIndex(index);
      if(item)
      {
          resultListView->setSelected(item,true);
      }
   }
}

void KBabelDictBox::clear()
{     
    dateLabel->setText("");
    locationLabel->setText("");
    translatorLabel->setText("");
    currentLabel->setText(TQString::number(0));
    totalResultsLabel->setText(TQString::number(0));
    origView->setText("");
    translationView->setText("");
    currentResult=0;
    currentInfo=0;
    total=0;

    resultListView->clear();
    clearModuleResults();

    moreButton->setEnabled(false);
    prevButton->setEnabled(false);
    nextButton->setEnabled(false);

    if(rmbPopup)
    {
        rmbPopup->changeItem(editFileIndex,i18n("Edit File"));
        rmbPopup->setItemEnabled(editFileIndex,false);
    }
}

void KBabelDictBox::nextInfo()
{   
   ResultListItem *item = static_cast<ResultListItem*>(resultListView->selectedItem());
   
   if(!item)
   {
      kdDebug(KBABELDICT) << "no item available" << endl;
   }
   else 
   {
      const SearchResult *result = item->result();
      if(!result)
         return;

      if(result->descriptions.count() > 0)
      {
         currentInfo++;
         TranslationInfo *info;
         if(currentInfo == (int)result->descriptions.count())
         {
            TQPtrListIterator<TranslationInfo> it(result->descriptions);
            info = it.current();
            currentInfo = 0;
         }
         else
         {
            TQPtrListIterator<TranslationInfo> it(result->descriptions);
            for(int i=0; i < currentInfo; i++)
            {
                ++it;
            }
            info=*it;
         }

         if(info->lastChange.isValid())
         {
             dateLabel->setText(KGlobal::locale()->formatDate(
                           info->lastChange.date(),true));
         }
         else
         {
             dateLabel->setText("");
         }

         locationLabel->setText(info->location);
         translatorLabel->setText(info->translator);
         
         if(rmbPopup)
         {
            if(!info->filePath.isEmpty())
            {
                rmbPopup->changeItem(editFileIndex
                        ,i18n("Edit File %1").arg(info->location));
                rmbPopup->setItemEnabled(editFileIndex,true);
            }
            else
            {
                rmbPopup->changeItem(editFileIndex, i18n("Edit File"));
                rmbPopup->setItemEnabled(editFileIndex,false);
            }
         }
      }
   }

}

void KBabelDictBox::showListOnly()
{
   int h=resultSplitter->height();
   TQValueList<int> sizes;
   sizes.append(1);
   sizes.append(h-1);
   resultSplitter->setSizes(sizes);
}

void KBabelDictBox::showDetailsOnly()
{
   int h=resultSplitter->height();
   TQValueList<int> sizes;
   sizes.append(h-1);
   sizes.append(h);
   resultSplitter->setSizes(sizes);
}

void KBabelDictBox::clearModuleResults()
{
    SearchEngine *engine = moduleList.at(active);
    if(engine)
        engine->clearResults();
}

void KBabelDictBox::about()
{
   KAboutApplication *aboutDlg = new KAboutApplication(this);

   SearchEngine *e;
   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      KAboutContainer *page = aboutDlg->addScrolledContainerPage(e->name());

      const KAboutData *aboutData = e->about();
      if(aboutData)
      {

         TQString text = aboutData->programName() + " " +
                      aboutData->version() + "\n";
               
         text += "\n"+aboutData->shortDescription()+"\n";

         if(!aboutData->homepage().isEmpty())
         {
            text += "\n" + aboutData->homepage() + "\n";
         }
         if(!aboutData->otherText().isEmpty())
         {
            text += "\n" + aboutData->otherText() + "\n";
         }
         if(!aboutData->copyrightStatement().isEmpty())
         {
            text += "\n" + aboutData->copyrightStatement() + "\n";
         }
      
         if(aboutData->bugAddress() != "submit@bugs.kde.org")
         {
            text += "\n" + i18n("Send bugs to %1")
                  .arg(aboutData->bugAddress()) +"\n";
         }

         TQLabel *label = new TQLabel(text,0);
         page->addWidget(label);

         int authorCount = aboutData->authors().count();
         if(authorCount)
         {
            if(authorCount==1)
                  text=i18n("Author:");
            else
                  text=i18n("Authors:");

            label = new TQLabel(text,0);
            page->addWidget(label);

            TQValueList<KAboutPerson>::ConstIterator it;
            for(it = aboutData->authors().begin(); 
                        it != aboutData->authors().end(); ++it)
            {
               page->addPerson( (*it).name(), (*it).emailAddress(),
                        (*it).webAddress(), (*it).task() ); 
            }
         }
         int creditsCount = aboutData->credits().count();
         if(creditsCount)
         {
            text = i18n("Thanks to:");
            label = new TQLabel(text,0);
            page->addWidget(label);

            TQValueList<KAboutPerson>::ConstIterator it;
            for(it = aboutData->credits().begin(); 
                        it != aboutData->credits().end(); ++it)
            {
               page->addPerson( (*it).name(), (*it).emailAddress(),
                        (*it).webAddress(), (*it).task() ); 
            }

         }
      }
      else
      {
         TQString text = i18n("No information available.");
         TQLabel *label = new TQLabel(text,0);
         page->addWidget(label);
      }
         
   }

   aboutDlg->setInitialSize(TQSize(400,1));
   aboutDlg->exec();

   delete aboutDlg;
}

void KBabelDictBox::aboutActiveModule()
{
    SearchEngine *engine = moduleList.at(active);
    if(!engine)
        return;

    aboutModule(engine->id());
}

void KBabelDictBox::aboutModule(const TQString& id)
{
   SearchEngine *e;   

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      if(e->id() == id)
      {
          break;
      }
   }
 
   if(!e)
       return;

   AboutModuleDlg *aboutDlg = new AboutModuleDlg(e->about(),this);
   aboutDlg->exec();

   delete aboutDlg;

}


void KBabelDictBox::slotNextResult()
{
   nextResult();
}

void KBabelDictBox::slotPrevResult()
{
   prevResult();
}


void KBabelDictBox::slotStopSearch()
{
   stopSearch();
}

void KBabelDictBox::slotStartSearch(const TQString& text)
{
   startSearch(text);
}

void KBabelDictBox::setEditedPackage(const TQString& name)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      e->setEditedPackage(name);
   }
}


void KBabelDictBox::setEditedFile(const TQString& path)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      e->setEditedFile(path);
   }
}

void KBabelDictBox::setLanguage(const TQString& languageCode,
        const TQString& languageName)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      e->setLanguage(languageCode,languageName);
      e->setLanguageCode(languageCode);
   }
}

void KBabelDictBox::copy()
{ 
   if(origView->hasSelectedText())
   {
      origView->copy();
   }
   else if(translationView->hasSelectedText())
   {
      translationView->copy();
   }
   else
   {
      TQClipboard *cb = KApplication::clipboard();
      cb->setText(translation());
   }
}

TQString KBabelDictBox::translation()
{
   TQString trans;
   
   TQListViewItem *item=resultListView->selectedItem();
   if(item)
   {
       ResultListItem *r=static_cast<ResultListItem*>(item);
       if(r)
       {
           const SearchResult *sr=r->result();
           if(sr)
           {
               if(r->richText())
                   trans=sr->plainTranslation;
               else
                   trans=sr->translation;
           }
       }
   }

   return trans;
}

void KBabelDictBox::setRMBMenu(TQPopupMenu *popup)
{    
   if(popup)
   {
      if(popup->count() > 0)
          popup->insertSeparator();

      editFileIndex = popup->insertItem(i18n("Edit File")
              , this, TQT_SLOT(editFile()));
      popup->setItemEnabled(editFileIndex,false);
       
      KContextMenuManager::insert(origView,popup);
      KContextMenuManager::insert(origView->viewport(),popup);
      KContextMenuManager::insert(translationView,popup);
      KContextMenuManager::insert(translationView->viewport(),popup);
      KContextMenuManager::insert(this,popup);
      //KContextMenuManager::insert(resultListView->viewport(),popup);

      rmbPopup = popup;
   }
}

bool KBabelDictBox::hasSelectedText() const
{
   bool have=false;
   if(origView->hasSelectedText())
      have=true;
   else if(translationView->hasSelectedText())
      have=true;
   else if(resultListView->selectedItem() )
      have=true;
  
   return have;
}

TQString KBabelDictBox::selectedText() const
{
   TQString text;
   if(origView->hasSelectedText())
      text=origView->selectedText();
   else if(translationView->hasSelectedText())
      translationView->selectedText();

   return text;
}



void KBabelDictBox::configure(const TQString& id, bool modal)
{

   TQWidget* w = prefDialogs[id];
   if(w)
   {
       KWin::setActiveWindow(w->winId());
       return;
   }

   SearchEngine *e;
   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      if(e->id() == id)
      {
         TQString caption = i18n("Configure Dictionary %1").arg(e->name());
         KDialogBase *dialog = new KDialogBase(this,"prefDialog"
                   , modal, caption
                   , KDialogBase::Ok|KDialogBase::Apply|KDialogBase::Cancel|
                   KDialogBase::Default);

         TQWhatsThis::add(dialog,"");

         PrefWidget *prefWidget = e->preferencesWidget(dialog);
         dialog->setMainWidget(prefWidget);
         
         connect(dialog, TQT_SIGNAL(okClicked()),prefWidget,TQT_SLOT(apply()));
         connect(dialog, TQT_SIGNAL(applyClicked()),prefWidget,TQT_SLOT(apply()));
         connect(dialog, TQT_SIGNAL(defaultClicked()),prefWidget,TQT_SLOT(standard()));
         connect(dialog, TQT_SIGNAL(cancelClicked()),prefWidget,TQT_SLOT(cancel()));
         
         connect(dialog, TQT_SIGNAL(finished()),this,TQT_SLOT(destroyConfigDialog()));
         
         prefDialogs.insert(id,dialog);

         if( modal ) dialog->exec();
	 else dialog->show();

         break;
      }
   }

}


void KBabelDictBox::destroyConfigDialog()
{
    const TQObject *obj = TQT_TQOBJECT(const_cast<TQT_BASE_OBJECT_NAME*>(sender()));
    if(obj && obj->inherits("KDialogBase"))
    {
       KDialogBase *dialog = (KDialogBase*)obj;
       if(dialog)
       {
           dialog->delayedDestruct();

           TQDictIterator<TQWidget> it(prefDialogs);
           while(it.current() != dialog)
           {
               ++it;
           }

           prefDialogs.remove(it.currentKey());
       }
    }
}

void KBabelDictBox::edit(const TQString& id)
{
   SearchEngine *e;   

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      if(e->id() == id)
      {
         if(e->isEditable())
             e->edit();
         
         break;
      }
   }
}

void KBabelDictBox::edit()
{
    SearchEngine *engine = moduleList.at(active);
    if(!engine)
        return;

    if(engine->isEditable())
        engine->edit();
}

void KBabelDictBox::setTextChanged(const TQStringList& orig, 
        const TQString& translation, uint pluralForm, const TQString& description)
{
   SearchEngine *e;

   for(e = moduleList.first(); e != 0; e = moduleList.next())
   {
      e->stringChanged(orig,translation,pluralForm,description);
   }
}


void KBabelDictBox::wheelEvent(TQWheelEvent *we)
{
    if(we->delta() > 0)
    {
        prevResult();
    }
    else
    {
        nextResult();
    }

    we->accept();
}

bool KBabelDictBox::eventFilter(TQObject *o, TQEvent *e)
{
    if(e->type() == TQEvent::Wheel)
    {
        TQWheelEvent *we = TQT_TQWHEELEVENT(e);
        if(we)
        {
            wheelEvent(we);
            return true;
        }
    }
    else if(e->type() == TQEvent::Resize && TQT_BASE_OBJECT(o) == TQT_BASE_OBJECT(resultListView))
    {
        if(resultListView->height() < 2)
        {
           detailButton->setEnabled(false); 
           listButton->setEnabled(true); 
        }
        else if(resultListView->height() > resultSplitter->height()-10)
        {
           detailButton->setEnabled(true); 
           listButton->setEnabled(false); 
        }
        else
        {
           detailButton->setEnabled(true); 
           listButton->setEnabled(true); 
        }
    }

    return false;
}

void KBabelDictBox::editFile()
{
    ResultListItem *item = static_cast<ResultListItem*>(resultListView->currentItem());
   
   if(!item)
   {
      kdDebug(KBABELDICT) << "no item available" << endl;
   }
   else 
   {
      const SearchResult *result = item->result();
      if(!result)
         return;

      if(!result->descriptions.isEmpty())
      {
         TranslationInfo *info;
         TQPtrListIterator<TranslationInfo> it(result->descriptions);
         for(int i=0; i < currentInfo; i++)
         {
             ++it;
         }
         info=*it;

         if(!info->filePath.isEmpty())
         {
             TQString url = info->filePath;
             TQString msgid;
             
             if( item->richText() )
             {
                msgid = result->plainFound;
             }
             else
             {
                 msgid = result->found.first();
             }

             DCOPClient *dcop = kapp->dcopClient();

             QCStringList list = dcop->registeredApplications();
             int index = list.findIndex("kbabel");
             if(index < 0)
//             if(!dcop->isApplicationRegistered("kbabel"));
             {
                 kdDebug(KBABELDICT) << "kbabel is not registered" << endl;
                 
                 TQString error;
                 TQStringList argList;
                 argList.append("--nosplash");
                 argList.append("--gotomsgid");
                 argList.append(msgid.local8Bit());
                 argList.append(url.local8Bit());
                 kapp->kdeinitExec("kbabel",argList,&error);
                 if(!error.isNull())
                 {
                     KMessageBox::sorry(this
                             ,i18n("There was an error starting KBabel:\n%1")
                                    .arg(error));
                     return;
                 }
             }
             else
             {             
                 TQByteArray data;
                 TQDataStream arg(data, IO_WriteOnly);
                 arg << url.utf8() << msgid.utf8();
                 if (!dcop->send("kbabel", "KBabelIFace"
                         , "gotoFileEntry(TQCString,TQCString)",data)) 
                 {
                     KMessageBox::sorry(this
                             ,i18n("There was an error using DCOP."));
                 }
             }
          }
       }
   }
}

void KBabelDictBox::showContextMenu(KListView *,TQListViewItem *,const TQPoint& p)
{
    if(rmbPopup)
    {
        rmbPopup->exec(p);
    }
}


bool KBabelDictBox::messagesForPackage(const TQString& package
           , TQValueList<DiffEntry>& resultList, TQString& error)
{
   setActiveModule("dbsearchengine");
   SearchEngine *engine = moduleList.at(active);

   if(!engine)
   {
       KMessageBox::sorry(this
          ,i18n("The \"Translation Database\" module\n"
              "appears not to be installed on your system."));
       return false;
   }

   TQValueList<SearchResult> rList;

   SearchFilter* filter = new SearchFilter();
   filter->setLocation(package);
   
   bool success = engine->messagesForFilter(filter,rList,error);

   if(success)
   {
       TQValueList<SearchResult>::Iterator it;
       for(it=rList.begin(); it != rList.end(); ++it)
       {
    	   // FIXME: what about plural forms?
           DiffEntry e;
           e.msgid = (*it).found.first();
           e.msgstr = (*it).translation;
           resultList.append(e);
       }
   }
   
   return success;
}

#include "kbabeldictbox.moc"

