diff --git a/game/arbitration.cpp b/game/arbitration.cpp index 7effa41..0bb9df6 100644 --- a/game/arbitration.cpp +++ b/game/arbitration.cpp @@ -64,7 +64,7 @@ void Arbitration::setRackManual(const wstring &iLetters) wstring upperLetters = iLetters; std::transform(upperLetters.begin(), upperLetters.end(), upperLetters.begin(), towupper); - const PlayedRack &newRack = helperSetRackManual(true, upperLetters); + const PlayedRack &newRack = helperSetRackManual(false, upperLetters); setGameAndPlayersRack(newRack); // Clear the results if everything went well diff --git a/qt/arbitration_widget.cpp b/qt/arbitration_widget.cpp index e46c906..9f0b582 100644 --- a/qt/arbitration_widget.cpp +++ b/qt/arbitration_widget.cpp @@ -68,6 +68,15 @@ ArbitrationWidget::ArbitrationWidget(QWidget *parent, splitter->setStretchFactor(1, 2); // FIXME arbitration end + blackPalette = lineEditRack->palette(); + redPalette = lineEditRack->palette(); + redPalette.setColor(QPalette::Text, Qt::red); + + // Define validators + QValidator * val = + ValidatorFactory::newRackValidator(this, m_game->getBag(), + true, &m_game->getHistory()); + lineEditRack->setValidator(val); lineEditCoords->setValidator(ValidatorFactory::newCoordsValidator(this)); // Associate a model to the players view. @@ -117,6 +126,9 @@ ArbitrationWidget::ArbitrationWidget(QWidget *parent, treeViewResults->setColumnWidth(1, 40); treeViewResults->setColumnWidth(2, 70); + // Validate manual rack changes + QObject::connect(lineEditRack, SIGNAL(textEdited(const QString&)), + this, SLOT(rackEdited(const QString&))); // Propagate the information on rack change QObject::connect(lineEditRack, SIGNAL(textChanged(const QString&)), this, SIGNAL(rackUpdated(const QString&))); @@ -390,7 +402,8 @@ int ArbitrationWidget::addSingleMove(const Move &iMove, int moveType, void ArbitrationWidget::setRackRandom() { - ASSERT(m_game->isLastTurn(), "The Random button should have been disabled"); + ASSERT(m_game->isLastTurn(), + "The Random button should only be active in the last turn"); // Warn if some players have already played bool someoneHasPlayed = false; @@ -421,6 +434,57 @@ void ArbitrationWidget::setRackRandom() } +void ArbitrationWidget::rackEdited(const QString &iText) +{ + ASSERT(m_game->isLastTurn(), + "Rack edition button should only be active in the last turn"); + + // Warn if some players have already played + bool someoneHasPlayed = false; + for (unsigned int i = 0; i < m_game->getNbPlayers(); ++i) + { + if (m_game->hasPlayed(i)) + someoneHasPlayed = true; + } + if (someoneHasPlayed) + { + QString msg = _q("Some player(s) already have an assigned move. " + "These moves will be lost if you change the rack."); + QString question = _q("Do you really want to change the rack?"); + if (!QtCommon::requestConfirmation(msg, question)) + { + // Restore the rack (visually) + const PlayedRack &pldRack = m_game->getHistory().getCurrentRack(); + QString qrack = qfw(pldRack.toString(PlayedRack::RACK_SIMPLE)); + lineEditRack->setText(qrack); + + return; + } + } + + m_game->removeTestRound(); + if (!lineEditRack->hasAcceptableInput()) + { + lineEditRack->setPalette(redPalette); + return; + } + try + { + lineEditRack->setPalette(blackPalette); + const wstring &input = m_game->getDic().convertFromInput(wfq(iText)); + m_game->arbitrationSetRackManual(input); + buttonSearch->setEnabled(m_resultsModel->rowCount() == 0 && + lineEditRack->text() != ""); + emit gameUpdated(); + } + catch (std::exception &e) + { + lineEditRack->setPalette(redPalette); + emit notifyProblem(_q("Warning: Cannot set the rack to '%1':\n%2").arg(iText).arg(e.what())); + } +} + + void ArbitrationWidget::resultsFilterChanged(const QString &iFilter) { treeViewResults->clearSelection(); diff --git a/qt/arbitration_widget.h b/qt/arbitration_widget.h index 9dcb8e3..c93070c 100644 --- a/qt/arbitration_widget.h +++ b/qt/arbitration_widget.h @@ -58,6 +58,7 @@ public slots: private slots: void setRackRandom(); + void rackEdited(const QString &); void on_buttonSearch_clicked(); void on_checkBoxHideAssigned_toggled(bool); void resultsFilterChanged(const QString &); @@ -100,6 +101,12 @@ private: /// Container for the moves manually entered in the interface QVector m_addedMoves; + /// Palette to write text in black + QPalette blackPalette; + + /// Palette to write text in red + QPalette redPalette; + /// Force synchronizing the model with the search results void updateResultsModel(); /// Force synchronizing the model with the players diff --git a/qt/training_widget.cpp b/qt/training_widget.cpp index 5e15d97..349e683 100644 --- a/qt/training_widget.cpp +++ b/qt/training_widget.cpp @@ -49,10 +49,9 @@ TrainingWidget::TrainingWidget(QWidget *parent, CoordModel &iCoordModel, PublicG setupUi(this); treeViewResults->setAlternatingRowColors(true); + blackPalette = lineEditRack->palette(); redPalette = lineEditRack->palette(); redPalette.setColor(QPalette::Text, Qt::red); - blackPalette = lineEditRack->palette(); - blackPalette.setColor(QPalette::Text, Qt::black); // Use the mediator m_mediator = new PlayWordMediator(this, *lineEditPlay, *lineEditCoords, @@ -109,7 +108,7 @@ TrainingWidget::TrainingWidget(QWidget *parent, CoordModel &iCoordModel, PublicG if (m_game) { - QValidator * val = ValidatorFactory::newRackValidator(this, &m_game->getBag()); + QValidator * val = ValidatorFactory::newRackValidator(this, m_game->getBag()); lineEditRack->setValidator(val); } @@ -273,7 +272,6 @@ void TrainingWidget::lockSizesChanged(bool checked) void TrainingWidget::on_lineEditRack_textEdited(const QString &iText) { - // FIXME: first parameter is hardcoded m_game->removeTestRound(); if (!lineEditRack->hasAcceptableInput()) { @@ -292,7 +290,7 @@ void TrainingWidget::on_lineEditRack_textEdited(const QString &iText) catch (std::exception &e) { lineEditRack->setPalette(redPalette); - emit notifyProblem(_q("Warning: Cannot set the rack to '%1'").arg(iText)); + emit notifyProblem(_q("Warning: Cannot set the rack to '%1'\n%2").arg(iText).arg(e.what())); } } diff --git a/qt/training_widget.h b/qt/training_widget.h index 6de16b2..62aa0b9 100644 --- a/qt/training_widget.h +++ b/qt/training_widget.h @@ -84,12 +84,12 @@ private: /// Mediator for the "play word" controls PlayWordMediator *m_mediator; - /// Palette to write text in red - QPalette redPalette; - /// Palette to write text in black QPalette blackPalette; + /// Palette to write text in red + QPalette redPalette; + /// Popup menu for words definition CustomPopup *m_customPopup; diff --git a/qt/ui/arbitration_widget.ui b/qt/ui/arbitration_widget.ui index 9de2a6b..dbb2515 100644 --- a/qt/ui/arbitration_widget.ui +++ b/qt/ui/arbitration_widget.ui @@ -16,7 +16,7 @@ Qt::Horizontal - + @@ -39,9 +39,6 @@ 0 - - true - diff --git a/qt/validator_factory.cpp b/qt/validator_factory.cpp index 1d1e728..4e19a6b 100644 --- a/qt/validator_factory.cpp +++ b/qt/validator_factory.cpp @@ -27,6 +27,8 @@ #include "dic.h" #include "bag.h" #include "coord.h" +#include "history.h" +#include "pldrack.h" // TODO: There is probably a good potential for code factorization in this file @@ -103,30 +105,33 @@ QValidator *ValidatorFactory::newChangeValidator(QObject *parent, class RackValidator: public QValidator { public: - explicit RackValidator(QObject *parent, const Bag *iBag); + RackValidator(QObject *parent, const Bag &iBag, + const History *iHistory, bool checkDuplicate); virtual State validate(QString &input, int &pos) const; private: - const Bag *m_bag; + const Bag &m_bag; + const History *m_history; + bool m_checkDuplicate; }; -RackValidator::RackValidator(QObject *parent, const Bag *iBag) - : QValidator(parent), m_bag(iBag) +RackValidator::RackValidator(QObject *parent, const Bag &iBag, + const History *iHistory, bool checkDuplicate) + : QValidator(parent), m_bag(iBag), + m_history(iHistory), m_checkDuplicate(checkDuplicate) { } QValidator::State RackValidator::validate(QString &input, int &) const { - // This should never happen, since the control should be disabled in - // such a case, but checking doesn't hurt... - if (m_bag == NULL) - return Invalid; + if (input == "") + return Intermediate; input = input.toUpper(); - const Dictionary &dic = m_bag->getDic(); + const Dictionary &dic = m_bag.getDic(); // The string is invalid if it contains invalid input characters const wistring &winput = wfq(input); @@ -145,19 +150,38 @@ QValidator::State RackValidator::validate(QString &input, int &) const for (int i = 0; i < qinput.size(); ++i) { if ((unsigned int)qinput.count(qinput[i], Qt::CaseInsensitive) > - m_bag->in(intInput[i])) + m_bag.in(intInput[i])) { return Invalid; } } + + // Check that the rack has 2 consonants and 2 vocals + if (m_checkDuplicate) + { + PlayedRack pld; + pld.setManual(intInput); + + int min; + if (m_bag.getNbVowels() > 1 && m_bag.getNbConsonants() > 1 + && m_history->getSize() < 15) + min = 2; + else + min = 1; + if (!pld.checkRack(min, min)) + return Intermediate; + } + return Acceptable; } QValidator *ValidatorFactory::newRackValidator(QObject *parent, - const Bag *iBag) + const Bag &iBag, + bool checkDuplicate, + const History *iHistory) { - return new RackValidator(parent, iBag); + return new RackValidator(parent, iBag, iHistory, checkDuplicate); } // }}} diff --git a/qt/validator_factory.h b/qt/validator_factory.h index 8d7ce19..2343be2 100644 --- a/qt/validator_factory.h +++ b/qt/validator_factory.h @@ -28,6 +28,7 @@ class QValidator; class QLineEdit; class Dictionary; class Bag; +class History; class ValidatorFactory: public QObject @@ -48,7 +49,9 @@ public: * Create a validator suitable for setting rack letters. */ static QValidator *newRackValidator(QObject *parent, - const Bag *iBag); + const Bag &iBag, + bool checkDuplicate = false, + const History *iHistory = 0); /** * Create a validator suitable for setting rack letters