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

  Copyright (C) 1999-2000 by Matthias Kiefer
                            <matthias.kiefer@gmx.de>
                2001-2002 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., 675 Mass Ave, Cambridge, MA 02139, USA.

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

#include "catmanresource.h"
#include "catalogmanager.h"
#include "catmanlistitem.h"
#include "catalog.h"
#include "kbabeldictbox.h"

#include "resources.h"
#include "roughtransdlg.h"
#include "prefwidgets.h"
#include "msgfmt.h"
#include "finddialog.h"
#include "kbmailer.h"

#include <qpopupmenu.h>
#include <qlabel.h>
#include <qpainter.h>

#include <kcmenumngr.h>
#include <kcursor.h>
#include <klocale.h>
#include <kglobal.h>
#include <kglobalsettings.h>
#include <kconfig.h>
#include <kiconloader.h>
#include <kmessagebox.h>
#include <kapplication.h>
#include <kaction.h>
#include <kfiledialog.h>
#include <kio/netaccess.h>
#include <kprogress.h>
#include <kwin.h>

#include <qfileinfo.h>
#include <qdir.h>
#include <qtimer.h>
#include <qbitmap.h>
#include <qwhatsthis.h>
#include <qheader.h>
#include <qdragobject.h>
#include <qlayout.h>
#include <qtextedit.h>

CatalogManagerView::CatalogManagerView(QWidget* parent,const char* name)
              : QListView(parent,name)
{
   _dirList.resize(200);
   _fileList.resize(500);
   _readInfoFileList.clear();
   _readInfoCount=0;
   _dirWatch=0;
   _logWindow=0;
   _logView=0;

   _updateNesting = 0;

   _pendingProcesses.setAutoDelete(true);

   _active=false;
   _stop=false;
   _stopSearch=false;

   setSelectionMode(Single);

   _dictBox = new KBabelDictBox(this, "dictbox");
   _dictBox->hide();

   _updateTimer = new QTimer(this);
   connect(_updateTimer,SIGNAL(timeout()),this,SLOT(checkUpdate()));

   addColumn(i18n("Name"));
   addColumn(i18n("M"),25);
   setColumnAlignment(1,AlignCenter);
   addColumn(i18n("Fuzzy"));
   setColumnAlignment(1,AlignCenter);
   addColumn(i18n("Untranslated"));
   setColumnAlignment(2,AlignCenter);
   addColumn(i18n("Total"));
   setColumnAlignment(3,AlignCenter);
   addColumn(i18n("Last Revision"));
   addColumn(i18n("Last Translator"));


   header()->setMovingEnabled(false);
   setAllColumnsShowFocus(true);
   setSorting(0);

   if(KContextMenuManager::showOnButtonPress())
   {
      connect(this,SIGNAL(rightButtonPressed(QListViewItem*,const QPoint &, int))
           ,this, SLOT(showContentsMenu(QListViewItem*,const QPoint &, int)));
   }
   else
   {
      connect(this,SIGNAL(rightButtonClicked(QListViewItem*,const QPoint &, int))
           ,this, SLOT(showContentsMenu(QListViewItem*,const QPoint &, int)));
   }
   connect(this, SIGNAL(returnPressed(QListViewItem*))
           ,this, SLOT(activateItem(QListViewItem*)));
   connect(this, SIGNAL(doubleClicked(QListViewItem*))
           ,this, SLOT(activateItem(QListViewItem*)));
   connect(this,SIGNAL(selectionChanged()),this,SLOT(checkSelected()));

   _dirCommandsMenu = 0;
   _fileCommandsMenu = 0;
   _dirContentsMenu = 0;
   _fileContentsMenu = 0;

   _logWindow = new KDialogBase(0,"log window",false,i18n("Log Window")
                      ,KDialogBase::Close | KDialogBase::User1,KDialogBase::Close);
   _logWindow->setButtonText(KDialogBase::User1,i18n("C&lear"));
   _logWindow->setInitialSize(QSize(300,200));

   QWhatsThis::add(_logWindow,i18n("<qt><p><b>Log window</b></p>\n"
				   "<p>In this window the output of "
				   "the executed commands are shown.</p></qt>"));

   _logView = new QTextEdit(_logWindow);
   _logView->setReadOnly(true);

   _logWindow->setMainWidget(_logView);

   connect(_logWindow,SIGNAL(user1Clicked()),_logView,SLOT(clear()));

   QWhatsThis::add(this,i18n("<qt><p><b>Catalog Manager</b></p>\n"
"<p>The Catalog Manager merges two directories into one tree and displays all\n"
"PO and POT files in these directories. This way you can easily see if a\n"
"new template has been added or removed. Also some information about the files\n"
"is displayed.</p>"
"<p>For more information see section <b>The Catalog Manager</b>"
" in the online help.</p></qt>"));

   setAcceptDrops(true); // just to get the drag displayed immediately

   mailer = new KBabelMailer();

   KConfig *config = KGlobal::config();
   restoreView(config);
   _dictBox->readSettings(new KConfig("kbabelrc"));
}

CatalogManagerView::~CatalogManagerView()
{
  if(_active)
     stop();

  if(_dirWatch)
      delete _dirWatch;

  if(_settings.killCmdOnExit)
  {
     KProcess* proc;
     for ( proc=_pendingProcesses.first(); proc != 0; proc=_pendingProcesses.next() )
     {
        proc->kill(SIGKILL);
     }
  }

  delete _logWindow;
  delete mailer;
}


void CatalogManagerView::saveView( KConfig *config) const
{
    saveMarker(config);
}


void CatalogManagerView::restoreView( KConfig *config)
{
    readMarker(config);
}

void CatalogManagerView::setRMBMenuFile( QPopupMenu *m )
{
    _fileContentsMenu = m;
}

void CatalogManagerView::setRMBMenuDir( QPopupMenu *m )
{
    _dirContentsMenu = m;
}

void CatalogManagerView::setDirCommandsMenu( QPopupMenu *m )
{
    _dirCommandsMenu = m;
    connect(_dirCommandsMenu,SIGNAL(activated(int)),this,SLOT(slotDirCommand(int)));
}

void CatalogManagerView::setFileCommandsMenu( QPopupMenu *m )
{
    _fileCommandsMenu = m;
    connect(_fileCommandsMenu,SIGNAL(activated(int)),this,SLOT(slotFileCommand(int)));
}

void CatalogManagerView::checkUpdate()
{
   _updateNesting++;
   pause(true);

   QDictIterator<CatManListItem> it( _fileList ); // iterator for dict

   while ( it.current() && !_stop)
   {
      CatManListItem* item=it.current();

      item->checkUpdate();
      ++it;
   }

   pause(false);
   --_updateNesting;
   if( _updateNesting == 0 )
   {
	emit updateFinished();
   }
}



void CatalogManagerView::pause(bool flag)
{
   if(flag)
   {
      _updateTimer->stop();
      if( _dirWatch ) _dirWatch->stopScan();
   }
   else
   {
      _updateTimer->start(10000);
      if( _dirWatch ) _dirWatch->startScan();
   }
}


void CatalogManagerView::stop(bool s)
{
   kdDebug(KBABEL_CATMAN) << "Stopping " << s << endl;
   pause(s);
   _stop=s;
   Catalog::stopStaticRead = true;
}

void CatalogManagerView::stopSearch()
{
    _stopSearch = true;
}

void CatalogManagerView::clear()
{
   pause(true);

   // first clear up
   if(_dirWatch)
      delete _dirWatch;

   _dirWatch= new KDirWatch();
   connect(_dirWatch,SIGNAL(deleted(const QString&)),this
				   ,SLOT(directoryDeleted(const QString&)));
   connect(_dirWatch,SIGNAL(dirty(const QString&)),this
				   ,SLOT(directoryChanged(const QString&)));
   connect(_dirWatch,SIGNAL(created(const QString&)),this
				   ,SLOT(directoryChanged(const QString&)));

   _dirList.clear();
   _fileList.clear();

   QListView::clear();
}

void CatalogManagerView::toggleAllMarks()
{
   _markerList.clear();

   QListViewItemIterator it( this );
   CatManListItem* item;

   for ( ; it.current(); ++it )
   {
      item = (CatManListItem*) it.current();
      if(item->isFile())
      {
         bool wasMarked=item->marked();
         item->setMarked(!wasMarked);
         if(!wasMarked)
         {
            _markerList.append(item->package());
         }
         else
         {
            _markerList.remove(item->package());
         }
      }
   }
   
   checkSelected();
}

void CatalogManagerView::clearAllMarks()
{
   _markerList.clear();
   QDictIterator<CatManListItem> it( _fileList ); // iterator for dict

   while ( it.current() )
   {
      CatManListItem* item=it.current();

      if(item->marked())
         _markerList.remove(item->package());

      item->setMarked(false);
      ++it;
   }

   checkSelected();
}

void CatalogManagerView::loadMarks()
{
    KURL url = KFileDialog::getOpenURL("","*.marklist", this);
    if( url.isEmpty() ) return;

    QString filename;
    if( !KIO::NetAccess::download( url.url(), filename ) )
    {
	KMessageBox::error(this,i18n(
	    "Error while trying to open file:\n %1").arg(url.url()));
	return;
    }

    // now load from file
    QStringList newMarkerList; // better create new list in case of problems
    QFile f( filename );
    if( f.open( IO_ReadOnly) )
    {
	QTextStream s(&f);

	QString input;

	s >> input ;
	if( input == "[Markers]" )
	{
	    while( !s.atEnd() )
	    {
		s >> input;
		newMarkerList.append(input);
	    }
	}
	else
	{
    	    KMessageBox::error(this
		,i18n("Error while trying to read file:\n %1\n"
		"Maybe it's not a valid file with list of markings.").arg(url.url()));
	    f.close();
	    return;
	}
	f.close();
    }
    else
    {
	KMessageBox::error(this,i18n(
	    "Error while trying to open file:\n %1").arg(url.url()));
    }

    KIO::NetAccess::removeTempFile( filename );

    // test validity of list items
    QStringList testedList;
    QStringList::Iterator it;
    for( it=newMarkerList.begin() ; it!=newMarkerList.end() ; it++ )
	if( _fileList[(*it)] != 0 ) testedList.append( (*it) );

    // apply new list
    for( it=_markerList.begin() ; it!=_markerList.end() ; it++ )
    {
	CatManListItem* item = _fileList[(*it)];
	if( item ) item->setMarked(false);
    }

    _markerList = testedList;
    for( it=_markerList.begin() ; it!=_markerList.end() ; it++ )
    {
	CatManListItem* item = _fileList[(*it)];
	if( item ) item->setMarked(true);
    }

   checkSelected();
}

void CatalogManagerView::saveMarks()
{
    KURL url = KFileDialog::getSaveURL("","*.marklist", this);
    if( url.isEmpty() ) return;

    if (KIO::NetAccess::exists(url))
    {
        if(KMessageBox::warningContinueCancel(this,QString("<qt>%1</qt>").arg(i18n("The file %1 already exists. "
	            "Do you want to overwrite it?").arg(url.url())),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Cancel)
	{
	    return;
	}
    }

    QString filename;
    if( url.isLocalFile() ) filename=url.path(0);
    else filename=kapp->tempSaveName( url.path(0) );

    bool error=false;

    QFile f(filename);
    if( f.open(IO_WriteOnly) )
    {
	QTextStream s( &f );
	s << "[Markers]" << endl;
	for( QStringList::Iterator it = _markerList.begin(); it!=_markerList.end() ; it++ )
	    s << (*it) << endl;
	f.close();
    }
    else
    {
	error=true;
        KMessageBox::error(this,
	    i18n("An error occurred while trying to write to file:\n%1\n").arg(url.url()));
    }

    if( !error && !url.isLocalFile())
    {
	KURL temp(filename);
	if( !KIO::NetAccess::upload( temp.url(), url.url() ) )
	{
    	    KMessageBox::error(this,
		i18n("An error occurred while trying to upload the file:\n%1\n").arg(url.url()));
	}
    }

    if( !url.isLocalFile() ) QFile::remove(filename);

   checkSelected();
}

void CatalogManagerView::statistics()
{
   CatManListItem* i=(CatManListItem*) currentItem();

   if(!i)
     i=(CatManListItem*)_dirList["/"];

   if(isActive() && i->isDir())
   {
      if(KMessageBox::warningContinueCancel(this
         ,i18n("The Catalog Manager is still updating information about the files!\n"
"If you continue, it will try to update all necessary files, however this can take "
"a long time and may lead to wrong results. Please wait until all files are updated."),i18n("Warning")
         ,i18n("Continue")) == KMessageBox::Cancel)
      {
        return;
      }
   }

   QStringList doList;

   if( i->isFile() ) doList.append(i->package());
   else doList = i->allChildrenList(true);

   showStatistics( i, doList );
}

void CatalogManagerView::markedStatistics()
{
   CatManListItem* i=(CatManListItem*) currentItem();

   if(!i)
     i=(CatManListItem*)_dirList["/"];

   if(isActive() && i->isDir())
   {
      if(KMessageBox::warningContinueCancel(this
         ,i18n("The Catalog Manager is still updating information about the files!\n"
"If you continue, it will try to update all necessary files, however this can take "
"a long time and may lead to wrong results. Please wait until all files are updated."),i18n("Warning")
         ,i18n("Continue")) == KMessageBox::Cancel)
      {
        return;
      }
   }

   QStringList doList;

   if( i->isFile() ) doList.append(i->package());
   else doList = i->allChildrenList(true);

   QStringList markedDoList;
   QStringList::Iterator it;
   for( it = doList.begin(); it != doList.end(); ++it )
   {
         CatManListItem* item = _fileList[(*it)];
	 if( item->marked() ) markedDoList.append(item->package());
   }

   showStatistics( i, markedDoList );
}

void CatalogManagerView::showStatistics( CatManListItem  *i, QStringList &childrenList )
{
   KLocale *locale = KGlobal::locale();

      QString msg;
      int totalPackages=0;
      int totalPo=0;
      int totalNoPot=0;
      int needworkPo=0;
      int totalMsgid=0;
      int totalFuzzy=0;
      int totalUntranslated=0;

      QStringList::Iterator it;
      for( it = childrenList.begin(); it != childrenList.end(); ++it )
      {
         CatManListItem* item = _fileList[(*it)];

         /*
         KASSERT1(item,KDEBUG_FATAL,KBABEL_CATMAN,"CatalogManagerView::statistics: item not in list %s"
                  ,(*it).ascii());
           */
         // be sure, that the information is updated
         _updateNesting++;
         item->checkUpdate();
         _updateNesting--;
	 if( _stop ) return;

         totalPackages++;

         int fuzzy=item->fuzzy();
         int total=item->total();
         int untrans=item->untranslated();

         if(item->hasPo())
            totalPo++;

         if(!item->hasPot())
            totalNoPot++;


         if(fuzzy || untrans)
            needworkPo++;

         totalMsgid+=total;
         totalFuzzy+=fuzzy;
         totalUntranslated+=untrans;
      }

      double percent;

      QString name=i->package(false);
      if(name.isEmpty())
         name=i18n("all");

      msg=i18n("Statistics for %1:\n").arg(name);

      msg+=i18n("Number of packages: %1\n").arg(locale->formatNumber(totalPackages, 0));

      percent=100-((double)needworkPo*100)/totalPackages;
      msg+=i18n("Complete translated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalPackages-needworkPo, 0));

      percent=100-((double)totalPo*100)/totalPackages;
      msg+=i18n("Only template available: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalPackages-totalPo,0));
      percent=((double)totalNoPot*100)/totalPackages;
      msg+=i18n("Only PO file available: %1 % (%2)\n").arg(locale->formatNumber(percent,02)).arg(locale->formatNumber(totalNoPot, 0));

      msg+=i18n("Number of messages: %1\n").arg(locale->formatNumber(totalMsgid, 0));

      long int totalTranslated = totalMsgid - totalFuzzy - totalUntranslated;
      percent=((double)totalTranslated*100)/totalMsgid;
      msg+=i18n("Translated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalTranslated, 0));

      percent=((double)totalFuzzy*100)/totalMsgid;
      msg+=i18n("Fuzzy: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalFuzzy, 0));

      percent=((double)totalUntranslated*100)/totalMsgid;
      msg+=i18n("Untranslated: %1 % (%2)\n").arg(locale->formatNumber(percent,2)).arg(locale->formatNumber(totalUntranslated, 0));

   KMessageBox::information(this,msg,i18n("Statistics"));
}

void CatalogManagerView::checkSyntax()
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(!item)
      item=(CatManListItem*) _dirList["/"];

   if(item->isFile())
   {
      if(!item->hasPo())
         return;

      Msgfmt::Status status;
      QString output;
      Msgfmt msgfmt;

      status=msgfmt.checkSyntax(item->poFile(),output);

      switch(status)
      {
         case Msgfmt::Ok:
         {
            KMessageBox::information(this,i18n("The file is syntactically correct!\nOutput of \"msgfmt --statistics\":")+"\n"+output);
            break;
         }
         case Msgfmt::SyntaxError:
         {
            KMessageBox::information(this,i18n("The file has syntax errors!\nOutput of \"msgfmt --statistics\":")+"\n"+output);
            break;
         }
         case Msgfmt::Error:
         {
            KMessageBox::error(this,i18n("An error occurred while processing \"msgfmt --statistics\""));
            break;
         }
         case Msgfmt::NoExecutable:
         {
            KMessageBox::sorry(this,i18n("Can't execute msgfmt. Please make sure you have msgfmt in your PATH!"));
            break;
         }
      }

   }
   else
   {
      Msgfmt::Status status;
      QString output;
      Msgfmt msgfmt;

      status=msgfmt.checkSyntaxInDir(item->poFile(), "*.po", output);

      QString name=item->package(false);

      switch(status)
      {
         case Msgfmt::Ok:
         {
            QString msg;
            if(!name.isEmpty())
            {
               msg=i18n("All files in directory %1 are syntactically correct!\n"
"Output of \"msgfmt --statistics\":\n").arg(name)+output;
            }
            else
            {
               msg=i18n("All files in the base directory are syntactically correct!\n"
"Output of \"msgfmt --statistics\":\n")+output;
            }
            KMessageBox::information(this,msg);
            break;
         }
         case Msgfmt::SyntaxError:
         {
            QString msg;
            if(!name.isEmpty())
            {
               msg=i18n("At least one file in directory %1 has syntax errors!\n"
"Output of \"msgfmt --statistics\":\n").arg(name)+output;
            }
            else
            {
               msg=i18n("At least one file in the base directory has syntax errors!\n"
"Output of \"msgfmt --statistics\":\n")+output;
            }
            KMessageBox::information(this,msg);
            break;
         }
         case Msgfmt::Error:
         {
            QString msg;
            if(!name.isEmpty())
            {
              msg=i18n("An error occurred while processing \"msgfmt --statistics *.po\" "
"in directory %1").arg(name);
            }
            else
            {
              msg=i18n("An error occurred while processing \"msgfmt --statistics *.po\" "
"in the base directory");
            }
            KMessageBox::error(this,msg);
            break;
         }
         case Msgfmt::NoExecutable:
         {
            KMessageBox::sorry(this,i18n("Can't execute msgfmt. Please make sure you have msgfmt in your PATH!"));
            break;
         }
      }
   }
}

void CatalogManagerView::roughTranslation()
{
    QPtrList<CatManListItem> result;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    if( current->isDir() )
    {
	QStringList s = current->allChildrenList(true);
	QStringList::Iterator it;
	for( it = s.begin() ; it != s.end(); it++ )
	{
	    CatManListItem *item = _fileList[(*it)];
	    if( item ) result.append( item );
	}
    }
    else
    {
	result.append( current );
    }

    RoughTransDlg* dialog=new RoughTransDlg( _dictBox, result, this );
    dialog->exec();
    delete dialog;
}

void CatalogManagerView::markedRoughTranslation()
{
    if( _markerList.count() == 0 ) return;

    QPtrList<CatManListItem> result;

    QStringList::Iterator it;
    for( it = _markerList.begin() ; it != _markerList.end(); it++ )
    {
	CatManListItem *item = _fileList[(*it)];
	result.append( item );
    }

    RoughTransDlg* dialog=new RoughTransDlg( _dictBox, result, this );
    dialog->exec();
    delete dialog;
}

void CatalogManagerView::mailFiles()
{
  CatManListItem* item = (CatManListItem*)currentItem();
  if(item->isDir()) {
    QStringList filesToSend;
    QStringList childrenList = item->allChildrenList(true);

    QStringList::Iterator it;
    for (it = childrenList.begin(); it != childrenList.end(); ++it) {
      CatManListItem* i = _fileList[(*it)];
      if (i->hasPo()) {
	filesToSend << i->poFile();
      }
    }
    mailer->sendFiles(filesToSend, item->text(0));
  } else {
    if (item->hasPo()) {
      mailer->sendOneFile(item->poFile());
    }
  }
}

void CatalogManagerView::mailMarkedFiles()
{
  if (_markerList.count() == 0)
    return;

  QStringList filesToSend;
  QStringList::Iterator it;
  for (it = _markerList.begin(); it != _markerList.end(); ++it) {
    CatManListItem* i = _fileList[(*it)];
    if (i->hasPo()) {
      filesToSend << i->poFile();
    }
  }
  mailer->sendFiles(filesToSend);
}

void CatalogManagerView::showLog()
{
   _logWindow->show();
}

QString CatalogManagerView::find( FindOptions &options, QStringList &rest )
{
   CatManListItem* i=(CatManListItem*) currentItem();

   if(!i || options.inAllFiles)
     i=(CatManListItem*)_dirList["/"];

   QValueList<QString> foundFiles;
   foundFiles.clear();
   _stopSearch = false;

   QString search = options.findStr.lower().simplifyWhiteSpace();
   QStringList searchWords = QStringList::split(' ', search);

   QStringList childrenList;
   if( i->isFile() ) childrenList.append(i->name());
   else childrenList =i->allChildrenList(true);

   emit prepareFindProgressBar(childrenList.size());

   QStringList::Iterator it;
   for( it = childrenList.begin(); it != childrenList.end(); ++it )
   {
	 CatManListItem* item = _fileList[(*it)];

	 // skip if not marked and we lookup in marked
	 if( options.inMarkedFiles && !item->marked() )
	 {
	    kdDebug(KBABEL_CATMAN) << "Skipping due marking " << item->name() << endl;
    	    emit signalSearchedFile(1);
	    continue;
	 }

	 bool doSearch = options.isRegExp || options.inTemplates; // for regexp and templates we do not support index search
	 if( item->wordsUpdated() )
	    doSearch = doSearch || hasMatchingWords(item->wordList(), searchWords);
	 else doSearch = true; // we do not have index, we need to search
	 if( doSearch )
	 {
	    QString itemFile = QString::null;
	    if( options.inTemplates )
	    {
		if( item->hasPot() ) itemFile=item->potFile();
	    } else {
		if( item->hasPo() ) itemFile=item->poFile();
	    }

	    if( itemFile.isNull() )
	    {
		emit signalSearchedFile(1);
		continue;
	    }

    	    if( Catalog::findInFile( itemFile , options ) )
	    {
    		emit signalSearchedFile(1);
		rest.clear();
		if( _stopSearch )
		{
		    // if we are stopped, return what we found and clear the rest
		    _stopSearch = false;
		    return itemFile;
		}
		QString foundItemFile = itemFile;

		it++;
		while( it != childrenList.end() )
		{
        	    CatManListItem *item = _fileList[(*it)];

		    itemFile = QString::null;
		    if( options.inTemplates )
		    {
			if( item->hasPot() ) itemFile=item->potFile();
		    } else {
			if( item->hasPo() )itemFile=item->poFile();
		    }
		    if( options.inMarkedFiles && !item->marked() )
			itemFile=QString::null;

		    if( !itemFile.isNull())
		    {
			if( item->wordsUpdated() &&  !options.inTemplates )
			{
			    if( options.isRegExp || hasMatchingWords(item->wordList(), searchWords) )
			    {
				rest.append( itemFile );
			    }
			    else kdDebug(KBABEL_CATMAN) << "Don't try to lookup in " << itemFile << endl;
			} else {
			    rest.append( itemFile ); // there is no word index, add the file
			}
		    } else emit signalSearchedFile(1);

		    it++;
		}
    		return foundItemFile;

	    }
	} else kdDebug(KBABEL_CATMAN) << "Skipping " << item->poFile() << endl;
	emit signalSearchedFile(1);
	kapp->processEvents(10);
	if( _stop || _stopSearch ) {
	    _stopSearch = false;
	    rest.clear();
	    if( _updateNesting == 0 && !_stop ) emit updateFinished();
	    return QString::null;
	}
   }
   return QString::null;
}

bool CatalogManagerView::hasMatchingWords( QStringList &itemWords, QStringList &searchWords)
{
    for( QStringList::Iterator it1 = searchWords.begin() ; it1 != searchWords.end() ; ++it1 )
	for( QStringList::Iterator it2 = itemWords.begin() ; it2 != itemWords.end() ; ++it2 )
	    if( *it1 == *it2
		|| (*it1).contains(*it2)
		|| (*it2).contains(*it1) ) return true;
    return false;
}

void CatalogManagerView::showContentsMenu(QListViewItem *i, const QPoint &point, int)
{
   CatManListItem* item = (CatManListItem*) i;

   if(!item)
      return;

  if(item->isDir())
   {
      _dirContentsMenu->exec(point);
   }
   else
   {
      _fileContentsMenu->exec(point);
   }
}

void CatalogManagerView::checkSelected()
{
   CatManListItem* item=(CatManListItem*)selectedItem();

   if(!item)
      return;
      
   emit selectedChanged(item->hasPo(),item->hasPot(), item->marked());
}

void CatalogManagerView::activateItem(QListViewItem *)
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(!item)
      return;

   if(item->isDir())
   {
      item->setOpen(!item->isOpen());
      return;
   }

   QString filename;
   if(item->hasPo())
   {
      emit openFile(item->poFile(),item->package());
   }
   else if(item->hasPot())
   {
      emit openTemplate(item->potFile(),item->poFile(),item->package());
   }
   else
   {
      kdError(KBABEL_CATMAN) << "CatalogManagerView::activateItem: item has no file?" << endl;
   }

}

void CatalogManagerView::slotOpenFile()
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(item && item->isFile())
   {
      activateItem(item);
   }
}

void CatalogManagerView::slotOpenFileInNewWindow()
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(item && item->isFile())
   {
	QString filename;
	if(item->hasPo())
	{
    	    emit openFileInNewWindow(item->poFile(),item->package());
	}
	else if(item->hasPot())
	{
    	    emit openTemplateInNewWindow(item->potFile(),item->poFile(),item->package());
	}
    }
}

void CatalogManagerView::slotOpenTemplate()
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(item && item->isFile())
   {
      emit openFile(item->potFile(),item->package());
   }
}

void CatalogManagerView::slotDeleteFile()
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(item && item->isFile() && item->hasPo() && !item->hasPot())
   {
      QString msg=i18n("Do you really want to delete the file %1?").arg(item->poFile());
      if(KMessageBox::warningContinueCancel(this,msg,i18n("Warning"),i18n("Delete"))== KMessageBox::Continue)
      {
         if(!QFile::remove(item->poFile()))
         {
             KMessageBox::sorry(this,i18n("Was not able to delete the file %1!").arg(item->poFile()));
         }
      }
   }
}

void CatalogManagerView::toggleMark()
{
    CatManListItem* i = (CatManListItem*) currentItem();
    if( i && i->isDir() ) slotToggleMarksInDir();
    else slotToggleMark();
}

void CatalogManagerView::slotToggleMark()
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(item && item->isFile())
   {
      bool wasMarked=item->marked();
      item->setMarked(!wasMarked);

      if(wasMarked)
      {
         _markerList.remove(item->package());
      }
      else
      {
         _markerList.append(item->package());
      }
   }
    
    checkSelected();
}

void CatalogManagerView::slotToggleMarksInDir()
{
   CatManListItem* i=(CatManListItem*) currentItem();

   if(i && i->isDir())
   {
      QStringList contentList = i->allChildrenList(true);

      QStringList::Iterator it;
      for( it = contentList.begin(); it != contentList.end(); ++it )
      {
         CatManListItem* item = _fileList[(*it)];

         if ( item == 0 )
             kdFatal(KBABEL_CATMAN) << "CatalogManagerView::slotToggleMarkInDir: item not in list" << endl;

         bool wasMarked=item->marked();
         item->setMarked(!wasMarked);

         if(wasMarked)
         {
            _markerList.remove(item->package());
         }
         else
         {
            _markerList.append(item->package());
         }
      }
   }
    
    checkSelected();
}


void CatalogManagerView::slotClearMarksInDir()
{
   CatManListItem* i=(CatManListItem*) currentItem();

   if(i && i->isDir())
   {
      QStringList contentList=i->contentsList(true);

      QStringList::Iterator it;
      for( it = contentList.begin(); it != contentList.end(); ++it )
      {
         CatManListItem* item = _fileList[(*it)];

         if ( item == 0 )
           kdFatal(KBABEL_CATMAN) << "CatalogManagerView::slotClearMarkInDir: item not in list" << endl;

         if(item->marked())
         {
            _markerList.remove(item->package());
         }
         item->setMarked(false);
      }
   }
    
    checkSelected();
}


void CatalogManagerView::slotDirCommand(int index)
{
   CatManListItem* item=(CatManListItem*) currentItem();


   if(index>=0 && item && item->isDir())
   {
      QString cmd=_settings.dirCommands[(uint)index];
      cmd.replace(QRegExp("@PACKAGE@"),item->name());
      cmd.replace(QRegExp("@PODIR@"),item->poFile());
      cmd.replace(QRegExp("@POTDIR@"),item->potFile());

      kdDebug(KBABEL_CATMAN) << cmd << endl;

      KProcess* proc = new KShellProcess();
      _pendingProcesses.append(proc);

      connect( proc,SIGNAL( processExited(KProcess *) ), this
               ,SLOT( processEnded(KProcess*) ) );
      connect( proc,SIGNAL( receivedStdout(KProcess*,char*,int) ), this
               ,SLOT( showOutput(KProcess*,char*,int) ) );
      connect( proc,SIGNAL( receivedStderr(KProcess*,char*,int) ), this
               ,SLOT( showOutput(KProcess*,char*,int) ) );

      *proc << "cd" << item->poFile() << ";" << cmd;
      proc->start(KProcess::NotifyOnExit,KProcess::AllOutput);
   }
}

void CatalogManagerView::slotFileCommand(int index)
{
   CatManListItem* item=(CatManListItem*) currentItem();

   if(index>=0 && item && item->isFile())
   {
      CatManListItem* parent = (CatManListItem*)item->parent();

      QString cmd=_settings.fileCommands[(uint)index];
      cmd.replace(QRegExp("@PACKAGE@"),item->name());
      cmd.replace(QRegExp("@POFILE@"),item->poFile());
      cmd.replace(QRegExp("@POTFILE@"),item->potFile());
      cmd.replace(QRegExp("@PODIR@"),parent->poFile());
      cmd.replace(QRegExp("@POTDIR@"),parent->potFile());
      cmd.replace(QRegExp("@POEMAIL@"),item->text(COL_TRANSLATOR));

      kdDebug(KBABEL_CATMAN) << cmd << endl;

      KProcess* proc = new KShellProcess();
      _pendingProcesses.append(proc);

      connect( proc,SIGNAL( processExited(KProcess *) ), this
               ,SLOT( processEnded(KProcess*) ) );
      connect( proc,SIGNAL( receivedStdout(KProcess*,char*,int) ), this
               ,SLOT( showOutput(KProcess*,char*,int) ) );
      connect( proc,SIGNAL( receivedStderr(KProcess*,char*,int) ), this
               ,SLOT( showOutput(KProcess*,char*,int) ) );

      *proc << "cd" << parent->poFile() << ";" << cmd;
      proc->start(KProcess::NotifyOnExit,KProcess::AllOutput);
   }

}


void CatalogManagerView::updateFile(QString fileWithPath, bool force)
{
   QString relFile;
   if(fileWithPath.contains(QRegExp("^"+_settings.poBaseDir)))
   {
      relFile=fileWithPath.right(fileWithPath.length()-_settings.poBaseDir.length());
   }
   else if(fileWithPath.contains(QRegExp("^"+_settings.potBaseDir)))
   {
      relFile=fileWithPath.right(fileWithPath.length()-_settings.potBaseDir.length());
   }
   else
   {
      return;
   }

   if(relFile.right(4)==".pot")
   {
      relFile.truncate(relFile.length()-4);
   }
   else if(relFile.right(3)==".po")
   {
      relFile.truncate(relFile.length()-3);
   }

   CatManListItem* item=_fileList[relFile];

   if(item)
   {
	_updateNesting++;
	if( force ) item->forceUpdate();
        else item->checkUpdate();
        _updateNesting--;
   }

}

void CatalogManagerView::updateAfterSave(QString fileWithPath, PoInfo &newInfo)
{
   QString relFile;
   if(fileWithPath.contains(QRegExp("^"+_settings.poBaseDir)))
   {
      relFile=fileWithPath.right(fileWithPath.length()-_settings.poBaseDir.length());
   }
   else if(fileWithPath.contains(QRegExp("^"+_settings.potBaseDir)))
   {
      relFile=fileWithPath.right(fileWithPath.length()-_settings.potBaseDir.length());
   }
   else
   {
      return;
   }

   if(relFile.right(4)==".pot")
   {
      relFile.truncate(relFile.length()-4);
   }
   else if(relFile.right(3)==".po")
   {
      relFile.truncate(relFile.length()-3);
   }

   CatManListItem* item=_fileList[relFile];

   if(item)
   {
      item->updateAfterSave(newInfo);
   }

}

void CatalogManagerView::buildTree()
{
   // in case we were called after settings update
   disconnect( this, SIGNAL( updateFinished() ), this, SLOT(buildTree() ) );

   emit signalBuildTree(false); // announce start of building

   clear();

   if(isActive())
      return;

   _updateNesting++;

   _active=true;
   _stop=false;


   CatManListItem* root = new CatManListItem(this, this,_settings.poBaseDir,_settings.potBaseDir);
   _dirList.insert("/",root);
   //root->setSelectable(false);

   QFileInfo fileInfo(_settings.poBaseDir);
   if(!fileInfo.isDir())
   {
      KMessageBox::error(this,i18n("You have not specified a valid directory "
"for the base directory of the PO files:\n%1\n"
"Please check your settings in the preferences dialog!").arg(_settings.poBaseDir));

      _active=false;
      _updateNesting--;
      if( _updateNesting == 0 ) emit updateFinished();
      return;
   }

   fileInfo.setFile(_settings.potBaseDir);
   if(!fileInfo.isDir() && !_settings.potBaseDir.isEmpty())
   {
      KMessageBox::error(this,i18n("You have not specified a valid directory "
"for the base directory of the PO template files:\n%1\n"
"Please check your settings in the preferences dialog!").arg(_settings.potBaseDir));
   }


   setCursor(KCursor::waitCursor());

   //"/" is the root item
   buildDir("/",true);   // build dir without updating the items...

    if( _stop ) {
        _active = false;
	_updateNesting--;
	if( _updateNesting == 0 ) emit updateFinished();
	return;
    }

   _dirWatch->addDir(_settings.poBaseDir);
   if(!_settings.potBaseDir.isEmpty())
	   _dirWatch->addDir(_settings.potBaseDir);

   emit signalBuildTree(true); // announce beginning of tree building

   unsetCursor();

    if( _stop ) {
        _active = false;
	_updateNesting--;
	if( _updateNesting == 0 ) emit updateFinished();
	return;
    }

   int files=_fileList.count()+_dirList.count();

   _readInfoCount = 0;

   emit prepareProgressBar(i18n("Reading file information"),files);

   root->setOpen(true);

    if( _stop ) {
        _active = false;
	_updateNesting--;
	if( _updateNesting == 0 ) emit updateFinished();
	return;
    }

   // first read information about the files...
   QDictIterator<CatManListItem> it( _fileList ); // iterator for dict

   int i=0;
   while ( it.current() && !_stop)
   {
      it.current()->checkUpdate(true);

      kapp->processEvents(100);

      i++;

      ++it;
   }

   // ...then update directories
   QDictIterator<CatManListItem> dit( _dirList ); // iterator for dict

   while ( dit.current() && !_stop)
   {
      dit.current()->checkUpdate();

      kapp->processEvents(100);

      i++;

      ++dit;
   }

   emit clearProgressBar();

   _dirWatch->startScan();
   pause(false);

   _active=false;

   _updateNesting--;

   if( _updateNesting == 0 )
   {
	emit updateFinished();
   }
}

bool CatalogManagerView::buildDir(QString relDir,bool fast)
{
   if( _stop ) return false;

   bool haveTemplateDir=true;
   QFileInfo fileInfo;

   fileInfo.setFile(_settings.potBaseDir);
   if(!fileInfo.isDir())
   {
      haveTemplateDir=false;
   }

   bool potHasFiles=false;
   if(haveTemplateDir)
   		potHasFiles=buildDir(_settings.potBaseDir,relDir,".pot",fast);

   bool poHasFiles=buildDir(_settings.poBaseDir,relDir,".po",fast);

   return (poHasFiles | potHasFiles);
}


bool CatalogManagerView::buildDir(const QString& baseDir,const QString& relDir
                                                , const QString extension , bool fast)
{
      if( _stop ) return false;

      bool havePoFiles=false;

      CatManListItem* thisItem=_dirList[relDir];
      if(!thisItem)
      {
         kdFatal(KBABEL_CATMAN) << "null pointer to this item" << endl;
         return false;
      }

      QString poBaseDir=_settings.poBaseDir;
      QString potBaseDir=_settings.potBaseDir;

      // traverse directory in poBaseDir
      QDir dir(baseDir+relDir);
      QStringList entryList=dir.entryList("*"+extension,QDir::Files,QDir::Name);

      QStringList::Iterator it;

      for (  it = entryList.begin(); it != entryList.end() && !_stop ; ++it )
      {
	  if( _stop ) return false;

          havePoFiles=true;

          QString file=relDir+(*it);
          file.replace(QRegExp(extension+"$"),"");
          CatManListItem* item = _fileList[file];
          if(!item)
          {
             item = new CatManListItem(this,thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file);
             _fileList.insert(file,item);
             _readInfoFileList.prepend(file);

             if(_markerList.contains(file))
             {
                item->setMarked(true);
             }

             if(!fast)
             {
                item->checkUpdate();
             }
          }
      }

      entryList=dir.entryList(QDir::Dirs,QDir::Name);

      for (  it = entryList.begin(); it != entryList.end() && !_stop ; ++it )
      {
          kapp->processEvents(100);

	  if( _stop ) return false;

          if((*it)=="." || (*it)=="..")
          {
             continue;
          }

          QString subDir=relDir+(*it)+"/";
          if(!_dirWatch->contains(baseDir+subDir))
          {
              _dirWatch->addDir(baseDir+subDir);
          }

          bool otherHasFiles=true;

          CatManListItem* item = _dirList[subDir];
          if(!item && !_stop)
          {
             item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir);
             _dirList.insert(subDir,item);

             otherHasFiles=false;
          }

	  if( _stop ) return false;

          // recursive call
          if(!buildDir(baseDir,subDir,extension,fast) && !otherHasFiles)
          {
             kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl;
             deleteDirItem(subDir);
			 item=0;
          }
          else
             havePoFiles=true;

      } // end looking up directories in po base dir

      return havePoFiles;
}


void CatalogManagerView::updateDir(QString relDir)
{
      if( _stop ) return;

      kdDebug(KBABEL_CATMAN) << "updating dir " << relDir << endl;

      bool havePoFiles=false;

      CatManListItem* thisItem=_dirList[relDir];
      if(!thisItem)
      {
         kdFatal(KBABEL_CATMAN) << "null pointer to this item" << endl;
         return;
      }

      QStringList contentList = thisItem->contentsList(true);

      QString poBaseDir=_settings.poBaseDir;
      QString potBaseDir=_settings.potBaseDir;

      // first lookup template directory
      QDir dir(potBaseDir+relDir);
      QStringList entryList=dir.entryList("*.pot",QDir::Files,QDir::Name);

      QStringList::Iterator it;

      for (  it = entryList.begin(); it != entryList.end(); ++it )
      {
          if( _stop ) return;

          havePoFiles=true;

          QString file=relDir+(*it);
          file.replace(QRegExp(".pot$"),"");
          CatManListItem* item = _fileList[file];
          if(!item)
          {
             item = new CatManListItem(this, thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file);
             _fileList.insert(file,item);

             if(_markerList.contains(file))
             {
                item->setMarked(true);
             }

             item->checkUpdate();
          }
		  else
		  {
			 item->checkUpdate();
		  }

          contentList.remove(file);
      }

      entryList=dir.entryList(QDir::Dirs,QDir::Name);

      for (  it = entryList.begin(); it != entryList.end(); ++it )
      {
          kapp->processEvents(100);

          if( _stop ) return;

          if((*it)=="." || (*it)=="..")
          {
             continue;
          }

          bool newDirAdded=false;

          QString subDir=relDir+(*it)+"/";
          if(!_dirWatch->contains(potBaseDir+subDir))
          {
              _dirWatch->addDir(potBaseDir+subDir);

              newDirAdded=true;
          }

          CatManListItem* item = _dirList[subDir];
          if(!item && newDirAdded)
          {
             item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir);
             _dirList.insert(subDir,item);

              if(!buildDir(subDir,false))
              {
                   kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl;
                   deleteDirItem(subDir);
                   item=0;
              }
          }
		  else if(newDirAdded)
		  {
			  updateDir(subDir);
		  }


		  // if directory was already here, but no item
		  // -> directory contains no files
          if(item && !newDirAdded)
          {
             havePoFiles=true;
          }

      } // end looking up directories in template dir

      // now traverse directory in poBaseDir
      dir.setPath(poBaseDir+relDir);
      entryList=dir.entryList("*.po",QDir::Files,QDir::Name);

      for (  it = entryList.begin(); it != entryList.end(); ++it )
      {
          havePoFiles=true;

          if( _stop ) return;

          QString file=relDir+(*it);
          file.replace(QRegExp(".po$"),"");
          CatManListItem* item = _fileList[file];
          if(!item)
          {
             item = new CatManListItem(this, thisItem,poBaseDir+file+".po",potBaseDir+file+".pot",file);
             _fileList.insert(file,item);

             if(_markerList.contains(file))
             {
                item->setMarked(true);
             }

             item->checkUpdate();
          }
		  else
		  {
			 item->checkUpdate();
		  }

          contentList.remove(file);
      }

      entryList=dir.entryList(QDir::Dirs,QDir::Name);

      for (  it = entryList.begin(); it != entryList.end(); ++it )
      {
          kapp->processEvents(100);

          if( _stop ) return;

          if((*it)=="." || (*it)=="..")
          {
             continue;
          }

          bool newDirAdded=false;

          QString subDir=relDir+(*it)+"/";
          if(!_dirWatch->contains(poBaseDir+subDir))
          {
               _dirWatch->addDir(poBaseDir+subDir);
               newDirAdded=true;
          }

          CatManListItem* item = _dirList[subDir];

          bool templateHasFiles=(bool)item;

          if(!item && newDirAdded)
          {
             item = new CatManListItem(this, thisItem,poBaseDir+subDir,potBaseDir+subDir,subDir);
             _dirList.insert(subDir,item);

              if(!buildDir(subDir,false) && !templateHasFiles)
              {
                   kdDebug(KBABEL_CATMAN) << "skipping " << subDir << endl;
                   deleteDirItem(subDir);
				   item=0;
              }
          }
		  else if(newDirAdded)
		  {
			  updateDir(subDir);
		  }

		  // if directory was already here, but no item
		  // -> directory contains no files
          if(item && !newDirAdded)
          {
             havePoFiles=true;
          }


      } // end looking up directories in po base dir


      // check, if something in the directory has been deleted
      // but only if we traversed also the template directory
      if(contentList.count()>0)
      {
          QStringList::Iterator it;
          for( it = contentList.begin(); it != contentList.end(); ++it )
          {
             QFileInfo po(poBaseDir+(*it));
             QFileInfo pot(potBaseDir+(*it));

             if(!po.exists() && !pot.exists())
             {
                CatManListItem* item = _fileList[(*it)];
                if(item)
                {
                   if(item->marked())
                      _markerList.remove(item->package());

                   _fileList.remove((*it));
                   delete item;
                }
             }
          }
      }

      if(!havePoFiles)
      {
	     deleteDirItem(relDir);

          // if this directory has to be removed, check, if
		  // the parent directory has to be removed too
          int index=relDir.findRev("/",relDir.length()-2);
          if(index<0)
          {
            relDir="/";
          }
          relDir=relDir.left(index+1);
          updateDir(relDir);
      }
}

void CatalogManagerView::directoryChanged(const QString& dir)
{
   pause(true);
   _dirWatch->stopScan();

   QString relDir;
   if(dir.contains(QRegExp("^"+_settings.poBaseDir)))
   {
      relDir=dir.right(dir.length()-_settings.poBaseDir.length());
   }
   else if(dir.contains(QRegExp("^"+_settings.potBaseDir)))
   {
      relDir=dir.right(dir.length()-_settings.potBaseDir.length());
   }

   if(relDir.right(1)!="/")
   {
      relDir+="/";
   }

   kdDebug(KBABEL_CATMAN) << "directory changed: " << relDir << endl;

   QFileInfo fileInfo(_settings.potBaseDir);

   CatManListItem* thisItem=_dirList[relDir];
   if(!thisItem)
   {
      // if this item is not in the list search for next existing parent item
      QString prevRelDir;
      do
      {
          prevRelDir=relDir;
          int index=relDir.findRev("/",relDir.length()-2);
          if(index<0)
          {
            relDir="/";
          }
          relDir=relDir.left(index+1);

          thisItem=_dirList[relDir];
      }
      while(relDir!="/" && !thisItem);

      if(!thisItem)
      {
         kdFatal(KBABEL_CATMAN) << "null pointer to this item: " << relDir << endl;
         return;
      }
      else
      {
          // if a parent item dir is found, create the needed item in this dir
          // and build the tree from this item on
          kdDebug(KBABEL_CATMAN) << "building dir: " << prevRelDir << endl;
          CatManListItem* item = new CatManListItem(this, thisItem,_settings.poBaseDir+prevRelDir
                     ,_settings.potBaseDir+prevRelDir,prevRelDir);
          _dirList.insert(prevRelDir,item);


          if(!buildDir(prevRelDir,false))
          {
             deleteDirItem(prevRelDir);
          }
      }
   }
   else
   {
      updateDir(relDir);
   }

   _dirWatch->startScan();
   pause(false);
}


void CatalogManagerView::directoryDeleted(const QString& dir)
{
   pause(true);
   _dirWatch->stopScan();

   QString relDir;
   if(dir.contains(QRegExp("^"+_settings.poBaseDir)))
   {
      relDir=dir.right(dir.length()-_settings.poBaseDir.length());
   }
   else if(dir.contains(QRegExp("^"+_settings.potBaseDir)))
   {
      relDir=dir.right(dir.length()-_settings.potBaseDir.length());
   }

   if(relDir.right(1)!="/")
   {
      relDir+="/";
   }

   kdDebug(KBABEL_CATMAN) << "directory deleted: " << relDir << endl;

   CatManListItem* thisItem=_dirList[relDir];
   if(thisItem)
   {
	  // we have to take care, if one directory still exists
	  bool poDeleted=!thisItem->hasPo();
	  bool potDeleted=!thisItem->hasPot();

	  // if neither the po- nor the pot-directory exists any more
	  // delete all sub items
	  if(poDeleted && potDeleted)
	  {
		  deleteDirItem(relDir);
	  }
	  else
	  {
      	 QStringList childList = thisItem->contentsList();

         CatManListItem* item;
         QStringList::Iterator it;
         for( it = childList.begin();it !=  childList.end(); ++it )
         {
            item=_fileList[(*it)];
            if(item)
            {
		       if( (poDeleted && !item->hasPot()) ||
						(potDeleted && !item->hasPo()) )
			   {
                  _fileList.remove((*it));
                  delete item;
			   }
			   else
			   {
			      item->checkUpdate();
			   }
            }
            else
            {
               item=_dirList[(*it)];
               if(item)
               {
                  if( (poDeleted && !item->hasPot()) ||
						(potDeleted && !item->hasPo()) )
				  {
					  deleteDirItem((*it));
				  }
               }
               else
               {
                  kdDebug(KBABEL_CATMAN) << "directoryDeleted: don't have item "
						  << (*it) << endl;
               }
            }
         }
      }
   }

   _dirWatch->startScan();
   pause(false);
}

void CatalogManagerView::fileInfoRead( QString filename )
{
    if( _readInfoFileList.contains( filename ) ) {
	emit progress( ++_readInfoCount);
	_readInfoFileList.remove( filename );
    }

    if( _readInfoFileList.isEmpty() ) emit clearProgressBar();
}

void CatalogManagerView::setSettings(CatManSettings newSettings)
{
   CatManSettings oldSettings=_settings;
   _settings=newSettings;

   if(_settings.poBaseDir.right(1)=="/")
      _settings.poBaseDir.truncate(_settings.poBaseDir.length()-1);
   if(_settings.potBaseDir.right(1)=="/")
      _settings.potBaseDir.truncate(_settings.potBaseDir.length()-1);

   _dirCommandsMenu->clear();
   int counter=0;
   for ( QStringList::Iterator it = _settings.dirCommandNames.begin()
                        ; it != _settings.dirCommandNames.end(); ++it )
   {
      _dirCommandsMenu->insertItem((*it),counter);
      counter++;
   }
   _dirCommandsMenu->insertSeparator();
   _dirCommandsMenu->insertItem(i18n("Log Window"),this,SLOT(showLog()));

   _fileCommandsMenu->clear();
   counter=0;
   for ( QStringList::Iterator it = _settings.fileCommandNames.begin()
                        ; it != _settings.fileCommandNames.end(); ++it )
   {
      _fileCommandsMenu->insertItem((*it),counter);
      counter++;
   }
   _fileCommandsMenu->insertSeparator();
   _fileCommandsMenu->insertItem(i18n("Log Window"),this,SLOT(showLog()));


   emit settingsChanged(_settings);

   bool pathChanged=false;
   if(oldSettings.poBaseDir!=_settings.poBaseDir)
   {
      pathChanged=true;
   }
   else if(oldSettings.potBaseDir!=_settings.potBaseDir)
   {
      pathChanged=true;
   }
   if(pathChanged)
   {
      if( !isActive() ) {
        QTimer::singleShot(100,this,SLOT(buildTree()));
      } else {
        stop();
        connect( this, SIGNAL( updateFinished() ), this, SLOT(buildTree() ) );
      }
   }
}


CatManSettings CatalogManagerView::settings() const
{
   return _settings;
}


void CatalogManagerView::hideEvent(QHideEvent*)
{
   pause(true);

   if(_dirWatch)
      _dirWatch->stopScan();
}

void CatalogManagerView::showEvent(QShowEvent*)
{
   QTimer::singleShot(1,this,SLOT(checkUpdate()));

   pause(false);

   if(_dirWatch)
      _dirWatch->startScan(true);
}

void CatalogManagerView::contentsMousePressEvent(QMouseEvent* event)
{
   if(event->button() == LeftButton)
      _pressPos=event->pos();

   QListView::contentsMousePressEvent( event );
}

void CatalogManagerView::contentsMouseMoveEvent(QMouseEvent* event)
{
   if(event->state() & LeftButton)
   {
      int delay = KGlobalSettings::dndEventDelay();
      if(QABS( event->pos().x() - _pressPos.x() ) >= delay ||
         QABS( event->pos().y() - _pressPos.y() ) >= delay)
      {
         CatManListItem* item = (CatManListItem*)itemAt(contentsToViewport(_pressPos));
         if(item && item->isFile())
         {
            // always add the po-file and if existing the pot-file to the drag and
            // let the user decide what to do, when dropping into kbabel
            QStrList uri;
            uri.append(QUriDrag::localFileToUri(item->poFile()));
            if(item->hasPot())
               uri.append(QUriDrag::localFileToUri(item->potFile()));

            QUriDrag* drag = new QUriDrag(uri,this);
            QPixmap icon=KGlobal::iconLoader()->loadIcon("txt",KIcon::Desktop);
            drag->setPixmap(icon,QPoint(icon.width()/2,icon.height()/2));
            drag->drag();
         }
         else
         {
            QListView::contentsMouseMoveEvent(event);
         }
      }
      else
      {
         QListView::contentsMouseMoveEvent(event);
      }
   }
   else
   {
      QListView::contentsMouseMoveEvent(event);
   }
}

void CatalogManagerView::readMarker( KConfig* config)
{
   KConfigGroupSaver cs(config,"CatalogManager");

   _markerList = config->readListEntry("Marker");
}

void CatalogManagerView::saveMarker( KConfig* config) const
{
   KConfigGroupSaver cs(config,"CatalogManager");

   config->writeEntry("Marker",_markerList);
   config->sync();
}


void CatalogManagerView::deleteDirItem(QString relDir)
{
	CatManListItem* thisItem=_dirList[relDir];

	if(!thisItem)
		return;

	_dirList.remove(relDir);

	QStringList childList = thisItem->allChildrenList();

	QStringList::Iterator it;
	for( it = childList.begin();it !=  childList.end(); ++it )
    {
		if(!_fileList.remove((*it)))
			_dirList.remove((*it));
	}


	// delete the item with all sub item
	delete thisItem;
}



void CatalogManagerView::processEnded(KProcess* proc)
{
   _pendingProcesses.removeRef(proc);
}


void CatalogManagerView::showOutput(KProcess*, char *buffer, int buflen)
{
   QCString output(buffer,buflen+1);

   _logView->insert(output);
}

CatManListItem *CatalogManagerView::itemBelow( CatManListItem *item )
{
    if( item->isDir() )
    {
	if( item->firstChild() )
	    return static_cast<CatManListItem *>( item->firstChild() );
	else
	{
	    while( !static_cast<CatManListItem *>( item->nextSibling() ) )
	    {
		item = static_cast<CatManListItem *>( item->parent() );
		if( !item ) return item;
	    }
	    return static_cast<CatManListItem *>( item->nextSibling() );
	}
    }
    else
    {
	while( !static_cast<CatManListItem *>( item->nextSibling() ) )
	{
	    item =  static_cast<CatManListItem *>( item->parent());
	    if( !item ) return item;
	}
	return static_cast<CatManListItem *>( item->nextSibling() );
    }
}

CatManListItem *CatalogManagerView::itemAbove( CatManListItem *item )
{
    if( item->isDir() )
    {
	if( item->firstChild() )
	    return static_cast<CatManListItem *>( item->lastChild() );
	else
	{
	    while( !static_cast<CatManListItem *>( item->previousSibling() ) )
	    {
		item = static_cast<CatManListItem *>( item->parent() );
		if( !item ) return item;
	    }
	    return static_cast<CatManListItem *>( item->previousSibling() );
	}
    }
    else
    {
	while( !static_cast<CatManListItem *>( item->previousSibling() ) )
	{
	    item =  static_cast<CatManListItem *>( item->parent());
	    if( !item ) return item;
	}
	return static_cast<CatManListItem *>( item->previousSibling() );
    }
}

void CatalogManagerView::gotoNextUntranslated()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->untranslated() > 0 )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousUntranslated()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->untranslated() > 0 )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoNextFuzzy()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->fuzzy() > 0 )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousFuzzy()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->fuzzy() > 0 )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoNextFuzzyOrUntranslated()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->untranslated() > 0 || i->fuzzy() > 0 )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousFuzzyOrUntranslated()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->untranslated() > 0 || i->fuzzy() > 0 )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoNextError()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->hasErrors() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousError()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->hasErrors() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoNextTemplate()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->hasPot() && !i->hasPo() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousTemplate()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->hasPot() && !i->hasPo() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoNextPo()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->hasPo() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousPo()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->hasPo() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoNextMarked()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( ( i = itemBelow(current)) )
    {
	if( i->marked() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

void CatalogManagerView::gotoPreviousMarked()
{
    CatManListItem *i;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    while( (i = itemAbove(current)) )
    {
	if( i->marked() )
	{
	    setCurrentItem(i);
	    ensureItemVisible(i);
	    return;
	} else current = i;
    }
}

QStringList CatalogManagerView::current()
{
    QStringList result;
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    if( current->isDir() )
    {
	QStringList s = current->allChildrenList(true);
	QStringList::Iterator it;
	for( it = s.begin() ; it != s.end(); it++ )
	{
	    CatManListItem *item = _fileList[(*it)];
	    result.append( item->poFile() );
	}
    }
    else
    {
	if( current->hasPo() ) result.append( current->poFile() );
    }
    return result;
}

QStringList CatalogManagerView::marked()
{
    QStringList result;

    QStringList::Iterator it;
    for( it = _markerList.begin() ; it != _markerList.end(); it++ )
    {
	CatManListItem *item = _fileList[(*it)];
	result.append( item->poFile() );
    }
    return result;
}

void CatalogManagerView::updateCurrent()
{
    CatManListItem *current = static_cast<CatManListItem *>(currentItem());
    if( !current->hasPo() && !current->hasPot() )
    {
	if( current->isFile() )
	{
	    _fileList.remove(current->package());
	    delete current;
	}
	else
	{
	    directoryDeleted(current->package());
	}
    }
    else
    {
	if( current->isDir() )
	{
	    directoryChanged(current->poFile() );
	}
        current->forceUpdate();
    }
}

#include "catalogmanagerview.moc"
