::iterator it = reportAsActions.begin(); it != reportAsActions.end(); ++it)
reports->addAction(*it);
reports->addSeparator();
m_htmlReportAction = new QAction(tr("Quick full-game HTML report"), this);
m_htmlReportAction->setEnabled(false);
connect(m_htmlReportAction, SIGNAL(triggered()), this, SLOT(htmlReport()));
reports->addAction(m_htmlReportAction);
#ifdef ENABLE_GRAPHICAL_REPORT
m_graphicalReportAction = new QAction(tr("Slow full-game HTML report with images"), this);
m_graphicalReportAction->setEnabled(false);
connect(m_graphicalReportAction, SIGNAL(triggered()), this, SLOT(graphicalReport()));
reports->addAction(m_graphicalReportAction);
#endif
QMenu *simulation = menuBar()->addMenu(tr("Si&mulation"));
simulation->addAction(m_simulateAction);
simulation->addAction(m_simulateDetailsAction);
simulation->addAction(m_simulateClearAction);
if (enableLetterbox)
{
QMenu *study = menuBar()->addMenu(tr("Stud&y"));
study->addAction(m_generateAction);
study->addAction(letterboxAction);
}
QMenu *settings = menuBar()->addMenu(tr("&Settings"));
settings->addAction(m_preferencesAction);
menuBar()->addSeparator();
QMenu *help = menuBar()->addMenu(tr("&Help"));
help->addAction(hintsAction);
help->addSeparator();
help->addAction(aboutAction);
help->addAction(aboutQtAction);
// file toolbar
QToolBar *fileBar = addToolBar(tr("File"));
fileBar->setObjectName("file-toolbar");
fileBar->addAction(m_newAction);
fileBar->addAction(m_generateAction);
// move toolbar
QToolBar *moveBar = addToolBar(tr("Move"));
moveBar->setObjectName("move-toolbar");
if (enableCommitAction && putCommitActionOnToolbar)
{
moveBar->addAction(m_commitAction);
moveBar->addSeparator();
}
moveBar->addAction(m_kibitzAction);
moveBar->addAction(m_nextPositionAction);
moveBar->addAction(m_kibitzAsActions->actions().front());
moveBar->addAction(m_simulateAction);
// study toolbar
if (enableLetterbox)
{
QToolBar *studyBar = addToolBar(tr("Study"));
studyBar->setObjectName("study-toolbar");
studyBar->addAction(letterboxAction);
}
}
void TopLevel::createWidgets()
{
m_splitter = new QSplitter(Qt::Horizontal, this);
setCentralWidget(m_splitter);
QWidget *leftSide = new QWidget;
m_leftSideLayout = new QVBoxLayout(leftSide);
Geometry::setupFramedLayout(m_leftSideLayout);
m_dashboard = new Dashboard;
plugIntoHistoryMatrix(m_dashboard);
m_choicesWidget = new QWidget;
QVBoxLayout *choicesLayout = new QVBoxLayout(m_choicesWidget);
Geometry::setupFramedLayout(choicesLayout);
m_simulatorWidget = new QGroupBox(tr("Simulation"));
m_simulatorWidget->setFlat(true);
QVBoxLayout *simulatorLayout = new QVBoxLayout(m_simulatorWidget);
Geometry::setupInnerLayout(simulatorLayout);
QHBoxLayout *plyLayout = new QHBoxLayout;
Geometry::setupInnerLayout(plyLayout);
m_pliesCombo = new QComboBox;
QStringList plyOptions;
for (int i = 1; i <= m_pliesToOffer; ++i)
plyOptions.push_back(QString::number(i));
plyOptions.push_back(tr("Many"));
m_pliesCombo->addItems(plyOptions);
connect(m_pliesCombo, SIGNAL(activated(const QString &)), this, SLOT(pliesSet(const QString &)));
QLabel *plyLabel = new QLabel(tr("p&lies"));
plyLabel->setBuddy(m_pliesCombo);
m_ignoreOpposCheck = new QCheckBox(tr("oppos pass"));
connect(m_ignoreOpposCheck, SIGNAL(stateChanged(int)), this, SLOT(ignoreOpposChanged()));
m_showDetailsButton = new QPushButton(tr("&Details"));
connect(m_showDetailsButton, SIGNAL(clicked()), this, SLOT(showSimulationDetails()));
plyLayout->addWidget(m_pliesCombo);
plyLayout->addWidget(plyLabel);
plyLayout->addWidget(m_ignoreOpposCheck);
plyLayout->addStretch();
plyLayout->addWidget(m_showDetailsButton);
simulatorLayout->addLayout(plyLayout);
m_partialOppoRackEnable = new QGroupBox(tr("Specify partial oppo rack"));
m_partialOppoRackEnable->setCheckable(true);
m_partialOppoRackEnable->setFlat(true);
connect(m_partialOppoRackEnable, SIGNAL(toggled(bool)), this, SLOT(partialOppoRackEnabled(bool)));
QHBoxLayout *partialOppoRackLayout = new QHBoxLayout(m_partialOppoRackEnable);
Geometry::setupInnerLayout(partialOppoRackLayout);
m_partialOppoRackEdit = new QLineEdit;
connect(m_partialOppoRackEdit, SIGNAL(textEdited(const QString &)), this, SLOT(partialOppoRackChanged()));
partialOppoRackLayout->addWidget(m_partialOppoRackEdit);
simulatorLayout->addWidget(m_partialOppoRackEnable);
m_logfileEnable = new QGroupBox(tr("Log sim to file"));
m_logfileEnable->setCheckable(true);
m_logfileEnable->setFlat(true);
connect(m_logfileEnable, SIGNAL(toggled(bool)), this, SLOT(logfileEnabled(bool)));
QHBoxLayout *logfileLayout = new QHBoxLayout(m_logfileEnable);
Geometry::setupInnerLayout(logfileLayout);
m_logfileEdit = new QLineEdit;
connect(m_logfileEdit, SIGNAL(editingFinished()), this, SLOT(logfileChanged()));
m_logfileChooser = new QPushButton(tr("Browse..."));
connect(m_logfileChooser, SIGNAL(clicked()), this, SLOT(chooseLogfile()));
logfileLayout->addWidget(m_logfileEdit);
logfileLayout->addWidget(m_logfileChooser);
simulatorLayout->addWidget(m_logfileEnable);
m_noteEditor = new NoteEditor;
plugIntoMatrix(m_noteEditor);
plugIntoPositionMatrix(m_noteEditor);
m_moveBox = new MoveBox;
plugIntoMatrix(m_moveBox);
plugIntoPositionMatrix(m_moveBox);
plugIntoMoveMatrix(m_moveBox);
choicesLayout->addWidget(m_moveBox, 3);
choicesLayout->addWidget(m_noteEditor, 1);
choicesLayout->addWidget(m_simulatorWidget, 1);
m_history = new History;
plugIntoHistoryMatrix(m_history);
m_tabWidget = new QTabWidget;
m_tabWidget->addTab(m_history, tr("Histor&y"));
m_tabWidget->addTab(m_choicesWidget, tr("&Choices"));
m_tabWidget->addTab(m_settings, tr("Se&ttings"));
GraphicalFactory factory;
m_brb = new BRB(&factory);
plugIntoMatrix(m_brb);
plugIntoPositionMatrix(m_brb);
m_leftSideLayout->addWidget(m_dashboard);
m_leftSideLayout->addWidget(m_tabWidget);
m_splitter->addWidget(leftSide);
m_splitter->addWidget(m_brb);
m_splitter->setStretchFactor(1, 4);
m_listerDialog = new ListerDialog(this, "quackle", tr("Quackle"), ListerDialog::NothingToReturn);
}
void TopLevel::switchToTab(TabIndex index)
{
m_tabWidget->setCurrentIndex(index);
}
QString TopLevel::playerString() const
{
QString ret;
if (!m_game->hasPositions())
return tr("No game");
Quackle::PlayerList players = m_game->currentPosition().endgameAdjustedScores();
if (players.empty())
return tr("No game");
bool begin = true;
int i = 0;
const int maximumIndex = players.size() - 1;
const Quackle::PlayerList::const_iterator end(players.end());
for (Quackle::PlayerList::const_iterator it = players.begin(); it != end; ++it, ++i)
{
if (!begin)
ret += tr(", ");
if (!begin && i == maximumIndex && i >= 2)
ret += tr("and ");
ret += tr("%1 (score %2)").arg(QuackleIO::Util::uvStringToQString((*it).name())).arg((*it).score());
begin = false;
}
return ret;
}
void TopLevel::showAscii()
{
if (!m_game->hasPositions())
return;
QString text;
// This is now usurped into Reporter's output.
//text += tr("Players: %1").arg(playerString()) + "\n\n";
UVString report;
Quackle::Reporter::reportPosition(m_game->currentPosition(), 0, &report);
text += QuackleIO::Util::uvStringToQString(report);
int result = QMessageBox::question(this, tr("Plaintext board - Quackle"), QString("%1
").arg(text), tr("&Write to file"), tr("Copy to clip&board"), tr("&OK"), 1);
switch (result)
{
case 0:
{
QString filename = QFileDialog::getSaveFileName(this, tr("Choose file to print plaintext board to - Quackle"), getInitialDirectory());
if (!filename.isEmpty())
{
setInitialDirectory(filename);
writeAsciiToFile(text, filename);
}
break;
}
case 1:
copyToClipboard(text);
break;
case 2:
break;
}
}
void TopLevel::copyToClipboard(const QString &text)
{
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
QApplication::clipboard()->setText(text, QClipboard::Selection);
statusMessage(tr("Copied to clipboard."));
}
void TopLevel::writeAsciiToFile(const QString &text, const QString &filename)
{
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QMessageBox::critical(this, tr("Error Writing File - Quackle"), dialogText(tr("Could not open %1 for writing.")).arg(file.fileName()));
return;
}
QTextStream stream(&file);
stream << text << "\n";
file.close();
statusMessage(tr("`%1' written.").arg(filename));
}
void TopLevel::print()
{
pause(true);
QString filename = QFileDialog::getSaveFileName(this, tr("Choose file to print to - Quackle"), m_filename + ".html");
if (filename.isEmpty())
return;
QFile file(filename);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
{
QMessageBox::critical(this, tr("Error Writing File - Quackle"), dialogText(tr("Could not open %1 for writing.")).arg(file.fileName()));
return;
}
QTextStream stream(&file);
//stream << printer.html() << "\n";
file.close();
statusMessage(tr("`%1' written.").arg(filename));
}
void TopLevel::firstTimeRun()
{
switchToTab(SettingsTabIndex);
QMessageBox::information(this, tr("Welcome - Quackle"), dialogText(tr("Welcome to Quackle! To get started, configure a board by clicking Add Board in the Settings tab, add some bonus squares, and then start a new game. Also check out the Helpful Hints from the Help menu, and keep your eye out for the aidant messages in the status bar at the bottom of the window.")));
}
void TopLevel::about()
{
QMessageBox::about(this, tr("About Quackle 1.0"), dialogText(tr(
"Quackle 1.0 is a crossword game playing, analysis, and study tool. Visit the Quackle homepage at http://quackle.org for more information.
"
"Quackle was written by Jason Katz-Brown, John O'Laughlin, John Fultz, Matt Liberty, and Anand Buddhdev. We thank the anonymous donor who made this software free.
"
"Copyright 2005-2015 by
"
""
"- Jason Katz-Brown <jasonkatzbrown@gmail.com>
"
"- John O'Laughlin <olaughlin@gmail.com>
"
"
"
"Quackle is free, open-source software licensed under the terms of the GNU General Public License Version 3. See
"
"http://quackle.org/LICENSE
"
)));
}
void TopLevel::hints()
{
QMessageBox::information(this, tr("Helpful Hints - Quackle"), dialogText(tr(
""
"- Press Shift-Enter after typing your word on the board to enter and commit your move quickly.
"
"- Double-click at any time during a game on any item in the History table to analyze that position. If you then commit a play, you will restart the game from that point and future plays will be lost.
"
"- To analyze a real-life game, start a two-player game with two \"Human With Unknown Rack\" players. For one player, for each turn set the rack to the rack you had in the game and then analyze the position and commit the play that you made in real life. For the other player, commit your oppo's real-life plays.
"
"- Stop simulations by unchecking \"Simulate\" in the Move menu. Sims can be stopped and restarted without losing their state, and sims of different plies can be combined. Check out the sim details during a simulation by choosing \"Show simulation details\" from the Move menu!
"
"- Quackle doesn't include the new American word list (OTCWL2014) because licensing terms prevent us from obtaining and distributing it.
"
"
"
"Have fun using Quackle. We'd love your help developing it, especially if you can code, but we like suggestions too! Please join the Quackle Yahoo! group at
"
"http://games.groups.yahoo.com/group/quackle/
"
)));
}
void TopLevel::showConfigDialog()
{
ConfigDialog dialog;
connect(&dialog, SIGNAL(refreshViews()), this, SLOT(updateAllViews()));
dialog.exec();
}
void TopLevel::saveSettings()
{
CustomQSettings settings;
settings.setValue("quackle/initial-directory", m_initialDirectory);
settings.setValue("quackle/window-size", size());
settings.setValue("quackle/splitter-sizes", m_splitter->saveState());
settings.setValue("quackle/window-state", saveState(0));
settings.setValue("quackle/plies", m_plies);
settings.setValue("quackle/ignoreoppos", m_ignoreOpposCheck->isChecked());
settings.setValue("quackle/logfileEnabled", isLogfileEnabled());
settings.setValue("quackle/logfile", userSpecifiedLogfile());
settings.setValue("quackle/partialopporackenabled", isPartialOppoRackEnabled());
settings.setValue("quackle/partialopporack", userSpecifiedPartialOppoRack());
settings.setValue("quackle/hasBeenRun", true);
QuackerSettings::self()->writeSettings();
}
void TopLevel::loadSettings()
{
CustomQSettings settings;
m_initialDirectory = settings.value("quackle/initial-directory", QString("")).toString();
resize(settings.value("quackle/window-size", QSize(800, 600)).toSize());
if (settings.contains("quackle/splitter-sizes"))
m_splitter->restoreState(settings.value("quackle/splitter-sizes").toByteArray());
if (settings.contains("quackle/window-state"))
restoreState(settings.value("quackle/window-state").toByteArray(), 0);
m_plies = settings.value("quackle/plies", 2).toInt();
updatePliesCombo();
m_ignoreOpposCheck->setChecked(settings.value("quackle/ignoreoppos", false).toBool());
m_logfileEdit->setText(settings.value("quackle/logfile", QString("")).toString());
const bool logfileEnabled = settings.value("quackle/logfileEnabled", false).toBool();
m_logfileEnable->setChecked(logfileEnabled);
setLogfileEnabled(logfileEnabled);
m_partialOppoRackEdit->setText(settings.value("quackle/partialopporack", QString("")).toString());
const bool partialOppoRackEnabled = settings.value("quackle/partialopporackenabled", false).toBool();
m_partialOppoRackEnable->setChecked(partialOppoRackEnabled);
setPartialOppoRackEnabled(partialOppoRackEnabled);
QuackerSettings::self()->readSettings();
}
QString TopLevel::dialogText(const QString &text)
{
return QString("%1").arg(text);
}
void TopLevel::startBirthday()
{
if (!m_game || !m_game->hasPositions())
{
return;
}
// Happy Birthday, Ong Suanne.
bool isBirthday = false;
const Quackle::PlayerList &players = m_game->currentPosition().players();
for (Quackle::PlayerList::const_iterator it = players.begin(); it != players.end(); ++it)
{
if ((*it).name() == "zorbonauts")
{
isBirthday = true;
break;
}
}
if (!isBirthday)
{
m_birthdayTimer->stop();
return;
}
m_birthdayIndex = 0;
m_birthdayTimer->start(800);
}
void TopLevel::birthdayBash()
{
birthdayGram(m_birthdayIndex, /* off */ false);
++m_birthdayIndex;
if (m_birthdayIndex >= 11)
m_birthdayIndex = 0;
birthdayGram(m_birthdayIndex, /* on */ true);
}
void TopLevel::birthdayGram(int index, bool on)
{
switch (index)
{
case 0:
setCaption(tr("HURRRRRRRRRRRRRRRRRRRRRRRRR"));
break;
case 1:
m_newAction->setIconText(on? tr("HAPPY") : tr("New game"));
break;
case 2:
m_generateAction->setIconText(on? tr("BIRTHDAY") : tr("Generate word list"));
break;
case 3:
m_kibitzAction->setIconText(on? tr("ONG") : tr("Generate choices"));
break;
case 4:
m_nextPositionAction->setIconText(on? tr("! ! ! ! ! ! ! ! !") : tr("Forward"));
break;
case 5:
m_kibitzAsActions->actions().front()->setIconText(on? tr("SUANNE") : tr("Ask Championship Player"));
break;
case 6:
m_simulateAction->setIconText(on? tr("! ! ! ! ! ! ! ! !") : tr("Simulate"));
break;
case 7:
m_tabWidget->setTabText(0, on? tr("HAVE A") : tr("Histor&y"));
break;
case 8:
m_tabWidget->setTabText(1, on? tr("SUPERPIMP") : tr("&Choices"));
break;
case 9:
m_tabWidget->setTabText(2, on? tr("YEAR") : tr("Se&ttings"));
break;
case 10:
statusMessage(on? tr("you're awesome don't ever change") : tr(""));
break;
default:
break;
}
}
//////////////
KibitzerListener::KibitzerListener(Quackle::ComputerPlayer *computerPlayer, QObject *parent)
: QObject(parent), m_computerPlayer(computerPlayer), m_slowPlayerWarningTriggered(false)
{
}
void KibitzerListener::kibitzTriggered()
{
if (slownessCheck())
emit kibitzAs(m_computerPlayer);
}
void KibitzerListener::reportTriggered()
{
if (slownessCheck())
emit reportAs(m_computerPlayer);
}
bool KibitzerListener::slownessCheck()
{
return true;
}