1
/* ****************************************************************************
2
This file is part of KBabel
4
Copyright (C) 1999-2000 by Matthias Kiefer
5
<matthias.kiefer@gmx.de>
6
2002-2004 by Stanislav Visnovsky
9
This program is free software; you can redistribute it and/or modify
10
it under the terms of the GNU General Public License as published by
11
the Free Software Foundation; either version 2 of the License, or
12
(at your option) any later version.
14
This program is distributed in the hope that it will be useful,
15
but WITHOUT ANY WARRANTY; without even the implied warranty of
16
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
In addition, as a special exception, the copyright holders give
24
permission to link the code of this program with any edition of
25
the Qt library by Trolltech AS, Norway (or with modified versions
26
of Qt that use the same license as Qt), and distribute linked
27
combinations including the two. You must obey the GNU General
28
Public License in all respects for all of the code used other than
29
Qt. If you modify this file, you may extend this exception to
30
your version of the file, but you are not obligated to do so. If
31
you do not wish to do so, delete this exception statement from
34
**************************************************************************** */
36
#include <kdatatool.h>
38
#include <kfiledialog.h>
39
#include <kinputdialog.h>
41
#include <kmessagebox.h>
42
#include <knotifyclient.h>
44
#include <kio/netaccess.h>
46
#include <qcheckbox.h>
49
#include <qmessagebox.h>
50
#include <qpopupmenu.h>
53
#include "catalogsettings.h"
55
#include "tagextractor.h"
56
#include "kbabelview.h"
57
#include "kbabeldictbox.h"
58
#include "mymultilineedit.h"
59
#include "hidingmsgedit.h"
60
#include "roughtransdlg.h"
61
#include "kbabelsettings.h"
62
#include "kbprojectsettings.h"
64
#include "resources.h"
66
using namespace KBabel;
68
QPtrList<ModuleInfo> KBabelView::dictionaries()
70
QPtrList<ModuleInfo> list = dictBox->moduleInfos();
75
void KBabelView::configureDictionary(const QString id)
77
dictBox->configure(id);
80
void KBabelView::editDictionary(const QString id)
86
void KBabelView::aboutDictionary(const QString id)
88
dictBox->aboutModule(id);
91
void KBabelView::informDictionary()
96
if( msgstrEdit->isModified() )
97
dictBox->setTextChanged(_catalog->msgid(_currentIndex,true)
98
,*(_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm()))
99
,msgstrEdit->currentForm()
100
,_catalog->comment(_currentIndex));
103
void KBabelView::setNewLanguage()
105
IdentitySettings s = _catalog->identitySettings();
107
dictBox->setLanguage(s.languageCode, s.languageName);
109
// setup new plural form number
110
int form = msgstrEdit->currentForm();
111
if( form >= s.numberOfPluralForms )
112
form = s.numberOfPluralForms-1;
114
msgstrEdit->setNumberOfPlurals (s.numberOfPluralForms);
117
if (! _catalog->currentURL().isEmpty())
119
updateEditor( form );
124
void KBabelView::wheelEvent(QWheelEvent *e)
126
if( _catalog->numberOfEntries() == 0 ) return;
128
if( (e->state() & ControlButton) && (e->state() & AltButton))
132
gotoPrevFuzzyOrUntrans();
136
gotoNextFuzzyOrUntrans();
139
else if(e->state() & ControlButton)
150
else if(e->state() & AltButton)
154
gotoPrevUntranslated();
158
gotoNextUntranslated();
178
void KBabelView::roughTranslation()
180
RoughTransDlg *dlg = new RoughTransDlg(dictBox, _catalog, this
189
void KBabelView::updateTags()
191
bool hadTags = _tags.count() > 0;
193
_tags = _catalog->tagList(_currentIndex);
200
QStringList::Iterator it;
202
for(it=_tags.begin(); it!=_tags.end(); ++it)
205
if( s.startsWith("&") ) s = "&"+s;
206
if(!tList.contains(s))
208
_tagsMenu->insertItem(s,counter);
215
bool haveTags = (_tags.count() > 0);
220
if(haveTags != hadTags)
222
emit signalNextTagAvailable(haveTags);
223
emit signalTagsAvailable(haveTags);
230
_tagExtractor->setString(_catalog->msgid(_currentIndex).first());
232
// if there is no tag, it will set invalid tag
236
void KBabelView::skipToNextTag()
238
if( (uint)_currentTag >= _tags.count()-1 ) return;
243
void KBabelView::skipToPreviousTag()
245
if( _currentTag == 0 ) return;
250
void KBabelView::selectTag()
252
if( _tagExtractor->countMatches() == 0 ) {
253
// no tags, select none
254
kdDebug() << "No tags" << endl;
255
msgidLabel->selectTag(0,0);
259
// count number of eofs in tag
261
// FIXME: what about plural forms
262
QString msgid = _catalog->msgid(_currentIndex).first();
264
for( uint i = _tagExtractor->matchIndex(_currentTag); i < _tagExtractor->matchIndex(_currentTag)+_tags[_currentTag].length()+1; i++ )
266
if( msgid[i] == '\n' ) diff++;
268
msgidLabel->selectTag(_tagExtractor->matchIndex(_currentTag),_tags[_currentTag].length()+diff);
269
emit signalNextTag (_currentTag);
272
void KBabelView::setTagsMenu(QPopupMenu *menu)
276
connect(_tagsMenu,SIGNAL(activated(int)),this,SLOT(insertTag(int)));
279
void KBabelView::modifyMsgstrText(const uint offset, const QString& text, bool clearFirst)
281
_catalog->applyBeginCommand( _currentIndex, Msgstr ,this);
283
if( clearFirst ) msgstrEdit->clear();
285
InsTextCmd* insCmd = new InsTextCmd(offset,text,msgstrEdit->currentForm());
286
insCmd->setPart(Msgstr);
287
insCmd->setIndex(_currentIndex);
289
msgstrEdit->processCommand(insCmd,false);
290
forwardMsgstrEditCmd(insCmd);
292
_catalog->applyEndCommand(_currentIndex, Msgstr,this);
294
autoCheck( true ); // check it NOW - it should not be needed, but it is, I don't know why :-(
297
void KBabelView::insertTag(int n)
299
QString tag = _tagsMenu->text(n);
300
if( tag.startsWith( "&&" ) ) tag = tag.remove(0,1); // replace && -> &. && is used for correct menu display
302
modifyMsgstrText( msgstrEdit->currentIndex(), tag );
305
void KBabelView::insertNextTag()
307
if(_currentTag >= (int)_tags.count())
309
KNotifyClient::beep();
313
int offset = msgstrEdit->currentIndex();
318
modifyMsgstrText( offset, _tags[_currentTag-1] );
321
void KBabelView::insertNextTagMsgid()
323
TagExtractor extractor;
325
int offset = msgstrEdit->beginOfLastMarkedText(); //msgstrEdit->currentIndex();
327
QString s = (*_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm())).left(offset);
331
if( _catalog->pluralForm( _currentIndex ) == KDESpecific )
333
int pos = msgstrEdit->currentIndex();
334
int currentFormBegin=s.findRev("\\n",pos);
335
if( currentFormBegin == -1 ) currentFormBegin=0;
336
else currentFormBegin+=3; // skip the newline
337
int currentFormEnd=s.find("\\n",pos);
338
if( currentFormEnd == -1 ) currentFormEnd=s.length();
340
s=s.mid(currentFormBegin,currentFormEnd-currentFormBegin);
343
extractor.setString(s);
344
uint num= extractor.countMatches();
345
if(num >= _tags.count())
347
KNotifyClient::beep();
353
modifyMsgstrText( offset, t );
356
void KBabelView::showTagsMenu()
358
if(_tagsMenu && _tags.count() > 0)
360
int y=msgstrEdit->height()/2;
361
int x=msgstrEdit->width()/2;
362
_tagsMenu->exec(msgstrEdit->mapToGlobal( QPoint(x,y) ) );
369
void KBabelView::updateArgs()
371
bool hadArgs = _args.count() > 0;
373
_args = _catalog->argList(_currentIndex);
380
QStringList::Iterator it;
382
for(it=_args.begin(); it!=_args.end(); ++it)
385
if(!tList.contains(s))
387
_argsMenu->insertItem(s,counter);
394
bool haveArgs = (_args.count() > 0);
399
if(haveArgs != hadArgs)
401
emit signalNextArgAvailable(haveArgs);
402
emit signalArgsAvailable(haveArgs);
406
void KBabelView::setArgsMenu(QPopupMenu *menu)
410
connect(_argsMenu,SIGNAL(activated(int)),this,SLOT(insertArg(int)));
414
void KBabelView::insertArg(int n)
416
QString arg = _argsMenu->text(n);
418
modifyMsgstrText( msgstrEdit->currentIndex(), arg );
421
void KBabelView::insertNextArg()
423
int offset = msgstrEdit->currentIndex();
425
QString s = (*_catalog->msgstr(_currentIndex).at(msgstrEdit->currentForm())).left(offset);
427
if( _catalog->pluralForm( _currentIndex ) == KDESpecific )
429
int pos = msgstrEdit->currentIndex();
430
int currentFormBegin=s.findRev("\\n",pos);
431
if( currentFormBegin == -1 ) currentFormBegin=0;
432
else currentFormBegin+=3; // skip the newline
433
int currentFormEnd=s.find("\\n",pos);
434
if( currentFormEnd == -1 ) currentFormEnd=s.length();
436
s=s.mid(currentFormBegin,currentFormEnd-currentFormBegin);
439
_argExtractor->setString(s);
440
uint num=_argExtractor->countMatches();
441
if(num >= _args.count())
443
KNotifyClient::beep();
447
QString t=_args[num];
449
modifyMsgstrText( offset,t );
452
void KBabelView::showArgsMenu()
454
if(_argsMenu && _args.count() > 0)
456
int y=msgstrEdit->height()/2;
457
int x=msgstrEdit->width()/2;
458
_argsMenu->exec(msgstrEdit->mapToGlobal( QPoint(x,y) ) );
465
void KBabelView::diff()
468
msgstrEdit->setFocus();
471
void KBabelView::diffShowOrig()
473
msgidLabel->setText(_catalog->msgid(_currentIndex));
474
msgidLabel->forceUpdate();
475
msgstrEdit->setFocus();
478
void KBabelView::toggleAutoDiff(bool on)
480
if(on != _diffEnabled)
495
void KBabelView::autoDiff()
500
void KBabelView::diffInternal(bool autoDf)
502
if(_diffing || _loadingDiffFile)
508
uint diffIndex = _currentIndex;
512
Catalog::DiffResult r = _catalog->diff(_currentIndex, &diffString);
514
if(r == Catalog::DiffNeedList)
516
switch( _project->settings()->useDBForDiff() )
520
_loadingDiffFile=true;
521
bool wasEnabled=_diffEnabled;
524
QValueList<DiffEntry> diffList;
526
QString package = _catalog->packageName()+".po";
527
kdDebug(KBABEL) << "getting list for " << package << endl;
529
if(dictBox->messagesForPackage(package,diffList,error))
531
kdDebug(KBABEL) << "got " << diffList.count()
532
<< " messages" << endl;
533
_catalog->setDiffList(diffList);
537
KMessageBox::sorry(this
538
,i18n("An error occurred while trying to get the list "
539
"of messages for this file from the database:\n"
544
_loadingDiffFile=false;
545
emit signalDiffEnabled(false);
550
_diffEnabled=wasEnabled;
551
_loadingDiffFile=false;
557
if(!openDiffFile(true))
560
emit signalDiffEnabled(false);
571
// get the list of all entries
572
QValueList<DiffEntry> diffList = _catalog->asDiffList();
574
QValueList<DiffEntry> resultList;
576
// swap msgstr and msgid
577
QValueList<DiffEntry>::iterator it;
580
for ( it = diffList.begin(); it != diffList.end(); ++it )
582
entry.msgstr = (*it).msgid;
583
// if there is no translation, do not show difference
584
if( !(*it).msgstr.isEmpty() )
586
entry.msgid = (*it).msgstr;
590
entry.msgid = (*it).msgid;
592
resultList.append(entry);
595
// set as a source for diff
596
_catalog->setDiffList(resultList);
600
_loadingDiffFile=false;
601
emit signalDiffEnabled(true);
605
diffIndex = _currentIndex;
606
r = _catalog->diff(_currentIndex, &diffString);
609
// if the index changed in the meanwhile
610
while(diffIndex != _currentIndex)
612
diffIndex=_currentIndex;
613
r = _catalog->diff(_currentIndex,&diffString);
616
if(r == Catalog::DiffOk)
618
msgidLabel->setText(diffString);
619
msgidLabel->forceUpdate();
621
// FIXME: should care about plural forms
622
if(diffString == _catalog->msgid(_currentIndex).first() )
624
emit signalChangeStatusbar(i18n("No difference found"));
628
emit signalChangeStatusbar(i18n("Difference found"));
635
KMessageBox::information(this
636
,i18n("No corresponding message found."));
640
emit signalChangeStatusbar(
641
i18n("No corresponding message found"));
648
bool KBabelView::openDiffFile()
650
return openDiffFile(false);
653
bool KBabelView::openDiffFile(bool autoDiff)
655
if(_diffing || _loadingDiffFile)
660
if( autoDiff && ! _project->settings()->diffBaseDir().isEmpty() )
662
KURL fileURL = _catalog->currentURL();
664
KURL poBaseURL( _project->catManSettings().poBaseDir );
666
QString poBase = poBaseURL.path();
667
int len = poBase.length();
668
if(fileURL.path().left(len) == poBase)
670
QString fileRelPath = fileURL.path().mid(len);
671
if(fileRelPath[0] == '/')
672
fileRelPath=fileRelPath.mid(1);
674
if(_project->settings()->diffBaseDir().right(1) != "/")
675
_project->settings()->diffBaseDir() += '/';
677
QString diffFilePath = _project->settings()->diffBaseDir() + fileRelPath;
680
KURL diffFileURL(diffFilePath);
682
if(diffFileURL.isValid() && KIO::NetAccess::exists(diffFileURL,true,NULL))
686
kdDebug(KBABEL) << "using file " << diffFileURL.prettyURL()
687
<< " as diff file" << endl;
695
url = KFileDialog::getOpenURL(_project->settings()->diffBaseDir(),
696
"application/x-gettext", this, i18n("Select File to Diff With"));
702
_loadingDiffFile=true;
703
bool wasEnabled=_diffEnabled;
709
connect(&cat,SIGNAL(signalProgress(int)),this,SIGNAL(signalProgress(int)));
710
emit signalResetProgressBar(i18n("loading file for diff"),100);
712
ConversionStatus stat = cat.openURL(url);
714
emit signalClearProgressBar();
717
if(stat != OK && stat != RECOVERED_PARSE_ERROR)
723
KMessageBox::sorry(this
724
,i18n("Error while trying to read file:\n %1\n"
725
"Maybe it is not a valid PO file.").arg(url.prettyURL()));
730
KMessageBox::sorry(this,i18n(
731
"You do not have permissions to read file:\n %1")
732
.arg(url.prettyURL()));
737
KMessageBox::sorry(this,i18n(
738
"You have not specified a valid file:\n %1")
739
.arg(url.prettyURL()));
744
KMessageBox::error(this,i18n(
745
"KBabel cannot find a corresponding plugin for the MIME type of the file:\n %1").arg(url.prettyURL()));
748
case UNSUPPORTED_TYPE:
750
KMessageBox::error(this,i18n(
751
"The import plugin cannot handle this type of the file:\n %1").arg(url.prettyURL()));
756
KMessageBox::sorry(this,i18n(
757
"Error while trying to open file:\n %1")
758
.arg(url.prettyURL()));
764
_diffEnabled=wasEnabled;
765
_loadingDiffFile=false;
770
_catalog->setDiffList( cat.asDiffList() );
772
_diffEnabled=wasEnabled;
773
_loadingDiffFile=false;
778
void KBabelView::showTryLaterMessageBox()
780
if( !_showTryLaterBox ) return;
782
KDialogBase *dialog= new KDialogBase(
785
KDialogBase::Yes, KDialogBase::Yes,
786
this, "information", true, true,
789
QVBox *topcontents = new QVBox (dialog);
790
topcontents->setSpacing(KDialog::spacingHint()*2);
791
topcontents->setMargin(KDialog::marginHint()*2);
793
QWidget *contents = new QWidget(topcontents);
794
QHBoxLayout * lay = new QHBoxLayout(contents);
795
lay->setSpacing(KDialog::spacingHint()*2);
798
QLabel *label1 = new QLabel( contents);
799
label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
801
QLabel *label2 = new QLabel( i18n("The search string has not been found yet.\n"
802
"However, the string might be found "
803
"in the files being searched at the moment.\n"
804
"Please try later."), contents);
805
label2->setAlignment( Qt::AlignAuto | Qt::AlignVCenter | Qt::ExpandTabs | Qt::WordBreak );
806
label2->setMinimumSize(label2->sizeHint());
810
QCheckBox *checkbox = new QCheckBox(i18n("Do not show in this find/replace session again"), topcontents);
812
dialog->setMainWidget(topcontents);
813
dialog->enableButtonSeparator(false);
814
dialog->incInitialSize( QSize(50,0) );
818
_showTryLaterBox = !checkbox->isChecked();
822
void KBabelView::setFilePackage()
825
QString p = KInputDialog::getText(QString::null, i18n("Enter new package for the current file:"),_catalog->package(),&result,this);
828
_catalog->setPackage(p);
829
emit signalChangeCaption(p);
833
void KBabelView::insertTagFromTool( const QString& tag )
835
modifyMsgstrText(msgstrEdit->currentIndex(),tag);
837
msgstrEdit->setFocus();
840
void KBabelView::skipToTagFromTool( int index )
846
void KBabelView::plural2msgstr()
848
int currentFormBegin, currentFormEnd, pos;
851
QStringList msgs = _catalog->msgstr(_currentIndex);
852
QString text= *msgs.at(msgstrEdit->currentForm());
853
uint numForms = _catalog->numberOfPluralForms(_currentIndex);
855
if( text.isEmpty() || _catalog->pluralForm(_currentIndex) == NoPluralForm) return;
860
switch( _catalog->pluralForm(_currentIndex) )
864
_catalog->applyBeginCommand( _currentIndex, Msgstr ,this);
867
for( QStringList::Iterator it=msgs.begin() ; it!=msgs.end() ; ++it )
869
if( i!= msgstrEdit->currentForm() )
872
DelTextCmd* insCmd = new DelTextCmd(0,(*it),i);
873
insCmd->setPart(Msgstr);
874
insCmd->setIndex(_currentIndex);
875
msgstrEdit->processCommand(insCmd,false);
876
forwardMsgstrEditCmd(insCmd);
879
insCmd = new InsTextCmd(0,text,i);
880
insCmd->setPart(Msgstr);
881
insCmd->setIndex(_currentIndex);
882
msgstrEdit->processCommand(insCmd,false);
883
forwardMsgstrEditCmd(insCmd);
888
// fill the non-initialized ones
889
while (i != numForms)
892
DelTextCmd* insCmd = new InsTextCmd(0,text,i);
893
insCmd->setPart(Msgstr);
894
insCmd->setIndex(_currentIndex);
895
msgstrEdit->processCommand(insCmd,false);
896
forwardMsgstrEditCmd(insCmd);
900
_catalog->applyEndCommand( _currentIndex, Msgstr ,this);
906
pos = msgstrEdit->currentIndex();
907
currentFormBegin=text.findRev("\\n",pos);
908
if( currentFormBegin == -1 ) currentFormBegin=0;
909
else currentFormBegin+=3; // skip the newline
910
currentFormEnd=text.find("\\n",pos);
911
if( currentFormEnd == -1 ) currentFormEnd=text.length();
913
text=text.mid(currentFormBegin,currentFormEnd-currentFormBegin);
916
for( i=1; i<numForms ; i++ )
917
result+="\\n\n"+text;
919
modifyMsgstrText( 0, result, true );
923
case NoPluralForm: break;
928
bool KBabelView::validateUsingTool( const KDataToolInfo & info, const QString &command )
930
if(currentURL().isEmpty())
933
KDataTool* tool = info.createTool();
936
kdWarning() << "Cannot create tool" << endl;
940
bool result=_catalog->checkUsingTool(tool);
943
QString checkName = *(info.userCommands().at( info.commands().findIndex(command) ));
947
KMessageBox::information(this
948
,i18n("No mismatch has been found.")
956
if(!_catalog->hasError(0,pos))
957
index = _catalog->nextError(0,pos);
960
kdDebug(KBABEL) << "Going to " << pos.item << ", " << pos.form << endl;
964
KMessageBox::error(this
965
,i18n("Some mismatches have been found.\n"
966
"Please check the questionable entries by using "
975
void KBabelView::modifyUsingTool( const KDataToolInfo & info, const QString &command )
977
KDataTool* tool = info.createTool();
980
kdWarning() << "Cannot create tool" << endl;
984
// do some stuff on all entries
985
_catalog->modifyUsingTool(tool, command);
990
void KBabelView::modifyCatalogUsingTool( const KDataToolInfo & info, const QString &command )
992
KDataTool* tool = info.createTool();
995
kdWarning() << "Cannot create tool" << endl;
999
// do some stuff on the catalog
1000
tool->run(command, _catalog, "Catalog", "application/x-kbabel-catalog");
1005
void KBabelView::insertChar( QChar ch )
1007
if( isReadOnly() || _catalog->package().isEmpty() )
1010
modifyMsgstrText(msgstrEdit->currentIndex(),ch);
1011
msgstrEdit->setFocus();
1014
void KBabelView::wordCount()
1016
uint total, untranslated, fuzzy;
1018
_catalog->wordCount( total, fuzzy, untranslated );
1020
KMessageBox::information( this
1021
, i18n("Total words: %1\n\n"
1022
"Words in untranslated messages: %2\n\n"
1023
"Words in fuzzy messages: %3").arg(total).arg(untranslated).arg(fuzzy)
1024
, i18n("Word Count") );