Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
phraseview.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "globals.h"
5#include "mainwindow.h"
6#include "messagemodel.h"
7#include "phrase.h"
8#include "phraseview.h"
9#include "phrasemodel.h"
10#include "simtexth.h"
11
12#include <QHeaderView>
13#include <QKeyEvent>
14#include <QSettings>
15#include <QShortcut>
16#include <QTreeView>
17#include <QWidget>
18#include <QDebug>
19
20
22
23using namespace Qt::Literals::StringLiterals;
24
26{
27 return settingPath("PhraseViewHeader");
28}
29
30PhraseView::PhraseView(MultiDataModel *model, QList<QHash<QString, QList<Phrase *> > > *phraseDict, QWidget *parent)
31 : QTreeView(parent),
32 m_dataModel(model),
33 m_phraseDict(phraseDict),
34 m_modelIndex(-1),
35 m_doGuesses(true)
36{
37 setObjectName("phrase list view");
38
39 m_phraseModel = new PhraseModel(this);
40
41 setModel(m_phraseModel);
42 setAlternatingRowColors(true);
43 setSelectionBehavior(QAbstractItemView::SelectRows);
44 setSelectionMode(QAbstractItemView::SingleSelection);
45 setRootIsDecorated(false);
46 setItemsExpandable(false);
47
48 for (int i = 0; i < 9; ++i) {
49 const auto key = static_cast<Qt::Key>(int(Qt::Key_1) + i);
50 auto shortCut = new QShortcut(Qt::CTRL | key, this);
51 connect(shortCut, &QShortcut::activated, this,
52 [i, this]() { this->guessShortcut(i); });
53 }
54
55 header()->setSectionResizeMode(QHeaderView::Interactive);
56 header()->setSectionsClickable(true);
57 header()->restoreState(QSettings().value(phraseViewHeaderKey()).toByteArray());
58
59 connect(this, &QAbstractItemView::activated,
60 this, &PhraseView::selectPhrase);
61}
62
64{
65 QSettings().setValue(phraseViewHeaderKey(), header()->saveState());
66 deleteGuesses();
67}
68
69void PhraseView::toggleGuessing()
70{
71 m_doGuesses = !m_doGuesses;
73}
74
76{
77 setSourceText(m_modelIndex, m_sourceText);
78}
79
80
81void PhraseView::contextMenuEvent(QContextMenuEvent *event)
82{
83 QModelIndex index = indexAt(event->pos());
84 if (!index.isValid())
85 return;
86
87 QMenu *contextMenu = new QMenu(this);
88
89 QAction *insertAction = new QAction(tr("Insert"), contextMenu);
90 connect(insertAction, &QAction::triggered,
91 this, &PhraseView::selectCurrentPhrase);
92
93 QAction *editAction = new QAction(tr("Edit"), contextMenu);
94 connect(editAction, &QAction::triggered,
95 this, &PhraseView::editPhrase);
96 Qt::ItemFlags isFromPhraseBook = model()->flags(index) & Qt::ItemIsEditable;
97 editAction->setEnabled(isFromPhraseBook);
98
99 QAction *gotoAction = new QAction(tr("Go to"), contextMenu);
100 connect(gotoAction, &QAction::triggered,
101 this, &PhraseView::gotoMessageFromGuess);
102 gotoAction->setEnabled(!isFromPhraseBook);
103
104 contextMenu->addAction(insertAction);
105 contextMenu->addAction(editAction);
106 contextMenu->addAction(gotoAction);
107
108 contextMenu->exec(event->globalPos());
109 event->accept();
110}
111
112void PhraseView::mouseDoubleClickEvent(QMouseEvent *event)
113{
114 QModelIndex index = indexAt(event->pos());
115 if (!index.isValid())
116 return;
117
118 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
119 event->accept();
120}
121
122void PhraseView::guessShortcut(int key)
123{
124 const auto phrases = m_phraseModel->phraseList();
125 for (const Phrase *phrase : phrases)
126 if (phrase->shortcut() == key) {
127 emit phraseSelected(m_modelIndex, phrase->target());
128 return;
129 }
130}
131
132void PhraseView::selectPhrase(const QModelIndex &index)
133{
134 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
135}
136
137void PhraseView::selectCurrentPhrase()
138{
139 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(currentIndex())->target());
140}
141
142void PhraseView::editPhrase()
143{
144 edit(currentIndex());
145}
146
147void PhraseView::gotoMessageFromGuess()
148{
149 emit setCurrentMessageFromGuess(m_modelIndex,
150 m_phraseModel->phrase(currentIndex())->candidate());
151}
152
153void PhraseView::setMaxCandidates(const int max)
154{
155 m_maxCandidates = max;
156 emit showFewerGuessesAvailable(m_maxCandidates > DefaultMaxCandidates);
157}
158
160{
162 setSourceText(m_modelIndex, m_sourceText);
163}
164
166{
168 setSourceText(m_modelIndex, m_sourceText);
169}
170
172{
174 setSourceText(m_modelIndex, m_sourceText);
175}
176
178 const char *text, int maxCandidates)
179{
180 QList<int> scores;
181 CandidateList candidates;
182
183 StringSimilarityMatcher stringmatcher(QString::fromLatin1(text));
184
185 auto findCandidates = [&candidates, maxCandidates, &scores, &stringmatcher](auto it) {
186 for (; it.isValid(); ++it) {
187 MessageItem *m = it.current();
188 if (!m)
189 continue;
190
192 if (mtm.type() == TranslatorMessage::Unfinished || mtm.translation().isEmpty())
193 continue;
194
195 QString s = m->text();
196
197 int score = stringmatcher.getSimilarityScore(s);
198
199 if (candidates.size() == maxCandidates && score > scores[maxCandidates - 1])
200 candidates.removeLast();
201 if (candidates.size() < maxCandidates && score >= textSimilarityThreshold) {
202 Candidate cand(mtm.context(), s, mtm.comment(), mtm.translation(), mtm.id(),
203 m->label());
204
205 int i;
206 for (i = 0; i < candidates.size(); ++i) {
207 if (score >= scores.at(i)) {
208 if (score == scores.at(i)) {
209 if (candidates.at(i) == cand)
210 goto continue_outer_loop;
211 } else {
212 break;
213 }
214 }
215 }
216 scores.insert(i, score);
217 candidates.insert(i, cand);
218 }
219 continue_outer_loop:;
220 }
221 };
222
223 findCandidates(MultiDataModelIterator(TEXTBASED, model, mi));
224 findCandidates(MultiDataModelIterator(IDBASED, model, mi));
225
226 return candidates;
227}
228
229
230void PhraseView::setSourceText(int model, const QString &sourceText)
231{
232 m_modelIndex = model;
233 m_sourceText = sourceText;
234 m_phraseModel->removePhrases();
235 deleteGuesses();
236
237 if (model < 0)
238 return;
239
240 const auto phrases = getPhrases(model, sourceText);
241 for (Phrase *p : phrases)
242 m_phraseModel->addPhrase(p);
243
244 if (!sourceText.isEmpty() && m_doGuesses) {
245 const CandidateList cl = similarTextHeuristicCandidates(m_dataModel, model,
246 sourceText.toLatin1(), m_maxCandidates);
247 int n = 0;
248 for (const Candidate &candidate : cl) {
249 QString def;
250 QString group = candidate.context.isEmpty() ? candidate.label : candidate.context;
251 if (n < 9)
252 def = tr("Guess from '%1' (%2)")
253 .arg(group,
254 QKeySequence(Qt::CTRL | (Qt::Key_0 + (n + 1)))
255 .toString(QKeySequence::NativeText));
256 else
257 def = tr("Guess from '%1'").arg(group);
258 Phrase *guess = new Phrase(candidate.source, candidate.translation, def, candidate, n);
259 m_guesses.append(guess);
260 m_phraseModel->addPhrase(guess);
261 ++n;
262 }
263 }
264}
265
266QList<Phrase *> PhraseView::getPhrases(int model, const QString &source)
267{
268 QList<Phrase *> phrases;
269 const QString f = friendlyString(source);
270 const QStringList lookupWords = f.split(u' ');
271
272 for (const QString &s : lookupWords) {
273 if (m_phraseDict->at(model).contains(s)) {
274 const auto phraseList = m_phraseDict->at(model).value(s);
275 for (Phrase *p : phraseList) {
276 if (f.contains(friendlyString(p->source())))
277 phrases.append(p);
278 }
279 }
280 }
281 return phrases;
282}
283
284void PhraseView::deleteGuesses()
285{
286 qDeleteAll(m_guesses);
287 m_guesses.clear();
288}
289
290QT_END_NAMESPACE
const TranslatorMessage & message() const
MultiDataModelIterator(TranslationType type, MultiDataModel *model=0, int modelNo=-1, int groupNo=0, int messageNo=0)
void resetNumGuesses()
void setMaxCandidates(const int max)
void mouseDoubleClickEvent(QMouseEvent *event) override
void update()
void moreGuesses()
void setSourceText(int model, const QString &sourceText)
void fewerGuesses()
void contextMenuEvent(QContextMenuEvent *event) override
@ IDBASED
@ TEXTBASED
static QString phraseViewHeaderKey()
static CandidateList similarTextHeuristicCandidates(MultiDataModel *model, int mi, const char *text, int maxCandidates)
static QT_BEGIN_NAMESPACE const int DefaultMaxCandidates
Definition phraseview.h:13
QList< Candidate > CandidateList
Definition simtexth.h:40