Warning, file /sdk/lokalize/src/editorview.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 This file is part of Lokalize (some bits of KBabel code were reused) 0003 0004 SPDX-FileCopyrightText: 2007-2014 Nick Shaforostoff <shafff@ukr.net> 0005 SPDX-FileCopyrightText: 1999-2000 Matthias Kiefer <matthias.kiefer@gmx.de> 0006 SPDX-FileCopyrightText: 2001-2004 Stanislav Visnovsky <visnovsky@kde.org> 0007 SPDX-FileCopyrightText: 2018-2019 Simon Depiets <sdepiets@gmail.com> 0008 0009 SPDX-License-Identifier: GPL-2.0-or-later WITH LicenseRef-Qt-Commercial-exception-1.0 0010 */ 0011 0012 #include "editorview.h" 0013 0014 #include "lokalize_debug.h" 0015 0016 #include "xlifftextedit.h" 0017 #include "project.h" 0018 #include "catalog.h" 0019 #include "cmd.h" 0020 #include "prefs_lokalize.h" 0021 #include "prefs.h" 0022 0023 #include <QTimer> 0024 #include <QMenu> 0025 #include <QDragEnterEvent> 0026 0027 #include <QLabel> 0028 #include <QHBoxLayout> 0029 #include <QTabBar> 0030 #include <QStringBuilder> 0031 0032 #include <klocalizedstring.h> 0033 #include <kmessagebox.h> 0034 #include <kled.h> 0035 #include <kstandardshortcut.h> 0036 #include <kcolorscheme.h> 0037 0038 //parent is set on qsplitter insertion 0039 LedsWidget::LedsWidget(QWidget* parent): QWidget(parent) 0040 { 0041 KColorScheme colorScheme(QPalette::Normal); 0042 0043 QHBoxLayout* layout = new QHBoxLayout(this); 0044 layout->addStretch(); 0045 layout->addWidget(new QLabel(i18nc("@label whether entry is fuzzy", "Not ready:"), this)); 0046 layout->addWidget(ledFuzzy = new KLed(colorScheme.foreground(KColorScheme::NeutralText).color()/*Qt::green*/, KLed::Off, KLed::Sunken, KLed::Rectangular)); 0047 layout->addWidget(new QLabel(i18nc("@label whether entry is untranslated", "Untranslated:"), this)); 0048 layout->addWidget(ledUntr = new KLed(colorScheme.foreground(KColorScheme::NegativeText).color()/*Qt::red*/, KLed::Off, KLed::Sunken, KLed::Rectangular)); 0049 layout->addSpacing(1); 0050 layout->addWidget(lblColumn = new QLabel(this)); 0051 layout->addStretch(); 0052 setMaximumHeight(minimumSizeHint().height()); 0053 } 0054 0055 void LedsWidget::contextMenuEvent(QContextMenuEvent* event) 0056 { 0057 QMenu menu; 0058 menu.addAction(i18nc("@action", "Hide")); 0059 if (!menu.exec(event->globalPos())) 0060 return; //NOTE the config doesn't seem to work 0061 Settings::setLeds(false); 0062 SettingsController::instance()->dirty = true; 0063 hide(); 0064 } 0065 0066 void LedsWidget::cursorPositionChanged(int column) 0067 { 0068 lblColumn->setText(i18nc("@info:label cursor position", "Column: %1", column)); 0069 } 0070 0071 0072 EditorView::EditorView(QWidget *parent, Catalog* catalog/*,keyEventHandler* kh*/) 0073 : QSplitter(Qt::Vertical, parent) 0074 , m_catalog(catalog) 0075 , m_sourceTextEdit(new TranslationUnitTextEdit(catalog, DocPosition::Source, this)) 0076 , m_targetTextEdit(new TranslationUnitTextEdit(catalog, DocPosition::Target, this)) 0077 , m_pluralTabBar(new QTabBar(this)) 0078 , m_leds(nullptr) 0079 , m_modifiedAfterFind(false) 0080 { 0081 m_pluralTabBar->hide(); 0082 m_sourceTextEdit->setWhatsThis(i18n("<qt><p><b>Original String</b></p>\n" 0083 "<p>This part of the window shows the original message\n" 0084 "of the currently displayed entry.</p></qt>")); 0085 m_sourceTextEdit->viewport()->setBackgroundRole(QPalette::Window); 0086 0087 m_sourceTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); 0088 m_targetTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); 0089 0090 0091 connect(m_targetTextEdit, &TranslationUnitTextEdit::contentsModified, this, &EditorView::resetFindForCurrent); 0092 connect(m_targetTextEdit, &TranslationUnitTextEdit::toggleApprovementRequested, this, &EditorView::toggleApprovement); 0093 connect(this, &EditorView::signalApprovedEntryDisplayed, m_targetTextEdit, &TranslationUnitTextEdit::reflectApprovementState); 0094 connect(m_sourceTextEdit, &TranslationUnitTextEdit::tagInsertRequested, m_targetTextEdit, &TranslationUnitTextEdit::insertTag); 0095 0096 connect(m_sourceTextEdit, &TranslationUnitTextEdit::binaryUnitSelectRequested, this, &EditorView::binaryUnitSelectRequested); 0097 connect(m_targetTextEdit, &TranslationUnitTextEdit::binaryUnitSelectRequested, this, &EditorView::binaryUnitSelectRequested); 0098 connect(m_sourceTextEdit, &TranslationUnitTextEdit::gotoEntryRequested, this, &EditorView::gotoEntryRequested); 0099 connect(m_targetTextEdit, &TranslationUnitTextEdit::gotoEntryRequested, this, &EditorView::gotoEntryRequested); 0100 0101 connect(m_sourceTextEdit, &TranslationUnitTextEdit::tmLookupRequested, this, &EditorView::tmLookupRequested); 0102 connect(m_targetTextEdit, &TranslationUnitTextEdit::tmLookupRequested, this, &EditorView::tmLookupRequested); 0103 0104 connect(m_sourceTextEdit, &TranslationUnitTextEdit::findRequested, this, &EditorView::findRequested); 0105 connect(m_targetTextEdit, &TranslationUnitTextEdit::findRequested, this, &EditorView::findRequested); 0106 connect(m_sourceTextEdit, &TranslationUnitTextEdit::findNextRequested, this, &EditorView::findNextRequested); 0107 connect(m_targetTextEdit, &TranslationUnitTextEdit::findNextRequested, this, &EditorView::findNextRequested); 0108 connect(m_sourceTextEdit, &TranslationUnitTextEdit::replaceRequested, this, &EditorView::replaceRequested); 0109 connect(m_targetTextEdit, &TranslationUnitTextEdit::replaceRequested, this, &EditorView::replaceRequested); 0110 connect(m_sourceTextEdit, &TranslationUnitTextEdit::zoomRequested, m_targetTextEdit, &TranslationUnitTextEdit::zoomRequestedSlot); 0111 connect(m_targetTextEdit, &TranslationUnitTextEdit::zoomRequested, m_sourceTextEdit, &TranslationUnitTextEdit::zoomRequestedSlot); 0112 0113 connect(this, &EditorView::doExplicitCompletion, m_targetTextEdit, &TranslationUnitTextEdit::doExplicitCompletion); 0114 0115 addWidget(m_pluralTabBar); 0116 addWidget(m_sourceTextEdit); 0117 addWidget(m_targetTextEdit); 0118 0119 QWidget::setTabOrder(m_targetTextEdit, m_sourceTextEdit); 0120 QWidget::setTabOrder(m_sourceTextEdit, m_targetTextEdit); 0121 setFocusProxy(m_targetTextEdit); 0122 // QTimer::singleShot(3000,this,SLOT(setupWhatsThis())); 0123 settingsChanged(); 0124 } 0125 0126 EditorView::~EditorView() 0127 { 0128 } 0129 0130 0131 void EditorView::resetFindForCurrent(const DocPosition& pos) 0132 { 0133 m_modifiedAfterFind = true; 0134 Q_EMIT signalChanged(pos.entry); 0135 } 0136 0137 0138 void EditorView::settingsChanged() 0139 { 0140 //Settings::self()->config()->setGroup("Editor"); 0141 m_sourceTextEdit->document()->setDefaultFont(Settings::msgFont()); 0142 m_targetTextEdit->document()->setDefaultFont(Settings::msgFont()); 0143 m_sourceTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); 0144 m_targetTextEdit->setVisualizeSeparators(Settings::self()->visualizeSeparators()); 0145 if (m_leds) m_leds->setVisible(Settings::leds()); 0146 else if (Settings::leds()) { 0147 m_leds = new LedsWidget(this); 0148 insertWidget(2, m_leds); 0149 connect(m_targetTextEdit, &TranslationUnitTextEdit::cursorPositionChanged, m_leds, &LedsWidget::cursorPositionChanged); 0150 connect(m_targetTextEdit, &TranslationUnitTextEdit::nonApprovedEntryDisplayed, m_leds->ledFuzzy, &KLed::on); 0151 connect(m_targetTextEdit, &TranslationUnitTextEdit::approvedEntryDisplayed, m_leds->ledFuzzy, &KLed::off); 0152 connect(m_targetTextEdit, &TranslationUnitTextEdit::untranslatedEntryDisplayed, m_leds->ledUntr, &KLed::on); 0153 connect(m_targetTextEdit, &TranslationUnitTextEdit::translatedEntryDisplayed, m_leds->ledUntr, &KLed::off); 0154 m_targetTextEdit->showPos(m_targetTextEdit->currentPos()); 0155 } 0156 } 0157 0158 0159 0160 void EditorView::gotoEntry() 0161 { 0162 return gotoEntry(DocPosition(), 0); 0163 } 0164 //main function in this file :) 0165 void EditorView::gotoEntry(DocPosition pos, int selection) 0166 { 0167 setUpdatesEnabled(false); 0168 0169 bool refresh = (pos.entry == -1); 0170 if (refresh) pos = m_targetTextEdit->currentPos(); 0171 //qCWarning(LOKALIZE_LOG)<<"refresh"<<refresh; 0172 //qCWarning(LOKALIZE_LOG)<<"offset"<<pos.offset; 0173 //TODO trigger refresh directly via Catalog signal 0174 0175 if (Q_UNLIKELY(m_catalog->isPlural(pos.entry))) { 0176 if (Q_UNLIKELY(m_catalog->numberOfPluralForms() != m_pluralTabBar->count())) { 0177 int i = m_pluralTabBar->count(); 0178 if (m_catalog->numberOfPluralForms() > m_pluralTabBar->count()) 0179 while (i < m_catalog->numberOfPluralForms()) 0180 m_pluralTabBar->addTab(i18nc("@title:tab", "Plural Form %1", ++i)); 0181 else 0182 while (i > m_catalog->numberOfPluralForms()) 0183 m_pluralTabBar->removeTab(i--); 0184 } 0185 m_pluralTabBar->show(); 0186 m_pluralTabBar->blockSignals(true); 0187 m_pluralTabBar->setCurrentIndex(pos.form); 0188 m_pluralTabBar->blockSignals(false); 0189 } else 0190 m_pluralTabBar->hide(); 0191 0192 //bool keepCursor=DocPos(pos)==DocPos(_msgidEdit->currentPos()); 0193 bool keepCursor = false; 0194 CatalogString sourceWithTags = m_sourceTextEdit->showPos(pos, CatalogString(), keepCursor); 0195 0196 //qCWarning(LOKALIZE_LOG)<<"calling showPos"; 0197 QString targetString = m_targetTextEdit->showPos(pos, sourceWithTags, keepCursor).string; 0198 //qCWarning(LOKALIZE_LOG)<<"ss"<<_msgstrEdit->textCursor().anchor()<<_msgstrEdit->textCursor().position(); 0199 m_sourceTextEdit->cursorToStart(); 0200 m_targetTextEdit->cursorToStart(); 0201 0202 bool untrans = targetString.isEmpty(); 0203 //qCWarning(LOKALIZE_LOG)<<"ss1"<<_msgstrEdit->textCursor().anchor()<<_msgstrEdit->textCursor().position(); 0204 0205 if (pos.offset || selection) { 0206 TranslationUnitTextEdit* msgEdit = (pos.part == DocPosition::Source ? m_sourceTextEdit : m_targetTextEdit); 0207 QTextCursor t = msgEdit->textCursor(); 0208 t.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, pos.offset); 0209 //NOTE this was kinda bug due to on-the-fly msgid wordwrap 0210 if (selection) 0211 t.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, selection); 0212 msgEdit->setTextCursor(t); 0213 } else if (!untrans) { 0214 QTextCursor t = m_targetTextEdit->textCursor(); 0215 //what if msg starts with a tag? 0216 if (Q_UNLIKELY(targetString.startsWith('<'))) { 0217 int offset = targetString.indexOf(QRegExp(QStringLiteral(">[^<]"))); 0218 if (offset != -1) 0219 t.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, offset + 1); 0220 } else if (Q_UNLIKELY(targetString.startsWith(TAGRANGE_IMAGE_SYMBOL))) { 0221 int offset = targetString.indexOf(QRegExp(QStringLiteral("[^") + QChar(TAGRANGE_IMAGE_SYMBOL) + ']')); 0222 if (offset != -1) 0223 t.movePosition(QTextCursor::NextCharacter, QTextCursor::MoveAnchor, offset + 1); 0224 } 0225 m_targetTextEdit->setTextCursor(t); 0226 } 0227 //qCWarning(LOKALIZE_LOG)<<"set-->"<<_msgstrEdit->textCursor().anchor()<<_msgstrEdit->textCursor().position(); 0228 //qCWarning(LOKALIZE_LOG)<<"anchor"<<t.anchor()<<"pos"<<t.position(); 0229 m_targetTextEdit->setFocus(); 0230 setUpdatesEnabled(true); 0231 } 0232 0233 0234 //BEGIN edit actions that are easier to do in this class 0235 void EditorView::unwrap() 0236 { 0237 unwrap(nullptr); 0238 } 0239 void EditorView::unwrap(TranslationUnitTextEdit* editor) 0240 { 0241 if (!editor) 0242 editor = m_targetTextEdit; 0243 0244 QTextCursor t = editor->document()->find(QRegExp("[^(\\\\n)]$")); 0245 if (t.isNull()) 0246 return; 0247 0248 if (editor == m_targetTextEdit) 0249 m_catalog->beginMacro(i18nc("@item Undo action item", "Unwrap")); 0250 t.movePosition(QTextCursor::EndOfLine); 0251 if (!t.atEnd()) 0252 t.deleteChar(); 0253 0254 QRegExp rx("[^(\\\\n)>]$"); 0255 //remove '\n's skipping "\\\\n" 0256 while (!(t = editor->document()->find(rx, t)).isNull()) { 0257 t.movePosition(QTextCursor::EndOfLine); 0258 if (!t.atEnd()) 0259 t.deleteChar(); 0260 } 0261 if (editor == m_targetTextEdit) 0262 m_catalog->endMacro(); 0263 } 0264 0265 void EditorView::insertTerm(const QString& term) 0266 { 0267 m_targetTextEdit->insertPlainTextWithCursorCheck(term); 0268 m_targetTextEdit->setFocus(); 0269 } 0270 0271 0272 QString EditorView::selectionInTarget() const 0273 { 0274 //TODO remove IMAGES 0275 return m_targetTextEdit->textCursor().selectedText(); 0276 } 0277 0278 QString EditorView::selectionInSource() const 0279 { 0280 //TODO remove IMAGES 0281 return m_sourceTextEdit->textCursor().selectedText(); 0282 } 0283 0284 void EditorView::setProperFocus() 0285 { 0286 m_targetTextEdit->setFocus(); 0287 } 0288 0289 0290 //END edit actions that are easier to do in this class 0291 0292 0293 0294 QObject* EditorView::viewPort() 0295 { 0296 return m_targetTextEdit; 0297 } 0298 0299 void EditorView::toggleBookmark(bool checked) 0300 { 0301 if (Q_UNLIKELY(m_targetTextEdit->currentPos().entry == -1)) 0302 return; 0303 0304 m_catalog->setBookmark(m_targetTextEdit->currentPos().entry, checked); 0305 } 0306 0307 void EditorView::toggleApprovement() 0308 { 0309 //qCWarning(LOKALIZE_LOG)<<"called"; 0310 if (Q_UNLIKELY(m_targetTextEdit->currentPos().entry == -1)) 0311 return; 0312 0313 bool newState = !m_catalog->isApproved(m_targetTextEdit->currentPos().entry); 0314 SetStateCmd::push(m_catalog, m_targetTextEdit->currentPos(), newState); 0315 Q_EMIT signalApprovedEntryDisplayed(newState); 0316 } 0317 0318 void EditorView::setState(TargetState state) 0319 { 0320 if (Q_UNLIKELY(m_targetTextEdit->currentPos().entry == -1 0321 || m_catalog->state(m_targetTextEdit->currentPos()) == state)) 0322 return; 0323 0324 SetStateCmd::instantiateAndPush(m_catalog, m_targetTextEdit->currentPos(), state); 0325 Q_EMIT signalApprovedEntryDisplayed(m_catalog->isApproved(m_targetTextEdit->currentPos())); 0326 } 0327 0328 void EditorView::setEquivTrans(bool equivTrans) 0329 { 0330 m_catalog->push(new SetEquivTransCmd(m_catalog, m_targetTextEdit->currentPos(), equivTrans)); 0331 } 0332 0333