blob: 3ffab4bdff0a7e9a77e695a54de3954af450ecd9 [file] [log] [blame]
/****************************************************************************
**
** 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$
** GNU Lesser General Public License Usage
** 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.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "globals.h"
#include "mainwindow.h"
#include "messagemodel.h"
#include "phrase.h"
#include "phraseview.h"
#include "phrasemodel.h"
#include "simtexth.h"
#include <QHeaderView>
#include <QKeyEvent>
#include <QSettings>
#include <QTreeView>
#include <QWidget>
#include <QDebug>
QT_BEGIN_NAMESPACE
// Maximum number of guesses to display
static const int MaxCandidates = 5;
static QString phraseViewHeaderKey()
{
return settingPath("PhraseViewHeader");
}
PhraseView::PhraseView(MultiDataModel *model, QList<QHash<QString, QList<Phrase *> > > *phraseDict, QWidget *parent)
: QTreeView(parent),
m_dataModel(model),
m_phraseDict(phraseDict),
m_modelIndex(-1),
m_doGuesses(true)
{
setObjectName(QLatin1String("phrase list view"));
m_phraseModel = new PhraseModel(this);
setModel(m_phraseModel);
setAlternatingRowColors(true);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSelectionMode(QAbstractItemView::SingleSelection);
setRootIsDecorated(false);
setItemsExpandable(false);
for (int i = 0; i < 10; i++)
(void) new GuessShortcut(i, this, SLOT(guessShortcut(int)));
header()->setResizeMode(QHeaderView::Interactive);
header()->setClickable(true);
header()->restoreState(QSettings().value(phraseViewHeaderKey()).toByteArray());
connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(selectPhrase(QModelIndex)));
}
PhraseView::~PhraseView()
{
QSettings().setValue(phraseViewHeaderKey(), header()->saveState());
deleteGuesses();
}
void PhraseView::toggleGuessing()
{
m_doGuesses = !m_doGuesses;
update();
}
void PhraseView::update()
{
setSourceText(m_modelIndex, m_sourceText);
}
void PhraseView::contextMenuEvent(QContextMenuEvent *event)
{
QModelIndex index = indexAt(event->pos());
if (!index.isValid())
return;
QMenu *contextMenu = new QMenu(this);
QAction *insertAction = new QAction(tr("Insert"), contextMenu);
connect(insertAction, SIGNAL(triggered()), this, SLOT(selectPhrase()));
QAction *editAction = new QAction(tr("Edit"), contextMenu);
connect(editAction, SIGNAL(triggered()), this, SLOT(editPhrase()));
editAction->setEnabled(model()->flags(index) & Qt::ItemIsEditable);
contextMenu->addAction(insertAction);
contextMenu->addAction(editAction);
contextMenu->exec(event->globalPos());
event->accept();
}
void PhraseView::mouseDoubleClickEvent(QMouseEvent *event)
{
QModelIndex index = indexAt(event->pos());
if (!index.isValid())
return;
emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
event->accept();
}
void PhraseView::guessShortcut(int key)
{
foreach (const Phrase *phrase, m_phraseModel->phraseList())
if (phrase->shortcut() == key) {
emit phraseSelected(m_modelIndex, phrase->target());
return;
}
}
void PhraseView::selectPhrase(const QModelIndex &index)
{
emit phraseSelected(m_modelIndex, m_phraseModel->phrase(index)->target());
}
void PhraseView::selectPhrase()
{
emit phraseSelected(m_modelIndex, m_phraseModel->phrase(currentIndex())->target());
}
void PhraseView::editPhrase()
{
edit(currentIndex());
}
static CandidateList similarTextHeuristicCandidates(MultiDataModel *model, int mi,
const char *text, int maxCandidates)
{
QList<int> scores;
CandidateList candidates;
StringSimilarityMatcher stringmatcher(QString::fromLatin1(text));
for (MultiDataModelIterator it(model, mi); it.isValid(); ++it) {
MessageItem *m = it.current();
if (!m)
continue;
TranslatorMessage mtm = m->message();
if (mtm.type() == TranslatorMessage::Unfinished
|| mtm.translation().isEmpty())
continue;
QString s = m->text();
int score = stringmatcher.getSimilarityScore(s);
if (candidates.count() == maxCandidates && score > scores[maxCandidates - 1])
candidates.removeLast();
if (candidates.count() < maxCandidates && score >= textSimilarityThreshold ) {
Candidate cand(s, mtm.translation());
int i;
for (i = 0; i < candidates.size(); ++i) {
if (score >= scores.at(i)) {
if (score == scores.at(i)) {
if (candidates.at(i) == cand)
goto continue_outer_loop;
} else {
break;
}
}
}
scores.insert(i, score);
candidates.insert(i, cand);
}
continue_outer_loop:
;
}
return candidates;
}
void PhraseView::setSourceText(int model, const QString &sourceText)
{
m_modelIndex = model;
m_sourceText = sourceText;
m_phraseModel->removePhrases();
deleteGuesses();
if (model < 0)
return;
foreach (Phrase *p, getPhrases(model, sourceText))
m_phraseModel->addPhrase(p);
if (!sourceText.isEmpty() && m_doGuesses) {
CandidateList cl = similarTextHeuristicCandidates(m_dataModel, model,
sourceText.toLatin1(), MaxCandidates);
int n = 0;
foreach (const Candidate &candidate, cl) {
QString def;
if (n < 9)
def = tr("Guess (%1)").arg(QString(QKeySequence(Qt::CTRL | (Qt::Key_0 + (n + 1)))));
else
def = tr("Guess");
Phrase *guess = new Phrase(candidate.source, candidate.target, def, n);
m_guesses.append(guess);
m_phraseModel->addPhrase(guess);
++n;
}
}
}
QList<Phrase *> PhraseView::getPhrases(int model, const QString &source)
{
QList<Phrase *> phrases;
QString f = MainWindow::friendlyString(source);
QStringList lookupWords = f.split(QLatin1Char(' '));
foreach (const QString &s, lookupWords) {
if (m_phraseDict->at(model).contains(s)) {
foreach (Phrase *p, m_phraseDict->at(model).value(s)) {
if (f.contains(MainWindow::friendlyString(p->source())))
phrases.append(p);
}
}
}
return phrases;
}
void PhraseView::deleteGuesses()
{
qDeleteAll(m_guesses);
m_guesses.clear();
}
QT_END_NAMESPACE