/* **************************************************************************** This file is part of KBabel Copyright (C) 1999-2000 by Matthias Kiefer 2002-2005 by Stanislav Visnovsky Copyright (C) 2006 by Nicolas GOUTTE This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. In addition, as a special exception, the copyright holders give permission to link the code of this program with any edition of the TQt library by Trolltech AS, Norway (or with modified versions of TQt that use the same license as TQt), and distribute linked combinations including the two. You must obey the GNU General Public License in all respects for all of the code used other than TQt. If you modify this file, you may extend this exception to your version of the file, but you are not obligated to do so. If you do not wish to do so, delete this exception statement from your version. **************************************************************************** */ #include "kbabelview.h" #include "catalogfileplugin.h" #include "toolaction.h" #include "kbabelsettings.h" #include "kbprojectsettings.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "resources.h" #include "editcmd.h" #include "finddialog.h" #include "gotodialog.h" #include "headereditor.h" #include "hidingmsgedit.h" #include "kbabeldictbox.h" #include "kbcatalog.h" #include "msgfmt.h" #include "spelldlg.h" #include "regexpextractor.h" #include "projectprefwidgets.h" #include "kbabel.h" #include "kbprojectmanager.h" #include "commentview.h" #include "contextview.h" #include "kbcataloglistview.h" #include "charselectview.h" #include "taglistview.h" #include "sourceview.h" #include "errorlistview.h" #include "version.h" #define ID_DROP_OPEN 1 #define ID_DROP_OPEN_TEMPLATE 2 #define MAX_HISTORY 50 using namespace KBabel; TQPtrList *KBabelView::viewList = 0; KBabelView::KBabelView(KBCatalog* catalog,KBabelMW *parent, Project::Ptr project) : TQWidget(parent) , _redirectedBackSearch (false) , _project (project) , m_mainwindow (parent) , m_sourceview (0) { if(!viewList) viewList = new TQPtrList; viewList->append(this); if (catalog == 0) kdFatal(KBABEL) << "catalog==0" << endl; _catalog=catalog; _catalog->registerView(this); _config = KSharedConfig::openConfig ("kbabelrc"); TDEConfigGroupSaver gs(_config,"Editor"); bool buildLeds=! KBabelSettings::ledInStatusbar(); _fuzzyLed=0; _untransLed=0; _errorLed=0; _currentIndex=0; _currentPos.item=1; // to ensure update _currentPos.form=0; _gotoDialog=0; _findDialog=0; _replaceDialog=0; _replaceAskDialog=0; _tagsMenu=0; _argsMenu=0; _autoSearchTempDisabled=false; _diffEnabled=false; _loadingDiffFile=false; _diffing=false; _dontBeep=false; m_overwrite = false; autoSaveTimer = 0; _showTryLaterBox=true; _tagExtractor = new RegExpExtractor( catalog->tagSettings().tagExpressions ); _argExtractor = new RegExpExtractor( catalog->tagSettings().argExpressions ); _editingDocumentation=false; _autocheckTools.clear(); _autocheckTools.setAutoDelete(true); spell.posDict.setAutoDelete(true); spell.active=false; spell2.kspell = 0; spell2.config = 0; setAcceptDrops(true); // this widget does not contain anything, we should hide it hide(); dictBox = new KBabelDictBox(this,"dictBox"); TQWhatsThis::add(dictBox, i18n("

Search results

" "

This part of the window shows the results of searching in " "dictionaries.

" "

In the top is displayed the number of entries found and " "where the currently displayed entry is found. Use the buttons " "at the bottom to navigate through the search results.

" "

Search is either started automatically when switching to " "another entry in the editor window or by choosing the desired " "dictionary in Dictionaries->Find....

" "

The common options can be configured in the preferences dialog " "in section Search and the options for the different " "dictionaries can be changed with " "Settings->Configure Dictionary.

")); initDockWidgets(); msgstrEdit->setReadOnly(true); dictBox->setEnabled(false); connect(this, TQT_SIGNAL(signalNewFileOpened(KURL)), m_cataloglistview, TQT_SLOT(slotNewFileOpened())); connect(msgstrEdit,TQT_SIGNAL(signalUndoCmd(KBabel::EditCommand*)),this,TQT_SLOT(forwardMsgstrEditCmd(KBabel::EditCommand*))); connect(msgstrEdit,TQT_SIGNAL(textChanged()),this ,TQT_SIGNAL(signalMsgstrChanged())); connect(msgstrEdit,TQT_SIGNAL(textChanged(const TQString&)),m_cataloglistview ,TQT_SLOT(msgstrChanged(const TQString&))); connect(this,TQT_SIGNAL(signalMsgstrChanged()),this,TQT_SLOT(autoCheck())); connect(msgstrEdit,TQT_SIGNAL(currentFormChanged(uint)), this ,TQT_SLOT(msgstrPluralFormChanged(uint))); connect(msgidLabel,TQT_SIGNAL(cursorPositionChanged(int,int)) , this, TQT_SIGNAL(signalCursorPosChanged(int,int))); connect(msgstrEdit,TQT_SIGNAL(cursorPositionChanged(int,int)) , this, TQT_SIGNAL(signalCursorPosChanged(int,int))); connect(dictBox,TQT_SIGNAL(searchStarted()),this ,TQT_SLOT(forwardSearchStart())); connect(dictBox, TQT_SIGNAL(progressStarts(const TQString&)), this ,TQT_SLOT(forwardProgressStart(const TQString&))); connect(dictBox,TQT_SIGNAL(progressed(int)),this ,TQT_SIGNAL(signalProgress(int))); connect(dictBox,TQT_SIGNAL(searchStopped()),this ,TQT_SLOT(forwardSearchStop())); connect(dictBox,TQT_SIGNAL(progressEnds()),this ,TQT_SIGNAL(signalClearProgressBar())); connect(dictBox,TQT_SIGNAL(modulesChanged()),this, TQT_SIGNAL(signalDictionariesChanged())); connect(dictBox,TQT_SIGNAL(errorInModule(const TQString&)),this ,TQT_SLOT(showError(const TQString&))); connect(_catalog,TQT_SIGNAL(signalSettingsChanged(KBabel::IdentitySettings)), this, TQT_SLOT(setNewLanguage())); connect(_catalog,TQT_SIGNAL(signalNumberOfFuzziesChanged(uint)), this, TQT_SLOT(checkFuzzies())); connect(_catalog,TQT_SIGNAL(signalNumberOfUntranslatedChanged(uint)), this, TQT_SLOT(checkUntranslated())); if(buildLeds) { connect(this,TQT_SIGNAL(signalFuzzyDisplayed(bool)) ,this,TQT_SLOT(toggleFuzzyLed(bool))); connect(this,TQT_SIGNAL(signalUntranslatedDisplayed(bool)) ,this,TQT_SLOT(toggleUntransLed(bool))); connect(this,TQT_SIGNAL(signalFaultyDisplayed(bool)) ,this,TQT_SLOT(toggleErrorLed(bool))); } _dropMenu = new TQPopupMenu(this); _dropMenu->insertItem(i18n("Menu item", "Open"),ID_DROP_OPEN); _dropMenu->insertItem(i18n("Open Template"),ID_DROP_OPEN_TEMPLATE); readSettings(_config); readProject(_project); connect (project, TQT_SIGNAL(signalSpellcheckSettingsChanged()), this, TQT_SLOT(updateProjectSettings())); if(!_catalog->currentURL().isEmpty()) { newFileOpened(_catalog->isReadOnly()); } // take over the language settings from the catalog setNewLanguage(); } KBabelView::~KBabelView() { viewList->remove(this); if(viewList->isEmpty()) { delete viewList; viewList=0; } _catalog->removeView(this); // check if this view was the last view and delete the catalog if necessary if(!_catalog->hasView()) { delete _catalog; } delete _argExtractor; delete _tagExtractor; if( spell2.kspell ) { spell2.kspell = 0; delete spell2.config; spell2.config = 0; } } void KBabelView::initDockWidgets() { // setup main dock widget - original text TQWidget *tempWidget=new TQWidget(this,"msgidWidget"); tempWidget->setMinimumSize(350,150); TQVBoxLayout *layout=new TQVBoxLayout(tempWidget); msgidLabel = new HidingMsgEdit(2, this, 0, tempWidget,"msgidLabel"); msgidLabel->installEventFilter(this); msgidLabel->setReadOnly(true); msgidLabel->setDiffMode(true); KCursor::setAutoHideCursor(msgidLabel,true); msgidLabel->setText(i18n("KBabel Version %1\n" "Copyright 1999-%2 by KBabel developers.\n" " Matthias Kiefer \n" " Stanislav Visnovsky \n" " Marco Wegner \n" " Dwayne Bailey \n" " Andrea Rizzi \n\n" "Any comments, suggestions, etc. should be sent to the mailing list .\n\n" "This program is licensed under the terms of the GNU GPL.\n\n" "Special thanks to Thomas Diehl for many hints to the GUI\n" "and the behavior of KBabel and to Stephan Kulow, who always\n" "lends me a helping hand.\n\n" "Many good ideas, especially for the Catalog Manager, are taken\n" "from KTranslator by Andrea Rizzi.").arg(VERSION).arg(2006)); TQLabel *label=new TQLabel(msgidLabel,i18n("O&riginal string (msgid):"),tempWidget); TQHBoxLayout* hb=new TQHBoxLayout(layout); hb->addSpacing(KDialog::marginHint()); hb->addWidget(label); layout->addWidget(msgidLabel); layout->setStretchFactor(msgidLabel,1); TQWhatsThis::add(tempWidget, i18n("

Original String

\n\

This part of the window shows the original message\n\ of the currently displayed entry.

")); KDockWidget* mainDock; mainDock = m_mainwindow->createDockWidget( "Original", TQPixmap ()); //i18n: translators: Dock window caption mainDock->setCaption(i18n("Original Text")); mainDock->setGeometry(50, 50, 100, 100); // forbit docking abilities of mainDock itself mainDock->setEnableDocking(KDockWidget::DockFullSite); mainDock->setWidget(tempWidget); m_mainwindow->setMainDockWidget(mainDock); // master dockwidget mainDock->show (); m_mainwindow->setView (mainDock); connect (this, TQT_SIGNAL (signalCopy ()), this, TQT_SLOT (textCopy ())); connect (this, TQT_SIGNAL (signalCut ()), this, TQT_SLOT (textCut ())); connect (this, TQT_SIGNAL (signalPaste ()), this, TQT_SLOT (textPaste ())); connect (this, TQT_SIGNAL (signalSelectAll ()), this, TQT_SLOT (selectAll ())); KDockWidget* comment_dock = m_mainwindow->createDockWidget( "Comment", TQPixmap ()); //i18n: translators: Dock window caption comment_dock->setCaption(i18n("Comment")); comment_dock->setGeometry(50, 50, 100, 100); comment_dock->setEnableDocking(KDockWidget::DockCorner); m_commentview = new CommentView(_catalog, comment_dock, _project); comment_dock->setWidget(m_commentview); comment_dock->manualDock( mainDock, // dock target KDockWidget::DockRight, // dock site 20 ); // relation target/this (in percent) comment_dock->show (); connect (this, TQT_SIGNAL (signalCopy ()), m_commentview, TQT_SLOT (textCopy ())); connect (this, TQT_SIGNAL (signalCut ()), m_commentview, TQT_SLOT (textCut ())); connect (this, TQT_SIGNAL (signalPaste ()), m_commentview, TQT_SLOT (textPaste ())); connect (this, TQT_SIGNAL (signalSelectAll ()), m_commentview, TQT_SLOT (textSelectAll ())); m_commentview->installEventFilter( TQT_TQOBJECT(this) ); // build the msgstr widget tempWidget=new TQWidget(this,"msgstrWidget"); tempWidget->setMinimumSize(350,150); layout=new TQVBoxLayout(tempWidget); // if undefined number of plural forms, use 1 int pf = _catalog->defaultNumberOfPluralForms(); if( pf < 1 ) pf = 1; msgstrEdit = new HidingMsgEdit( pf,this,spell2.kspell,tempWidget,"msgstrEdit"); msgstrEdit->installEventFilter(this); KCursor::setAutoHideCursor(msgstrEdit,true); label=new TQLabel(msgstrEdit,i18n("Trans&lated string (msgstr):"),tempWidget); hb=new TQHBoxLayout(layout); hb->setSpacing(KDialog::spacingHint()); hb->addSpacing(KDialog::marginHint()); hb->addWidget(label); hb->addStretch(1); if(! KBabelSettings::ledInStatusbar()) { _fuzzyLed = new KLed(TQt::red,KLed::Off,KLed::Sunken,KLed::Rectangular ,tempWidget); _fuzzyLed->setFixedSize(15,12); label = new TQLabel(i18n("fuzzy"),tempWidget); hb->addWidget(_fuzzyLed); hb->addWidget(label); hb->addSpacing(KDialog::spacingHint()); _untransLed = new KLed(TQt::red,KLed::Off,KLed::Sunken,KLed::Rectangular ,tempWidget); _untransLed->setFixedSize(15,12); label = new TQLabel(i18n("untranslated"),tempWidget); hb->addWidget(_untransLed); hb->addWidget(label); hb->addSpacing(KDialog::marginHint()); _errorLed = new KLed(TQt::red,KLed::Off,KLed::Sunken,KLed::Rectangular ,tempWidget); _errorLed->setFixedSize(15,12); label = new TQLabel(i18n("faulty"),tempWidget); hb->addWidget(_errorLed); hb->addWidget(label); hb->addSpacing(KDialog::marginHint()); hb->addStretch(1); // ### TODO: perhaps it should be moreprecise where the setting can be changed TQString ledMsg=i18n("

Status LEDs

\n" "

These LEDs display the status of the currently displayed message.\n" "You can change their color in the preferences dialog section\n" "Editor on page Appearance

"); TQWhatsThis::add(_fuzzyLed,ledMsg); TQWhatsThis::add(_untransLed,ledMsg); TQWhatsThis::add(_errorLed,ledMsg); } layout->addWidget(msgstrEdit); layout->setStretchFactor(msgstrEdit,1); TQWhatsThis::add(tempWidget, i18n("

Translation Editor

\n\

This editor displays and lets you edit the translation of the currently displayed message.

")); KDockWidget* msgstr_dock = m_mainwindow->createDockWidget( "Msgstr", TQPixmap ()); //i18n: translators: Dock window caption msgstr_dock->setCaption(i18n("Translated String")); msgstr_dock->setEnableDocking(KDockWidget::DockCorner); msgstr_dock->setWidget(tempWidget); msgstr_dock->manualDock( mainDock, // dock target KDockWidget::DockBottom, // dock site 50 ); // relation target/this (in percent) msgstr_dock->show (); KDockWidget* dock = m_mainwindow->createDockWidget( "Search", TQPixmap ()); //i18n: translators: Dock window caption dock->setCaption(i18n("the search (noun)","Search")); //i18n: translators: Dock tab caption dock->setTabPageLabel(i18n("the search (noun)","Se&arch")); dock->setGeometry(50, 50, 100, 100); dock->setWidget(dictBox); dock->manualDock( comment_dock, // dock target KDockWidget::DockBottom, // dock site 20 ); // relation target/this (in percent) dock->show (); KDockWidget* tools = dock; dock = m_mainwindow->createDockWidget( "PO context", TQPixmap ()); //i18n: translators: Dock window caption dock->setCaption(i18n("PO Context")); //i18n: translators: Dock tab caption dock->setTabPageLabel(i18n("PO C&ontext")); dock->setGeometry(50, 50, 100, 100); ContextView * m_contextview = new ContextView(_catalog, dock, _project); dock->setWidget(m_contextview); dock->manualDock( tools, // dock target KDockWidget::DockCenter, // dock site 20 ); // relation target/this (in percent) dock->show (); dock = m_mainwindow->createDockWidget( "Charselector", TQPixmap ()); //i18n: translators: Dock window caption dock->setCaption(i18n("Character Table")); //i18n: translators: Dock tab caption dock->setTabPageLabel(i18n("C&hars")); dock->setGeometry(50, 50, 100, 100); m_charselectorview = new CharacterSelectorView(_catalog, dock, _project); dock->setWidget(m_charselectorview); dock->manualDock( tools, // dock target KDockWidget::DockCenter, // dock site 20 ); // relation target/this (in percent) dock->show (); dock = m_mainwindow->createDockWidget( "Tag List", TQPixmap ()); //i18n: translators: Dock window caption dock->setCaption(i18n("Tag List")); //i18n: translators: Dock tab caption dock->setTabPageLabel(i18n("Tags")); dock->setGeometry(50, 50, 100, 100); TagListView* m_taglistview = new TagListView(_catalog, dock, _project); dock->setWidget(m_taglistview); dock->manualDock( tools, // dock target KDockWidget::DockCenter, // dock site 20 ); // relation target/this (in percent) dock->show (); dock = m_mainwindow->createDockWidget( "Source Context", TQPixmap ()); //i18n: translators: Dock window caption dock->setCaption(i18n("Source Context")); //i18n: translators: Dock tab caption dock->setTabPageLabel(i18n("Source")); dock->setGeometry(50, 50, 100, 100); m_sourceview = new SourceView(_catalog, dock, _project); dock->setWidget(m_sourceview); dock->manualDock( tools, // dock target KDockWidget::DockCenter, // dock site 20 ); // relation target/this (in percent) dock->show (); KDockWidget* translist_dock = m_mainwindow->createDockWidget( "Translation List", TQPixmap ()); translist_dock->setCaption(i18n("Translation List")); translist_dock->setGeometry(50, 50, 100, 100); translist_dock->setEnableDocking(KDockWidget::DockFullSite); m_cataloglistview = new KBCatalogListView(_catalog, translist_dock, _project); translist_dock->setWidget(m_cataloglistview); translist_dock->manualDock( mainDock, KDockWidget::DockTop,100); translist_dock->show (); dock = m_mainwindow->createDockWidget( "Error List", TQPixmap ()); //i18n: translators: Dock window caption dock->setCaption(i18n("Error List")); //i18n: translators: Dock tab caption dock->setTabPageLabel(i18n("Errors")); dock->setGeometry(50, 50, 100, 100); ErrorListView* m_errorlistview = new ErrorListView(_catalog, dock, _project); dock->setWidget(m_errorlistview); dock->manualDock( tools, // dock target KDockWidget::DockCenter, // dock site 20 ); dock->show (); connect(m_cataloglistview,TQT_SIGNAL(signalSelectionChanged(const KBabel::DocPosition&)) ,this,TQT_SLOT(gotoEntry(const KBabel::DocPosition&))); connect(this,TQT_SIGNAL(signalDisplayed(const KBabel::DocPosition&)) ,m_commentview,TQT_SLOT(gotoEntry(const KBabel::DocPosition&))); connect(this,TQT_SIGNAL(signalDisplayed(const KBabel::DocPosition&)) ,m_contextview,TQT_SLOT(gotoEntry(const KBabel::DocPosition&))); connect(this,TQT_SIGNAL(signalDisplayed(const KBabel::DocPosition&)) ,m_taglistview,TQT_SLOT(gotoEntry(const KBabel::DocPosition&))); connect(this,TQT_SIGNAL(signalDisplayed(const KBabel::DocPosition&)) ,m_sourceview,TQT_SLOT(gotoEntry(const KBabel::DocPosition&))); connect(this,TQT_SIGNAL(signalDisplayed(const KBabel::DocPosition&)) ,m_errorlistview,TQT_SLOT(gotoEntry(const KBabel::DocPosition&))); connect(this,TQT_SIGNAL(signalFaultyDisplayed(bool)) ,m_errorlistview,TQT_SLOT(updateView())); connect(m_charselectorview, TQT_SIGNAL( characterDoubleClicked(TQChar) ) ,this, TQT_SLOT( insertChar(TQChar) )); connect(m_taglistview,TQT_SIGNAL(signalTagSelected(const TQString&)) , this, TQT_SLOT(insertTagFromTool(const TQString&))); connect(m_taglistview,TQT_SIGNAL(signalHighlightedTagChanged(int)) , this, TQT_SLOT(skipToTagFromTool(int))); connect(this, TQT_SIGNAL(signalNextTag(int)) , m_taglistview, TQT_SLOT(highlightTag(int))); connect(m_commentview,TQT_SIGNAL(signalCursorPosChanged(int,int)) , m_mainwindow, TQT_SLOT(updateCursorPosition(int,int))); } KBabelView *KBabelView::viewForURL(const KURL& url, const TQString project) { if(url.isEmpty()) return 0; if(!viewList) return 0; KURL u = url; u.cleanPath(); TQPtrListIterator it(*viewList); KBabelView *view=0; while( it.current() && !view) { KURL cu = it.current()->currentURL(); cu.cleanPath(); if(cu == u && it.current()->project()==project) { view = it.current(); } ++it; } return view; } KBabelView *KBabelView::emptyView(const TQString) { if(!viewList) return 0; TQPtrListIterator it(*viewList); KBabelView *view=0; while( it.current() && !view) { KURL cu = it.current()->currentURL(); if( cu.isEmpty() ) return it.current(); ++it; } return 0; } KURL KBabelView::currentURL() const { return _catalog->currentURL(); } bool KBabelView::isLastView() const { return _catalog->isLastView(); } bool KBabelView::isModified() const { return _catalog->isModified(); } bool KBabelView::isReadOnly() const { return _catalog->isReadOnly(); } bool KBabelView::isOverwriteMode() const { return m_overwrite; } void KBabelView::setOverwriteMode(bool ovr) { m_overwrite = ovr; msgstrEdit->setOverwriteMode(ovr); m_commentview->setOverwriteMode(ovr); } bool KBabelView::isSearching() const { return dictBox->isSearching(); } void KBabelView::update(EditCommand* cmd, bool undo) { if((int)_currentIndex==cmd->index()) { emitEntryState(); if(cmd->part()==Msgstr) { msgstrEdit->processCommand(cmd,undo); emit signalMsgstrChanged(); } } } void KBabelView::readSettings(TDEConfig* config) { if(KBabelSettings::autoUnsetFuzzy()) { connect(msgstrEdit,TQT_SIGNAL(textChanged()) ,this,TQT_SLOT(autoRemoveFuzzyStatus())); } setupAutoCheckTools(); TDEConfigGroupSaver saver(config,"Editor"); _diffEnabled = config->readBoolEntry("AutoDiff", false); emit signalDiffEnabled(_diffEnabled); if(_fuzzyLed) { _fuzzyLed->setColor(KBabelSettings::ledColor()); } if(_untransLed) { _untransLed->setColor(KBabelSettings::ledColor()); } if(_errorLed) { _errorLed->setColor(KBabelSettings::ledColor()); } msgstrEdit->setCleverEditing(KBabelSettings::cleverEditing()); msgstrEdit->setHighlightBg(KBabelSettings::highlightBackground()); msgidLabel->setHighlightBg(KBabelSettings::highlightBackground()); msgstrEdit->setHighlightSyntax(KBabelSettings::highlightSyntax()); msgidLabel->setHighlightSyntax(KBabelSettings::highlightSyntax()); msgstrEdit->setQuotes(KBabelSettings::enableQuotes()); msgidLabel->setQuotes(KBabelSettings::enableQuotes()); msgstrEdit->setSpacePoints(KBabelSettings::whitespacePoints()); msgidLabel->setSpacePoints(KBabelSettings::whitespacePoints()); msgstrEdit->setFont(KBabelSettings::msgFont()); msgidLabel->setFont(KBabelSettings::msgFont()); msgstrEdit->setBgColor(KBabelSettings::backgroundColor()); msgidLabel->setBgColor(KBabelSettings::backgroundColor()); msgstrEdit->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor() ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor()); msgidLabel->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor() ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor()); msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline() ,KBabelSettings::diffDelStrikeOut() ); msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor() ); } void KBabelView::updateProjectSettings() { readProject(_project); } void KBabelView::readProject(Project::Ptr project) { _spellcheckSettings = project->spellcheckSettings(); if( _spellcheckSettings.onFlySpellcheck ) { // if there is a spellchecker already, free it if( spell2.kspell ) { // ensure the spellchecker is not used anymore msgstrEdit->setSpellChecker(0L); // free it spell2.kspell->cleanUp(); delete spell2.kspell; spell2.kspell = 0; } spell2.config = new KSpellConfig(0L, "tempSpellConfig"); spell2.config->setNoRootAffix(_spellcheckSettings.noRootAffix); spell2.config->setRunTogether(_spellcheckSettings.runTogether); spell2.config->setClient(_spellcheckSettings.spellClient); spell2.config->setEncoding(_spellcheckSettings.spellEncoding); spell2.config->setDictionary(_spellcheckSettings.spellDict); spell2.kspell= new KSpell(this, "", TQT_TQOBJECT(this), TQT_SLOT(dummy(KSpell *)), spell2.config, false, false); if(spell2.kspell->status() == KSpell::Error) kdWarning(KBABEL) << "Something's wrong with KSpell, can't start on-the-fly checking" << endl; else { kdDebug() << "On the fly spellchecker: " << spell2.kspell << endl; msgstrEdit->setSpellChecker(spell2.kspell); } // spell2.kspell->setAutoDelete(true); // let KSpell handle delete //on-the-fly spellcheck end } else { // turn off spellchecker msgstrEdit->setSpellChecker(0); // invalidate the current settings, to make sure they are updated when needed _spellcheckSettings.valid = false; } dictBox->readSettings(project->config()); m_sourceview->setProject(project); } void KBabelView::saveSettings() { TDEConfigGroupSaver saver(_config,"Editor"); _config->writeEntry("AutoDiff",_diffEnabled); dictBox->saveSettings( _project->config() ); _catalog->savePreferences(); _config->sync(); _project->config()->sync(); KBabelSettings::writeConfig(); } void KBabelView::updateSettings() { msgstrEdit->setFont(KBabelSettings::msgFont()); msgidLabel->setFont(KBabelSettings::msgFont()); msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline() ,KBabelSettings::diffDelStrikeOut()); msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor()); if( _diffEnabled && !_catalog->currentURL().isEmpty() ) { diffShowOrig (); diff(); } msgstrEdit->setBgColor(KBabelSettings::backgroundColor()); msgidLabel->setBgColor(KBabelSettings::backgroundColor()); msgstrEdit->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor() ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor()); msgidLabel->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor() ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor()); msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline() ,KBabelSettings::diffDelStrikeOut()); msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor()); if(_fuzzyLed) { _fuzzyLed->setColor(KBabelSettings::ledColor()); } if(_untransLed) { _untransLed->setColor(KBabelSettings::ledColor()); } if(_errorLed) { _errorLed->setColor(KBabelSettings::ledColor()); } disconnect(msgstrEdit,TQT_SIGNAL(textChanged()) ,this,TQT_SLOT(autoRemoveFuzzyStatus())); if(KBabelSettings::autoUnsetFuzzy()) { connect(msgstrEdit,TQT_SIGNAL(textChanged()) ,this,TQT_SLOT(autoRemoveFuzzyStatus())); } msgstrEdit->setCleverEditing(KBabelSettings::cleverEditing()); msgstrEdit->setHighlightBg(KBabelSettings::highlightBackground()); msgidLabel->setHighlightBg(KBabelSettings::highlightBackground()); msgstrEdit->setHighlightSyntax(KBabelSettings::highlightSyntax()); msgidLabel->setHighlightSyntax(KBabelSettings::highlightSyntax()); msgstrEdit->setQuotes(KBabelSettings::enableQuotes()); msgidLabel->setQuotes(KBabelSettings::enableQuotes()); msgstrEdit->setSpacePoints(KBabelSettings::whitespacePoints()); msgidLabel->setSpacePoints(KBabelSettings::whitespacePoints()); msgstrEdit->setFont(KBabelSettings::msgFont()); msgidLabel->setFont(KBabelSettings::msgFont()); msgstrEdit->setBgColor(KBabelSettings::backgroundColor()); msgidLabel->setBgColor(KBabelSettings::backgroundColor()); msgstrEdit->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor() ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor()); msgidLabel->setHighlightColors(KBabelSettings::quotedColor(),KBabelSettings::errorColor() ,KBabelSettings::cformatColor(),KBabelSettings::accelColor(),KBabelSettings::tagColor()); msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline() ,KBabelSettings::diffDelStrikeOut()); msgidLabel->setDiffColors(KBabelSettings::diffAddColor(), KBabelSettings::diffDelColor()); // if errors should not use special color, reset the color of the text if(! KBabelSettings::autoCheckColorError()) { msgstrEdit->setCurrentColor( MsgMultiLineEdit::NormalColor); } if(_fuzzyLed) { _fuzzyLed->setColor(KBabelSettings::ledColor()); } if(_untransLed) { _untransLed->setColor(KBabelSettings::ledColor()); } if(_errorLed) { _errorLed->setColor(KBabelSettings::ledColor()); } emit ledColorChanged(KBabelSettings::ledColor()); setupAutoCheckTools(); if( _catalog->numberOfEntries() > 0 ) autoCheck(false); } void KBabelView::setupAutoCheckTools() { _autocheckTools.clear(); kdDebug () << "Autocheck tools: " << KBabelSettings::autoCheckTools().join(",") << endl; if(!KBabelSettings::autoCheckTools().isEmpty() ) { TQValueList tools = ToolAction::validationTools(); TQValueList::Iterator it; for( it=tools.begin(); it!=tools.end() ; ++it ) { if(KBabelSettings::autoCheckTools().contains((*it).service()->library()) ) { // maybe we can reuse the tools KDataTool* t = (*it).createTool(); if( t ) _autocheckTools.append( t ); } } } } void KBabelView::setRMBEditMenu(TQPopupMenu* popup) { msgidLabel->setContextMenu( popup ); msgstrEdit->setContextMenu( popup ); KContextMenuManager::insert(this,popup); } void KBabelView::setRMBSearchMenu(TQPopupMenu* popup) { dictBox->setRMBMenu(popup); } void KBabelView::saveView(TDEConfig *) { } void KBabelView::restoreView(TDEConfig *) { } void KBabelView::saveSession(TDEConfig* config) { TQString focus; int line=0,col=0; if(msgstrEdit->hasFocus()) { focus="msgstr"; msgstrEdit->getCursorPosition(&line,&col); } else if(msgidLabel->hasFocus()) { focus="msgid"; msgidLabel->getCursorPosition(&line,&col); } else if(dictBox->hasFocus()) { focus="searchbox"; } config->writeEntry("Focus",focus); config->writeEntry("CursorLine",line); config->writeEntry("CursorCol",col); config->writeEntry("Index",_currentIndex); config->writeEntry("PluralForm",_currentPos.form); config->writePathEntry("URL",currentURL().url()); config->writeEntry("AutoDiff",_diffEnabled); if( _spellcheckSettings.valid ) { TDEConfigGroupSaver (config, "Spellcheck"); config->writeEntry("NoRootAffix",_spellcheckSettings.noRootAffix); config->writeEntry("RunTogether",_spellcheckSettings.runTogether); config->writeEntry("SpellEncoding",_spellcheckSettings.spellEncoding); config->writeEntry("SpellClient",_spellcheckSettings.spellClient); config->writeEntry("SpellDictionary",_spellcheckSettings.spellDict); config->writeEntry("RememberIgnored",_spellcheckSettings.rememberIgnored); config->writePathEntry("IgnoreURL",_spellcheckSettings.ignoreURL); } saveView(config); } void KBabelView::restoreSession(TDEConfig* config) { TQString url=config->readPathEntry("URL"); if(!url.isEmpty()) { open(KURL( url ), TQString(), false,true); } _diffEnabled = config->readBoolEntry("AutoDiff", false); emit signalDiffEnabled(_diffEnabled); msgidLabel->setDiffDisplayMode( KBabelSettings::diffAddUnderline() , KBabelSettings::diffDelStrikeOut() ); msgidLabel->setDiffColors( KBabelSettings::diffAddColor() , KBabelSettings::diffDelColor() ); // go to last displayed entry DocPosition pos; pos.item=config->readNumEntry("Index"); pos.form=config->readNumEntry("PluralForm"); gotoEntry(pos); TQString focus=config->readEntry("Focus"); int line=config->readNumEntry("CursorLine"); int col=config->readNumEntry("CursorCol"); if(focus=="msgstr") { msgstrEdit->setFocus(); msgstrEdit->setCursorPosition(line,col); } else if(focus=="msgid") { msgidLabel->setFocus(); msgstrEdit->setCursorPosition(line,col); } else if(focus=="searchbox") { dictBox->setFocus(); } restoreView(config); } void KBabelView::newFileOpened(bool readOnly) { // disable editing for empty files if(_catalog->numberOfEntries() == 0) readOnly = true; if(_gotoDialog) { _gotoDialog->setMax(_catalog->numberOfEntries()); } dictBox->setDisabled(readOnly); msgstrEdit->setReadOnly(readOnly); msgstrEdit->setFocus(); TQString caption=_catalog->package(); if(readOnly) caption+=i18n(" [readonly]"); emit signalChangeCaption(caption); emit signalNewFileOpened(_catalog->currentURL()); dictBox->setEditedPackage(_catalog->packageDir()+_catalog->packageName()); dictBox->setEditedFile(_catalog->currentURL().url()); _editingDocumentation = _catalog->isGeneratedFromDocbook(); _backHistory.clear(); emit signalBackHistory(false); _forwardHistory.clear(); emit signalForwardHistory(false); DocPosition pos; pos.item=0; pos.form=0; _autoSearchTempDisabled=true; gotoEntry(pos,false); _autoSearchTempDisabled=false; emit signalDisplayed(pos); if(isActiveWindow() && KBabelSettings::autoSearch()) { startSearch(true); } } void KBabelView::open() { open(KURL()); } void KBabelView::open(const KURL& _url, const TQString & package, bool checkIfModified, bool newView) { #if KDE_IS_VERSION( 3, 5, 0) KURL url = TDEIO::NetAccess::mostLocalURL(_url,this); #else KURL url = _url; #endif url.cleanPath(); KURL cu = currentURL(); cu.cleanPath(); if(checkIfModified && !url.isEmpty() && cu==url) { KWin::activateWindow(topLevelWidget()->winId()); return; } stopSearch(); if(!checkIfModified || checkModified()) { if(url.isEmpty()) { TQString filename; if ((url = KFileDialog::getOpenURL(currentURL().url(), CatalogImportPlugin::availableImportMimeTypes().join(" ") ,this)).isEmpty()) { return; } } // deactive editor /*setEnabled(false); setCursor(KCursor::waitCursor());*/ KBabelView *v = viewForURL(url,_project->filename()); if(v && v != this) { if( newView ) { // unregister old catalog _catalog->removeView(this); if( !_catalog->hasView() ) delete _catalog; // setup new one _catalog = v->catalog(); _catalog->registerView(this); newFileOpened(_catalog->isReadOnly()); return; } else { KWin::activateWindow(v->topLevelWidget()->winId()); return; } } ConversionStatus stat=_catalog->openURL(url, package); switch(stat) { case OK: { break; } case RECOVERED_HEADER_ERROR: // Old name HEADER_ERROR { KMessageBox::sorry(this, i18n("There was an error while reading the file header. " "Please check the header." )); editHeader(); break; } case PARSE_ERROR: { KMessageBox::error(this ,i18n("Error while trying to read file:\n %1\n" "Maybe it is not a valid PO file.").arg(url.prettyURL())); break; } case NO_ENTRY_ERROR: { KMessageBox::error(this ,i18n("Error while reading the file:\n %1\n" "No entry found.").arg(url.prettyURL())); break; } case RECOVERED_PARSE_ERROR: { TQString msg=i18n( "The file contained syntax errors and an attempt has been " "made to recover it.\n" "Please check the questionable entries by using " "Go->Next error"); KMessageBox::sorry(this,msg); emitEntryState(); break; } case NO_PERMISSIONS: { KMessageBox::error(this,i18n( "You do not have permissions to read file:\n %1").arg(url.prettyURL())); break; } case NO_FILE: { KMessageBox::error(this,i18n( "You have not specified a valid file:\n %1").arg(url.prettyURL())); break; } case NO_PLUGIN: { KMessageBox::error(this,i18n( "KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(url.prettyURL())); break; } case UNSUPPORTED_TYPE: { KMessageBox::error(this,i18n( "The import plugin cannot handle this type of the file:\n %1").arg(url.prettyURL())); break; } case STOPPED: break; default: { KMessageBox::error(this,i18n( "Error while trying to open file:\n %1").arg(url.prettyURL())); break; } } /* //activate editor setEnabled(true); setCursor(KCursor::arrowCursor());*/ _autoSaveDelay = _catalog->saveSettings( ).autoSaveDelay; if ( _autoSaveDelay ) { if ( !autoSaveTimer ) { autoSaveTimer = new TQTimer( this, "AUTOSAVE TIMER" ); connect( autoSaveTimer, TQT_SIGNAL( timeout( ) ), this, TQT_SLOT( slotAutoSaveTimeout( ) ) ); } autoSaveTimer->stop( ); autoSaveTimer->start( 1000 * 60 * _autoSaveDelay ); } } } void KBabelView::revertToSaved() { if(isModified()) { // ### TODO: "Cancel" should be the default if(KMessageBox::warningContinueCancel(this ,i18n("All changes will be lost if the file " "is reverted to its last saved state.") ,i18n("Warning"),i18n("&Revert")) == KMessageBox::Cancel) { return; } } open(_catalog->currentURL(),TQString(),false); } void KBabelView::openTemplate(const KURL& openURL, const KURL& saveURL) { stopSearch(); if(checkModified()) { // deactive editor /*setEnabled(false); setCursor(KCursor::waitCursor());*/ ConversionStatus stat=_catalog->openURL(openURL,saveURL); switch(stat) { case OK: { break; } case RECOVERED_HEADER_ERROR: { // For a template, recoverable errors are disqualifying KMessageBox::sorry(this, i18n("There was an error while reading the file header of file:\n %1") .arg(openURL.prettyURL())); break; } case PARSE_ERROR: { KMessageBox::error(this ,i18n("Error while trying to read file:\n %1\n" "Maybe it is not a valid PO file.").arg(openURL.prettyURL())); break; } case NO_ENTRY_ERROR: { KMessageBox::error(this ,i18n("Error while reading the file:\n %1\n" "No entry found.").arg(openURL.prettyURL())); break; } case RECOVERED_PARSE_ERROR: { // For a template, recoverable errors are disqualifying KMessageBox::sorry(this, i18n("Minor syntax errors were found while reading file:\n %1") .arg(openURL.prettyURL())); break; } case NO_PERMISSIONS: { KMessageBox::error(this,i18n("You do not have permissions to read file:\n %1").arg(openURL.prettyURL())); break; } case NO_FILE: { KMessageBox::error(this,i18n("You have not specified a valid file:\n %1").arg(openURL.prettyURL())); break; } case NO_PLUGIN: { KMessageBox::error(this,i18n( "KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(openURL.prettyURL())); break; } case UNSUPPORTED_TYPE: { KMessageBox::error(this,i18n( "The import plugin cannot handle this type of the file:\n %1").arg(openURL.prettyURL())); break; } case STOPPED: break; default: { KMessageBox::error(this,i18n("Error while trying to open file:\n %1").arg(openURL.prettyURL())); break; } } /* //activate editor setEnabled(true); setCursor(KCursor::arrowCursor());*/ } } bool KBabelView::saveFile(bool syntaxCheck) { if(_catalog->isReadOnly()) { return saveFileAs(); } else { ConversionStatus stat=_catalog->saveFile(); int whatToDo = -1; switch(stat) { case OK: { informDictionary(); if(syntaxCheck && _catalog->saveSettings().autoSyntaxCheck ) return checkSyntax(true,false); else return true; } case NO_PERMISSIONS: { whatToDo=KMessageBox::warningContinueCancel(this, i18n("You do not have permission to write to file:\n%1\n" "Do you want to save to another file or cancel?").arg(_catalog->currentURL().prettyURL()), i18n("Error"),KStdGuiItem::save()); break; } case NO_PLUGIN: { KMessageBox::error(this,i18n( "KBabel cannot find a corresponding plugin for the MIME type of file:\n %1").arg(_catalog->currentURL().prettyURL())); break; } case UNSUPPORTED_TYPE: { KMessageBox::error(this,i18n( "The export plugin cannot handle this type of file:\n %1").arg(_catalog->currentURL().prettyURL())); break; } case BUSY: { KMessageBox::error(this,i18n( "KBabel has not finished the last operation yet.\n" "Please wait.")); break; } case STOPPED: break; default: { whatToDo=KMessageBox::warningContinueCancel(this, i18n("An error occurred while trying to write to file:\n%1\n" "Do you want to save to another file or cancel?").arg(_catalog->currentURL().prettyURL()), i18n("Error"),KStdGuiItem::save()); break; } } switch(whatToDo) { case KMessageBox::Continue: return saveFileAs(); default: return false; } } return true; } bool KBabelView::saveFileAs(KURL url, bool syntaxCheck) { bool newName=false; if(url.isEmpty()) { if((url = KFileDialog::getSaveURL(currentURL().url(), CatalogExportPlugin::availableExportMimeTypes().join(" "),this)).isEmpty()) { return false; } newName=true; } if (TDEIO::NetAccess::exists(url, false, this)) { if(KMessageBox::warningContinueCancel(this,TQString("%1").arg(i18n("The file %1 already exists. " "Do you want to overwrite it?").arg(url.prettyURL())),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Cancel) { return false; } } bool wasReadOnly=_catalog->isReadOnly(); ConversionStatus stat=_catalog->saveFileAs(url,true); // if the file was not saved sucessfully ask for saving to another file if(stat!=OK) { bool cancelLoop=false; // flag, if the saving loop should be canceled do { // select the right error message TQString message; switch(stat) { case NO_PERMISSIONS: { message=i18n("You do not have permission to write to file:\n%1\n" "Do you want to save to another file or cancel?").arg(url.prettyURL()); break; } case NO_FILE: { message=i18n("You have specified a folder:\n%1\n" "Do you want to save to another file or cancel?").arg(url.prettyURL()); break; } case NO_PLUGIN: { message=i18n("KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(url.prettyURL()); break; } case UNSUPPORTED_TYPE: { message=i18n( "The export plugin cannot handle this type of the file:\n %1").arg(url.prettyURL()); break; } default: { message=i18n("An error occurred while trying to write to file:\n%1\n" "Do you want to save to another file or cancel?").arg(url.prettyURL()); break; } } // now ask, if the user wants to save to another file or cancel switch(KMessageBox::warningContinueCancel(this,message,i18n("Error"),KStdGuiItem::save())) { // save to another file case KMessageBox::Continue: { // ask for new filename if ((url = KFileDialog::getSaveURL(currentURL().url(), CatalogExportPlugin::availableExportMimeTypes().join(" "), this)).isEmpty()) { // if no filename was given cancel all return false; } if (TDEIO::NetAccess::exists(url, false, this)) { if(KMessageBox::warningContinueCancel(this,i18n("The file %1 already exists.\n" "Do you want to overwrite it?").arg(url.prettyURL()),i18n("Warning"),i18n("&Overwrite"))==KMessageBox::Continue) { stat=_catalog->saveFileAs(url); if(stat!=OK) cancelLoop=false; else cancelLoop=true; } } else { stat=_catalog->saveFileAs(url); if(stat!=OK) cancelLoop=false; else cancelLoop=true; } break; } default: // the user do not want to save to another file return false; } } while(!cancelLoop); } if(wasReadOnly) { msgstrEdit->setReadOnly(false); } emit signalChangeCaption(_catalog->package()); if(newName) { dictBox->setEditedPackage(_catalog->packageName()); dictBox->setEditedFile(_catalog->currentURL().url()); } // after save put current edit into dictionary as well informDictionary(); if(syntaxCheck && _catalog->saveSettings().autoSyntaxCheck) return checkSyntax(true,false); else return true; } bool KBabelView::saveFileSpecial() { TQString tmpname; bool result = false; { // generate temporary name KTempFile tmp; tmp.setAutoDelete (true); tmpname = tmp.name (); } { // make sure the project is freed (pointer going out of scope) KBabel::Project::Ptr project = KBabel::ProjectManager::open (tmpname); project->setSettings( _catalog->saveSettings() ); TDEConfigDialog *_prefDialog = new TDEConfigDialog(this, "project dialog", project->settings(), KDialogBase::IconList, KDialogBase::Cancel|KDialogBase::Ok|KDialogBase::Help); _prefDialog->setCaption( i18n("Special Save Settings") ); _prefDialog->setHelp("preferences_save"); SavePreferences* _prefWidget = new SavePreferences(_prefDialog); _prefWidget->setAutoSaveVisible(false); _prefDialog->addPage(_prefWidget, i18n("title of page in preferences dialog","Save") , "filesave" , i18n("Options for File Saving")); if( _prefDialog->exec() == TQDialog::Accepted ) { SaveSettings settings = project->saveSettings(); SaveSettings originalSettings = _catalog->saveSettings(); _catalog->setSettings(settings); result = saveFileAs(); _catalog->setSettings(originalSettings); } } TQFile::remove( tmpname ); return result; } bool KBabelView::checkSyntax() { return checkSyntax(false,false); } bool KBabelView::checkSyntax(bool msgOnlyAtError,bool question) { if(currentURL().isEmpty()) return false; bool returnCode=true; TQString output; Msgfmt::Status result=_catalog->checkSyntax( output ); const TQStringList outputLines = TQStringList::split("\n",output); switch(result) { case Msgfmt::Ok: { if(!msgOnlyAtError) { KMessageBox::informationList( this, i18n("The file is syntactically correct.\n\n" "Output of \"msgfmt --statistics\":\n"), outputLines ); } returnCode=true; break; } case Msgfmt::Unsupported: { if(!msgOnlyAtError) { KMessageBox::sorry(this ,i18n("You can use gettext tools only for checking PO files.")); } returnCode=true; break; } case Msgfmt::HeaderError: case Msgfmt::SyntaxError: { TQString msg = ( result == Msgfmt::SyntaxError ) ? i18n("msgfmt detected a syntax error.\n") : i18n("msgfmt detected a header syntax error.\n"); if(question) { msg += i18n("\nDo you want to continue or cancel and edit the file again?"); msg += "\n\n"; msg += i18n("Output of \"msgfmt --statistics\":\n"); switch( KMessageBox::warningContinueCancelList( this, msg, outputLines, i18n("Warning"), KStdGuiItem::cont()) ) { case KMessageBox::Continue: returnCode=true; break; default: returnCode=false; } } else { #if KDE_IS_VERSION ( 3, 4, 0 ) msg += "\n"; msg += i18n("Please edit the file again."); msg += "\n\n"; msg += i18n("Output of \"msgfmt --statistics\":\n"); KMessageBox::errorList( this, msg, outputLines ); #else msg += i18n("Output of \"msgfmt --statistics\":\n"); msg += output; msg += "\n\n"; msg += i18n("Please edit the file again."); KMessageBox::error( this, msg ); #endif returnCode=false; } break; } case Msgfmt::NoExecutable: case Msgfmt::Error: { TQString msg = i18n("While trying to check syntax with msgfmt an error occurred.\n" "Please make sure that you have installed\n" "the GNU gettext package properly."); if(question) { msg += i18n("\nDo you want to continue or cancel and edit the file again?"); switch( KMessageBox::warningContinueCancelList( this, msg, outputLines, i18n("Warning"), KStdGuiItem::cont() )) { case KMessageBox::Continue: returnCode=true; break; default: returnCode=false; } } else { #if KDE_IS_VERSION ( 3, 4, 0 ) msg += "\n"; msg += i18n("Please edit the file again."); KMessageBox::errorList( this, msg, outputLines ); #else msg += output; msg += "\n\n"; msg += i18n("Please edit the file again."); KMessageBox::error( this, msg ); #endif returnCode=false; } break; } } emitEntryState(); return returnCode; } bool KBabelView::checkAll() { if(currentURL().isEmpty()) return false; bool a,badresult=false; TQValueList tools = ToolAction::validationTools(); TQValueList::ConstIterator entry = tools.begin(); for( ; entry != tools.end(); ++entry ) { KDataTool* tool = (*entry).createTool(); if( tool ) { a = _catalog->checkUsingTool(tool,entry==tools.begin()); badresult = badresult || !a; delete tool; } } TQString output; a = (_catalog->checkSyntax(output, false)!=Msgfmt::Ok); badresult=badresult||a; emitEntryState(); if(!badresult) { KMessageBox::information(this ,i18n("No mismatch has been found.") , i18n("Title in Dialog: Perform all checks","Perform All Checks")); } else { int index=0; DocPosition pos; if(!_catalog->hasError(0,pos)) index = _catalog->nextError(0, pos); if(index>=0) { gotoEntry(pos); } KMessageBox::error(this ,i18n("Some mismatches have been found.\n" "Please check the questionable entries by using " "Go->Next error") , i18n("Title in Dialog: Perform all checks","Perform All Checks")); } return !badresult; } bool KBabelView::checkModified() { bool flag=true; if(isModified()) { switch(KMessageBox::warningYesNoCancel(this, i18n("The document contains unsaved changes.\n" "Do you want to save your changes or discard them?"),i18n("Warning"), KStdGuiItem::save(),KStdGuiItem::discard())) { case KMessageBox::Yes: { flag = saveFile(false); if(flag && _catalog->saveSettings().autoSyntaxCheck) { flag = checkSyntax(true,true); } break; } case KMessageBox::No: flag = true; break; default: // canceled flag = false; break; } } return flag; } void KBabelView::updateEditor(int form, bool delay) { msgstrEdit->blockSignals(true); if(KBabelSettings::autoUnsetFuzzy() && !msgstrEdit->isModified()) { disconnect(msgstrEdit,TQT_SIGNAL(textChanged()),this,TQT_SLOT(autoRemoveFuzzyStatus())); } msgidLabel->setText(_catalog->msgid(_currentIndex), _catalog->msgctxt(_currentIndex)); msgidLabel->repaint(); msgstrEdit->setText(_catalog->msgstr(_currentIndex)); msgstrEdit->showForm( form ); msgstrEdit->repaint(); m_cataloglistview->setSelectedItem(_currentIndex); if(KBabelSettings::autoUnsetFuzzy() && _catalog->isFuzzy(_currentIndex)) { connect(msgstrEdit,TQT_SIGNAL(textChanged()),this,TQT_SLOT(autoRemoveFuzzyStatus())); } msgstrEdit->blockSignals(false); autoCheck(false); // no need to display diff if this message wasn't translated if(_diffEnabled && !(_catalog->isUntranslated(_currentIndex))) { autoDiff(); } if(isActiveWindow() && KBabelSettings::autoSearch() && !_autoSearchTempDisabled) { if (delay) { TQTimer::singleShot(0, this, TQT_SLOT (startSearch())); } else { startSearch(); } } msgstrEdit->setFocus(); msgstrEdit->setModified(false); } void KBabelView::undo() { if(!_catalog->isUndoAvailable()) return; int newIndex=_catalog->undo(); if(newIndex != (int)_currentIndex) { DocPosition pos; pos.item=newIndex; pos.form=0; gotoEntry(pos); } } void KBabelView::redo() { if(!_catalog->isRedoAvailable()) return; int newIndex=_catalog->redo(); if(newIndex != (int)_currentIndex) { DocPosition pos; pos.item=newIndex; pos.form=0; gotoEntry(pos); } } void KBabelView::textCut() { if(msgstrEdit->hasFocus()) { msgstrEdit->cut(); } } void KBabelView::textCopy() { if(msgstrEdit->hasSelectedText()) { msgstrEdit->copy(); } else if(msgidLabel->hasSelectedText()) { msgidLabel->copy(); } else if(dictBox->isVisible() && dictBox->hasSelectedText()) { dictBox->copy(); } } void KBabelView::textPaste() { msgstrEdit->paste(); } bool KBabelView::findNext() { if(!_findDialog) return false; if( !_redirectedBackSearch && _findDialog->findOpts().backwards ) { _redirectedBackSearch = true; bool res = findPrev(); _redirectedBackSearch = false; return res; } DocPosition pos; pos.item=_currentIndex; pos.form=0; if( m_commentview->hasFocus() ) { pos.part = Comment; pos.offset = m_commentview->currentIndex(); } else if(msgidLabel->hasFocus() ) { pos.part = Msgid; pos.offset = msgidLabel->currentIndex(); } else { pos.part = Msgstr; pos.offset = msgstrEdit->currentIndex(); pos.form = msgstrEdit->currentForm(); } _findStartPos=pos; _findBreakAtEnd=false; return findNext_internal(pos); } bool KBabelView::findPrev() { if(!_findDialog) return false; if( !_redirectedBackSearch && _findDialog->findOpts().backwards ) { _redirectedBackSearch = true; bool res = findNext(); _redirectedBackSearch = false; return res; } DocPosition pos; pos.item=_currentIndex; if( m_commentview->hasFocus()) { pos.part = Comment; pos.offset = m_commentview->currentIndex(); } else if(msgidLabel->hasFocus() ) { pos.part = Msgid; pos.offset = msgidLabel->currentIndex(); } else { pos.part = Msgstr; pos.offset = msgstrEdit->currentIndex(); pos.form = msgstrEdit->currentForm(); } _findStartPos=pos; _findBreakAtEnd=false; return findPrev_internal(pos); } bool KBabelView::findNext_internal(DocPosition& pos, bool forReplace, bool gui) { FindOptions opts; if(forReplace) opts = _replaceDialog->replaceOpts(); else opts = _findDialog->findOpts(); int len=0; deselectAll(); bool success=false; if( !opts.askFile ) // for find in all files ignore return to the beginning if(!_findBreakAtEnd && !(success=_catalog->findNext(&opts,pos,len))) { int r; if(forReplace) { _replaceWasAtEnd=true; _findBreakAtEnd=true; if(gui) { r = KMessageBox::questionYesNo(this, i18n("%n replacement made.
End of document reached.
Continue from the beginning?
", "%n replacements made.
End of document reached.
Continue from the beginning?
", _replacesTotal), TQString(), KStdGuiItem::cont(), KStdGuiItem::cancel()); } else { r = KMessageBox::Yes; } } else { r = KMessageBox::questionYesNo(this,i18n("End of document reached.\n" "Continue from the beginning?"), TQString(), KStdGuiItem::cont(), KStdGuiItem::cancel()); } if(r == KMessageBox::Yes) { if(opts.inMsgid && !forReplace) pos.part = Msgid; else if(opts.inComment) pos.part = Comment; else pos.part = Msgstr; pos.item = 0; pos.offset = 0; pos.form = 0; } else return false; } if(!success && !_catalog->findNext(&opts,pos,len)) { // reached end the second time if( !opts.askFile ) { if(forReplace) { KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal)); } else { KMessageBox::information(this,i18n("Search string not found.")); } return false; } else { if( opts.askForNextFile ) { int r = KMessageBox::questionYesNo(this,i18n("End of document reached.\n" "Continue in the next file?"), TQString(), KStdGuiItem::cont(), KStdGuiItem::cancel()); if( r != KMessageBox::Yes ) return false; } if( isModified() && !opts.askForSave ) saveFile(); DCOPClient *client = kapp->dcopClient(); TQByteArray data, replyData; TQCString replyType; bool morefiles = false; // more files to lookup in if( !client->call( _fileSource,"CatalogManagerIFace", "findNextFile()", data, replyType, replyData) ) kdDebug(KBABEL) << "unable to call, reply type is " << replyType << endl; else if( replyType == "TQCString" ) { TQDataStream rep( replyData, IO_ReadOnly); TQCString f; rep >> f; TQString foundFile = TQString::fromUtf8(f); morefiles = !f.isEmpty() && !f.isNull(); if( morefiles ) { emit open( KURL(foundFile) ); pos.item = 0; pos.part = Msgid; pos.offset = 0; _catalog->findNext(&opts,pos,len); } else { if( f.isNull() ) // is there possibility to get a new file? { // no, this is the end finally if( forReplace ) KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal)); else KMessageBox::information(this,i18n("Search string not found.")); return false; } else { // there can be a new file, let user know showTryLaterMessageBox(); if( forReplace ) return true; // let replace dialog stay else return false; } } } else { KMessageBox::error(this,i18n("DCOP communication with Catalog Manager failed.")); return false; } } } if(gui) { if( _currentIndex != pos.item || (pos.part==Msgstr && msgstrEdit->currentForm() != pos.form) ) { gotoEntry(pos); } int line,col,endline,endcol; switch(pos.part) { case Msgid: msgidLabel->selectAll(false); msgidLabel->setFocus(); msgidLabel->offset2Pos(pos.offset,line,col); msgidLabel->offset2Pos(pos.offset+len,endline,endcol); msgidLabel->setSelection(line,col,endline,endcol); msgidLabel->setCursorPosition(endline,endcol); _lastFoundString=msgidLabel->selectedText(); break; case Msgstr: msgstrEdit->selectAll(false); msgstrEdit->setFocus(); msgstrEdit->offset2Pos(pos.offset,line,col); msgstrEdit->offset2Pos(pos.offset+len,endline,endcol); msgstrEdit->setSelection(line,col,endline,endcol); msgstrEdit->setCursorPosition(endline,endcol); _lastFoundString=msgstrEdit->selectedText(); break; case Comment: { m_mainwindow->makeWidgetDockVisible (m_commentview); _lastFoundString= m_commentview->selectText (pos.offset, pos.offset+len); break; } case UndefPart: break; } } if(forReplace) { kdDebug(KBABEL) << "This is forReplace" << endl; _replaceLen=len; bool finished=false; // check if we had reached the beginning before and now are before our starting position if(_replaceWasAtEnd) { if( pos.item > _findStartPos.item ) { finished=true; } else if(pos.item == _findStartPos.item) { if(pos.part==Msgstr && !opts.inComment && pos.offset >= _findStartPos.offset+_replaceExtraOffset) finished=true; else if(pos.part==Comment && pos.offset >= _findStartPos.offset+_replaceExtraOffset) finished=true; } } if(finished) { KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal)); return false; } } return true; } bool KBabelView::findPrev_internal(DocPosition& pos, bool forReplace, bool gui) { FindOptions opts; if(forReplace) opts = _replaceDialog->replaceOpts(); else opts = _findDialog->findOpts(); int len=0; deselectAll(); bool success=false; if(!_findBreakAtEnd && !(success=_catalog->findPrev(&opts,pos,len))) { int r; if(forReplace) { _replaceWasAtEnd=true; _findBreakAtEnd=true; if(gui) { r = KMessageBox::questionYesNo(this, i18n("%n replacement made.
Beginning of document reached.
Continue from the end?
", "%n replacements made.
Beginning of document reached.
Continue from the end?
", _replacesTotal),TQString(), KStdGuiItem::cont(), KStdGuiItem::cancel()); } else { r = KMessageBox::Yes; } } else { r = KMessageBox::questionYesNo(this,i18n("Beginning of document reached.\n" "Continue from the end?"), TQString(), KStdGuiItem::cont(), KStdGuiItem::cancel()); } if(r == KMessageBox::Yes) { pos.item = _catalog->numberOfEntries()-1; if(opts.inComment) { pos.part = Comment; pos.offset = _catalog->comment(pos.item).length(); } else if(opts.inMsgstr || forReplace) { pos.part = Msgstr; if( _catalog->msgstr(pos.item).empty() ) pos.offset=0; else pos.offset = _catalog->msgstr(pos.item).last().length(); pos.form = _catalog->msgstr(pos.item).count()-1; } else { pos.part = Msgid; //FIXME: we should search in msgid plural forms pos.offset = _catalog->msgid(pos.item).first().length(); } } else return false; } // start at the end if(!success && !_catalog->findPrev(&opts,pos,len)) { if(forReplace) { KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal)); } else { KMessageBox::information(this,i18n("Search string not found.")); } return false; } else if(gui) { if(_currentIndex != pos.item || (pos.part==Msgstr && msgstrEdit->currentForm() != pos.form) ) gotoEntry(pos); int line,col,endline,endcol; switch(pos.part) { case Msgid: msgidLabel->selectAll(false); msgidLabel->setFocus(); msgidLabel->offset2Pos(pos.offset+len,line,col); msgidLabel->offset2Pos(pos.offset,endline,endcol); msgidLabel->setSelection(line,col,endline,endcol); msgidLabel->setCursorPosition(endline,endcol); _lastFoundString=msgidLabel->selectedText(); break; case Msgstr: msgstrEdit->selectAll(false); msgstrEdit->setFocus(); msgstrEdit->offset2Pos(pos.offset+len,line,col); msgstrEdit->offset2Pos(pos.offset,endline,endcol); msgstrEdit->setSelection(line,col,endline,endcol); msgstrEdit->setCursorPosition(endline,endcol); _lastFoundString=msgstrEdit->selectedText(); break; case Comment: m_mainwindow->makeWidgetDockVisible (m_commentview); _lastFoundString=m_commentview-> selectText(pos.offset, pos.offset+len); break; case UndefPart: break; } } if(forReplace) { _replaceLen=len; bool finished=false; // check if we had reached the beginning before and now are before our starting position if(_replaceWasAtEnd) { if( pos.item < _findStartPos.item ) { finished=true; } else if(pos.item == _findStartPos.item) { if(pos.part==Comment && !opts.inMsgstr && pos.offset < _findStartPos.offset+_replaceExtraOffset) finished=true; else if(pos.part==Msgstr && pos.offset < _findStartPos.offset+_replaceExtraOffset) finished=true; } } if(finished) { KMessageBox::information(this,i18n("%n replacement made","%n replacements made",_replacesTotal)); return false; } } return true; } void KBabelView::find() { Part hadFocus; if(msgidLabel->hasFocus()) hadFocus=Msgid; else if(m_commentview->hasFocus()) hadFocus=Comment; else hadFocus=Msgstr; if( !_findDialog ) { _findDialog = new FindDialog(false,this); } TQString marked; if(msgstrEdit->hasFocus()) { marked=msgstrEdit->selectedText(); msgstrEdit->selectAll(false); } else if(m_commentview->hasFocus()) { marked=m_commentview->selectedText(); m_commentview->textDeselectAll(); } else if(msgidLabel->hasFocus()) { marked=msgidLabel->selectedText(); msgidLabel->selectAll(false); } if(marked==_lastFoundString) marked=""; if( _findDialog->exec(marked) == TQDialog::Accepted ) { DocPosition pos; FindOptions opts=_findDialog->findOpts(); opts.askFile = false; // do not search in more files _findDialog->setFindOpts(opts); if(opts.fromCursor) { _findBreakAtEnd=false; pos.item=_currentIndex; if(hadFocus == Comment && opts.inComment) { pos.part = Comment; pos.offset = m_commentview->currentIndex(); } else if( hadFocus == Msgid && opts.inMsgid) { pos.part = Msgid; pos.offset = msgidLabel->currentIndex(); } else { pos.part = Msgstr; pos.offset = msgstrEdit->currentIndex(); } } else { _findBreakAtEnd=true; if(opts.backwards) { pos.item=_catalog->numberOfEntries(); if(opts.inComment) pos.part=Comment; else if(opts.inMsgstr) pos.part=Msgstr; else pos.part=Msgid; pos.offset=1000; // set to a high number } else { pos.item=0; if(opts.inMsgid) pos.part=Msgid; else if(opts.inMsgstr) pos.part=Msgstr; else pos.part=Comment; pos.offset=0; } } if( opts.backwards ) { _findStartPos=pos; findPrev_internal(pos); } else { _findStartPos=pos; findNext_internal(pos); } } } void KBabelView::replace() { _replacesTotal=0; _replaceLen=0; _replaceWasAtEnd=false; _replaceExtraOffset=0; Part hadFocus; if(msgidLabel->hasFocus()) hadFocus=Msgid; else if(m_commentview->hasFocus()) hadFocus=Comment; else hadFocus=Msgstr; if( !_replaceDialog ) { _replaceDialog = new FindDialog(true,this); } TQString marked; if(msgstrEdit->hasFocus()) { marked=msgstrEdit->selectedText(); msgstrEdit->selectAll(false); } else if(m_commentview->hasFocus()) { marked=m_commentview->selectedText(); m_commentview->textDeselectAll(); } else if(msgidLabel->hasFocus()) { marked=msgidLabel->selectedText(); msgidLabel->selectAll(false); } if(marked==_lastFoundString) marked=""; if( _replaceDialog->exec(marked) == TQDialog::Accepted ) { KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts(); if(opts.fromCursor) { _findBreakAtEnd=false; _replacePos.item=_currentIndex; if(hadFocus==Comment && opts.inComment) { _replacePos.part = Comment; _replacePos.offset = m_commentview->currentIndex(); } else { _replacePos.part = Msgstr; _replacePos.offset = msgstrEdit->currentIndex(); } } else { _findBreakAtEnd=true; if(opts.backwards) { _replacePos.item=_catalog->numberOfEntries(); if(opts.inComment) _replacePos.part=Comment; else _replacePos.part=Msgstr; _replacePos.offset=1000; // set to a high number } else { _replacePos.item=0; if(opts.inMsgstr) _replacePos.part=Msgstr; else _replacePos.part=Comment; _replacePos.offset=0; } } // do not ask for next file from catalog manager opts.askFile = false; _replaceDialog->setReplaceOpts(opts); bool success; if( opts.backwards ) { _findStartPos=_replacePos; success = findPrev_internal(_replacePos,true,opts.ask); } else { _findStartPos=_replacePos; success = findNext_internal(_replacePos,true,opts.ask); } if(success) { if(!_replaceAskDialog) { _replaceAskDialog = new ReplaceDialog(this); connect(_replaceAskDialog,TQT_SIGNAL(replace()),this,TQT_SLOT(replaceNext())); connect(_replaceAskDialog,TQT_SIGNAL(next()),this,TQT_SLOT(findNextReplace())); connect(_replaceAskDialog,TQT_SIGNAL(replaceAll()),this,TQT_SLOT(replaceAll())); } if(opts.ask) { _replaceAskDialog->exec(); } else replaceAll(); } } } void KBabelView::replaceNext() { _replacesTotal++; KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts(); // calculate the diff to original offset due to replacing a string // in the starting item if(_findStartPos.item == _replacePos.item ) { if((opts.backwards && !_replaceWasAtEnd) || (!opts.backwards && _replaceWasAtEnd)) { _replaceExtraOffset += (opts.replaceStr.length()-_replaceLen); } } Part part; uint form = 0; TQString str; if(_replacePos.part==Msgstr) { part=Msgstr; str = _catalog->msgstr(_replacePos.item).first() .mid(_replacePos.offset,_replaceLen); form=_replacePos.form; } else if(_replacePos.part==Comment) { part = Comment; str = _catalog->comment(_replacePos.item) .mid(_replacePos.offset,_replaceLen); } else { kdWarning() << "msgid can not be changed in KBabelView::replaceNext()" << endl; return; } _catalog->applyBeginCommand( _replacePos.item,part,this); DelTextCmd* delCmd = new DelTextCmd(_replacePos.offset,str,form); delCmd->setPart(part); delCmd->setIndex(_replacePos.item); _catalog->applyEditCommand(delCmd,0); InsTextCmd* insCmd = new InsTextCmd(_replacePos.offset,opts.replaceStr,form); insCmd->setPart(part); insCmd->setIndex(_replacePos.item); _catalog->applyEditCommand(insCmd,0); _catalog->applyEndCommand( _replacePos.item,part,this); // now find next string bool success; if( opts.backwards ) { success = findPrev_internal(_replacePos,true); } else { _replacePos.offset+=opts.replaceStr.length(); success = findNext_internal(_replacePos,true); } if(!success) { if(_replaceAskDialog && _replaceAskDialog->isVisible()) _replaceAskDialog->hide(); } } void KBabelView::replaceAll() { if(_replaceAskDialog && _replaceAskDialog->isVisible()) _replaceAskDialog->hide(); KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts(); bool success=true; _catalog->applyBeginCommand(_replacePos.item,Msgstr,this); while(success) { kapp->processEvents(100); _replacesTotal++; // calculate the diff to original offset due to replacing a string // in the starting item if(_findStartPos.item == _replacePos.item ) { if((opts.backwards && !_replaceWasAtEnd) || (!opts.backwards && _replaceWasAtEnd)) { _replaceExtraOffset += (opts.replaceStr.length()-_replaceLen); } } Part part; uint form=0; TQString str; if(_replacePos.part==Msgstr) { part=Msgstr; form=_replacePos.form; str = _catalog->msgstr(_replacePos.item).first().mid(_replacePos.offset,_replaceLen); } else if(_replacePos.part==Comment) { part = Comment; str = _catalog->comment(_replacePos.item).mid(_replacePos.offset,_replaceLen); } else { kdWarning() << "msgid can not be changed in KBabelView::replaceNext()" << endl; return; } DelTextCmd* delCmd = new DelTextCmd(_replacePos.offset,str,form); delCmd->setPart(part); delCmd->setIndex(_replacePos.item); _catalog->applyEditCommand(delCmd,0); InsTextCmd* insCmd = new InsTextCmd(_replacePos.offset,opts.replaceStr,form); insCmd->setPart(part); insCmd->setIndex(_replacePos.item); _catalog->applyEditCommand(insCmd,0); // now find next string if( opts.backwards ) { success = findPrev_internal(_replacePos,true,false); } else { _replacePos.offset+=opts.replaceStr.length(); success = findNext_internal(_replacePos,true,false); } } _catalog->applyEndCommand(_replacePos.item,Msgstr,this); } void KBabelView::findNextReplace() { bool success; KBabel::ReplaceOptions opts=_replaceDialog->replaceOpts(); if( opts.backwards ) { success = findPrev_internal(_replacePos,true); } else { _replacePos.offset++; success = findNext_internal(_replacePos,true); } if(!success) { if(_replaceAskDialog && _replaceAskDialog->isVisible()) _replaceAskDialog->hide(); } } void KBabelView::findInFile(TQCString fileSource, FindOptions options) { DocPosition pos; pos.item=0; pos.part=Msgid; pos.offset=0; _findStartPos=pos; _findBreakAtEnd=true; // do not start from the beginning at the end _showTryLaterBox=true; // delete dontDisplayAgain from configuration TDEConfig* config = TDEGlobal::config(); TDEConfigGroupSaver saver(config,"Notification Messages"); config->writeEntry("waitForNextFile",true); // set that there can be more files options.askFile = true; _fileSource = fileSource; if( !_findDialog ) _findDialog = new FindDialog(false,this); _findDialog->setFindOpts(options); findNext_internal(pos); } void KBabelView::replaceInFile(TQCString fileSource, KBabel::ReplaceOptions options) { _replacePos.item=0; _replacePos.part=Msgid; _replacePos.offset=0; _replacesTotal=0; _replaceLen=0; _replaceWasAtEnd=false; _replaceExtraOffset=0; _findBreakAtEnd=true; _showTryLaterBox=true; // delete dontDisplayAgain from configuration TDEConfig* config = TDEGlobal::config(); TDEConfigGroupSaver saver(config,"Notification Messages"); config->writeEntry("waitForNextFile",true); // set that there can be more files options.askFile = true; _fileSource = fileSource; if( !_replaceDialog ) _replaceDialog = new FindDialog(true,this); _replaceDialog->setReplaceOpts(options); bool success; success = findNext_internal(_replacePos,true); if(!success) kdDebug(KBABEL) << "Not found in file where catalog manager told us. This should not happen" << endl; else { if(!_replaceAskDialog) { _replaceAskDialog = new ReplaceDialog(this); connect(_replaceAskDialog,TQT_SIGNAL(replace()),this,TQT_SLOT(replaceNext())); connect(_replaceAskDialog,TQT_SIGNAL(next()),this,TQT_SLOT(findNextReplace())); connect(_replaceAskDialog,TQT_SIGNAL(replaceAll()),this,TQT_SLOT(replaceAll())); } if(options.ask) { _replaceAskDialog->exec(); } else replaceAll(); } } void KBabelView::deselectAll() { msgstrEdit->selectAll(false); // FIXME: commentEdit->selectAll(false); msgidLabel->selectAll(false); } void KBabelView::selectAll() { if(msgstrEdit->hasFocus()) { msgstrEdit->selectAll(); } // FIXME: else if(commentEdit->hasFocus()) // FIXME: { // FIXME: commentEdit->selectAll(); // FIXME: } else if(msgidLabel->hasFocus()) { msgidLabel->selectAll(); } } void KBabelView::clear() { if(msgstrEdit->hasFocus()) { msgstrEdit->clear(); } // FIXME: else if(commentEdit->hasFocus()) // FIXME: { // FIXME: commentEdit->clear(); // FIXME: } } void KBabelView::msgid2msgstr() { // FIXME: should care about plural forms TQString text = _catalog->msgid(_currentIndex).first(); // this is KDE specific: if(text.find("_: NAME OF TRANSLATORS\\n")==0) { text=_catalog->identitySettings().authorLocalizedName; } else if(text.find("_: EMAIL OF TRANSLATORS\\n")==0) { text=_catalog->identitySettings().authorEmail; } else if(_catalog->isGeneratedFromDocbook() && text.find("ROLES_OF_TRANSLATORS")==0) { text="\n" "\n" "

"+_catalog->identitySettings().authorEmail+"
\n" ""; } else if(_catalog->isGeneratedFromDocbook() && text.find("CREDIT_FOR_TRANSLATORS")==0) { text=""+_catalog->identitySettings().authorLocalizedName+"\n"+ ""+_catalog->identitySettings().authorEmail+""; } else if(text.contains(_catalog->miscSettings().singularPlural)) { text.replace(_catalog->miscSettings().singularPlural,""); } // end of KDE specific part TQRegExp reg=_catalog->miscSettings().contextInfo; if(text.contains(reg)) { text.replace(reg,""); } modifyMsgstrText(0,text,true); msgstrEdit->setCursorPosition(0,0); } void KBabelView::search2msgstr() { modifyMsgstrText(0,dictBox->translation(),true); msgstrEdit->setCursorPosition(0,0); } void KBabelView::gotoFirst() { DocPosition pos; pos.item=0; pos.form=0; gotoEntry(pos); } void KBabelView::gotoLast() { DocPosition pos; pos.item=_catalog->numberOfEntries()-1; pos.form=0; gotoEntry(pos); } void KBabelView::gotoNext() { DocPosition pos; pos.item=_currentIndex; pos.form=msgstrEdit->currentForm(); if( (int)pos.form+1 < _catalog->defaultNumberOfPluralForms() && _catalog->pluralForm(_currentIndex)==Gettext ) { pos.form++; } else { // check, if we are already showing the last entry if(_currentIndex>=_catalog->numberOfEntries()-1) { return; } else { pos.item++; pos.form=0; } } gotoEntry(pos); } void KBabelView::gotoPrev() { DocPosition pos; pos.item=_currentIndex; pos.form=msgstrEdit->currentForm(); // check, if we are already showing the first entry if(_currentIndex==0 && pos.form==0) { return; } else { if( pos.form==0 ) { pos.item--; if( _catalog->pluralForm(pos.item)==Gettext ) pos.form=_catalog->defaultNumberOfPluralForms()-1; } else pos.form--; gotoEntry(pos); } } void KBabelView::gotoEntry() { if( !_gotoDialog ) { _gotoDialog = new GotoDialog(_catalog->numberOfEntries(),this); } _gotoDialog->exec(); if( _gotoDialog->result() ) { int number=_gotoDialog->number()-1; int max=_catalog->numberOfEntries()-1; if(number>max) number=max; else if(number<0) number=0; DocPosition pos; pos.item=number; pos.form=0; gotoEntry(pos); } } void KBabelView::gotoNextFuzzy() { DocPosition pos; if( _catalog->nextFuzzy(_currentIndex,pos) >= 0 ) { gotoEntry(pos); } } void KBabelView::gotoPrevFuzzy() { DocPosition pos; if( _catalog->prevFuzzy(_currentIndex,pos) >= 0 ) { gotoEntry(pos); } } void KBabelView::gotoNextError() { DocPosition pos; if(_catalog->nextError(_currentIndex,pos) >= 0 ) { _dontBeep=true; gotoEntry(pos); _dontBeep=false; } } void KBabelView::gotoPrevError() { DocPosition pos; if(_catalog->prevError(_currentIndex,pos) >= 0) { _dontBeep=true; gotoEntry(pos); _dontBeep=false; } } void KBabelView::gotoNextFuzzyOrUntrans() { DocPosition fuzzyPos,untransPos; int fuzzyIndex=_catalog->nextFuzzy(_currentIndex,fuzzyPos); int untransIndex=_catalog->nextUntranslated(_currentIndex,untransPos); if(fuzzyIndex<0 && untransIndex<0 ) return; if(fuzzyIndex<0) { gotoEntry(untransPos); return; } if(untransIndex<0) { gotoEntry(fuzzyPos); return; } if( fuzzyIndexprevFuzzy(_currentIndex,fuzzyPos); int untransIndex=_catalog->prevUntranslated(_currentIndex,untransPos); if(fuzzyIndex<0 && untransIndex<0 ) return; if(fuzzyIndex<0) { gotoEntry(untransPos); return; } if(untransIndex<0) { gotoEntry(fuzzyPos); return; } if( fuzzyIndex>untransIndex || (fuzzyIndex==untransIndex && fuzzyPos.form>untransPos.form)) { gotoEntry(fuzzyPos); } else { gotoEntry(untransPos); } } void KBabelView::gotoNextUntranslated() { DocPosition pos; if(_catalog->nextUntranslated(_currentIndex,pos)>=0) { gotoEntry(pos); } } void KBabelView::gotoPrevUntranslated() { DocPosition pos; if(_catalog->prevUntranslated(_currentIndex,pos)>=0) { gotoEntry(pos); } } void KBabelView::gotoEntry(const DocPosition& pos, bool updateHistory) { // clear up statusbar emit signalChangeStatusbar(""); if(updateHistory) { if(_forwardHistory.count()>0) { emit signalForwardHistory(false); } _forwardHistory.clear(); _backHistory.append(_currentIndex); if(_backHistory.count()==1) { emit signalBackHistory(true); } else if(_backHistory.count()>MAX_HISTORY) { _backHistory.remove(_backHistory.begin()); } } informDictionary(); _currentPos=pos; _currentIndex=pos.item; updateEditor(pos.form,true); emitEntryState(); updateTags(); updateArgs(); } void KBabelView::msgstrPluralFormChanged ( uint index ) { _currentPos.form = index; emit signalDisplayed (_currentPos); } void KBabelView::backHistory() { if(_backHistory.isEmpty()) { kdDebug(KBABEL) << "KBabelView::backHistory called without any history." << endl; return; } _forwardHistory.append(_currentIndex); uint index=_backHistory.last(); _backHistory.remove(_backHistory.fromLast()); DocPosition pos; pos.item=index; pos.form=0; gotoEntry(pos,false); if(_backHistory.count()==0) { emit signalBackHistory(false); } if(_forwardHistory.count()==1) { emit signalForwardHistory(true); } } void KBabelView::forwardHistory() { if(_forwardHistory.isEmpty()) { kdDebug(KBABEL) << "KBabelView::forwardHistory called without any history." << endl; return; } _backHistory.append(_currentIndex); uint index=_forwardHistory.last(); _forwardHistory.remove(_forwardHistory.fromLast()); DocPosition pos; pos.item=index; pos.form=0; gotoEntry(pos,false); if(_forwardHistory.count()==0) { emit signalForwardHistory(false); } if(_backHistory.count()==1) { emit signalBackHistory(true); } } void KBabelView::removeFuzzyStatus() { bool newState = !_catalog->isFuzzy(_currentIndex); _catalog->setFuzzy(_currentIndex,newState); // ensure we will update the translation memory as needed msgstrEdit->setModified (true); emit signalFuzzyDisplayed(newState); } void KBabelView::editHeader() { HeaderEditor* editor=_catalog->headerEditor(); int editHeight=editor->height(); int editWidth=editor->width(); int w=width(); int h=height(); int x=w/2-editWidth/2; int y=h/2-editHeight/2; editor->move(mapToGlobal(TQPoint(x,y))); editor->show(); editor->raise(); } void KBabelView::stopSearch() { dictBox->stopSearch(); } void KBabelView::startSearch() { startSearch(false); } void KBabelView::startSearch(bool delay) { TQString msg = _catalog->msgid(_currentIndex,true).first(); TQRegExp reg=_catalog->miscSettings().contextInfo; if(msg.contains(reg)) { msg.replace(reg,""); } dictBox->setActiveModule(KBabelSettings::defaultModule()); if(delay) { dictBox->startDelayedSearch(msg); } else { dictBox->startSearch(msg); } } void KBabelView::startSearch(const TQString module) { // FIXME: should care about plural forms TQString msg = _catalog->msgid(_currentIndex,true).first(); TQRegExp reg=_catalog->miscSettings().contextInfo; if(msg.contains(reg)) { msg.replace(reg,""); } dictBox->setActiveModule(module); dictBox->startSearch(msg); } void KBabelView::startSelectionSearch() { startSelectionSearch(KBabelSettings::defaultModule()); } void KBabelView::startSelectionSearch(const TQString module) { dictBox->setActiveModule(module); if(msgidLabel->hasSelectedText()) { // TODO: should we care about end of lines? dictBox->startSearch(msgidLabel->selectedText()); } else if(msgstrEdit->hasSelectedText()) { dictBox->startTranslationSearch(msgstrEdit->selectedText()); } else { // should care about plural forms TQString msg = _catalog->msgid(_currentIndex,true).first(); TQRegExp reg=_catalog->miscSettings().contextInfo; if(msg.contains(reg)) { msg.replace(reg,""); } dictBox->startSearch(msg); } } void KBabelView::emitEntryState() { // flag, so I don't have to always change the color of the text static bool isError=false; emit signalDisplayed(_currentPos); emit signalFirstDisplayed(_currentIndex==0, msgstrEdit->currentForm()==0); emit signalLastDisplayed((unsigned)(_currentIndex+1)==_catalog->numberOfEntries(), (signed)(msgstrEdit->currentForm())==_catalog->numberOfPluralForms(_currentIndex)-1); bool fuzzy=_catalog->isFuzzy(_currentIndex); bool untrans=_catalog->isUntranslated(_currentIndex); emit signalFuzzyDisplayed(fuzzy); emit signalUntranslatedDisplayed(untrans); emit signalFuzzyAfterwards(_catalog->hasFuzzyAfterwards(_currentIndex)); emit signalUntranslatedAfterwards(_catalog->hasUntranslatedAfterwards(_currentIndex)); emit signalFuzzyInFront(_catalog->hasFuzzyInFront(_currentIndex)); emit signalUntranslatedInFront(_catalog->hasUntranslatedInFront(_currentIndex)); emit signalErrorAfterwards(_catalog->hasErrorAfterwards(_currentIndex)); emit signalErrorInFront(_catalog->hasErrorInFront(_currentIndex)); DocPosition pos; if( _catalog->hasError(_currentIndex,pos) != isError ) { isError = !isError; emit signalFaultyDisplayed(isError); if(isError) { TQPalette palette=msgstrEdit->palette(); palette.setColor( TQColorGroup::Text, red ); if( _catalog->itemStatus(_currentIndex).contains("syntax error")) { msgstrEdit->setCurrentColor( MsgMultiLineEdit::ErrorColor ); } else if( !_catalog->itemStatus(_currentIndex).isEmpty() && KBabelSettings::autoCheckColorError()) { msgstrEdit->setCurrentColor( MsgMultiLineEdit::ErrorColor ); } } else { msgstrEdit->setCurrentColor( MsgMultiLineEdit::NormalColor ); } } } void KBabelView::checkFuzzies() { emit signalFuzzyAfterwards(_catalog->hasFuzzyAfterwards(_currentIndex)); emit signalFuzzyInFront(_catalog->hasFuzzyInFront(_currentIndex)); } void KBabelView::checkUntranslated() { emit signalUntranslatedAfterwards(_catalog->hasUntranslatedAfterwards(_currentIndex)); emit signalUntranslatedInFront(_catalog->hasUntranslatedInFront(_currentIndex)); } void KBabelView::autoRemoveFuzzyStatus() { // only at first text change remove fuzzy status disconnect(msgstrEdit,TQT_SIGNAL(textChanged()),this,TQT_SLOT(autoRemoveFuzzyStatus())); //removeFuzzyStatus(); } void KBabelView::toggleFuzzyLed(bool on) { if(!_fuzzyLed) return; if(on) { if(_fuzzyLed->state()==KLed::Off) { _fuzzyLed->on(); } } else { if(_fuzzyLed->state()==KLed::On) _fuzzyLed->off(); } } void KBabelView::toggleUntransLed(bool on) { if(!_untransLed) return; if(on) { if(_untransLed->state()==KLed::Off) _untransLed->on(); } else { if(_untransLed->state()==KLed::On) _untransLed->off(); } } void KBabelView::toggleErrorLed(bool on) { if(!_errorLed) return; if(on) { if(_errorLed->state()==KLed::Off) { _errorLed->on(); } } else { if(_errorLed->state()==KLed::On) _errorLed->off(); } } void KBabelView::showError(const TQString& message) { KMessageBox::error(this,message); } void KBabelView::dragEnterEvent(TQDragEnterEvent *event) { // accept uri drops only event->accept(KURLDrag::canDecode(event)); } void KBabelView::dropEvent(TQDropEvent *event) { KURL::List uri; // see if we can decode a URI.. if not, just ignore it if (KURLDrag::decode(event, uri)) { processUriDrop(uri , mapToGlobal(event->pos())); } } bool KBabelView::eventFilter( TQObject* object, TQEvent* event) { if(event->type() == TQEvent::DragEnter) { TQDragEnterEvent* e = (TQDragEnterEvent*) event; if(KURLDrag::canDecode(e)) { e->accept(true); return true; } } else if(event->type() == TQEvent::Drop) { KURL::List uri; // see if we can decode a URI.. if not, just ignore it if (KURLDrag::decode((TQDropEvent*)event, uri)) { processUriDrop(uri ,( (TQWidget*)object)->mapToGlobal( ( (TQDropEvent*)event )->pos())); return true; } } else if(event->type() == TQEvent::KeyPress) { // This is a little workaround to use CTRL+ALT+Home, CTRL+ALT+End, Undo keys // to go to the first and the last entry. Because otherwise // CTRL+Home and CTRL+End and Undo are caught by TQTextEdit TQKeyEvent *ke = (TQKeyEvent*)event; if(ke->key() == Key_Home && ke->state() == (AltButton | ControlButton)) { gotoFirst(); return true; } else if(ke->key() == Key_End && ke->state() == (AltButton | ControlButton)) { gotoLast(); return true; } else if( KShortcut(KKey(ke)) == KStdAccel::undo() ) { undo(); return true; } else if( KShortcut(KKey(ke)) == KStdAccel::redo() ) { redo(); return true; } else if( ke->key() == Key_Insert ) { m_mainwindow->toggleEditMode(); return true; } } return false; } void KBabelView::processUriDrop(KURL::List& uriList, const TQPoint& pos) { // if we have two entries, the chance is high, that it // is a drag from the catalog manager if(uriList.count() == 2) { int result = _dropMenu->exec(pos); switch(result) { case ID_DROP_OPEN: { KURL first(uriList.first()); KURL second(uriList.last()); if( TDEIO::NetAccess::exists(first, true, this) ) { open(first); } else { openTemplate(second,first); } break; } case ID_DROP_OPEN_TEMPLATE: { open(uriList.last()); break; } } } else { // okay, we have one URI.. process it KURL url( uriList.first() ); // load in the file open(url); } } void KBabelView::forwardMsgstrEditCmd(EditCommand* cmd) { /* if(cmd->terminator()!=0) { kdDebug(KBABEL) << TQString::number(cmd->terminator()) << endl; } else { DelTextCmd* delcmd = (DelTextCmd*) cmd; kdDebug(KBABEL) << TQString::number(delcmd->offset)+":"+delcmd->str+"|" << endl; } */ bool fuzzyRemoved=false; if(KBabelSettings::autoUnsetFuzzy() && _catalog->isFuzzy(_currentIndex) ) { fuzzyRemoved=true; _catalog->applyBeginCommand(_currentIndex,Msgstr,this); removeFuzzyStatus(); } cmd->setPart(Msgstr); cmd->setIndex(_currentIndex); bool wasUntranslated=_catalog->isUntranslated(_currentIndex); _catalog->applyEditCommand(cmd,this); if( fuzzyRemoved ) { _catalog->applyEndCommand(_currentIndex,Msgstr,this); } bool isUntranslated=_catalog->isUntranslated(_currentIndex); if(wasUntranslated && !isUntranslated) emit signalUntranslatedDisplayed(false); else if(!wasUntranslated && isUntranslated) emit signalUntranslatedDisplayed(true); } void KBabelView::autoCheck() { autoCheck(true); } void KBabelView::autoCheck(bool onlyWhenChanged) { if( !_autocheckTools.isEmpty() ) { TQStringList oldStatus = _catalog->itemStatus(_currentIndex); TQStringList status = _catalog->itemStatus( _currentIndex,true, _autocheckTools ); // if there is more than one view, the status changes only in // one view, so we have to update always. if(_catalog->isLastView() && onlyWhenChanged && oldStatus == status) return; if( !status.isEmpty() ) { TQString msg = ""; // ### TODO: whynot use i18n("context",text) directly? KLocale* locale=TDEGlobal::locale(); for( TQStringList::iterator it=status.begin() ; it != status.end() ; ++it ) { if( msg.isEmpty() ) msg = locale->translate("what check found errors",(*it).utf8()); else msg += ", "+locale->translate("what check found errors",(*it).utf8()); } //i18n: translators: Status bar text that automatic checks have found some errors emit signalChangeStatusbar(i18n("1 error: %1", "%n errors: %1", status.size ()).arg(msg)); emit signalFaultyDisplayed(true); if(KBabelSettings::autoCheckColorError()) { msgstrEdit->setCurrentColor( MsgMultiLineEdit::ErrorColor ); } if(KBabelSettings::beepOnError() && !_dontBeep) { if(onlyWhenChanged) { if(oldStatus != status && oldStatus.isEmpty() ) { KNotifyClient::beep(); } } else if(isActiveWindow()) { KNotifyClient::beep(); } } } else if( _catalog->itemStatus(_currentIndex).isEmpty() ) { _catalog->removeFromErrorList(_currentIndex); emit signalFaultyDisplayed(false); if(KBabelSettings::autoCheckColorError()) { msgstrEdit->setCurrentColor( MsgMultiLineEdit::NormalColor ); } } } } void KBabelView::spellcheckAll() { spell.what2Check=All; spellcheck(); } void KBabelView::spellcheckAllMulti() { spell.what2Check=AllMulti; spellcheck(); } void KBabelView::spellcheckFromCursor() { spell.what2Check=End; spellcheck(); } void KBabelView::spellcheckCurrent() { spell.what2Check=Current; spellcheck(); } void KBabelView::spellcheckFromCurrent() { spell.what2Check=BeginCurrent; spellcheck(); } void KBabelView::spellcheckMarked() { if(!msgstrEdit->hasSelectedText()) { return; } spell.what2Check=Marked; spellcheck(); } void KBabelView::spellcheckCommon() { SpellDlg *spellDlg = new SpellDlg(msgstrEdit->hasSelectedText(),this ,"SpellDlg"); if(spellDlg->exec()) { if(spellDlg->all()) spell.what2Check=All; else if(spellDlg->current()) spell.what2Check=Current; else if(spellDlg->begin()) spell.what2Check=Begin; else if(spellDlg->end()) spell.what2Check=End; else if(spellDlg->marked()) spell.what2Check=Marked; else if(spellDlg->beginCurrent()) spell.what2Check=BeginCurrent; else { kdError() << "unhandled option in spell dialog" << endl; return; } spellcheck(); } delete spellDlg; } void KBabelView::addSpellcheckWords( uint pos, TQString text, uint index, uint form ) { // special format chars TQString spclChars="abfnrtv'\"?\\"; TQChar accelMarker=_catalog->miscSettings().accelMarker; uint textLength=text.length(); do { TQString word=""; bool wordBegin=false; while(!wordBegin && pos < textLength) { TQChar c=text[pos]; if(c.isLetter() || c==accelMarker) { wordBegin=true; } else if( c == '\\') { if(pos+1 < textLength && spclChars.contains(text[pos+1]) ) { pos+=2; } else { // consider it to be unnecessary escaped character pos++; } } else { pos++; } } int begin=pos; bool wordEnd=false; while(!wordEnd && pos < textLength) { if(text[pos].isLetter() || text[pos]=='-' || (text[pos]=='\'' && !spell.config->dictionary().startsWith("malti"))) { word+=text[pos]; pos++; } else if(text[pos]==accelMarker) { pos++; } else if(text[pos]=='\n') { // newline without \n counts as nothing pos++; } else { wordEnd=true; } } int end=pos; // remove '-' and accelMarker at the end of a word while(text[end]=='-' || (text[pos]=='\'' && !spell.config->dictionary().startsWith("malti")) || text[end]==accelMarker) { end--; word.truncate(word.length()-1); } if(!word.isEmpty()) { spell.wordList.append(word); Position *pos = new Position; pos->index=index; pos->form=form; pos->pos=begin; pos->end=end; spell.posDict.append(pos); } } while(pos < textLength); } void KBabelView::spellcheck() { if(isReadOnly() || spell.active) return; spell.wordList.clear(); spell.posDict.clear(); spell.ignoreList.clear(); spell.newIgnoreList.clear(); spell.misspelled=0; spell.replaced=0; spell.lastIndex=0; spell.posCorrection=0; spell.lastPos=0; spell.inWordCorrection=0; if( !_spellcheckSettings.valid ) { _spellcheckSettings = _project->spellcheckSettings(); } spell.config = new KSpellConfig(this,"tempSpellConfig"); spell.config->setNoRootAffix(_spellcheckSettings.noRootAffix); spell.config->setRunTogether(_spellcheckSettings.runTogether); spell.config->setClient(_spellcheckSettings.spellClient); spell.config->setEncoding(_spellcheckSettings.spellEncoding); spell.config->setDictionary(_spellcheckSettings.spellDict); if(spell.what2Check==Marked) { spell.lastIndex=_currentIndex; _tagExtractor->setString(msgstrEdit->selectedText()); TQString marked=_tagExtractor->plainString(true); addSpellcheckWords(msgstrEdit->beginOfMarkedText(),marked ,_currentIndex,msgstrEdit->currentForm()); } else { uint first=0; uint last=_catalog->numberOfEntries()-1; TQString text; bool emitProgress=false; if(spell.what2Check==All || spell.what2Check==Begin || spell.what2Check==End || spell.what2Check==AllMulti || spell.what2Check==BeginCurrent) { emitProgress=true; } if(spell.what2Check==Begin) { first=0; last=_currentIndex-1; } else if(spell.what2Check==End) { first=_currentIndex+1; last=_catalog->numberOfEntries()-1; int pos=msgstrEdit->currentIndex(); int form=msgstrEdit->currentForm(); TQStringList msgs = _catalog->msgstr(_currentIndex); _tagExtractor->setString((*msgs.at(form))); text=_tagExtractor->plainString(true); addSpellcheckWords( pos, text, _currentIndex, form++ ); for( TQStringList::Iterator i=msgs.at(form++) ; i!=msgs.end(); i++) { _tagExtractor->setString(*i); text=_tagExtractor->plainString(true); addSpellcheckWords( pos, text, _currentIndex, form++ ); } } else if(spell.what2Check==BeginCurrent) { first=_currentIndex; last=_catalog->numberOfEntries()-1; } else if(spell.what2Check!=All && spell.what2Check!=AllMulti) { first=last=_currentIndex; } if(emitProgress) { emit signalResetProgressBar(i18n("Preparing spell check"),100); kapp->processEvents(100); } uint total=last-first+1; uint lastPercent=0; for(uint i=first; i <= last; i++) { if(emitProgress && 100*i/ TQMAX(total,1) > lastPercent) { lastPercent++; emit signalProgress(lastPercent); kapp->processEvents(100); } TQStringList msgs=_catalog->msgstr(i); uint formCounter=0; for(TQStringList::Iterator j=msgs.begin() ; j!=msgs.end() ; ++j) { _tagExtractor->setString(*j); text=_tagExtractor->plainString(true); addSpellcheckWords(0,text,i,formCounter++); } } if(spell.what2Check==Begin) { int pos=msgstrEdit->currentIndex(); int form=msgstrEdit->currentForm(); TQStringList msgs = _catalog->msgstr(_currentIndex); _tagExtractor->setString((*msgs.at(form)).left(pos)); text=_tagExtractor->plainString(true); addSpellcheckWords( 0, text, _currentIndex, form++ ); for( TQStringList::Iterator i=msgs.at(form++) ; i!=msgs.end(); i++) { _tagExtractor->setString(*i); text=_tagExtractor->plainString(true); addSpellcheckWords( 0, text, _currentIndex, form++ ); } } if(emitProgress) { emit signalClearProgressBar(); } } if(!spell.wordList.isEmpty()) { spell.active=true; _dontBeep=true; spell.kspell= new KSpell (this, i18n("Spellcheck"), TQT_TQOBJECT(this), TQT_SLOT(spellStart(KSpell *)), spell.config, true, true); if( spell.kspell->status() == KSpell::Error ) { KMessageBox::error( this, i18n("KBabel cannot start spell checker. " "Please check your TDE installation.") ); return; } connect(spell.kspell, TQT_SIGNAL(death()),this, TQT_SLOT(spellCleanDone())); connect(spell.kspell, TQT_SIGNAL(misspelling(const TQString &, const TQStringList & , unsigned int)), this , TQT_SLOT(spellMisspelled(const TQString &, const TQStringList &, unsigned int))); connect(spell.kspell, TQT_SIGNAL(corrected(const TQString &, const TQString &, unsigned int)) , this, TQT_SLOT(spellCorrected(const TQString &, const TQString &, unsigned int))); connect(spell.kspell,TQT_SIGNAL(ignoreall(const TQString &)) , this, TQT_SLOT(spellAddIgnore(const TQString &))); connect(spell.kspell, TQT_SIGNAL(done(bool)) , this, TQT_SLOT(spellResult(bool))); spell.kspell->setAutoDelete(true); // let KSpell handle delete } else { KMessageBox::information(this,i18n( "No relevant text has been found for spell checking.")); } } void KBabelView::spellStart(KSpell *) { // set ignored words if(_spellcheckSettings.rememberIgnored) { TQString urlString = _spellcheckSettings.ignoreURL; if(urlString.contains("@PACKAGE@")) { urlString.replace("@PACKAGE@",_catalog->packageName()); } // ### TODO: correctly set the URL; support for MostLocalURL KURL url(urlString); if(url.isLocalFile()) { TQFile file(url.path()); if(file.open(IO_ReadOnly)) { TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); TQString contents = stream.read(); file.close(); spell.ignoreList = TQStringList::split('\n',contents); } else if(file.exists()) { KMessageBox::sorry(this, i18n("Error opening the file that contains words " "to ignore during spell checking:\n" "%1").arg(file.name())); } } else { KMessageBox::sorry(this, i18n("Only local files are allowed for saving " "ignored words to during spell checking:\n" "%1").arg(urlString)); } if(spell.ignoreList.count() > 0) { emit signalResetProgressBar(i18n("Preparing spell check"),100); kapp->processEvents(100); uint total = spell.ignoreList.count(); uint oldPercent=0; uint counter=0; TQStringList::Iterator it; for(it=spell.ignoreList.begin(); it != spell.ignoreList.end(); ++it) { counter++; if(counter/total > oldPercent) { oldPercent++; emit signalProgress(oldPercent); kapp->processEvents(100); } spell.kspell->ignore(*it); } emit signalClearProgressBar(); } } spell.kspell->checkList(&spell.wordList); } bool KBabelView::markMisspelled(const TQString &orig, unsigned int pos) { Position *p = spell.posDict.at(pos); if(!p) { kdError() << "not a valid position: " << pos << endl; return false; } if(p->index != _currentIndex || (p->index==_currentIndex && p->form!=msgstrEdit->currentForm())) { DocPosition pos; pos.item=p->index; pos.form=p->form; gotoEntry(pos); } if(p->index != spell.lastIndex) { spell.lastIndex=p->index; spell.posCorrection=0; } if(pos != spell.lastPos) { spell.lastPos=pos; spell.inWordCorrection=0; } int x=0; int y=0; int begin=p->pos+spell.posCorrection-spell.inWordCorrection; int end=p->end+spell.posCorrection-spell.inWordCorrection; // check if this is the correct word TQString text = *_catalog->msgstr(p->index).at(p->form); text=text.mid(begin,end-begin); TQChar accelMarker=_catalog->miscSettings().accelMarker; if(text.contains(accelMarker)) { text.replace(accelMarker,""); } if(text.contains('\n')) { text.replace("\n",""); } bool textOk=true; if(text != orig) { // if text and orig are not the same, // maybe it was a word with hyphens int n=text.contains('-'); n+=text.contains('\''); if( n > 0 ) { // re-get the original text since we replace some things above TQString text = *_catalog->msgstr(p->index).at(p->form); text=text.mid(begin,end-begin); bool textFound=false; int i = 0; int e=-1; while(!textFound && i <= n) { int lastPos=e+1; e = text.find('-',lastPos); int tmp = text.find('\'',lastPos); if(e < 0 && tmp > 0) { e=tmp; } else if(e > 0 && tmp > 0 && tmp < e) { e=tmp; } if(e<0) e=text.length(); TQString w=text.mid(lastPos,e-lastPos); if(w.contains(accelMarker)) { w.replace(accelMarker,""); } if(text.contains('\n')) { text.replace("\n",""); } if( w == orig) { textFound=true; end=begin+e; begin=begin+lastPos; } i++; } if(!textFound) { textOk=false; } } else { textOk=false; } } int beginx, beginy; msgstrEdit->offset2Pos(end,y,x); msgstrEdit->offset2Pos(begin,beginy,beginx); msgstrEdit->setSelection(beginy,beginx,y,x); if(!textOk) { text = *_catalog->msgstr(p->index).at(p->form); text=text.mid(begin,end-begin); kdDebug(KBABEL) << "Sync error: given: " << orig << " have: " << text << endl; cancelSpellcheck(); KMessageBox::error(this,i18n( "There seems to be an error with the synchronization " "of the spell checking process and KBabel.\n" "Please check that you have set the correct settings for " "your language for spell checking.\n" "If you have, and this problem is reproducible, please " "send a detailed bug report (your spell checking options, " "what file you have checked and what to do to reproduce " "the problem) by using Help->Report Bug...")); } return textOk; } void KBabelView::spellMisspelled(const TQString &orig, const TQStringList &, unsigned int pos) { kdDebug(KBABEL) << "misspelled: " << orig << " pos: " << pos << endl; spell.misspelled++; markMisspelled(orig,pos); } void KBabelView::spellCorrected(const TQString &orig, const TQString &word, unsigned int pos) { if(orig != word) { TQString newWord(word); kdDebug(KBABEL) << "corrected: " << orig << " " << newWord << " pos: " << pos << endl; if(spell.replaced==0) { // handle the spell check as one action int index; Position *p = spell.posDict.at(pos); if(p) { index=p->index; } else { index=_currentIndex; } _catalog->applyBeginCommand(index,Msgstr,this); } spell.replaced++; if(markMisspelled(orig,pos)) { TQString marked=msgstrEdit->selectedText(); spell.origWords.append(marked); if(marked.contains("\n") && !newWord.contains('\n')) { TQString s1=newWord; s1.replace(" ","\n"); // if only a newline has been replaced with a white space if(s1==marked) { newWord.replace(" "," \n"); } } // check if the old word had an accelerator. If yes and the new // word has no accelerator, try to add the accelerator for // the same char else add in at the same position TQChar accelMarker=_catalog->miscSettings().accelMarker; if(marked.contains(accelMarker) && !newWord.contains(accelMarker)) { int b=marked.find(accelMarker); TQChar accel=marked[b+1]; int nb=newWord.find(accel,0,false); if(nb>=0) { newWord.insert(nb,accelMarker); } // if the new word does not contain the old accel char // set the accelerator to the same position as the old else { if((uint)b >= newWord.length()) b = 0; newWord.insert(b,accelMarker); } } spell.newWords.append(newWord); msgstrEdit->cut(); int row=0; int col=0; msgstrEdit->getCursorPosition(&row,&col); msgstrEdit->insertAt(newWord,row,col,true); int newCorrection = newWord.length() - marked.length(); spell.posCorrection += newCorrection; spell.inWordCorrection += newCorrection; // now store the new position Position *p = spell.posDict.at(pos); if(p) { p->end=p->end+newCorrection; } } } } void KBabelView::spellResult(bool flag) { kdDebug(KBABEL) << "spellResult: " << flag << endl; if(spell.replaced > 0) { // close the spell check action _catalog->applyEndCommand(spell.lastIndex,Msgstr,this); } if(flag) { emit signalChangeStatusbar(i18n("Spellcheck: %n word replaced","Spellcheck: %n words replaced",spell.replaced)); if(spell.misspelled==0) { KMessageBox::information(this,i18n( "Spellcheck successfully finished.\n" "No misspelled words have been found.")); } else if(spell.replaced > 0 && spell.what2Check!=Current && spell.what2Check!=Marked) { TQStringList list; TQStringList::Iterator origIt; TQStringList::Iterator newIt; origIt=spell.origWords.begin(); newIt=spell.newWords.begin(); for(;origIt != spell.origWords.end() && newIt != spell.newWords.end(); origIt++,newIt++) { list.append(*origIt+" -> "+*newIt); } } if( spell.what2Check!=AllMulti && spell.misspelled!=0 ) KMessageBox::information(this,i18n("Spellcheck: %n word replaced","Spellcheck: %n words replaced",spell.replaced)); if(_spellcheckSettings.rememberIgnored) { if(spell.newIgnoreList.count() > 0) { KURL url(_spellcheckSettings.ignoreURL); if(url.isLocalFile()) { TQFile file(url.path()); if(file.open(IO_WriteOnly|IO_Append)) { TQStringList::Iterator it; TQTextStream stream(&file); stream.setEncoding(TQTextStream::UnicodeUTF8); for(it=spell.newIgnoreList.begin(); it!=spell.newIgnoreList.end(); ++it) { stream << *it << "\n"; } file.close(); } } else { kdDebug(KBABEL) << "only local files are supported for storing" << "ignored words" << endl; } } } } else { emit signalChangeStatusbar(i18n("Spellcheck canceled")); if(spell.replaced > 0) undo(); } int s=spell.kspell->dlgResult(); spell.kspell->cleanUp(); emit signalSpellcheckDone(s); TQTimer::singleShot(0,this,TQT_SLOT(cleanUpSpellStruct())); } void KBabelView::spellCleanDone() { kdDebug(KBABEL) << "spellCleanDone" << endl; // if the pointer is cleared, you have finished correcly if( !spell.kspell ) return; KSpell::spellStatus status = spell.kspell->status(); if(status == KSpell::Error || status == KSpell::Crashed) { cleanUpSpellStruct(); } if(status == KSpell::Error) { KMessageBox::sorry(this, i18n("The spell checker program could not be started.\n" "Please make sure you have the spell checker program properly " "configured and in your PATH.")); } else if(status == KSpell::Crashed) { KMessageBox::sorry(this, i18n("The spell checker program seems to have crashed.")); } } void KBabelView::cleanUpSpellStruct() { kdDebug(KBABEL) << "Cleaning structure" << endl; // spell.kspell is set to be autodeleted spell.kspell = 0; delete spell.config; spell.config=0; spell.wordList.clear(); spell.posDict.clear(); spell.origWords.clear(); spell.newWords.clear(); spell.ignoreList.clear(); spell.newIgnoreList.clear(); spell.active = false; _dontBeep=false; } void KBabelView::cancelSpellcheck() { spell.active=false; } void KBabelView::spellAddIgnore(const TQString &word) { if(!spell.ignoreList.contains(word)) { spell.newIgnoreList.append(word); } } void KBabelView::forwardSearchStart() { emit signalResetProgressBar(i18n("Searching"),100); emit signalSearchActive(true); } void KBabelView::forwardSearchStop() { emit signalClearProgressBar(); emit signalSearchActive(false); } void KBabelView::forwardProgressStart(const TQString& msg) { emit signalResetProgressBar(msg,100); } void KBabelView::slotAutoSaveTimeout( ) { if ( isModified( ) ) { autoSaveTimer->stop( ); saveFile( false ); autoSaveTimer->start( 1000 * 60 * _autoSaveDelay ); } } void KBabelView::useProject (Project::Ptr project) { // FIXME: close the current project first disconnect (_project, TQT_SIGNAL(signalSpellcheckSettingsChanged()), this, TQT_SLOT(updateProjectSettings())); _project = project; _catalog->useProject(_project); readProject(_project); connect (project, TQT_SIGNAL(signalSpellcheckSettingsChanged()), this, TQT_SLOT(updateProjectSettings())); } #include "kbabelview.moc"