File indexing completed on 2024-04-28 04:03:13
0001 /*************************************************************************** 0002 File : knights.cpp 0003 Project : Knights 0004 Description : Main window of the application 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2016-1018 Alexander Semke (alexander.semke@web.de) 0007 SPDX-FileCopyrightText: 2010-2012 Miha Čančula (miha@noughmad.eu) 0008 0009 ***************************************************************************/ 0010 0011 /*************************************************************************** 0012 * * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * * 0015 * This program is distributed in the hope that it will be useful, * 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0018 * GNU General Public License for more details. * 0019 * * 0020 * You should have received a copy of the GNU General Public License * 0021 * along with this program; if not, write to the Free Software * 0022 * Foundation, Inc., 51 Franklin Street, Fifth Floor, * 0023 * Boston, MA 02110-1301 USA * 0024 * * 0025 ***************************************************************************/ 0026 0027 #include "knights.h" 0028 #include "proto/localprotocol.h" 0029 #include "gamemanager.h" 0030 #include "knightsview.h" 0031 #include "knightsdebug.h" 0032 #include "settings.h" 0033 #include "gamedialog.h" 0034 #include "clockwidget.h" 0035 #include "historywidget.h" 0036 #include "enginesettings.h" 0037 0038 // KDEGames 0039 #include <KGameThemeSelector> 0040 #include <KGameStandardAction> 0041 0042 #include <KConfigDialog> 0043 #include <KActionCollection> 0044 #include <KStandardAction> 0045 #include <KToggleAction> 0046 #include <KLocalizedString> 0047 #include <KMessageBox> 0048 0049 #include <QCloseEvent> 0050 #include <QDockWidget> 0051 #include <QFileDialog> 0052 #include <QTimer> 0053 #include <QStatusBar> 0054 0055 const char* DontAskDiscard = "dontAskInternal"; 0056 0057 using namespace Knights; 0058 0059 /** 0060 * This class serves as the main window for Knights. It handles the 0061 * menus, toolbars, and status bars. 0062 * 0063 * @short Main window class 0064 * @author %{AUTHOR} <%{EMAIL}> 0065 * @version %{VERSION} 0066 */ 0067 MainWindow::MainWindow() : KXmlGuiWindow(), 0068 m_view(new KnightsView(this)), 0069 m_themeProvider(new KGameThemeProvider("Theme", this)) { 0070 // accept dnd 0071 setAcceptDrops(true); 0072 0073 // tell the KXmlGuiWindow that this is indeed the main widget 0074 setCentralWidget(m_view); 0075 0076 // initial creation/setup of the docks 0077 setDockNestingEnabled(true); 0078 setupDocks(); 0079 0080 // setup actions and GUI 0081 setupActions(); 0082 setupGUI(); 0083 0084 //protocol features 0085 m_protocolFeatures = { 0086 {KGameStandardAction::name(KGameStandardAction::Pause), Protocol::Pause}, 0087 {QStringLiteral("propose_draw"), Protocol::Draw}, 0088 {QStringLiteral("adjourn"), Protocol::Adjourn}, 0089 {QStringLiteral("resign"), Protocol::Resign}, 0090 {QStringLiteral("abort"), Protocol::Abort}, 0091 }; 0092 0093 // setup difficulty management 0094 connect(KGameDifficulty::global(), &KGameDifficulty::currentLevelChanged, Manager::self(), &Manager::levelChanged); 0095 KGameDifficulty::global()->addLevel(new KGameDifficultyLevel(0, "custom", i18n("Custom"), false)); 0096 KGameDifficulty::global()->addStandardLevelRange(KGameDifficultyLevel::VeryEasy, KGameDifficultyLevel::VeryHard, KGameDifficultyLevel::Medium); 0097 KGameDifficultyGUI::init(this); 0098 KGameDifficulty::global()->setEditable(false); 0099 0100 // make all the docks invisible. 0101 // Show required docks after the game protocols are selected 0102 m_clockDock->hide(); 0103 m_bconsoleDock->hide(); 0104 m_wconsoleDock->hide(); 0105 m_chatDock->hide(); 0106 m_historyDock->hide(); 0107 0108 connect(Manager::self(), &Manager::initComplete, this, &MainWindow::protocolInitSuccesful); 0109 connect(Manager::self(), &Manager::playerNameChanged, this, &MainWindow::updateCaption); 0110 connect(Manager::self(), &Manager::activePlayerChanged, this, &MainWindow::activePlayerChanged); 0111 connect(Manager::self(), &Manager::pieceMoved, this, &MainWindow::gameChanged); 0112 connect(Manager::self(), &Manager::winnerNotify, this, &MainWindow::gameOver); 0113 connect(qApp, &QGuiApplication::lastWindowClosed, this, &MainWindow::exitKnights); 0114 0115 m_themeProvider->discoverThemes(QStringLiteral("themes")); 0116 m_view->drawBoard(m_themeProvider); 0117 } 0118 0119 void MainWindow::activePlayerChanged() { 0120 statusBar()->clearMessage(); 0121 Knights::Color color = Manager::self()->activePlayer(); 0122 0123 //show the notification in the status bar, delay it by one second 0124 QTimer::singleShot(1000, this, [=] () { 0125 //the current player has changed within one second, 0126 //don't need to show the notification 0127 if (Manager::self()->activePlayer() != color) 0128 return; 0129 0130 QString name; 0131 if (color == White) 0132 name = Protocol::white()->playerName(); 0133 else 0134 name = Protocol::black()->playerName(); 0135 statusBar()->showMessage(i18n("%1 is thinking...", name)); 0136 }); 0137 0138 } 0139 0140 void MainWindow::setupDocks() { 0141 // clock dock 0142 m_clockDock = new QDockWidget(i18n("Clock"), this); 0143 m_clockDock->setObjectName(QStringLiteral("ClockDockWidget")); // for QMainWindow::saveState() 0144 m_playerClock = new ClockWidget(this); 0145 m_clockDock->setWidget(m_playerClock); 0146 m_clockDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); 0147 connect(m_view, &KnightsView::displayedPlayerChanged, m_playerClock, &ClockWidget::setDisplayedPlayer); 0148 connect(Manager::self(), &Manager::timeChanged, m_playerClock, &ClockWidget::setCurrentTime); 0149 addDockWidget(Qt::RightDockWidgetArea, m_clockDock); 0150 0151 // console dock for black 0152 m_bconsoleDock = new QDockWidget(); 0153 m_bconsoleDock->setObjectName(QStringLiteral("BlackConsoleDockWidget")); 0154 m_bconsoleDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); 0155 addDockWidget(Qt::LeftDockWidgetArea, m_bconsoleDock); 0156 0157 // console dock for white 0158 m_wconsoleDock = new QDockWidget(); 0159 m_wconsoleDock->setObjectName(QStringLiteral("WhiteConsoleDockWidget")); 0160 m_wconsoleDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); 0161 addDockWidget(Qt::LeftDockWidgetArea, m_wconsoleDock); 0162 0163 // chat dock 0164 m_chatDock = new QDockWidget(); 0165 m_chatDock->setObjectName(QStringLiteral("ChatDockWidget")); 0166 m_chatDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); 0167 addDockWidget(Qt::LeftDockWidgetArea, m_chatDock); 0168 0169 // history dock 0170 m_historyDock = new QDockWidget(); 0171 m_historyDock->setObjectName(QStringLiteral("HistoryDockWidget")); 0172 m_historyDock->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); 0173 m_historyDock->setWindowTitle(i18nc("@title:window Title of the list of all the moves made in the game", "Move History")); 0174 m_historyDock->setWidget(new HistoryWidget); 0175 addDockWidget(Qt::LeftDockWidgetArea, m_historyDock); 0176 } 0177 0178 void MainWindow::setupActions() { 0179 KGameStandardAction::gameNew(this, &MainWindow::fileNew, actionCollection()); 0180 KGameStandardAction::quit(qApp, &QApplication::closeAllWindows, actionCollection()); 0181 m_pauseAction = KGameStandardAction::pause(Manager::self(), &Manager::pause, actionCollection()); 0182 m_pauseAction->setEnabled(false); 0183 KStandardAction::preferences(this, &MainWindow::optionsPreferences, actionCollection()); 0184 0185 m_saveAction = KGameStandardAction::save(this, &MainWindow::fileSave, actionCollection()); 0186 m_saveAction->setEnabled(false); 0187 m_saveAsAction = KGameStandardAction::saveAs(this, &MainWindow::fileSaveAs, actionCollection()); 0188 m_saveAsAction->setEnabled(false); 0189 KGameStandardAction::load(this, &MainWindow::fileLoad, actionCollection()); 0190 0191 m_resignAction = actionCollection()->addAction(QStringLiteral("resign"), this, &MainWindow::resign); 0192 m_resignAction->setText(i18n("Resign")); 0193 m_resignAction->setToolTip(i18n("Admit your inevitable defeat")); 0194 m_resignAction->setIcon(QIcon::fromTheme(QStringLiteral("flag-red"))); 0195 m_resignAction->setEnabled(false); 0196 0197 m_undoAction = actionCollection()->addAction(QStringLiteral("move_undo"), this, &MainWindow::undo); 0198 m_undoAction->setText(i18n("Undo")); 0199 m_undoAction->setToolTip(i18n("Take back your last move")); 0200 m_undoAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-undo"))); 0201 connect(Manager::self(), &Manager::undoPossible, m_undoAction, &QAction::setEnabled); 0202 m_undoAction->setEnabled(false); 0203 0204 m_redoAction = actionCollection()->addAction(QStringLiteral("move_redo"), this, &MainWindow::redo); 0205 m_redoAction->setText(i18n("Redo")); 0206 m_redoAction->setToolTip(i18n("Repeat your last move")); 0207 m_redoAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-redo"))); 0208 connect(Manager::self(), &Manager::redoPossible, m_redoAction, &QAction::setEnabled); 0209 m_redoAction->setEnabled(false); 0210 m_redoAction->setVisible(false); 0211 0212 m_drawAction = actionCollection()->addAction(QStringLiteral("propose_draw"), Manager::self(), &Manager::offerDraw); 0213 m_drawAction->setText(i18n("Offer &Draw")); 0214 m_drawAction->setToolTip(i18n("Offer a draw to your opponent")); 0215 m_drawAction->setIcon(QIcon::fromTheme(QStringLiteral("flag-blue"))); 0216 m_drawAction->setEnabled(false); 0217 0218 m_adjournAction = actionCollection()->addAction(QStringLiteral("adjourn"), Manager::self(), &Manager::adjourn); 0219 m_adjournAction->setText(i18n("Adjourn")); 0220 m_adjournAction->setToolTip(i18n("Continue this game at a later time")); 0221 m_adjournAction->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); 0222 m_adjournAction->setEnabled(false); 0223 0224 QAction* abortAction = actionCollection()->addAction(QStringLiteral("abort"), Manager::self(), &Manager::abort); 0225 abortAction->setText(i18n("Abort")); 0226 abortAction->setToolTip(i18n("End the game immediately")); 0227 abortAction->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel"))); 0228 abortAction->setEnabled(false); 0229 0230 KToggleAction* clockAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("clock")), i18n("Show Clock"), actionCollection()); 0231 actionCollection()->addAction(QStringLiteral("show_clock"), clockAction); 0232 connect(clockAction, &KToggleAction::triggered, m_clockDock, &QDockWidget::setVisible); 0233 connect(clockAction, &KToggleAction::triggered, this, &MainWindow::setShowClockSetting); 0234 clockAction->setVisible(false); 0235 0236 KToggleAction* historyAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("view-history")), i18n("Show History"), actionCollection()); 0237 actionCollection()->addAction(QStringLiteral("show_history"), historyAction); 0238 connect(historyAction, &KToggleAction::triggered, m_historyDock, &QDockWidget::setVisible); 0239 connect(historyAction, &KToggleAction::triggered, this, &MainWindow::setShowHistorySetting); 0240 historyAction->setVisible(true); 0241 historyAction->setChecked(Settings::showHistory()); 0242 0243 KToggleAction* wconsoleAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("utilities-terminal")), i18n("Show White Console"), actionCollection()); 0244 actionCollection()->addAction(QStringLiteral("show_console_white"), wconsoleAction); 0245 connect(wconsoleAction, &KToggleAction::triggered, m_wconsoleDock, &QDockWidget::setVisible); 0246 connect(wconsoleAction, &KToggleAction::triggered, this, &MainWindow::setShowConsoleSetting); 0247 wconsoleAction->setVisible(false); 0248 0249 KToggleAction* bconsoleAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("utilities-terminal")), i18n("Show Black Console"), actionCollection()); 0250 actionCollection()->addAction(QStringLiteral("show_console_black"), bconsoleAction); 0251 connect(bconsoleAction, &KToggleAction::triggered, m_bconsoleDock, &QDockWidget::setVisible); 0252 connect(bconsoleAction, &KToggleAction::triggered, this, &MainWindow::setShowConsoleSetting); 0253 bconsoleAction->setVisible(false); 0254 0255 KToggleAction* chatAction = new KToggleAction(QIcon::fromTheme(QStringLiteral("meeting-attending")), i18n("Show Chat"), actionCollection()); 0256 actionCollection()->addAction(QStringLiteral("show_chat"), chatAction); 0257 connect(chatAction, &KToggleAction::triggered, m_chatDock, &QDockWidget::setVisible); 0258 connect(chatAction, &KToggleAction::triggered, this, &MainWindow::setShowChatSetting); 0259 chatAction->setVisible(false); 0260 } 0261 0262 void MainWindow::fileNew() { 0263 if(!maybeSave()) 0264 return; 0265 0266 QPointer<GameDialog> gameNewDialog = new GameDialog(this); 0267 if(gameNewDialog->exec() == QDialog::Accepted) { 0268 Manager::self()->reset(); 0269 gameNewDialog->setupProtocols(); 0270 connect(Protocol::white(), &Protocol::error, this, &MainWindow::protocolError); 0271 connect(Protocol::black(), &Protocol::error, this, &MainWindow::protocolError); 0272 gameNewDialog->save(); 0273 0274 m_pauseAction->setChecked(false); 0275 Manager::self()->initialize(); 0276 0277 bool difficulty = (Protocol::white()->supportedFeatures()& Protocol::AdjustDifficulty) 0278 || (Protocol::black()->supportedFeatures()& Protocol::AdjustDifficulty); 0279 KGameDifficulty::global()->setEditable(difficulty); 0280 } 0281 delete gameNewDialog; 0282 0283 m_saveAction->setEnabled(false); 0284 m_saveAsAction->setEnabled(false); 0285 m_fileName = QString(); 0286 } 0287 0288 void MainWindow::fileLoad() { 0289 if(!maybeSave()) 0290 return; 0291 0292 KConfigGroup conf(KSharedConfig::openConfig(), QStringLiteral("MainWindow")); 0293 QString dir = conf.readEntry("LastOpenDir", ""); 0294 const QString& fileName = QFileDialog::getOpenFileName(this, i18n("Open File"), dir, 0295 i18n("Portable game notation (*.pgn)")); 0296 if(fileName.isEmpty()) 0297 return; 0298 0299 Manager::self()->reset(); 0300 Protocol::setWhiteProtocol(new LocalProtocol()); 0301 Protocol::setBlackProtocol(new LocalProtocol()); 0302 0303 connect(Protocol::white(), &Protocol::error, this, &MainWindow::protocolError); 0304 connect(Protocol::black(), &Protocol::error, this, &MainWindow::protocolError); 0305 0306 m_loadFileName = fileName; 0307 Manager::self()->initialize(); 0308 m_saveAction->setEnabled(false); 0309 0310 //save new "last open directory" 0311 int pos = fileName.lastIndexOf(QDir::separator()); 0312 if (pos != -1) { 0313 const QString& newDir = fileName.left(pos); 0314 if (newDir != dir) 0315 conf.writeEntry("LastOpenDir", newDir); 0316 } 0317 } 0318 0319 void MainWindow::protocolInitSuccesful() { 0320 qCDebug(LOG_KNIGHTS) << "Show Clock:" << Settings::showClock() << "Show Console:" << Settings::showConsole(); 0321 updateCaption(); 0322 0323 // show clock action button if timer active 0324 // show clock dock widget if timer active and configuration file entry has visible = true 0325 bool showClock = false; 0326 if(Manager::self()->timeControlEnabled(White) || Manager::self()->timeControlEnabled(Black)) { 0327 actionCollection()->action(QStringLiteral("show_clock"))->setVisible(true); 0328 m_playerClock->setPlayerName(White, Protocol::white()->playerName()); 0329 m_playerClock->setPlayerName(Black, Protocol::black()->playerName()); 0330 m_playerClock->setTimeLimit(White, Manager::self()->timeLimit(White)); 0331 m_playerClock->setTimeLimit(Black, Manager::self()->timeLimit(Black)); 0332 showClock = Settings::showClock(); 0333 } 0334 m_clockDock->setVisible(showClock); 0335 actionCollection()->action(QStringLiteral("show_clock"))->setChecked(showClock); 0336 0337 //history dock 0338 bool showHistory = Settings::showHistory(); 0339 m_historyDock->setVisible(showHistory); 0340 actionCollection()->action(QStringLiteral("show_history"))->setChecked(showHistory); 0341 0342 if ( !(Protocol::white()->supportedFeatures() & Protocol::Undo && 0343 Protocol::black()->supportedFeatures() & Protocol::Undo) ) { 0344 m_undoAction->setVisible(false); 0345 m_redoAction->setVisible(false); 0346 } else { 0347 m_undoAction->setVisible(true); 0348 m_redoAction->setVisible(true); 0349 } 0350 0351 Protocol::Features f = Protocol::NoFeatures; 0352 if(Protocol::white()->isLocal() && !(Protocol::black()->isLocal())) 0353 f = Protocol::black()->supportedFeatures(); 0354 else if(Protocol::black()->isLocal() && !(Protocol::white()->isLocal())) 0355 f = Protocol::white()->supportedFeatures(); 0356 else if(!(Protocol::black()->isLocal()) && !(Protocol::white()->isLocal())) { 0357 // These protocol features make sense when neither player is local 0358 f = Protocol::Pause | Protocol::Adjourn | Protocol::Abort; 0359 f &= Protocol::white()->supportedFeatures(); 0360 f &= Protocol::black()->supportedFeatures(); 0361 } 0362 0363 for (auto it = m_protocolFeatures.constBegin(); it != m_protocolFeatures.constEnd(); ++it) 0364 actionCollection()->action(it.key())->setEnabled(f & it.value()); 0365 0366 // show console action button if protocol allows a console 0367 // show console dock widget if protocol allows and configuration file entry has visible = true 0368 // finally, hide any dock widget not needed - in case it is still active from previous game 0369 actionCollection()->action(QStringLiteral("show_console_white"))->setVisible(false); 0370 actionCollection()->action(QStringLiteral("show_console_black"))->setVisible(false); 0371 actionCollection()->action(QStringLiteral("show_chat"))->setVisible(false); 0372 QList<Protocol::ToolWidgetData> list; 0373 list << Protocol::black()->toolWidgets(); 0374 list << Protocol::white()->toolWidgets(); 0375 for (const auto& data : std::as_const(list)) { 0376 switch(data.type) { 0377 case Protocol::ConsoleToolWidget: 0378 if(data.owner == White) { 0379 m_wconsoleDock->setWindowTitle(data.title); 0380 m_wconsoleDock->setWidget(data.widget); 0381 actionCollection()->action(QStringLiteral("show_console_white"))->setVisible(true); 0382 if(Settings::showConsole()) { 0383 m_wconsoleDock->setVisible(true); 0384 actionCollection()->action(QStringLiteral("show_console_white"))->setChecked(true); 0385 } else { 0386 m_wconsoleDock->setVisible(false); 0387 actionCollection()->action(QStringLiteral("show_console_white"))->setChecked(false); 0388 } 0389 } else { 0390 m_bconsoleDock->setWindowTitle(data.title); 0391 m_bconsoleDock->setWidget(data.widget); 0392 actionCollection()->action(QStringLiteral("show_console_black"))->setVisible(true); 0393 if(Settings::showConsole()) { 0394 m_bconsoleDock->setVisible(true); 0395 actionCollection()->action(QStringLiteral("show_console_black"))->setChecked(true); 0396 } else { 0397 m_bconsoleDock->setVisible(false); 0398 actionCollection()->action(QStringLiteral("show_console_black"))->setChecked(false); 0399 } 0400 } 0401 break; 0402 0403 case Protocol::ChatToolWidget: 0404 m_chatDock->setWindowTitle(data.title); 0405 m_chatDock->setWidget(data.widget); 0406 actionCollection()->action(QStringLiteral("show_chat"))->setVisible(true); 0407 if(Settings::showChat()) { 0408 m_chatDock->setVisible(true); 0409 actionCollection()->action(QStringLiteral("show_chat"))->setChecked(true); 0410 } else { 0411 m_chatDock->setVisible(false); 0412 actionCollection()->action(QStringLiteral("show_chat"))->setChecked(false); 0413 } 0414 break; 0415 0416 default: 0417 break; 0418 } 0419 } 0420 if(!actionCollection()->action(QStringLiteral("show_console_white"))->isVisible()) 0421 m_wconsoleDock->hide(); 0422 if(!actionCollection()->action(QStringLiteral("show_console_black"))->isVisible()) 0423 m_bconsoleDock->hide(); 0424 if(!actionCollection()->action(QStringLiteral("show_chat"))->isVisible()) 0425 m_chatDock->hide(); 0426 0427 Manager::self()->startGame(); 0428 0429 if(m_loadFileName.isEmpty()) 0430 m_view->setupBoard(m_themeProvider); 0431 else { 0432 int speed = Settings::animationSpeed(); 0433 Settings::setAnimationSpeed(Settings::EnumAnimationSpeed::Instant); 0434 m_view->setupBoard(m_themeProvider); 0435 0436 Manager::self()->loadGameHistoryFrom(m_loadFileName); 0437 setCaption(m_loadFileName); 0438 0439 m_loadFileName.clear(); 0440 Settings::setAnimationSpeed(speed); 0441 } 0442 } 0443 0444 void MainWindow::protocolError(Protocol::ErrorCode errorCode, const QString& errorString) { 0445 if(errorCode != Protocol::UserCancelled) 0446 KMessageBox::error(this, errorString, Protocol::stringFromErrorCode(errorCode)); 0447 Protocol::white()->deleteLater(); 0448 Protocol::black()->deleteLater(); 0449 } 0450 0451 void MainWindow::optionsPreferences() { 0452 if(KConfigDialog::showDialog(QStringLiteral("settings"))) 0453 return; 0454 KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Settings::self()); 0455 QWidget *generalSettingsDlg = new QWidget; 0456 ui_prefs_base.setupUi(generalSettingsDlg); 0457 0458 dialog->addPage(generalSettingsDlg, i18n("General"), QStringLiteral("games-config-options")); 0459 connect(dialog, &KConfigDialog::settingsChanged, m_view, &KnightsView::settingsChanged); 0460 0461 EngineSettings* engineSettings = new EngineSettings(this); 0462 dialog->addPage(engineSettings, i18n("Computer Engines"), QStringLiteral("computer")); 0463 connect(dialog, &KConfigDialog::accepted, engineSettings, &EngineSettings::save); 0464 0465 //FIXME: the accessibility page doesn't seem to be used at the moment. 0466 //Furthermore, the option "Speak opponent's moves" has to be behind HAVE_SPEECH 0467 // QWidget* accessDlg = new QWidget; 0468 // ui_prefs_access.setupUi(accessDlg); 0469 // dialog->addPage(accessDlg, i18n("Accessibility"), QLatin1String("preferences-desktop-accessibility")); 0470 0471 KGameThemeSelector* themeDlg = new KGameThemeSelector(m_themeProvider, KGameThemeSelector::EnableNewStuffDownload, dialog); 0472 themeDlg->setNewStuffConfigFileName(QStringLiteral("knights.knsrc")); 0473 dialog->addPage(themeDlg, i18n("Theme"), QStringLiteral("games-config-theme")); 0474 dialog->setAttribute(Qt::WA_DeleteOnClose); 0475 0476 dialog->show(); 0477 } 0478 0479 void MainWindow::resign() { 0480 int rc = KMessageBox::questionTwoActions(this, 0481 i18n("Do you really want to resign?"), i18n("Resign"), 0482 KGuiItem(i18nc("@action:button", "Resign"), QStringLiteral("flag-red")), 0483 KStandardGuiItem::cancel()); 0484 if (rc == KMessageBox::PrimaryAction) 0485 Manager::self()->resign(); 0486 } 0487 0488 void MainWindow::undo() { 0489 if(!Protocol::white()->isLocal() && !Protocol::black()->isLocal()) { 0490 // No need to pause the game if both players are local 0491 QAction* pa = actionCollection()->action(KGameStandardAction::name(KGameStandardAction::Pause)); 0492 if(pa) 0493 pa->setChecked(true); 0494 } 0495 Manager::self()->undo(); 0496 } 0497 0498 void MainWindow::redo() { 0499 Manager::self()->redo(); 0500 if(!Protocol::white()->isLocal() && !Protocol::black()->isLocal()) { 0501 // No need to pause the game if both players are local 0502 QAction* pa = actionCollection()->action(KGameStandardAction::name(KGameStandardAction::Pause)); 0503 if(pa && !Manager::self()->canRedo()) 0504 pa->setChecked(false); 0505 } 0506 } 0507 0508 void MainWindow::gameChanged() { 0509 m_saveAction->setEnabled(true); 0510 m_saveAsAction->setEnabled(true); 0511 } 0512 0513 void MainWindow::gameOver(Color winner) { 0514 qCDebug(LOG_KNIGHTS) << colorName (winner); 0515 0516 statusBar()->clearMessage(); 0517 0518 //game is over -> disable game actions 0519 m_pauseAction->setEnabled(false); 0520 m_drawAction->setEnabled(false); 0521 m_resignAction->setEnabled(false); 0522 m_adjournAction->setEnabled(false); 0523 0524 //show the dialog to ask to save the current game or to start a new one 0525 QPointer<QDialog> dlg = new QDialog ( this ); 0526 QVBoxLayout *mainLayout = new QVBoxLayout; 0527 QWidget *mainWidget = new QWidget(this); 0528 dlg->setLayout(mainLayout); 0529 dlg->setWindowTitle (i18nc("@title:window", "Game over")); 0530 mainLayout->addWidget(mainWidget); 0531 0532 QDialogButtonBox *bBox = new QDialogButtonBox( QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Apply ); 0533 QMap<QDialogButtonBox::StandardButton, QString> buttonsMap; 0534 buttonsMap[QDialogButtonBox::Ok] = KGameStandardAction::name ( KGameStandardAction::New ); 0535 buttonsMap[QDialogButtonBox::Apply] = KGameStandardAction::name ( KGameStandardAction::Save ); 0536 0537 for ( auto it = buttonsMap.constBegin(); it != buttonsMap.constEnd(); ++it ) { 0538 QAction* a = actionCollection()->action ( it.value() ); 0539 Q_ASSERT(a); 0540 0541 bBox->button ( it.key() )->setText ( a->text() ); 0542 bBox->button ( it.key() )->setIcon ( QIcon ( a->icon() ) ); 0543 bBox->button ( it.key() )->setToolTip ( a->toolTip() ); 0544 } 0545 0546 connect( bBox, &QDialogButtonBox::accepted, dlg.data(), &QDialog::accept ); 0547 connect( bBox, &QDialogButtonBox::rejected, dlg.data(), &QDialog::reject ); 0548 connect( bBox->button (QDialogButtonBox::Apply), &QPushButton::clicked, 0549 static_cast<MainWindow *> (window()), &MainWindow::fileSave ); 0550 0551 QLabel* label = new QLabel(this); 0552 if ( winner == NoColor ) 0553 label->setText ( i18n ( "The game ended in a draw" ) ); 0554 else { 0555 QString winnerName = Protocol::byColor ( winner )->playerName(); 0556 if ( winnerName == colorName(winner) ) { 0557 if ( winner == White ) { 0558 label->setText ( i18nc("White as in the player with white pieces", 0559 "The game ended with a victory for <em>White</em>") ); 0560 } else { 0561 label->setText ( i18nc("Black as in the player with black pieces", 0562 "The game ended with a victory for <em>Black</em>") ); 0563 } 0564 } else { 0565 if ( winner == White ) { 0566 label->setText ( i18nc("Player name, then <White as in the player with white pieces", 0567 "The game ended with a victory for <em>%1</em>, playing White", winnerName) ); 0568 } else { 0569 label->setText ( i18nc("Player name, then Black as in the player with black pieces", 0570 "The game ended with a victory for <em>%1</em>, playing Black", winnerName) ); 0571 } 0572 } 0573 } 0574 mainLayout->addWidget(label); 0575 mainLayout->addWidget(bBox); 0576 0577 int rc = dlg->exec(); 0578 0579 qCDebug(LOG_KNIGHTS) << Protocol::white(); 0580 qCDebug(LOG_KNIGHTS) << Protocol::black(); 0581 delete dlg; 0582 0583 if (rc == QDialog::Accepted) 0584 fileNew(); 0585 } 0586 0587 void MainWindow::setShowClockSetting(bool value) { 0588 Settings::setShowClock(value); 0589 } 0590 0591 void MainWindow::setShowHistorySetting(bool value) { 0592 Settings::setShowHistory(value); 0593 } 0594 0595 void MainWindow::setShowConsoleSetting() { 0596 if((actionCollection()->action(QStringLiteral("show_console_white"))->isChecked()) && (actionCollection()->action(QStringLiteral("show_console_white"))->isVisible())) 0597 Settings::setShowConsole(true); 0598 else if((actionCollection()->action(QStringLiteral("show_console_black"))->isChecked()) && (actionCollection()->action(QStringLiteral("show_console_black"))->isVisible())) 0599 Settings::setShowConsole(true); 0600 else 0601 Settings::setShowConsole(false); 0602 } 0603 0604 void MainWindow::setShowChatSetting(bool value) { 0605 Settings::setShowChat(value); 0606 } 0607 0608 void MainWindow::exitKnights() { 0609 //This will close the gnuchess/crafty/whatever process if it's running. 0610 Manager::self()->reset(); 0611 Settings::self()->save(); 0612 } 0613 0614 void MainWindow::updateCaption() { 0615 if(Protocol::white() && Protocol::black()) 0616 setCaption(i18n("%1 vs. %2", Protocol::white()->playerName(), Protocol::black()->playerName())); 0617 } 0618 0619 bool MainWindow::maybeSave() { 0620 if(!Manager::self()->isGameActive()) 0621 return true; 0622 0623 if(!Settings::askDiscard()) 0624 return true; 0625 0626 Settings::setDontAskInternal(QString()); 0627 0628 int result = KMessageBox::warningTwoActionsCancel(QApplication::activeWindow(), 0629 i18n("This will end your game.\nWould you like to save the move history?"), 0630 QString(), 0631 KStandardGuiItem::save(), 0632 KStandardGuiItem::discard(), 0633 KStandardGuiItem::cancel(), 0634 QLatin1String(DontAskDiscard)); 0635 0636 KMessageBox::ButtonCode res; 0637 Settings::setAskDiscard(KMessageBox::shouldBeShownTwoActions(QLatin1String(DontAskDiscard), res)); 0638 0639 if(result == KMessageBox::PrimaryAction) 0640 fileSave(); 0641 0642 return result != KMessageBox::Cancel; 0643 } 0644 0645 void MainWindow::fileSave() { 0646 if(m_fileName.isEmpty()) { 0647 KConfigGroup conf(KSharedConfig::openConfig(), QStringLiteral("MainWindow")); 0648 QString dir = conf.readEntry("LastOpenDir", ""); 0649 m_fileName = QFileDialog::getSaveFileName(this, i18n("Save"), dir, 0650 i18n("Portable game notation (*.pgn)")); 0651 0652 if (m_fileName.isEmpty())// "Cancel" was clicked 0653 return; 0654 0655 //save new "last open directory" 0656 int pos = m_fileName.lastIndexOf(QDir::separator()); 0657 if (pos != -1) { 0658 const QString& newDir = m_fileName.left(pos); 0659 if (newDir != dir) 0660 conf.writeEntry("LastOpenDir", newDir); 0661 } 0662 } 0663 0664 Manager::self()->saveGameHistoryAs(m_fileName); 0665 setCaption(m_fileName); 0666 m_saveAction->setEnabled(false); 0667 } 0668 0669 void MainWindow::fileSaveAs() { 0670 KConfigGroup conf(KSharedConfig::openConfig(), QStringLiteral("MainWindow")); 0671 QString dir = conf.readEntry("LastOpenDir", ""); 0672 QString fileName = QFileDialog::getSaveFileName(this, i18nc("@title:window", "Save As"), dir, 0673 i18n("Portable game notation (*.pgn)")); 0674 0675 if (fileName.isEmpty())// "Cancel" was clicked 0676 return; 0677 0678 if (fileName.contains(QLatin1String(".lml"), Qt::CaseInsensitive) == false) 0679 fileName.append(QLatin1String(".lml")); 0680 0681 //save new "last open directory" 0682 int pos = fileName.lastIndexOf(QDir::separator()); 0683 if (pos != -1) { 0684 const QString& newDir = fileName.left(pos); 0685 if (newDir != dir) 0686 conf.writeEntry("LastOpenDir", newDir); 0687 } 0688 0689 m_fileName = fileName; 0690 Manager::self()->saveGameHistoryAs(m_fileName); 0691 setCaption(m_fileName); 0692 } 0693 0694 void MainWindow::closeEvent(QCloseEvent* event) { 0695 if (!maybeSave()) 0696 event->ignore(); 0697 } 0698 0699 #include "moc_knights.cpp"