Remove print game functionality
[sloppygui.git] / projects / gui / src / mainwindow.cpp
blobb4bee1cd5a7fdad35dbcc7021ce2c328581c2aad
1 /*
2 This file is part of Cute Chess.
4 Cute Chess is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 Cute Chess is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with Cute Chess. If not, see <http://www.gnu.org/licenses/>.
18 #include <QtGui>
20 #include <chessgame.h>
21 #include <chessplayer.h>
22 #include <timecontrol.h>
23 #include <engineconfiguration.h>
24 #include <enginefactory.h>
25 #include <engineprocess.h>
26 #include <humanplayer.h>
28 #include "mainwindow.h"
29 #include "chessboardview.h"
30 #include "chessboardmodel.h"
31 #include "movelistmodel.h"
32 #include "newgamedlg.h"
33 #include "chessclock.h"
34 #include "engineconfigurationmodel.h"
35 #include "enginemanagementdlg.h"
36 #include "plaintextlog.h"
37 #include "gamedatabasemodel.h"
39 MainWindow::MainWindow()
41 setWindowTitle("Cute Chess");
43 QHBoxLayout* clockLayout = new QHBoxLayout();
44 for (int i = 0; i < 2; i++)
46 m_chessClock[i] = new ChessClock();
47 clockLayout->addWidget(m_chessClock[i]);
50 m_boardModel = new ChessboardModel(this);
51 m_chessboardView = new ChessboardView(this);
52 m_chessboardView->setModel(m_boardModel);
53 m_moveListModel = new MoveListModel(this);
54 connect(m_boardModel, SIGNAL(moveMade(const QModelIndex&, const QModelIndex&)),
55 m_chessboardView, SLOT(onMoveMade(const QModelIndex&, const QModelIndex&)));
57 QVBoxLayout* mainLayout = new QVBoxLayout();
58 mainLayout->addLayout(clockLayout);
59 mainLayout->addWidget(m_chessboardView);
61 // The content margins look stupid when used with dock widgets. Drop the
62 // margins except from the top so that the chess clocks have spacing
63 mainLayout->setContentsMargins(0,
64 style()->pixelMetric(QStyle::PM_LayoutTopMargin), 0, 0);
66 QWidget* mainWidget = new QWidget(this);
67 mainWidget->setLayout(mainLayout);
68 setCentralWidget(mainWidget);
70 setStatusBar(new QStatusBar());
72 m_engineConfigurations = new EngineConfigurationModel(this);
74 createActions();
75 createMenus();
76 createToolBars();
77 createDockWindows();
79 readSettings();
82 void MainWindow::createActions()
84 m_newGameAct = new QAction(tr("&New game..."), this);
85 m_newGameAct->setShortcut(QKeySequence("Ctrl+N"));
87 m_quitGameAct = new QAction(tr("&Quit"), this);
88 m_quitGameAct->setShortcut(QKeySequence(tr("Ctrl+Q")));
90 m_manageEnginesAct = new QAction(tr("Manage..."), this);
92 connect(m_newGameAct, SIGNAL(triggered(bool)), this, SLOT(newGame()));
93 connect(m_quitGameAct, SIGNAL(triggered(bool)), this, SLOT(close()));
95 connect (m_manageEnginesAct, SIGNAL(triggered(bool)), this,
96 SLOT(manageEngines()));
99 void MainWindow::createMenus()
101 m_gameMenu = menuBar()->addMenu(tr("&Game"));
102 m_gameMenu->addAction(m_newGameAct);
103 m_gameMenu->addSeparator();
104 m_gameMenu->addAction(m_quitGameAct);
106 m_viewMenu = menuBar()->addMenu(tr("&View"));
108 m_enginesMenu = menuBar()->addMenu(tr("En&gines"));
109 m_enginesMenu->addAction(m_manageEnginesAct);
111 m_helpMenu = menuBar()->addMenu(tr("&Help"));
114 void MainWindow::createToolBars()
116 // Create tool bars here, use actions from createActions()
117 // See: createActions(), QToolBar documentation
120 void MainWindow::createDockWindows()
122 // Engine debug
123 QDockWidget* engineDebugDock = new QDockWidget(tr("Engine Debug"), this);
124 m_engineDebugLog = new PlainTextLog(engineDebugDock);
125 connect(m_engineDebugLog, SIGNAL(saveLogToFileRequest()), this,
126 SLOT(saveLogToFile()));
127 engineDebugDock->setWidget(m_engineDebugLog);
129 addDockWidget(Qt::BottomDockWidgetArea, engineDebugDock);
131 // Game database
132 QDockWidget* gameDatabaseDock = new QDockWidget(tr("Game Database"), this);
133 QTreeView* gameDatabaseView = new QTreeView(gameDatabaseDock);
134 gameDatabaseView->setModel(new GameDatabaseModel(this));
135 gameDatabaseView->setAlternatingRowColors(true);
136 gameDatabaseView->setRootIsDecorated(false);
137 gameDatabaseView->setUniformRowHeights(true);
138 gameDatabaseDock->setWidget(gameDatabaseView);
140 addDockWidget(Qt::BottomDockWidgetArea, gameDatabaseDock);
141 tabifyDockWidget(engineDebugDock, gameDatabaseDock);
143 // Move list
144 QDockWidget* moveListDock = new QDockWidget(tr("Move List"), this);
145 QTreeView* moveListView = new QTreeView(moveListDock);
146 moveListView->setModel(m_moveListModel);
147 moveListView->setAlternatingRowColors(true);
148 moveListView->setRootIsDecorated(false);
149 moveListDock->setWidget(moveListView);
151 connect(m_moveListModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)),
152 moveListView, SLOT(scrollToBottom()));
154 addDockWidget(Qt::RightDockWidgetArea, moveListDock);
156 // Add toggle view actions to the View menu
157 m_viewMenu->addAction(moveListDock->toggleViewAction());
158 m_viewMenu->addAction(engineDebugDock->toggleViewAction());
159 m_viewMenu->addAction(gameDatabaseDock->toggleViewAction());
162 void MainWindow::readSettings()
164 QSettings settings;
166 int size = settings.beginReadArray("engines");
167 for (int i = 0; i < size; i++)
169 settings.setArrayIndex(i);
170 EngineConfiguration config;
171 config.setName(settings.value("name").toString());
172 config.setCommand(settings.value("command").toString());
173 config.setWorkingDirectory(
174 settings.value("working_directory").toString());
175 config.setProtocol(ChessEngine::Protocol(
176 settings.value("protocol").toInt()));
178 m_engineConfigurations->addConfiguration(config);
180 settings.endArray();
183 void MainWindow::newGame()
185 NewGameDialog dlg(m_engineConfigurations, this);
186 if (dlg.exec() != QDialog::Accepted)
187 return;
189 ChessPlayer* player[2] = { 0, 0 };
190 ChessGame* chessgame = new ChessGame(Chess::Variant::Standard, this);
191 connect(chessgame, SIGNAL(humanEnabled(bool)),
192 m_chessboardView, SLOT(setEnabled(bool)));
194 TimeControl tc;
195 tc.setTimePerTc(180000);
196 tc.setMovesPerTc(40);
198 for (int i = 0; i < 2; i++)
200 Chess::Side side = (Chess::Side)i;
201 if (dlg.playerType(side) == NewGameDialog::CPU)
203 EngineConfiguration config = m_engineConfigurations->configuration(dlg.selectedEngine(side));
205 EngineProcess* process = new EngineProcess(this);
207 if (config.workingDirectory().isEmpty())
208 process->setWorkingDirectory(QDir::tempPath());
209 else
210 process->setWorkingDirectory(config.workingDirectory());
212 process->start(config.command());
213 if (!process->waitForStarted())
215 qDebug() << "Cannot start the engine process:" << config.command();
216 return;
218 ChessEngine* engine = EngineFactory::createEngine(config.protocol(), process, this);
219 engine->start();
220 engine->setName(config.name());
221 player[i] = engine;
223 else
225 player[i] = new HumanPlayer(this);
226 connect(m_chessboardView, SIGNAL(humanMove(const GenericMove&)),
227 player[i], SLOT(onHumanMove(const GenericMove&)));
230 player[i]->setTimeControl(tc);
231 chessgame->setPlayer(side, player[i]);
233 connect(player[i], SIGNAL(startedThinking(int)),
234 m_chessClock[i], SLOT(start(int)));
235 connect(player[i], SIGNAL(moveMade(const Chess::Move&)),
236 m_chessClock[i], SLOT(stop()));
237 connect(chessgame, SIGNAL(gameEnded()),
238 m_chessClock[i], SLOT(stop()));
239 connect(player[i], SIGNAL(debugMessage(const QString&)),
240 m_engineDebugLog, SLOT(appendPlainText(const QString&)));
242 m_moveListModel->setGame(chessgame);
244 m_boardModel->setBoard(chessgame->board());
245 chessgame->start();
248 void MainWindow::manageEngines()
250 QList<EngineConfiguration> oldConfigurations =
251 m_engineConfigurations->configurations();
253 EngineManagementDialog dlg(m_engineConfigurations, this);
255 if (dlg.exec() == QDialog::Accepted)
257 QSettings settings;
259 const QList<EngineConfiguration> engines = m_engineConfigurations->configurations();
261 settings.beginWriteArray("engines");
262 for (int i = 0; i < engines.size(); i++)
264 settings.setArrayIndex(i);
265 settings.setValue("name", engines.at(i).name());
266 settings.setValue("command", engines.at(i).command());
267 settings.setValue("working_directory", engines.at(i).workingDirectory());
268 settings.setValue("protocol", engines.at(i).protocol());
270 settings.endArray();
272 // Make sure that the settings are flushed to disk now
273 settings.sync();
275 else
277 // Release the engine configurations model and use
278 // the old configurations as base for the new model
279 delete m_engineConfigurations;
280 m_engineConfigurations = new EngineConfigurationModel(oldConfigurations);
284 void MainWindow::saveLogToFile()
286 PlainTextLog* log = qobject_cast<PlainTextLog*>(QObject::sender());
287 Q_ASSERT(log != 0);
289 const QString fileName = QFileDialog::getSaveFileName(this, tr("Save Log"),
290 QString(), tr("Text Files (*.txt);;All Files (*.*)"));
292 if (fileName.isEmpty())
293 return;
295 QFile file(fileName);
296 if (!file.open(QFile::WriteOnly | QFile::Text))
298 QFileInfo fileInfo(file);
300 QMessageBox msgBox;
301 msgBox.setIcon(QMessageBox::Warning);
302 msgBox.setWindowTitle("Cute Chess");
304 switch (file.error())
306 case QFile::OpenError:
307 case QFile::PermissionsError:
308 msgBox.setText(
309 tr("The file \"%1\" could not be saved because "
310 "of insufficient privileges.")
311 .arg(fileInfo.fileName()));
313 msgBox.setInformativeText(
314 tr("Try selecting a location where you have "
315 "the permissions to create files."));
316 break;
318 case QFile::TimeOutError:
319 msgBox.setText(
320 tr("The file \"%1\" could not be saved because "
321 "the operation timed out.")
322 .arg(fileInfo.fileName()));
324 msgBox.setInformativeText(
325 tr("Try saving the file to a local or another "
326 "network disk."));
327 break;
329 default:
330 msgBox.setText(tr("The file \"%1\" could not be saved.")
331 .arg(fileInfo.fileName()));
333 msgBox.setInformativeText(file.errorString());
334 break;
336 msgBox.exec();
338 return;
341 QTextStream out(&file);
342 out << log->toPlainText();