23using namespace Qt::Literals::StringLiterals;
27 return settingPath(
"PhraseViewHeader");
33 m_phraseDict(phraseDict),
37 setObjectName(
"phrase list view");
39 m_phraseModel =
new PhraseModel(
this);
41 setModel(m_phraseModel);
42 setAlternatingRowColors(
true);
43 setSelectionBehavior(QAbstractItemView::SelectRows);
44 setSelectionMode(QAbstractItemView::SingleSelection);
45 setRootIsDecorated(
false);
46 setItemsExpandable(
false);
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); });
55 header()->setSectionResizeMode(QHeaderView::Interactive);
56 header()->setSectionsClickable(
true);
57 header()->restoreState(QSettings().value(phraseViewHeaderKey()).toByteArray());
59 connect(
this, &QAbstractItemView::activated,
60 this, &PhraseView::selectPhrase);
65 QSettings().setValue(phraseViewHeaderKey(), header()->saveState());
71 m_doGuesses = !m_doGuesses;
77 setSourceText(m_modelIndex, m_sourceText);
83 QModelIndex index = indexAt(event->pos());
87 QMenu *contextMenu =
new QMenu(
this);
89 QAction *insertAction =
new QAction(tr(
"Insert"), contextMenu);
90 connect(insertAction, &QAction::triggered,
91 this, &PhraseView::selectCurrentPhrase);
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);
99 QAction *gotoAction =
new QAction(tr(
"Go to"), contextMenu);
100 connect(gotoAction, &QAction::triggered,
101 this, &PhraseView::gotoMessageFromGuess);
102 gotoAction->setEnabled(!isFromPhraseBook);
104 contextMenu->addAction(insertAction);
105 contextMenu->addAction(editAction);
106 contextMenu->addAction(gotoAction);
108 contextMenu->exec(event->globalPos());
114 QModelIndex index = indexAt(event->pos());
115 if (!index.isValid())
118 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
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());
132void PhraseView::selectPhrase(
const QModelIndex &index)
134 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
139 emit phraseSelected(m_modelIndex, m_phraseModel->phrase(currentIndex())->target());
144 edit(currentIndex());
149 emit setCurrentMessageFromGuess(m_modelIndex,
150 m_phraseModel->phrase(currentIndex())->candidate());
155 m_maxCandidates = max;
162 setSourceText(m_modelIndex, m_sourceText);
168 setSourceText(m_modelIndex, m_sourceText);
174 setSourceText(m_modelIndex, m_sourceText);
178 const char *text,
int maxCandidates)
185 auto findCandidates = [&candidates, maxCandidates, &scores, &stringmatcher](
auto it) {
186 for (; it.isValid(); ++it) {
195 QString s = m->text();
197 int score = stringmatcher.getSimilarityScore(s);
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(),
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;
216 scores.insert(i, score);
217 candidates.insert(i, cand);
219 continue_outer_loop:;
232 m_modelIndex = model;
233 m_sourceText = sourceText;
234 m_phraseModel->removePhrases();
240 const auto phrases = getPhrases(model, sourceText);
241 for (Phrase *p : phrases)
242 m_phraseModel->addPhrase(p);
244 if (!sourceText.isEmpty() && m_doGuesses) {
245 const CandidateList cl = similarTextHeuristicCandidates(m_dataModel, model,
246 sourceText.toLatin1(), m_maxCandidates);
248 for (
const Candidate &candidate : cl) {
250 QString group = candidate.context.isEmpty() ? candidate.label : candidate.context;
252 def = tr(
"Guess from '%1' (%2)")
254 QKeySequence(Qt::CTRL | (Qt::Key_0 + (n + 1)))
255 .toString(QKeySequence::NativeText));
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);
266QList<Phrase *>
PhraseView::getPhrases(
int model,
const QString &source)
268 QList<Phrase *> phrases;
269 const QString f = friendlyString(source);
270 const QStringList lookupWords = f.split(u' ');
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())))
286 qDeleteAll(m_guesses);
const TranslatorMessage & message() const
MultiDataModelIterator(TranslationType type, MultiDataModel *model=0, int modelNo=-1, int groupNo=0, int messageNo=0)
void setMaxCandidates(const int max)
void mouseDoubleClickEvent(QMouseEvent *event) override
void setSourceText(int model, const QString &sourceText)
void contextMenuEvent(QContextMenuEvent *event) override
static QString phraseViewHeaderKey()
static CandidateList similarTextHeuristicCandidates(MultiDataModel *model, int mi, const char *text, int maxCandidates)
static QT_BEGIN_NAMESPACE const int DefaultMaxCandidates
QList< Candidate > CandidateList