Warning, file /games/kfourinline/src/kwin4.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     This file is part of the KDE games kwin4 program
0003     SPDX-FileCopyrightText: 1995-2007 Martin Heni <kde@heni-online.de>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "kwin4.h"
0009 
0010 // own
0011 #include "chatdlg.h"
0012 #include "kfourinline_debug.h"
0013 #include "kgamedebugdialog.h"
0014 #include "kgamedialog.h"
0015 #include "kgamedialogconfig.h"
0016 #include "kwin4doc.h"
0017 #include "kwin4view.h"
0018 #include "prefs.h"
0019 #include "reflectiongraphicsscene.h"
0020 #include "ui_settings.h"
0021 #include "ui_statistics.h"
0022 // KDEGames
0023 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
0024 #include <libkdegamesprivate/kgame/kgamechat.h>
0025 // KF
0026 #include <KActionCollection>
0027 #include <KConfig>
0028 #include <KConfigDialog>
0029 #include <KLocalizedString>
0030 #include <KMessageBox>
0031 #include <KSelectAction>
0032 #include <KStandardAction>
0033 #include <KStandardGameAction>
0034 // Qt
0035 #include <QFileDialog>
0036 #include <QGroupBox>
0037 #include <QIcon>
0038 #include <QLayout>
0039 #include <QRadioButton>
0040 #include <QStatusBar>
0041 #include <QTimer>
0042 #include <QVBoxLayout>
0043 
0044 // Abbreviations
0045 #define ACTION(x) (actionCollection()->action(x))
0046 #define ID_STATUS_MSG 1003
0047 #define ID_STATUS_MOVER 1002
0048 
0049 #define UPDATE_TIME 25 /* [ms] */
0050 
0051 // Configuration file
0052 #include "config-src.h"
0053 
0054 // Construct the main application window
0055 KWin4App::KWin4App(QWidget *parent)
0056     : KXmlGuiWindow(parent)
0057     , mTheme()
0058     , mView()
0059     , mDoc()
0060     , mScene()
0061     , mColorGroup()
0062     , mMyChatDlg()
0063     , mStatusMsg()
0064     , mStatusMover()
0065 {
0066     // Read theme files
0067     QStringList themeList;
0068     const QString dir = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("grafix"), QStandardPaths::LocateDirectory);
0069     const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop"));
0070     for (const QString &file : fileNames)
0071         themeList.append(dir + QLatin1Char('/') + file);
0072 
0073     if (themeList.isEmpty()) {
0074         KMessageBox::error(this, i18n("Installation error: No theme list found."));
0075         QTimer::singleShot(0, this, &QWidget::close);
0076         return;
0077     }
0078 
0079     // Read theme files
0080     for (int i = 0; i < themeList.size(); i++) {
0081         KConfig themeInfo(themeList.at(i), KConfig::SimpleConfig);
0082         KConfigGroup themeGroup(&themeInfo, "Theme");
0083         QString name = themeGroup.readEntry("Name", QString());
0084         QString file = themeGroup.readEntry("File", QString());
0085         bool isDefault = themeGroup.readEntry("Default", false);
0086         if (mThemeDefault.isNull())
0087             mThemeDefault = name;
0088         if (isDefault)
0089             mThemeDefault = name;
0090         mThemeFiles[name] = file;
0091         qCDebug(KFOURINLINE_LOG) << "Found theme(" << i << "): " << themeList.at(i) << " Name(i18n)=" << name << " File=" << file << " default=" << isDefault;
0092     }
0093     mThemeIndexNo = themeIdxFromName(mThemeDefault);
0094 
0095     // Setup application
0096     mDoc = new KWin4Doc(this);
0097     qCDebug(KFOURINLINE_LOG) << "Init doc";
0098     QString aiEngine = mDoc->findProcessName();
0099     qCDebug(KFOURINLINE_LOG) << "Init AI" << aiEngine;
0100     if (aiEngine.isEmpty()) {
0101         KMessageBox::error(this, i18n("Installation error: No AI engine found. Continue without AI."));
0102     }
0103 
0104     // Read properties (before GUI and thememanager but after new document)
0105     qCDebug(KFOURINLINE_LOG) << "read prop";
0106     readProperties();
0107 
0108     // Scene
0109     mScene = new ReflectionGraphicsScene(UPDATE_TIME, this);
0110 
0111     // Theme
0112     QString themeFile = themefileFromIdx(mThemeIndexNo);
0113     qCDebug(KFOURINLINE_LOG) << "Loading theme" << themeFile << " #" << mThemeIndexNo;
0114     mTheme = new ThemeManager(themeFile, this);
0115     if (mTheme->checkTheme() != 0) {
0116         KMessageBox::error(this, i18n("Installation error: Theme file error."));
0117         QTimer::singleShot(0, this, &QWidget::close);
0118         return;
0119     }
0120 
0121     // View
0122     mView = new KWin4View(UPDATE_TIME, QSize(800, 600), mScene, mTheme, this);
0123     mDoc->setView(mView);
0124     connect(mView, &KWin4View::signalQuickStart, this, &KWin4App::quickStart);
0125 
0126     // Players (after view)
0127     qCDebug(KFOURINLINE_LOG) << "Init pl";
0128     mDoc->initPlayers();
0129 
0130     // Init GUI
0131     initGUI();
0132     initStatusBar();
0133 
0134     // Adjust GUI
0135     setCentralWidget(mView);
0136     setupGUI();
0137 
0138     // Connect signals
0139     connectDocument();
0140     // Read global config for document (after initPlayers)
0141     mDoc->readConfig(KSharedConfig::openConfig().data());
0142 
0143     // Check menus
0144     checkMenus();
0145 
0146     // Skip intro?
0147     if (global_skip_intro) {
0148         menuNewGame();
0149     }
0150     // Start game automatically in demo mode
0151     else if (global_demo_mode) {
0152         QTimer::singleShot(11500, this, &KWin4App::menuNewGame);
0153     }
0154 }
0155 
0156 // Destruct application
0157 KWin4App::~KWin4App()
0158 {
0159     qCDebug(KFOURINLINE_LOG) << "~KWin4App()";
0160     delete mDoc;
0161     delete mView;
0162     delete mScene;
0163     delete mTheme;
0164     delete mMyChatDlg;
0165     qCDebug(KFOURINLINE_LOG) << "~KWin4App()";
0166 }
0167 
0168 // Called by Qt when the window is closed
0169 void KWin4App::closeEvent(QCloseEvent *event)
0170 {
0171     endGame();
0172     saveProperties();
0173     KXmlGuiWindow::closeEvent(event);
0174 }
0175 
0176 // Retrieve a theme file name from the menu index number
0177 QString KWin4App::themefileFromIdx(int idx)
0178 {
0179     QStringList list(mThemeFiles.keys());
0180     list.sort();
0181     QString themeFile = mThemeFiles[list.at(idx)];
0182     return themeFile;
0183 }
0184 
0185 // Retrieve a theme idx from a theme name
0186 int KWin4App::themeIdxFromName(const QString &name)
0187 {
0188     QStringList list(mThemeFiles.keys());
0189     list.sort();
0190     for (int i = 0; i < list.size(); ++i) {
0191         if (list[i] == name)
0192             return i;
0193     }
0194     qCCritical(KFOURINLINE_LOG) << "Theme index lookup failed for " << name;
0195     return 0;
0196 }
0197 
0198 // This method is called from various places
0199 // and signals to check, uncheck and enable
0200 // or disable all menu items.
0201 // The menu parameter can limit this operation
0202 // to one or more of the main menus (File,View,...)
0203 void KWin4App::checkMenus(CheckFlags menu)
0204 {
0205     bool localgame = (!mDoc->isNetwork());
0206     bool isRunning = (mDoc->gameStatus() == KGame::Run);
0207 
0208     // Check file menu
0209     if (!menu || (menu & CheckFileMenu)) {
0210         changeAction("move_hint", !(!isRunning && localgame));
0211         changeAction("game_new", !isRunning);
0212         changeAction("game_save", isRunning);
0213         changeAction("game_end", isRunning);
0214     }
0215 
0216     // Edit menu
0217     if (!menu || (menu & CheckEditMenu)) {
0218         if (!isRunning || !localgame) {
0219             disableAction("move_undo");
0220         } else if (mDoc->getHistoryCnt() == 0) {
0221             disableAction("move_undo");
0222         } else if (mDoc->getCurrentMove() < 1) {
0223             disableAction("move_undo");
0224         } else {
0225             enableAction("move_undo");
0226         }
0227 
0228         // Show redo
0229         if (!isRunning || !localgame) {
0230             disableAction("move_redo");
0231         } else if (mDoc->getHistoryCnt() == mDoc->getMaxMove()) {
0232             disableAction("move_redo");
0233         } else {
0234             enableAction("move_redo");
0235         }
0236     }
0237 
0238     // Disable some menus in demo mode
0239     if (global_demo_mode) {
0240         disableAction(KStandardAction::name(KStandardAction::Preferences));
0241         disableAction("move_undo");
0242         disableAction("move_redo");
0243         disableAction("game_new");
0244         disableAction("game_end");
0245         disableAction("game_save");
0246         disableAction("game_open");
0247         disableAction("network_conf");
0248         disableAction("network_chat");
0249         disableAction("statistics");
0250         disableAction("move_hint");
0251     }
0252 }
0253 
0254 // Create the actions for the menu. This works together with the xml guirc file
0255 void KWin4App::initGUI()
0256 {
0257     QAction *action;
0258 
0259     // Game
0260     KStandardGameAction::gameNew(this, &KWin4App::menuNewGame, actionCollection());
0261     KStandardGameAction::load(this, &KWin4App::menuOpenGame, actionCollection());
0262     KStandardGameAction::save(this, &KWin4App::menuSaveGame, actionCollection());
0263     action = KStandardGameAction::end(this, &KWin4App::endGame, actionCollection());
0264     action->setWhatsThis(i18n("Ends a currently played game. No winner will be declared."));
0265     KStandardGameAction::hint(this, &KWin4App::askForHint, actionCollection());
0266     KStandardGameAction::quit(this, &KWin4App::close, actionCollection());
0267 
0268     action = actionCollection()->addAction(QStringLiteral("network_conf"));
0269     action->setText(i18n("&Network Configuration..."));
0270     connect(action, &QAction::triggered, this, &KWin4App::configureNetwork);
0271 
0272     action = actionCollection()->addAction(QStringLiteral("network_chat"));
0273     action->setText(i18n("Network Chat..."));
0274     connect(action, &QAction::triggered, this, &KWin4App::configureChat);
0275 
0276     action = actionCollection()->addAction(QStringLiteral("statistics"));
0277     action->setIcon(QIcon::fromTheme(QStringLiteral("view-statistics")));
0278     action->setText(i18n("&Show Statistics"));
0279     connect(action, &QAction::triggered, this, &KWin4App::showStatistics);
0280     action->setToolTip(i18n("Show statistics."));
0281 
0282     // Move
0283     KStandardGameAction::undo(this, &KWin4App::undoMove, actionCollection());
0284     KStandardGameAction::redo(this, &KWin4App::redoMove, actionCollection());
0285 
0286     KStandardAction::preferences(this, &KWin4App::configureSettings, actionCollection());
0287 
0288     // Add all theme files to the menu
0289     QStringList themes(mThemeFiles.keys());
0290     themes.sort();
0291 
0292     KSelectAction *themeAction = new KSelectAction(i18n("Theme"), this);
0293     actionCollection()->addAction(QStringLiteral("theme"), themeAction);
0294     themeAction->setIcon(QIcon::fromTheme(QStringLiteral("games-config-theme")));
0295     themeAction->setItems(themes);
0296     connect(themeAction, &KSelectAction::indexTriggered, this, &KWin4App::changeTheme);
0297     qCDebug(KFOURINLINE_LOG) << "Setting current theme item to" << mThemeIndexNo;
0298     themeAction->setCurrentItem(mThemeIndexNo);
0299 
0300     // Debug
0301     if (global_debug > 0) {
0302         action = actionCollection()->addAction(QStringLiteral("file_debug"));
0303         action->setText(i18n("Debug KGame"));
0304         connect(action, &QAction::triggered, this, &KWin4App::debugKGame);
0305     }
0306 }
0307 
0308 // Change the theme of the game
0309 void KWin4App::changeTheme(int idx)
0310 {
0311     mThemeIndexNo = idx;
0312     QString themeFile = themefileFromIdx(idx);
0313     qCDebug(KFOURINLINE_LOG) << "Select theme" << themeFile;
0314     mTheme->updateTheme(themeFile);
0315     updateStatusNames();
0316 }
0317 
0318 // Create the status bar with the message part, the player part.
0319 void KWin4App::initStatusBar()
0320 {
0321     mStatusMsg = new QLabel();
0322     mStatusMover = new QLabel();
0323     statusBar()->addWidget(mStatusMsg);
0324     statusBar()->addPermanentWidget(mStatusMover);
0325 
0326     displayStatusMessage(i18n("Welcome to Four Wins"));
0327 }
0328 
0329 // Set up the document, i.e. the KGame object
0330 // and connect all signals emitted by it
0331 void KWin4App::connectDocument()
0332 {
0333     // KGame signals
0334     connect(mDoc, &KWin4Doc::signalGameOver, this, &KWin4App::slotGameOver);
0335     connect(mDoc, &KWin4Doc::signalNextPlayer, this, &KWin4App::moveDone);
0336     connect(mDoc, &KWin4Doc::signalClientLeftGame, this, &KWin4App::networkBroken);
0337     connect(mDoc, &KWin4Doc::signalGameRun, this, &KWin4App::gameRun);
0338 }
0339 
0340 // Enable or disable an action
0341 void KWin4App::changeAction(const char *action, bool enable)
0342 {
0343     if (!action) {
0344         return;
0345     }
0346 
0347     QAction *act = actionCollection()->action(QLatin1String(action));
0348     if (act) {
0349         act->setEnabled(enable);
0350     }
0351 }
0352 
0353 // Save instance-specific properties. The function is
0354 void KWin4App::saveProperties(KConfigGroup &grp)
0355 {
0356     qCDebug(KFOURINLINE_LOG) << "SAVE PROPERTIES for GROUP" << grp.name();
0357 
0358     // Save current game?
0359     QString name = QStringLiteral("current_game") + grp.name();
0360     QString filename = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + name;
0361     bool isRunning = (mDoc->gameStatus() == KGame::Run);
0362     if (isRunning) {
0363         qCDebug(KFOURINLINE_LOG) << "Saving" << filename;
0364         mDoc->save(filename);
0365         grp.writeEntry("CurrentGame", filename);
0366     } else {
0367         QFile file(filename);
0368         qCDebug(KFOURINLINE_LOG) << "Deleting" << file.fileName();
0369         file.remove();
0370         grp.deleteEntry("CurrentGame");
0371     }
0372 }
0373 
0374 // Read instance-specific properties.
0375 void KWin4App::readProperties(const KConfigGroup &grp)
0376 {
0377     qCDebug(KFOURINLINE_LOG) << "READ PROPERTIES for GROUP" << grp.name();
0378 
0379     QString filename = grp.readEntry("CurrentGame", QString());
0380     qCDebug(KFOURINLINE_LOG) << "Filename is" << filename;
0381 
0382     if (!filename.isNull() && QFile::exists(filename)) {
0383         qCDebug(KFOURINLINE_LOG) << "Loading" << filename;
0384         // TODO: CRASHES mDoc->load(filename);
0385         qCDebug(KFOURINLINE_LOG) << "Loading" << filename << "done";
0386     }
0387 }
0388 
0389 // Store the current game
0390 void KWin4App::saveProperties()
0391 {
0392     KConfig *config = KSharedConfig::openConfig().data();
0393 
0394     // Program data
0395     KConfigGroup cfg = config->group("ProgramData");
0396     cfg.writeEntry("ThemeIndexNo", mThemeIndexNo);
0397 
0398     mDoc->writeConfig(config);
0399 
0400     config->sync();
0401     qCDebug(KFOURINLINE_LOG) << "SAVED PROPERTIES";
0402 }
0403 
0404 // Load current game back
0405 void KWin4App::readProperties()
0406 {
0407     KConfig *config = KSharedConfig::openConfig().data();
0408 
0409     // Program data
0410     KConfigGroup cfg = config->group("ProgramData");
0411     mThemeIndexNo = cfg.readEntry("ThemeIndexNo", themeIdxFromName(mThemeDefault));
0412     if (mThemeIndexNo >= mThemeFiles.size())
0413         mThemeIndexNo = 0;
0414     qCDebug(KFOURINLINE_LOG) << "Index = " << mThemeIndexNo << " def index=" << themeIdxFromName(mThemeDefault);
0415 
0416     qCDebug(KFOURINLINE_LOG) << "LOADED PROPERTIES";
0417 }
0418 
0419 // Load a game menu
0420 void KWin4App::menuOpenGame()
0421 {
0422     const QString file = (global_debug < 1) ? QFileDialog::getOpenFileName(this) : QStringLiteral("/tmp/kwin.save");
0423     mDoc->load(file, true);
0424     checkMenus();
0425 }
0426 
0427 // Save game menu
0428 void KWin4App::menuSaveGame()
0429 {
0430     const QString file = (global_debug < 1) ? QFileDialog::getSaveFileName(this) : QStringLiteral("/tmp/kwin.save");
0431     mDoc->save(file);
0432 }
0433 
0434 // Received quick start command from view
0435 void KWin4App::quickStart(COLOUR startPlayer, KGameIO::IOMode input0, KGameIO::IOMode input1, int level)
0436 {
0437     if (startPlayer == Yellow) {
0438         Prefs::setStartcolourred(false);
0439         Prefs::setStartcolouryellow(true);
0440     } else if (startPlayer == Red) {
0441         Prefs::setStartcolourred(true);
0442         Prefs::setStartcolouryellow(false);
0443     }
0444     if (level >= 0) {
0445         Prefs::setLevel(level);
0446     }
0447     if (input0 == KGameIO::MouseIO) {
0448         Prefs::setInput0mouse(true);
0449         Prefs::setInput0key(false);
0450         Prefs::setInput0ai(false);
0451     }
0452     if (input0 == KGameIO::ProcessIO) {
0453         Prefs::setInput0mouse(false);
0454         Prefs::setInput0key(false);
0455         Prefs::setInput0ai(true);
0456     }
0457     if (input1 == KGameIO::MouseIO) {
0458         Prefs::setInput1mouse(true);
0459         Prefs::setInput1key(false);
0460         Prefs::setInput1ai(false);
0461     }
0462     if (input1 == KGameIO::ProcessIO) {
0463         Prefs::setInput1mouse(false);
0464         Prefs::setInput1key(false);
0465         Prefs::setInput1ai(true);
0466     }
0467 
0468     // Reload settings
0469     mDoc->loadSettings();
0470 
0471     // Start game (direct call will crash as intro object will be deleted)
0472     QTimer::singleShot(0, this, &KWin4App::menuNewGame);
0473 }
0474 
0475 // Start a new game menu
0476 void KWin4App::menuNewGame()
0477 {
0478     qCDebug(KFOURINLINE_LOG) << "MENU NEW GAME";
0479     // End the intro if it is running
0480     mDoc->setGameStatus(KWin4Doc::End);
0481     // Init the board and Clear the old game out
0482     mDoc->setGameStatus(KWin4Doc::Init);
0483     // Run it
0484     mDoc->setGameStatus(KWin4Doc::Run);
0485     // Display game status
0486     displayStatusMessage(i18n("Game running..."));
0487 }
0488 
0489 // Slot: Noticed that a new game started...update menus
0490 void KWin4App::gameRun()
0491 {
0492     updateStatusNames();
0493     checkMenus(All);
0494 }
0495 
0496 // Abort a running game
0497 void KWin4App::endGame()
0498 {
0499     mDoc->setGameStatus(KWin4Doc::Abort);
0500 }
0501 
0502 // Menu to ask for a game hint
0503 void KWin4App::askForHint()
0504 {
0505     if (mDoc)
0506         mDoc->calculateHint();
0507 }
0508 
0509 // Show statistics dialog
0510 void KWin4App::showStatistics()
0511 {
0512     QPointer<QDialog> dlg = new QDialog(this);
0513     Ui::Statistics ui;
0514     ui.setupUi(dlg);
0515 
0516     ui.p1_name->setText(mDoc->getName(Yellow));
0517     ui.p1_won->display(mDoc->getStatistic(Yellow, TWin));
0518     ui.p1_drawn->display(mDoc->getStatistic(Yellow, TRemis));
0519     ui.p1_lost->display(mDoc->getStatistic(Yellow, TLost));
0520     ui.p1_aborted->display(mDoc->getStatistic(Yellow, TBrk));
0521     ui.p1_sum->display(mDoc->getStatistic(Yellow, TSum));
0522 
0523     ui.p2_name->setText(mDoc->getName(Red));
0524     ui.p2_won->display(mDoc->getStatistic(Red, TWin));
0525     ui.p2_drawn->display(mDoc->getStatistic(Red, TRemis));
0526     ui.p2_lost->display(mDoc->getStatistic(Red, TLost));
0527     ui.p2_aborted->display(mDoc->getStatistic(Red, TBrk));
0528     ui.p2_sum->display(mDoc->getStatistic(Red, TSum));
0529 
0530     if (dlg->exec() == QDialog::Rejected) {
0531         mDoc->resetStatistic();
0532     }
0533     delete dlg;
0534 }
0535 
0536 // Undo menu call
0537 void KWin4App::undoMove()
0538 {
0539     mDoc->undoMove();
0540     // Undo twice if computer is moving to keep player as input
0541     if (mDoc->playedBy(mDoc->getCurrentPlayer()) == KGameIO::ProcessIO) {
0542         mDoc->undoMove();
0543     } else {
0544         // Make sure the current player has the turn
0545         // without this it can happen that the AI still think has the turn and plays
0546         // instead of the human player
0547         mDoc->getPlayer(mDoc->getCurrentPlayer())->setTurn(true);
0548     }
0549 
0550     // Refresh menus
0551     updateStatusNames();
0552     checkMenus(CheckEditMenu);
0553 }
0554 
0555 // Redo menu call
0556 void KWin4App::redoMove()
0557 {
0558     mDoc->redoMove();
0559     // Redo twice if computer is moving to keep player as input
0560     if (mDoc->playedBy(mDoc->getCurrentPlayer()) == KGameIO::ProcessIO) {
0561         mDoc->redoMove();
0562     }
0563     updateStatusNames();
0564     checkMenus(CheckEditMenu);
0565 }
0566 
0567 // Set the given text into the statusbar change status message permanently
0568 void KWin4App::displayStatusMessage(const QString &text)
0569 {
0570     mStatusMsg->setText(text);
0571 }
0572 
0573 // Set the string in the statusbar window for
0574 // the player currently moving change status mover permanently
0575 void KWin4App::displayStatusbarMover(const QString &text)
0576 {
0577     mStatusMover->setText(text);
0578 }
0579 
0580 // Ends the current game.
0581 // Called by the gameover signal
0582 void KWin4App::EndGame(TABLE mode)
0583 {
0584     mDoc->endGame(mode);
0585     mDoc->switchStartPlayer();
0586     updateStatusNames();
0587     checkMenus();
0588 
0589     // Automatically restart game in demo mode
0590     if (global_demo_mode) {
0591         QTimer::singleShot(10000, this, &KWin4App::menuNewGame);
0592     }
0593 }
0594 
0595 // Set the names in the mover field
0596 void KWin4App::updateStatusNames()
0597 {
0598     QString msg;
0599     if (!(mDoc->gameStatus() == KGame::Run))
0600         msg = i18n("No game  ");
0601     else if (mDoc->getCurrentPlayer() == Yellow)
0602         msg = i18n(" %1 - %2 ", mDoc->getName(Yellow), mTheme->colorNamePlayer(0));
0603     else if (mDoc->getCurrentPlayer())
0604         msg = i18n(" %1 - %2 ", mDoc->getName(Red), mTheme->colorNamePlayer(1));
0605     else
0606         msg = i18n("Nobody  ");
0607     displayStatusbarMover(msg);
0608 }
0609 
0610 // Notification that the network connection is lost.
0611 void KWin4App::networkBroken(int /*id*/, int oldstatus, KGame * /*game */)
0612 {
0613     qCDebug(KFOURINLINE_LOG) << "KWin4App::networkBroken(" << oldstatus << ")";
0614 
0615     // Set all input devices back to default
0616     if (mDoc->playedBy(Yellow) == 0)
0617         mDoc->setPlayedBy(Yellow, KGameIO::MouseIO);
0618     if (mDoc->playedBy(Red) == 0)
0619         mDoc->setPlayedBy(Red, KGameIO::MouseIO);
0620 
0621     qCDebug(KFOURINLINE_LOG) << "CurrrentPlayer=" << mDoc->getCurrentPlayer();
0622     qCDebug(KFOURINLINE_LOG) << "   " << mDoc->getPlayer(mDoc->getCurrentPlayer());
0623 
0624     // Activate input device
0625     mDoc->getPlayer(mDoc->getCurrentPlayer())->setTurn(true, true);
0626 
0627     // Issue message
0628     KMessageBox::information(this, i18n("The network game ended!\n"));
0629 
0630     // Restore status
0631     mDoc->setGameStatus(oldstatus);
0632 }
0633 
0634 // A move is done. Update status display.
0635 void KWin4App::moveDone(int /*playerNumber*/)
0636 {
0637     checkMenus(CheckEditMenu);
0638     updateStatusNames();
0639     displayStatusMessage(i18n("Game running..."));
0640 }
0641 
0642 // The game is over or aborted. Set status and display it.
0643 void KWin4App::slotGameOver(int status, KPlayer *p, KGame * /*me*/)
0644 {
0645     qCDebug(KFOURINLINE_LOG) << "KWin4App::slotGameOver";
0646     if (status == -1) // remis
0647     {
0648         EndGame(TRemis);
0649         displayStatusMessage(i18n("The game is drawn. Please restart next round."));
0650     } else if (status == 1) // One of the players won
0651     {
0652         if (p->userId() == Yellow)
0653             EndGame(TWin);
0654         else
0655             EndGame(TLost);
0656         QString msg = i18n("%1 won the game. Please restart next round.", mDoc->getName(((COLOUR)p->userId())));
0657         displayStatusMessage(msg);
0658     } else if (status == 2) // Abort
0659     {
0660         EndGame(TBrk);
0661         QString m = i18n(" Game ended. Please restart next round.");
0662         displayStatusMessage(m);
0663     } else {
0664         qCCritical(KFOURINLINE_LOG) << "Gameover with status" << status << ". This is unexpected and a serious problem";
0665     }
0666     checkMenus(CheckEditMenu);
0667 }
0668 
0669 // Show the network configuration dialog
0670 void KWin4App::configureNetwork()
0671 {
0672     if (mDoc->gameStatus() == KWin4Doc::Intro) {
0673         mDoc->setGameStatus(KWin4Doc::Pause);
0674     }
0675 
0676     QString host = Prefs::host();
0677     int port = Prefs::port();
0678 
0679     // just for testing - should be non-modal
0680     KGameDialog dlg(mDoc, nullptr, i18n("Network Configuration"), this);
0681     dlg.networkConfig()->setDefaultNetworkInfo(host, port);
0682     dlg.networkConfig()->setDiscoveryInfo(QStringLiteral("_kfourinline._tcp"), Prefs::gamename());
0683 
0684     QWidget *box = dlg.configPage();
0685     QLayout *l = box->layout();
0686 
0687     mColorGroup = new QGroupBox(box);
0688     QVBoxLayout *grouplay = new QVBoxLayout(mColorGroup);
0689     connect(dlg.networkConfig(), &KGameDialogNetworkConfig::signalServerTypeChanged, this, &KWin4App::serverTypeChanged);
0690 
0691     QRadioButton *b1 = new QRadioButton(i18n("Black should be played by remote player"), mColorGroup);
0692     QRadioButton *b2 = new QRadioButton(i18n("Red should be played by remote player"), mColorGroup);
0693     grouplay->addWidget(b1);
0694     grouplay->addWidget(b2);
0695     l->addWidget(mColorGroup);
0696     b1->setChecked(true);
0697     remoteChanged(0);
0698 
0699     connect(b1, &QAbstractButton::toggled, this, [this](bool toggled) {
0700         if (toggled)
0701             remoteChanged(0);
0702     });
0703     connect(b2, &QAbstractButton::toggled, this, [this](bool toggled) {
0704         if (toggled)
0705             remoteChanged(1);
0706     });
0707 
0708     dlg.adjustSize();
0709     dlg.exec(); // note: we don't have to check for the result - maybe a bug
0710 }
0711 
0712 // Can't get rid of this function in KGame's current state.
0713 // Can't pass a int signal to a bool slot, so this must be here
0714 void KWin4App::serverTypeChanged(int t)
0715 {
0716     mColorGroup->setDisabled(t);
0717 }
0718 
0719 // The remote player in the network dialog has changed. Adapt priorities.
0720 void KWin4App::remoteChanged(int button)
0721 {
0722     if (button == 0) {
0723         mDoc->getPlayer(Yellow)->setNetworkPriority(0);
0724         mDoc->getPlayer(Red)->setNetworkPriority(10);
0725     } else {
0726         mDoc->getPlayer(Yellow)->setNetworkPriority(10);
0727         mDoc->getPlayer(Red)->setNetworkPriority(0);
0728     }
0729 }
0730 
0731 // Show the chat dialog.
0732 void KWin4App::configureChat()
0733 {
0734     if (!mMyChatDlg) {
0735         mMyChatDlg = new ChatDlg(mDoc, this);
0736         KWin4Player *p = mDoc->getPlayer(Yellow);
0737         if (!p->isVirtual())
0738             mMyChatDlg->setPlayer(mDoc->getPlayer(Yellow));
0739         else
0740             mMyChatDlg->setPlayer(mDoc->getPlayer(Red));
0741         connect(mDoc, &KWin4Doc::signalChatChanged, mMyChatDlg, &ChatDlg::setPlayer);
0742     }
0743 
0744     if (mMyChatDlg->isHidden())
0745         mMyChatDlg->show();
0746     else
0747         mMyChatDlg->hide();
0748 }
0749 
0750 // Show the KGame debug window.
0751 void KWin4App::debugKGame()
0752 {
0753     KGameDebugDialog *debugWindow = new KGameDebugDialog(mDoc, this);
0754     debugWindow->show();
0755 }
0756 
0757 // Show Configure dialog.
0758 void KWin4App::configureSettings()
0759 {
0760     static Ui::Settings ui; // Dialog is internally static anyway
0761     if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
0762         // The dialog need to refresh the buttons as they are not connectable via a signal-slot
0763         // in KConfigDialog
0764         ui.kcfg_startcolourred->setChecked(Prefs::startcolourred());
0765         ui.kcfg_startcolourred->setText(mTheme->colorNamePlayer(0));
0766         ui.kcfg_startcolouryellow->setChecked(Prefs::startcolouryellow());
0767         ui.kcfg_startcolouryellow->setText(mTheme->colorNamePlayer(1));
0768         ui.kcfg_level->setValue(Prefs::level());
0769         ui.Input0->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(0)));
0770         ui.Input1->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(1)));
0771         ui.kcfg_input0mouse->setChecked(Prefs::input0mouse());
0772         ui.kcfg_input0key->setChecked(Prefs::input0key());
0773         ui.kcfg_input0ai->setChecked(Prefs::input0ai());
0774         ui.kcfg_input1mouse->setChecked(Prefs::input1mouse());
0775         ui.kcfg_input1key->setChecked(Prefs::input1key());
0776         ui.kcfg_input1ai->setChecked(Prefs::input1ai());
0777 
0778         return;
0779     }
0780 
0781     KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Prefs::self());
0782     dialog->setFaceType(KPageDialog::Plain);
0783     dialog->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Help);
0784     dialog->button(QDialogButtonBox::Ok)->setDefault(true);
0785     dialog->setModal(true);
0786     // QT5 dialog->setHelp(QString(),"kfourinline");
0787     QWidget *frame = new QWidget(dialog);
0788     ui.setupUi(frame);
0789     ui.kcfg_startcolourred->setText(mTheme->colorNamePlayer(0));
0790     ui.kcfg_startcolouryellow->setText(mTheme->colorNamePlayer(1));
0791     ui.Input0->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(0)));
0792     ui.Input1->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(1)));
0793     dialog->addPage(frame, i18n("General"), QStringLiteral("games-config-options"));
0794     connect(dialog, &KConfigDialog::settingsChanged, mDoc, &KWin4Doc::loadSettings);
0795     dialog->show();
0796 }
0797 
0798 #include "moc_kwin4.cpp"