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
24{
25 return settingPath("PhraseViewHeader");
26}
27
28PhraseView::PhraseView(MultiDataModel *model, QList<QHash<QString, QList<Phrase *> > > *phraseDict, QWidget *parent)
29 : QTreeView(parent),
30 m_dataModel(model),
31 m_phraseDict(phraseDict),
32 m_modelIndex(-1),
33 m_doGuesses(true)
34{
35 setObjectName(QLatin1String("phrase list view"));
36
37 m_phraseModel = new PhraseModel(this);
38
39 setModel(m_phraseModel);
40 setAlternatingRowColors(true);
41 setSelectionBehavior(QAbstractItemView::SelectRows);
42 setSelectionMode(QAbstractItemView::SingleSelection);
43 setRootIsDecorated(false);
44 setItemsExpandable(false);
45
46 for (int i = 0; i < 9; ++i) {
47 const auto key = static_cast<Qt::Key>(int(Qt::Key_1) + i);
48 auto shortCut = new QShortcut(Qt::CTRL | key, this);
49 connect(shortCut, &QShortcut::activated, this,
50 [i, this]() { this->guessShortcut(i); });
51 }
52
53 header()->setSectionResizeMode(QHeaderView::Interactive);
54 header()->setSectionsClickable(true);
55 header()->restoreState(QSettings().value(phraseViewHeaderKey()).toByteArray());
56
57 connect(this, &QAbstractItemView::activated,
58 this, &PhraseView::selectPhrase);
59}
60
62{
63 QSettings().setValue(phraseViewHeaderKey(), header()->saveState());
64 deleteGuesses();
65}
66
67void PhraseView::toggleGuessing()
68{
69 m_doGuesses = !m_doGuesses;
71}
72
74{
75 setSourceText(m_modelIndex, m_sourceText);
76}
77
78
79void PhraseView::contextMenuEvent(QContextMenuEvent *event)
80{
81 QModelIndex index = indexAt(event->pos());
82 if (!index.isValid())
83 return;
84
85 QMenu *contextMenu = new QMenu(this);
86
87 QAction *insertAction = new QAction(tr("Insert"), contextMenu);
88 connect(insertAction, &QAction::triggered,
89 this, &PhraseView::selectCurrentPhrase);
90
91 QAction *editAction = new QAction(tr("Edit"), contextMenu);
92 connect(editAction, &QAction::triggered,
93 this, &PhraseView::editPhrase);
94 Qt::ItemFlags isFromPhraseBook = model()->flags(index) & Qt::ItemIsEditable;
95 editAction->setEnabled(isFromPhraseBook);
96
97 QAction *gotoAction = new QAction(tr("Go to"), contextMenu);
98 connect(gotoAction, &QAction::triggered,
99 this, &PhraseView::gotoMessageFromGuess);
100 gotoAction->setEnabled(!isFromPhraseBook);
101
102 contextMenu->addAction(insertAction);
103 contextMenu->addAction(editAction);
104 contextMenu->addAction(gotoAction);
105
106 contextMenu->exec(event->globalPos());
107 event->accept();
108}
109
110void PhraseView::mouseDoubleClickEvent(QMouseEvent *event)
111{
112 QModelIndex index = indexAt(event->pos());
113 if (!index.isValid())
114 return;
115
116 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
117 event->accept();
118}
119
120void PhraseView::guessShortcut(int key)
121{
122 const auto phrases = m_phraseModel->phraseList();
123 for (const Phrase *phrase : phrases)
124 if (phrase->shortcut() == key) {
125 emit phraseSelected(m_modelIndex, phrase->target());
126 return;
127 }
128}
129
130void PhraseView::selectPhrase(const QModelIndex &index)
131{
132 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
133}
134
135void PhraseView::selectCurrentPhrase()
136{
137 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(currentIndex())->target());
138}
139
140void PhraseView::editPhrase()
141{
142 edit(currentIndex());
143}
144
145void PhraseView::gotoMessageFromGuess()
146{
147 emit setCurrentMessageFromGuess(m_modelIndex,
148 m_phraseModel->phrase(currentIndex())->candidate());
149}
150
151void PhraseView::setMaxCandidates(const int max)
152{
153 m_maxCandidates = max;
154 emit showFewerGuessesAvailable(m_maxCandidates > DefaultMaxCandidates);
155}
156
158{
160 setSourceText(m_modelIndex, m_sourceText);
161}
162
164{
166 setSourceText(m_modelIndex, m_sourceText);
167}
168
170{
172 setSourceText(m_modelIndex, m_sourceText);
173}
174
176 const char *text, int maxCandidates)
177{
178 QList<int> scores;
179 CandidateList candidates;
180
181 StringSimilarityMatcher stringmatcher(QString::fromLatin1(text));
182
183 for (MultiDataModelIterator it(model, mi); it.isValid(); ++it) {
184 MessageItem *m = it.current();
185 if (!m)
186 continue;
187
190 || mtm.translation().isEmpty())
191 continue;
192
193 QString s = m->text();
194
195 int score = stringmatcher.getSimilarityScore(s);
196
197 if (candidates.size() == maxCandidates && score > scores[maxCandidates - 1])
198 candidates.removeLast();
199 if (candidates.size() < maxCandidates && score >= textSimilarityThreshold ) {
200 Candidate cand(mtm.context(), s, mtm.comment(), mtm.translation());
201
202 int i;
203 for (i = 0; i < candidates.size(); ++i) {
204 if (score >= scores.at(i)) {
205 if (score == scores.at(i)) {
206 if (candidates.at(i) == cand)
207 goto continue_outer_loop;
208 } else {
209 break;
210 }
211 }
212 }
213 scores.insert(i, score);
214 candidates.insert(i, cand);
215 }
216 continue_outer_loop:
217 ;
218 }
219 return candidates;
220}
221
222
223void PhraseView::setSourceText(int model, const QString &sourceText)
224{
225 m_modelIndex = model;
226 m_sourceText = sourceText;
227 m_phraseModel->removePhrases();
228 deleteGuesses();
229
230 if (model < 0)
231 return;
232
233 const auto phrases = getPhrases(model, sourceText);
234 for (Phrase *p : phrases)
235 m_phraseModel->addPhrase(p);
236
237 if (!sourceText.isEmpty() && m_doGuesses) {
238 const CandidateList cl = similarTextHeuristicCandidates(m_dataModel, model,
239 sourceText.toLatin1(), m_maxCandidates);
240 int n = 0;
241 for (const Candidate &candidate : cl) {
242 QString def;
243 if (n < 9)
244 def = tr("Guess from '%1' (%2)")
245 .arg(candidate.context, QKeySequence(Qt::CTRL | (Qt::Key_0 + (n + 1)))
246 .toString(QKeySequence::NativeText));
247 else
248 def = tr("Guess from '%1'").arg(candidate.context);
249 Phrase *guess = new Phrase(candidate.source, candidate.translation, def, candidate, n);
250 m_guesses.append(guess);
251 m_phraseModel->addPhrase(guess);
252 ++n;
253 }
254 }
255}
256
257QList<Phrase *> PhraseView::getPhrases(int model, const QString &source)
258{
259 QList<Phrase *> phrases;
260 const QString f = MainWindow::friendlyString(source);
261 const QStringList lookupWords = f.split(QLatin1Char(' '));
262
263 for (const QString &s : lookupWords) {
264 if (m_phraseDict->at(model).contains(s)) {
265 const auto phraseList = m_phraseDict->at(model).value(s);
266 for (Phrase *p : phraseList) {
267 if (f.contains(MainWindow::friendlyString(p->source())))
268 phrases.append(p);
269 }
270 }
271 }
272 return phrases;
273}
274
275void PhraseView::deleteGuesses()
276{
277 qDeleteAll(m_guesses);
278 m_guesses.clear();
279}
280
281QT_END_NAMESPACE
const TranslatorMessage & message() const
MultiDataModelIterator(MultiDataModel *model, int modelNo, int contextNo=0, int messageNo=0)
MessageItem * current() const
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
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE 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:37
const int textSimilarityThreshold
Definition simtexth.h:7