File indexing completed on 2024-12-01 03:46:42

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