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

  Copyright (C) 1999-2000 by Matthias Kiefer
                            <matthias.kiefer@gmx.de>

  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 "kbabel.h"

#include "kbabelpref.h"
#include "kbabelsplash.h"
#include "tagextractor.h"
#include "argextractor.h"

#include <qdragobject.h>
#include <qlineedit.h>
#include <qpopupmenu.h>
#include <qhbox.h>
#include <qwhatsthis.h>
#include <qsize.h>
#include <qtextcodec.h>
#include <qtooltip.h>
#include <qtimer.h>

#include <dcopclient.h>
#include <kaccel.h>
#include <kpopupmenu.h>
#include <kstatusbar.h>
#include <kedittoolbar.h>
#include <kglobal.h>
#include <kled.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kkeydialog.h>
#include <ktoolbar.h>
#include <kfiledialog.h>
#include <kconfig.h>
#include <kurl.h>
#include <kdialogbase.h>
#include <kprogress.h>
#include <kmessagebox.h>
#include <kwin.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kspelldlg.h>

#include "resources.h"
#include "kbcatalog.h"
#include "dictionarymenu.h"
#include "kbabeldictbox.h"
#include "kbmailer.h"

#include "version.h"

#define ID_STATUS_TOTAL 1
#define ID_STATUS_CURRENT 2
#define ID_STATUS_FUZZY 3
#define ID_STATUS_UNTRANS 4
#define ID_STATUS_EDITMODE 5
#define ID_STATUS_READONLY 6
#define ID_STATUS_CURSOR 7

#define NAVIGATIONBAR toolBar("navigationbar")

// maximum number of recent files
#define MAX_RECENT 10


QStringList KBabel::_recentFiles;
QPtrList<KBabelPreferences> KBabel::prefDialogs;

CatManSettings KBabel::_catManSettings;

class MyKProgress: public KProgress 
{
public:
    MyKProgress( QWidget *parent, const char *name ) : KProgress( parent, name ) {}
    QSize sizeHint() const { return QSize( 0, KProgress::sizeHint().height());}
};

KBabel::KBabel(QString projectFile)
	: KMainWindow(0,0)
{
   if( projectFile.isEmpty() ) _projectFile = QString::null;
   else _projectFile = projectFile;
   
   if( !projectFile.isEmpty() ) kdDebug() << "KBabel has project file " << _projectFile << endl;
   
   KBCatalog* catalog=new KBCatalog(_projectFile);
   init(catalog);
}

KBabel::KBabel(KBCatalog* catalog, QString projectFile)
	:KMainWindow(0,0)
{
   if( projectFile.isEmpty() ) _projectFile = QString::null;
   else _projectFile = projectFile;
   
    init(catalog);
}

void KBabel::init(KBCatalog* catalog)
{
    _fuzzyLed=0;
    _untransLed=0;
	_errorLed=0;

    _prefDialog=0;
    prefDialogs.setAutoDelete(true);

	_statusbarTimer = new QTimer(this, "statusbartimer");
	connect(_statusbarTimer,SIGNAL(timeout()),this
					,SLOT(clearStatusbarMsg()));
	
    m_view=new KBabelView(catalog,this, _projectFile);
    // tell the KMainWindow that this is indeed the main widget
    setCentralWidget(m_view);


    m_accel=new KAccel(this);

    m_accel->insertItem(i18n("Toggle Edit Mode"),"Toggle Editmode","Insert");
    m_accel->connectItem("Toggle Editmode",this,SLOT(toggleEditMode()));



    // accept dnd
    setAcceptDrops(true);


    // setup our menubars and toolbars
    setupStatusBar();
    setupActions();

    m_accel->setEnabled(false);

	QPopupMenu* popup;
	popup = (QPopupMenu*)(factory()->container("rmb_edit", this));
	if(popup)
	{
		m_view->setRMBEditMenu(popup);
	}	
	popup = (QPopupMenu*)(factory()->container("rmb_search", this));
	if(popup)
	{
		m_view->setRMBSearchMenu(popup);
	}	
	

    connect(catalog,SIGNAL(signalUndoAvailable(bool)),this
            ,SLOT(enableUndo(bool)));
    connect(catalog,SIGNAL(signalRedoAvailable(bool)),this
            ,SLOT(enableRedo(bool)));
    connect(catalog,SIGNAL(signalNumberOfFuzziesChanged(uint)),this
            ,SLOT(setNumberOfFuzzies(uint)));
    connect(catalog,SIGNAL(signalNumberOfUntranslatedChanged(uint)),this
            ,SLOT(setNumberOfUntranslated(uint)));
    connect(catalog,SIGNAL(signalTotalNumberChanged(uint)),this
            ,SLOT(setNumberOfTotal(uint)));
    connect(catalog,SIGNAL(signalProgress(int)),_progressBar,SLOT(setProgress(int)));
    connect(catalog,SIGNAL(signalClearProgressBar()),this,SLOT(clearProgressBar()));
    connect(catalog,SIGNAL(signalResetProgressBar(QString,int))
           ,this,SLOT(prepareProgressBar(QString,int)));
    connect(catalog,SIGNAL(signalFileOpened(bool)),this,SLOT(enableDefaults(bool)));
    connect(catalog,SIGNAL(signalFileOpened(bool)),m_view,SLOT(newFileOpened(bool)));
    connect(catalog,SIGNAL(signalModified(bool)),this,SLOT(showModified(bool)));


    // allow the view to change the statusbar and caption
    connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
            this,   SLOT(changeStatusbar(const QString&)));
    connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
            this,   SLOT(changeCaption(const QString&)));
//    connect(m_view,SIGNAL(signalNewFileOpened(KURL)),this
//           ,SLOT(addToRecentFiles(KURL)));
    connect(m_view,SIGNAL(signalFirstDisplayed(bool)),this
           ,SLOT(firstEntryDisplayed(bool)));
    connect(m_view,SIGNAL(signalLastDisplayed(bool)),this
           ,SLOT(lastEntryDisplayed(bool)));
    connect(m_view,SIGNAL(signalFuzzyDisplayed(bool)),this
           ,SLOT(fuzzyDisplayed(bool)));
    connect(m_view,SIGNAL(signalUntranslatedDisplayed(bool)),this
           ,SLOT(untranslatedDisplayed(bool)));
    connect(m_view,SIGNAL(signalFaultyDisplayed(bool)),this
           ,SLOT(faultyDisplayed(bool)));
    connect(m_view,SIGNAL(signalDisplayed(uint)),this
           ,SLOT(displayedEntryChanged(uint)));
    connect(m_view,SIGNAL(signalFuzzyAfterwards(bool)),this
            ,SLOT(hasFuzzyAfterwards(bool)));
    connect(m_view,SIGNAL(signalFuzzyInFront(bool)),this
            ,SLOT(hasFuzzyInFront(bool)));
    connect(m_view,SIGNAL(signalUntranslatedAfterwards(bool)),this
            ,SLOT(hasUntranslatedAfterwards(bool)));
    connect(m_view,SIGNAL(signalUntranslatedInFront(bool)),this
            ,SLOT(hasUntranslatedInFront(bool)));
    connect(m_view,SIGNAL(signalErrorAfterwards(bool)),this
            ,SLOT(hasErrorAfterwards(bool)));
    connect(m_view,SIGNAL(signalErrorInFront(bool)),this
            ,SLOT(hasErrorInFront(bool)));
    connect(m_view,SIGNAL(signalBackHistory(bool)),this
            ,SLOT(enableBackHistory(bool)));
    connect(m_view,SIGNAL(signalForwardHistory(bool)),this
            ,SLOT(enableForwardHistory(bool)));


    connect(m_view,SIGNAL(ledColorChanged(const QColor&)),this
                  ,SLOT(setLedColor(const QColor&)));


    connect(m_view,SIGNAL(signalSearchActive(bool)),this,SLOT(enableStop(bool)));
    
    connect(m_view,SIGNAL(signalToolsShown()),this,SLOT(checkMenuItemTools()));
    connect(m_view,SIGNAL(signalCommentsShown()),this,SLOT(checkMenuItemComments()));
    connect(m_view,SIGNAL(signalProgress(int)),_progressBar,SLOT(setProgress(int)));
    connect(m_view,SIGNAL(signalClearProgressBar()),this,SLOT(clearProgressBar()));
    connect(m_view,SIGNAL(signalResetProgressBar(QString,int))
           ,this,SLOT(prepareProgressBar(QString,int)));

    connect(m_view,SIGNAL(signalDictionariesChanged())
           , this, SLOT(buildDictMenus()));

    connect(m_view,SIGNAL(signalCursorPosChanged(int,int)), this
            , SLOT(updateCursorPosition(int,int)));

    if(!catalog->currentURL().isEmpty())
    {
       enableDefaults(catalog->isReadOnly());
       setNumberOfFuzzies(catalog->numberOfFuzzies());
       setNumberOfUntranslated(catalog->numberOfUntranslated());
       setNumberOfTotal(catalog->numberOfEntries());

       enableUndo(catalog->isUndoAvailable());
       enableUndo(catalog->isRedoAvailable());

       m_view->emitEntryState();

       changeCaption(catalog->currentURL().url());
    }

    mailer = new KBabelMailer();

    KConfig* config;
    
    if( !_projectFile.isEmpty() ) config=new KConfig(_projectFile);
    else config=KGlobal::config();

    restoreSettings(config);

    KConfigGroupSaver saver(config,"KBabel");
    if(!config->hasKey("Version"))
    {
      QString encodingStr;
      switch(catalog->saveSettings().encoding)
      {
         case UTF8:
            encodingStr=QTextCodec::codecForName("UTF-8")->name();
            break;
         case UTF16:
            encodingStr=QTextCodec::codecForName("UTF-16")->name();
            break;
         default:
            encodingStr=QTextCodec::codecForLocale()->name();
      }
      
      if( KBabelSplash::_splashWidget ) KBabelSplash::_splashWidget->close(); //close splash screen window, if there is one

      KMessageBox::information(0,i18n("You have not run KBabel before. "
		   "To allow KBabel to work correctly you must enter some "
		   "information in the preferences dialog first.\n"
		   "The minimum requirement is to fill out the Identity page.\n"
		   "Also check the encoding on the Save page, which is currently "
		   "set to %1. You may want to change this setting "
		   "according to the settings of your language team.").arg(encodingStr));

      QTimer::singleShot(1,this,SLOT(optionsPreferences()));
    }

    config->writeEntry("Version",VERSION);
    config->sync();
}

KBabel::~KBabel()
{
   if(_prefDialog)
   {
      prefDialogs.remove(_prefDialog);
   }
   delete mailer;
}


void KBabel::setSettings(SearchSettings searchOpts, EditorSettings editOpts
                       , SaveSettings saveOpts,IdentitySettings idOpts)
{
   m_view->setSettings(searchOpts);
   m_view->setSettings(editOpts);
   m_view->catalog()->setSettings(saveOpts);
   m_view->catalog()->setSettings(idOpts);

   if(_fuzzyLed)
   {
      _fuzzyLed->setColor(editOpts.ledColor);
   }
   if(_untransLed)
   {
      _untransLed->setColor(editOpts.ledColor);
   }
   if(_errorLed)
   {
      _errorLed->setColor(editOpts.ledColor);
   }

}

void KBabel::setSettings(SearchSettings searchOpts, EditorSettings editOpts)
{
   m_view->setSettings(searchOpts);
   m_view->setSettings(editOpts);

   if(_fuzzyLed)
   {
      _fuzzyLed->setColor(editOpts.ledColor);
   }
   if(_untransLed)
   {
      _untransLed->setColor(editOpts.ledColor);
   }
   if(_errorLed)
   {
      _errorLed->setColor(editOpts.ledColor);
   }

}


void KBabel::setupActions()
{
   KAction* action;

   // the file menu
   action = KStdAction::open(this, SLOT(fileOpen()), actionCollection());
   KStdAction::openRecent(this, SLOT(openRecent(const KURL&)), actionCollection());
   action = KStdAction::revert(m_view,SLOT(revertToSaved()),actionCollection());
   action->setEnabled(false);
   action=KStdAction::save(this, SLOT(fileSave()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
   action->setEnabled(false);
   action = new KAction(i18n("Save Sp&ecial..."), 0, this, SLOT(fileSaveSpecial()), 
	 actionCollection(), "save_special" );
   action->setEnabled(false);
   action = new KAction(i18n("Set &Package..."), 0, m_view, SLOT(setFilePackage()), 
	 actionCollection(), "set_package" );
   action->setEnabled(false);

   action = KStdAction::mail(this, SLOT(fileMail()), actionCollection());
   action->setEnabled(false);

   action = new KAction(i18n("&New View"), 0, this, SLOT(fileNewView()),
         actionCollection(), "file_new_view");

   action = new KAction(i18n("New &Window"), 0, this, SLOT(fileNewWindow()),
         actionCollection(), "file_new_window");
   action->setAccel( KStdAccel::openNew() );

   action = KStdAction::quit(this, SLOT(quit()), actionCollection());



   // the edit menu
   action = KStdAction::undo(m_view, SLOT(undo()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::redo(m_view, SLOT(redo()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::cut(m_view, SLOT(textCut()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::copy(m_view, SLOT(textCopy()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::paste(m_view, SLOT(textPaste()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::selectAll(m_view, SLOT(selectAll()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::find(m_view, SLOT(find()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::findNext(m_view, SLOT(findNext()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::findPrev(m_view, SLOT(findPrev()), actionCollection());
   action->setEnabled(false);
   action = KStdAction::replace(m_view, SLOT(replace()), actionCollection());
   action->setEnabled(false);
   
   action = new KAction(i18n("C&lear"), "editclear", CTRL+SHIFT+Key_Delete, m_view, SLOT(clear()), actionCollection(), "clear" );
   action->setEnabled(false);

   action = new KAction(i18n("Cop&y Msgid to Msgstr"), "msgid2msgstr", CTRL+Key_Space, m_view
                 ,SLOT(msgid2msgstr()), actionCollection(), "msgid2msgstr");
   action->setEnabled(false);
   action = new KAction(i18n("Copy Searc&h Result to Msgstr"), "search2msgstr",
			CTRL+ALT+Key_Space, m_view, SLOT(search2msgstr()),
			actionCollection(), "search2msgstr");
   action->setEnabled(false);
   a_unsetFuzzy = new KAction(i18n("To&ggle Fuzzy Status"), "togglefuzzy", CTRL+Key_U, m_view
                 , SLOT(removeFuzzyStatus()), actionCollection(), "edit_toggle_fuzzy");
   a_unsetFuzzy->setEnabled(false);
   action = new KAction(i18n("&Edit Header..."), 0, m_view, SLOT(editHeader()),
         actionCollection(), "edit_edit_header");
   action->setEnabled(false);

   action = new KAction(i18n("&Insert Next Tag"), "insert_tag", CTRL+ALT+Key_N
           , m_view, SLOT(insertNextTag())
           , actionCollection(),"insert_next_tag");
   action->setEnabled(false);
   connect(m_view,SIGNAL(signalNextTagAvailable(bool)),action
           ,SLOT(setEnabled(bool)));
   KActionMenu *actionMenu= new KActionMenu(i18n("Inser&t Tag"), "insert_tag"
         , actionCollection(),"insert_tag");
   m_view->setTagsMenu(actionMenu->popupMenu());
   actionMenu->setEnabled(false);
   connect(m_view,SIGNAL(signalTagsAvailable(bool)),actionMenu
           ,SLOT(setEnabled(bool)));
   connect(actionMenu,SIGNAL(activated()),m_view,SLOT(insertNextTag()));

   action = new KAction(i18n("Show Tags Menu"),CTRL+Key_Less
           , m_view, SLOT(showTagsMenu()), actionCollection(),"show_tags_menu");
   action->setEnabled(false);
   action->plugAccel(m_accel);
   connect(m_view,SIGNAL(signalTagsAvailable(bool)),action
           ,SLOT(setEnabled(bool)));

   action = new KAction(i18n("Insert Next Argument"), "insert_arg", CTRL+ALT+Key_A
           , m_view, SLOT(insertNextArg())
           , actionCollection(),"insert_next_arg");
   action->setEnabled(false);
   connect(m_view,SIGNAL(signalNextArgAvailable(bool)),action
           ,SLOT(setEnabled(bool)));
   actionMenu= new KActionMenu(i18n("Inser&t Argument"), "insert_arg"
         , actionCollection(),"insert_arg");
   m_view->setArgsMenu(actionMenu->popupMenu());
   actionMenu->setEnabled(false);
   connect(m_view,SIGNAL(signalArgsAvailable(bool)),actionMenu
           ,SLOT(setEnabled(bool)));
   connect(actionMenu,SIGNAL(activated()),m_view,SLOT(insertNextArg()));

   action = new KAction(i18n("Show Arguments Menu"),CTRL+Key_Percent
           , m_view, SLOT(showArgsMenu()), actionCollection(),"show_args_menu");
   action->setEnabled(false);
   action->plugAccel(m_accel);
   connect(m_view,SIGNAL(signalArgsAvailable(bool)),action
           ,SLOT(setEnabled(bool)));

    // next, the go-menu
    action = new KAction(i18n("&Previous"), "previous",
                 KStdAccel::key(KStdAccel::Prior), m_view , SLOT(gotoPrev()),
                 actionCollection(),"go_prev_entry");
   action->setEnabled(false);
   action = new KAction(i18n("&Next"), "next",
                 KStdAccel::key(KStdAccel::Next), m_view , SLOT(gotoNext()),
                 actionCollection(),"go_next_entry");
   action->setEnabled(false);
   action = KStdAction::goTo(m_view, SLOT(gotoEntry()), actionCollection());
   action->setAccel( KStdAccel::gotoLine());
   action->setEnabled(false);
   action = KStdAction::firstPage(m_view, SLOT(gotoFirst()),actionCollection());
   action->setText(i18n("&First Entry"));
   action->setAccel(CTRL+ALT+Key_Home);
   action->setEnabled(false);
   action = KStdAction::lastPage(m_view, SLOT(gotoLast()),actionCollection());
   action->setText(i18n("&Last Entry"));
   action->setAccel(CTRL+ALT+Key_End);
   action->setEnabled(false);
   a_prevFoU = new KAction(i18n("P&revious Fuzzy or Untranslated"),"prevfuzzyuntrans",
         CTRL+SHIFT+Key_Prior, m_view,
         SLOT(gotoPrevFuzzyOrUntrans()),actionCollection(), "go_prev_fuzzyUntr");
   a_prevFoU->setEnabled(false);
   a_nextFoU = new KAction(i18n("N&ext Fuzzy or Untranslated"),"nextfuzzyuntrans",
         CTRL+SHIFT+Key_Next, m_view,
         SLOT(gotoNextFuzzyOrUntrans()),actionCollection(), "go_next_fuzzyUntr");
   a_nextFoU->setEnabled(false);
   a_prevFuzzy = new KAction(i18n("Pre&vious Fuzzy"),"prevfuzzy",
         CTRL+Key_Prior, m_view,
         SLOT(gotoPrevFuzzy()),actionCollection(), "go_prev_fuzzy");
   a_prevFuzzy->setEnabled(false);
   a_nextFuzzy = new KAction(i18n("Ne&xt Fuzzy"), "nextfuzzy",
         CTRL+Key_Next, m_view,
         SLOT(gotoNextFuzzy()),actionCollection(), "go_next_fuzzy");
   a_nextFuzzy->setEnabled(false);
   a_prevUntrans = new KAction(i18n("Prev&ious Untranslated"), "prevuntranslated",
         ALT+Key_Prior, m_view,
         SLOT(gotoPrevUntranslated()),actionCollection(), "go_prev_untrans");
   a_prevUntrans->setEnabled(false);
   a_nextUntrans = new KAction(i18n("Nex&t Untranslated"), "nextuntranslated",
         ALT+Key_Next, m_view,
         SLOT(gotoNextUntranslated()),actionCollection(), "go_next_untrans");
   a_nextUntrans->setEnabled(false);
   action = new KAction(i18n("Previo&us Error"), "preverror",
          SHIFT+Key_Prior, m_view,
         SLOT(gotoPrevError()),actionCollection(), "go_prev_error");
   action->setEnabled(false);;
   action = new KAction(i18n("Next Err&or"), "nexterror",
         SHIFT+Key_Next, m_view,
         SLOT(gotoNextError()),actionCollection(), "go_next_error");
   action->setEnabled(false);
   action = new KAction(i18n("&Back"), "back", ALT+Key_Left, m_view,
         SLOT(backHistory()),actionCollection(), "go_back_history");
   action->setEnabled(false);
   action = new KAction(i18n("For&ward"), "forward", ALT+Key_Right, m_view,
         SLOT(forwardHistory()),actionCollection(), "go_forward_history");
   action->setEnabled(false);

    // the search menu
   actionMenu=new KActionMenu(i18n("&Find Text"),
         "transsearch",actionCollection(),"dict_search_all");
   connect(actionMenu,SIGNAL(activated()),m_view,SLOT(startSearch()));
   ((KAction*)actionMenu)->setEnabled(false);
   dictMenu = new DictionaryMenu(actionMenu->popupMenu(),m_accel,this);
   connect(dictMenu,SIGNAL(activated(const QString)), m_view
           , SLOT(startSearch(const QString)));
   
   actionMenu=new KActionMenu(i18n("F&ind Selected Text"),
         "transsearch",actionCollection(),"dict_search_selected");
   connect(actionMenu,SIGNAL(activated()),m_view,SLOT(startSelectionSearch()));
   ((KAction*)actionMenu)->setEnabled(false);
   selectionDictMenu = new DictionaryMenu(actionMenu->popupMenu(),m_accel,this);
   connect(selectionDictMenu,SIGNAL(activated(const QString)), m_view
           , SLOT(startSelectionSearch(const QString)));

   actionMenu=new KActionMenu(i18n("&Edit Dictionary"),
         "transsearch",actionCollection(),"dict_edit");
   editDictMenu = new DictionaryMenu(actionMenu->popupMenu(),m_accel,this);
   connect(editDictMenu,SIGNAL(activated(const QString)), m_view
           , SLOT(editDictionary(const QString)));


   actionMenu=new KActionMenu(i18n("Con&figure Dictionary"),
         "transsearch",actionCollection(),"dict_configure");
   configDictMenu = new DictionaryMenu(actionMenu->popupMenu(),m_accel,this);
   connect(configDictMenu,SIGNAL(activated(const QString)), m_view
           , SLOT(configureDictionary(const QString)));

   actionMenu=new KActionMenu(i18n("About Dictionary"), "transsearch",
         actionCollection(), "dict_about");
   aboutDictMenu = new DictionaryMenu(actionMenu->popupMenu(),m_accel,this);
   connect(aboutDictMenu,SIGNAL(activated(const QString)), m_view
           , SLOT(aboutDictionary(const QString)));
   
   buildDictMenus();

    // the tools menu
   action = new KAction(i18n("&Spell Check..."), "spellcheck", CTRL+Key_I 
           , m_view, SLOT(spellcheckCommon()),actionCollection()
           ,"spellcheck_common");
   action->setEnabled(false);
   action = new KAction(i18n("&Check All..."), "spellcheck_all", 0
           , m_view, SLOT(spellcheckAll()),actionCollection()
           ,"spellcheck_all");
   action->setEnabled(false);
   action = new KAction(i18n("C&heck From Cursor Position..."), "spellcheck_from_cursor", 0
           , m_view, SLOT(spellcheckFromCursor()),actionCollection()
           ,"spellcheck_from_cursor");
   action->setEnabled(false);
   action = new KAction(i18n("Ch&eck Current..."), "spellcheck_actual", 0 
           , m_view, SLOT(spellcheckCurrent()),actionCollection()
           ,"spellcheck_current");
   action->setEnabled(false);
   action = new KAction(i18n("Chec&k Selected Text..."), "spellcheck_selected", 0
           , m_view, SLOT(spellcheckMarked()),actionCollection()
           ,"spellcheck_marked");
   action->setEnabled(false);


   KToggleAction *toggleAction;
   
   toggleAction = new KToggleAction(i18n("&Diffmode"), "autodiff", 0
           ,actionCollection(), "diff_toggleDiff");
   connect(toggleAction,SIGNAL(toggled(bool)), m_view, SLOT(toggleAutoDiff(bool)));
   toggleAction->setEnabled(false);
   connect(m_view,SIGNAL(signalDiffEnabled(bool)), toggleAction
               , SLOT(setChecked(bool)));
   toggleAction->setChecked(m_view->autoDiffEnabled());
   
   action = new KAction(i18n("&Show Diff"), "diff", Key_F5
           , m_view, SLOT(diff()),actionCollection()
           ,"diff_diff");
   action->setEnabled(false);
   action = new KAction(i18n("S&how Original Text"), "contents", Key_F6
           , m_view, SLOT(diffShowOrig()),actionCollection()
           ,"diff_showOrig");
   action->setEnabled(false);

   action = new KAction(i18n("&Open File for Diff"), "fileopen" ,0
           , m_view, SLOT(openDiffFile()),actionCollection()
           ,"diff_openFile");
   action->setEnabled(false);

   
   action = new KAction(i18n("&Rough Translation..."), 0
           , m_view, SLOT(roughTranslation()),actionCollection()
           ,"rough_translation");
   action->setEnabled(false);

   action = new KAction(i18n("&Catalog Manager..."),"catalogmanager", 0 , this,
         SLOT(openCatalogManager()),actionCollection(), "open_catalog_manager");
   action = new KAction(i18n("C&heck Syntax"), CTRL+Key_T , m_view,
         SLOT(checkSyntax()),actionCollection(), "check_syntax");
   action->setEnabled(false);
     
   action = new KAction(i18n("Ch&eck Arguments"), CTRL+Key_D , m_view,
         SLOT(checkArgs()),actionCollection(), "check_arguments");
   action->setEnabled(false);

   action = new KAction(i18n("Chec&k Accelerators"), CTRL+Key_H , m_view,
         SLOT(checkAccels()),actionCollection(), "check_accels");
   action->setEnabled(false);

   action = new KAction(i18n("Check E&quations"), CTRL+Key_J , m_view,
         SLOT(checkEquations()),actionCollection(), "check_equations");
   action->setEnabled(false);

   action = new KAction(i18n("Look &for Translated Context Info"), CTRL+Key_L , m_view,
         SLOT(checkForContext()),actionCollection(), "check_context");
   action->setEnabled(false);
   action = new KAction(i18n("Check &Plural Forms (KDE only)"), 0 , m_view,
         SLOT(checkSingularPlural()),actionCollection(), "check_pluralforms");
   action->setEnabled(false);
   action = new KAction(i18n("Check &Tags"), 0 , m_view,
         SLOT(checkXmlTags()),actionCollection(), "check_xmltags");
   action->setEnabled(false);
   action = new KAction(i18n("Perform &All Checks"), CTRL+Key_E , m_view,
         SLOT(checkAll()),actionCollection(), "check_all");
   action->setEnabled(false);




    // next, the settings menu

    toggleAction = KStdAction::showToolbar(this,SLOT(dummySlot()), actionCollection());
    connect(toggleAction,SIGNAL(toggled(bool)), this, SLOT(optionsShowToolbar(bool)));
    toggleAction=KStdAction::showStatusbar(this,SLOT(dummySlot()), actionCollection());
    connect(toggleAction,SIGNAL(toggled(bool)), this, SLOT(optionsShowStatusbar(bool)));

    KStdAction::configureToolbars(this,SLOT(optionsEditToolbars()),actionCollection());

    toggleAction = new KToggleAction(i18n("Show &Navigation Bar"), 0,
                  actionCollection(),"settings_show_navbar");
    connect(toggleAction,SIGNAL(toggled(bool)), this, SLOT(optionsShowNavBar(bool)));
    toggleAction = new KToggleAction(i18n("Show Co&mments"), 0,
                  actionCollection(),"settings_show_comments");
    connect(toggleAction,SIGNAL(toggled(bool)), m_view, SLOT(showComments(bool)));
    toggleAction = new KToggleAction(i18n("Show T&ools"), 0,
                  actionCollection(),"settings_show_tools");
    connect(toggleAction,SIGNAL(toggled(bool)), m_view, SLOT(showTools(bool)));

    KStdAction::keyBindings(this,SLOT(optionsConfigure()),actionCollection());
    KStdAction::preferences(this,SLOT(optionsPreferences()),actionCollection());



   action = new KAction(i18n("&Stop Searching"), "stop",Key_Escape, m_view,
         SLOT(stopSearch()),actionCollection(), "stop_search");
   action->setEnabled(false);

   new KAction(i18n("&Gettext Info"), 0, this,
           SLOT(gettextHelp()), actionCollection(), "help_gettext");
   
   
   createGUI();
}


void KBabel::setupStatusBar()
{
    statusBar()->insertItem(i18n("Current: 0"),ID_STATUS_CURRENT);
    statusBar()->insertItem(i18n("Total: 0"),ID_STATUS_TOTAL);
    statusBar()->insertItem(i18n("Fuzzy: 0"),ID_STATUS_FUZZY);
    statusBar()->insertItem(i18n("Untranslated: 0"),ID_STATUS_UNTRANS);

    if(m_view->editorSettings().ledInStatusbar)
    {
       QColor ledColor=m_view->editorSettings().ledColor;
       QHBox* statusBox = new QHBox(statusBar(),"statusBox");
       statusBox->setSpacing(2);
       new QLabel(" "+i18n("Status: "),statusBox);
       _fuzzyLed = new KLed(ledColor,KLed::Off,KLed::Sunken,KLed::Rectangular
                   ,statusBox);
       _fuzzyLed->setFixedSize(15,12);
       new QLabel(i18n("fuzzy")+" ",statusBox);
       _untransLed = new KLed(ledColor,KLed::Off,KLed::Sunken,KLed::Rectangular
                   ,statusBox);
       _untransLed->setFixedSize(15,12);
       new QLabel(i18n("untranslated")+" ",statusBox);
       _errorLed = new KLed(ledColor,KLed::Off,KLed::Sunken,KLed::Rectangular
                   ,statusBox);
       _errorLed->setFixedSize(15,12);
       new QLabel(i18n("faulty")+" ",statusBox);

       statusBox->setFixedWidth(statusBox->sizeHint().width());
       statusBar()->addWidget(statusBox);
    }

    statusBar()->insertItem(i18n("INS"),ID_STATUS_EDITMODE);

    statusBar()->insertItem(i18n("RW"),ID_STATUS_READONLY);

    statusBar()->insertItem(i18n("Line: %1 Col: %2").arg(1).arg(1)
            ,ID_STATUS_CURSOR);

    QHBox* progressBox = new QHBox(statusBar(),"progressBox");
    progressBox->setSpacing(2);
    _progressLabel = new QLabel( "", progressBox );
    _progressBar=new MyKProgress(progressBox,"progressbar");
    _progressBar->hide();

    statusBar()->addWidget(progressBox,1);
    statusBar()->setMinimumHeight(_progressBar->sizeHint().height());

    QWhatsThis::add(statusBar(),
       i18n("<qt><p><b>Statusbar</b></p>\n\
<p>The statusbar displays some information about the opened file,\n\
like the total number of entries and the number of fuzzy and untranslated\n\
messages. Also the index and the status of the currently displayed entry is shown.</p></qt>"));

}


void KBabel::saveSettings( KConfig *config )
{
    {
        KConfigGroupSaver saver(config,"View");

        KToggleAction* toggleAction;

        toggleAction=(KToggleAction*)actionCollection()->action("settings_show_tools");
        config->writeEntry("Tools",toggleAction->isChecked());
        toggleAction=(KToggleAction*)actionCollection()->action("settings_show_comments");
        config->writeEntry("Comments",toggleAction->isChecked());
	
	saveMainWindowSettings(config, "View");
    }

    {
        KConfigGroupSaver saver(config,"KBabel");

        config->writeEntry("RecentFiles",_recentFiles);
    }
    {
#if 0
       KConfigGroupSaver cs(config,"CatalogManager");

       config->writeEntry("PoBaseDir",_catManSettings.poBaseDir);
       config->writeEntry("PotBaseDir",_catManSettings.potBaseDir);
       config->writeEntry("OpenWindow",_catManSettings.openWindow);

       config->writeEntry("KillCmdOnExit",_catManSettings.killCmdOnExit);

       config->writeEntry("DirCommands",_catManSettings.dirCommands);
       config->writeEntry("DirCommandNames",_catManSettings.dirCommandNames);
       config->writeEntry("FileCommands",_catManSettings.fileCommands);
       config->writeEntry("FileCommandNames",_catManSettings.fileCommandNames);
#endif
    }
    
    {
	KConfigGroupSaver tags(config, "Tags");
	
	config->writeEntry("Expressions", *TagExtractor::tagExpressions() );
    }

    config->sync();
}

void KBabel::restoreSettings( KConfig* config )
{
    {
       applyMainWindowSettings(config, "View");

       KToggleAction* toggleAction=(KToggleAction*)actionCollection()->action(KStdAction::stdName(KStdAction::ShowToolbar));
       toggleAction->setChecked(!toolBar()->isHidden());

       toggleAction=(KToggleAction*)actionCollection()->action("settings_show_navbar");
       toggleAction->setChecked(!NAVIGATIONBAR->isHidden());

       toggleAction=(KToggleAction*)actionCollection()->action(KStdAction::stdName(KStdAction::ShowStatusbar));
       toggleAction->setChecked(!statusBar()->isHidden());

       KConfigGroupSaver saver(config,"View");
       
       toggleAction=(KToggleAction*)actionCollection()->action("settings_show_comments");
       bool show=config->readBoolEntry("Comments",true);
       toggleAction->setChecked(show);
       m_view->showComments(show); // hmm, this should be called by the action, but it doesn't

       toggleAction=(KToggleAction*)actionCollection()->action(
                   "settings_show_tools");
       show=config->readBoolEntry("Tools",true);
       toggleAction->setChecked(show);
       m_view->showTools(show); // hmm, this should be called by the action, but it doesn't

       m_view->restoreView(config);
    }

    {
       KConfigGroupSaver saver(config,"KBabel");

       _recentFiles=config->readListEntry("RecentFiles");
       KRecentFilesAction *recent;
       recent = (KRecentFilesAction*)actionCollection()->action(KStdAction::stdName(KStdAction::OpenRecent));
       recent->setItems(_recentFiles);
    }

    if(memberList->count()==1) // if this is the first window, read settings
    {
       KConfigGroupSaver cs(config,"CatalogManager");

       _catManSettings.poBaseDir=config->readEntry("PoBaseDir"
               ,Defaults::CatalogManager::poBaseDir());
       _catManSettings.potBaseDir=config->readEntry("PotBaseDir"
               ,Defaults::CatalogManager::potBaseDir());
       _catManSettings.openWindow=config->readBoolEntry("OpenWindow"
               ,Defaults::CatalogManager::openWindow);

       _catManSettings.killCmdOnExit=config->readBoolEntry("KillCmdOnExit"
               ,Defaults::CatalogManager::killCmdOnExit);

       if(config->hasKey("DirCommands"))
       {
          _catManSettings.dirCommands = config->readListEntry("DirCommands");
          _catManSettings.dirCommandNames = 
              config->readListEntry("DirCommandNames");
       }
       else
       {
          _catManSettings.dirCommands = Defaults::CatalogManager::dirCommands();
          _catManSettings.dirCommandNames = 
              Defaults::CatalogManager::dirCommandNames();
       }
       if(config->hasKey("FileCommands"))
       {
          _catManSettings.fileCommands = config->readListEntry("FileCommands");
          _catManSettings.fileCommandNames = 
              config->readListEntry("FileCommandNames");
       }
       else
       {
          _catManSettings.fileCommands=Defaults::CatalogManager::fileCommands();
          _catManSettings.fileCommandNames = 
              Defaults::CatalogManager::fileCommandNames();
       }

       if(!config->hasGroup("PathInfo"))
       {
           config->setGroup("PathInfo");
           config->writeEntry("MessageRoot",_catManSettings.poBaseDir);
           config->writeEntry("TemplateRoot",_catManSettings.potBaseDir);
       }
               
    }
    
    {
       KConfigGroupSaver saver(config,"Tags");

       if( config->hasKey("Expressions") )
       {
           QStringList s = config->readListEntry("Expressions");
    	    TagExtractor::setTagExpressions(&s);
       }
    }

    m_view->setSettings(_catManSettings);
}



void KBabel::saveProperties(KConfig *config)
{
   m_view->saveSession(config);
}

void KBabel::readProperties(KConfig *config)
{
   m_view->restoreSession(config);
}

bool KBabel::queryClose()
{
   if(m_view->isSearching())
   {
       connect(m_view,SIGNAL(signalSearchActive(bool)),this,SLOT(quit()));
       m_view->stopSearch();
       return false;
   }

   if(m_view->isLastView() && m_view->isModified())
   {
      switch(KMessageBox::warningYesNoCancel(this,
      i18n("The document contains unsaved changes.\n\
Do you want to save your changes or discard them?"),i18n("Warning"),
      i18n("&Save"),i18n("&Discard")))
      {
         case KMessageBox::Yes:
         {
            return m_view->saveFile();
         }
         case KMessageBox::No:
            return true;
         default:
            return false;
      }
   }

  return true;
}

bool KBabel::queryExit()
{
   KConfig* config;
   if( _projectFile.isEmpty() ) config=KGlobal::config();
   else config=new KConfig(_projectFile);
   saveSettings(config);
   m_view->saveSettings(config);
   m_view->saveView(config);

  return true;
}

void KBabel::quit()
{
    close();
}


void KBabel::dragEnterEvent(QDragEnterEvent *event)
{
    // accept uri drops only
    event->accept(QUriDrag::canDecode(event));
}

void KBabel::dropEvent(QDropEvent *event)
{
    QStrList uri;

    // see if we can decode a URI.. if not, just ignore it
    if (QUriDrag::decode(event, uri))
    {
       m_view->processUriDrop(uri,mapToGlobal(event->pos()));
    }
}

void KBabel::openRecent(const KURL& url)
{
   KBabelView *view = KBabelView::viewForURL(url,QString::null);
   if(view)
   {
       KWin::setActiveWindow(view->topLevelWidget()->winId());
       return;
   }   
   
   m_view->open(url);
}

void KBabel::open(const KURL& url)
{
   open(url,QString::null,false);
}

void KBabel::open(const KURL& url, const QString package, bool newWindow)
{
   kdDebug() << "opening file with project:" << _projectFile << endl;
   addToRecentFiles(url);
   KBabelView *view = KBabelView::viewForURL(url, _projectFile);
   if(view)
   {
	kdDebug() << "there is a such view" << endl;
       KWin::setActiveWindow(view->topLevelWidget()->winId());
       return;
   }
       
   if(newWindow)
   {
	kdDebug() << "creating new window"<< endl;
      fileNewWindow()->open(url, package,false);
   }
   else
   {
        m_view->open(url,package);
   }
}

void KBabel::openTemplate(const KURL& openURL,const KURL& saveURL,const QString& package, bool newWindow)
{
   if(newWindow)
   {
      fileNewWindow()->openTemplate(openURL,saveURL,package,false);
   }
   else
   {
      m_view->openTemplate(openURL,saveURL);
      m_view->catalog()->setPackage(package);
   }
}

void KBabel::fileOpen()
{
    m_view->open();

    KURL url=m_view->currentURL();
    addToRecentFiles(url);
}


void KBabel::addToRecentFiles(KURL url)
{
    KRecentFilesAction *recent;
    recent = (KRecentFilesAction*)actionCollection()->action(KStdAction::stdName(KStdAction::OpenRecent));

   recent->addURL(url);

   QStringList::Iterator it=_recentFiles.find(url.url());

   if(it != _recentFiles.end())
   {
      _recentFiles.remove(it);
      _recentFiles.prepend(url.url());
   }
   else if( _recentFiles.count() < MAX_RECENT)
   {
      _recentFiles.prepend(url.url());
   }
   else
   {
      _recentFiles.prepend(url.url());
      _recentFiles.remove(_recentFiles.last());
   }
}

void KBabel::fileSave()
{
    // this slot is called whenever the File->Save menu is selected,
    // the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
    // button is clicked

    if(!m_view->isModified())
    {
       statusBar()->message(i18n("There are no changes to save."),2000);
    }
    else
    {
       m_view->saveFile();

       KURL url=m_view->currentURL();

       DCOPClient *client = kapp->dcopClient();
       QByteArray data;
       QDataStream arg(data, IO_WriteOnly);
       arg << ((url.directory(false)+url.fileName()).utf8())  ;
       if( !client->send( "catalogmanager-*", "CatalogManagerIFace", "updatedFile(QCString)", data )) 
        kdDebug() << "Unable to send file update info via DCOP" << endl;
    }
}

void KBabel::fileSaveAs()
{
    m_view->saveFileAs();
    KURL url=m_view->currentURL();

    DCOPClient *client = kapp->dcopClient();
    QByteArray data;
    QDataStream arg(data, IO_WriteOnly);
    arg << ((url.directory(false)+url.fileName()).utf8())  ;
    if( !client->send( "catalogmanager-*", "CatalogManagerIFace", "updatedFile(QCString)", data )) 
	kdDebug() << "Unable to send file update info via DCOP" << endl;
}

void KBabel::fileSaveSpecial()
{
    if( !m_view->saveFileSpecial() ) return;

    KURL url=m_view->currentURL();

    DCOPClient *client = kapp->dcopClient();
    QByteArray data;
    QDataStream arg(data, IO_WriteOnly);
    arg << ((url.directory(false)+url.fileName()).utf8())  ;
    if( !client->send( "catalogmanager-*", "CatalogManagerIFace", "updatedFile(QCString)", data )) 
	kdDebug() << "Unable to send file update info via DCOP" << endl;
}

void KBabel::fileMail()
{
    if( m_view->isModified() ) fileSave();
    mailer->sendOneFile(m_view->currentURL().prettyURL());
}

void KBabel::fileNewView()
{
   KBabel* b=new KBabel(m_view->catalog(),_projectFile);
   b->setSettings(m_view->searchSettings(),m_view->editorSettings());
   b->show();
}

KBabel* KBabel::fileNewWindow()
{
   KBabel* b=new KBabel(_projectFile);
   b->setSettings(m_view->searchSettings(),m_view->editorSettings()
            ,m_view->catalog()->saveSettings(),m_view->catalog()->identitySettings());
   b->show();

   return b;
}

void KBabel::toggleEditMode()
{
   bool ovr=!m_view->isOverwriteMode();

   m_view->setOverwriteMode(ovr);

   if(ovr)
      statusBar()->changeItem(i18n("OVR"),ID_STATUS_EDITMODE);
   else
      statusBar()->changeItem(i18n("INS"),ID_STATUS_EDITMODE);

}

void KBabel::optionsShowToolbar(bool on)
{
   if(on)
   {
      toolBar()->show();
   }
   else
   {
      toolBar()->hide();
   }
}

void KBabel::optionsShowNavBar(bool on)
{
   if(on)
   {
      NAVIGATIONBAR->show();
   }
   else
   {
      NAVIGATIONBAR->hide();
   }
}

void KBabel::optionsShowStatusbar(bool on)
{
   if(on)
   {
      statusBar()->show();
   }
   else
   {
      statusBar()->hide();
   }

}

void KBabel::optionsEditToolbars()
{
   KEditToolbar dlg(actionCollection());

   if (dlg.exec() == true)
   {
     createGUI();
   }
}


void KBabel::checkMenuItemTools()
{
   KToggleAction* action=(KToggleAction*)actionCollection()->action("settings_show_tools");
   action->setChecked(true);
}

void KBabel::checkMenuItemComments()
{
   KToggleAction* action=(KToggleAction*)actionCollection()->action("settings_show_comments");
   action->setChecked(true);
}

void KBabel::optionsConfigure()
{

    KKeyDialog::configureKeys(actionCollection(),"kbabelui.rc",true);
}

void KBabel::optionsPreferences()
{
    if(!_prefDialog)
    {
        _prefDialog = new KBabelPreferences(m_view->searchSettings()
                        , m_view->editorSettings()
                        , m_view->catalog()->saveSettings()
                        , m_view->catalog()->identitySettings()
                        , _catManSettings
                        , m_view->catalog()->miscSettings()
			, m_view->sourceContextSettings()
                        , m_view->dictionaries());
        prefDialogs.append(_prefDialog);

        connect(_prefDialog,SIGNAL(identityOptionsChanged(IdentitySettings))
                ,m_view->catalog(),SLOT(setSettings(IdentitySettings)));
        connect(_prefDialog,SIGNAL(saveOptionsChanged(SaveSettings))
                ,m_view->catalog(),SLOT(setSettings(SaveSettings)));
        connect(_prefDialog,SIGNAL(editorOptionsChanged(EditorSettings))
                ,m_view,SLOT(setSettings(EditorSettings)));
        connect(_prefDialog,SIGNAL(searchOptionsChanged(SearchSettings))
                ,m_view,SLOT(setSettings(SearchSettings)));
        connect(_prefDialog,SIGNAL(miscOptionsChanged(MiscSettings))
                , m_view->catalog(),SLOT(setSettings(MiscSettings)));
        connect(_prefDialog,SIGNAL(sourceContextOptionsChanged(SourceContextSettings))
                , m_view,SLOT(setSettings(SourceContextSettings)));

        connect(m_view->catalog(),SIGNAL(signalSettingsChanged(SaveSettings))
                ,_prefDialog, SLOT(updateSaveSettings(SaveSettings)));
        connect(m_view->catalog()
                , SIGNAL(signalSettingsChanged(IdentitySettings)),_prefDialog
                , SLOT(updateIdentitySettings(IdentitySettings)));
        connect(m_view,SIGNAL(signalSearchSettingsChanged(SearchSettings))
                ,_prefDialog, SLOT(updateSearchSettings(SearchSettings)));

        connect(_prefDialog,SIGNAL(catManOptionsChanged(CatManSettings))
                  ,this,SLOT(setCatManSettings(CatManSettings)));

        connect(m_view->catalog(),SIGNAL(signalSettingsChanged(MiscSettings))
                ,_prefDialog, SLOT(updateMiscSettings(MiscSettings)));
    }

    int prefHeight=_prefDialog->height();
    int prefWidth=_prefDialog->width();
    int width=this->width();
    int height=this->height();

    int x=width/2-prefWidth/2;
    int y=height/2-prefHeight/2;

    _prefDialog->move(mapToGlobal(QPoint(x,y)));

    if(!_prefDialog->isVisible())
    {
       _prefDialog->show();
    }

    _prefDialog->raise();
    KWin::setActiveWindow(_prefDialog->winId());
}

void KBabel::setLedColor(const QColor& color)
{
   if(_fuzzyLed)
   {
      _fuzzyLed->setColor(color);
   }
   if(_untransLed)
   {
      _untransLed->setColor(color);
   }
   if(_errorLed)
   {
      _errorLed->setColor(color);
   }
}


void KBabel::setCatManSettings(CatManSettings settings)
{
#if 0
   if(_catalogManager)
   {
      _catalogManager->setSettings(settings);
   }

   updateCatManSettings(settings);
#endif
}

void KBabel::updateCatManSettings(CatManSettings settings)
{
   _catManSettings=settings;

   // update settings of the catalog manager in all preferences dialogs
   KBabelPreferences* dialog;
   for(dialog=prefDialogs.first(); dialog != 0 ; dialog=prefDialogs.next())
   {
       dialog->updateCatManSettings(settings);
   }
   
    KConfig* config;
    if( _projectFile.isEmpty() ) config = KGlobal::config();
    else config = new KConfig(_projectFile);
   KConfigGroupSaver gs(config,"PathInfo");
       
   config->writeEntry("MessageRoot",_catManSettings.poBaseDir);
   config->writeEntry("TemplateRoot",_catManSettings.potBaseDir);

   emit catalogManagerSettingsChanged();

   m_view->setSettings(_catManSettings);
}


void KBabel::openCatalogManager()
{
    QCString service;
    QString result;
    
    DCOPClient * client = kapp->dcopClient();
    
    // find out, if there is a running catalog manager
    QCStringList apps = client->registeredApplications();
    for( QCStringList::Iterator it = apps.begin() ; it != apps.end() ; it++ )
    {
	QString clientID = *it;
	if( clientID.startsWith("catalogmanager") )
	{
	    service = *it;
	    break;
	}
    }
    
    // if there is no running catalog manager, start one
    if( service.isEmpty() )
    {
	QString prog = "catalogmanager";
	QString url = "";
	if( kapp->startServiceByDesktopName(prog,url, &result,&service))
	{
	     KMessageBox::error(this, i18n("Unable to use KLauncher to start "
	        "Catalog Manager. You should check the installation of KDE.\n"
		"Please start Catalog Manager manually."));
	     return;
	}
    }
    
    // set preferred window 
    QByteArray data;
    QDataStream arg(data, IO_WriteOnly);
    arg << (this->winId()) ;
    if( !client->send( service, "CatalogManagerIFace", "setPreferredWindow( WId )", data )) kdDebug() << "Unable to set preferred window via DCOP" << endl;
}



void KBabel::firstEntryDisplayed(bool flag)
{
   KAction* firstAction=(KAction*)actionCollection()->action(KStdAction::stdName(KStdAction::FirstPage));
   KAction* prevAction=(KAction*)actionCollection()->action("go_prev_entry");

   firstAction->setEnabled(!flag);
   prevAction->setEnabled(!flag);

}

void KBabel::lastEntryDisplayed(bool flag)
{
   KAction* lastAction=(KAction*)actionCollection()->action(KStdAction::stdName(KStdAction::LastPage));
   KAction* nextAction=(KAction*)actionCollection()->action("go_next_entry");

   lastAction->setEnabled(!flag);
   nextAction->setEnabled(!flag);
}

void KBabel::fuzzyDisplayed(bool flag)
{
    if(!_fuzzyLed)
       return;

    if(flag)
    {
       if(_fuzzyLed->state()==KLed::Off)
       {
          _fuzzyLed->on();
       }
    }
    else
    {
       if(_fuzzyLed->state()==KLed::On)
           _fuzzyLed->off();
    }
}

void KBabel::untranslatedDisplayed(bool flag)
{
    if(!_untransLed)
       return;

    // do not allow fuzzy toggle for untranslated
    KAction *action=actionCollection()->action("edit_toggle_fuzzy");
    if(action)
        action->setEnabled(!flag);


    if(flag)
    {
       if(_untransLed->state()==KLed::Off)
          _untransLed->on();
    }
    else
    {
       if(_untransLed->state()==KLed::On)
          _untransLed->off();
    }
}


void KBabel::faultyDisplayed(bool flag)
{
    if(!_errorLed)
       return;

    if(flag)
    {
       if(_errorLed->state()==KLed::Off)
          _errorLed->on();
    }
    else
    {
       if(_errorLed->state()==KLed::On)
          _errorLed->off();
    }
}


void KBabel::displayedEntryChanged(uint index)
{
   statusBar()->changeItem(i18n("Current: %1").arg(index),ID_STATUS_CURRENT);
}

void KBabel::setNumberOfTotal(uint number)
{
   statusBar()->changeItem(i18n("Total: %1").arg(number),ID_STATUS_TOTAL);
}

void KBabel::setNumberOfFuzzies(uint number)
{
   statusBar()->changeItem(i18n("Fuzzy: %1").arg(number),ID_STATUS_FUZZY);
}

void KBabel::setNumberOfUntranslated(uint number)
{
   statusBar()->changeItem(i18n("Untranslated: %1").arg(number),ID_STATUS_UNTRANS);
}

void KBabel::hasFuzzyAfterwards(bool flag)
{
   a_nextFuzzy->setEnabled(flag);

   // check if there is  a fuzzy or untranslated afterwards
   if( flag || a_nextUntrans->isEnabled() )
   {
       a_nextFoU->setEnabled(true);
   }
   else
   {
       a_nextFoU->setEnabled(false);
   }

}

void KBabel::hasFuzzyInFront(bool flag)
{
   a_prevFuzzy->setEnabled(flag);

   // check if there is  a fuzzy or untranslated in front
   if( flag || a_prevUntrans->isEnabled() )
   {
       a_prevFoU->setEnabled(true);
   }
   else
   {
       a_prevFoU->setEnabled(false);
   }
}

void KBabel::hasUntranslatedAfterwards(bool flag)
{
   a_nextUntrans->setEnabled(flag);

   // check if there is a fuzzy or untranslated afterwards
   if( flag || a_nextFuzzy->isEnabled() )
   {
       a_nextFoU->setEnabled(true);
   }
   else
   {
       a_nextFoU->setEnabled(false);
   }
}

void KBabel::hasUntranslatedInFront(bool flag)
{
   a_prevUntrans->setEnabled(flag);

   // check if there is  a fuzzy or translated in front
   if( flag || a_prevFuzzy->isEnabled() )
   {
       a_prevFoU->setEnabled(true);
   }
   else
   {
       a_prevFoU->setEnabled(false);
   }
}



void KBabel::hasErrorAfterwards(bool flag)
{
   KAction* action=actionCollection()->action("go_next_error");
   action->setEnabled(flag);
}

void KBabel::hasErrorInFront(bool flag)
{
   KAction* action=actionCollection()->action("go_prev_error");
   action->setEnabled(flag);
}


void KBabel::enableBackHistory(bool on)
{
   KAction* action=actionCollection()->action("go_back_history");
   action->setEnabled(on);
}

void KBabel::enableForwardHistory(bool on)
{
   KAction* action=actionCollection()->action("go_forward_history");
   action->setEnabled(on);
}


void KBabel::prepareProgressBar(QString msg,int max)
{
   if(_statusbarTimer->isActive())
        _statusbarTimer->stop();

   _progressBar->show();
   _progressLabel->setText(" "+msg);
   _progressBar->setTotalSteps(max);
   _progressBar->setProgress(0);

}

void KBabel::clearProgressBar()
{
   _progressBar->setProgress(0);
   _progressBar->hide();
   _progressLabel->setText("      ");
}


void KBabel::changeStatusbar(const QString& text)
{
    // display the text on the statusbar
    _progressLabel->setText(" "+text);

    if(_statusbarTimer->isActive())
        _statusbarTimer->stop();

    _statusbarTimer->start(5000,true);
}

void KBabel::clearStatusbarMsg()
{
    _progressLabel->setText("");
}

void KBabel::changeCaption(const QString& text)
{
    // display the text on the caption
    setCaption(text,m_view->isModified());
}


void KBabel::showModified(bool on)
{
    // display the text on the caption
    setCaption(m_view->catalog()->package(),on);

    KAction *action=actionCollection()->action(
            KStdAction::stdName(KStdAction::Save));
    action->setEnabled(on);
    
    action=actionCollection()->action(KStdAction::stdName(KStdAction::Revert));
    action->setEnabled(on);
}


void KBabel::enableDefaults(bool readOnly)
{
    m_accel->setEnabled(!readOnly);

    KAction* action;
    action=actionCollection()->action(KStdAction::stdName(KStdAction::SaveAs));
    if(action)
       action->setEnabled(true);
    action=actionCollection()->action("save_special");
    if(action)
       action->setEnabled(true);
    action=actionCollection()->action("set_package");
    if(action)
       action->setEnabled(true);
    action=actionCollection()->action(KStdAction::stdName(KStdAction::Mail));
    if(action)
       action->setEnabled(true);

    action=actionCollection()->action(KStdAction::stdName(KStdAction::Cut));
    if(action)
        action->setEnabled(!readOnly);
    action=actionCollection()->action(KStdAction::stdName(KStdAction::Copy));
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action(KStdAction::stdName(KStdAction::Paste));
    if(action)
        action->setEnabled(!readOnly);

    action=actionCollection()->action(KStdAction::stdName(KStdAction::Find));
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action(KStdAction::stdName(KStdAction::FindNext));
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action(KStdAction::stdName(KStdAction::FindPrev));
    if(action)
        action->setEnabled(true);

    action=actionCollection()->action(KStdAction::stdName(KStdAction::Replace));
    if(action)
        action->setEnabled(!readOnly);



    action=actionCollection()->action(KStdAction::stdName(KStdAction::SelectAll));
    if(action)
       action->setEnabled(true);

    action=actionCollection()->action("clear");
    if(action)
       action->setEnabled(!readOnly);

    action=actionCollection()->action("msgid2msgstr");
    if(action)
       action->setEnabled(!readOnly);

    action=actionCollection()->action("search2msgstr");
    if(action)
        action->setEnabled(!readOnly);

    action=actionCollection()->action("edit_edit_header");
    if(action)
        action->setEnabled(true);

    action=actionCollection()->action("edit_toggle_fuzzy");
    if(action)
        action->setEnabled(true);

    action=actionCollection()->action("dict_search_selected");
    if(action)
        action->setEnabled(true);


    action=actionCollection()->action("dict_search_all");
    if(action)
       action->setEnabled(true);

    action=actionCollection()->action(KStdAction::stdName(KStdAction::Goto));
    if(action)
       action->setEnabled(true);

    action=actionCollection()->action("spellcheck_common");
    if(action)
        action->setEnabled(!readOnly);
    action=actionCollection()->action("spellcheck_all");
    if(action)
        action->setEnabled(!readOnly);
    action=actionCollection()->action("spellcheck_from_cursor");
    if(action)
       action->setEnabled(!readOnly);
    action=actionCollection()->action("spellcheck_current");
    if(action)
       action->setEnabled(!readOnly);

    action=actionCollection()->action("spellcheck_marked");
    if(action)
        action->setEnabled(!readOnly);

    action=actionCollection()->action("diff_toggleDiff");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("diff_diff");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("diff_showOrig");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("diff_openFile");
    if(action)
        action->setEnabled(true);
    
    action=actionCollection()->action("rough_translation");
    if(action)
        action->setEnabled(!readOnly);


    action=actionCollection()->action("check_syntax");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("check_accels");
   if(action)
       action->setEnabled(true);
    action=actionCollection()->action("check_arguments");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("check_equations");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("check_context");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("check_pluralforms");
    if(action)
        action->setEnabled(true);
    action=actionCollection()->action("check_xmltags");
    if(action)
        action->setEnabled( m_view->catalog()->isGeneratedFromDocbook() );
    action=actionCollection()->action("check_all");
    if(action)
        action->setEnabled( true );

    if(readOnly)
       statusBar()->changeItem(i18n("RO"),ID_STATUS_READONLY);
    else
       statusBar()->changeItem(i18n("RW"),ID_STATUS_READONLY);
}

void KBabel::enableUndo(bool on)
{
   KAction* action=actionCollection()->action(KStdAction::stdName(KStdAction::Undo));
   action->setEnabled(on);
}

void KBabel::enableRedo(bool on)
{
   KAction* action=actionCollection()->action(KStdAction::stdName(KStdAction::Redo));
   action->setEnabled(on);
}

void KBabel::enableStop(bool flag)
{
   KAction* action=(KAction*)actionCollection()->action("stop_search");
   action->setEnabled(flag);
}

void KBabel::gettextHelp()
{
    QString error;
    KApplication::startServiceByDesktopName("khelpcenter",
                QString("info:/gettext"), &error);

    if(!error.isEmpty())
    {
        KMessageBox::sorry(this,i18n("An error occurred while "
                "trying to open the gettext info page:\n%1").arg(error));
    }
}

void KBabel::buildDictMenus()
{
   QPtrList<ModuleInfo> dictList = m_view->dictionaries();
   dictList.setAutoDelete(true);

   dictMenu->clear();
   selectionDictMenu->clear();
   configDictMenu->clear();
   editDictMenu->clear();
   aboutDictMenu->clear();
   
   ModuleInfo *info;
   for(info = dictList.first(); info !=0; info = dictList.next())
   {
      QString accel="Ctrl+Alt+%1";
      dictMenu->add(info->name,info->id, accel);
      
      accel=QString("Ctrl+%1");
      selectionDictMenu->add(info->name,info->id, accel);
      
      configDictMenu->add(info->name,info->id);
      aboutDictMenu->add(info->name,info->id);

      if(info->editable)
      {
         dictMenu->add(info->name,info->id);
      }
   }
}

void KBabel::updateCursorPosition(int line, int col)
{
    statusBar()->changeItem(i18n("Line: %1 Col: %2").arg(line+1).arg(col+1)
            ,ID_STATUS_CURSOR);
}


KBabel *KBabel::winForURL(const KURL& url, QString project)
{
    KBabel *kb=0;
    
    KBabelView *v = KBabelView::viewForURL(url,project);
    if(v)
    {
        QObject *p = v->parent();
        while(p && !p->inherits("KBabel"))
        {
            p = p->parent();
        }
       
        if(p)
            kb = static_cast<KBabel*>(p);
    }

    return kb;
}

KBabel *KBabel::emptyWin(QString project)
{
    KBabel *kb=0;
    
    KBabelView *v = KBabelView::emptyView(project);
    if(v)
    {
        QObject *p = v->parent();
        while(p && !p->inherits("KBabel"))
        {
            p = p->parent();
        }
       
        if(p)
            kb = static_cast<KBabel*>(p);
    }

    return kb;
}

void KBabel::spellcheckMoreFiles(QStringList filelist)
{
    if( filelist.isEmpty() ) return;
    _toSpellcheck = filelist;
    connect( m_view, SIGNAL( signalSpellcheckDone(int) ), this, SLOT( spellcheckDone(int)));
    spellcheckDone( KS_IGNORE ); // use something else than KS_STOP
}

void KBabel::spellcheckDone( int result)
{
    if( _toSpellcheck.isEmpty() || result == KS_STOP)
    {
	disconnect( m_view, SIGNAL( signalSpellcheckDone(int)), this, SLOT(spellcheckDone( int)));
	KMessageBox::information( this, i18n("MessageBox text", "Spellchecking of multiple files is finished."),
	    i18n("MessageBox caption", "Spellcheck Done"));
    }
    else 
    {
	QString file = _toSpellcheck.first();
	_toSpellcheck.pop_front();
	if( m_view->isModified() ) fileSave();
	open(file, QString::null, false);
	QTimer::singleShot( 1, m_view, SLOT(spellcheckAll()));
    }
}

#include "kbabel.moc"
