summaryrefslogtreecommitdiffstats
path: root/src/linguist/linguist/messageeditor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/linguist/linguist/messageeditor.cpp')
-rw-r--r--src/linguist/linguist/messageeditor.cpp880
1 files changed, 880 insertions, 0 deletions
diff --git a/src/linguist/linguist/messageeditor.cpp b/src/linguist/linguist/messageeditor.cpp
new file mode 100644
index 000000000..3a705c1a7
--- /dev/null
+++ b/src/linguist/linguist/messageeditor.cpp
@@ -0,0 +1,880 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the Qt Linguist of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/* TRANSLATOR MessageEditor
+
+ This is the right panel of the main window.
+*/
+
+#include "messageeditor.h"
+#include "messageeditorwidgets.h"
+#include "simtexth.h"
+#include "phrasemodel.h"
+
+#include <QApplication>
+#include <QBoxLayout>
+#include <QClipboard>
+#include <QDebug>
+#include <QDockWidget>
+#include <QHeaderView>
+#include <QKeyEvent>
+#include <QMainWindow>
+#include <QPainter>
+#include <QTreeView>
+#include <QVBoxLayout>
+
+QT_BEGIN_NAMESPACE
+
+#ifdef NEVER_TRUE
+// Allow translators to provide localized names for QLocale::languageToString
+// At least the own language should be translated ... This is a "hack" until
+// functionality is provided within Qt (see task 196275).
+static const char * language_strings[] =
+{
+ QT_TRANSLATE_NOOP("MessageEditor", "Russian"),
+ QT_TRANSLATE_NOOP("MessageEditor", "German"),
+ QT_TRANSLATE_NOOP("MessageEditor", "Japanese"),
+ QT_TRANSLATE_NOOP("MessageEditor", "French"),
+ QT_TRANSLATE_NOOP("MessageEditor", "Polish"),
+ QT_TRANSLATE_NOOP("MessageEditor", "Chinese")
+};
+#endif
+
+/*
+ MessageEditor class impl.
+
+ Handles layout of dock windows and the editor page.
+*/
+MessageEditor::MessageEditor(MultiDataModel *dataModel, QMainWindow *parent)
+ : QScrollArea(parent->centralWidget()),
+ m_dataModel(dataModel),
+ m_currentModel(-1),
+ m_currentNumerus(-1),
+ m_lengthVariants(false),
+ m_undoAvail(false),
+ m_redoAvail(false),
+ m_cutAvail(false),
+ m_copyAvail(false),
+ m_selectionHolder(0),
+ m_focusWidget(0)
+{
+ setObjectName(QLatin1String("scroll area"));
+
+ QPalette p;
+ p.setBrush(QPalette::Window, p.brush(QPalette::Active, QPalette::Base));
+ setPalette(p);
+
+ setupEditorPage();
+
+ // Signals
+ connect(qApp->clipboard(), SIGNAL(dataChanged()),
+ SLOT(clipboardChanged()));
+ connect(m_dataModel, SIGNAL(modelAppended()),
+ SLOT(messageModelAppended()));
+ connect(m_dataModel, SIGNAL(modelDeleted(int)),
+ SLOT(messageModelDeleted(int)));
+ connect(m_dataModel, SIGNAL(allModelsDeleted()),
+ SLOT(allModelsDeleted()));
+ connect(m_dataModel, SIGNAL(languageChanged(int)),
+ SLOT(setTargetLanguage(int)));
+
+ m_tabOrderTimer.setSingleShot(true);
+ connect(&m_tabOrderTimer, SIGNAL(timeout()), SLOT(reallyFixTabOrder()));
+
+ clipboardChanged();
+
+ setWhatsThis(tr("This whole panel allows you to view and edit "
+ "the translation of some source text."));
+ showNothing();
+}
+
+void MessageEditor::setupEditorPage()
+{
+ QFrame *editorPage = new QFrame;
+ editorPage->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
+
+ m_source = new FormWidget(tr("Source text"), false);
+ m_source->setHideWhenEmpty(true);
+ m_source->setWhatsThis(tr("This area shows the source text."));
+ connect(m_source, SIGNAL(selectionChanged(QTextEdit*)),
+ SLOT(selectionChanged(QTextEdit*)));
+
+ m_pluralSource = new FormWidget(tr("Source text (Plural)"), false);
+ m_pluralSource->setHideWhenEmpty(true);
+ m_pluralSource->setWhatsThis(tr("This area shows the plural form of the source text."));
+ connect(m_pluralSource, SIGNAL(selectionChanged(QTextEdit*)),
+ SLOT(selectionChanged(QTextEdit*)));
+
+ m_commentText = new FormWidget(tr("Developer comments"), false);
+ m_commentText->setHideWhenEmpty(true);
+ m_commentText->setObjectName(QLatin1String("comment/context view"));
+ m_commentText->setWhatsThis(tr("This area shows a comment that"
+ " may guide you, and the context in which the text"
+ " occurs.") );
+
+ QBoxLayout *subLayout = new QVBoxLayout;
+
+ subLayout->setMargin(5);
+ subLayout->addWidget(m_source);
+ subLayout->addWidget(m_pluralSource);
+ subLayout->addWidget(m_commentText);
+
+ m_layout = new QVBoxLayout;
+ m_layout->setSpacing(2);
+ m_layout->setMargin(2);
+ m_layout->addLayout(subLayout);
+ m_layout->addStretch(1);
+ editorPage->setLayout(m_layout);
+
+ setWidget(editorPage);
+ setWidgetResizable(true);
+}
+
+QPalette MessageEditor::paletteForModel(int model) const
+{
+ QBrush brush = m_dataModel->brushForModel(model);
+ QPalette pal;
+
+ if (m_dataModel->isModelWritable(model)) {
+ pal.setBrush(QPalette::Window, brush);
+ } else {
+ QPixmap pm(brush.texture().size());
+ pm.fill();
+ QPainter p(&pm);
+ p.fillRect(brush.texture().rect(), brush);
+ pal.setBrush(QPalette::Window, pm);
+ }
+ return pal;
+}
+
+void MessageEditor::messageModelAppended()
+{
+ int model = m_editors.size();
+ m_editors.append(MessageEditorData());
+ MessageEditorData &ed = m_editors.last();
+ ed.pluralEditMode = false;
+ ed.fontSize = font().pointSize();
+ ed.container = new QWidget;
+ if (model > 0) {
+ ed.container->setPalette(paletteForModel(model));
+ ed.container->setAutoFillBackground(true);
+ if (model == 1) {
+ m_editors[0].container->setPalette(paletteForModel(0));
+ m_editors[0].container->setAutoFillBackground(true);
+ }
+ }
+ bool writable = m_dataModel->isModelWritable(model);
+ ed.transCommentText = new FormWidget(QString(), true);
+ ed.transCommentText->setEditingEnabled(writable);
+ ed.transCommentText->setHideWhenEmpty(!writable);
+ ed.transCommentText->setWhatsThis(tr("Here you can enter comments for your own use."
+ " They have no effect on the translated applications.") );
+ ed.transCommentText->getEditor()->installEventFilter(this);
+ connect(ed.transCommentText, SIGNAL(selectionChanged(QTextEdit*)),
+ SLOT(selectionChanged(QTextEdit*)));
+ connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit*)),
+ SLOT(emitTranslatorCommentChanged(QTextEdit*)));
+ connect(ed.transCommentText, SIGNAL(textChanged(QTextEdit*)), SLOT(resetHoverSelection()));
+ connect(ed.transCommentText, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection()));
+ fixTabOrder();
+ QBoxLayout *box = new QVBoxLayout(ed.container);
+ box->setMargin(5);
+ box->addWidget(ed.transCommentText);
+ box->addSpacing(ed.transCommentText->getEditor()->fontMetrics().height() / 2);
+ m_layout->addWidget(ed.container);
+ setTargetLanguage(model);
+}
+
+void MessageEditor::allModelsDeleted()
+{
+ foreach (const MessageEditorData &med, m_editors)
+ med.container->deleteLater();
+ m_editors.clear();
+ m_currentModel = -1;
+ // Do not emit activeModelChanged() - the main window will refresh anyway
+ m_currentNumerus = -1;
+ showNothing();
+}
+
+void MessageEditor::messageModelDeleted(int model)
+{
+ m_editors[model].container->deleteLater();
+ m_editors.removeAt(model);
+ if (model <= m_currentModel) {
+ if (model < m_currentModel || m_currentModel == m_editors.size())
+ --m_currentModel;
+ // Do not emit activeModelChanged() - the main window will refresh anyway
+ if (m_currentModel >= 0) {
+ if (m_currentNumerus >= m_editors[m_currentModel].transTexts.size())
+ m_currentNumerus = m_editors[m_currentModel].transTexts.size() - 1;
+ activeEditor()->setFocus();
+ } else {
+ m_currentNumerus = -1;
+ }
+ }
+ if (m_editors.size() == 1) {
+ m_editors[0].container->setAutoFillBackground(false);
+ } else {
+ for (int i = model; i < m_editors.size(); ++i)
+ m_editors[i].container->setPalette(paletteForModel(i));
+ }
+}
+
+void MessageEditor::addPluralForm(int model, const QString &label, bool writable)
+{
+ FormMultiWidget *transEditor = new FormMultiWidget(label);
+ connect(transEditor, SIGNAL(editorCreated(QTextEdit*)), SLOT(editorCreated(QTextEdit*)));
+ transEditor->setEditingEnabled(writable);
+ transEditor->setHideWhenEmpty(!writable);
+ if (!m_editors[model].transTexts.isEmpty())
+ transEditor->setVisible(false);
+ transEditor->setMultiEnabled(m_lengthVariants);
+ static_cast<QBoxLayout *>(m_editors[model].container->layout())->insertWidget(
+ m_editors[model].transTexts.count(), transEditor);
+
+ connect(transEditor, SIGNAL(selectionChanged(QTextEdit*)),
+ SLOT(selectionChanged(QTextEdit*)));
+ connect(transEditor, SIGNAL(textChanged(QTextEdit*)),
+ SLOT(emitTranslationChanged(QTextEdit*)));
+ connect(transEditor, SIGNAL(textChanged(QTextEdit*)), SLOT(resetHoverSelection()));
+ connect(transEditor, SIGNAL(cursorPositionChanged()), SLOT(resetHoverSelection()));
+
+ m_editors[model].transTexts << transEditor;
+}
+
+void MessageEditor::editorCreated(QTextEdit *te)
+{
+ FormMultiWidget *snd = static_cast<FormMultiWidget *>(sender());
+ for (int model = 0; ; ++model) {
+ MessageEditorData med = m_editors.at(model);
+ if (med.transTexts.contains(snd)) {
+ QFont font;
+ font.setPointSize(static_cast<int>(med.fontSize));
+ te->setFont(font);
+
+ te->installEventFilter(this);
+
+ fixTabOrder();
+ return;
+ }
+ }
+}
+
+void MessageEditor::fixTabOrder()
+{
+ m_tabOrderTimer.start(0);
+}
+
+void MessageEditor::reallyFixTabOrder()
+{
+ QWidget *prev = this;
+ foreach (const MessageEditorData &med, m_editors) {
+ foreach (FormMultiWidget *fmw, med.transTexts)
+ foreach (QTextEdit *te, fmw->getEditors()) {
+ setTabOrder(prev, te);
+ prev = te;
+ }
+ QTextEdit *te = med.transCommentText->getEditor();
+ setTabOrder(prev, te);
+ prev = te;
+ }
+}
+
+/*! internal
+ Returns all translations for an item.
+ The number of translations is dependent on if we have a plural form or not.
+ If we don't have a plural form, then this should only contain one item.
+ Otherwise it will contain the number of numerus forms for the particular language.
+*/
+QStringList MessageEditor::translations(int model) const
+{
+ QStringList translations;
+ for (int i = 0; i < m_editors[model].transTexts.count() &&
+ m_editors[model].transTexts.at(i)->isVisible(); ++i)
+ translations << m_editors[model].transTexts[i]->getTranslation();
+ return translations;
+}
+
+static void clearSelection(QTextEdit *t)
+{
+ bool oldBlockState = t->blockSignals(true);
+ QTextCursor c = t->textCursor();
+ c.clearSelection();
+ t->setTextCursor(c);
+ t->blockSignals(oldBlockState);
+}
+
+void MessageEditor::selectionChanged(QTextEdit *te)
+{
+ if (te != m_selectionHolder) {
+ if (m_selectionHolder)
+ clearSelection(m_selectionHolder);
+ m_selectionHolder = (te->textCursor().hasSelection() ? te : 0);
+ updateCanCutCopy();
+ }
+}
+
+void MessageEditor::resetHoverSelection()
+{
+ if (m_selectionHolder &&
+ (m_selectionHolder == m_source->getEditor()
+ || m_selectionHolder == m_pluralSource->getEditor()))
+ resetSelection();
+}
+
+void MessageEditor::resetSelection()
+{
+ if (m_selectionHolder) {
+ clearSelection(m_selectionHolder);
+ m_selectionHolder = 0;
+ updateCanCutCopy();
+ }
+}
+
+void MessageEditor::activeModelAndNumerus(int *model, int *numerus) const
+{
+ for (int j = 0; j < m_editors.count(); ++j) {
+ for (int i = 0; i < m_editors[j].transTexts.count(); ++i)
+ foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors())
+ if (m_focusWidget == te) {
+ *model = j;
+ *numerus = i;
+ return;
+ }
+ if (m_focusWidget == m_editors[j].transCommentText->getEditor()) {
+ *model = j;
+ *numerus = -1;
+ return;
+ }
+ }
+ *model = -1;
+ *numerus = -1;
+}
+
+QTextEdit *MessageEditor::activeTranslation() const
+{
+ if (m_currentNumerus < 0)
+ return 0;
+ const QList<FormatTextEdit *> &editors =
+ m_editors[m_currentModel].transTexts[m_currentNumerus]->getEditors();
+ foreach (QTextEdit *te, editors)
+ if (te->hasFocus())
+ return te;
+ return editors.first();
+}
+
+QTextEdit *MessageEditor::activeOr1stTranslation() const
+{
+ if (m_currentNumerus < 0) {
+ for (int i = 0; i < m_editors.size(); ++i)
+ if (m_editors[i].container->isVisible()
+ && !m_editors[i].transTexts.first()->getEditors().first()->isReadOnly())
+ return m_editors[i].transTexts.first()->getEditors().first();
+ return 0;
+ }
+ return activeTranslation();
+}
+
+QTextEdit *MessageEditor::activeTransComment() const
+{
+ if (m_currentModel < 0 || m_currentNumerus >= 0)
+ return 0;
+ return m_editors[m_currentModel].transCommentText->getEditor();
+}
+
+QTextEdit *MessageEditor::activeEditor() const
+{
+ if (QTextEdit *te = activeTransComment())
+ return te;
+ return activeTranslation();
+}
+
+QTextEdit *MessageEditor::activeOr1stEditor() const
+{
+ if (QTextEdit *te = activeTransComment())
+ return te;
+ return activeOr1stTranslation();
+}
+
+void MessageEditor::setTargetLanguage(int model)
+{
+ const QStringList &numerusForms = m_dataModel->model(model)->numerusForms();
+ const QString &langLocalized = m_dataModel->model(model)->localizedLanguage();
+ for (int i = 0; i < numerusForms.count(); ++i) {
+ const QString &label = tr("%1 translation (%2)").arg(langLocalized, numerusForms[i]);
+ if (!i)
+ m_editors[model].firstForm = label;
+ if (i >= m_editors[model].transTexts.count())
+ addPluralForm(model, label, m_dataModel->isModelWritable(model));
+ else
+ m_editors[model].transTexts[i]->setLabel(label);
+ m_editors[model].transTexts[i]->setVisible(!i || m_editors[model].pluralEditMode);
+ m_editors[model].transTexts[i]->setWhatsThis(
+ tr("This is where you can enter or modify"
+ " the translation of the above source text.") );
+ }
+ for (int j = m_editors[model].transTexts.count() - numerusForms.count(); j > 0; --j)
+ delete m_editors[model].transTexts.takeLast();
+ m_editors[model].invariantForm = tr("%1 translation").arg(langLocalized);
+ m_editors[model].transCommentText->setLabel(tr("%1 translator comments").arg(langLocalized));
+}
+
+MessageEditorData *MessageEditor::modelForWidget(const QObject *o)
+{
+ for (int j = 0; j < m_editors.count(); ++j) {
+ for (int i = 0; i < m_editors[j].transTexts.count(); ++i)
+ foreach (QTextEdit *te, m_editors[j].transTexts[i]->getEditors())
+ if (te == o)
+ return &m_editors[j];
+ if (m_editors[j].transCommentText->getEditor() == o)
+ return &m_editors[j];
+ }
+ return 0;
+}
+
+static bool applyFont(MessageEditorData *med)
+{
+ QFont font;
+ font.setPointSize(static_cast<int>(med->fontSize));
+ for (int i = 0; i < med->transTexts.count(); ++i)
+ foreach (QTextEdit *te, med->transTexts[i]->getEditors())
+ te->setFont(font);
+ med->transCommentText->getEditor()->setFont(font);
+ return true;
+}
+
+static bool incFont(MessageEditorData *med)
+{
+ if (!med || med->fontSize >= 32)
+ return true;
+ med->fontSize *= 1.2;
+ return applyFont(med);
+}
+
+static bool decFont(MessageEditorData *med)
+{
+ if (!med || med->fontSize <= 8)
+ return true;
+ med->fontSize /= 1.2;
+ return applyFont(med);
+}
+
+bool MessageEditor::eventFilter(QObject *o, QEvent *e)
+{
+ // handle copying from the source
+ if (e->type() == QEvent::ShortcutOverride) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+
+ if (ke->modifiers() & Qt::ControlModifier) {
+ if (ke->key() == Qt::Key_C) {
+ if (m_source->getEditor()->textCursor().hasSelection()) {
+ m_source->getEditor()->copy();
+ return true;
+ }
+ if (m_pluralSource->getEditor()->textCursor().hasSelection()) {
+ m_pluralSource->getEditor()->copy();
+ return true;
+ }
+ } else if (ke->key() == Qt::Key_A) {
+ return true;
+ }
+ }
+ } else if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+ if (ke->modifiers() & Qt::ControlModifier) {
+ if (ke->key() == Qt::Key_Plus || ke->key() == Qt::Key_Equal)
+ return incFont(modelForWidget(o));
+ if (ke->key() == Qt::Key_Minus)
+ return decFont(modelForWidget(o));
+ } else {
+ // Ctrl-Tab is still passed through to the textedit and causes a tab to be inserted.
+ if (ke->key() == Qt::Key_Tab) {
+ focusNextChild();
+ return true;
+ }
+ }
+ } else if (e->type() == QEvent::Wheel) {
+ QWheelEvent *we = static_cast<QWheelEvent *>(e);
+ if (we->modifiers() & Qt::ControlModifier) {
+ if (we->delta() > 0)
+ return incFont(modelForWidget(o));
+ return decFont(modelForWidget(o));
+ }
+ } else if (e->type() == QEvent::FocusIn) {
+ QWidget *widget = static_cast<QWidget *>(o);
+ if (widget != m_focusWidget)
+ trackFocus(widget);
+ }
+
+ return QScrollArea::eventFilter(o, e);
+}
+
+void MessageEditor::grabFocus(QWidget *widget)
+{
+ if (widget != m_focusWidget) {
+ widget->setFocus();
+ trackFocus(widget);
+ }
+}
+
+void MessageEditor::trackFocus(QWidget *widget)
+{
+ m_focusWidget = widget;
+
+ int model, numerus;
+ activeModelAndNumerus(&model, &numerus);
+ if (model != m_currentModel || numerus != m_currentNumerus) {
+ resetSelection();
+ m_currentModel = model;
+ m_currentNumerus = numerus;
+ emit activeModelChanged(activeModel());
+ updateBeginFromSource();
+ updateUndoRedo();
+ updateCanPaste();
+ }
+}
+
+void MessageEditor::showNothing()
+{
+ m_source->clearTranslation();
+ m_pluralSource->clearTranslation();
+ m_commentText->clearTranslation();
+ for (int j = 0; j < m_editors.count(); ++j) {
+ setEditingEnabled(j, false);
+ foreach (FormMultiWidget *widget, m_editors[j].transTexts)
+ widget->clearTranslation();
+ m_editors[j].transCommentText->clearTranslation();
+ }
+ emit pasteAvailable(false);
+ updateBeginFromSource();
+ updateUndoRedo();
+}
+
+void MessageEditor::showMessage(const MultiDataIndex &index)
+{
+ m_currentIndex = index;
+
+ bool hadMsg = false;
+ for (int j = 0; j < m_editors.size(); ++j) {
+
+ MessageEditorData &ed = m_editors[j];
+
+ MessageItem *item = m_dataModel->messageItem(index, j);
+ if (!item) {
+ ed.container->hide();
+ continue;
+ }
+ ed.container->show();
+
+ if (!hadMsg) {
+
+ // Source text form
+ m_source->setTranslation(item->text());
+ m_pluralSource->setTranslation(item->pluralText());
+ // Use location from first non-obsolete message
+ if (!item->fileName().isEmpty()) {
+ QString toolTip = tr("'%1'\nLine: %2").arg(item->fileName(), QString::number(item->lineNumber()));
+ m_source->setToolTip(toolTip);
+ } else {
+ m_source->setToolTip(QLatin1String(""));
+ }
+
+ // Comment field
+ QString commentText = item->comment().simplified();
+
+ if (!item->extraComment().isEmpty()) {
+ if (!commentText.isEmpty())
+ commentText += QLatin1String("\n");
+ commentText += item->extraComment().simplified();
+ }
+
+ m_commentText->setTranslation(commentText);
+
+ hadMsg = true;
+ }
+
+ setEditingEnabled(j, m_dataModel->isModelWritable(j)
+ && item->message().type() != TranslatorMessage::Obsolete);
+
+ // Translation label
+ ed.pluralEditMode = item->translations().count() > 1;
+ ed.transTexts.first()->setLabel(ed.pluralEditMode ? ed.firstForm : ed.invariantForm);
+
+ // Translation forms
+ if (item->text().isEmpty() && !item->context().isEmpty()) {
+ for (int i = 0; i < ed.transTexts.size(); ++i)
+ ed.transTexts.at(i)->setVisible(false);
+ } else {
+ QStringList normalizedTranslations =
+ m_dataModel->model(j)->normalizedTranslations(*item);
+ for (int i = 0; i < ed.transTexts.size(); ++i) {
+ bool shouldShow = (i < normalizedTranslations.count());
+ if (shouldShow)
+ setTranslation(j, normalizedTranslations.at(i), i);
+ else
+ setTranslation(j, QString(), i);
+ ed.transTexts.at(i)->setVisible(i == 0 || shouldShow);
+ }
+ }
+
+ ed.transCommentText->setTranslation(item->translatorComment().trimmed(), false);
+ }
+
+ updateUndoRedo();
+}
+
+void MessageEditor::setTranslation(int model, const QString &translation, int numerus)
+{
+ MessageEditorData &ed = m_editors[model];
+ if (numerus >= ed.transTexts.count())
+ numerus = 0;
+ FormMultiWidget *transForm = ed.transTexts[numerus];
+ transForm->setTranslation(translation, false);
+
+ updateBeginFromSource();
+}
+
+void MessageEditor::setTranslation(int latestModel, const QString &translation)
+{
+ int numerus;
+ if (m_currentNumerus < 0) {
+ numerus = 0;
+ } else {
+ latestModel = m_currentModel;
+ numerus = m_currentNumerus;
+ }
+ FormMultiWidget *transForm = m_editors[latestModel].transTexts[numerus];
+ transForm->getEditors().first()->setFocus();
+ transForm->setTranslation(translation, true);
+
+ updateBeginFromSource();
+}
+
+void MessageEditor::setEditingEnabled(int model, bool enabled)
+{
+ MessageEditorData &ed = m_editors[model];
+ foreach (FormMultiWidget *widget, ed.transTexts)
+ widget->setEditingEnabled(enabled);
+ ed.transCommentText->setEditingEnabled(enabled);
+
+ updateCanPaste();
+}
+
+void MessageEditor::setLengthVariants(bool on)
+{
+ m_lengthVariants = on;
+ foreach (const MessageEditorData &ed, m_editors)
+ foreach (FormMultiWidget *widget, ed.transTexts)
+ widget->setMultiEnabled(on);
+}
+
+void MessageEditor::undo()
+{
+ activeEditor()->document()->undo();
+}
+
+void MessageEditor::redo()
+{
+ activeEditor()->document()->redo();
+}
+
+void MessageEditor::updateUndoRedo()
+{
+ bool newUndoAvail = false;
+ bool newRedoAvail = false;
+ if (QTextEdit *te = activeEditor()) {
+ QTextDocument *doc = te->document();
+ newUndoAvail = doc->isUndoAvailable();
+ newRedoAvail = doc->isRedoAvailable();
+ }
+
+ if (newUndoAvail != m_undoAvail) {
+ m_undoAvail = newUndoAvail;
+ emit undoAvailable(newUndoAvail);
+ }
+
+ if (newRedoAvail != m_redoAvail) {
+ m_redoAvail = newRedoAvail;
+ emit redoAvailable(newRedoAvail);
+ }
+}
+
+void MessageEditor::cut()
+{
+ m_selectionHolder->cut();
+}
+
+void MessageEditor::copy()
+{
+ m_selectionHolder->copy();
+}
+
+void MessageEditor::updateCanCutCopy()
+{
+ bool newCopyState = false;
+ bool newCutState = false;
+
+ if (m_selectionHolder) {
+ newCopyState = true;
+ newCutState = !m_selectionHolder->isReadOnly();
+ }
+
+ if (newCopyState != m_copyAvail) {
+ m_copyAvail = newCopyState;
+ emit copyAvailable(m_copyAvail);
+ }
+
+ if (newCutState != m_cutAvail) {
+ m_cutAvail = newCutState;
+ emit cutAvailable(m_cutAvail);
+ }
+}
+
+void MessageEditor::paste()
+{
+ activeEditor()->paste();
+}
+
+void MessageEditor::updateCanPaste()
+{
+ QTextEdit *te;
+ emit pasteAvailable(!m_clipboardEmpty
+ && (te = activeEditor()) && !te->isReadOnly());
+}
+
+void MessageEditor::clipboardChanged()
+{
+ // this is expensive, so move it out of the common path in updateCanPaste
+ m_clipboardEmpty = qApp->clipboard()->text().isNull();
+ updateCanPaste();
+}
+
+void MessageEditor::selectAll()
+{
+ // make sure we don't select the selection of a translator textedit,
+ // if we really want the source text editor to be selected.
+ QTextEdit *te;
+ if ((te = m_source->getEditor())->underMouse()
+ || (te = m_pluralSource->getEditor())->underMouse()
+ || ((te = activeEditor()) && te->hasFocus()))
+ te->selectAll();
+}
+
+void MessageEditor::emitTranslationChanged(QTextEdit *widget)
+{
+ grabFocus(widget); // DND proofness
+ updateBeginFromSource();
+ updateUndoRedo();
+ emit translationChanged(translations(m_currentModel));
+}
+
+void MessageEditor::emitTranslatorCommentChanged(QTextEdit *widget)
+{
+ grabFocus(widget); // DND proofness
+ updateUndoRedo();
+ emit translatorCommentChanged(m_editors[m_currentModel].transCommentText->getTranslation());
+}
+
+void MessageEditor::updateBeginFromSource()
+{
+ bool overwrite = false;
+ if (QTextEdit *activeEditor = activeTranslation())
+ overwrite = !activeEditor->isReadOnly()
+ && activeEditor->toPlainText().trimmed().isEmpty();
+ emit beginFromSourceAvailable(overwrite);
+}
+
+void MessageEditor::beginFromSource()
+{
+ MessageItem *item = m_dataModel->messageItem(m_currentIndex, m_currentModel);
+ setTranslation(m_currentModel,
+ m_currentNumerus > 0 && !item->pluralText().isEmpty() ?
+ item->pluralText() : item->text());
+}
+
+void MessageEditor::setEditorFocus()
+{
+ if (!widget()->hasFocus())
+ if (QTextEdit *activeEditor = activeOr1stEditor())
+ activeEditor->setFocus();
+}
+
+void MessageEditor::setEditorFocus(int model)
+{
+ if (m_currentModel != model) {
+ if (model < 0) {
+ resetSelection();
+ m_currentNumerus = -1;
+ m_currentModel = -1;
+ m_focusWidget = 0;
+ emit activeModelChanged(activeModel());
+ updateBeginFromSource();
+ updateUndoRedo();
+ updateCanPaste();
+ } else {
+ m_editors[model].transTexts.first()->getEditors().first()->setFocus();
+ }
+ }
+}
+
+bool MessageEditor::focusNextUnfinished(int start)
+{
+ for (int j = start; j < m_editors.count(); ++j)
+ if (m_dataModel->isModelWritable(j))
+ if (MessageItem *item = m_dataModel->messageItem(m_currentIndex, j))
+ if (item->type() == TranslatorMessage::Unfinished) {
+ m_editors[j].transTexts.first()->getEditors().first()->setFocus();
+ return true;
+ }
+ return false;
+}
+
+void MessageEditor::setUnfinishedEditorFocus()
+{
+ focusNextUnfinished(0);
+}
+
+bool MessageEditor::focusNextUnfinished()
+{
+ return focusNextUnfinished(m_currentModel + 1);
+}
+
+QT_END_NAMESPACE