tools/linguist/linguist/trwindow.cpp

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 ** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.
00004 **
00005 ** This file is part of the Qt Linguist of the Qt Toolkit.
00006 **
00007 ** This file may be used under the terms of the GNU General Public
00008 ** License version 2.0 as published by the Free Software Foundation
00009 ** and appearing in the file LICENSE.GPL included in the packaging of
00010 ** this file.  Please review the following information to ensure GNU
00011 ** General Public Licensing requirements will be met:
00012 ** http://www.trolltech.com/products/qt/opensource.html
00013 **
00014 ** If you are unsure which license is appropriate for your use, please
00015 ** review the following information:
00016 ** http://www.trolltech.com/products/qt/licensing.html or contact the
00017 ** sales department at sales@trolltech.com.
00018 **
00019 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
00020 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00021 **
00022 ****************************************************************************/
00023 
00024 /*  TRANSLATOR TrWindow
00025 
00026   This is the application's main window.
00027 */
00028 
00029 #include "trwindow.h"
00030 #include "finddialog.h"
00031 #include "translatedialog.h"
00032 #include "batchtranslationdialog.h"
00033 #include "translationsettingsdialog.h"
00034 #include "msgedit.h"
00035 #include "phrasebookbox.h"
00036 #include "printout.h"
00037 #include "statistics.h"
00038 #include "messagemodel.h"
00039 #include "phrasemodel.h"
00040 #include "translator.h"
00041 #include "previewtool/trpreviewtool.h"
00042 
00043 #include <QAction>
00044 #include <QApplication>
00045 #include <QBitmap>
00046 #include <QDockWidget>
00047 #include <QFile>
00048 #include <QFileDialog>
00049 #include <QFileInfo>
00050 #include <QHeaderView>
00051 #include <QLabel>
00052 #include <QLayout>
00053 #include <QMenuBar>
00054 #include <QMessageBox>
00055 #include <QMenu>
00056 #include <QRegExp>
00057 #include <QSettings>
00058 #include <QStatusBar>
00059 #include <QToolBar>
00060 #include <QWhatsThis>
00061 #include <QAssistantClient>
00062 #include <QDesktopWidget>
00063 #include <QPrintDialog>
00064 #include <QLibraryInfo>
00065 #include <QUiLoader>
00066 
00067 #define pagecurl_mask_width 53
00068 #define pagecurl_mask_height 51
00069 static const uchar pagecurl_mask_bits[] = {
00070    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff,
00071    0xff, 0x0f, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0xfe, 0xff,
00072    0xff, 0xff, 0xff, 0x0f, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00,
00073    0xc0, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff,
00074    0x0f, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xfe, 0xff,
00075    0xff, 0xff, 0x0f, 0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
00076    0xfc, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff, 0x0f,
00077    0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xf0, 0xff, 0xff,
00078    0xff, 0x0f, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xf0,
00079    0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00,
00080    0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff,
00081    0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff,
00082    0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00,
00083    0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f,
00084    0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff,
00085    0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0,
00086    0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00,
00087    0x00, 0xe0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
00088    0x0f, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xfc,
00089    0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00,
00090    0x00, 0x00, 0x00, 0xfc, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f,
00091    0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
00092    0xe0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00,
00093    0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00,
00094    0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
00095    0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00,
00096    0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
00097    0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
00098    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
00099    0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08 };
00100 
00101 static const int ErrorMS = 600000; // for error messages
00102 static const int MessageMS = 2500;
00103 
00104 QPixmap *TrWindow::pxOn = 0;
00105 QPixmap *TrWindow::pxOff = 0;
00106 QPixmap *TrWindow::pxObsolete = 0;
00107 QPixmap *TrWindow::pxDanger = 0;
00108 QPixmap *TrWindow::pxWarning = 0;
00109 QPixmap *TrWindow::pxEmpty = 0;
00110 
00111 enum Ending {End_None, End_FullStop, End_Interrobang, End_Colon,
00112               End_Ellipsis};
00113 
00114 static Ending ending(QString str, QLocale::Language lang)
00115 {
00116     str = str.simplified();
00117     int ch = 0;
00118     if (!str.isEmpty())
00119         ch = str.right(1)[0].unicode();
00120 
00121     switch (ch) {
00122     case 0x002e: // full stop
00123         if (str.endsWith(QString("...")))
00124             return End_Ellipsis;
00125         else
00126             return End_FullStop;
00127     case 0x0589: // armenian full stop
00128     case 0x06d4: // arabic full stop
00129     case 0x3002: // ideographic full stop
00130         return End_FullStop;
00131     case 0x0021: // exclamation mark
00132     case 0x003f: // question mark
00133     case 0x00a1: // inverted exclamation mark
00134     case 0x00bf: // inverted question mark
00135     case 0x01c3: // latin letter retroflex click
00136     case 0x037e: // greek question mark
00137     case 0x061f: // arabic question mark
00138     case 0x203c: // double exclamation mark
00139     case 0x203d: // interrobang
00140     case 0x2048: // question exclamation mark
00141     case 0x2049: // exclamation question mark
00142     case 0x2762: // heavy exclamation mark ornament
00143         return End_Interrobang;
00144     case 0x003b: // greek 'compatibility' questionmark
00145         return lang == QLocale::Greek ? End_Interrobang : End_None;
00146     case 0x003a: // colon
00147         return End_Colon;
00148     case 0x2026: // horizontal ellipsis
00149         return End_Ellipsis;
00150     default:
00151         return End_None;
00152     }
00153 }
00154 
00155 const QPixmap TrWindow::pageCurl()
00156 {
00157     QPixmap pixmap;
00158     pixmap.load(":/images/pagecurl.png" );
00159     if ( !pixmap.isNull() ) {
00160         QBitmap pageCurlMask = QBitmap::fromData(QSize(pagecurl_mask_width, pagecurl_mask_height),
00161                                                  pagecurl_mask_bits, QImage::Format_MonoLSB);
00162         pixmap.setMask(pageCurlMask);
00163     }
00164 
00165     return pixmap;
00166 }
00167 
00168 #ifdef Q_WS_MAC
00169 const QString rsrcString = ":/images/mac";
00170 #else
00171 const QString rsrcString = ":/images/win";
00172 #endif
00173 
00174 TrWindow::TrWindow()
00175     : QMainWindow(0, Qt::Window)
00176 {
00177     ac = 0;
00178 
00179 #ifndef Q_WS_MAC
00180     setWindowIcon(QPixmap(":/images/appicon.png" ));
00181 #endif
00182 
00183     m_previewTool = 0;
00184 
00185     // Create the application global listview symbols
00186     pxOn  = new QPixmap(":/images/s_check_on.png");
00187     pxOff = new QPixmap(":/images/s_check_off.png");
00188     pxObsolete = new QPixmap(":/images/s_check_obsolete.png");
00189     pxDanger = new QPixmap(":/images/s_check_danger.png");
00190     pxWarning = new QPixmap(":/images/s_check_warning.png");
00191     pxEmpty = new QPixmap(":/images/s_check_empty.png");
00192 
00193     setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
00194     setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
00195     setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
00196     setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
00197 
00198     // Set up the Scope dock window
00199     dwScope = new QDockWidget(this);
00200     dwScope->setObjectName("ContextDockWidget");
00201     dwScope->setAllowedAreas(Qt::AllDockWidgetAreas);
00202     dwScope->setFeatures(QDockWidget::AllDockWidgetFeatures);
00203     dwScope->setWindowTitle(tr("Context"));
00204 
00205     tv = new MessagesTreeView(dwScope);
00206     cmdl = new MessageModel(dwScope);
00207     tv->setModel(cmdl);
00208     dwScope->setWidget(tv);
00209     addDockWidget(Qt::LeftDockWidgetArea, dwScope);
00210 
00211     me = new MessageEditor(cmdl, this);
00212     //setCentralWidget(me);
00213     ptv = me->phraseView();
00214     pmdl = qobject_cast<PhraseModel *>(ptv->model());
00215 
00216     connect(tv->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
00217              this, SLOT(showNewCurrent(QModelIndex,QModelIndex)));
00218 
00219     connect(cmdl, SIGNAL(languageChanged(QLocale::Language)), this, SLOT(updateLanguage(QLocale::Language)));
00220 
00221     m_translatedlg = new TranslateDialog(this);
00222     m_batchTranslateDlg = new BatchTranslationDialog(cmdl, this);
00223     m_translationSettingsDialog = 0;
00224     finddlg = new FindDialog(this);
00225     findMatchCase = false;
00226     findWhere = 0;
00227     foundWhere = 0;
00228     foundOffset = 0;
00229 
00230     setupMenuBar();
00231     setupToolBars();
00232     // We can't call setCentralWidget(me), since it is already called in m_ui.setupUi()
00233     QBoxLayout *lout = new QBoxLayout(QBoxLayout::TopToBottom, m_ui.centralwidget);
00234     lout->addWidget(me);
00235     lout->setMargin(0);
00236     m_ui.centralwidget->setLayout(lout);
00237 
00238     progress = new QLabel(statusBar());
00239     statusBar()->addPermanentWidget(progress);
00240     modified = new QLabel(QString(" %1 ").arg(tr("MOD")), statusBar());
00241     statusBar()->addPermanentWidget(modified);
00242 
00243     updateProgress();
00244     updateCaption();
00245 
00246 
00247     connect(tv, SIGNAL(clicked(QModelIndex)),
00248         this, SLOT(toggleFinished(QModelIndex)));
00249     connect(me, SIGNAL(translationChanged(QStringList)),
00250         this, SLOT(updateTranslation(QStringList)));
00251     connect(me, SIGNAL(finished(bool)), this, SLOT(updateFinished(bool)));
00252     connect(me, SIGNAL(prevUnfinished()), this, SLOT(prevUnfinished()));
00253     connect(me, SIGNAL(nextUnfinished()), this, SLOT(nextUnfinished()));
00254     connect(me, SIGNAL(focusSourceList()), this, SLOT(focusSourceList()));
00255     connect(me, SIGNAL(focusPhraseList()), this, SLOT(focusPhraseList()));
00256     connect(finddlg, SIGNAL(findNext(QString,int,bool)),
00257         this, SLOT(findNext(QString,int,bool)));
00258     connect(m_translatedlg, SIGNAL( translateAndFindNext(QString,QString,int,int,bool) ),
00259         this, SLOT( translateAndFindNext(QString,QString,int,int,bool) ));
00260 
00261     connect(tv->header(), SIGNAL(sectionClicked(int)),
00262         tv, SLOT(clearSelection()));
00263 
00264     tv->setWhatsThis(tr("This panel lists the source contexts."));
00265 
00266     QSize as( qApp->desktop()->size() );
00267     as -= QSize( 30, 30 );
00268     resize( QSize( 1000, 800 ).boundedTo( as ) );
00269     readConfig();
00270     stats = 0;
00271 
00272     QWidget::setTabOrder(ptv, tv);
00273 }
00274 
00275 void TrWindow::updateLanguage(QLocale::Language lang)
00276 {
00277     QStringList forms;
00278     QByteArray rules;
00279 
00280     getNumerusInfo(lang, cmdl->country(), &rules, &forms);
00281     me->setNumerusForms(tr("Translation"), forms);
00282 }
00283 
00284 TrWindow::~TrWindow()
00285 {
00286     writeConfig();
00287     cmdl->clearContextList();
00288     delete stats;
00289     delete m_previewTool;
00290 }
00291 
00292 void TrWindow::openFile( const QString& name )
00293 {
00294     if (name.isEmpty())
00295         return;
00296 
00297     statusBar()->showMessage(tr("Loading..."));
00298     qApp->processEvents();
00299 
00300     if (!cmdl->load(name)) {
00301         statusBar()->clearMessage();
00302         QMessageBox::warning(this, tr("Qt Linguist"), tr("Cannot open '%1'.").arg(name));
00303         return;
00304     }
00305 
00306     MessageItem *m;
00307     for (MessageModel::iterator it = cmdl->begin() ; (m = it.current()) ; ++it) {
00308         updateDanger(m);
00309     }
00310 
00311     tv->clearSelection();
00312 
00313     setEnabled(true);
00314     updateProgress();
00315     filename = name;
00316     
00317     updateCaption();
00318 
00319     me->showNothing();
00320 
00321     m_ui.actionDoneAndNext->setEnabled(false);
00322     m_ui.actionPreviewForm->setEnabled(true);
00323 
00324     statusBar()->showMessage(tr("%n source phrase(s) loaded.", 0, cmdl->getMessageCount()), MessageMS);
00325     foundWhere = 0;
00326     foundOffset = 0;
00327 
00328     if (cmdl->contextsInList() > 0) {
00329         m_ui.actionFind->setEnabled(true);
00330         m_ui.actionFindNext->setEnabled(false);
00331         m_ui.actionTranslationFileSettings->setEnabled(true);
00332         m_ui.actionBatchTranslation->setEnabled(true);
00333         m_ui.actionSearchAndTranslate->setEnabled(true);
00334     }
00335 
00336     addRecentlyOpenedFile(name, recentFiles);
00337     updateStatistics();
00338 }
00339 
00340 void TrWindow::open()
00341 {
00342     if (maybeSave()) {
00343         QString newFilename = QFileDialog::getOpenFileName( this, QString(), filename,
00344             tr("Qt translation source (*.ts)\nAll files (*)"));
00345         openFile(newFilename);
00346     }
00347 }
00348 
00349 void TrWindow::save()
00350 {
00351     if (filename.isEmpty())
00352         return;
00353 
00354     if (cmdl->save(filename)) {
00355         updateCaption();
00356         statusBar()->showMessage(tr("File saved."), MessageMS);
00357     } else {
00358         QMessageBox::warning(this, tr("Qt Linguist"), tr("Cannot save '%1'.").arg(filename));
00359     }
00360 }
00361 
00362 void TrWindow::saveAs()
00363 {
00364     QString newFilename = QFileDialog::getSaveFileName(this, QString(), filename,
00365         tr( "Qt translation source (*.ts)\nAll files (*)"));
00366     if (!newFilename.isEmpty()) {
00367         filename = newFilename;
00368         save();
00369         updateCaption();
00370     }
00371 }
00372 
00373 void TrWindow::releaseAs()
00374 {
00375     QString newFilename = filename;
00376     newFilename.replace(QRegExp(".ts$"), "");
00377     newFilename += QString(".qm");
00378 
00379     newFilename = QFileDialog::getSaveFileName(this, tr("Release"), newFilename,
00380         tr("Qt message files for released applications (*.qm)\nAll files (*)"));
00381     if (!newFilename.isEmpty()) {
00382         if (cmdl->release(newFilename, false, false, Translator::Everything))
00383             statusBar()->showMessage(tr("File created."), MessageMS);
00384         else
00385             QMessageBox::warning(this, tr("Qt Linguist"), tr("Cannot save '%1'.").arg(newFilename));
00386     }
00387 }
00388 
00389 // No-question
00390 void TrWindow::release()
00391 {
00392     QString newFilename = filename;
00393     newFilename.replace(QRegExp(".ts$"), "");
00394     newFilename += QString(".qm");
00395 
00396     if (!newFilename.isEmpty()) {
00397         if (cmdl->release(newFilename, false, false, Translator::Everything))
00398             statusBar()->showMessage(tr("File created."), MessageMS);
00399         else
00400             QMessageBox::warning(this, tr("Qt Linguist"), tr("Cannot save '%1'.").arg(newFilename));
00401     }
00402 }
00403 
00404 void TrWindow::print()
00405 {
00406     int pageNum = 0;
00407     QList <ContextItem *> ctxtList;
00408     QList <MessageItem *> msgList;
00409     const MessageItem *m;
00410     ContextItem *c;
00411 
00412     QPrintDialog dlg(&printer, this);
00413     if (dlg.exec()) {
00414         QApplication::setOverrideCursor(Qt::WaitCursor);
00415         printer.setDocName(filename);
00416         statusBar()->showMessage(tr("Printing..."));
00417         PrintOut pout(&printer);
00418         ctxtList = cmdl->contextList();
00419 
00420         for (int i=0; i<ctxtList.count(); i++) {
00421             c = ctxtList.at(i);
00422             pout.vskip();
00423             pout.setRule(PrintOut::ThickRule);
00424             pout.setGuide(c->context());
00425             pout.addBox(100, tr("Context: %1").arg(c->context()),
00426                 PrintOut::Strong);
00427             pout.flushLine();
00428             pout.addBox(4);
00429             pout.addBox(92, c->comment(), PrintOut::Emphasis);
00430             pout.flushLine();
00431             pout.setRule(PrintOut::ThickRule);
00432 
00433             msgList = c->messageItemList();
00434             for (int j=0; j<msgList.count(); j++) {
00435                 m = msgList.at(j);
00436                 pout.setRule(PrintOut::ThinRule);
00437 
00438                 QString type;
00439                 switch (m->message().type()) {
00440                 case MetaTranslatorMessage::Finished:
00441                     type = tr("finished");
00442                     break;
00443                 case MetaTranslatorMessage::Unfinished:
00444                     type = m->danger() ? tr("unresolved") : QString("unfinished");
00445                     break;
00446                 case MetaTranslatorMessage::Obsolete:
00447                     type = tr("obsolete");
00448                     break;
00449                 default:
00450                     type = QString("");
00451                 }
00452                 pout.addBox(40, m->sourceText());
00453                 pout.addBox(4);
00454                 pout.addBox(40, m->translation());
00455                 pout.addBox(4);
00456                 pout.addBox(12, type, PrintOut::Normal, Qt::AlignRight);
00457                 if (!m->comment().isEmpty()) {
00458                     pout.flushLine();
00459                     pout.addBox(4);
00460                     pout.addBox(92, m->comment(), PrintOut::Emphasis);
00461                 }
00462                 pout.flushLine(true);
00463 
00464                 if (pout.pageNum() != pageNum) {
00465                     pageNum = pout.pageNum();
00466                     statusBar()->showMessage(tr("Printing... (page %1)")
00467                         .arg(pageNum));
00468                 }
00469             }
00470         }
00471         pout.flushLine(true);
00472         QApplication::restoreOverrideCursor();
00473         statusBar()->showMessage(tr("Printing completed"), MessageMS);
00474     } else {
00475         statusBar()->showMessage(tr("Printing aborted"), MessageMS);
00476     }
00477 }
00478 
00479 void TrWindow::find()
00480 {
00481     finddlg->show();
00482     finddlg->activateWindow();
00483     finddlg->raise();
00484 }
00485 
00486 void TrWindow::findAgain()
00487 {
00488     if (cmdl->contextsInList() <= 0)
00489         return;
00490 
00491     int pass = 0;
00492     int scopeNo = 0;
00493     int itemNo = 0;
00494 
00495 
00496     QModelIndex indxItem = tv->currentIndex();
00497     if (indxItem.isValid())
00498         itemNo = indxItem.row();
00499     QModelIndex indxScope = tv->currentIndex().parent();
00500     if (indxScope.isValid())
00501         scopeNo = indxScope.row();
00502 
00503     QString delayedMsg;
00504 
00505     //scopeNo = foundScope;
00506     ContextItem *c = cmdl->contextItem(cmdl->index(scopeNo, 1));
00507     MessageItem *m; // = c->messageItem(foundItem);
00508 
00509 #if 1
00510     /*
00511       As long as we don't implement highlighting of the text in the QTextView,
00512       we may have only one match per message.
00513     */
00514     foundOffset = (int) 0x7fffffff;
00515 #else
00516     foundOffset++;
00517 #endif
00518 
00519     // We want to search the scope we started from *again*, since we did not necessarily search that *completely* when we started.
00520     // (Problaby we started somewhere in the middle of it.)
00521     // Therefore, "pass <=" and not "pass < " 
00522     while (pass <= cmdl->contextsInList()) {
00523         for (int mit = itemNo; mit < c->messageItemsInList() ; ++mit) {
00524             m = c->messageItem(mit);
00525             switch (foundWhere) {
00526                 case 0:
00527                     foundWhere = FindDialog::SourceText;
00528                     foundOffset = 0;
00529                     // fall-through
00530                 case FindDialog::SourceText:
00531                     if (searchItem(m->sourceText(), scopeNo, mit)) {
00532                         finddlg->hide();
00533                         if (!delayedMsg.isEmpty())
00534                             statusBar()->showMessage(delayedMsg, MessageMS);
00535                         return;
00536                     }
00537                     foundWhere = FindDialog::Translations;
00538                     foundOffset = 0;
00539                     // fall-through
00540                 case FindDialog::Translations:
00541                     if (searchItem(m->translation(), scopeNo, mit)) {
00542                         finddlg->hide();
00543                         if (!delayedMsg.isEmpty())
00544                             statusBar()->showMessage(delayedMsg, MessageMS);
00545                         return;
00546                     }
00547                     foundWhere = FindDialog::Comments;
00548                     foundOffset = 0;
00549                     // fall-through
00550                 case FindDialog::Comments: // what about comments in messages?
00551                     if (searchItem(c->fullContext(), scopeNo, mit)) {
00552                         finddlg->hide();
00553                         if (!delayedMsg.isEmpty())
00554                             statusBar()->showMessage(delayedMsg, MessageMS);
00555                         return;
00556                     }
00557                     foundWhere = 0;
00558                     foundOffset = 0;
00559             }
00560         }
00561         itemNo = 0;
00562         ++pass;
00563 
00564         ++scopeNo;
00565         if (scopeNo >= cmdl->contextsInList()) {
00566             scopeNo = 0;
00567             delayedMsg = tr("Search wrapped.");
00568         }
00569 
00570         c = cmdl->contextItem(cmdl->index(scopeNo, 1));
00571     }
00572 
00573     qApp->beep();
00574     QMessageBox::warning( finddlg, tr("Qt Linguist"),
00575                           QString( tr("Cannot find the string '%1'.") ).arg(findText));
00576 //    foundItem   = 0;
00577     foundWhere  = 0;
00578     foundOffset = 0;
00579 }
00580 
00581 void TrWindow::showTranslateDialog()
00582 {
00583     m_translatedlg->show();
00584     m_translatedlg->activateWindow();
00585     m_translatedlg->raise();
00586 }
00587 
00588 void TrWindow::showBatchTranslateDialog()
00589 {
00590     QList<PhraseBook> frasebooks = phraseBooks[PhraseEditMenu].values();
00591     m_batchTranslateDlg->setPhraseBooks(frasebooks);
00592     m_batchTranslateDlg->exec();
00593     
00594 }
00595 
00596 void TrWindow::translateAndFindNext(const QString& findWhat, const QString &translateTo, 
00597                                     int matchOption, int mode, bool markFinished)
00598 {
00599     findText = findWhat;
00600     m_translateTo = translateTo;
00601     findMatchCase = matchOption & TranslateDialog::MatchCase;
00602     m_markFinished = markFinished;
00603     m_findMatchSubstring = false;
00604 
00605     translate(mode);
00606 }
00607 
00608 void TrWindow::translate(int mode)
00609 {
00610     int itemNo = 0;
00611     int scopeNo = 0;
00612     QModelIndex indxItem = tv->currentIndex();
00613     if (indxItem.isValid())
00614         itemNo = indxItem.row();      // The for-loop condition for the ContextItem will rule this potential overflow on itemNo
00615     QModelIndex indxScope = tv->currentIndex().parent();
00616     if (indxScope.isValid()) {
00617         scopeNo = indxScope.row();
00618     }else{
00619         scopeNo = itemNo;
00620         itemNo = 0;
00621     }
00622 
00623     int translatedCount = 0;
00624     bool found = false;
00625 
00626 
00627     MessageModel::iterator it = cmdl->Iterator(scopeNo, itemNo);
00628     switch (mode) {
00629     case TranslateDialog::TranslateAll:
00630         {
00631             int passes = cmdl->getMessageCount();
00632             while (passes > 0) {
00633                 MessageItem *m = it.current();
00634                 if (!m) {
00635                     it.reset();
00636                     m = it.current();
00637                 }
00638                 if (m && m->compare(findText, m_findMatchSubstring, findMatchCase ? Qt::CaseSensitive : Qt::CaseInsensitive)) {
00639                     cmdl->setTranslation(it, m_translateTo);
00640                     if (indxScope.isValid() && it.contextNo() == scopeNo && it.messageNo() == itemNo)
00641                         me->setTranslation(m_translateTo, 0, false);
00642                     updateFinished(it.contextNo(), it.messageNo(), m_markFinished);
00643                     ++translatedCount;
00644                 }
00645                 ++it;
00646                 --passes;
00647             }
00648             found = translatedCount == 0 ? false : true;
00649             if (found) {
00650                 QMessageBox::warning( m_translatedlg, tr("Translate"),
00651                                   QString( tr("Translated %n entries to '%1'", 0, translatedCount).arg(m_translateTo) ));
00652             }
00653         }
00654         break;
00655     case TranslateDialog::Translate:
00656         {
00657             MessageItem *m = it.current();
00658             if (m && m->compare(findText, m_findMatchSubstring, findMatchCase ? Qt::CaseSensitive : Qt::CaseInsensitive)) {
00659                 cmdl->setTranslation(it, m_translateTo);
00660                 updateFinished(it.contextNo(), it.messageNo(), m_markFinished);
00661                 ++translatedCount;
00662             }
00663         }
00664     case TranslateDialog::Skip:
00665         {
00666             ++it;
00667             int passes = cmdl->getMessageCount() - 1;
00668             while (passes > 0) {
00669                 MessageItem *m = it.current();
00670                 if (!m) {
00671                     it.reset();
00672                     m = it.current();
00673                 }
00674                 if (m && m->compare(findText, m_findMatchSubstring, findMatchCase ? Qt::CaseSensitive : Qt::CaseInsensitive)) {
00675                     found = true;
00676                     break;
00677                 }
00678                 ++it;
00679                 --passes;
00680             }
00681         }
00682         break;
00683     }
00684 
00685     if (found) {
00686         QModelIndex cidx = cmdl->index(it.contextNo(),0);
00687         if (cidx.isValid()) {
00688             setCurrentMessage(cmdl->index(it.messageNo(),0, cidx));
00689         }
00690     } else {
00691         qApp->beep();
00692         QMessageBox::warning( m_translatedlg, tr("Qt Linguist"),
00693                               QString( tr("Cannot find the string '%1'.") ).arg(findText) );
00694     }
00695 }
00696 
00697 bool TrWindow::searchItem(const QString &searchWhat, int c, int m)
00698 {
00699     if ((findWhere & foundWhere) != 0) {
00700         foundOffset = searchWhat.indexOf(findText, foundOffset,
00701             findMatchCase ? Qt::CaseSensitive : Qt::CaseInsensitive);
00702         if (foundOffset >= 0) {
00703             QModelIndex cidx = cmdl->index(c,0);
00704             setCurrentMessage(cmdl->index(m,0, cidx));
00705             return true;
00706         }
00707     }
00708     foundOffset = 0;
00709     return false;
00710 }
00711 
00712 void TrWindow::newPhraseBook()
00713 {
00714     QString name;
00715     for (;;) {
00716         name = QFileDialog::getSaveFileName(this, tr("Create New Phrase Book"),
00717             QString(), tr("Qt phrase books (*.qph)\nAll files (*)"));
00718         if (name.isEmpty())
00719             break;
00720         else if (!QFile::exists(name)) {
00721             break;
00722             QMessageBox::warning(this, tr("Qt Linguist"),
00723                 tr("A file called '%1' already exists."
00724                 "  Please choose another name.").arg(name));
00725         }
00726     }
00727     if (!name.isEmpty()) {
00728         PhraseBook pb;
00729         if (savePhraseBook(name, pb)) {
00730             if (openPhraseBook(name))
00731                 statusBar()->showMessage(tr("Phrase book created."), MessageMS);
00732         }
00733     }
00734 }
00735 
00736 bool TrWindow::phraseBooksContains(QString name)
00737 {
00738     foreach(PhraseBook pb, phraseBooks[PhraseCloseMenu]) {
00739         if (pb.fileName() == name)
00740             return true;
00741     }
00742 
00743     return false;
00744 }
00745 
00746 PhraseBook TrWindow::phraseBookFromFileName(QString name) const
00747 {
00748     foreach(PhraseBook pb, phraseBooks[PhraseCloseMenu]) {
00749         if (pb.fileName() == name)
00750             return pb;
00751     }
00752 
00753     return PhraseBook(); // empty phrasebook
00754 }
00755 
00756 void TrWindow::openPhraseBook()
00757 {
00758     QString phrasebooks(QLibraryInfo::location(QLibraryInfo::DataPath));
00759     QString name = QFileDialog::getOpenFileName(this, tr("Open Phrase Book"),
00760         phrasebooks + "/phrasebooks", tr("Qt phrase books (*.qph)\nAll files (*)"));
00761     //### The phrasebooks are not stored here!!
00762     if (!name.isEmpty() && !phraseBooksContains(name)) {
00763         if (openPhraseBook(name)) {
00764             int n = phraseBookFromFileName(name).count();
00765             statusBar()->showMessage(tr("%n phrase(s) loaded.", 0, n), MessageMS);
00766         }
00767     }
00768 }
00769 
00770 void TrWindow::closePhraseBook(QAction *action)
00771 {
00772     PhraseBook pb = phraseBooks[PhraseCloseMenu].value(action);
00773     phraseBooks[PhraseCloseMenu].remove(action);
00774     m_ui.menuClosePhraseBook->removeAction(action);
00775 
00776     QAction *act = phraseBooks[PhraseEditMenu].key(pb);
00777     phraseBooks[PhraseEditMenu].remove(act);
00778     m_ui.menuEditPhraseBook->removeAction(act);
00779 
00780     act = phraseBooks[PhrasePrintMenu].key(pb);
00781     m_ui.menuPrintPhraseBook->removeAction(act);
00782 
00783     updatePhraseDict();
00784     m_ui.actionBatchTranslation->setEnabled(phraseBooks[PhraseCloseMenu].count() > 0);
00785 }
00786 
00787 void TrWindow::editPhraseBook(QAction *action)
00788 {
00789     PhraseBook pb = phraseBooks[PhraseEditMenu].value(action);
00790     PhraseBookBox box(pb.fileName(), pb, this);
00791     box.setWindowTitle(tr("%1 - %2").arg(tr("Qt Linguist"))
00792         .arg(pb.friendlyPhraseBookName()));
00793     box.resize(500, 300);
00794     box.exec();
00795 
00796     // delete phrasebook from all menus before changing
00797     // this avoids detachment
00798     phraseBooks[PhraseEditMenu].remove(action);
00799     QAction *closeact = phraseBooks[PhraseCloseMenu].key(pb);
00800     phraseBooks[PhraseCloseMenu].remove(closeact);
00801     QAction *printact = phraseBooks[PhrasePrintMenu].key(pb);
00802     phraseBooks[PhrasePrintMenu].remove(printact);
00803 
00804     phraseBooks[PhraseEditMenu].insert(action, box.phraseBook());
00805     phraseBooks[PhraseCloseMenu].insert(closeact, box.phraseBook());
00806     phraseBooks[PhrasePrintMenu].insert(printact, box.phraseBook());
00807 
00808     updatePhraseDict();
00809 }
00810 
00811 void TrWindow::printPhraseBook(QAction *action)
00812 {
00813     PhraseBook phraseBook = phraseBooks[PhrasePrintMenu].value(action);
00814 
00815     int pageNum = 0;
00816 
00817     QPrintDialog dlg(&printer, this);
00818     if (dlg.exec()) {
00819         printer.setDocName(phraseBook.fileName());
00820         statusBar()->showMessage(tr("Printing..."));
00821         PrintOut pout(&printer);
00822         pout.setRule(PrintOut::ThinRule);
00823         foreach (Phrase p, phraseBook) {
00824             pout.setGuide(p.source());
00825             pout.addBox(29, p.source());
00826             pout.addBox(4);
00827             pout.addBox(29, p.target());
00828             pout.addBox(4);
00829             pout.addBox(34, p.definition(), PrintOut::Emphasis);
00830 
00831             if (pout.pageNum() != pageNum) {
00832                 pageNum = pout.pageNum();
00833                 statusBar()->showMessage(tr("Printing... (page %1)")
00834                     .arg(pageNum));
00835             }
00836             pout.setRule(PrintOut::NoRule);
00837             pout.flushLine(true);
00838         }
00839         pout.flushLine(true);
00840         statusBar()->showMessage(tr("Printing completed"), MessageMS);
00841     } else {
00842         statusBar()->showMessage(tr("Printing aborted"), MessageMS);
00843     }
00844 }
00845 
00846 void TrWindow::revertSorting()
00847 {
00848     if (cmdl->contextsInList() < 0)
00849         return;
00850 
00851     tv->clearSelection();
00852     tv->header()->setSortIndicator(1, Qt::AscendingOrder);
00853     tv->header()->setSortIndicatorShown(true);
00854     cmdl->sort(1, Qt::AscendingOrder);
00855     //mmdl->setContextItem(0);
00856 
00857     foreach(ContextItem *c, cmdl->contextList()) {
00858         c->sortMessages(1, Qt::AscendingOrder);
00859     }
00860 }
00861 
00862 void TrWindow::manual()
00863 {
00864     if (!ac)
00865         ac = new QAssistantClient(QLibraryInfo::location(QLibraryInfo::BinariesPath), this);
00866     ac->showPage(QLibraryInfo::location(QLibraryInfo::DocumentationPath) +
00867                  "/html/linguist-manual.html");
00868 }
00869 
00870 void TrWindow::about()
00871 {
00872 
00873     QMessageBox box(this);
00874     box.setTextFormat(Qt::RichText);
00875     QString version = tr("Version %1");
00876 #if QT_EDITION == QT_EDITION_OPENSOURCE
00877     QString open = tr(" Open Source Edition");
00878     version.append(open);
00879 #endif
00880     version = version.arg(QT_VERSION_STR);
00881 
00882     QString edition =
00883 #if QT_EDITION == QT_EDITION_OPENSOURCE
00884                     tr("This version of Qt Linguist is part of the Qt Open Source Edition, for use "
00885                     "in the development of Open Source applications. "
00886                     "Qt is a comprehensive C++ framework for cross-platform application "
00887                     "development.<br/><br/>"
00888                     "You need a commercial Qt license for development of proprietary (closed "
00889                     "source) applications. Please see <tt>http://www.trolltech.com/company/model"
00890                     ".html</tt> for an overview of Qt licensing.");
00891 #else
00892                     tr("This program is licensed to you under the terms of the "
00893                     "Qt Commercial License Agreement. For details, see the file LICENSE "
00894                     "that came with this software distribution.");
00895 #endif
00896     
00897     box.setText(tr("<center><img src=\":/images/splash.png\"/></img><p>%1</p></center>"
00898                     "<p>Qt Linguist is a tool for adding translations to Qt "
00899                     "applications.</p>"
00900                     "<p>%2</p>"
00901                     "<p>Copyright (C) 2000-2006 Trolltech ASA. All rights reserved."
00902                     "</p><p>The program is provided AS IS with NO WARRANTY OF ANY KIND,"
00903                     " INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A"
00904                     " PARTICULAR PURPOSE.</p>").arg(version).arg(edition));
00905     
00906     box.setWindowTitle(QApplication::translate("AboutDialog", "Qt Linguist"));
00907     box.setIcon(QMessageBox::NoIcon);
00908     box.exec();
00909 }
00910 
00911 void TrWindow::aboutQt()
00912 {
00913     QMessageBox::aboutQt(this, tr("Qt Linguist"));
00914 }
00915 
00916 void TrWindow::setupPhrase()
00917 {
00918     bool enabled = !phraseBooks[PhraseCloseMenu].isEmpty();
00919     m_ui.menuClosePhraseBook->setEnabled(enabled);
00920     m_ui.menuEditPhraseBook->setEnabled(enabled);
00921     m_ui.menuPrintPhraseBook->setEnabled(enabled);
00922 }
00923 
00924 void TrWindow::closeEvent(QCloseEvent *e)
00925 {
00926     if (maybeSave()) {
00927         e->accept();
00928         delete m_previewTool;
00929         m_previewTool = 0;
00930     } else {
00931         e->ignore();
00932     }
00933 }
00934 
00935 bool TrWindow::maybeSave()
00936 {
00937     if (cmdl->isModified()) {
00938         switch (QMessageBox::information(this, tr("Qt Linguist"),
00939             tr("Do you want to save '%1'?").arg(filename),
00940             QMessageBox::Yes | QMessageBox::Default,
00941             QMessageBox::No,
00942             QMessageBox::Cancel | QMessageBox::Escape))
00943         {
00944             case QMessageBox::Cancel:
00945                 return false;
00946             case QMessageBox::Yes:
00947                 save();
00948                 return !cmdl->isModified();
00949             case QMessageBox::No:
00950                 break;
00951         }
00952     }
00953     return true;
00954 }
00955 
00956 void TrWindow::updateCaption()
00957 {
00958     QString cap;
00959     bool enable = !filename.isEmpty();
00960     m_ui.actionSave->setEnabled(enable);
00961     m_ui.actionSaveAs->setEnabled(enable);
00962     m_ui.actionRelease->setEnabled(enable);
00963     m_ui.actionReleaseAs->setEnabled(enable);
00964     m_ui.actionPrint->setEnabled(enable);
00965     m_ui.actionAccelerators->setEnabled(enable);
00966     m_ui.actionEndingPunctuation->setEnabled(enable);
00967     m_ui.actionPhraseMatches->setEnabled(enable);
00968     m_ui.actionPlaceMarkerMatches->setEnabled(enable);
00969     m_ui.actionRevertSorting->setEnabled(enable);
00970 
00971     if (filename.isEmpty())
00972         cap = tr("Qt Linguist by Trolltech");
00973     else
00974         cap = tr("%1 - %2%3").arg( tr("Qt Linguist by Trolltech"))
00975         .arg(filename).arg(cmdl->isModified() ? "*" : "");
00976     setWindowTitle(cap);
00977     modified->setEnabled(cmdl->isModified());
00978 }
00979 
00980 void TrWindow::showNewCurrent(const QModelIndex &current, const QModelIndex &old)
00981 {
00982     if (current.isValid()) {
00983         MessageItem *m = cmdl->messageItem(current);
00984         ContextItem *c = cmdl->contextItem(current);
00985         if (m && c) {
00986             QStringList translations  = cmdl->normalizedTranslations(*m);
00987             me->showMessage(m->sourceText(), m->comment(), c->fullContext(),
00988                 translations, m->message().type(), getPhrases(m->sourceText()));
00989             if (m->danger())
00990                 printDanger(m);
00991             else
00992                 statusBar()->clearMessage();
00993 
00994             m_ui.actionDoneAndNext->setEnabled(m->message().type() !=
00995                 MetaTranslatorMessage::Obsolete);
00996         } else {
00997             me->showNothing();
00998             m_ui.actionDoneAndNext->setEnabled(false);
00999         }
01000     }
01001     else {
01002         me->showNothing();
01003         m_ui.actionDoneAndNext->setEnabled(false);
01004     }
01005 
01006     m_ui.actionSelectAll->setEnabled(m_ui.actionDoneAndNext->isEnabled());
01007 
01008     Q_UNUSED(old);
01009 }
01010 
01011 void TrWindow::updateTranslation(const QStringList &translations)
01012 {
01013     QModelIndex item = tv->currentIndex();
01014     if (!item.isValid())
01015         return;
01016 
01017     MessageItem *m = cmdl->messageItem(item);
01018     if (m) {
01019         if (translations != m->translations()) {
01020             m->setTranslations(translations);
01021             updateDanger(m, true);
01022             cmdl->updateItem(item);
01023 
01024             if (m->finished()) {
01025                 updateFinished(false);
01026             } else {
01027                 cmdl->setModified(true);
01028                 updateCaption();
01029             }
01030         }
01031     }
01032 }
01033 
01037 void TrWindow::updateTranslation(int context, int message, const QString &translation)
01038 {
01039     MessageItem *m = cmdl->messageItem(context, message);
01040 
01041     if (m && translation != m->translation()) {
01042         m->setTranslation(translation);
01043 
01044         updateDanger(m, true);
01045 
01046         if (m->finished())
01047             updateFinished(false);
01048         else
01049             updateCaption();
01050 
01051         // Notify the view(s)
01052         QModelIndex idx = cmdl->modelIndex(context, message);
01053         cmdl->updateItem(idx);
01054     }
01055 }
01056 
01057 void TrWindow::updateFinished(int context, int message, bool finished)
01058 {
01059     MessageItem *m = cmdl->messageItem(context, message);
01060     if (finished != m->finished()) {
01061         m->setFinished(finished);
01062         updateProgress();
01063         updateCaption();
01064         updateStatistics();
01065 
01066         // Notify the view(s)
01067         QModelIndex idx = cmdl->modelIndex(context, message);
01068         cmdl->updateItem(idx);
01069     }
01070 }
01071 
01072 
01073 void TrWindow::updateFinished(bool finished)
01074 {
01075     QModelIndex item = tv->currentIndex();
01076     if (!item.isValid())
01077         return;
01078     MessageItem *m = cmdl->messageItem(item);
01079     if (finished != m->finished()) {
01080         m->setFinished(finished);
01081         updateProgress();
01082         updateCaption();
01083         updateStatistics();
01084 
01085         cmdl->updateItem(item);
01086     }
01087 }
01088 
01089 void TrWindow::doneAndNext()
01090 {
01091     if (!tv->currentIndex().isValid())
01092         return;
01093 
01094     MessageItem *m = cmdl->messageItem(tv->currentIndex());
01095 
01096     if (!m->danger()) {
01097         updateFinished(true);
01098         nextUnfinished();
01099         me->setEditorFocus();
01100     }
01101     else {
01102         qApp->beep();
01103     }
01104 }
01105 
01106 void TrWindow::toggleFinished(const QModelIndex &index)
01107 {
01108     if ( !index.isValid() || (index.column() != 0) || (index.parent() == QModelIndex()) )
01109         return;
01110 
01111     MessageItem *m = cmdl->messageItem(index);
01112 
01113     if (m->message().type() == MetaTranslatorMessage::Obsolete)
01114         return;
01115 
01116     if (m->danger())
01117         printDanger(m);
01118 
01119     if (!m->danger() && !m->finished())
01120         updateFinished(true);
01121     else if (m->finished())
01122         updateFinished(false);
01123 }
01124 
01125 int TrWindow::findCurrentContextRow()
01126 {
01127     QModelIndex index = tv->selectionModel()->currentIndex();
01128     if (index.isValid())
01129         return index.row();
01130 
01131     //if no context is selected
01132     setCurrentContextRow(0);
01133     return 0;
01134 }
01135 
01136 bool TrWindow::setNextContext(int *currentrow, bool checkUnfinished)
01137 {
01138     QModelIndex mindx;
01139     ++(*currentrow);
01140 
01141     for (; *currentrow < cmdl->contextsInList(); ++(*currentrow)) {
01142         if (!checkUnfinished) {
01143             setCurrentContextRow(*currentrow);
01144             return true; //it is one more item
01145         }
01146 
01147         mindx = cmdl->index(*currentrow, 0);
01148         if (cmdl->contextItem(mindx)->unFinishedCount() > 0) {
01149             setCurrentContext(mindx);
01150             return true; // found a unfinished context
01151         }
01152     }
01153 
01154     return false; // done
01155 }
01156 
01157 bool TrWindow::setPrevContext(int *currentrow, bool checkUnfinished)
01158 {
01159     QModelIndex mindx;
01160     --(*currentrow);
01161 
01162     for (; *currentrow >= 0; --(*currentrow)) {
01163         if (!checkUnfinished) {
01164             setCurrentContextRow(*currentrow);
01165             return true; //it is one more item
01166         }
01167 
01168         mindx = cmdl->index(*currentrow, 0);
01169         if (cmdl->contextItem(mindx)->unFinishedCount() > 0) {
01170             setCurrentContext(mindx);
01171             return true; // found a unfinished context
01172         }
01173     }
01174 
01175     return false; // done
01176 }
01177 
01178 bool TrWindow::setNextMessage(QModelIndex *currentIndex, bool checkUnfinished)
01179 {
01180     bool found = false;
01181     if (currentIndex->isValid()) {
01182         QModelIndex idx = *currentIndex;
01183         do {
01184             int row = 0;
01185             QModelIndex par = idx.parent();
01186             if (par.isValid()) {
01187                 row = idx.row() + 1;
01188             } else {        //In case we are located on a top-level node
01189                 par = idx;
01190             }
01191 
01192             if (row >= cmdl->rowCount(par)) {
01193                 int toprow = par.row() + 1;
01194                 if (toprow >= cmdl->rowCount()) toprow = 0;
01195                 par = cmdl->index(toprow, 0);
01196                 row = 0;
01197                 idx = cmdl->index(row, 1, par);
01198             } else {
01199                 idx = cmdl->index(row, 1, par);
01200             }
01201             found = checkUnfinished ? !cmdl->finished(idx) : true;
01202             if (idx == *currentIndex) break;
01203         } while(!found);
01204 
01205         if (found) {
01206             *currentIndex = idx;
01207             tv->setCurrentIndex(*currentIndex);
01208         }
01209     }
01210     return found;
01211 }
01212 
01213 bool TrWindow::setPrevMessage(QModelIndex *currentIndex, bool checkUnfinished)
01214 {
01215     bool found = false;
01216     Q_ASSERT(currentIndex);
01217     QModelIndex idx = currentIndex->isValid() ? *currentIndex : cmdl->index(0, 0);
01218     do {
01219         int row = idx.row() - 1;
01220         QModelIndex par = idx.parent();
01221         if (!par.isValid()) {   //In case we are located on a top-level node
01222             par = idx;
01223             row = -1;
01224         }
01225 
01226         if (row < 0) {
01227             int toprow = par.row() - 1;
01228             if (toprow < 0) toprow = cmdl->rowCount() - 1;
01229             par = cmdl->index(toprow, 0);
01230             row = cmdl->rowCount(par) - 1;
01231             idx = cmdl->index(row, 1, par);
01232         } else {
01233             idx = cmdl->index(row, 1, par);
01234         }
01235         found = checkUnfinished ? !cmdl->finished(idx) : true;
01236         if (idx == *currentIndex) break;
01237     } while(!found);
01238 
01239     if (found) {
01240         *currentIndex = idx;
01241         tv->setCurrentIndex(*currentIndex);
01242     }
01243     return found;
01244 }
01245 
01246 void TrWindow::nextUnfinished()
01247 {
01248     if (m_ui.actionNextUnfinished->isEnabled()) {
01249         if (!next(true)) {
01250             // If no Unfinished message is left, the user has finished the job.  We
01251             // congratulate on a job well done with this ringing bell.
01252             statusBar()->showMessage(tr("No untranslated phrases left."), MessageMS);
01253             qApp->beep();
01254         }
01255     }
01256 }
01257 
01258 void TrWindow::prevUnfinished()
01259 {
01260     if (m_ui.actionNextUnfinished->isEnabled()) {
01261         if (!prev(true)) {
01262             // If no Unfinished message is left, the user has finished the job.  We
01263             // congratulate on a job well done with this ringing bell.
01264             statusBar()->showMessage(tr("No untranslated phrases left."), MessageMS);
01265             qApp->beep();
01266         }
01267     }
01268 }
01269 
01270 void TrWindow::prev()
01271 {
01272     prev(false);
01273 }
01274 
01275 bool TrWindow::prev(bool checkUnfinished)
01276 {
01277     QModelIndex current = tv->currentIndex();
01278     return setPrevMessage(&current, checkUnfinished);    
01279 }
01280 
01281 bool TrWindow::next(bool checkUnfinished)
01282 {
01283     QModelIndex current = tv->currentIndex();
01284     return setNextMessage(&current, checkUnfinished);
01285 }
01286 
01287 void TrWindow::next()
01288 {
01289     next(false);
01290 }
01291 
01292 
01293 void TrWindow::findNext(const QString &text, int where, bool matchCase)
01294 {
01295     if (text.isEmpty())
01296         return;
01297     findText = text;
01298     findWhere = where;
01299     findMatchCase = matchCase;
01300     m_ui.actionFindNext->setEnabled(true);
01301     findAgain();
01302 }
01303 
01304 void TrWindow::revalidate()
01305 {
01306     if (cmdl->contextsInList() <= 0)
01307         return;
01308 
01309     ContextItem *c;
01310     MessageItem *m;
01311 
01312     for (int ci=0; ci<cmdl->contextsInList(); ++ci) {
01313         c = cmdl->contextItem(cmdl->index(ci, 0));
01314         for (int mi=0; mi<c->messageItemsInList(); ++mi) {
01315             m = c->messageItem(mi);
01316             updateDanger(m);
01317             //if (cmdl->contextItem() == c)
01318             //    cmdl->updateItem(cmdl->index(mi, 0));
01319         }
01320         cmdl->updateItem(cmdl->index(ci, 0));
01321     }
01322 }
01323 
01324 QString TrWindow::friendlyString(const QString& str)
01325 {
01326     QString f = str.toLower();
01327     f.replace(QRegExp(QString("[.,:;!?()-]")), QString(" "));
01328     f.replace("&", QString(""));
01329     f = f.simplified();
01330     f = f.toLower();
01331     return f;
01332 }
01333 
01334 
01335 void TrWindow::setupMenuBar()
01336 {
01337     m_ui.setupUi(this);
01338     m_ui.actionAccelerators->setIcon(QIcon(rsrcString + "/accelerator.png"));
01339     m_ui.actionOpenPhraseBook->setIcon(QIcon(rsrcString + "/book.png"));
01340     m_ui.actionDoneAndNext->setIcon(QIcon(rsrcString + "/doneandnext.png"));
01341     m_ui.actionCopy->setIcon(QIcon(rsrcString + "/editcopy.png"));
01342     m_ui.actionCut->setIcon(QIcon(rsrcString + "/editcut.png"));
01343     m_ui.actionPaste->setIcon(QIcon(rsrcString + "/editpaste.png"));
01344     m_ui.actionOpen->setIcon(QIcon(rsrcString + "/fileopen.png"));
01345     m_ui.actionSave->setIcon(QIcon(rsrcString + "/filesave.png"));
01346     m_ui.actionNext->setIcon(QIcon(rsrcString + "/next.png"));
01347     m_ui.actionNextUnfinished->setIcon(QIcon(rsrcString + "/nextunfinished.png"));
01348     m_ui.actionPhraseMatches->setIcon(QIcon(rsrcString + "/phrase.png"));
01349     m_ui.actionEndingPunctuation->setIcon(QIcon(rsrcString + "/punctuation.png"));
01350     m_ui.actionPrev->setIcon(QIcon(rsrcString + "/prev.png"));
01351     m_ui.actionPrevUnfinished->setIcon(QIcon(rsrcString + "/prevunfinished.png"));
01352     m_ui.actionPrint->setIcon(QIcon(rsrcString + "/print.png"));
01353     m_ui.actionRedo->setIcon(QIcon(rsrcString + "/redo.png"));
01354     m_ui.actionFind->setIcon(QIcon(rsrcString + "/searchfind.png"));
01355     m_ui.actionUndo->setIcon(QIcon(rsrcString + "/undo.png"));
01356     m_ui.actionPlaceMarkerMatches->setIcon(QIcon(rsrcString + "/validateplacemarkers.png"));
01357     m_ui.actionWhatsThis->setIcon(QIcon(rsrcString + "/whatsthis.png"));
01358     
01359 
01360     // File menu
01361     connect(m_ui.actionOpen, SIGNAL(triggered()), this, SLOT(open()));
01362     connect(m_ui.actionSave, SIGNAL(triggered()), this, SLOT(save()));
01363     connect(m_ui.actionSaveAs, SIGNAL(triggered()), this, SLOT(saveAs()));
01364     connect(m_ui.actionRelease, SIGNAL(triggered()), this, SLOT(release()));
01365     connect(m_ui.actionReleaseAs, SIGNAL(triggered()), this, SLOT(releaseAs()));
01366     connect(m_ui.actionPrint, SIGNAL(triggered()), this, SLOT(print()));
01367     connect(m_ui.actionExit, SIGNAL(triggered()), this, SLOT(close()));
01368 
01369     // Edit menu
01370     connect(m_ui.actionUndo, SIGNAL(triggered()), me, SLOT(undo()));
01371     connect(me, SIGNAL(undoAvailable(bool)), m_ui.actionUndo, SLOT(setEnabled(bool)));
01372 
01373     connect(m_ui.actionRedo, SIGNAL(triggered()), me, SLOT(redo()));
01374     connect(me, SIGNAL(redoAvailable(bool)), m_ui.actionRedo, SLOT(setEnabled(bool)));
01375 
01376     connect(m_ui.actionCopy, SIGNAL(triggered()), me, SLOT(copy()));
01377     connect(me, SIGNAL(copyAvailable(bool)), m_ui.actionCopy, SLOT(setEnabled(bool)));
01378 
01379     connect(me, SIGNAL(cutAvailable(bool)), m_ui.actionCut, SLOT(setEnabled(bool)));
01380     connect(m_ui.actionCut, SIGNAL(triggered()), me, SLOT(cut()));
01381 
01382     connect(me, SIGNAL(pasteAvailable(bool)), m_ui.actionPaste, SLOT(setEnabled(bool)));
01383     connect(m_ui.actionPaste, SIGNAL(triggered()), me, SLOT(paste()));
01384 
01385     connect(m_ui.actionSelectAll, SIGNAL(triggered()), me, SLOT(selectAll()));
01386     connect(m_ui.actionFind, SIGNAL(triggered()), this, SLOT(find()));
01387     connect(m_ui.actionFindNext, SIGNAL(triggered()), this, SLOT(findAgain()));
01388     connect(m_ui.actionSearchAndTranslate, SIGNAL(triggered()), this, SLOT(showTranslateDialog()));
01389     connect(m_ui.actionBatchTranslation, SIGNAL(triggered()), this, SLOT(showBatchTranslateDialog()));
01390     
01391     connect( m_ui.actionTranslationFileSettings, SIGNAL(triggered()), this, SLOT(showTranslationSettings()) );
01392 
01393     // Translation menu
01394     // when updating the accelerators, remember the status bar
01395     connect(m_ui.actionPrevUnfinished, SIGNAL(triggered()), this, SLOT(prevUnfinished()));
01396     connect(m_ui.actionNextUnfinished, SIGNAL(triggered()), this, SLOT(nextUnfinished()));
01397     connect(m_ui.actionNext, SIGNAL(triggered()), this, SLOT(next()));
01398     connect(m_ui.actionPrev, SIGNAL(triggered()), this, SLOT(prev()));
01399     connect(m_ui.actionDoneAndNext, SIGNAL(triggered()), this, SLOT(doneAndNext()));
01400     connect(m_ui.actionBeginFromSource, SIGNAL(triggered()), me, SLOT(beginFromSource()));
01401     connect(me, SIGNAL(updateActions(bool)), m_ui.actionBeginFromSource, SLOT(setEnabled(bool)));
01402 
01403     // Phrasebook menu
01404     connect(m_ui.actionNewPhraseBook, SIGNAL(triggered()), this, SLOT(newPhraseBook()));
01405     connect(m_ui.actionOpenPhraseBook, SIGNAL(triggered()), this, SLOT(openPhraseBook()));
01406     connect(m_ui.menuClosePhraseBook, SIGNAL(triggered(QAction*)),
01407         this, SLOT(closePhraseBook(QAction*)));
01408     connect(m_ui.menuEditPhraseBook, SIGNAL(triggered(QAction*)),
01409         this, SLOT(editPhraseBook(QAction*)));
01410     connect(m_ui.menuPrintPhraseBook, SIGNAL(triggered(QAction*)),
01411         this, SLOT(printPhraseBook(QAction*)));
01412 
01413     // Validation menu
01414     connect(m_ui.actionAccelerators, SIGNAL(triggered()), this, SLOT(revalidate()));
01415     connect(m_ui.actionEndingPunctuation, SIGNAL(triggered()), this, SLOT(revalidate()));
01416     connect(m_ui.actionPhraseMatches, SIGNAL(triggered()), this, SLOT(revalidate()));
01417     connect(m_ui.actionPlaceMarkerMatches, SIGNAL(triggered()), this, SLOT(revalidate()));
01418 
01419     // View menu
01420     connect(m_ui.actionRevertSorting, SIGNAL(triggered()), this, SLOT(revertSorting()));
01421     connect(m_ui.actionDisplayGuesses, SIGNAL(triggered()), this, SLOT(toggleGuessing()));
01422     connect(m_ui.actionStatistics, SIGNAL(triggered()), this, SLOT(toggleStatistics()));
01423     connect(m_ui.menuView, SIGNAL(aboutToShow()), this, SLOT(updateViewMenu()));
01424     m_ui.menuViewViews->addAction( dwScope->toggleViewAction() );
01425     m_ui.menuViewViews->addAction( me->phraseDockWnd()->toggleViewAction() );
01426 
01427     // Tools menu
01428     connect(m_batchTranslateDlg, SIGNAL(finished()), this, SLOT(finishedBatchTranslation()));
01429     connect(m_ui.actionPreviewForm, SIGNAL(triggered()), this, SLOT(previewForm()));
01430 
01431 #if defined(Q_WS_MAC)
01432     // Window menu
01433     QMenu *windowMenu = new QMenu(tr("&Window"), this);
01434     menuBar()->insertMenu(m_ui.menuHelp->menuAction(), windowMenu);
01435     windowMenu->addAction(tr("Minimize"), this,
01436         SLOT(showMinimized()), QKeySequence(tr("Ctrl+M")));
01437 #endif
01438 
01439     // Help
01440     connect(m_ui.actionManual, SIGNAL(triggered()), this, SLOT(manual()));
01441     connect(m_ui.actionAbout, SIGNAL(triggered()), this, SLOT(about()));
01442     connect(m_ui.actionAboutQt, SIGNAL(triggered()), this, SLOT(aboutQt()));
01443     connect(m_ui.actionWhatsThis, SIGNAL(triggered()), this, SLOT(onWhatsThis()));
01444 
01445     connect(m_ui.menuFile, SIGNAL(aboutToShow()), this,
01446         SLOT(setupRecentFilesMenu()));
01447     connect(m_ui.menuRecentlyOpenedFiles, SIGNAL(triggered(QAction*)), this,
01448         SLOT(recentFileActivated(QAction*)));
01449 
01450     m_ui.actionManual->setWhatsThis(tr("Display the manual for %1.").arg(tr("Qt Linguist")));
01451     m_ui.actionAbout->setWhatsThis(tr("Display information about %1.").arg(tr("Qt Linguist")));
01452     m_ui.actionDoneAndNext->setShortcuts(QList<QKeySequence>()
01453                                             << QKeySequence("Ctrl+Return")
01454                                             << QKeySequence("Ctrl+Enter"));
01455 
01456     // Disable the Close/Edit/Print phrasebook menuitems if they are not loaded
01457     connect(m_ui.menuPhrases, SIGNAL(aboutToShow()), this, SLOT(setupPhrase()));
01458 }
01459 
01460 void TrWindow::updateViewMenu()
01461 {
01462     if (stats)
01463         m_ui.actionStatistics->setChecked(stats->isVisible());
01464     else
01465         m_ui.actionStatistics->setChecked(false);
01466 }
01467 
01468 void TrWindow::onWhatsThis()
01469 {
01470     QWhatsThis::enterWhatsThisMode();
01471 }
01472 
01473 void TrWindow::setupToolBars()
01474 {
01475     QToolBar *filet = new QToolBar(this);
01476     filet->setObjectName("FileToolbar");
01477     filet->setWindowTitle(tr("File"));
01478   this->addToolBar(filet);
01479     m_ui.menuToolbars->addAction(filet->toggleViewAction());
01480 
01481     QToolBar *editt = new QToolBar(this);
01482     editt->setVisible(false);
01483     editt->setObjectName("EditToolbar");
01484     editt->setWindowTitle(tr("Edit"));
01485     this->addToolBar(editt);
01486     m_ui.menuToolbars->addAction(editt->toggleViewAction());
01487 
01488     QToolBar *translationst = new QToolBar(this);
01489     translationst->setObjectName("TranslationToolbar");
01490     translationst->setWindowTitle(tr("Translation"));
01491   this->addToolBar(translationst);
01492     m_ui.menuToolbars->addAction(translationst->toggleViewAction());
01493 
01494     QToolBar *validationt = new QToolBar(this);
01495     validationt->setObjectName("ValidationToolbar");
01496     validationt->setWindowTitle(tr("Validation"));
01497   this->addToolBar(validationt);
01498     m_ui.menuToolbars->addAction(validationt->toggleViewAction());
01499 
01500     QToolBar *helpt = new QToolBar(this);
01501     helpt->setVisible(false);
01502     helpt->setObjectName("HelpToolbar");
01503     helpt->setWindowTitle(tr("Help"));
01504   this->addToolBar(helpt);
01505     m_ui.menuToolbars->addAction(helpt->toggleViewAction());
01506 
01507 
01508     filet->addAction(m_ui.actionOpen);
01509     filet->addAction(m_ui.actionSave);
01510     filet->addAction(m_ui.actionPrint);
01511     filet->addSeparator();
01512     filet->addAction(m_ui.actionOpenPhraseBook);
01513 
01514     editt->addAction(m_ui.actionUndo);
01515     editt->addAction(m_ui.actionRedo);
01516     editt->addSeparator();
01517     editt->addAction(m_ui.actionCut);
01518     editt->addAction(m_ui.actionCopy);
01519     editt->addAction(m_ui.actionPaste);
01520     editt->addSeparator();
01521     editt->addAction(m_ui.actionFind);
01522 
01523     translationst->addAction(m_ui.actionPrev);
01524     translationst->addAction(m_ui.actionNext);
01525     translationst->addAction(m_ui.actionPrevUnfinished);
01526     translationst->addAction(m_ui.actionNextUnfinished);
01527     translationst->addAction(m_ui.actionDoneAndNext);
01528 
01529     validationt->addAction(m_ui.actionAccelerators);
01530     validationt->addAction(m_ui.actionEndingPunctuation);
01531     validationt->addAction(m_ui.actionPhraseMatches);
01532     validationt->addAction(m_ui.actionPlaceMarkerMatches);
01533 
01534     helpt->addAction(m_ui.actionWhatsThis);
01535 
01536 }
01537 
01538 void TrWindow::setCurrentContext(const QModelIndex &indx)
01539 {
01540     tv->setCurrentIndex(indx);
01541     tv->scrollTo(indx);
01542 }
01543 
01544 void TrWindow::setCurrentContextRow(int row)
01545 {
01546     QModelIndex mdlI = cmdl->index(row,1);
01547     tv->setCurrentIndex(mdlI);
01548     tv->scrollTo(mdlI);
01549 }
01550 
01551 void TrWindow::setCurrentMessage(const QModelIndex &indx)
01552 {
01553     tv->setCurrentIndex(indx);
01554     tv->scrollTo(indx);
01555 }
01556 
01557 bool TrWindow::openPhraseBook(const QString& name)
01558 {
01559     PhraseBook pb;
01560     if (!pb.load(name)) {
01561         QMessageBox::warning(this, tr("Qt Linguist"),
01562             tr("Cannot read from phrase book '%1'.").arg(name));
01563         return false;
01564     }
01565 
01566     QAction *a = m_ui.menuClosePhraseBook->addAction(pb.friendlyPhraseBookName());
01567     phraseBooks[PhraseCloseMenu].insert(a, pb);
01568     a->setWhatsThis(tr("Close this phrase book."));
01569 
01570     a = m_ui.menuEditPhraseBook->addAction(pb.friendlyPhraseBookName());
01571     phraseBooks[PhraseEditMenu].insert(a, pb);
01572     a->setWhatsThis(tr("Allow you to add, modify, or delete"
01573         " phrases of this phrase book."));
01574 
01575     a = m_ui.menuPrintPhraseBook->addAction(pb.friendlyPhraseBookName());
01576     phraseBooks[PhrasePrintMenu].insert(a, pb);
01577     a->setWhatsThis(tr("Print the entries of the phrase"
01578         " book."));
01579     
01580     updatePhraseDict();
01581     m_ui.actionBatchTranslation->setEnabled(phraseBooks[PhraseCloseMenu].count() > 0);
01582     return true;
01583 }
01584 
01585 bool TrWindow::savePhraseBook(QString &name, const PhraseBook &pb)
01586 {
01587     if (!name.contains(".qph") && !name.contains("."))
01588         name += ".qph";
01589 
01590     if (!pb.save(name)) {
01591         QMessageBox::warning(this, tr("Qt Linguist"),
01592             tr("Cannot create phrase book '%1'.").arg(name));
01593         return false;
01594     }
01595     return true;
01596 }
01597 
01598 void TrWindow::updateProgress()
01599 {
01600     int numNonobsolete = cmdl->getNumNonobsolete();
01601     int numFinished = cmdl->getNumFinished();
01602     if (numNonobsolete == 0)
01603         progress->setText(QString("    " "    "));
01604     else
01605         progress->setText(QString(" %1/%2 ").arg(numFinished)
01606         .arg(numNonobsolete));
01607     m_ui.actionPrevUnfinished->setEnabled(numFinished != numNonobsolete);
01608     m_ui.actionNextUnfinished->setEnabled(numFinished != numNonobsolete);
01609 
01610     m_ui.actionPrev->setEnabled(cmdl->contextsInList() > 0);
01611     m_ui.actionNext->setEnabled(cmdl->contextsInList() > 0);
01612 }
01613 
01614 void TrWindow::updatePhraseDict()
01615 {
01616     phraseDict.clear();
01617 
01618     foreach (PhraseBook pb, phraseBooks[PhraseCloseMenu]) {
01619         foreach (Phrase p, pb) {
01620             QString f = friendlyString(p.source());
01621             if ( f.length() > 0 ) {
01622                 f = f.split(QChar(' ')).first();
01623                 if (!phraseDict.contains(f)) {
01624                     PhraseBook pbe;
01625                     phraseDict.insert(f, pbe);
01626                 }
01627                 phraseDict[f].append(p);
01628             }
01629         }
01630     }
01631     revalidate();
01632 }
01633 
01634 PhraseBook TrWindow::getPhrases(const QString &source)
01635 {
01636     PhraseBook phrases;
01637     QString f = friendlyString(source);
01638     QStringList lookupWords = f.split(QChar(' '));
01639 
01640     foreach (QString s, lookupWords) {
01641         if (phraseDict.contains(s)) {
01642             PhraseBook ent = phraseDict.value(s);
01643             foreach (Phrase p, ent) {
01644                 if (f.indexOf(friendlyString((p).source())) >= 0)
01645                     phrases.append(p);
01646             }
01647         }
01648     }
01649     return phrases;
01650 }
01651 
01652 void TrWindow::printDanger(MessageItem *m)
01653 {
01654     danger(m, true);
01655 }
01656 
01657 bool TrWindow::updateDanger(MessageItem *m, bool verbose)
01658 {
01659     bool dngr = danger(m, verbose);
01660 
01661     if (dngr != m->danger())
01662         m->setDanger(dngr);
01663 
01664     return dngr;
01665 }
01666 
01667 bool TrWindow::danger( const MessageItem *m,
01668                        bool verbose )
01669 {
01670     QString source = m->sourceText();
01671     QStringList translations = m->translations();
01672     if (m_ui.actionAccelerators->isChecked()) {
01673         bool sk = source.contains(Qt::Key_Ampersand);
01674         bool tk = true;
01675         for (int i = 0; i < translations.count() && tk; ++i) {
01676             tk &= bool(translations[i].contains(Qt::Key_Ampersand));
01677         }
01678 
01679         if (!sk && tk) {
01680             if (verbose)
01681                 statusBar()->showMessage(tr("Accelerator possibly superfluous in"
01682                                          " translation."), ErrorMS);
01683             return true;
01684         } else if (sk && !tk) {
01685             if (verbose)
01686                 statusBar()->showMessage(tr("Accelerator possibly missing in"
01687                                          " translation."), ErrorMS);
01688             return true;
01689         }
01690     }
01691     if (m_ui.actionEndingPunctuation->isChecked()) {
01692         bool endingok = true;
01693         for (int i = 0; i < translations.count() && endingok; ++i) {
01694             endingok &= (ending( source, cmdl->language()) == ending(translations[i], cmdl->language() ));
01695         }
01696 
01697         if (!endingok) {
01698             if (verbose)
01699                 statusBar()->showMessage(tr("Translation does not end with the"
01700                     " same punctuation as the source text."), ErrorMS);
01701             return true;
01702         }
01703     }
01704     if (m_ui.actionPhraseMatches->isChecked()) {
01705         QString fsource = friendlyString(source);
01706         QString ftranslation = friendlyString(translations.first());
01707         QStringList lookupWords = fsource.split(QChar(' '));
01708 
01709         bool phraseFound;
01710         foreach (QString s, lookupWords) {
01711             if (phraseDict.contains(s)) {
01712                 PhraseBook ent = phraseDict.value(s);
01713                 phraseFound = false;
01714                 foreach (Phrase p, ent) {
01715                     if (fsource.indexOf(friendlyString(p.source())) < 0 ||
01716                         ftranslation.indexOf(friendlyString(p.target())) >= 0) {
01717                         phraseFound = true;
01718                         break;
01719                     }
01720                 }
01721                 if (!phraseFound) {
01722                     if (verbose)
01723                         statusBar()->showMessage(tr("A phrase book suggestion for"
01724                             " '%1' was ignored.").arg(s), ErrorMS );
01725                     return true;
01726                 }
01727             }
01728         }
01729     }
01730 
01731     if (m_ui.actionPlaceMarkerMatches->isChecked()) {
01732         // Stores the occurence count of the place markers in the vector placeMarkerIndexes.
01733         // i.e. the occurence count of %1 is stored at placeMarkerIndexes[1], 
01734         // count of %2 is stored at placeMarkerIndexes[2] etc.
01735         // In the first pass, it counts all place markers in the sourcetext.
01736         // In the second pass it (de)counts all place markers in the translation.
01737         // When finished, all elements should have returned to a count of 0, if not there is a mismatch
01738         // between place markers in the source text and the translation text.
01739         QVector<int> placeMarkerIndexes;
01740         QString translation;
01741         int numTranslations = translations.count();
01742         for (int pass = 0; pass < numTranslations + 1; ++pass) {
01743             const QChar *uc_begin = source.unicode();
01744             const QChar *uc_end = uc_begin + source.length();
01745             if (pass >= 1) {
01746                 translation = translations[pass - 1];
01747                 uc_begin = translation.unicode();
01748                 uc_end = uc_begin + translation.length();
01749             }
01750             const QChar *c = uc_begin;
01751             while (c < uc_end) {
01752                 if (c->unicode() == '%') {
01753                     const QChar *escape_start = ++c;
01754                     while (c->isDigit()) ++c;
01755                     const QChar *escape_end = c;
01756                     bool ok = true;
01757                     int markerIndex = QString::fromRawData(escape_start, escape_end - escape_start).toInt(&ok);
01758                     if (ok) {
01759                         if (markerIndex >= placeMarkerIndexes.size()) {
01760                             placeMarkerIndexes.resize(markerIndex + 1);
01761                         }
01762                         placeMarkerIndexes[markerIndex]+= (pass == 0 ? numTranslations : -1);
01763                     }
01764                 }
01765                 ++c;
01766             }
01767         }
01768 
01769         for (int i = 0; i < placeMarkerIndexes.size(); ++i) {
01770             if (placeMarkerIndexes.at(i) != 0) {
01771                 if (verbose)
01772                     statusBar()->showMessage(tr("Translation does not refer"
01773                         " to the same place markers as in the source text."), ErrorMS);
01774                 return true;
01775 
01776             }
01777         }        
01778     }
01779     if (verbose)
01780         statusBar()->clearMessage();
01781 
01782     return false;
01783 }
01784 
01785 void TrWindow::readConfig()
01786 {
01787     QString keybase(QString::number((QT_VERSION >> 16) & 0xff)
01788                     + "." + QString::number((QT_VERSION >> 8) & 0xff) + "/");
01789     QSettings config;
01790 
01791     QRect r( pos(), size() );
01792     recentFiles = config.value(keybase + "RecentlyOpenedFiles").toStringList();
01793     restoreGeometry(config.value(keybase + "Geometry/WindowGeometry").toByteArray());
01794     restoreState(config.value(keybase + "MainWindowState").toByteArray());
01795 
01796     m_ui.actionAccelerators->setChecked(config.value(keybase+ "Validators/Accelerator", true).toBool());
01797     m_ui.actionEndingPunctuation->setChecked(config.value(keybase+ "Validators/EndingPunctuation", true).toBool());
01798     m_ui.actionPhraseMatches->setChecked(config.value(keybase+ "Validators/PhraseMatch", true).toBool());
01799     m_ui.actionPlaceMarkerMatches->setChecked(config.value(keybase+ "Validators/PlaceMarkers", true).toBool());
01800 }
01801 
01802 void TrWindow::writeConfig()
01803 {
01804     QString keybase(QString::number( (QT_VERSION >> 16) & 0xff ) +
01805                      "." + QString::number( (QT_VERSION >> 8) & 0xff ) + "/" );
01806     QSettings config;
01807     config.setValue(keybase + "RecentlyOpenedFiles", recentFiles);
01808     config.setValue(keybase + "Geometry/WindowGeometry", saveGeometry());
01809     config.setValue(keybase+ "Validators/Accelerator", m_ui.actionAccelerators->isChecked());
01810     config.setValue(keybase+ "Validators/EndingPunctuation", m_ui.actionEndingPunctuation->isChecked());
01811     config.setValue(keybase+ "Validators/PhraseMatch", m_ui.actionPhraseMatches->isChecked());
01812     config.setValue(keybase+ "Validators/PlaceMarkers", m_ui.actionPlaceMarkerMatches->isChecked());
01813     config.setValue(keybase + "MainWindowState", saveState());
01814 }
01815 
01816 void TrWindow::setupRecentFilesMenu()
01817 {
01818     m_ui.menuRecentlyOpenedFiles->clear();
01819 
01820     if (recentFiles.count() > 0) {
01821         m_ui.menuRecentlyOpenedFiles->setEnabled(true);
01822         QStringList::Iterator it = recentFiles.begin();
01823         for (; it != recentFiles.end(); ++it) {
01824             m_ui.menuRecentlyOpenedFiles->addAction(*it);
01825         }
01826     } else {
01827         m_ui.menuRecentlyOpenedFiles->setEnabled(false);
01828     }
01829 }
01830 
01831 void TrWindow::recentFileActivated(QAction *action)
01832 {
01833     if (!action->text().isEmpty()) {
01834         if (maybeSave())
01835             openFile(action->text());
01836     }
01837 }
01838 
01839 void TrWindow::addRecentlyOpenedFile(const QString &fn, QStringList &lst)
01840 {
01841     QFileInfo fi(fn);
01842     if (lst.contains(fi.absoluteFilePath()))
01843         return;
01844     if ( lst.count() >= 10 )
01845         lst.removeLast();
01846 
01847     lst.prepend(fi.absoluteFilePath());
01848 }
01849 
01850 void TrWindow::toggleGuessing()
01851 {
01852     me->toggleGuessing();
01853 }
01854 
01855 void TrWindow::focusSourceList()
01856 {
01857     stv->setFocus();
01858 }
01859 
01860 void TrWindow::focusPhraseList()
01861 {
01862     ptv->setFocus();
01863 }
01864 
01865 void TrWindow::toggleStatistics()
01866 {
01867     if (m_ui.actionStatistics->isChecked()) {
01868         if (!stats) {
01869             stats = new Statistics(this);
01870             connect(cmdl, SIGNAL(statsChanged(int,int,int,int,int,int)), stats,
01871                 SLOT(updateStats(int,int,int,int,int,int)));
01872         }
01873         stats->show();
01874         updateStatistics();
01875     }
01876     else if (stats) {
01877         stats->close();
01878     }
01879 }
01880 
01881 void TrWindow::updateStatistics()
01882 {
01883     // don't call this if stats dialog is not open
01884     // because this can be slow...
01885     if (!stats || !stats->isVisible())
01886         return;
01887 
01888     cmdl->updateStatistics();
01889 }
01890 
01891 void TrWindow::finishedBatchTranslation()
01892 {
01893     updateStatistics();
01894     updateProgress();
01895     updateCaption();
01896 }
01897 
01898 QStringList TrWindow::findFormFilesInCurrentTranslationFile()
01899 {
01900     QStringList ret;
01901     for (MessageModel::iterator it = cmdl->begin(); it != cmdl->end(); ++it) {
01902         QString fileName = (*it)->message().fileName();
01903         if (fileName.endsWith(QLatin1String(".ui"))) {
01904             if (!ret.contains(fileName)) {
01905                 ret+=fileName;
01906             }
01907         }
01908     }
01909     return ret;
01910 }
01911 
01912 void TrWindow::previewForm()
01913 {
01914     if (m_previewTool.isNull()) {
01915         m_previewTool = new TrPreviewTool();
01916         QStringList fileNames = findFormFilesInCurrentTranslationFile();
01917         bool ok = true;
01918         for (QStringList::iterator it = fileNames.begin(); it != fileNames.end(); ++it) {
01919             QString fileName = *it;
01920             if (!fileName.isEmpty() && QFileInfo(fileName).exists()) {
01921                 if (!m_previewTool->addFormFile(fileName)) {
01922                     ok = false;
01923                     break;
01924                 }
01925             }
01926         }
01927         if (ok) {
01928             ok = m_previewTool->addTranslator(cmdl->translator(), QFileInfo(filename).fileName());
01929             if (ok) {
01930                 m_previewTool->cascade();
01931             } else {
01932                 QMessageBox::warning(this, tr("Qt Linguist"), tr("There was a problem in the preparation of form preview."));
01933             }
01934         }
01935     } else {
01936         // Only do a refresh if it is already open
01937         m_previewTool->reloadTranslations();
01938     }
01939     m_previewTool->show();
01940 }
01941 
01942 void TrWindow::showTranslationSettings()
01943 {
01944     if (!m_translationSettingsDialog) {
01945         m_translationSettingsDialog = new TranslationSettingsDialog(this);
01946     }
01947     m_translationSettingsDialog->setMessageModel(cmdl);
01948     m_translationSettingsDialog->exec();
01949 }

Generated on Thu Mar 15 12:01:46 2007 for Qt 4.2 User's Guide by  doxygen 1.5.1