/*
* Quackle -- Crossword game artificial intelligence and analysis tool
* Copyright (C) 2005-2014 Jason Katz-Brown and John O'Laughlin.
*
* 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 3 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "newgame.h"
#include "customqsettings.h"
NewGameDialog::NewGameDialog(QWidget *parent)
: QDialog(parent)
{
m_tabs = new QTabWidget;
m_playerTab = new PlayerTab;
m_tabs->addTab(m_playerTab, tr("&Players"));
QPushButton *okButton = new QPushButton(tr("&OK"));
QPushButton *cancelButton = new QPushButton(tr("&Cancel"));
connect(okButton, SIGNAL(clicked()), this, SLOT(accept()));
connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject()));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addStretch(1);
buttonLayout->addWidget(okButton);
buttonLayout->addWidget(cancelButton);
QVBoxLayout *topLayout = new QVBoxLayout;
topLayout->addWidget(m_tabs);
topLayout->addLayout(buttonLayout);
setLayout(topLayout);
loadSettings();
setWindowTitle(tr("New Game - Quackle"));
okButton->setDefault(true);
}
Quackle::PlayerList NewGameDialog::players() const
{
return m_playerTab->players();
}
void NewGameDialog::accept()
{
saveSettings();
QDialog::accept();
}
void NewGameDialog::saveSettings()
{
m_playerTab->saveSettings();
}
void NewGameDialog::loadSettings()
{
}
/////////////
PlayerTab::PlayerTab(QWidget *parent)
: QWidget(parent), m_changingEditorManually(false)
{
m_addPlayerButton = new QPushButton(tr("&Add New Player"));
m_removePlayerButton = new QPushButton(tr("&Remove Player"));
connect(m_addPlayerButton, SIGNAL(clicked()), this, SLOT(addPlayer()));
connect(m_removePlayerButton, SIGNAL(clicked()), this, SLOT(removePlayer()));
QHBoxLayout *buttonLayout = new QHBoxLayout;
buttonLayout->addWidget(m_addPlayerButton);
buttonLayout->addWidget(m_removePlayerButton);
m_playersTreeWidget = new QTreeWidget;
// probably too confusing to be able to select multiple players at oncet?
// all functionality for it is implemented wrt removing multiple players at oncet
//m_playersTreeWidget->setSelectionMode(QTreeWidget::ExtendedSelection);
connect(m_playersTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
QStringList headers;
headers << tr("Name") << tr("Controller");
m_playersTreeWidget->setHeaderLabels(headers);
m_editGroup = new QGroupBox(tr("Player &Information"));
QHBoxLayout *editLayout = new QHBoxLayout(m_editGroup);
m_nameEdit = new QLineEdit;
connect(m_nameEdit, SIGNAL(textEdited(const QString &)), this, SLOT(playerEdited()));
editLayout->addWidget(m_nameEdit);
m_playerType = new QComboBox;
QStringList playerTypes(tr("Human"));
playerTypes.push_back(tr("Human With Unknown Racks"));
for (Quackle::PlayerList::const_reverse_iterator it = QUACKLE_COMPUTER_PLAYERS.rbegin(); it != QUACKLE_COMPUTER_PLAYERS.rend(); ++it)
{
if ((*it).computerPlayer()->isUserVisible())
playerTypes.push_back(QuackleIO::Util::uvStringToQString((*it).name()));
}
m_playerType->addItems(playerTypes);
connect(m_playerType, SIGNAL(activated(const QString &)), this, SLOT(playerEdited()));
editLayout->addWidget(m_playerType);
QVBoxLayout *topLayout = new QVBoxLayout;
topLayout->addWidget(m_playersTreeWidget);
topLayout->addWidget(m_editGroup);
topLayout->addStretch();
topLayout->addLayout(buttonLayout);
setLayout(topLayout);
QTimer::singleShot(0, this, SLOT(populatePlayers()));
}
void PlayerTab::saveSettings()
{
CustomQSettings settings;
QList playerIds;
QList playerList(m_playerMap.keys());
for (QList::iterator it = playerList.begin(); it != playerList.end(); ++it)
{
playerIds.push_back((*it).id());
settings.setValue(QString("quackle/newgame/players/%1").arg((*it).id()), QuackleIO::Util::uvStringToQString((*it).storeInformationToString()));
}
settings.setValue("quackle/newgame/playerIds", playerIds);
// this is a workaround for one item lists getting saved oddly
if (playerIds.size() == 1)
settings.setValue("quackle/newgame/playerId", playerIds.front().toInt());
else
settings.setValue("quackle/newgame/playerId", -1);
}
void PlayerTab::populatePlayers()
{
CustomQSettings settings;
// this is a workaround for one item lists getting saved oddly
int playerId = settings.value("quackle/newgame/playerId", -1).toInt();
QList playerIds;
if (playerId >= 0)
playerIds.push_back(QVariant(playerId));
else
playerIds = settings.value("quackle/newgame/playerIds", QList()).toList();
for (QList::iterator it = playerIds.begin(); it != playerIds.end(); ++it)
{
int id = (*it).toInt();
QString infoString = settings.value(QString("quackle/newgame/players/%1").arg(id)).toString();
if (infoString.isNull())
continue;
Quackle::Player player(Quackle::Player::makePlayerFromString(QuackleIO::Util::qstringToString(infoString)));
if (!player.computerPlayer())
{
// this is required if the computer id in the settings is no longer
// offered by Quackle
player.setComputerPlayer(defaultComputerPlayer());
}
addPlayer(player);
}
if (m_playerMap.empty())
{
// one computer
Quackle::Player newPlayer(QuackleIO::Util::qstringToString(tr("Quackle")), Quackle::Player::ComputerPlayerType, 0);
newPlayer.setComputerPlayer(defaultComputerPlayer());
addPlayer(newPlayer);
// and a human
addPlayer();
}
selectionChanged();
}
Quackle::PlayerList PlayerTab::players() const
{
// this is all silly to do but oh well
QList playerList(m_playerMap.keys());
Quackle::PlayerList ret;
for (QList::const_iterator it = playerList.begin(); it != playerList.end(); ++it)
{
ret.push_back(*it);
if (ret.back().name().empty())
ret.back().setName(QuackleIO::Util::qstringToString(tr("No Name")));
QStringList splitName = QuackleIO::Util::uvStringToQString(ret.back().name()).split(QRegExp("\\s+"));
ret.back().setAbbreviatedName(QuackleIO::Util::qstringToString(splitName.join("_")));
}
return ret;
}
void PlayerTab::addPlayer(const Quackle::Player &player)
{
QTreeWidgetItem *item = new QTreeWidgetItem(m_playersTreeWidget);
m_playerMap.insert(player, item);
setItem(item, player);
m_playersTreeWidget->clearSelection();
m_playersTreeWidget->setItemSelected(item, true);
}
Quackle::ComputerPlayer *PlayerTab::defaultComputerPlayer() const
{
for (Quackle::PlayerList::const_reverse_iterator it = QUACKLE_COMPUTER_PLAYERS.rbegin(); it != QUACKLE_COMPUTER_PLAYERS.rend(); ++it)
if ((*it).computerPlayer()->isUserVisible() && !(*it).computerPlayer()->isSlow())
return (*it).computerPlayer();
return QUACKLE_COMPUTER_PLAYERS.back().computerPlayer();
}
void PlayerTab::setItem(QTreeWidgetItem *item, const Quackle::Player &player)
{
item->setText(PlayerName, QuackleIO::Util::uvStringToQString(player.name()));
item->setText(PlayerType, stringForPlayer(player));
}
void PlayerTab::addPlayer()
{
QString name(tr("New Player %1"));
QString unusedName;
int unusedId;
for (int i = 1; ; ++i)
{
unusedName = name.arg(i);
UVString nameString = QuackleIO::Util::qstringToString(unusedName);
bool found = false;
for (QMap::iterator it = m_playerMap.begin(); it != m_playerMap.end(); ++it)
{
if (it.key().name() == nameString)
{
found = true;
break;
}
}
if (!found)
break;
}
for (unusedId = 0; ; ++unusedId)
{
bool found = false;
for (QMap::iterator it = m_playerMap.begin(); it != m_playerMap.end(); ++it)
{
if (it.key().id() == unusedId)
{
found = true;
break;
}
}
if (!found)
break;
}
Quackle::Player player(QuackleIO::Util::qstringToString(unusedName), Quackle::Player::HumanPlayerType, unusedId);
addPlayer(player);
}
void PlayerTab::removePlayer()
{
QList items = m_playersTreeWidget->selectedItems();
for (QList::iterator it = items.begin(); it != items.end(); ++it)
{
delete *it;
QList correspondingPlayers(m_playerMap.keys(*it));
if (correspondingPlayers.size() > 0)
m_playerMap.remove(correspondingPlayers.front());
}
selectionChanged();
}
void PlayerTab::playerEdited()
{
if (m_changingEditorManually || !hasSelection())
return;
Quackle::Player lastPlayer(getLastPlayer());
if (lastPlayer.id() < 0)
return;
lastPlayer.setName(QuackleIO::Util::qstringToString(m_nameEdit->text()));
updatePlayerFromString(m_playerType->currentText(), lastPlayer);
// please excuse the HORRIBLE use of QMap here
QTreeWidgetItem *item = m_playerMap.value(lastPlayer);
m_playerMap.remove(lastPlayer);
m_playerMap.insert(lastPlayer, item);
setItem(item, lastPlayer);
}
void PlayerTab::selectionChanged()
{
bool hasSel = hasSelection();
m_removePlayerButton->setEnabled(hasSel);
m_editGroup->setEnabled(hasSel);
if (!hasSel)
return;
Quackle::Player lastPlayer(getLastPlayer());
if (lastPlayer.id() < 0)
{
UVcout << "last player id < 0" << endl;
return;
}
m_changingEditorManually = true;
m_nameEdit->setText(QuackleIO::Util::uvStringToQString(lastPlayer.name()));
m_playerType->setCurrentIndex(m_playerType->findText(stringForPlayer(lastPlayer)));
m_changingEditorManually = false;
}
bool PlayerTab::hasSelection()
{
return !m_playersTreeWidget->selectedItems().empty();
}
Quackle::Player PlayerTab::getLastPlayer()
{
QTreeWidgetItem *lastItem = m_playersTreeWidget->selectedItems().back();
Quackle::Player lastPlayer;
for (QMap::iterator it = m_playerMap.begin(); it != m_playerMap.end(); ++it)
if (it.value() == lastItem)
return it.key();
// urp!
return Quackle::Player();
}
QString PlayerTab::stringForPlayer(const Quackle::Player &player)
{
switch (player.type())
{
case Quackle::Player::HumanPlayerType:
{
if (player.racksAreKnown())
return tr("Human");
else
return tr("Human With Unknown Racks");
}
case Quackle::Player::ComputerPlayerType:
if (player.computerPlayer())
return QuackleIO::Util::uvStringToQString(player.computerPlayer()->name());
default:
return tr("Unknown Player");
}
}
void PlayerTab::updatePlayerFromString(const QString &typeString, Quackle::Player &player)
{
if (typeString == tr("Human"))
{
player.setType(Quackle::Player::HumanPlayerType);
player.setRacksAreKnown(true);
player.setComputerPlayer(0);
return;
}
if (typeString == tr("Human With Unknown Racks"))
{
player.setType(Quackle::Player::HumanPlayerType);
player.setRacksAreKnown(false);
player.setComputerPlayer(0);
return;
}
player.setType(Quackle::Player::ComputerPlayerType);
bool found = false;
const Quackle::Player &modelPlayer = QUACKLE_COMPUTER_PLAYERS.playerForName(QuackleIO::Util::qstringToString(typeString), found);
if (found)
player.setComputerPlayer(modelPlayer.computerPlayer());
else
player.setComputerPlayer(0);
}