2009-02-19 19:25:17 +01:00
|
|
|
/*****************************************************************************
|
|
|
|
* Eliot
|
|
|
|
* Copyright (C) 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 <QtGui/QLineEdit>
|
|
|
|
#include <QtGui/QPushButton>
|
|
|
|
|
|
|
|
#include "play_word_mediator.h"
|
|
|
|
#include "coord_model.h"
|
|
|
|
#include "qtcommon.h"
|
|
|
|
|
|
|
|
#include "public_game.h"
|
|
|
|
#include "coord.h"
|
|
|
|
#include "dic.h"
|
2009-06-27 20:09:44 +02:00
|
|
|
#include "header.h"
|
2009-02-19 19:25:17 +01:00
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
|
|
|
|
/// Validator used for the "play word" line edit
|
|
|
|
class PlayWordValidator: public QValidator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit PlayWordValidator(QObject *parent,
|
|
|
|
const Dictionary &iDic);
|
|
|
|
virtual State validate(QString &input, int &pos) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
const Dictionary &m_dic;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/// Validator used for the "coords" line edit
|
|
|
|
class CoordsValidator: public QValidator
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit CoordsValidator(QObject *parent);
|
|
|
|
virtual State validate(QString &input, int &pos) const;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PlayWordMediator::PlayWordMediator(QObject *parent, QLineEdit &iEditPlay,
|
|
|
|
QLineEdit &iEditCoord, QPushButton &iButtonPlay,
|
|
|
|
CoordModel &iCoordModel, PublicGame *iGame)
|
|
|
|
: QObject(parent), m_game(iGame), m_lineEditPlay(iEditPlay),
|
|
|
|
m_lineEditCoord(iEditCoord), m_pushButtonPlay(iButtonPlay),
|
|
|
|
m_coordModel(iCoordModel)
|
|
|
|
{
|
|
|
|
m_lineEditPlay.setFocus();
|
|
|
|
// These strings cannot be in the .ui file, because of the newlines
|
|
|
|
m_lineEditPlay.setToolTip(_q("Enter the word to play (case-insensitive).\n"
|
|
|
|
"A joker from the rack must be written in parentheses.\n"
|
|
|
|
"E.g.: w(o)rd or W(O)RD"));
|
|
|
|
m_lineEditCoord.setToolTip(_q("Enter the coordinates of the word.\n"
|
|
|
|
"Specify the row before the column for horizontal words,\n"
|
|
|
|
"and the column before the row for vertical words.\n"
|
|
|
|
"E.g.: H4 or 4H"));
|
|
|
|
|
|
|
|
/// Set validators;
|
|
|
|
if (m_game)
|
|
|
|
{
|
|
|
|
m_lineEditPlay.setValidator(new PlayWordValidator(this, m_game->getDic()));
|
|
|
|
m_lineEditCoord.setValidator(new CoordsValidator(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set all the connections
|
|
|
|
QObject::connect(&m_lineEditPlay, SIGNAL(textChanged(const QString&)),
|
|
|
|
this, SLOT(lineEditPlay_textChanged()));
|
|
|
|
QObject::connect(&m_lineEditPlay, SIGNAL(returnPressed()),
|
|
|
|
this, SLOT(lineEditPlay_returnPressed()));
|
|
|
|
QObject::connect(&m_lineEditCoord, SIGNAL(textChanged(const QString&)),
|
|
|
|
this, SLOT(lineEditCoord_textChanged(const QString&)));
|
|
|
|
QObject::connect(&m_lineEditCoord, SIGNAL(returnPressed()),
|
|
|
|
this, SLOT(lineEditCoord_returnPressed()));
|
|
|
|
QObject::connect(&m_pushButtonPlay, SIGNAL(clicked()),
|
|
|
|
this, SLOT(pushButtonPlay_clicked()));
|
|
|
|
QObject::connect(&m_coordModel, SIGNAL(coordChanged(const Coord&)),
|
|
|
|
this, SLOT(updateCoord(const Coord&)));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PlayWordMediator::lineEditPlay_textChanged()
|
|
|
|
{
|
|
|
|
m_pushButtonPlay.setEnabled(m_lineEditPlay.hasAcceptableInput() &&
|
|
|
|
m_lineEditCoord.hasAcceptableInput());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PlayWordMediator::lineEditPlay_returnPressed()
|
|
|
|
{
|
|
|
|
if (!m_lineEditPlay.hasAcceptableInput() ||
|
|
|
|
!m_lineEditCoord.hasAcceptableInput())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Convert the jokers to lowercase
|
2009-06-27 20:09:44 +02:00
|
|
|
const wistring &inputWord = qtw(m_lineEditPlay.text().toUpper());
|
|
|
|
// Convert to internal representation, then back to QString
|
|
|
|
QString word = qfw(m_game->getDic().getHeader().convertFromInput(inputWord));
|
|
|
|
|
2009-02-19 19:25:17 +01:00
|
|
|
int pos;
|
|
|
|
while ((pos = word.indexOf('(')) != -1)
|
|
|
|
{
|
|
|
|
if (word.size() < pos + 3 || word[pos + 2] != ')' ||
|
|
|
|
!m_game->getDic().validateLetters(qtw(QString(word[pos + 1]))))
|
|
|
|
{
|
|
|
|
// Bug in validate()!
|
|
|
|
// This should never happen
|
|
|
|
QString msg = _q("Cannot play word: misplaced parentheses");
|
|
|
|
emit notifyProblem(msg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
QChar chr = word[pos + 1].toLower();
|
|
|
|
word.remove(pos, 3);
|
|
|
|
word.insert(pos, chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-27 20:09:44 +02:00
|
|
|
// Convert the input string into an internal one
|
|
|
|
const wstring intWord =
|
|
|
|
m_game->getDic().getHeader().convertFromInput(qtw(word));
|
|
|
|
|
2009-02-19 19:25:17 +01:00
|
|
|
QString coords = m_lineEditCoord.text();
|
2009-06-27 20:09:44 +02:00
|
|
|
int res = m_game->play(intWord, qtw(coords));
|
2009-02-19 19:25:17 +01:00
|
|
|
if (res == 0)
|
|
|
|
{
|
|
|
|
emit gameUpdated();
|
|
|
|
m_lineEditPlay.setFocus();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Try to be as explicit as possible concerning the error
|
|
|
|
QString msg = _q("Cannot play '%1' at position '%2':\n")
|
|
|
|
.arg(m_lineEditPlay.text()).arg(coords);
|
|
|
|
switch (res)
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
msg += _q("Some letters are not valid for the current dictionary");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
msg += _q("Invalid coordinates");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
msg += _q("The word does not exist");
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
msg += _q("The rack doesn't contain the letters needed to play this word");
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
msg += _q("The word is part of a longer one");
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
msg += _q("The word tries to replace an existing letter");
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
msg += _q("An orthogonal word is not valid");
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
msg += _q("The word is already present on the board at these coordinates");
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
msg += _q("A word cannot be isolated (not connected to the placed words)");
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
msg += _q("The first word of the game must be horizontal");
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
msg += _q("The first word of the game must cover the H8 square");
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
msg += _q("The word is going out of the board");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
msg += _q("Incorrect or misplaced word (%1)").arg(1);
|
|
|
|
}
|
|
|
|
// FIXME: the error is too generic
|
|
|
|
emit notifyProblem(msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PlayWordMediator::lineEditCoord_textChanged(const QString &iText)
|
|
|
|
{
|
|
|
|
Coord c(qtw(iText));
|
|
|
|
if (!(m_coordModel.getCoord() == c))
|
|
|
|
m_coordModel.setCoord(Coord(qtw(iText)));
|
|
|
|
lineEditPlay_textChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PlayWordMediator::updateCoord(const Coord &iCoord)
|
|
|
|
{
|
|
|
|
if (iCoord.isValid() && m_lineEditCoord.text() != qfw(iCoord.toString()))
|
|
|
|
m_lineEditCoord.setText(qfw(iCoord.toString()));
|
|
|
|
else if (!iCoord.isValid() && m_lineEditCoord.hasAcceptableInput())
|
|
|
|
m_lineEditCoord.setText("");
|
|
|
|
lineEditPlay_textChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ------ Validators ------
|
|
|
|
|
|
|
|
PlayWordValidator::PlayWordValidator(QObject *parent,
|
|
|
|
const Dictionary &iDic)
|
|
|
|
: QValidator(parent), m_dic(iDic)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QValidator::State PlayWordValidator::validate(QString &input, int &) const
|
|
|
|
{
|
|
|
|
if (input == "")
|
|
|
|
return Intermediate;
|
|
|
|
|
2009-06-27 20:09:44 +02:00
|
|
|
const wistring &winput = qtw(input);
|
|
|
|
// The string is invalid if it contains invalid input characters
|
|
|
|
if (!m_dic.validateInputChars(winput, L"()") || input.contains('?'))
|
2009-02-19 19:25:17 +01:00
|
|
|
return Invalid;
|
|
|
|
|
2009-06-27 20:09:44 +02:00
|
|
|
// Convert the string to internal letters
|
|
|
|
const wstring &intInput = m_dic.getHeader().convertFromInput(winput);
|
|
|
|
// The string is invalid if it contains characters not present
|
|
|
|
// in the dictionary (ignoring parentheses)
|
|
|
|
if (!m_dic.validateLetters(intInput, L"()"))
|
|
|
|
return Intermediate;
|
|
|
|
|
2009-02-19 19:25:17 +01:00
|
|
|
// Check the parentheses pairs
|
2009-06-27 20:09:44 +02:00
|
|
|
QString qintInput = qfw(intInput);
|
2009-02-19 19:25:17 +01:00
|
|
|
int pos;
|
2009-06-27 20:09:44 +02:00
|
|
|
while ((pos = qintInput.indexOf('(')) != -1)
|
2009-02-19 19:25:17 +01:00
|
|
|
{
|
2009-06-27 20:09:44 +02:00
|
|
|
if (qintInput.size() < pos + 3 || qintInput[pos + 2] != ')' ||
|
|
|
|
!m_dic.validateLetters(qtw(QString(qintInput[pos + 1]))))
|
2009-02-19 19:25:17 +01:00
|
|
|
{
|
|
|
|
return Intermediate;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-27 20:09:44 +02:00
|
|
|
qintInput.remove(pos, 3);
|
2009-02-19 19:25:17 +01:00
|
|
|
}
|
|
|
|
}
|
2009-06-27 20:09:44 +02:00
|
|
|
if (qintInput.indexOf(')') != -1)
|
2009-02-19 19:25:17 +01:00
|
|
|
return Intermediate;
|
|
|
|
|
|
|
|
return Acceptable;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CoordsValidator::CoordsValidator(QObject *parent)
|
|
|
|
: QValidator(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QValidator::State CoordsValidator::validate(QString &input, int &) const
|
|
|
|
{
|
|
|
|
// Only authorize characters part of a valid coordinate
|
|
|
|
wstring copy = qtw(input.toUpper());
|
|
|
|
wstring authorized = L"ABCDEFGHIJKLMNO1234567890";
|
|
|
|
if (copy.find_first_not_of(authorized) != wstring::npos)
|
|
|
|
return Invalid;
|
|
|
|
|
|
|
|
// Check coordinates
|
|
|
|
Coord c(qtw(input));
|
|
|
|
if (!c.isValid())
|
|
|
|
return Intermediate;
|
|
|
|
|
|
|
|
return Acceptable;
|
|
|
|
}
|
|
|
|
|
|
|
|
|