Logo Search packages:      
Sourcecode: kdesdk version File versions

KDBSearchEngine.cpp

/***************************************************************************
                          KDBSearchEngine.cpp  -  description
                             -------------------
    begin                : Fri Sep 8 2000
    copyright            : (C) 2000 by Andrea Rizzi
    email                : rizzi@kde.org
 ***************************************************************************/

/*
 Translation search engine


  Copyright  2000
  Andrea Rizzi rizzi@kde.org

  License GPL v 2.0

*/

#include <qtextedit.h>
#include <qprogressdialog.h>

#include <qinputdialog.h>
#include <kdeversion.h>
#include <klocale.h>
#include <kdebug.h>
#include <kio/netaccess.h>
#include <kmessagebox.h>
#include <kfiledialog.h>
#include <kurlrequester.h>
#include <kstandarddirs.h>

#include "kapplication.h"
#include "KDBSearchEngine.h"

#include "dbscan.h"

#include "errno.h"
#include "stdio.h"
#include "stdlib.h"
#include <sys/time.h>
#include "preferenceswidget.h"
#include "dbse_factory.h"
#include <qprogressbar.h>
#include <qpushbutton.h>
#include <klineedit.h>
#include <kconfig.h>

#include <qdir.h>
#include <qradiobutton.h>
#include <qcheckbox.h>
#include <qspinbox.h>
#include <qslider.h>
#include <qmemarray.h>

#include "database.h"

#include "catalogsettings.h"

#define BIGNUMBER 400000000

using namespace KBabel;

KDBSearchEngine::KDBSearchEngine (QObject * parent, const char *name):
SearchEngine (parent, name)
{
    edited = "unknown";
    dm = 0;             //Database Manager
    pw = 0;             //Preference widget
    lang = "";
    dbOpened = false;
    dbname = "";
    lasterror = i18n ("No error");
    connect (this, SIGNAL (hasError (const QString &)),
           SLOT (setLastError (const QString &)));

    IAmReady = true;          //  I don't know if it is a good idea, no DB loaded!!!

    scanInProgress = false;
    searching = false;
    stopNow = false;

    norm = false;       // Normalize white space = FALSE
    comm = true;        // Remove Comments = TRUE

}


KDBSearchEngine::~KDBSearchEngine ()
{
}



bool
KDBSearchEngine::loadDatabase (QString database, bool noask = false)
{
    bool ret = true;
    bool asked = false;
    if (noask)
      asked = true;
    if (dm != 0)
      {
        delete dm;
        dm = 0;
      }

    QDir dir (database);
    if (!dir.exists ())
      {
        if (asked
            || KMessageBox::questionYesNo (0,
                                   i18n
                                   ("Database folder does not exist:\n%1\n"
                                    "Do you want to create it now?").
                                   arg (database)) ==
            KMessageBox::Yes)
          {
            asked = true;

            QStringList dirList;
            while (!dir.exists () && !dir.dirName ().isEmpty ())
              {
                  dirList.prepend (dir.dirName ());
                  dir.setPath (dir.path () + "/..");
              }

            for (QStringList::Iterator it = dirList.begin ();
                 it != dirList.end (); ++it)
              {
                  if (!dir.mkdir (*it))
                  {
                      KMessageBox::sorry (0,
                                    i18n
                                    ("It was not possible to create folder %1").
                                    arg (dir.path () + "/" +
                                         (*it)));
                      ret = false;
                      break;
                  }
                  dir.cd (*it);
              }
          }
        else
          {
            ret = false;
          }
      }

    if (ret)
      {
        // test, if there are both of ,old and standard databases
        QString transFile = database + "/translations." + lang + ".db";

        bool oldstuff = QFile::exists (transFile + ",old");
        bool newstuff = QFile::exists (transFile);

        if (oldstuff && newstuff)
          {
            // there is an old db2 database, ask user

            if (KMessageBox::
                questionYesNo (0,
                           i18n
                           ("<p>There are backup database files from previous versions "
                            "of KBabel. However, another version of KBabel (probably from KDE 3.1.1 or 3.1.2) "
                            "created a new database. As a result, your KBabel installation contains two versions "
                            "of database files. Unfortunatelly, the old and new version "
                            "can not be merged. You need to choose one of them.<br/><br/>"
                            "If you choose the old version, the new one will be removed. "
                            "If you choose the new version, the old database files will be left alone "
                            "and you need to remove them manually. Otherwise this message will be displayed "
                            "again (the old files are at $KDEHOME/share/apps/kbabeldict/dbsearchengine/*,old).</p>"),
                           i18n ("Old Database Found"),
                           i18n ("Use &Old Database"),
                           i18n ("Use &New Database")) ==
                KMessageBox::Yes)
              {
                  // remove the new files
                  QFile::remove (transFile);
                  QFile::remove (database + "/wordsindex." + lang +
                             ".db");
                  QFile::remove (database + "/keysindex." + lang + ".db");
                  QFile::remove (database + "/catalogsinfo." + lang +
                             ".db");

                  // rename the old files
                  KIO::NetAccess::copy (KURL (transFile + ",old"),
                                  KURL (transFile));
                  KIO::NetAccess::
                    copy (KURL
                        (database + "/wordsindex." + lang +
                         ".db,old"),
                        KURL (database + "/wordsindex." + lang +
                              ".db"));
                  KIO::NetAccess::
                    copy (KURL
                        (database + "/keysindex." + lang + ".db,old"),
                        KURL (database + "/keysindex." + lang +
                              ".db"));
                  KIO::NetAccess::
                    copy (KURL
                        (database + "/catalogsinfo." + lang +
                         ".db,old"),
                        KURL (database + "/catalogsinfo." + lang +
                              ".db"));

                  QFile::remove (transFile + ",old");
                  QFile::remove (database + "/wordsindex." + lang +
                             ".db,old");
                  QFile::remove (database + "/keysindex." + lang +
                             ".db,old");
                  QFile::remove (database + "/catalogsinfo." + lang +
                             ".db,old");
              }
          }
        else if (oldstuff)
          {
            // rename the old files
            KIO::NetAccess::copy (KURL (transFile + ",old"),
                              KURL (transFile));
            KIO::NetAccess::
                copy (KURL (database + "/wordsindex." + lang + ".db,old"),
                    KURL (database + "/wordsindex." + lang + ".db"));
            KIO::NetAccess::
                copy (KURL (database + "/keysindex." + lang + ".db,old"),
                    KURL (database + "/keysindex." + lang + ".db"));
            KIO::NetAccess::
                copy (KURL
                    (database + "/catalogsinfo." + lang + ".db,old"),
                    KURL (database + "/catalogsinfo." + lang + ".db"));

            QFile::remove (transFile + ",old");
            QFile::remove (database + "/wordsindex." + lang + ".db,old");
            QFile::remove (database + "/keysindex." + lang + ".db,old");
            QFile::remove (database + "/catalogsinfo." + lang +
                         ".db,old");
          }

        dm = new DataBaseManager (database, lang, this, "Database manager");

        if (!dm->isOk ())
          {
            if (asked
                || KMessageBox::questionYesNo (0,
                                       i18n
                                       ("Database files not found.\nDo you want to create them now?"))
                == KMessageBox::Yes)
              {
                  //fprintf(stderr,"SI\n");
                  ret = dm->createDataBase (database, lang);
              }
            else
                ret = false;
          }
        else
            ret = true;
      }

//Wrong errore hangdling

    if (ret)
      totalRecord = dm->count ();
    else
      totalRecord = 0;

    return ret;
}


/*
   Set if the research have to consider multiple spaces as a single one.
 */

void
KDBSearchEngine::setNormalizeSpace (bool normalize)
{
    norm = normalize;
}


void
KDBSearchEngine::setRemoveInternalComment (bool internalcomment)
{
    comm = internalcomment;
}

/*
   Set if the research have to be Case Sensitive or not
 */

void
KDBSearchEngine::setCaseSensitive (bool sensitive)
{
    sens = sensitive;
}

/*
   Set the a string containing all char that must be ignored
   during the search.
 */

void
KDBSearchEngine::setRemoveCharString (QString chartoremove)
{
    remchar = chartoremove;
}

/*
   Return true if there's a search in progress.
  */
bool
KDBSearchEngine::isSearching () const
{
    return searching;
}




/*
   Add a search string in the list of the string to search for.
   Returns the ID of the string in the list.
   Returns -1 if there is a problem (may be search in progress)
  */

int
KDBSearchEngine::addSearchString (QString searchString, int rule)
{
    if (searching || scanInProgress)
      return -1;
    SearchEntry e;
    e.string = QString (searchString);
    e.rules = rule;
    searchStringList.append (e);
    return searchStringList.count ();
}


/*
   Start the research in the database of all the string in the list

  */

bool
KDBSearchEngine::startSearch (const QString & str, uint pluralForm,
                        const SearchFilter * filter)
{

    if (autoUpdate)
      {
        updateSettings ();
      }


    int l1 = 0, l2 = 0;
    if (defSub1)
      l1 = defLimit1;
    if (defSub2)
      l2 = defLimit2;

    return startSingleSearch (str, l1, l2);


}

bool
KDBSearchEngine::startSearchInTranslation (QString s)
{

    if (autoUpdate)
      {
        updateSettings ();
      }


    int l1 = 0, l2 = 0;
    if (defSub1)
      l1 = defLimit1;
    if (defSub2)
      l2 = defLimit2;


    return startSingleSearch (s, l1, l2, true);

}


bool
KDBSearchEngine::openDb (bool noask = false)
{
    if (!dbOpened)
      {
        dbOpened = loadDatabase (dbname, noask);      //Try first to open it now
        if (!dbOpened)  // Still not opened!!
          {
            hasError (i18n ("Cannot open the database"));
            return false;
          }
      }

    return true;
}




bool
KDBSearchEngine::messagesForFilter (const SearchFilter * filter,
                            QValueList < SearchResult > &resultList,
                            QString & error)
{

    int count = 0;
    stopNow = false;          // Remove dirty.
    SearchResult m;

    if (searching)
      {
        error = i18n ("Another search has already been started");
        return false;
      }

    if (scanInProgress)
      {
        error =
            i18n ("Unable to search now: a PO file scan is in progress");
        return false;
      }


    if (!openDb ())
      {
        error = i18n ("Unable to open the database");
        return false;
      }

    if (totalRecord <= 0)
      {
        error = i18n ("Database empty");
        return false;
      }

    QString package = filter->location ();

    int step = (totalRecord / 30) + 1;
    int ntra, nref;
    int req = dm->searchCatalogInfo (package);
    if (req == -1)
      {
        error = i18n ("No entry for this package in the database.");
        return false;
      }
    DataBaseItem item;
    int i, h;
    kdDebug (0) << "looking for catalog " << req << endl;

    progressStarts (i18n ("Searching for %1 in database").arg (package));

    for (item = dm->firstItem (); !item.isNull (); item = dm->nextItem ())
      {
        count++;
        if (count % step == 0)
          {
            emit progress (100 * count / totalRecord);
            kapp->processEvents (100);
          }
        if (stopNow)
          {
            stopNow = false;
            searching = false;
            emit finished ();
            return true;      // No error, stopped!
          }

        ntra = item.numTra;
        for (i = 0; i < ntra; i++)
          {
            nref = item.translations[i].numRef;

            for (h = 0; h < nref; h++)
              {
                  if (item.translations[i].infoRef[h] == req)
                  {
                      m.found = item.key;
                      m.translation = item.translations[i].translation;
                      resultList.append (m);
                  }
              }
          }

      }

    return true;
}

void
KDBSearchEngine::repeat ()
{

    int count = 0;
    stopNow = false;          // Remove dirty.

    if (searching)
      {
        return;
      }

    if (scanInProgress)
      {
        return;
      }


    if (!openDb ())
      {
        return;
      }

    if (totalRecord <= 0)
      {
        return;
      }

    int step = (totalRecord / 30) + 1;
    int ntra, nref;

    DataBaseItem item;
    int i, h, tot;

    int req = dm->searchCatalogInfo ("kdelibs.po");
    if (req == -1)
      kdDebug (0) << "No kdelibs.po found!" << endl;


    QProgressDialog *pd =
      new QProgressDialog (i18n ("Looking for repetitions"), i18n ("Stop"),
                       100);

    connect (this, SIGNAL (progress (int)), pd, SLOT (setProgress (int)));
    connect (this, SIGNAL (finished ()), pd, SLOT (close ()));
    connect (pd, SIGNAL (cancelled ()), this, SLOT (stopSearch ()));


    QString txt = "// %1 repetitions, %2 translation(s)\ni18n(\"%3\");\n";
    QString id;
    int min;
    bool ok = false;

    min =
      QInputDialog::getInteger (i18n ("Minimum Repetition"),
                          i18n
                          ("Insert the minimum number of repetitions for a string:"),
                          2, 1, 999999, 1, &ok);

    if (!ok)
      return;

    pd->show ();

    progressStarts (i18n ("Searching repeated string"));

    static QTextEdit *mle = new QTextEdit ();
    mle->clear ();

    bool inlibs;

    for (item = dm->firstItem (); !item.isNull (); item = dm->nextItem ())
      {
        count++;
        if (count % step == 0)
          {
            emit progress (100 * count / totalRecord);
            kapp->processEvents (100);
          }
        if (stopNow)
          {
            stopNow = false;
            searching = false;
            emit finished ();
            return;           // No error, stopped!
          }
        tot = 0;
        inlibs = false;
        ntra = item.numTra;
        for (i = 0; i < ntra; i++)
          {
            nref = item.translations[i].numRef;
            for (h = 0; h < nref; h++)
                if (item.translations[i].infoRef[h] == req)
                  inlibs = true;

            tot += nref;
          }

        if (tot >= min && !inlibs)
          {
            id = item.key;
            id = id.replace ("\n", "\"\n\"");
            mle->append (txt.arg (tot).arg (ntra).arg (id));

          }
      }


    emit progress (100);
    emit finished ();
    mle->resize (400, 400);
    mle->show ();

    delete pd;
    return;
}



bool
KDBSearchEngine::startSearchNow (int searchmode)
{
    if (searchmode == -1)
      searchmode = mode;
    int count = 0;
    stopNow = false;          // Remove dirty.
    clearResults ();


    if (searching)
      {
        hasError (i18n ("Another search has already been started"));
        return false;
      }

    if (scanInProgress)
      {
        hasError (i18n
                ("Unable to search now: a PO file scan is in progress"));
        return false;
      }


    if (!openDb ())
      return false;


    if (totalRecord <= 0)
      {
        hasError (i18n ("Database empty"));
        return false;
      }



    searching = true;

    emit started ();

    bool allkey = (searchmode == MD_ALL_GOOD_KEYS);

    bool equal, contains, contained, regexp, intra;

    intra = searchmode & MD_IN_TRANSLATION;

    QString msgIdFound;
    QString msgId;
    QString msgStr;
    //QString msgIdRequested;
    SearchResult *aresult;
    TranslationInfo *adescription;
    SearchList searchList;
    int i, len, files, h;
    len = remchar.length ();

    int n, m;                 //,word;
    QString *id;

    QString mainRequest = searchStringList[0].string;


    SearchList::Iterator it, it1;
    QString *idMod;
    bool foundSomething = false;

    searchList = searchStringList;  //Create a copy and modify it
    if (!allkey)
      {
        for (it = searchList.begin (); it != searchList.end (); ++it)
          {
            idMod = &((*it).string);
            int pos;
            for (i = 0; i < len; i++)
              {
                  while ((pos = idMod->find (remchar.at (i))) != -1)
                    idMod->remove (pos, 1);
              }

            if (comm)
                idMod->replace (QRegExp ("\\_\\:.*\\\\n"), "");   //Read it from catalog !!! (NOT ONLY HERE)


            if (norm)
                idMod->simplifyWhiteSpace ();
            if (!sens)
                *idMod = idMod->upper ();
          }

      }

    timeval now;
    gettimeofday (&now, NULL);
    //fprintf(stderr,"\n%ld.%ld\n",now.tv_sec,now.tv_usec);
    //double tim=1.0*now.tv_usec/1000000.0+now.tv_sec;
    int pos;



    DataBaseItem item;


    //Now we can browse the whole db or the "good keys"
    QValueList < KeyAndScore > goodkeys;
    int totalprogress;

    bool gk = (searchmode == MD_GOOD_KEYS) || allkey;
    int k = 0;

    if (gk)
      {
        goodkeys = searchWords (mainRequest, thre, threorig, listmax);  //FIX IT, mainReq?
        if (goodkeys.count () == 0)
            gk = false; // if no good keys, use the whole database
      }
    totalprogress = gk ? goodkeys.count () : totalRecord;
    int step = (totalprogress / 30) + 1;

    for (item = gk ? (dm->getItem (goodkeys[0])) : (dm->firstItem ());
       !item.isNull ();
       item = gk ? (dm->getItem (goodkeys[++k])) : (dm->nextItem ()))
      {


//   Emit progress, process event and check stop now
        if (count % step == 0)
          {
            emit progress (100 * count / /*QMAX( */
                         totalprogress /*,1) */ );
            kapp->processEvents (100);
          }
        if (stopNow)
          {
            stopNow = false;
            searching = false;
            emit finished ();
            return true;      // No error, stopped!
          }

        //  fprintf(stderr,"%s\n",(const char *)item.key.utf8());
        msgIdFound = item.key;      //Check if this is OK with UTF8

//     searchmode && MD_IN_TRANSLATION)

        count++;



        msgId = msgIdFound;

        if (!allkey)
          {

            //Remove character in list of character to be ignored
            for (i = 0; i < len; i++)
                while ((pos = msgId.find (remchar.at (i))) != -1)
                  msgId.remove (pos, 1);

            //Remove context information from id found
            if (comm)
                msgId.replace (QRegExp ("\\_\\:.*\\\\n"), "");


            if (norm)
                msgId.simplifyWhiteSpace ();
            if (!sens)
                msgId = msgId.upper ();
          }



        it = searchList.begin ();
        idMod = &((*it).string);
        bool foundExact = false;


        for (it1 = searchStringList.begin ();
             it1 != searchStringList.end (); it1++)
          {

            id = &((*it1).string);
            uint nn = 0;
            do
              {
                  if (intra)
                  {
                      msgId = item.translations[nn].translation;
                      if (!allkey)
                        {
                          //Remove character in list of character to be ignored
                          for (i = 0; i < len; i++)
                              while ((pos =
                                    msgId.find (remchar.at (i))) !=
                                   -1)
                                msgId.remove (pos, 1);

                          //Remove context information from id found
                          if (comm)
                              msgId.
                                replace (QRegExp ("\\_\\:.*\\\\n"),
                                       "");


                          if (norm)
                              msgId.simplifyWhiteSpace ();
                          if (!sens)
                              msgId = msgId.upper ();
                        }


                  }


                  int rules = (*it).rules;

                  if (rules & Equal)
                    equal = (*idMod == msgId);
                  else
                    equal = false;

                  if (rules & Contains)
                    contains = idMod->contains (msgId);
                  else
                    contains = false;

                  if (rules & Contained)
                    contained = msgId.contains (*idMod);
                  else
                    contained = false;

                  if (!foundExact && (rules & RegExp))
                  {
                      QRegExp reg (*idMod);
                      regexp = (reg.search (msgId) != -1);
                  }
                  else
                    regexp = false;
                  nn++;
              }
            while (intra && nn < item.numTra);

            if (equal || contains || contained || regexp || allkey)
              {

//           kdDebug(0) << QString("Found") << endl;


                  if (equal)
                    foundExact = true;

                  m = item.numTra;  //Translations found.

                  for (n = 0; n < m; n++)
                  {

                      foundSomething = true;


                      msgStr = item.translations[n].translation;

                      files = item.translations[n].numRef;

                      aresult = new SearchResult ();

                      results.setAutoDelete (true);
                      if (!gk)
                        aresult->score =
                            score (mainRequest, msgIdFound);
                      else
                        aresult->score = goodkeys[k].score;

                      if (intra)
                        aresult->score =
                            score (mainRequest,
                                 item.translations[n].translation);


                      SearchResult *s = 0;
                      for (s = results.first (); s != 0;
                         s = results.next ())
                        {
                          if (s->score > aresult->score)
                            {
                              results.insert (results.at (),
                                          aresult);
                              break;
                            }

                        }
                      if (s == 0)   //no break or empty list
                        results.append (aresult);


/*            if(*id==msgIdFound)  //Put it first of the list
              results.prepend(aresult);
                else
              results.append(aresult);
*/
                      aresult->requested = *id;
                      aresult->found = msgIdFound;
                      aresult->translation = msgStr;
                      aresult->descriptions.setAutoDelete (true);
                      for (h = 0; h < files; h++)
                        {

                          aresult->descriptions.append (adescription =
                                                new
                                                TranslationInfo
                                                ());
                          int rr = item.translations[n].infoRef[h];

                          InfoItem info = dm->getCatalogInfo (rr);


                          adescription->location = info.catalogName;
                          adescription->translator =
                              info.lastTranslator;
                          adescription->filePath = info.lastFullPath;
                        }

                      emit numberOfResultsChanged (results.count ());
                      emit resultFound (aresult);

//                if(*id==msgIdFound)  //Put it first of the list so th order change
                      emit resultsReordered ();



                  }
              }
            //        idMod=searchList.next();
            it++;
            idMod = &((*it).string);
          }


      }
    gettimeofday (&now, NULL);
    //fprintf(stderr,"%ld.%ld\n",now.tv_sec,now.tv_usec);

    //fprintf(stderr,"Finish, %d (of %d) records in %f seconds!!\n",count,totalRecord, 1.0*now.tv_usec/1000000.0+now.tv_sec-tim);
    emit progress (100);
    emit finished ();

    searching = false;
    return true;        //foundSomething;
}

/*
  Start a search for a single string
 */

bool
KDBSearchEngine::startSingleSearch (QString searchString,
                            unsigned int pattern1Limit,
                            unsigned int /*pattern2Limit */ ,
                            bool inTranslation)
{
    /*
       Check Ret
       value.
     */

    unsigned int nw = 0;
    int in = 0, len = 0;
    clearList ();
    addSearchString (searchString, defRule);



    QRegExp reg ("[a-zA-Z0-9_%" /*+remchar */  + regaddchar + "]+");
    while ((in = reg.search (searchString, in + len)) != -1)
      {
        nw++;
        len = reg.matchedLength ();
      }
    in = 0;
    len = 0;
    // fprintf(stderr,"asas %d\n",nw);

    if (mode == MD_ALL_GOOD_KEYS && !inTranslation)
      return startSearchNow ();



    if ((nw < pattern1Limit) && (nw > 1))
      for (unsigned int k = 0; k < nw; k++)
        {
            in = reg.search (searchString, in + len);
            len = reg.matchedLength ();
            QString regToAdd = searchString;
            regToAdd.replace (in, len, "[a-zA-Z0-9_%" + regaddchar + "]*");
            regToAdd.append ("$");
            regToAdd.prepend ("^");
//      fprintf(stderr,"%s",(const char *)regToAdd.local8Bit());
            addSearchString (regToAdd, RegExp);
        }

    if (inTranslation)
      return startSearchNow (MD_IN_TRANSLATION);
    else
      return startSearchNow ();

    return false;

}


/*
  Start a search for a list of string
 */

//bool KDBSearchEngine::startListSearch(QPtrList<QString> searchStrList)
//{
  //  searchStringList=searchStrList;
//  return startSearchNow();
//}
/*
  Stop the current search
  */



void
KDBSearchEngine::setLanguageCode (const QString & ll)
{
    if (ll == lang)
      return;

    lang = ll;
    if (dbOpened)       //if opened open it again with new code, what about close before open ?
      dbOpened = loadDatabase (dbname);

}

void
KDBSearchEngine::setLanguage (const QString & languageCode,
                        const QString & /*languageName */ )
{
    setLanguageCode (languageCode);
}

void
KDBSearchEngine::stopSearch ()
{
    stopNow = true;
}


void
KDBSearchEngine::clearList ()
{
    searchStringList.clear ();
}

bool
KDBSearchEngine::isReady () const 
{
    return IAmReady;
}


void
KDBSearchEngine::saveSettings (KConfigBase * config)
{
// updateSettings();  //maybe with autoupdate
    KConfigGroupSaver cgs (config, "KDBSearchEngine");
#if KDE_IS_VERSION(3,1,3)
    config->writePathEntry ("Filename", dbname);
#else
    config->writeEntry ("Filename", dbname);
#endif
    config->writeEntry ("Language", lang);


    config->writeEntry ("CaseSensitive", sens);
    config->writeEntry ("Normalize", norm);
    config->writeEntry ("RemoveContext", comm);

    config->writeEntry ("Rules", defRule);
    config->writeEntry ("Limit1", defLimit1);
    config->writeEntry ("Limit2", defLimit2);
    config->writeEntry ("Substitution1", defSub1);
    config->writeEntry ("Substitution2", defSub2);

    config->writeEntry ("RegExp", regaddchar);
    config->writeEntry ("RemoveCharacter", remchar);

    config->writeEntry ("Threshold1", thre);
    config->writeEntry ("Threshold2", threorig);
    config->writeEntry ("ListMax", listmax);
    config->writeEntry ("Mode", mode);
    config->writeEntry ("CommonThrs", commonthre);
    config->writeEntry ("ReturnNothing", retnot);

    config->writeEntry ("AutoAuthor", autoauthor);
    config->writeEntry ("AutoUp", autoup);

}


void
KDBSearchEngine::readSettings (KConfigBase * config)
{
    QString newName;

    KConfigGroupSaver cgs (config, "KDBSearchEngine");

    QString defaultLang;
    QString oldLang = lang;
    Defaults::Identity def;
    defaultLang = def.languageCode ();
    lang = config->readEntry ("Language", defaultLang);

    QString defaultDir;
    KStandardDirs *dirs = KGlobal::dirs ();
    if (dirs)
      {
        defaultDir = dirs->saveLocation ("data");
        if (defaultDir.right (1) != "/")
            defaultDir += "/";
        defaultDir += "kbabeldict/dbsearchengine";
      }

    newName = config->readPathEntry ("Filename", defaultDir);

    if (newName != dbname || oldLang != lang)
      {
        dbname = newName;
        if (dbOpened)         //Reload only if it is opened
            dbOpened = loadDatabase (dbname);
      }

    sens = config->readBoolEntry ("CaseSensitive", false);
    norm = config->readBoolEntry ("Normalize", true);
    comm = config->readBoolEntry ("RemoveContext", true);

    defRule = config->readNumEntry ("Rules", 1);
    defLimit1 = config->readNumEntry ("Limit1", 20);
    defLimit2 = config->readNumEntry ("Limit2", 8);

    thre = config->readNumEntry ("Threshold1", 50);
    threorig = config->readNumEntry ("Threshold2", 50);
    listmax = config->readNumEntry ("ListMax", 500);
    mode = config->readNumEntry ("Mode", MD_GOOD_KEYS);

    defSub1 = config->readBoolEntry ("Substitution1", true);
    defSub2 = config->readBoolEntry ("Substitution2", false);

    regaddchar = config->readEntry ("RegExp");
    remchar = config->readEntry ("RemoveCharacter", "&.:");
    commonthre = config->readNumEntry ("CommonThrs", 300);
    retnot = config->readBoolEntry ("ReturnNothing", false);
    autoauthor = config->readEntry ("AutoAuthor");
    autoup = config->readBoolEntry ("AutoUp", true);

    setSettings ();
}

PrefWidget *
KDBSearchEngine::preferencesWidget (QWidget * parent)
{

    pw = new PreferencesWidget (parent);
    setSettings ();
    connect (pw, SIGNAL (restoreNow ()), this, SLOT (setSettings ()));
    connect (pw, SIGNAL (applyNow ()), this, SLOT (updateSettings ()));
    connect (pw, SIGNAL (destroyed ()), this, SLOT (prefDestr ()));
    connect (pw->dbpw->scanPB_2, SIGNAL (clicked ()), this, SLOT (scan ()));
    connect (pw->dbpw->scanrecPB, SIGNAL (clicked ()), this,
           SLOT (scanRecur ()));
    connect (pw->dbpw->scanFilePB, SIGNAL (clicked ()), this,
           SLOT (scanFile ()));
    connect (pw->dbpw->repeatPB, SIGNAL (clicked ()), this, SLOT (repeat ()));


    return pw;
}

void
KDBSearchEngine::scanRecur ()
{
    if (scanInProgress)
      return;
    updateSettings ();

    if (!openDb ())
      return;
    scanInProgress = true;
    PoScanner *sca = new PoScanner (dm, this, "Po Scanner");
    QString cvsdir;
    cvsdir =
      KFileDialog::getExistingDirectory ("", 0,
                                 i18n
                                 ("Select Folder to Scan Recursively"));

    if (cvsdir.isEmpty ())
      {
        scanInProgress = false;
        return;
      }
    if (pw)
      {
        connect (sca, SIGNAL (patternProgress (int)), pw->dbpw->totalPB,
               SLOT (setProgress (int)));
        connect (sca, SIGNAL (fileLoading (int)), pw->dbpw->loadingPB,
               SLOT (setProgress (int)));
        connect (sca, SIGNAL (fileProgress (int)), pw->dbpw->processPB,
               SLOT (setProgress (int)));
      }

    connect (sca, SIGNAL (patternProgress (int)), SIGNAL (progress (int)));   //Kbabel progress bar

    connect (sca, SIGNAL (added (int)), pw, SLOT (setEntries (int)));
    connect (sca, SIGNAL (filename (QString)), pw, SLOT (setName (QString)));


    progressStarts (i18n ("Scanning folder %1").arg (cvsdir));
    connect (sca, SIGNAL (patternFinished ()), SIGNAL (progressEnds ()));

    sca->scanPattern (cvsdir, "*.po", true);
    disconnect (this, SIGNAL (progress (int)));
//disconnect(SIGNAL(patternStarted()),this,SIGNAL(started()) );
    disconnect (this, SIGNAL (progressEnds ()));
    if (pw)
      {
        disconnect (pw->dbpw->totalPB, SLOT (setProgress (int)));
        disconnect (pw->dbpw->loadingPB, SLOT (setProgress (int)));
        disconnect (pw->dbpw->processPB, SLOT (setProgress (int)));
      }
    totalRecord = dm->count ();

    scanInProgress = false;
    dm->sync ();
    delete sca;
}


void
KDBSearchEngine::scan ()
{
    if (scanInProgress)
      return;
    updateSettings ();

    if (!openDb ())
      return;
    scanInProgress = true;
    PoScanner *sca = new PoScanner (dm, this, "Po Scanner");
    QString cvsdir;

    cvsdir =
      KFileDialog::getExistingDirectory ("", 0,
                                 i18n ("Select Folder to Scan"));
    if (cvsdir.isEmpty ())
      {
        scanInProgress = false;
        return;
      }
    if (pw)
      {
        connect (sca, SIGNAL (patternProgress (int)), pw->dbpw->totalPB,
               SLOT (setProgress (int)));
        connect (sca, SIGNAL (fileLoading (int)), pw->dbpw->loadingPB,
               SLOT (setProgress (int)));
        connect (sca, SIGNAL (fileProgress (int)), pw->dbpw->processPB,
               SLOT (setProgress (int)));
      }
    connect (sca, SIGNAL (patternProgress (int)), SIGNAL (progress (int)));
    progressStarts (i18n ("Scanning folder %1").arg (cvsdir));
    connect (sca, SIGNAL (patternFinished ()), SIGNAL (progressEnds ()));

    connect (sca, SIGNAL (added (int)), pw, SLOT (setEntries (int)));
    connect (sca, SIGNAL (filename (QString)), pw, SLOT (setName (QString)));



    sca->scanPattern (cvsdir, "*.po", false);

    disconnect (this, SIGNAL (progress (int)));
//disconnect(SIGNAL(patternStarted()),this,SIGNAL(started()) );
    disconnect (this, SIGNAL (progressEnds ()));
    if (pw)
      {
        disconnect (pw->dbpw->totalPB, SLOT (setProgress (int)));
        disconnect (pw->dbpw->loadingPB, SLOT (setProgress (int)));
        disconnect (pw->dbpw->processPB, SLOT (setProgress (int)));
      }
    totalRecord = dm->count ();

    scanInProgress = false;

    dm->sync ();
    delete sca;
}

void
KDBSearchEngine::scanFile ()
{
    if (scanInProgress)
      return;
    updateSettings ();

    if (!openDb ())
      return;
    scanInProgress = true;
    PoScanner *sca = new PoScanner (dm, this, "Po Scanner");
    QString cvsdir;
    pw->dbpw->totalPB->setProgress (0);

    cvsdir =
      KFileDialog::getOpenFileName ("", "*.po", 0,
                              i18n ("Select PO File to Scan"));
    if (cvsdir.isEmpty ())
      {
        scanInProgress = false;
        return;
      }
    if (pw)
      {
        connect (sca, SIGNAL (fileLoading (int)), pw->dbpw->loadingPB,
               SLOT (setProgress (int)));
        connect (sca, SIGNAL (fileProgress (int)), pw->dbpw->processPB,
               SLOT (setProgress (int)));
      }
    connect (sca, SIGNAL (fileProgress (int)), SIGNAL (progress (int)));
    progressStarts (i18n ("Scanning file %1").arg (directory (cvsdir, 0)));
    connect (sca, SIGNAL (fileFinished ()), SIGNAL (progressEnds ()));

    connect (sca, SIGNAL (added (int)), pw, SLOT (setEntries (int)));
    connect (sca, SIGNAL (filename (QString)), pw, SLOT (setName (QString)));



    sca->scanFile (cvsdir);

    sca->disconnect (SIGNAL (fileProgress (int)), this,
                 SIGNAL (progress (int)));
//disconnect(SIGNAL(patternStarted()),this,SIGNAL(started()) );
    sca->disconnect (SIGNAL (fileFinished ()), this,
                 SIGNAL (progressEnds ()));
    if (pw)
      {
        disconnect (pw->dbpw->loadingPB, SLOT (setProgress (int)));
        disconnect (pw->dbpw->processPB, SLOT (setProgress (int)));
      }

    totalRecord = dm->count ();

    scanInProgress = false;

    dm->sync ();
    delete sca;
}

const KAboutData *
KDBSearchEngine::about () const
{

    return DbSeFactory::instance ()->aboutData ();

}

QString
KDBSearchEngine::name () const
{
    return i18n ("Translation Database");
}

QString
KDBSearchEngine::id () const
{
    return QString ("KDBSearchEngine");
}

QString
KDBSearchEngine::lastError ()
{
    return lasterror;
}

void
KDBSearchEngine::prefDestr ()
{
    pw = 0;
}


void
KDBSearchEngine::setSettings ()
{

    if (pw == 0)
      return;

    pw->dbpw->dirInput->setURL (dbname);
    pw->dbpw->caseSensitiveCB->setChecked (sens);
    pw->dbpw->normalizeCB->setChecked (norm);
    pw->dbpw->removeContextCB->setChecked (comm);

    pw->dbpw->oneWordSubCB->setChecked (defSub1);
    pw->dbpw->twoWordSubCB->setChecked (defSub2);


    if (defRule == 8)
      pw->dbpw->RegExpRB->setChecked (true);
    else
      {
        pw->dbpw->normalTextRB->setChecked (true);
        pw->dbpw->equalCB->setChecked (defRule & Equal);
        pw->dbpw->containsCB->setChecked (defRule & Contains);
        pw->dbpw->containedCB->setChecked (defRule & Contained);
      }

    pw->dbpw->oneWordSubSB->setValue (defLimit1);
    pw->dbpw->twoWordSubSB->setValue (defLimit2);

    pw->dbpw->maxSB->setValue (listmax);
    pw->dbpw->thresholdSL->setValue (thre);
    pw->dbpw->thresholdOrigSL->setValue (threorig);

    pw->dbpw->allRB->setChecked (mode == MD_ALL_DB);
    pw->dbpw->slistRB->setChecked (mode == MD_GOOD_KEYS);
    pw->dbpw->rlistRB->setChecked (mode == MD_ALL_GOOD_KEYS);

    pw->dbpw->nothingCB->setChecked (retnot);
    pw->dbpw->freqSB->setValue (commonthre);

    pw->dbpw->regExpLE->setText (regaddchar);
    pw->dbpw->ignoreLE->setText (remchar);

    pw->dbpw->authorLE->setText (autoauthor);
    pw->dbpw->autoAddCB_2->setChecked (autoup);



}


void
KDBSearchEngine::updateSettings ()
{
    if (pw == 0)
      return;

    QString newName = pw->dbpw->dirInput->url ();

    if (newName != dbname)
      {
        kdDebug (0) << "Database changed" << endl;
        dbname = newName;
        if (dbOpened)
            dbOpened = loadDatabase (dbname);
      }

    sens = pw->dbpw->caseSensitiveCB->isChecked ();
    norm = pw->dbpw->normalizeCB->isChecked ();
    comm = pw->dbpw->removeContextCB->isChecked ();

    int tmpRule = 0;
    if (pw->dbpw->RegExpRB->isChecked ())
      tmpRule = RegExp;
    else
      {
        if (pw->dbpw->equalCB->isChecked ())
            tmpRule += Equal;
        if (pw->dbpw->containsCB->isChecked ())
            tmpRule += Contains;
        if (pw->dbpw->containedCB->isChecked ())
            tmpRule += Contained;
      }

    defRule = tmpRule;

    defLimit1 = pw->dbpw->oneWordSubSB->text ().toInt ();
    defLimit2 = pw->dbpw->twoWordSubSB->text ().toInt ();
    defSub1 = pw->dbpw->oneWordSubCB->isChecked ();
    defSub2 = pw->dbpw->twoWordSubCB->isChecked ();

    listmax = pw->dbpw->maxSB->value ();
    thre = pw->dbpw->thresholdSL->value ();
    threorig = pw->dbpw->thresholdOrigSL->value ();

    if (pw->dbpw->allRB->isChecked ())
      mode = MD_ALL_DB;
    if (pw->dbpw->slistRB->isChecked ())
      mode = MD_GOOD_KEYS;
    if (pw->dbpw->rlistRB->isChecked ())
      mode = MD_ALL_GOOD_KEYS;


    regaddchar = pw->dbpw->regExpLE->text ();
    remchar = pw->dbpw->ignoreLE->text ();

    retnot = pw->dbpw->nothingCB->isChecked ();
    commonthre = pw->dbpw->freqSB->value ();

    autoauthor = pw->dbpw->authorLE->text ();
    autoup = pw->dbpw->autoAddCB_2->isChecked ();


}

void
KDBSearchEngine::setLastError (const QString & er)
{
    lasterror = er;
}

QString
KDBSearchEngine::translate (const QString & text, const uint pluralForm)
{
    if (!openDb ())
      return QString::null;
/*

if(!dbOpened)
    {
    dbOpened=loadDatabase(dbname);  //Try first to open it now
    if(!dbOpened) // Still not opened!!
        {
         //emit anerror
       hasError(i18n("Database not opened"));
         return QString::null;
       }
     }
*/

    DataBaseItem dbit = dm->getItem (text);

    if (dbit.isNull ())
      return QString::null;
    if (dbit.numTra == 1)
      return dbit.translations[0].translation;

    uint32 n = dbit.numTra;
    uint32 max = 0, nmax = 0;
    for (uint32 i = 0; i < n; i++)
      if (dbit.translations[i].numRef > max)
        {
            nmax = i;
            max = dbit.translations[i].numRef;
        }

    return dbit.translations[nmax].translation;


}

QValueList < KeyAndScore > KDBSearchEngine::searchWords (QString phrase,
                                           int threshold,
                                           int thresholdorig,
                                           uint32 max)
{
    QValueList < QString > wordlist;

    if (!openDb ())
      {
        QValueList < KeyAndScore > a;
        return a;
      }

    progressStarts (i18n ("Searching words"));

    QValueList < QString >::Iterator wlit;
    wordlist = dm->wordsIn (phrase);
    int
      nw = wordlist.count ();
//QMemArray<WordItem> wi(nw);
    QMemArray < uint32 > numofloc (nw), currentloc (nw);
    QMemArray < int >
    score (nw);
    QMemArray < uint32 * >loc (nw), locorig (nw);
    QValueList < uint32 > resloc;
    QValueList < int >
      resfound;
    QValueList < KeyAndScore > keylist;
//wi.resize(wordlist.count());
    int
      totalprogress = 0;
    int
      totrec = dm->count ();
    uint32
      cthre = totrec * commonthre / 10000;
    int
      i = 0, common = 0;
    for (wlit = wordlist.begin (); wlit != wordlist.end (); ++wlit)
      {
        WordItem
            wi = dm->getWordLocations (*wlit);
        if (!wi.notFound ())
          {
            if (wi.count < cthre)
                score[i] = 1;
            else
              {
                  score[i] = 0;
                  common++;
              }

            locorig[i] = loc[i] = wi.locations;
            totalprogress += numofloc[i] = wi.count;
            currentloc[i] = 0;
//         score[i]=wi.score;
            //wi[i]=WordItem(wi[i]);
            //wi[i].locations.detach();
            i++;
//     }
            //   else
            //  common++;



          }
      }
    bool
      cs = (common == nw);    //All words are common;
    if (totalprogress == 0)
      totalprogress = 1;
    int
      step = totalprogress / 30 + 1;
    int
      count = 0;
    int
      thrs = (wordlist.count () * threshold) / 100;
    if (thrs < 1)
      thrs = 1;         // whole database ???

    int
      tot = i;
//nt32 jmin=0;
    int
      found;
    uint32
      min;              //Big ?
    bool
      empty = false;


    while (!empty)
      {

        empty = true;
        found = retnot ? common : 0;
        if (thrs <= found)
            thrs = found + 1; // whole database ???

        min = BIGNUMBER;
        for (int j = 0; j < tot; j++)
            if (cs || score[j])
            {
                if (numofloc[j] > currentloc[j])      // Check if there's still something to do.
                  empty = false;
                if (loc[j][0] < min)      //Found the minimum head
                  min = loc[j][0];


            }
        if (min != BIGNUMBER)
          {
            for (int j = 0; j < tot; j++)
                if (cs || score[j])
                  {
                    if (loc[j][0] == min) //Count the heads, move forward
                      {
                        found++;
                        count++;
                        //check stopnow  here
                        if (count % step == 0)
                          {
                              emit
                              progress (100 * count / totalprogress);
                              kapp->processEvents (100);
                          }

                        currentloc[j]++;
                        if (numofloc[j] == currentloc[j])   //End reached
                            loc[j][0] = BIGNUMBER;    //so set head to a big number
                        else  //Go on..
                          {
                              loc[j]++;
                          }
                      }
                  }           //end of for
            bool
                inserted = false;



            if (found >= thrs)
              {
                  //Words count in key.
                  int
                    nword = 0;

                  int
                    in = 0, len = 0;
                  QString
                    keyst = dm->getKey (min);
                  QRegExp
                  reg ("[a-zA-Z0-9_%" /*+remchar */  + regaddchar + "]+");
                  while ((in = reg.search (keyst, in + len)) != -1)
                  {
                      nword++;
                      len = reg.matchedLength ();
                  }

                  if (found >= nword * thresholdorig / 100) //
                  {

                      if (resfound.count () <= max
                        || (*resfound.end () < found))
                        if ((*resfound.end ()) >= found)
                          {
                              inserted = true;
                              resloc.append (min);
                              resfound.append (found);

                          }
                        else
                            for (uint32 j = 0; j < resloc.count ();
                               j++)
                              {
                                if (resfound[j] < found || (resfound[j] == found && 0))   //Orig word
                                  {
                                    resloc.insert (resloc.at (j),
                                                 min);
                                    resfound.insert (resfound.
                                                 at (j),
                                                 found);
                                    inserted = true;
                                    break;
                                  }
                              }
                      if (!inserted)
                        {
                          resloc.append (min);
                          resfound.append (found);
                        }

                  }
              }

          }

      }
    int
      nres = (resloc.count () < max) ? resloc.count () : max;

    for (int j = 0; j < nres; j++)
      {
        QString
            strkey = dm->getKey (resloc[j]);
        int
            stdscore = KDBSearchEngine::score (phrase, strkey);
        int
            sc = 0;

        if (stdscore < 99)
          {
            int
                in = 0, len = 0, nword = 0;
            int
                remove = retnot ? common : 0;
            QRegExp
            reg ("[a-zA-Z0-9_%" /*+remchar */  + regaddchar + "]+");
            while ((in = reg.search (strkey, in + len)) != -1)
              {
                  nword++;
                  len = reg.matchedLength ();
              }

//    kdDebug(0) << nword << "NWORD  " << resfound[j] << "FOUND  "
//    << resfound[j]-remove << "REAL  " << remove << "to be remove   " << endl;
            if (nword < 1)
                nword = 1;
            sc = 70 - resfound[j] * 70 / nw + abs (nword -
                                           (resfound[j] -
                                          remove)) * 30 /
                nword + 2;
            sc = 100 - sc;
//    kdDebug(0) <<" Score : " << sc << endl;

          }
        else
            sc = stdscore;

        KeyAndScore
        key (strkey, sc);

//  kdDebug(0) << (QString) key << " [" << key.score << "]" << endl;
        keylist.append (key);
      }

//kdDebug(0) << "Here!" << endl;

    for (int j = 0; j < tot; j++)
      {
        free (locorig[j]);
      }
    progressStarts (i18n ("Process output"));
    return keylist;
}

void
KDBSearchEngine::stringChanged (const QStringList & o,
                        const QString & translated, const uint,
                        const QString &)
{

    QString orig = o.first ();      // FIXME: plural forms

    // skip empty originals or translated texts
    if (orig.isEmpty () || translated.isEmpty ())
      return;
    
    if (autoup)
      {
        if (openDb (true))    //true= no ask
          {

            dm->putNewTranslation (orig, translated,
                  dm->catalogRef (directory (edited, 0),
                  autoauthor, edited));
            //kdDebug(0) << "Changed " << orig << " " << translated << endl;
            dm->sync ();
          }
      }

}

void
KDBSearchEngine::setEditedFile (const QString & file)
{

    edited = file;            //kdDebug(0) << edited << endl;
}

KeyAndScore::KeyAndScore (const QString & a, int sc):
QString (a)
{
    score = sc;
}

KeyAndScore::KeyAndScore ():QString ()
{
    score = 0;
}

#include "KDBSearchEngine.moc"

Generated by  Doxygen 1.6.0   Back to index