eliot/qt/dic_tools_widget.cpp

413 lines
13 KiB
C++

/*****************************************************************************
* Eliot
* Copyright (C) 2008-2009 Olivier Teulière
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include "config.h"
#include <map>
#include <vector>
#include <algorithm>
#include <QtGui/QTreeView>
#include <QtGui/QStandardItemModel>
#include <QtGui/QVBoxLayout>
#include <QtGui/QLineEdit>
#include <QtGui/QToolTip>
#include <QtCore/QString>
#include "dic_tools_widget.h"
#include "qtcommon.h"
#include "dic.h"
#include "header.h"
#include "dic_exception.h"
using namespace std;
/// Validator used for the line edits accepting only dictionary characters
class DicRackValidator: public QValidator
{
public:
explicit DicRackValidator(QObject *parent,
const Dictionary *iDic,
bool acceptJoker = false);
virtual State validate(QString &input, int &pos) const;
private:
const Dictionary *m_dic;
const bool m_acceptJoker;
};
/// Validator used for the regexp line edit
class RegexpValidator: public QValidator
{
public:
explicit RegexpValidator(QObject *parent,
const Dictionary *iDic);
virtual State validate(QString &input, int &pos) const;
private:
const Dictionary *m_dic;
};
DicToolsWidget::DicToolsWidget(QWidget *parent)
: QWidget(parent), m_dic(NULL)
{
setupUi(this);
redPalette = labelCheck->palette();
redPalette.setColor(QPalette::Foreground, Qt::red);
darkYellowPalette = labelCheck->palette();
darkYellowPalette.setColor(QPalette::Foreground, Qt::darkYellow);
greenPalette = labelCheck->palette();
greenPalette.setColor(QPalette::Foreground, Qt::darkGreen);
labelLimitReached->hide();
// Create connections
QObject::connect(lineEditCheck, SIGNAL(textChanged(const QString&)), this, SLOT(refreshCheck()));
QObject::connect(lineEditPlus1, SIGNAL(returnPressed()), this, SLOT(refreshPlus1()));
QObject::connect(lineEditRegexp, SIGNAL(returnPressed()), this, SLOT(refreshRegexp()));
// Create models
m_plus1Model = new QStandardItemModel(this);
treeViewPlus1->setModel(m_plus1Model);
m_plus1Model->setColumnCount(1);
m_plus1Model->setHeaderData(0, Qt::Horizontal, _q("Rack:"), Qt::DisplayRole);
m_regexpModel = new QStandardItemModel(this);
treeViewRegexp->setModel(m_regexpModel);
m_regexpModel->setColumnCount(1);
m_regexpModel->setHeaderData(0, Qt::Horizontal, _q("Rack:"), Qt::DisplayRole);
m_dicInfoModel = new QStandardItemModel(this);
treeViewDicLetters->setModel(m_dicInfoModel);
m_dicInfoModel->setColumnCount(6);
m_dicInfoModel->setHeaderData(0, Qt::Horizontal, _q("Letter"), Qt::DisplayRole);
m_dicInfoModel->setHeaderData(1, Qt::Horizontal, _q("Points"), Qt::DisplayRole);
m_dicInfoModel->setHeaderData(2, Qt::Horizontal, _q("Frequency"), Qt::DisplayRole);
m_dicInfoModel->setHeaderData(3, Qt::Horizontal, _q("Vowel?"), Qt::DisplayRole);
m_dicInfoModel->setHeaderData(4, Qt::Horizontal, _q("Consonant?"), Qt::DisplayRole);
m_dicInfoModel->setHeaderData(5, Qt::Horizontal, _q("Alternative inputs"), Qt::DisplayRole);
}
void DicToolsWidget::setDic(const Dictionary *iDic)
{
if (m_dic != iDic)
{
m_dic = iDic;
// Reset the letters
lineEditCheck->clear();
lineEditPlus1->clear();
lineEditRegexp->clear();
// Create new validators
lineEditCheck->setValidator(new DicRackValidator(this, m_dic));
lineEditPlus1->setValidator(new DicRackValidator(this, m_dic, true));
lineEditRegexp->setValidator(new RegexpValidator(this, m_dic));
// Refresh
refreshCheck();
refreshPlus1();
refreshRegexp();
refreshDicInfo();
}
}
void DicToolsWidget::setPlus1Rack(const QString &iRack)
{
lineEditPlus1->setText(iRack);
refreshPlus1();
}
void DicToolsWidget::refreshCheck()
{
QLineEdit *rack = lineEditCheck;
if (m_dic == NULL)
{
labelCheck->setText(_q("Please select a dictionary"));
return;
}
if (rack->text() == "")
labelCheck->setText("");
else
{
if (!rack->hasAcceptableInput())
{
labelCheck->setText(_q("Invalid or incomplete letters"));
labelCheck->setPalette(darkYellowPalette);
return;
}
wstring input = m_dic->convertFromInput(qtw(rack->text()));
bool res = m_dic->searchWord(input);
// Convert the input to uppercase
std::transform(input.begin(), input.end(), input.begin(), towupper);
const wdstring &dispStr = m_dic->convertToDisplay(input);
if (res)
{
labelCheck->setText(_q("The word '%1' exists").arg(qfw(dispStr)));
labelCheck->setPalette(greenPalette);
}
else
{
labelCheck->setText(_q("The word '%1' does not exist").arg(qfw(dispStr)));
labelCheck->setPalette(redPalette);
}
}
}
void DicToolsWidget::refreshPlus1()
{
QStandardItemModel *model = m_plus1Model;
QTreeView *treeView = treeViewPlus1;
QLineEdit *rack = lineEditPlus1;
model->removeRows(0, model->rowCount());
if (m_dic == NULL)
{
model->setHeaderData(0, Qt::Horizontal,
_q("Please select a dictionary"),
Qt::DisplayRole);
return;
}
const wstring &input = m_dic->convertFromInput(qtw(rack->text().toUpper()));
const wdstring &disp = m_dic->convertToDisplay(input);
model->setHeaderData(0, Qt::Horizontal,
_q("Rack: %1").arg(qfw(disp)),
Qt::DisplayRole);
if (input != L"")
{
map<unsigned int, vector<wstring> > wordList;
m_dic->search7pl1(input, wordList, true);
int rowNum = 0;
map<unsigned int, vector<wstring> >::const_iterator it;
for (it = wordList.begin(); it != wordList.end(); it++)
{
// Create the header line
model->insertRow(rowNum);
const QModelIndex &index = model->index(rowNum, 0);
if (it->first != 0)
model->setData(index, qfw(m_dic->getHeader().getDisplayStr(it->first)));
else
model->setData(index, _q("Anagrams"));
treeView->setExpanded(index, true);
++rowNum;
// Create the result lines
model->insertColumn(0, index);
model->insertRows(0, it->second.size(), index);
const vector<wstring> &results = it->second;
for (unsigned i = 0; i < results.size(); ++i)
{
model->setData(model->index(i, 0, index),
qfw(results[i]));
}
}
}
}
void DicToolsWidget::refreshRegexp()
{
QStandardItemModel *model = m_regexpModel;
QLineEdit *rack = lineEditRegexp;
model->removeRows(0, model->rowCount());
if (m_dic == NULL)
{
model->setHeaderData(0, Qt::Horizontal,
_q("Please select a dictionary"),
Qt::DisplayRole);
return;
}
const wstring &input = m_dic->convertFromInput(qtw(rack->text().toUpper()));
const wdstring &disp = m_dic->convertToDisplay(input);
model->setHeaderData(0, Qt::Horizontal,
_q("Regular expression: %1").arg(qfw(disp)),
Qt::DisplayRole);
if (input != L"")
{
unsigned lmin = spinBoxMinLength->value();
unsigned lmax = spinBoxMaxLength->value();
// FIXME: this value should not be hardcoded,
// or a warning should appear when it is reached
unsigned limit = 1000;
vector<wstring> wordList;
bool res = true;
int rowNum = 0;
try
{
res = m_dic->searchRegExp(input, wordList, lmin, lmax, limit);
}
catch (InvalidRegexpException &e)
{
model->insertRow(rowNum);
model->setData(model->index(rowNum, 0),
_q("Invalid regular expression: %1").arg(qfl(e.what())));
model->setData(model->index(rowNum, 0),
QBrush(Qt::red), Qt::ForegroundRole);
}
vector<wstring>::const_iterator it;
for (it = wordList.begin(); it != wordList.end(); it++)
{
model->insertRow(rowNum);
model->setData(model->index(rowNum, 0), qfw(*it));
++rowNum;
}
if (res)
labelLimitReached->hide();
else
labelLimitReached->show();
}
}
void DicToolsWidget::refreshDicInfo()
{
if (m_dic == NULL)
{
lineEditName->setText("");
lineEditLetters->setText("");
spinBoxWords->setValue(0);
m_dicInfoModel->clear();
}
else
{
const Header &header = m_dic->getHeader();
lineEditName->setText(qfw(header.getName()));
lineEditLetters->setText(qfw(m_dic->convertToDisplay(header.getLetters())));
spinBoxWords->setValue(header.getNbWords());
QStandardItemModel *model = m_dicInfoModel;
model->removeRows(0, model->rowCount());
const vector<Tile> &allTiles = m_dic->getAllTiles();
vector<Tile>::const_iterator it;
int rowNum = 0;
for (it = allTiles.begin(); it != allTiles.end(); ++it)
{
model->insertRow(rowNum);
model->setData(model->index(rowNum, 0),
qfw(it->getDisplayStr()));
model->setData(model->index(rowNum, 1), it->getPoints());
model->setData(model->index(rowNum, 2), it->maxNumber());
model->setData(model->index(rowNum, 3),
it->isVowel() ? _q("Yes") : _q("No"));
model->setData(model->index(rowNum, 4),
it->isConsonant() ? _q("Yes") : _q("No"));
const vector<wistring> &inputVect = it->getInputStr();
wstring tmp;
for (unsigned int i = 1; i < inputVect.size(); ++i)
{
tmp += inputVect[i] + L" ";
}
model->setData(model->index(rowNum, 5), qfw(tmp));
++rowNum;
}
treeViewDicLetters->resizeColumnToContents(0);
treeViewDicLetters->resizeColumnToContents(1);
treeViewDicLetters->resizeColumnToContents(2);
treeViewDicLetters->resizeColumnToContents(3);
treeViewDicLetters->resizeColumnToContents(4);
}
}
DicRackValidator::DicRackValidator(QObject *parent,
const Dictionary *iDic,
bool acceptJoker)
: QValidator(parent), m_dic(iDic), m_acceptJoker(acceptJoker)
{
}
QValidator::State DicRackValidator::validate(QString &input, int &) const
{
if (m_dic == NULL)
return Invalid;
if (input == "")
return Intermediate;
// The string is invalid if it contains invalid input characters
const wistring &winput = qtw(input);
if (!m_dic->validateInputChars(winput))
return Invalid;
// Convert the string to internal letters
const wstring &intInput = m_dic->convertFromInput(winput);
// The string is invalid if it contains characters not present
// in the dictionary
if (!m_dic->validateLetters(intInput))
return Intermediate;
// A '?' may not be acceptable
if (!m_acceptJoker && input.contains('?'))
return Invalid;
// Do not accept more than 2 jokers
if (input.count('?') > 2)
return Invalid;
return Acceptable;
}
RegexpValidator::RegexpValidator(QObject *parent,
const Dictionary *iDic)
: QValidator(parent), m_dic(iDic)
{
}
QValidator::State RegexpValidator::validate(QString &input, int &) const
{
if (m_dic == NULL)
return Invalid;
if (input == "")
return Intermediate;
wstring authorizedChars = L".[]()*+?:^";
// The string is invalid if it contains invalid input characters
const wistring &winput = qtw(input);
if (!m_dic->validateInputChars(winput, authorizedChars))
return Invalid;
// Convert the string to internal letters
const wstring &intInput = m_dic->convertFromInput(winput);
// The string is invalid if it contains characters not present
// in the dictionary
if (!m_dic->validateLetters(intInput, authorizedChars))
return Intermediate;
return Acceptable;
}