5
6
7
14#include <QApplication>
16#ifndef QT_NO_CLIPBOARD
31
32
33
34
37 m_dataModel(dataModel),
40 m_lengthVariants(
false),
41 m_fontSize(font().pointSize()),
46 m_visualizeWhitespace(
true),
50 setObjectName(QLatin1String(
"scroll area"));
53 p.setBrush(QPalette::Window, p.brush(QPalette::Active, QPalette::Base));
59#ifndef QT_NO_CLIPBOARD
60 connect(qApp->clipboard(), &QClipboard::dataChanged,
61 this, &MessageEditor::clipboardChanged);
63 connect(m_dataModel, &MultiDataModel::modelAppended,
64 this, &MessageEditor::messageModelAppended);
65 connect(m_dataModel, &MultiDataModel::modelDeleted,
66 this, &MessageEditor::messageModelDeleted);
67 connect(m_dataModel, &MultiDataModel::allModelsDeleted,
68 this, &MessageEditor::allModelsDeleted);
69 connect(m_dataModel, &MultiDataModel::languageChanged,
70 this, &MessageEditor::setTargetLanguage);
72 m_tabOrderTimer.setSingleShot(
true);
73 connect(&m_tabOrderTimer, &QTimer::timeout,
74 this, &MessageEditor::reallyFixTabOrder);
76#ifndef QT_NO_CLIPBOARD
80 setWhatsThis(tr(
"This whole panel allows you to view and edit "
81 "the translation of some source text."));
87 if (FormatTextEdit *fte = qobject_cast<FormatTextEdit *>(m_selectionHolder))
88 disconnect(fte, &FormatTextEdit::editorDestroyed,
this, &MessageEditor::editorDestroyed);
93 QFrame *editorPage =
new QFrame;
94 editorPage->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
96 m_source =
new FormWidget(tr(
"Source text"),
false);
98 m_source->setWhatsThis(tr(
"This area shows the source text."));
99 connect(m_source, &
FormWidget::selectionChanged,
102 m_pluralSource =
new FormWidget(tr(
"Source text (Plural)"),
false);
104 m_pluralSource->setWhatsThis(tr(
"This area shows the plural form of the source text."));
105 connect(m_pluralSource, &
FormWidget::selectionChanged,
108 m_commentText =
new FormWidget(tr(
"Developer comments"),
false);
110 m_commentText->setObjectName(QLatin1String(
"comment/context view"));
111 m_commentText->setWhatsThis(tr(
"This area shows a comment that"
112 " may guide you, and the context in which the text"
114 connect(m_commentText, &
FormWidget::selectionChanged,
117 QBoxLayout *subLayout =
new QVBoxLayout;
119 subLayout->setContentsMargins(5, 5, 5, 5);
120 subLayout->addWidget(m_source);
121 subLayout->addWidget(m_pluralSource);
122 subLayout->addWidget(m_commentText);
124 m_layout =
new QVBoxLayout;
125 m_layout->setSpacing(2);
126 m_layout->setContentsMargins(2, 2, 2, 2);
127 m_layout->addLayout(subLayout);
128 m_layout->addStretch(1);
129 editorPage->setLayout(m_layout);
131 setWidget(editorPage);
132 setWidgetResizable(
true);
137 QBrush brush = m_dataModel->brushForModel(model);
141 pal.setBrush(QPalette::Window, brush);
143 QPixmap pm(brush.texture().size());
146 p.fillRect(brush.texture().rect(), brush);
147 pal.setBrush(QPalette::Window, pm);
154 int model = m_editors.size();
155 m_editors.append(MessageEditorData());
158 ed.fontSize = m_fontSize;
159 ed.container =
new QWidget;
161 ed.container->setPalette(paletteForModel(model));
162 ed.container->setAutoFillBackground(
true);
164 m_editors[0].container->setPalette(paletteForModel(0));
165 m_editors[0].container->setAutoFillBackground(
true);
169 ed.transCommentText =
new FormWidget(QString(),
true);
172 ed
.transCommentText->setWhatsThis(tr(
"Here you can enter comments for your own use."
173 " They have no effect on the translated applications.") );
178 connect(ed.transCommentText, &FormWidget::textChanged,
179 this, &MessageEditor::emitTranslatorCommentChanged);
180 connect(ed.transCommentText, &FormWidget::textChanged,
181 this, &MessageEditor::resetHoverSelection);
185 QBoxLayout *box =
new QVBoxLayout(ed.container);
186 box->setContentsMargins(5, 5, 5, 5);
189 m_layout->addWidget(ed.container);
190 setTargetLanguage(model);
195 for (
const MessageEditorData &med : std::as_const(m_editors))
196 med.container->deleteLater();
200 m_currentNumerus = -1;
206 m_editors[model].container->deleteLater();
207 m_editors.removeAt(model);
208 if (model <= m_currentModel) {
209 if (model < m_currentModel || m_currentModel == m_editors.size())
212 if (m_currentModel >= 0) {
213 if (m_currentNumerus >= m_editors[m_currentModel].transTexts.size())
214 m_currentNumerus = m_editors[m_currentModel].transTexts.size() - 1;
215 activeEditor()->setFocus();
217 m_currentNumerus = -1;
220 if (m_editors.size() == 1) {
221 m_editors[0].container->setAutoFillBackground(
false);
223 for (
int i = model; i < m_editors.size(); ++i)
224 m_editors[i].container->setPalette(paletteForModel(i));
228void MessageEditor::addPluralForm(
int model,
const QString &label,
bool writable)
231 connect(transEditor, &FormMultiWidget::editorCreated,
232 this, &MessageEditor::editorCreated);
235 if (!m_editors[model].transTexts.isEmpty())
236 transEditor->setVisible(
false);
238 static_cast<QBoxLayout *>(m_editors[model].container->layout())->insertWidget(
239 m_editors[model].transTexts.size(), transEditor);
250 m_editors[model].transTexts << transEditor;
256 font.setPointSize(
static_cast<
int>(m_fontSize));
259 for (
int model = 0; ; ++model) {
262 if (med.transTexts.contains(snd)) {
265 te->installEventFilter(
this);
267 if (m_visualizeWhitespace) {
268 QTextOption option = te->document()->defaultTextOption();
270 option.setFlags(option.flags()
271 | QTextOption::ShowLineAndParagraphSeparators
272 | QTextOption::ShowTabsAndSpaces);
273 te->document()->setDefaultTextOption(option);
284 if (m_selectionHolder == sender())
290 m_tabOrderTimer.start(0);
295 QWidget *prev =
this;
296 for (
const MessageEditorData &med : std::as_const(m_editors)) {
297 for (FormMultiWidget *fmw : med.transTexts)
298 for (QTextEdit *te : fmw->getEditors()) {
299 setTabOrder(prev, te);
302 QTextEdit *te = med.transCommentText->getEditor();
303 setTabOrder(prev, te);
309
310
311
312
313
314
317 QStringList translations;
318 for (
int i = 0; i < m_editors[model].transTexts.size() &&
319 m_editors[model].transTexts.at(i)->isVisible(); ++i)
320 translations << m_editors[model].transTexts[i]->getTranslation();
326 bool oldBlockState = t->blockSignals(
true);
327 QTextCursor c = t->textCursor();
330 t->blockSignals(oldBlockState);
335 if (te != m_selectionHolder) {
336 if (m_selectionHolder) {
339 disconnect(fte, &FormatTextEdit::editorDestroyed,
340 this, &MessageEditor::editorDestroyed);
343 m_selectionHolder = (te->textCursor().hasSelection() ? te :
nullptr);
345 connect(fte, &FormatTextEdit::editorDestroyed,
346 this, &MessageEditor::editorDestroyed);
348#ifndef QT_NO_CLIPBOARD
356 if (m_selectionHolder &&
364 if (m_selectionHolder) {
367 disconnect(fte, &FormatTextEdit::editorDestroyed,
368 this, &MessageEditor::editorDestroyed);
370 m_selectionHolder =
nullptr;
371#ifndef QT_NO_CLIPBOARD
377void MessageEditor::activeModelAndNumerus(
int *model,
int *numerus)
const
379 for (
int j = 0; j < m_editors.size(); ++j) {
380 for (
int i = 0; i < m_editors[j].transTexts.size(); ++i)
381 for (QTextEdit *te : m_editors[j].transTexts[i]->getEditors())
382 if (m_focusWidget == te) {
387 if (m_focusWidget == m_editors[j].transCommentText->getEditor()) {
399 if (m_currentNumerus < 0)
401 const QList<FormatTextEdit *> &editors =
402 m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditors();
403 for (QTextEdit *te : editors)
406 return editors.first();
411 if (m_currentNumerus < 0) {
412 for (
int i = 0; i < m_editors.size(); ++i)
413 if (m_editors[i].container->isVisible()
414 && !m_editors[i].transTexts.first()->getEditors().first()->isReadOnly())
415 return m_editors[i].transTexts.first()->getEditors().first();
418 return activeTranslation();
423 if (m_currentModel < 0 || m_currentNumerus >= 0)
425 return m_editors[m_currentModel].transCommentText->getEditor();
430 if (QTextEdit *te = activeTransComment())
432 return activeTranslation();
437 if (QTextEdit *te = activeTransComment())
439 return activeOr1stTranslation();
444 const QStringList &numerusForms = m_dataModel->model(model)->numerusForms();
445 const QString &langLocalized = m_dataModel
->model(model
)->localizedLanguage();
446 for (
int i = 0; i < numerusForms.size(); ++i) {
447 const QString &label = tr(
"Translation to %1 (%2)").arg(langLocalized, numerusForms[i]);
449 m_editors[model].firstForm = label;
450 if (i >= m_editors[model].transTexts.size())
451 addPluralForm(model, label, m_dataModel->isModelWritable(model));
453 m_editors[model].transTexts[i]->setLabel(label);
454 m_editors[model].transTexts[i]->setVisible(!i || m_editors[model].pluralEditMode);
455 m_editors[model].transTexts[i]->setWhatsThis(
456 tr(
"This is where you can enter or modify"
457 " the translation of the above source text.") );
459 for (
int j = m_editors[model].transTexts.size() - numerusForms.size(); j > 0; --j)
460 delete m_editors[model].transTexts.takeLast();
461 m_editors[model].invariantForm = tr(
"Translation to %1").arg(langLocalized);
462 m_editors[model].transCommentText->setLabel(tr(
"Translator comments for %1").arg(langLocalized));
467 for (
int j = 0; j < m_editors.size(); ++j) {
468 for (
int i = 0; i < m_editors[j].transTexts.size(); ++i)
469 for (QTextEdit *te : m_editors[j].transTexts[i]->getEditors())
471 return &m_editors[j];
472 if (m_editors[j].transCommentText->getEditor() == o)
473 return &m_editors[j];
481 if (e->type() == QEvent::ShortcutOverride) {
482 QKeyEvent *ke =
static_cast<QKeyEvent *>(e);
484 if (ke->modifiers() & Qt::ControlModifier) {
485#ifndef QT_NO_CLIPBOARD
486 if (ke->key() == Qt::Key_C) {
491 if (m_pluralSource
->getEditor()->textCursor().hasSelection()) {
497 if (ke->key() == Qt::Key_A) {
501 }
else if (e->type() == QEvent::KeyPress) {
503 QKeyEvent *ke =
static_cast<QKeyEvent *>(e);
504 if (ke->key() == Qt::Key_Tab &&
505 !(ke->modifiers() & Qt::ControlModifier)) {
509 }
else if (e->type() == QEvent::FocusIn) {
510 QWidget *widget =
static_cast<QWidget *>(o);
511 if (widget != m_focusWidget)
515 return QScrollArea::eventFilter(o, e);
520 if (widget != m_focusWidget) {
528 m_focusWidget = widget;
531 activeModelAndNumerus(&model, &numerus);
532 if (model != m_currentModel || numerus != m_currentNumerus) {
534 m_currentModel = model;
535 m_currentNumerus = numerus;
536 emit activeModelChanged(activeModel());
537 updateBeginFromSource();
539#ifndef QT_NO_CLIPBOARD
550 for (
int j = 0; j < m_editors.size(); ++j) {
551 setEditingEnabled(j,
false);
552 for (FormMultiWidget *widget : std::as_const(m_editors[j].transTexts))
553 widget->clearTranslation();
554 m_editors[j].transCommentText->clearTranslation();
556#ifndef QT_NO_CLIPBOARD
557 emit pasteAvailable(
false);
559 updateBeginFromSource();
565 m_currentIndex = index;
568 for (
int j = 0; j < m_editors.size(); ++j) {
574 ed.container->hide();
577 ed.container->show();
585 if (!item->fileName().isEmpty()) {
586 QString toolTip = tr(
"'%1'\nLine: %2").arg(item->fileName(), QString::number(item->lineNumber()));
587 m_source->setToolTip(toolTip);
589 m_source->setToolTip(QLatin1String(
""));
593 QString commentText = item->comment().simplified();
595 if (!item->extraComment().isEmpty()) {
596 if (!commentText.isEmpty())
597 commentText += QLatin1String(
"\n");
598 commentText += item->extraComment().simplified();
612 ed.transTexts.first()->setLabel(ed
.pluralEditMode ? ed.firstForm : ed.invariantForm);
615 if (item->text().isEmpty() && !item->context().isEmpty()) {
616 for (
int i = 0; i < ed.transTexts.size(); ++i)
617 ed.transTexts.at(i)->setVisible(
false);
619 QStringList normalizedTranslations =
620 m_dataModel->model(j)->normalizedTranslations(*item);
621 for (
int i = 0; i < ed.transTexts.size(); ++i) {
622 bool shouldShow = (i < normalizedTranslations.size());
624 setNumerusTranslation(j, normalizedTranslations.at(i), i);
626 setNumerusTranslation(j, QString(), i);
627 ed.transTexts.at(i)->setVisible(i == 0 || shouldShow);
637void MessageEditor::setNumerusTranslation(
int model,
const QString &translation,
int numerus)
640 if (numerus >= ed.transTexts.size())
645 updateBeginFromSource();
648void MessageEditor::setTranslation(
int latestModel,
const QString &translation)
651 if (m_currentNumerus < 0) {
654 latestModel = m_currentModel;
655 numerus = m_currentNumerus;
657 FormMultiWidget *transForm = m_editors[latestModel].transTexts[numerus];
658 transForm->getEditors().first()->setFocus();
661 updateBeginFromSource();
664void MessageEditor::setEditingEnabled(
int model,
bool enabled)
667 for (FormMultiWidget *widget : std::as_const(ed.transTexts))
668 widget->setEditingEnabled(enabled);
671#ifndef QT_NO_CLIPBOARD
678 m_lengthVariants = on;
679 for (
const MessageEditorData &ed : std::as_const(m_editors))
680 for (FormMultiWidget *widget : ed.transTexts)
681 widget->setMultiEnabled(on);
686 activeEditor()->document()->undo();
691 activeEditor()->document()->redo();
696 bool newUndoAvail =
false;
697 bool newRedoAvail =
false;
698 if (QTextEdit *te = activeEditor()) {
699 QTextDocument *doc = te->document();
700 newUndoAvail = doc->isUndoAvailable();
701 newRedoAvail = doc->isRedoAvailable();
704 if (newUndoAvail != m_undoAvail) {
705 m_undoAvail = newUndoAvail;
706 emit undoAvailable(newUndoAvail);
709 if (newRedoAvail != m_redoAvail) {
710 m_redoAvail = newRedoAvail;
711 emit redoAvailable(newRedoAvail);
715#ifndef QT_NO_CLIPBOARD
718 m_selectionHolder->cut();
723 m_selectionHolder->copy();
728 bool newCopyState =
false;
729 bool newCutState =
false;
731 if (m_selectionHolder) {
733 newCutState = !m_selectionHolder->isReadOnly();
736 if (newCopyState != m_copyAvail) {
737 m_copyAvail = newCopyState;
738 emit copyAvailable(m_copyAvail);
741 if (newCutState != m_cutAvail) {
742 m_cutAvail = newCutState;
743 emit cutAvailable(m_cutAvail);
749 activeEditor()->paste();
755 emit pasteAvailable(!m_clipboardEmpty
756 && (te = activeEditor()) && !te->isReadOnly());
762 m_clipboardEmpty = qApp->clipboard()->text().isNull();
774 || ((te = activeEditor()) && te->hasFocus()))
781 updateBeginFromSource();
783 emit translationChanged(translations(m_currentModel));
786void MessageEditor::emitTranslatorCommentChanged(QTextEdit *widget)
790 emit translatorCommentChanged(m_editors[m_currentModel].transCommentText->getTranslation());
795 bool overwrite =
false;
796 if (QTextEdit *activeEditor = activeTranslation())
797 overwrite = !activeEditor->isReadOnly()
798 && activeEditor->toPlainText().trimmed().isEmpty();
799 emit beginFromSourceAvailable(overwrite);
805 setTranslation(m_currentModel,
806 m_currentNumerus > 0 && !item->pluralText().isEmpty() ?
807 item->pluralText() : item->text());
812 if (!widget()->hasFocus())
813 if (QTextEdit *activeEditor = activeOr1stEditor())
814 activeEditor->setFocus();
819 if (m_currentModel != model) {
822 m_currentNumerus = -1;
825 emit activeModelChanged(activeModel());
826 updateBeginFromSource();
828#ifndef QT_NO_CLIPBOARD
832 m_editors[model].transTexts.first()->getEditors().first()->setFocus();
839 for (
int j = start; j < m_editors.size(); ++j)
843 m_editors[j].transTexts.first()->getEditors().first()->setFocus();
851 focusNextUnfinished(0);
856 return focusNextUnfinished(m_currentModel + 1);
861 m_visualizeWhitespace = value;
866 for (
const MessageEditorData &med : std::as_const(m_editors)) {
867 med.transCommentText->getEditor()->setVisualizeWhitespace(value);
868 for (FormMultiWidget *widget : med.transTexts)
869 for (FormatTextEdit *te : widget->getEditors())
870 te->setVisualizeWhitespace(value);
876 if (m_fontSize != fontSize) {
877 m_fontSize = fontSize;
890 font.setPointSize(
static_cast<
int>(m_fontSize));
896 for (
const MessageEditorData &med : std::as_const(m_editors)) {
897 for (FormMultiWidget *fmw : med.transTexts)
898 for (QTextEdit *te : fmw->getEditors())
900 med.transCommentText->getEditor()->setFont(font);
906 if (m_fontSize >= 32)
915 if (m_fontSize > 8) {
923 m_fontSize = font().pointSize();
void setVisualizeWhitespace(bool value)
void setLengthVariants(bool on)
void setVisualizeWhitespace(bool value)
void setEditorFocusForModel(int model)
void setFontSize(const float fontSize)
void setUnfinishedEditorFocus()
bool focusNextUnfinished()
void showMessage(const MultiDataIndex &index)
bool eventFilter(QObject *, QEvent *) override
const TranslatorMessage & message() const
TranslatorMessage::Type type() const
MessageItem * messageItem(const MultiDataIndex &index, int model) const
bool isModelWritable(int model) const
static void clearSelection(QTextEdit *t)
Combined button and popup list for selecting options.
FormWidget * transCommentText