5
6
7
28#include <QApplication>
37#include <QInputDialog>
38#include <QItemDelegate>
41#include <QLibraryInfo>
47#include <QRegularExpression>
51#include <QSortFilterProxyModel>
52#include <QStackedWidget>
59#if QT_CONFIG(printsupport)
60#include <QPrintDialog>
80 return fileName.endsWith(QLatin1String(
".ui"))
81 || fileName.endsWith(QLatin1String(
".jui"));
87 for (; i < str.size(); i++) {
88 if (!str[i].isSpace()) {
99 if (!str[i].isSpace()) {
103 return str.mid(i + 1);
108 str = str.simplified();
112 switch (str.at(str.size() - 1).unicode()) {
114 if (str.endsWith(QLatin1String(
"...")))
138 return lang == QLocale::Greek ? End_Interrobang : End_None;
155 void paint(QPainter *painter,
const QStyleOptionViewItem &option,
156 const QModelIndex &index)
const override
158 const QAbstractItemModel *model = index.model();
161 if (!model->parent(index).isValid()) {
163 QStyleOptionViewItem opt = option;
164 opt.font.setBold(
true);
165 QItemDelegate::paint(painter, opt, index);
169 QItemDelegate::paint(painter, option, index);
178 static const QVariant v =
179 QVariant::fromValue(QPixmap(QLatin1String(
":/images/s_check_obsolete.png")));
191 if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
193 case 0:
return QString();
194 case 1:
return MainWindow::tr(
"Source text");
195 case 2:
return MainWindow::tr(
"Index");
198 if (role == Qt::DecorationRole && orientation == Qt::Horizontal && section - 1 < m_dataModel->modelCount())
215 if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
217 case 0:
return QString();
218 case 1:
return MainWindow::tr(
"Context");
219 case 2:
return MainWindow::tr(
"Items");
220 case 3:
return MainWindow::tr(
"Index");
223 if (role == Qt::DecorationRole && orientation == Qt::Horizontal && section - 1 < m_dataModel->modelCount())
247 if (event->type() == QEvent::FocusIn)
254 m_assistantProcess(0),
256 m_translationSettingsDialog(0),
257 m_settingCurrentMessage(
false),
258 m_fileActiveModel(-1),
259 m_editActiveModel(-1),
262 setUnifiedTitleAndToolBarOnMac(
true);
265#if !defined(Q_OS_MACOS) && !defined(Q_OS_WIN)
266 setWindowIcon(QPixmap(QLatin1String(
":/images/appicon.png") ));
269 m_dataModel =
new MultiDataModel(
this);
270 m_messageModel =
new MessageModel(
this, m_dataModel);
273 m_contextDock =
new QDockWidget(
this);
274 m_contextDock->setObjectName(QLatin1String(
"ContextDockWidget"));
275 m_contextDock->setAllowedAreas(Qt::AllDockWidgetAreas);
276 m_contextDock->setWindowTitle(tr(
"Context"));
277 m_contextDock->setAcceptDrops(
true);
278 m_contextDock->installEventFilter(
this);
280 m_sortedContextsModel =
new SortedContextsModel(
this, m_dataModel);
281 m_sortedContextsModel->setSortRole(MessageModel::SortRole);
282 m_sortedContextsModel->setSortCaseSensitivity(Qt::CaseInsensitive);
283 m_sortedContextsModel->setSourceModel(m_messageModel);
285 m_contextView =
new QTreeView(
this);
286 m_contextView->setRootIsDecorated(
false);
287 m_contextView->setItemsExpandable(
false);
288 m_contextView->setUniformRowHeights(
true);
289 m_contextView->setAlternatingRowColors(
true);
290 m_contextView->setAllColumnsShowFocus(
true);
291 m_contextView->setItemDelegate(
new ContextItemDelegate(
this, m_dataModel));
292 m_contextView->setSortingEnabled(
true);
293 m_contextView->setWhatsThis(tr(
"This panel lists the source contexts."));
294 m_contextView->setModel(m_sortedContextsModel);
295 m_contextView->header()->setSectionsMovable(
false);
296 m_contextView->setColumnHidden(0,
true);
297 m_contextView->header()->setStretchLastSection(
false);
299 m_contextDock->setWidget(m_contextView);
302 m_messagesDock =
new QDockWidget(
this);
303 m_messagesDock->setObjectName(QLatin1String(
"StringsDockWidget"));
304 m_messagesDock->setAllowedAreas(Qt::AllDockWidgetAreas);
305 m_messagesDock->setWindowTitle(tr(
"Strings"));
306 m_messagesDock->setAcceptDrops(
true);
307 m_messagesDock->installEventFilter(
this);
309 m_sortedMessagesModel =
new SortedMessagesModel(
this, m_dataModel);
310 m_sortedMessagesModel->setSortRole(MessageModel::SortRole);
311 m_sortedMessagesModel->setSortCaseSensitivity(Qt::CaseInsensitive);
312 m_sortedMessagesModel->setSortLocaleAware(
true);
313 m_sortedMessagesModel->setSourceModel(m_messageModel);
315 m_messageView =
new QTreeView(m_messagesDock);
316 m_messageView->setSortingEnabled(
true);
317 m_messageView->setRootIsDecorated(
false);
318 m_messageView->setUniformRowHeights(
true);
319 m_messageView->setAllColumnsShowFocus(
true);
320 m_messageView->setItemsExpandable(
false);
321 m_messageView->setModel(m_sortedMessagesModel);
322 m_messageView->header()->setSectionsMovable(
false);
323 m_messageView->setColumnHidden(0,
true);
325 m_messagesDock->setWidget(m_messageView);
328 m_messageEditor =
new MessageEditor(m_dataModel,
this);
329 m_messageEditor->setAcceptDrops(
true);
330 m_messageEditor->installEventFilter(
this);
332 QBoxLayout *lout =
new QBoxLayout(QBoxLayout::TopToBottom, m_ui.centralwidget);
333 lout->addWidget(m_messageEditor);
334 lout->setContentsMargins(QMargins());
335 m_ui.centralwidget->setLayout(lout);
338 m_phrasesDock =
new QDockWidget(
this);
339 m_phrasesDock->setObjectName(QLatin1String(
"PhrasesDockwidget"));
340 m_phrasesDock->setAllowedAreas(Qt::AllDockWidgetAreas);
341 m_phrasesDock->setWindowTitle(tr(
"Phrases and guesses"));
343 m_phraseView =
new PhraseView(m_dataModel, &m_phraseDict,
this);
344 m_phrasesDock->setWidget(m_phraseView);
347 m_sourceAndFormDock =
new QDockWidget(
this);
348 m_sourceAndFormDock->setObjectName(QLatin1String(
"SourceAndFormDock"));
349 m_sourceAndFormDock->setAllowedAreas(Qt::AllDockWidgetAreas);
350 m_sourceAndFormDock->setWindowTitle(tr(
"Sources and Forms"));
351 m_sourceAndFormView =
new QStackedWidget(
this);
352 m_sourceAndFormDock->setWidget(m_sourceAndFormView);
353 m_formPreviewView =
new FormPreviewView(0, m_dataModel);
354 m_sourceCodeView =
new SourceCodeView(0);
355 m_sourceAndFormView->addWidget(m_sourceCodeView);
356 m_sourceAndFormView->addWidget(m_formPreviewView);
359 m_errorsDock =
new QDockWidget(
this);
360 m_errorsDock->setObjectName(QLatin1String(
"ErrorsDockWidget"));
361 m_errorsDock->setAllowedAreas(Qt::AllDockWidgetAreas);
362 m_errorsDock->setWindowTitle(tr(
"Warnings"));
363 m_errorsView =
new ErrorsView(m_dataModel,
this);
364 m_errorsDock->setWidget(m_errorsView);
367 setDockNestingEnabled(
true);
368 setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
369 setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
370 setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
371 setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
372 addDockWidget(Qt::LeftDockWidgetArea, m_contextDock);
373 addDockWidget(Qt::TopDockWidgetArea, m_messagesDock);
374 addDockWidget(Qt::BottomDockWidgetArea, m_phrasesDock);
375 addDockWidget(Qt::TopDockWidgetArea, m_sourceAndFormDock);
376 addDockWidget(Qt::BottomDockWidgetArea, m_errorsDock);
381 m_messageEditor->installEventFilter(m_phraseView);
384 QShortcut *contextShortcut =
new QShortcut(QKeySequence(Qt::Key_F6),
this);
385 connect(contextShortcut, &QShortcut::activated,
386 this, &MainWindow::showContextDock);
387 QShortcut *messagesShortcut =
new QShortcut(QKeySequence(Qt::Key_F7),
this);
388 connect(messagesShortcut, &QShortcut::activated,
389 this, &MainWindow::showMessagesDock);
390 QShortcut *errorsShortcut =
new QShortcut(QKeySequence(Qt::Key_F8),
this);
391 connect(errorsShortcut, &QShortcut::activated,
392 this, &MainWindow::showErrorDock);
393 QShortcut *sourceCodeShortcut =
new QShortcut(QKeySequence(Qt::Key_F9),
this);
394 connect(sourceCodeShortcut, &QShortcut::activated,
395 this, &MainWindow::showSourceCodeDock);
396 QShortcut *phrasesShortcut =
new QShortcut(QKeySequence(Qt::Key_F10),
this);
397 connect(phrasesShortcut, &QShortcut::activated,
398 this, &MainWindow::showPhrasesDock);
400 connect(m_phraseView, &PhraseView::phraseSelected,
401 m_messageEditor, &MessageEditor::setTranslation);
403 this, &
MainWindow::setCurrentMessageFromGuess);
404 connect(m_contextView->selectionModel(), &QItemSelectionModel::currentRowChanged,
405 this, &MainWindow::selectedContextChanged);
406 connect(m_messageView->selectionModel(), &QItemSelectionModel::currentRowChanged,
407 this, &MainWindow::selectedMessageChanged);
408 connect(m_contextView->selectionModel(), &QItemSelectionModel::currentColumnChanged,
409 this, &MainWindow::updateLatestModel);
410 connect(m_messageView->selectionModel(), &QItemSelectionModel::currentColumnChanged,
411 this, &MainWindow::updateLatestModel);
416 m_translateDialog =
new TranslateDialog(
this);
417 m_batchTranslateDialog =
new BatchTranslationDialog(m_dataModel,
this);
418 m_findDialog =
new FindDialog(
this);
423 m_progressLabel =
new QLabel();
424 statusBar()->addPermanentWidget(m_progressLabel);
425 m_modifiedLabel =
new QLabel(tr(
" MOD ",
"status bar: file(s) modified"));
426 statusBar()->addPermanentWidget(m_modifiedLabel);
432 connect(m_dataModel, &MultiDataModel::modifiedChanged,
433 this, &QWidget::setWindowModified);
434 connect(m_dataModel, &MultiDataModel::modifiedChanged,
435 m_modifiedLabel, &QWidget::setVisible);
448 connect(m_messageView, &QAbstractItemView::clicked,
449 this, &MainWindow::toggleFinished);
450 connect(m_messageView, &QAbstractItemView::activated,
451 m_messageEditor, &MessageEditor::setEditorFocus);
452 connect(m_contextView, &QAbstractItemView::activated,
453 m_messageView, qOverload<>(&QWidget::setFocus));
454 connect(m_messageEditor, &MessageEditor::translationChanged,
455 this, &MainWindow::updateTranslation);
456 connect(m_messageEditor, &MessageEditor::translatorCommentChanged,
457 this, &MainWindow::updateTranslatorComment);
458 connect(m_findDialog, &FindDialog::findNext,
459 this, &MainWindow::findNext);
460 connect(m_translateDialog, &TranslateDialog::requestMatchUpdate,
461 this, &MainWindow::updateTranslateHit);
462 connect(m_translateDialog, &TranslateDialog::activated,
465 QSize as(screen()->size());
467 resize(QSize(1000, 800).boundedTo(as));
472 connect(m_ui.actionLengthVariants, &QAction::toggled,
473 m_messageEditor, &MessageEditor::setLengthVariants);
474 m_messageEditor->setLengthVariants(m_ui.actionLengthVariants->isChecked());
475 m_messageEditor->setVisualizeWhitespace(m_ui.actionVisualizeWhitespace->isChecked());
477 m_focusWatcher =
new FocusWatcher(m_messageEditor,
this);
478 m_contextView->installEventFilter(m_focusWatcher);
479 m_messageView->installEventFilter(m_focusWatcher);
480 m_messageEditor->installEventFilter(m_focusWatcher);
481 m_sourceAndFormView->installEventFilter(m_focusWatcher);
482 m_phraseView->installEventFilter(m_focusWatcher);
483 m_errorsView->installEventFilter(m_focusWatcher);
489 if (m_assistantProcess && m_assistantProcess->state() == QProcess::Running) {
490 m_assistantProcess->terminate();
491 m_assistantProcess->waitForFinished(3000);
493 qDeleteAll(m_phraseBooks);
496#if QT_CONFIG(printsupport)
503 m_contextView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
504 m_contextView->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
505 m_messageView->setColumnHidden(2,
true);
513 for (
int i = 0; i < mc; ++i) {
514 m_contextView->header()->setSectionResizeMode(i + 1, QHeaderView::Fixed);
515 m_contextView->header()->resizeSection(i + 1, 24);
517 m_messageView->header()->setSectionResizeMode(i + 1, QHeaderView::Fixed);
518 m_messageView->header()->resizeSection(i + 1, 24);
522 selectedMessageChanged(QModelIndex(), QModelIndex());
523 doUpdateLatestModel(-1);
525 if (!m_contextView->currentIndex().isValid()) {
527 m_contextView->setCurrentIndex(m_sortedContextsModel->index(0, 0));
530 m_contextView->selectionModel()->select(m_contextView->currentIndex(),
531 QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
532 m_messageView->selectionModel()->select(m_messageView->currentIndex(),
533 QItemSelectionModel::SelectCurrent|QItemSelectionModel::Rows);
538 doUpdateLatestModel(0);
539 else if (m_currentIndex
.model() >= mc)
540 doUpdateLatestModel(mc - 1);
543 m_contextView->setUpdatesEnabled(
true);
544 m_messageView->setUpdatesEnabled(
true);
549 m_ui.actionFind->setEnabled(m_dataModel->contextCount() > 0);
550 m_ui.actionFindNext->setEnabled(
false);
551 m_ui.actionFindPrev->setEnabled(
false);
569 bool waitCursor =
false;
570 statusBar()->showMessage(tr(
"Loading..."));
571 qApp->processEvents();
573 QList<OpenedFile> opened;
574 bool closeOld =
false;
575 for (QString name : names) {
577 QApplication::setOverrideCursor(Qt::WaitCursor);
581 bool readWrite = globalReadWrite;
582 if (name.startsWith(QLatin1Char(
'='))) {
588 name = fi.canonicalFilePath();
589 if (m_dataModel->isFileLoaded(name) >= 0)
593 DataModel *dm =
new DataModel(m_dataModel);
594 if (!dm->load(name, &langGuessed,
this)) {
598 if (opened.isEmpty()) {
599 if (!m_dataModel->isWellMergeable(dm)) {
600 QApplication::restoreOverrideCursor();
602 switch (QMessageBox::information(
this, tr(
"Loading File - Qt Linguist"),
603 tr(
"The file '%1' does not seem to be related to the currently open file(s) '%2'.\n\n"
604 "Close the open file(s) first?")
605 .arg(DataModel::prettifyPlainFileName(name), m_dataModel->condensedSrcFileNames(
true)),
606 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes))
608 case QMessageBox::Cancel:
611 case QMessageBox::Yes:
619 if (!opened.first().dataModel->isWellMergeable(dm)) {
620 QApplication::restoreOverrideCursor();
622 switch (QMessageBox::information(
this, tr(
"Loading File - Qt Linguist"),
623 tr(
"The file '%1' does not seem to be related to the file '%2'"
624 " which is being loaded as well.\n\n"
625 "Skip loading the first named file?")
626 .arg(DataModel::prettifyPlainFileName(name), opened.first().dataModel->srcFileName(
true)),
627 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes))
629 case QMessageBox::Cancel:
631 for (
const OpenedFile &op : std::as_const(opened))
634 case QMessageBox::Yes:
642 opened.append(OpenedFile(dm, readWrite, langGuessed));
647 QApplication::restoreOverrideCursor();
651 for (
const OpenedFile &op : std::as_const(opened))
657 for (
const OpenedFile &op : std::as_const(opened)) {
658 if (op.langGuessed) {
660 QApplication::restoreOverrideCursor();
663 if (!m_translationSettingsDialog)
664 m_translationSettingsDialog =
new TranslationSettingsDialog(
this);
665 m_translationSettingsDialog->setDataModel(op.dataModel);
666 m_translationSettingsDialog->exec();
671 QApplication::setOverrideCursor(Qt::WaitCursor);
672 m_contextView->setUpdatesEnabled(
false);
673 m_messageView->setUpdatesEnabled(
false);
675 for (
const OpenedFile &op : std::as_const(opened)) {
676 m_phraseDict.append(QHash<QString, QList<Phrase *> >());
677 m_dataModel->append(op.dataModel, op.readWrite);
679 updatePhraseDictInternal(m_phraseDict.size() - 1);
680 totalCount += op.dataModel->messageCount();
682 statusBar()->showMessage(tr(
"%n translation unit(s) loaded.", 0, totalCount), MessageMS);
687 QApplication::restoreOverrideCursor();
693 static RecentFiles recentFiles(10);
699 openFiles(pickTranslationFiles());
704 openFiles(pickTranslationFiles(),
false);
710 if (model >= 0 && maybeSave(model)) {
711 m_phraseDict.removeAt(model);
712 m_contextView->setUpdatesEnabled(
false);
713 m_messageView->setUpdatesEnabled(
false);
721 if (maybeSaveAll()) {
722 m_phraseDict.clear();
723 m_contextView->setUpdatesEnabled(
false);
724 m_messageView->setUpdatesEnabled(
false);
736 static const QString pattern(QLatin1String(
"%1 (*.%2);;"));
737 QStringList allExtensions;
739 for (
const Translator::FileFormat &format : std::as_const(Translator::registeredFileFormats())) {
740 if (format.fileType == Translator::FileFormat::TranslationSource && format.priority >= 0) {
741 filter.append(pattern.arg(format.description(), format.extension));
742 allExtensions.append(QLatin1String(
"*.") + format.extension);
745 QString allFilter = QObject::tr(
"Translation files (%1);;").arg(allExtensions.join(QLatin1Char(
' ')));
747 filter.prepend(allFilter);
749 filter.append(allFilter);
750 filter.append(QObject::tr(
"All files (*)"));
757 if (!recentFiles().isEmpty())
758 dir = QFileInfo(recentFiles().lastOpenedFile()).path();
762 QFileInfo mainFile(m_dataModel->srcFileName(0));
763 QString mainFileBase = mainFile.baseName();
764 int pos = mainFileBase.indexOf(QLatin1Char(
'_'));
766 varFilt = tr(
"Related files (%1);;")
767 .arg(mainFileBase.left(pos) + QLatin1String(
"_*.") + mainFile.completeSuffix());
770 return QFileDialog::getOpenFileNames(
this, tr(
"Open Translation Files"), dir,
777 QApplication::setOverrideCursor(Qt::WaitCursor);
778 if (m_dataModel->save(model,
this)) {
780 statusBar()->showMessage(tr(
"File saved."), MessageMS);
782 QApplication::restoreOverrideCursor();
798 saveInternal(m_currentIndex
.model());
806 QString newFilename = QFileDialog::getSaveFileName(
this, QString(), m_dataModel->srcFileName(m_currentIndex.model()),
808 if (!newFilename.isEmpty()) {
809 if (m_dataModel->saveAs(m_currentIndex.model(), newFilename,
this)) {
811 statusBar()->showMessage(tr(
"File saved."), MessageMS);
822 QFileInfo oldFile(m_dataModel->srcFileName(m_currentIndex.model()));
823 QString newFilename = oldFile.path() + QLatin1String(
"/")
824 + oldFile.completeBaseName() + QLatin1String(
".qm");
826 newFilename = QFileDialog::getSaveFileName(
this, tr(
"Release"), newFilename,
827 tr(
"Qt message files for released applications (*.qm)\nAll files (*)"));
828 if (!newFilename.isEmpty()) {
829 if (m_dataModel->release(m_currentIndex.model(), newFilename,
false,
false, SaveEverything,
this))
830 statusBar()->showMessage(tr(
"File created."), MessageMS);
836 QFileInfo oldFile(m_dataModel->srcFileName(model));
837 QString newFilename = oldFile.path() + QLatin1Char(
'/')
838 + oldFile.completeBaseName() + QLatin1String(
".qm");
840 if (!newFilename.isEmpty()) {
841 if (m_dataModel->release(model, newFilename,
false,
false, SaveEverything,
this))
842 statusBar()->showMessage(tr(
"File created."), MessageMS);
852 releaseInternal(m_currentIndex
.model());
862#if QT_CONFIG(printsupport)
863QPrinter *MainWindow::printer()
866 m_printer =
new QPrinter;
870void MainWindow::print()
873 QPrintDialog dlg(printer(),
this);
875 QApplication::setOverrideCursor(Qt::WaitCursor);
876 printer()->setDocName(m_dataModel->condensedSrcFileNames(
true));
877 statusBar()->showMessage(tr(
"Printing..."));
878 PrintOut pout(printer());
880 for (
int i = 0; i < m_dataModel->contextCount(); ++i) {
881 MultiContextItem *mc = m_dataModel->multiContextItem(i);
883 pout.setRule(PrintOut::ThickRule);
884 pout.setGuide(mc->context());
885 pout.addBox(100, tr(
"Context: %1").arg(mc->context()),
889 pout.addBox(92, mc->comment(), PrintOut::Emphasis);
891 pout.setRule(PrintOut::ThickRule);
893 for (
int j = 0; j < mc->messageCount(); ++j) {
894 pout.setRule(PrintOut::ThinRule);
895 bool printedSrc =
false;
897 for (
int k = 0; k < m_dataModel->modelCount(); ++k) {
898 if (
const MessageItem *m = mc->messageItem(k, j)) {
900 pout.addBox(40, m->text());
902 comment = m->comment();
907 if (m->message().isPlural() && m_dataModel->language(k) != QLocale::C) {
908 QStringList transls = m->translations();
909 pout.addBox(40, transls.join(QLatin1Char(
'\n')));
911 pout.addBox(40, m->translation());
915 switch (m->message().type()) {
916 case TranslatorMessage::Finished:
917 type = tr(
"finished");
919 case TranslatorMessage::Unfinished:
920 type = m->danger() ? tr(
"unresolved") : QLatin1String(
"unfinished");
922 case TranslatorMessage::Obsolete:
923 case TranslatorMessage::Vanished:
924 type = tr(
"obsolete");
927 pout.addBox(12, type, PrintOut::Normal, Qt::AlignRight);
931 if (!comment.isEmpty()) {
933 pout.addBox(92, comment, PrintOut::Emphasis);
934 pout.flushLine(
true);
937 if (pout.pageNum() != pageNum) {
938 pageNum = pout.pageNum();
939 statusBar()->showMessage(tr(
"Printing... (page %1)")
944 pout.flushLine(
true);
945 QApplication::restoreOverrideCursor();
946 statusBar()->showMessage(tr(
"Printing completed"), MessageMS);
948 statusBar()->showMessage(tr(
"Printing aborted"), MessageMS);
956 if ((m_findWhere & where) == 0)
959 QString text = searchWhat;
961 if (m_findOptions.testFlag(FindDialog::IgnoreAccelerators))
963 text.remove(QLatin1Char(
'&'));
965 if (m_findOptions.testFlag(FindDialog::UseRegExp))
966 return m_findDialog->getRegExp().match(text).hasMatch();
968 return text.indexOf(m_findText, 0, m_findOptions.testFlag(FindDialog::MatchCase)
969 ? Qt::CaseSensitive : Qt::CaseInsensitive) >= 0;
977 const QModelIndex &startIndex = m_messageView->currentIndex();
978 QModelIndex index = (direction == FindNext
979 ? nextMessage(startIndex)
980 : prevMessage(startIndex));
982 while (index.isValid()) {
983 QModelIndex realIndex = m_sortedMessagesModel->mapToSource(index);
984 MultiDataIndex dataIndex = m_messageModel->dataIndex(realIndex, -1);
985 bool hadMessage =
false;
988 if (m_findStatusFilter != -1 && m_findStatusFilter != m
->type())
991 if (m_findOptions.testFlag(FindDialog::SkipObsolete)
998 if (searchItem(DataModel::SourceText, m->text()))
1000 if (searchItem(DataModel::SourceText, m->pluralText()))
1002 if (searchItem(DataModel::Comments, m->comment()))
1004 if (searchItem(DataModel::Comments, m->extraComment()))
1007 const auto translations = m->translations();
1008 for (
const QString &trans : translations)
1009 if (searchItem(DataModel::Translations, trans))
1011 if (searchItem(DataModel::Comments, m->translatorComment()))
1018 setCurrentMessage(realIndex, i);
1021 const QModelIndex &c1 = m_sortedContextsModel->mapFromSource(
1022 m_sortedMessagesModel->mapToSource(startIndex)).parent();
1023 const QModelIndex &c2 = m_sortedContextsModel->mapFromSource(realIndex).parent();
1024 const QModelIndex &m = m_sortedMessagesModel->mapFromSource(realIndex);
1026 if (c2.row() < c1.row() || (c1.row() == c2.row() && m.row() <= startIndex.row()))
1027 statusBar()->showMessage(tr(
"Search wrapped."), MessageMS);
1029 m_findDialog->hide();
1037 if (index == startIndex)
1040 index = (direction == FindNext
1041 ? nextMessage(index)
1042 : prevMessage(index));
1046 QMessageBox::warning(m_findDialog, tr(
"Qt Linguist"),
1047 tr(
"Cannot find the string '%1'.").arg(m_findText));
1052 m_messageModel->blockSignals(
true);
1053 m_batchTranslateDialog->setPhraseBooks(m_phraseBooks, m_currentIndex.model());
1054 if (m_batchTranslateDialog->exec() != QDialog::Accepted)
1055 m_messageModel->blockSignals(
false);
1061 m_latestCaseSensitivity = -1;
1062 QModelIndex idx = m_messageView->currentIndex();
1063 QModelIndex idx2 = m_sortedMessagesModel->index(idx.row(), m_currentIndex.model() + 1, idx.parent());
1064 m_messageView->setCurrentIndex(idx2);
1065 QString fn = QFileInfo(m_dataModel->srcFileName(m_currentIndex.model())).baseName();
1066 m_translateDialog->setWindowTitle(tr(
"Search And Translate in '%1' - Qt Linguist").arg(fn));
1067 m_translateDialog->exec();
1070void MainWindow::updateTranslateHit(
bool &hit)
1075 && m->compare(m_translateDialog->findText(),
false, m_translateDialog->caseSensitivity());
1080 QString findText = m_translateDialog->findText();
1081 QString replaceText = m_translateDialog->replaceText();
1082 bool markFinished = m_translateDialog->markFinished();
1083 Qt::CaseSensitivity caseSensitivity = m_translateDialog->caseSensitivity();
1085 int translatedCount = 0;
1087 if (mode == TranslateDialog::TranslateAll) {
1090 if (m && !m->isObsolete() && m->compare(findText,
false, caseSensitivity)) {
1091 if (!translatedCount)
1092 m_messageModel->blockSignals(
true);
1093 m_dataModel->setTranslation(it, replaceText);
1098 if (translatedCount) {
1100 QMessageBox::warning(m_translateDialog, tr(
"Translate - Qt Linguist"),
1101 tr(
"Translated %n entry(s)", 0, translatedCount));
1104 if (mode == TranslateDialog::Translate) {
1105 m_dataModel->setTranslation(m_currentIndex, replaceText);
1109 if (findText != m_latestFindText || caseSensitivity != m_latestCaseSensitivity) {
1110 m_latestFindText = findText;
1111 m_latestCaseSensitivity = caseSensitivity;
1116 QModelIndex index = m_messageView->currentIndex();
1117 int prevRemained = m_remainingCount;
1119 if (--m_remainingCount <= 0) {
1122 m_remainingCount = m_dataModel->messageCount() - 1;
1123 if (QMessageBox::question(m_translateDialog, tr(
"Translate - Qt Linguist"),
1124 tr(
"No more occurrences of '%1'. Start over?").arg(findText),
1125 QMessageBox::Yes|QMessageBox::No) != QMessageBox::Yes)
1127 m_remainingCount -= prevRemained;
1130 index = nextMessage(index);
1132 QModelIndex realIndex = m_sortedMessagesModel->mapToSource(index);
1133 MultiDataIndex dataIndex = m_messageModel->dataIndex(realIndex, m_currentIndex.model());
1134 if (MessageItem *m = m_dataModel->messageItem(dataIndex)) {
1135 if (!m->isObsolete() && m->compare(findText,
false, caseSensitivity)) {
1136 setCurrentMessage(realIndex, m_currentIndex.model());
1145 if (!translatedCount) {
1147 QMessageBox::warning(m_translateDialog, tr(
"Translate - Qt Linguist"),
1148 tr(
"Cannot find the string '%1'.").arg(findText));
1154 QString name = QFileDialog::getSaveFileName(
this, tr(
"Create New Phrase Book"),
1155 m_phraseBookDir, tr(
"Qt phrase books (*.qph)\nAll files (*)"));
1156 if (!name.isEmpty()) {
1158 if (!m_translationSettingsDialog)
1159 m_translationSettingsDialog =
new TranslationSettingsDialog(
this);
1161 if (!m_translationSettingsDialog->exec())
1163 m_phraseBookDir = QFileInfo(name).absolutePath();
1164 if (savePhraseBook(&name, pb)) {
1165 if (doOpenPhraseBook(name))
1166 statusBar()->showMessage(tr(
"Phrase book created."), MessageMS);
1171bool MainWindow::isPhraseBookOpen(
const QString &name)
1173 for (
const PhraseBook *pb : std::as_const(m_phraseBooks)) {
1174 if (pb->fileName() == name)
1183 QString name = QFileDialog::getOpenFileName(
this, tr(
"Open Phrase Book"),
1184 m_phraseBookDir, tr(
"Qt phrase books (*.qph);;All files (*)"));
1186 if (!name.isEmpty()) {
1187 m_phraseBookDir = QFileInfo(name).absolutePath();
1188 if (!isPhraseBookOpen(name)) {
1189 if (
PhraseBook *phraseBook = doOpenPhraseBook(name)) {
1190 int n = phraseBook->phrases().size();
1191 statusBar()->showMessage(tr(
"%n phrase(s) loaded.", 0, n), MessageMS);
1197void MainWindow::closePhraseBook(QAction *action)
1199 PhraseBook *pb = m_phraseBookMenu[PhraseCloseMenu].value(action);
1200 if (!maybeSavePhraseBook(pb))
1203 m_phraseBookMenu[PhraseCloseMenu].remove(action);
1204 m_ui.menuClosePhraseBook->removeAction(action);
1206 QAction *act = m_phraseBookMenu[PhraseEditMenu].key(pb);
1207 m_phraseBookMenu[PhraseEditMenu].remove(act);
1208 m_ui.menuEditPhraseBook->removeAction(act);
1210 act = m_phraseBookMenu[PhrasePrintMenu].key(pb);
1211 m_ui.menuPrintPhraseBook->removeAction(act);
1213 m_phraseBooks.removeOne(pb);
1216 updatePhraseDicts();
1218 updatePhraseBookActions();
1221void MainWindow::editPhraseBook(QAction *action)
1223 PhraseBook *pb = m_phraseBookMenu[PhraseEditMenu].value(action);
1227 updatePhraseDicts();
1230#if QT_CONFIG(printsupport)
1232void MainWindow::printPhraseBook(QAction *action)
1234 PhraseBook *phraseBook = m_phraseBookMenu[PhrasePrintMenu].value(action);
1238 QPrintDialog dlg(printer(),
this);
1240 printer()->setDocName(phraseBook->fileName());
1241 statusBar()->showMessage(tr(
"Printing..."));
1242 PrintOut pout(printer());
1243 pout.setRule(PrintOut::ThinRule);
1244 const auto phrases = phraseBook->phrases();
1245 for (
const Phrase *p : phrases) {
1246 pout.setGuide(p->source());
1247 pout.addBox(29, p->source());
1249 pout.addBox(29, p->target());
1251 pout.addBox(34, p->definition(), PrintOut::Emphasis);
1253 if (pout.pageNum() != pageNum) {
1254 pageNum = pout.pageNum();
1255 statusBar()->showMessage(tr(
"Printing... (page %1)")
1258 pout.setRule(PrintOut::NoRule);
1259 pout.flushLine(
true);
1261 pout.flushLine(
true);
1262 statusBar()->showMessage(tr(
"Printing completed"), MessageMS);
1264 statusBar()->showMessage(tr(
"Printing aborted"), MessageMS);
1272 QStringList phraseBookList;
1273 QHash<QString, PhraseBook *> phraseBookHash;
1274 for (PhraseBook *pb : std::as_const(m_phraseBooks)) {
1275 if (pb->language() != QLocale::C && m_dataModel->language(m_currentIndex.model()) != QLocale::C) {
1276 if (pb->language() != m_dataModel->language(m_currentIndex.model()))
1278 if (pb->territory() == m_dataModel->model(m_currentIndex.model())->territory())
1279 phraseBookList.prepend(pb->friendlyPhraseBookName());
1281 phraseBookList.append(pb->friendlyPhraseBookName());
1283 phraseBookList.append(pb->friendlyPhraseBookName());
1285 phraseBookHash.insert(pb->friendlyPhraseBookName(), pb);
1287 if (phraseBookList.isEmpty()) {
1288 QMessageBox::warning(
this, tr(
"Add to phrase book"),
1289 tr(
"No appropriate phrasebook found."));
1293 QString selectedPhraseBook;
1294 if (phraseBookList.size() == 1) {
1295 selectedPhraseBook = phraseBookList.at(0);
1296 if (QMessageBox::information(
this, tr(
"Add to phrase book"),
1297 tr(
"Adding entry to phrasebook %1").arg(selectedPhraseBook),
1298 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok)
1302 bool okPressed =
false;
1303 selectedPhraseBook = QInputDialog::getItem(
this, tr(
"Add to phrase book"),
1304 tr(
"Select phrase book to add to"),
1305 phraseBookList, 0,
false, &okPressed);
1311 Phrase *phrase =
new Phrase(currentMessage->text(), currentMessage->translation(),
1312 QString(),
nullptr);
1314 phraseBookHash.value(selectedPhraseBook)->append(phrase);
1319 m_contextView->sortByColumn(-1, Qt::AscendingOrder);
1320 m_messageView->sortByColumn(-1, Qt::AscendingOrder);
1325 if (!m_assistantProcess)
1326 m_assistantProcess =
new QProcess();
1328 if (m_assistantProcess->state() != QProcess::Running) {
1329 QString app = QLibraryInfo::path(QLibraryInfo::BinariesPath) + QDir::separator();
1330#if !defined(Q_OS_MAC)
1331 app += QLatin1String(
"assistant");
1333 app += QLatin1String(
"Assistant.app/Contents/MacOS/Assistant");
1336 m_assistantProcess->start(app, QStringList() << QLatin1String(
"-enableRemoteControl"));
1337 if (!m_assistantProcess->waitForStarted()) {
1338 QMessageBox::critical(
this, tr(
"Qt Linguist"),
1339 tr(
"Unable to launch Qt Assistant (%1)").arg(app));
1343 QTextStream str(m_assistantProcess);
1344 str << QLatin1String(
"SetSource qthelp://org.qt-project.linguist.")
1345 << (QT_VERSION >> 16) << ((QT_VERSION >> 8) & 0xFF)
1346 << (QT_VERSION & 0xFF)
1347 << QLatin1String(
"/qtlinguist/qtlinguist-index.html")
1348 << QLatin1Char(
'\n') << Qt::endl;
1353 QMessageBox box(
this);
1354 box.setTextFormat(Qt::RichText);
1355 QString version = tr(
"Version %1");
1356 version = version.arg(QLatin1String(QT_VERSION_STR));
1358 const QString description
1359 = tr(
"Qt Linguist is a tool for adding translations to Qt applications.");
1360 box.setText(QStringLiteral(
"<center><img src=\":/images/icons/linguist-128-32.png\"/></img><p>%1</p></center>"
1362 "<p>Copyright (C) The Qt Company Ltd.</p>").arg(version, description));
1364 box.setWindowTitle(QApplication::translate(
"AboutDialog",
"Qt Linguist"));
1365 box.setIcon(QMessageBox::NoIcon);
1371 QMessageBox::aboutQt(
this, tr(
"Qt Linguist"));
1376 bool enabled = !m_phraseBooks.isEmpty();
1377 m_ui.menuClosePhraseBook->setEnabled(enabled);
1378 m_ui.menuEditPhraseBook->setEnabled(enabled);
1379#if QT_CONFIG(printsupport)
1380 m_ui.menuPrintPhraseBook->setEnabled(enabled);
1386 if (maybeSaveAll() && maybeSavePhraseBooks())
1397 switch (QMessageBox::information(
this, tr(
"Qt Linguist"),
1398 tr(
"Do you want to save the modified files?"),
1399 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes))
1401 case QMessageBox::Cancel:
1403 case QMessageBox::Yes:
1417 switch (QMessageBox::information(
this, tr(
"Qt Linguist"),
1418 tr(
"Do you want to save '%1'?").arg(m_dataModel->srcFileName(model,
true)),
1419 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes))
1421 case QMessageBox::Cancel:
1423 case QMessageBox::Yes:
1424 saveInternal(model);
1435 bool enable =
false;
1436 bool enableRw =
false;
1444 m_ui.actionSaveAll->setEnabled(enableRw);
1445 m_ui.actionReleaseAll->setEnabled(enableRw);
1446 m_ui.actionCloseAll->setEnabled(enable);
1447#if QT_CONFIG(printsupport)
1448 m_ui.actionPrint->setEnabled(enable);
1450 m_ui.actionAccelerators->setEnabled(enable);
1451 m_ui.actionSurroundingWhitespace->setEnabled(enable);
1452 m_ui.actionEndingPunctuation->setEnabled(enable);
1453 m_ui.actionPhraseMatches->setEnabled(enable);
1454 m_ui.actionPlaceMarkerMatches->setEnabled(enable);
1455 m_ui.actionResetSorting->setEnabled(enable);
1459 m_fileActiveModel = m_editActiveModel = -2;
1462 cap = tr(
"Qt Linguist[*]");
1464 cap = tr(
"%1[*] - Qt Linguist").arg(m_dataModel->condensedSrcFileNames(
true));
1465 setWindowTitle(cap);
1468void MainWindow::selectedContextChanged(
const QModelIndex &sortedIndex,
const QModelIndex &oldIndex)
1470 if (sortedIndex.isValid()) {
1471 if (m_settingCurrentMessage)
1474 QModelIndex sourceIndex = m_sortedContextsModel->mapToSource(sortedIndex);
1475 if (m_messageModel->parent(currentMessageIndex()).row() == sourceIndex.row())
1478 QModelIndex contextIndex = setMessageViewRoot(sourceIndex);
1479 const QModelIndex &firstChild =
1480 m_sortedMessagesModel->index(0, sourceIndex.column(), contextIndex);
1481 m_messageView->setCurrentIndex(firstChild);
1482 }
else if (oldIndex.isValid()) {
1483 m_contextView->setCurrentIndex(oldIndex);
1488
1489
1490void MainWindow::selectedMessageChanged(
const QModelIndex &sortedIndex,
const QModelIndex &oldIndex)
1493 if (!sortedIndex.isValid() && oldIndex.isValid()) {
1494 m_messageView->setCurrentIndex(oldIndex);
1500 QModelIndex index = m_sortedMessagesModel->mapToSource(sortedIndex);
1501 if (index.isValid()) {
1502 model = (index.column() && (index.column() - 1 < m_dataModel
->modelCount())) ?
1503 index.column() - 1 : m_currentIndex
.model();
1504 m_currentIndex = m_messageModel->dataIndex(index, model);
1508 m_phraseView->setSourceText(m_currentIndex
.model(), m->text());
1510 m_phraseView->setSourceText(-1, QString());
1518 m_phraseView->setSourceText(-1, QString());
1520 m_errorsView->setEnabled(m != 0);
1521 updateDanger(m_currentIndex,
true);
1525 m_phraseView->setSourceText(-1, QString());
1527 updateSourceView(model, m);
1529 updatePhraseBookActions();
1530 m_ui.actionSelectAll->setEnabled(index.isValid());
1537 if (index
!= m_currentIndex)
1541 updateDanger(index,
true);
1544 if (hasFormPreview(m->fileName()))
1550void MainWindow::updateTranslation(
const QStringList &translations)
1555 if (translations == m->translations())
1558 m->setTranslations(translations);
1559 if (!m->fileName().isEmpty() && hasFormPreview(m->fileName()))
1561 updateDanger(m_currentIndex,
true);
1569void MainWindow::updateTranslatorComment(
const QString &comment)
1574 if (comment == m->translatorComment())
1577 m->setTranslatorComment(comment);
1584 m_messageModel->blockSignals(
false);
1585 m_contextView->update();
1586 m_messageView->update();
1606void MainWindow::toggleFinished(
const QModelIndex &index)
1608 if (!index.isValid() || index.column() - 1 >= m_dataModel
->modelCount()
1612 QModelIndex item = m_sortedMessagesModel->mapToSource(index);
1624
1625
1626
1627
1628QModelIndex
MainWindow::nextContext(
const QModelIndex &index)
const
1630 QModelIndex sortedContextIndex = m_sortedContextsModel->mapFromSource(
1631 m_sortedMessagesModel->mapToSource(index));
1633 int nextRow = sortedContextIndex.row() + 1;
1634 if (nextRow >= m_sortedContextsModel->rowCount())
1636 sortedContextIndex = m_sortedContextsModel->index(nextRow, index.column());
1638 return m_sortedMessagesModel->mapFromSource(
1639 m_sortedContextsModel->mapToSource(sortedContextIndex));
1643
1644
1645QModelIndex
MainWindow::prevContext(
const QModelIndex &index)
const
1647 QModelIndex sortedContextIndex = m_sortedContextsModel->mapFromSource(
1648 m_sortedMessagesModel->mapToSource(index));
1650 int prevRow = sortedContextIndex.row() - 1;
1651 if (prevRow < 0) prevRow = m_sortedContextsModel->rowCount() - 1;
1652 sortedContextIndex = m_sortedContextsModel->index(prevRow, index.column());
1654 return m_sortedMessagesModel->mapFromSource(
1655 m_sortedContextsModel->mapToSource(sortedContextIndex));
1658QModelIndex
MainWindow::nextMessage(
const QModelIndex ¤tIndex,
bool checkUnfinished)
const
1660 QModelIndex idx = currentIndex.isValid() ? currentIndex : m_sortedMessagesModel->index(0, 0);
1663 QModelIndex par = idx.parent();
1664 if (par.isValid()) {
1665 row = idx.row() + 1;
1670 if (row >= m_sortedMessagesModel->rowCount(par)) {
1671 par = nextContext(par);
1674 idx = m_sortedMessagesModel->index(row, idx.column(), par);
1676 if (!checkUnfinished)
1679 QModelIndex item = m_sortedMessagesModel->mapToSource(idx);
1683 }
while (idx != currentIndex);
1684 return QModelIndex();
1687QModelIndex
MainWindow::prevMessage(
const QModelIndex ¤tIndex,
bool checkUnfinished)
const
1689 QModelIndex idx = currentIndex.isValid() ? currentIndex : m_sortedMessagesModel->index(0, 0);
1691 int row = idx.row() - 1;
1692 QModelIndex par = idx.parent();
1693 if (!par.isValid()) {
1699 par = prevContext(par);
1700 row = m_sortedMessagesModel->rowCount(par) - 1;
1702 idx = m_sortedMessagesModel->index(row, idx.column(), par);
1704 if (!checkUnfinished)
1707 QModelIndex item = m_sortedMessagesModel->mapToSource(idx);
1711 }
while (idx != currentIndex);
1712 return QModelIndex();
1717 if (m_ui.actionNextUnfinished->isEnabled()) {
1718 if (!doNext(
true)) {
1721 statusBar()->showMessage(tr(
"No untranslated translation units left."), MessageMS);
1729 if (m_ui.actionNextUnfinished->isEnabled()) {
1730 if (!doPrev(
true)) {
1733 statusBar()->showMessage(tr(
"No untranslated translation units left."), MessageMS);
1751 QModelIndex index = prevMessage(m_messageView->currentIndex(), checkUnfinished);
1752 if (index.isValid())
1753 setCurrentMessage(m_sortedMessagesModel->mapToSource(index));
1754 if (checkUnfinished)
1758 return index.isValid();
1763 QModelIndex index = nextMessage(m_messageView->currentIndex(), checkUnfinished);
1764 if (index.isValid())
1765 setCurrentMessage(m_sortedMessagesModel->mapToSource(index));
1766 if (checkUnfinished)
1770 return index.isValid();
1774 FindDialog::FindOptions options,
int statusFilter)
1779 m_findWhere = where;
1780 m_findOptions = options;
1781 m_findStatusFilter = statusFilter;
1782 if (options.testFlag(FindDialog::UseRegExp)) {
1783 m_findDialog->getRegExp().setPatternOptions(options.testFlag(FindDialog::MatchCase)
1784 ? QRegularExpression::NoPatternOption
1785 : QRegularExpression::CaseInsensitiveOption);
1787 m_ui.actionFindNext->setEnabled(
true);
1788 m_ui.actionFindPrev->setEnabled(
true);
1795 updateDanger(it,
false);
1798 updateDanger(m_currentIndex,
true);
1803 QString f = str.toLower();
1804 f.replace(QRegularExpression(QString(QLatin1String(
"[.,:;!?()-]"))), QString(QLatin1String(
" ")));
1805 f.remove(QLatin1Char(
'&'));
1806 return f.simplified();
1812 m_ui.menuRecentlyOpenedFiles->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentOpenRecent));
1813 m_ui.actionCloseAll->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::WindowClose));
1814 m_ui.actionExit->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::ApplicationExit));
1815 m_ui.actionSelectAll->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditSelectAll));
1818 const QString prefix = QApplication::platformName().compare(QStringLiteral(
"cocoa"), Qt::CaseInsensitive) ?
1819 QStringLiteral(
":/images/win") : QStringLiteral(
":/images/mac");
1821 m_ui.actionOpen->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentOpen,
1822 QIcon(prefix + QStringLiteral(
"/fileopen.png"))));
1823 m_ui.actionOpenAux->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentOpen,
1824 QIcon(prefix + QStringLiteral(
"/fileopen.png"))));
1825 m_ui.actionSave->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentSave,
1826 QIcon(prefix + QStringLiteral(
"/filesave.png"))));
1827 m_ui.actionSaveAll->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentSave,
1828 QIcon(prefix + QStringLiteral(
"/filesave.png"))));
1829 m_ui.actionPrint->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::DocumentPrint,
1830 QIcon(prefix + QStringLiteral(
"/print.png"))));
1831 m_ui.actionRedo->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditRedo,
1832 QIcon(prefix + QStringLiteral(
"/redo.png"))));
1833 m_ui.actionUndo->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditUndo,
1834 QIcon(prefix + QStringLiteral(
"/undo.png"))));
1835 m_ui.actionCut->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditCut,
1836 QIcon(prefix + QStringLiteral(
"/editcut.png"))));
1837 m_ui.actionCopy->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditCopy,
1838 QIcon(prefix + QStringLiteral(
"/editcopy.png"))));
1839 m_ui.actionPaste->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditPaste,
1840 QIcon(prefix + QStringLiteral(
"/editpaste.png"))));
1841 m_ui.actionFind->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::EditFind,
1842 QIcon(prefix + QStringLiteral(
"/searchfind.png"))));
1845 m_ui.actionAccelerators->setIcon(QIcon(prefix + QStringLiteral(
"/accelerator.png")));
1846 m_ui.actionOpenPhraseBook->setIcon(QIcon(prefix + QStringLiteral(
"/book.png")));
1847 m_ui.actionDone->setIcon(QIcon(prefix + QStringLiteral(
"/done.png")));
1848 m_ui.actionDoneAndNext->setIcon(QIcon(prefix + QStringLiteral(
"/doneandnext.png")));
1849 m_ui.actionNext->setIcon(QIcon(prefix + QStringLiteral(
"/next.png")));
1850 m_ui.actionNextUnfinished->setIcon(QIcon(prefix + QStringLiteral(
"/nextunfinished.png")));
1851 m_ui.actionPhraseMatches->setIcon(QIcon(prefix + QStringLiteral(
"/phrase.png")));
1852 m_ui.actionSurroundingWhitespace->setIcon(QIcon(prefix + QStringLiteral(
"/surroundingwhitespace.png")));
1853 m_ui.actionEndingPunctuation->setIcon(QIcon(prefix + QStringLiteral(
"/punctuation.png")));
1854 m_ui.actionPrev->setIcon(QIcon(prefix + QStringLiteral(
"/prev.png")));
1855 m_ui.actionPrevUnfinished->setIcon(QIcon(prefix + QStringLiteral(
"/prevunfinished.png")));
1856 m_ui.actionPlaceMarkerMatches->setIcon(QIcon(prefix + QStringLiteral(
"/validateplacemarkers.png")));
1857 m_ui.actionWhatsThis->setIcon(QIcon(prefix + QStringLiteral(
"/whatsthis.png")));
1860 connect(m_ui.menuFile, &QMenu::aboutToShow,
this, &MainWindow::fileAboutToShow);
1861 connect(m_ui.actionOpen, &QAction::triggered,
this, &MainWindow::open);
1862 connect(m_ui.actionOpenAux, &QAction::triggered,
this, &MainWindow::openAux);
1863 connect(m_ui.actionSaveAll, &QAction::triggered,
this, &MainWindow::saveAll);
1864 connect(m_ui.actionSave, &QAction::triggered,
this, &MainWindow::save);
1865 connect(m_ui.actionSaveAs, &QAction::triggered,
this, &MainWindow::saveAs);
1866 connect(m_ui.actionReleaseAll, &QAction::triggered,
this, &MainWindow::releaseAll);
1867 connect(m_ui.actionRelease, &QAction::triggered,
this, &MainWindow::release);
1868 connect(m_ui.actionReleaseAs, &QAction::triggered,
this, &MainWindow::releaseAs);
1869#if QT_CONFIG(printsupport)
1870 connect(m_ui.actionPrint, &QAction::triggered,
this, &MainWindow::print);
1872 m_ui.actionPrint->setEnabled(
false);
1874 connect(m_ui.actionClose, &QAction::triggered,
this, &MainWindow::closeFile);
1875 connect(m_ui.actionCloseAll, &QAction::triggered,
this, &MainWindow::closeAll);
1876 connect(m_ui.actionExit, &QAction::triggered,
this, &MainWindow::close);
1879 connect(m_ui.menuEdit, &QMenu::aboutToShow,
this, &MainWindow::editAboutToShow);
1881 connect(m_ui.actionUndo, &QAction::triggered, m_messageEditor, &MessageEditor::undo);
1882 connect(m_messageEditor, &MessageEditor::undoAvailable, m_ui.actionUndo, &QAction::setEnabled);
1884 connect(m_ui.actionRedo, &QAction::triggered, m_messageEditor, &MessageEditor::redo);
1885 connect(m_messageEditor, &MessageEditor::redoAvailable, m_ui.actionRedo, &QAction::setEnabled);
1887#ifndef QT_NO_CLIPBOARD
1888 connect(m_ui.actionCut, &QAction::triggered, m_messageEditor, &MessageEditor::cut);
1889 connect(m_messageEditor, &MessageEditor::cutAvailable, m_ui.actionCut, &QAction::setEnabled);
1891 connect(m_ui.actionCopy, &QAction::triggered, m_messageEditor, &MessageEditor::copy);
1892 connect(m_messageEditor, &MessageEditor::copyAvailable, m_ui.actionCopy, &QAction::setEnabled);
1894 connect(m_ui.actionPaste, &QAction::triggered, m_messageEditor, &MessageEditor::paste);
1895 connect(m_messageEditor, &MessageEditor::pasteAvailable, m_ui.actionPaste, &QAction::setEnabled);
1898 connect(m_ui.actionSelectAll, &QAction::triggered,
1899 m_messageEditor, &MessageEditor::selectAll);
1900 connect(m_ui.actionFind, &QAction::triggered,
1901 m_findDialog, &FindDialog::find);
1902 connect(m_ui.actionFindNext, &QAction::triggered,
1903 this, [
this] {findAgain(FindNext);});
1904 connect(m_ui.actionFindPrev, &QAction::triggered,
1905 this, [
this] {findAgain(FindPrev);});
1906 connect(m_ui.actionSearchAndTranslate, &QAction::triggered,
1907 this, &MainWindow::showTranslateDialog);
1908 connect(m_ui.actionBatchTranslation, &QAction::triggered,
1909 this, &MainWindow::showBatchTranslateDialog);
1910 connect(m_ui.actionTranslationFileSettings, &QAction::triggered,
1911 this, &MainWindow::showTranslationSettings);
1913 connect(m_batchTranslateDialog, &BatchTranslationDialog::finished,
1914 this, &MainWindow::refreshItemViews);
1918 connect(m_ui.actionPrevUnfinished, &QAction::triggered,
this, &MainWindow::prevUnfinished);
1919 connect(m_ui.actionNextUnfinished, &QAction::triggered,
this, &MainWindow::nextUnfinished);
1920 connect(m_ui.actionNext, &QAction::triggered,
this, &MainWindow::next);
1921 connect(m_ui.actionPrev, &QAction::triggered,
this, &MainWindow::prev);
1922 connect(m_ui.actionDone, &QAction::triggered,
this, &MainWindow::done);
1923 connect(m_ui.actionDoneAndNext, &QAction::triggered,
this, &MainWindow::doneAndNext);
1924 connect(m_ui.actionBeginFromSource, &QAction::triggered, m_messageEditor, &MessageEditor::beginFromSource);
1925 connect(m_messageEditor, &MessageEditor::beginFromSourceAvailable,
1926 m_ui.actionBeginFromSource, &QAction::setEnabled);
1929 connect(m_ui.actionNewPhraseBook, &QAction::triggered,
this, &MainWindow::newPhraseBook);
1930 connect(m_ui.actionOpenPhraseBook, &QAction::triggered,
this, &MainWindow::openPhraseBook);
1931 connect(m_ui.menuClosePhraseBook, &QMenu::triggered,
1932 this, &MainWindow::closePhraseBook);
1933 connect(m_ui.menuEditPhraseBook, &QMenu::triggered,
1934 this, &MainWindow::editPhraseBook);
1935#if QT_CONFIG(printsupport)
1936 connect(m_ui.menuPrintPhraseBook, &QMenu::triggered,
1937 this, &MainWindow::printPhraseBook);
1939 m_ui.menuPrintPhraseBook->setEnabled(
false);
1941 connect(m_ui.actionAddToPhraseBook, &QAction::triggered,
1942 this, &MainWindow::addToPhraseBook);
1945 connect(m_ui.actionAccelerators, &QAction::triggered,
this, &MainWindow::revalidate);
1946 connect(m_ui.actionSurroundingWhitespace, &QAction::triggered,
this, &MainWindow::revalidate);
1947 connect(m_ui.actionEndingPunctuation, &QAction::triggered,
this, &MainWindow::revalidate);
1948 connect(m_ui.actionPhraseMatches, &QAction::triggered,
this, &MainWindow::revalidate);
1949 connect(m_ui.actionPlaceMarkerMatches, &QAction::triggered,
this, &MainWindow::revalidate);
1952 connect(m_ui.actionResetSorting, &QAction::triggered,
1953 this, &MainWindow::resetSorting);
1954 connect(m_ui.actionDisplayGuesses, &QAction::triggered,
1955 m_phraseView, &PhraseView::toggleGuessing);
1956 connect(m_ui.actionStatistics, &QAction::triggered,
1957 this, &MainWindow::toggleStatistics);
1958 connect(m_ui.actionVisualizeWhitespace, &QAction::triggered,
1959 this, &MainWindow::toggleVisualizeWhitespace);
1960 connect(m_ui.menuView, &QMenu::aboutToShow,
1961 this, &MainWindow::updateViewMenu);
1962 connect(m_ui.actionIncreaseZoom, &QAction::triggered,
1963 m_messageEditor, &MessageEditor::increaseFontSize);
1964 connect(m_ui.actionDecreaseZoom, &QAction::triggered,
1965 m_messageEditor, &MessageEditor::decreaseFontSize);
1966 connect(m_ui.actionResetZoomToDefault, &QAction::triggered,
1967 m_messageEditor, &MessageEditor::resetFontSize);
1968 connect(m_ui.actionShowMoreGuesses, &QAction::triggered,
1969 m_phraseView, &PhraseView::moreGuesses);
1970 connect(m_ui.actionShowFewerGuesses, &QAction::triggered,
1971 m_phraseView, &PhraseView::fewerGuesses);
1972 connect(m_phraseView, &PhraseView::showFewerGuessesAvailable,
1973 m_ui.actionShowFewerGuesses, &QAction::setEnabled);
1974 connect(m_ui.actionResetGuessesToDefault, &QAction::triggered,
1975 m_phraseView, &PhraseView::resetNumGuesses);
1976 m_ui.menuViewViews->addAction(m_contextDock->toggleViewAction());
1977 m_ui.menuViewViews->addAction(m_messagesDock->toggleViewAction());
1978 m_ui.menuViewViews->addAction(m_phrasesDock->toggleViewAction());
1979 m_ui.menuViewViews->addAction(m_sourceAndFormDock->toggleViewAction());
1980 m_ui.menuViewViews->addAction(m_errorsDock->toggleViewAction());
1982#if defined(Q_OS_MAC)
1984 QMenu *windowMenu =
new QMenu(tr(
"&Window"),
this);
1985 menuBar()->insertMenu(m_ui.menuHelp->menuAction(), windowMenu);
1986 windowMenu->addAction(tr(
"Minimize"), QKeySequence(tr(
"Ctrl+M")),
1987 this, &QWidget::showMinimized);
1991 connect(m_ui.actionManual, &QAction::triggered,
this, &MainWindow::manual);
1992 connect(m_ui.actionAbout, &QAction::triggered,
this, &MainWindow::about);
1993 connect(m_ui.actionAboutQt, &QAction::triggered,
this, &MainWindow::aboutQt);
1994 connect(m_ui.actionWhatsThis, &QAction::triggered,
this, &MainWindow::onWhatsThis);
1996 connect(m_ui.menuRecentlyOpenedFiles, &QMenu::triggered,
1997 this, &MainWindow::recentFileActivated);
1999 m_ui.actionManual->setWhatsThis(tr(
"Display the manual for %1.").arg(tr(
"Qt Linguist")));
2000 m_ui.actionAbout->setWhatsThis(tr(
"Display information about %1.").arg(tr(
"Qt Linguist")));
2001 m_ui.actionDone->setShortcuts(QList<QKeySequence>()
2002 << QKeySequence(QLatin1String(
"Alt+Return"))
2003 << QKeySequence(QLatin1String(
"Alt+Enter")));
2004 m_ui.actionDoneAndNext->setShortcuts(QList<QKeySequence>()
2005 << QKeySequence(QLatin1String(
"Ctrl+Return"))
2006 << QKeySequence(QLatin1String(
"Ctrl+Enter")));
2009 connect(m_ui.menuPhrases, &QMenu::aboutToShow,
this, &MainWindow::setupPhrase);
2011 connect(m_ui.menuRecentlyOpenedFiles, &QMenu::aboutToShow,
2012 this, &MainWindow::setupRecentFilesMenu);
2018 doUpdateLatestModel(model);
2022void MainWindow::updateLatestModel(
const QModelIndex &index)
2024 if (index.column() && (index.column() - 1 < m_dataModel
->modelCount()))
2025 doUpdateLatestModel(index.column() - 1);
2028void MainWindow::doUpdateLatestModel(
int model)
2031 bool enable =
false;
2032 bool enableRw =
false;
2042 m_phraseView->setSourceText(model, item->text());
2044 m_phraseView->setSourceText(-1, QString());
2046 m_phraseView->setSourceText(-1, QString());
2050 updateSourceView(model, item);
2051 m_ui.actionSave->setEnabled(enableRw);
2052 m_ui.actionSaveAs->setEnabled(enableRw);
2053 m_ui.actionRelease->setEnabled(enableRw);
2054 m_ui.actionReleaseAs->setEnabled(enableRw);
2055 m_ui.actionClose->setEnabled(enable);
2056 m_ui.actionTranslationFileSettings->setEnabled(enableRw);
2057 m_ui.actionSearchAndTranslate->setEnabled(enableRw);
2059 updatePhraseBookActions();
2065 if (item && !item->fileName().isEmpty()) {
2066 if (hasFormPreview(item->fileName())) {
2067 m_sourceAndFormView->setCurrentWidget(m_formPreviewView);
2070 m_sourceAndFormView->setCurrentWidget(m_sourceCodeView);
2071 QDir dir = QFileInfo(m_dataModel->srcFileName(model)).dir();
2072 QString fileName = QDir::cleanPath(dir.absoluteFilePath(item->fileName()));
2073 m_sourceCodeView->setSourceContext(fileName, item->lineNumber());
2076 m_sourceAndFormView->setCurrentWidget(m_sourceCodeView);
2077 m_sourceCodeView->setSourceContext(QString(), 0);
2086 if (m_fileActiveModel != m_currentIndex
.model()) {
2091 QString fn = QFileInfo(m_dataModel->srcFileName(m_currentIndex.model())).baseName();
2092 m_ui.actionSave->setText(tr(
"&Save '%1'").arg(fn));
2093 m_ui.actionSaveAs->setText(tr(
"Save '%1' &As...").arg(fn));
2094 m_ui.actionRelease->setText(tr(
"Release '%1'").arg(fn));
2095 m_ui.actionReleaseAs->setText(tr(
"Release '%1' As...").arg(fn));
2096 m_ui.actionClose->setText(tr(
"&Close '%1'").arg(fn));
2098 m_ui.actionSave->setText(tr(
"&Save"));
2099 m_ui.actionSaveAs->setText(tr(
"Save &As..."));
2100 m_ui.actionRelease->setText(tr(
"Release"));
2101 m_ui.actionReleaseAs->setText(tr(
"Release As..."));
2102 m_ui.actionClose->setText(tr(
"&Close"));
2105 m_ui.actionSaveAll->setText(tr(
"Save All"));
2106 m_ui.actionReleaseAll->setText(tr(
"&Release All"));
2107 m_ui.actionCloseAll->setText(tr(
"Close All"));
2110 m_ui.actionSaveAs->setText(tr(
"Save &As..."));
2111 m_ui.actionReleaseAs->setText(tr(
"Release As..."));
2113 m_ui.actionSaveAll->setText(tr(
"&Save"));
2114 m_ui.actionReleaseAll->setText(tr(
"&Release"));
2115 m_ui.actionCloseAll->setText(tr(
"&Close"));
2118 m_ui.actionSave->setVisible(en);
2119 m_ui.actionRelease->setVisible(en);
2120 m_ui.actionClose->setVisible(en);
2121 m_fileActiveModel = m_currentIndex
.model();
2127 if (m_editActiveModel != m_currentIndex
.model()) {
2129 QString fn = QFileInfo(m_dataModel->srcFileName(m_currentIndex.model())).baseName();
2130 m_ui.actionTranslationFileSettings->setText(tr(
"Translation File &Settings for '%1'...").arg(fn));
2131 m_ui.actionBatchTranslation->setText(tr(
"&Batch Translation of '%1'...").arg(fn));
2132 m_ui.actionSearchAndTranslate->setText(tr(
"Search And &Translate in '%1'...").arg(fn));
2134 m_ui.actionTranslationFileSettings->setText(tr(
"Translation File &Settings..."));
2135 m_ui.actionBatchTranslation->setText(tr(
"&Batch Translation..."));
2136 m_ui.actionSearchAndTranslate->setText(tr(
"Search And &Translate..."));
2138 m_editActiveModel = m_currentIndex
.model();
2144 bool check = m_statistics ? m_statistics->isVisible() :
false;
2145 m_ui.actionStatistics->setChecked(check);
2150 m_contextDock->show();
2151 m_contextDock->raise();
2156 m_messagesDock->show();
2157 m_messagesDock->raise();
2162 m_phrasesDock->show();
2163 m_phrasesDock->raise();
2168 m_sourceAndFormDock->show();
2169 m_sourceAndFormDock->raise();
2174 m_errorsDock->show();
2175 m_errorsDock->raise();
2180 QWhatsThis::enterWhatsThisMode();
2185 QToolBar *filet =
new QToolBar(
this);
2186 filet->setObjectName(QLatin1String(
"FileToolbar"));
2187 filet->setWindowTitle(tr(
"File"));
2188 this->addToolBar(filet);
2189 m_ui.menuToolbars->addAction(filet->toggleViewAction());
2191 QToolBar *editt =
new QToolBar(
this);
2192 editt->setVisible(
false);
2193 editt->setObjectName(QLatin1String(
"EditToolbar"));
2194 editt->setWindowTitle(tr(
"Edit"));
2195 this->addToolBar(editt);
2196 m_ui.menuToolbars->addAction(editt->toggleViewAction());
2198 QToolBar *translationst =
new QToolBar(
this);
2199 translationst->setObjectName(QLatin1String(
"TranslationToolbar"));
2200 translationst->setWindowTitle(tr(
"Translation"));
2201 this->addToolBar(translationst);
2202 m_ui.menuToolbars->addAction(translationst->toggleViewAction());
2204 QToolBar *validationt =
new QToolBar(
this);
2205 validationt->setObjectName(QLatin1String(
"ValidationToolbar"));
2206 validationt->setWindowTitle(tr(
"Validation"));
2207 this->addToolBar(validationt);
2208 m_ui.menuToolbars->addAction(validationt->toggleViewAction());
2210 QToolBar *helpt =
new QToolBar(
this);
2211 helpt->setVisible(
false);
2212 helpt->setObjectName(QLatin1String(
"HelpToolbar"));
2213 helpt->setWindowTitle(tr(
"Help"));
2214 this->addToolBar(helpt);
2215 m_ui.menuToolbars->addAction(helpt->toggleViewAction());
2218 filet->addAction(m_ui.actionOpen);
2219 filet->addAction(m_ui.actionSaveAll);
2220 filet->addAction(m_ui.actionPrint);
2221 filet->addSeparator();
2222 filet->addAction(m_ui.actionOpenPhraseBook);
2224 editt->addAction(m_ui.actionUndo);
2225 editt->addAction(m_ui.actionRedo);
2226 editt->addSeparator();
2227 editt->addAction(m_ui.actionCut);
2228 editt->addAction(m_ui.actionCopy);
2229 editt->addAction(m_ui.actionPaste);
2230 editt->addSeparator();
2231 editt->addAction(m_ui.actionFind);
2233 translationst->addAction(m_ui.actionPrev);
2234 translationst->addAction(m_ui.actionNext);
2235 translationst->addAction(m_ui.actionPrevUnfinished);
2236 translationst->addAction(m_ui.actionNextUnfinished);
2237 translationst->addAction(m_ui.actionDone);
2238 translationst->addAction(m_ui.actionDoneAndNext);
2240 validationt->addAction(m_ui.actionAccelerators);
2241 validationt->addAction(m_ui.actionSurroundingWhitespace);
2242 validationt->addAction(m_ui.actionEndingPunctuation);
2243 validationt->addAction(m_ui.actionPhraseMatches);
2244 validationt->addAction(m_ui.actionPlaceMarkerMatches);
2246 helpt->addAction(m_ui.actionWhatsThis);
2249QModelIndex
MainWindow::setMessageViewRoot(
const QModelIndex &index)
2251 const QModelIndex &sortedContextIndex = m_sortedMessagesModel->mapFromSource(index);
2252 const QModelIndex &trueContextIndex = m_sortedMessagesModel->index(sortedContextIndex.row(), 0);
2253 if (m_messageView->rootIndex() != trueContextIndex)
2254 m_messageView->setRootIndex(trueContextIndex);
2255 return trueContextIndex;
2259
2260
2261void MainWindow::setCurrentMessage(
const QModelIndex &index)
2263 const QModelIndex &contextIndex = m_messageModel->parent(index);
2264 if (!contextIndex.isValid())
2267 const QModelIndex &trueIndex = m_messageModel->index(contextIndex.row(), index.column(), QModelIndex());
2268 m_settingCurrentMessage =
true;
2269 m_contextView->setCurrentIndex(m_sortedContextsModel->mapFromSource(trueIndex));
2270 m_settingCurrentMessage =
false;
2272 setMessageViewRoot(contextIndex);
2273 m_messageView->setCurrentIndex(m_sortedMessagesModel->mapFromSource(index));
2276void MainWindow::setCurrentMessage(
const QModelIndex &index,
int model)
2278 const QModelIndex &theIndex = m_messageModel->index(index.row(), model + 1, index.parent());
2279 setCurrentMessage(theIndex);
2285 int contextIndex = m_dataModel->findContextIndex(cand.context);
2287 cand.disambiguation);
2288 setCurrentMessage(m_messageModel->modelIndex(MultiDataIndex(modelIndex, contextIndex,
2292QModelIndex
MainWindow::currentContextIndex()
const
2294 return m_sortedContextsModel->mapToSource(m_contextView->currentIndex());
2297QModelIndex
MainWindow::currentMessageIndex()
const
2299 return m_sortedMessagesModel->mapToSource(m_messageView->currentIndex());
2306 if (!pb->load(name, &langGuessed)) {
2307 QMessageBox::warning(
this, tr(
"Qt Linguist"),
2308 tr(
"Cannot read from phrase book '%1'.").arg(name));
2313 if (!m_translationSettingsDialog)
2314 m_translationSettingsDialog =
new TranslationSettingsDialog(
this);
2316 m_translationSettingsDialog->exec();
2319 m_phraseBooks.append(pb);
2321 QAction *a = m_ui.menuClosePhraseBook->addAction(pb->friendlyPhraseBookName());
2322 m_phraseBookMenu[PhraseCloseMenu].insert(a, pb);
2323 a->setWhatsThis(tr(
"Close this phrase book."));
2325 a = m_ui.menuEditPhraseBook->addAction(pb->friendlyPhraseBookName());
2326 m_phraseBookMenu[PhraseEditMenu].insert(a, pb);
2327 a->setWhatsThis(tr(
"Enables you to add, modify, or delete"
2328 " entries in this phrase book."));
2330 a = m_ui.menuPrintPhraseBook->addAction(pb->friendlyPhraseBookName());
2331 m_phraseBookMenu[PhrasePrintMenu].insert(a, pb);
2332 a->setWhatsThis(tr(
"Print the entries in this phrase book."));
2335 updatePhraseDicts();
2336 updatePhraseBookActions();
2341bool MainWindow::savePhraseBook(QString *name, PhraseBook &pb)
2343 if (!name->contains(QLatin1Char(
'.')))
2344 *name += QLatin1String(
".qph");
2346 if (!pb.save(*name)) {
2347 QMessageBox::warning(
this, tr(
"Qt Linguist"),
2348 tr(
"Cannot create phrase book '%1'.").arg(*name));
2357 switch (QMessageBox::information(
this, tr(
"Qt Linguist"),
2358 tr(
"Do you want to save phrase book '%1'?").arg(pb->friendlyPhraseBookName()),
2359 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes))
2361 case QMessageBox::Cancel:
2363 case QMessageBox::Yes:
2364 if (!pb->save(pb->fileName()))
2375 for (PhraseBook *phraseBook : std::as_const(m_phraseBooks))
2376 if (!maybeSavePhraseBook(phraseBook))
2386 m_progressLabel->setText(QString(QLatin1String(
" ")));
2387 m_progressLabel->setToolTip(QString());
2389 m_progressLabel->setText(QStringLiteral(
" %1/%2 ").arg(numFinished).arg(numEditable));
2390 m_progressLabel->setToolTip(tr(
"%n unfinished message(s) left.", 0,
2391 numEditable - numFinished));
2393 bool enable = numFinished != numEditable;
2394 m_ui.actionPrevUnfinished->setEnabled(enable);
2395 m_ui.actionNextUnfinished->setEnabled(enable);
2396 m_ui.actionDone->setEnabled(enable);
2397 m_ui.actionDoneAndNext->setEnabled(enable);
2399 m_ui.actionPrev->setEnabled(m_dataModel->contextCount() > 0);
2400 m_ui.actionNext->setEnabled(m_dataModel->contextCount() > 0);
2405 bool phraseBookLoaded = (m_currentIndex.model() >= 0) && !m_phraseBooks.isEmpty();
2406 m_ui.actionBatchTranslation->setEnabled(m_dataModel->contextCount() > 0 && phraseBookLoaded
2407 && m_dataModel->isModelWritable(m_currentIndex.model()));
2408 m_ui.actionAddToPhraseBook->setEnabled(currentMessageIndex().isValid() && phraseBookLoaded);
2411void MainWindow::updatePhraseDictInternal(
int model)
2413 QHash<QString, QList<Phrase *> > &pd = m_phraseDict[model];
2416 for (PhraseBook *pb : std::as_const(m_phraseBooks)) {
2418 if (pb->language() != QLocale::C && m_dataModel->language(model) != QLocale::C) {
2419 if (pb->language() != m_dataModel->language(model))
2421 before = (pb->territory() == m_dataModel->model(model)->territory());
2425 const auto phrases = pb->phrases();
2426 for (Phrase *p : phrases) {
2427 QString f = friendlyString(p->source());
2429 f = f.split(QLatin1Char(
' ')).first();
2430 if (!pd.contains(f)) {
2431 pd.insert(f, QList<Phrase *>());
2444 updatePhraseDictInternal(model);
2450 for (
int i = 0; i < m_phraseDict.size(); ++i)
2452 m_phraseDict[i].clear();
2454 updatePhraseDictInternal(i);
2461 for (
const ushort *p = (ushort *)str.constData();; ) {
2471 if (c !=
'&' && c !=
' ' && QChar(c).isPrint()) {
2472 const ushort *pp = p;
2473 for (; *p < 256 && isalpha(*p); p++) ;
2474 if (pp == p || *p !=
';')
2499 bool danger =
false;
2501 if (source.isEmpty()) {
2502 source = m->pluralText();
2503 if (source.isEmpty())
2506 QStringList translations = m->translations();
2509 for (
int i = 0; i < translations.size(); ++i) {
2512 translations[i].truncate(sep);
2515 if (m_ui.actionAccelerators->isChecked()) {
2516 bool sk = haveMnemonic(source);
2518 for (
int i = 0; i < translations.size() && tk; ++i) {
2519 tk &= haveMnemonic(translations[i]);
2524 m_errorsView->addError(mi, ErrorsView::SuperfluousAccelerator);
2526 }
else if (sk && !tk) {
2528 m_errorsView->addError(mi, ErrorsView::MissingAccelerator);
2532 if (m_ui.actionSurroundingWhitespace->isChecked()) {
2533 bool whitespaceok =
true;
2534 for (
int i = 0; i < translations.size() && whitespaceok; ++i) {
2535 whitespaceok &= (leadingWhitespace(source) == leadingWhitespace(translations[i]));
2536 whitespaceok &= (trailingWhitespace(source) == trailingWhitespace(translations[i]));
2539 if (!whitespaceok) {
2541 m_errorsView->addError(mi, ErrorsView::SurroundingWhitespaceDiffers);
2545 if (m_ui.actionEndingPunctuation->isChecked()) {
2546 bool endingok =
true;
2547 for (
int i = 0; i < translations.size() && endingok; ++i) {
2548 endingok &= (ending(source, m_dataModel->sourceLanguage(mi)) ==
2549 ending(translations[i], m_dataModel->language(mi)));
2554 m_errorsView->addError(mi, ErrorsView::PunctuationDiffers);
2558 if (m_ui.actionPhraseMatches->isChecked()) {
2559 QString fsource = friendlyString(source);
2560 QString ftranslation = friendlyString(translations.first());
2561 QStringList lookupWords = fsource.split(QLatin1Char(
' '));
2564 for (
const QString &s : std::as_const(lookupWords)) {
2565 if (m_phraseDict[mi].contains(s)) {
2567 const auto phrases = m_phraseDict[mi].value(s);
2568 for (
const Phrase *p : phrases) {
2569 if (fsource == friendlyString(p->source())) {
2570 if (ftranslation.indexOf(friendlyString(p->target())) >= 0) {
2574 phraseFound =
false;
2580 m_errorsView->addError(mi, ErrorsView::IgnoredPhrasebook, s);
2587 if (m_ui.actionPlaceMarkerMatches->isChecked()) {
2596 QHash<
int,
int> placeMarkerIndexes;
2597 QString translation;
2598 int numTranslations = translations.size();
2599 for (
int pass = 0; pass < numTranslations + 1; ++pass) {
2600 const QChar *uc_begin = source.unicode();
2601 const QChar *uc_end = uc_begin + source.size();
2603 translation = translations[pass - 1];
2604 uc_begin = translation.unicode();
2605 uc_end = uc_begin + translation.size();
2607 const QChar *c = uc_begin;
2608 while (c < uc_end) {
2609 if (c->unicode() ==
'%') {
2610 const QChar *escape_start = ++c;
2611 while (c->isDigit())
2613 const QChar *escape_end = c;
2615 int markerIndex = QString::fromRawData(
2616 escape_start, escape_end - escape_start).toInt(&ok);
2618 placeMarkerIndexes[markerIndex] += (pass == 0 ? numTranslations : -1);
2625 for (
int i : std::as_const(placeMarkerIndexes)) {
2628 m_errorsView->addError(mi, ErrorsView::PlaceMarkersDiffer);
2636 for (
int i = 0; i < numTranslations; ++i)
2637 if (m_dataModel
->model(mi
)->countRefNeeds().at(i)
2638 && !(translations[i].contains(QLatin1String(
"%n"))
2639 || translations[i].contains(QLatin1String(
"%Ln")))) {
2641 m_errorsView->addError(mi, ErrorsView::NumerusMarkerMissing);
2654 statusBar()->showMessage(m_errorsView->firstError());
2661 restoreGeometry(config.value(settingPath(
"Geometry/WindowGeometry")).toByteArray());
2662 restoreState(config.value(settingPath(
"MainWindowState")).toByteArray());
2664 m_ui.actionAccelerators->setChecked(
2665 config.value(settingPath(
"Validators/Accelerator"),
true).toBool());
2666 m_ui.actionSurroundingWhitespace->setChecked(
2667 config.value(settingPath(
"Validators/SurroundingWhitespace"),
true).toBool());
2668 m_ui.actionEndingPunctuation->setChecked(
2669 config.value(settingPath(
"Validators/EndingPunctuation"),
true).toBool());
2670 m_ui.actionPhraseMatches->setChecked(
2671 config.value(settingPath(
"Validators/PhraseMatch"),
true).toBool());
2672 m_ui.actionPlaceMarkerMatches->setChecked(
2673 config.value(settingPath(
"Validators/PlaceMarkers"),
true).toBool());
2674 m_ui.actionLengthVariants->setChecked(
2675 config.value(settingPath(
"Options/LengthVariants"),
false).toBool());
2676 m_ui.actionVisualizeWhitespace->setChecked(
2677 config.value(settingPath(
"Options/VisualizeWhitespace"),
true).toBool());
2679 m_messageEditor->setFontSize(
2680 config.value(settingPath(
"Options/EditorFontsize"), font().pointSize()).toReal());
2681 m_phraseView->setMaxCandidates(config.value(settingPath(
"Options/NumberOfGuesses"),
2682 PhraseView::getDefaultMaxCandidates()).toInt());
2686 int size = config.beginReadArray(settingPath(
"OpenedPhraseBooks"));
2687 for (
int i = 0; i < size; ++i) {
2688 config.setArrayIndex(i);
2689 doOpenPhraseBook(config.value(QLatin1String(
"FileName")).toString());
2697 config.setValue(settingPath(
"Geometry/WindowGeometry"),
2699 config.setValue(settingPath(
"Validators/Accelerator"),
2700 m_ui.actionAccelerators->isChecked());
2701 config.setValue(settingPath(
"Validators/SurroundingWhitespace"),
2702 m_ui.actionSurroundingWhitespace->isChecked());
2703 config.setValue(settingPath(
"Validators/EndingPunctuation"),
2704 m_ui.actionEndingPunctuation->isChecked());
2705 config.setValue(settingPath(
"Validators/PhraseMatch"),
2706 m_ui.actionPhraseMatches->isChecked());
2707 config.setValue(settingPath(
"Validators/PlaceMarkers"),
2708 m_ui.actionPlaceMarkerMatches->isChecked());
2709 config.setValue(settingPath(
"Options/LengthVariants"),
2710 m_ui.actionLengthVariants->isChecked());
2711 config.setValue(settingPath(
"Options/VisualizeWhitespace"),
2712 m_ui.actionVisualizeWhitespace->isChecked());
2713 config.setValue(settingPath(
"MainWindowState"),
2717 config.setValue(settingPath(
"Options/EditorFontsize"), m_messageEditor->fontSize());
2718 config.setValue(settingPath(
"Options/NumberOfGuesses"), m_phraseView->getMaxCandidates());
2720 config.beginWriteArray(settingPath(
"OpenedPhraseBooks"),
2721 m_phraseBooks.size());
2722 for (
int i = 0; i < m_phraseBooks.size(); ++i) {
2723 config.setArrayIndex(i);
2724 config.setValue(QLatin1String(
"FileName"), m_phraseBooks.at(i)->fileName());
2731 m_ui.menuRecentlyOpenedFiles->clear();
2732 for (
const QStringList &strList : recentFiles().filesLists())
2733 if (strList.size() == 1) {
2734 const QString &str = strList.first();
2735 m_ui.menuRecentlyOpenedFiles->addAction(
2736 DataModel::prettifyFileName(str))->setData(str);
2738 QMenu *menu = m_ui.menuRecentlyOpenedFiles->addMenu(
2739 MultiDataModel::condenseFileNames(
2740 MultiDataModel::prettifyFileNames(strList)));
2741 menu->addAction(tr(
"All"))->setData(strList);
2742 for (
const QString &str : strList)
2743 menu->addAction(DataModel::prettifyFileName(str))->setData(str);
2747void MainWindow::recentFileActivated(QAction *action)
2749 openFiles(action->data().toStringList());
2754 if (m_ui.actionStatistics->isChecked()) {
2755 if (!m_statistics) {
2756 m_statistics =
new Statistics(
this);
2757 connect(m_dataModel, &MultiDataModel::statsChanged,
2758 m_statistics, &Statistics::updateStats);
2760 m_statistics->show();
2763 else if (m_statistics) {
2764 m_statistics->close();
2770 m_messageEditor->setVisualizeWhitespace(m_ui.actionVisualizeWhitespace->isChecked());
2783 if (!m_statistics || !m_statistics->isVisible() || m_currentIndex
.model() < 0)
2789void MainWindow::doShowTranslationSettings(
int model)
2791 if (!m_translationSettingsDialog)
2792 m_translationSettingsDialog =
new TranslationSettingsDialog(
this);
2794 m_translationSettingsDialog->exec();
2799 doShowTranslationSettings(m_currentIndex
.model());
2804 if (event->type() == QEvent::DragEnter) {
2805 QDragEnterEvent *e =
static_cast<QDragEnterEvent*>(event);
2806 if (e->mimeData()->hasFormat(QLatin1String(
"text/uri-list"))) {
2807 e->acceptProposedAction();
2810 }
else if (event->type() == QEvent::Drop) {
2811 QDropEvent *e =
static_cast<QDropEvent*>(event);
2812 if (!e->mimeData()->hasFormat(QLatin1String(
"text/uri-list")))
2815 for (
const QUrl &url : e->mimeData()->urls())
2816 if (!url.toLocalFile().isEmpty())
2817 urls << url.toLocalFile();
2818 if (!urls.isEmpty())
2820 e->acceptProposedAction();
2822 }
else if (event->type() == QEvent::KeyPress) {
2823 QKeyEvent *ke =
static_cast<QKeyEvent *>(event);
2824 if (ke->key() == Qt::Key_Escape) {
2825 if (object == m_messageEditor)
2826 m_messageView->setFocus();
2827 else if (object == m_messagesDock)
2828 m_contextView->setFocus();
2829 }
else if ((ke->key() == Qt::Key_Plus || ke->key() == Qt::Key_Equal)
2830 && (ke->modifiers() & Qt::ControlModifier)) {
2832 }
else if (ke->key() == Qt::Key_Minus
2833 && (ke->modifiers() & Qt::ControlModifier)) {
2836 }
else if (event->type() == QEvent::Wheel) {
2837 QWheelEvent *we =
static_cast<QWheelEvent *>(event);
2838 if (we->modifiers() & Qt::ControlModifier) {
2839 if (we->angleDelta().y() > 0)
ContextItemDelegate(QObject *parent, MultiDataModel *model)
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
This pure abstract function must be reimplemented if you want to provide custom rendering.
FocusWatcher(MessageEditor *msgedit, QObject *parent)
bool eventFilter(QObject *object, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
void closeEvent(QCloseEvent *event) override
[21]
bool openFiles(const QStringList &names, bool readWrite=true)
static RecentFiles & recentFiles()
bool eventFilter(QObject *obj, QEvent *ev) override
Filters events if this object has been installed as an event filter for the watched object.
void setEditorFocusForModel(int model)
void setUnfinishedEditorFocus()
bool focusNextUnfinished()
void activeModelChanged(int model)
void showMessage(const MultiDataIndex &index)
const TranslatorMessage & message() const
TranslatorMessage::Type type() const
MultiDataIndex(int model, int context, int message)
bool operator!=(const MultiDataIndex &other) const
MultiDataModelIterator(MultiDataModel *model, int modelNo, int contextNo=0, int messageNo=0)
MessageItem * current() const
bool isModified(int model) const
MessageItem * messageItem(const MultiDataIndex &index, int model) const
void setModified(int model, bool dirty)
void languageChanged(int model)
int getNumFinished() const
void setDanger(const MultiDataIndex &index, bool danger)
bool isModelWritable(int model) const
MultiMessageItem * multiMessageItem(const MultiDataIndex &index) const
int getNumEditable() const
MultiContextItem * multiContextItem(int ctxIdx) const
void translationChanged(const MultiDataIndex &index)
MessageItem * messageItem(const MultiDataIndex &index) const
void setFinished(const MultiDataIndex &index, bool finished)
void messageDataChanged(const MultiDataIndex &index)
void multiContextDataChanged(const MultiDataIndex &index)
void setCurrentMessageFromGuess(int modelIndex, const Candidate &cand)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
\reimp
SortedContextsModel(QObject *parent, MultiDataModel *model)
SortedMessagesModel(QObject *parent, MultiDataModel *model)
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
\reimp
void setDataModel(DataModel *model)
void setPhraseBook(PhraseBook *phraseBook)
bool isTranslated() const
static QString leadingWhitespace(const QString &str)
static Ending ending(QString str, QLocale::Language lang)
static bool hasFormPreview(const QString &fileName)
static QString trailingWhitespace(const QString &str)
static QString fileFilters(bool allFirst)
static const QVariant & pxObsolete()
static bool haveMnemonic(const QString &str)
static QT_BEGIN_NAMESPACE const int MessageMS
int firstNonobsoleteMessageIndex(int msgIdx) const
bool isUnfinished() const
OpenedFile(DataModel *_dataModel, bool _readWrite, bool _langGuessed)