File indexing completed on 2024-04-28 07:51:35

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 <KGameStandardAction>
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({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, QStringLiteral("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(KGameStandardAction::name(KGameStandardAction::Hint), !(!isRunning && localgame));
0211         changeAction(KGameStandardAction::name(KGameStandardAction::New), !isRunning);
0212         changeAction(KGameStandardAction::name(KGameStandardAction::Save), isRunning);
0213         changeAction(KGameStandardAction::name(KGameStandardAction::End), isRunning);
0214     }
0215 
0216     // Edit menu
0217     if (!menu || (menu & CheckEditMenu)) {
0218         const QString moveUndoActionId = KGameStandardAction::name(KGameStandardAction::Undo);
0219         if (!isRunning || !localgame) {
0220             disableAction(moveUndoActionId);
0221         } else if (mDoc->getHistoryCnt() == 0) {
0222             disableAction(moveUndoActionId);
0223         } else if (mDoc->getCurrentMove() < 1) {
0224             disableAction(moveUndoActionId);
0225         } else {
0226             enableAction(moveUndoActionId);
0227         }
0228 
0229         // Show redo
0230         const QString moveRedoActionId = KGameStandardAction::name(KGameStandardAction::Redo);
0231         if (!isRunning || !localgame) {
0232             disableAction(moveRedoActionId);
0233         } else if (mDoc->getHistoryCnt() == mDoc->getMaxMove()) {
0234             disableAction(moveRedoActionId);
0235         } else {
0236             enableAction(moveRedoActionId);
0237         }
0238     }
0239 
0240     // Disable some menus in demo mode
0241     if (global_demo_mode) {
0242         disableAction(KStandardAction::name(KStandardAction::Preferences));
0243         disableAction(KGameStandardAction::name(KGameStandardAction::Undo));
0244         disableAction(KGameStandardAction::name(KGameStandardAction::Redo));
0245         disableAction(KGameStandardAction::name(KGameStandardAction::New));
0246         disableAction(KGameStandardAction::name(KGameStandardAction::End));
0247         disableAction(KGameStandardAction::name(KGameStandardAction::Save));
0248         disableAction(KGameStandardAction::name(KGameStandardAction::Load));
0249         disableAction(QStringLiteral("network_conf"));
0250         disableAction(QStringLiteral("network_chat"));
0251         disableAction(QStringLiteral("statistics"));
0252         disableAction(KGameStandardAction::name(KGameStandardAction::Hint));
0253     }
0254 }
0255 
0256 // Create the actions for the menu. This works together with the xml guirc file
0257 void KWin4App::initGUI()
0258 {
0259     QAction *action;
0260 
0261     // Game
0262     KGameStandardAction::gameNew(this, &KWin4App::menuNewGame, actionCollection());
0263     KGameStandardAction::load(this, &KWin4App::menuOpenGame, actionCollection());
0264     KGameStandardAction::save(this, &KWin4App::menuSaveGame, actionCollection());
0265     action = KGameStandardAction::end(this, &KWin4App::endGame, actionCollection());
0266     action->setWhatsThis(i18n("Ends a currently played game. No winner will be declared."));
0267     KGameStandardAction::hint(this, &KWin4App::askForHint, actionCollection());
0268     KGameStandardAction::quit(this, &KWin4App::close, actionCollection());
0269 
0270     action = actionCollection()->addAction(QStringLiteral("network_conf"));
0271     action->setText(i18n("&Network Configuration..."));
0272     connect(action, &QAction::triggered, this, &KWin4App::configureNetwork);
0273 
0274     action = actionCollection()->addAction(QStringLiteral("network_chat"));
0275     action->setText(i18n("Network Chat..."));
0276     connect(action, &QAction::triggered, this, &KWin4App::configureChat);
0277 
0278     action = actionCollection()->addAction(QStringLiteral("statistics"));
0279     action->setIcon(QIcon::fromTheme(QStringLiteral("view-statistics")));
0280     action->setText(i18n("&Show Statistics"));
0281     connect(action, &QAction::triggered, this, &KWin4App::showStatistics);
0282     action->setToolTip(i18n("Show statistics."));
0283 
0284     // Move
0285     KGameStandardAction::undo(this, &KWin4App::undoMove, actionCollection());
0286     KGameStandardAction::redo(this, &KWin4App::redoMove, actionCollection());
0287 
0288     KStandardAction::preferences(this, &KWin4App::configureSettings, actionCollection());
0289 
0290     // Add all theme files to the menu
0291     QStringList themes(mThemeFiles.keys());
0292     themes.sort();
0293 
0294     KSelectAction *themeAction = new KSelectAction(i18n("Theme"), this);
0295     actionCollection()->addAction(QStringLiteral("theme"), themeAction);
0296     themeAction->setIcon(QIcon::fromTheme(QStringLiteral("games-config-theme")));
0297     themeAction->setItems(themes);
0298     connect(themeAction, &KSelectAction::indexTriggered, this, &KWin4App::changeTheme);
0299     qCDebug(KFOURINLINE_LOG) << "Setting current theme item to" << mThemeIndexNo;
0300     themeAction->setCurrentItem(mThemeIndexNo);
0301 
0302     // Debug
0303     if (global_debug > 0) {
0304         action = actionCollection()->addAction(QStringLiteral("file_debug"));
0305         action->setText(i18n("Debug KGame"));
0306         connect(action, &QAction::triggered, this, &KWin4App::debugKGame);
0307     }
0308 }
0309 
0310 // Change the theme of the game
0311 void KWin4App::changeTheme(int idx)
0312 {
0313     mThemeIndexNo = idx;
0314     QString themeFile = themefileFromIdx(idx);
0315     qCDebug(KFOURINLINE_LOG) << "Select theme" << themeFile;
0316     mTheme->updateTheme(themeFile);
0317     updateStatusNames();
0318 }
0319 
0320 // Create the status bar with the message part, the player part.
0321 void KWin4App::initStatusBar()
0322 {
0323     mStatusMsg = new QLabel();
0324     mStatusMover = new QLabel();
0325     statusBar()->addWidget(mStatusMsg);
0326     statusBar()->addPermanentWidget(mStatusMover);
0327 
0328     displayStatusMessage(i18n("Welcome to Four Wins"));
0329 }
0330 
0331 // Set up the document, i.e. the KGame object
0332 // and connect all signals emitted by it
0333 void KWin4App::connectDocument()
0334 {
0335     // KGame signals
0336     connect(mDoc, &KWin4Doc::signalGameOver, this, &KWin4App::slotGameOver);
0337     connect(mDoc, &KWin4Doc::signalNextPlayer, this, &KWin4App::moveDone);
0338     connect(mDoc, &KWin4Doc::signalClientLeftGame, this, &KWin4App::networkBroken);
0339     connect(mDoc, &KWin4Doc::signalGameRun, this, &KWin4App::gameRun);
0340 }
0341 
0342 // Enable or disable an action
0343 void KWin4App::changeAction(const QString &action, bool enable)
0344 {
0345     QAction *act = actionCollection()->action(action);
0346     if (act) {
0347         act->setEnabled(enable);
0348     }
0349 }
0350 
0351 // Save instance-specific properties. The function is
0352 void KWin4App::saveProperties(KConfigGroup &grp)
0353 {
0354     qCDebug(KFOURINLINE_LOG) << "SAVE PROPERTIES for GROUP" << grp.name();
0355 
0356     // Save current game?
0357     QString name = QStringLiteral("current_game") + grp.name();
0358     QString filename = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + name;
0359     bool isRunning = (mDoc->gameStatus() == KGame::Run);
0360     if (isRunning) {
0361         qCDebug(KFOURINLINE_LOG) << "Saving" << filename;
0362         mDoc->save(filename);
0363         grp.writeEntry("CurrentGame", filename);
0364     } else {
0365         QFile file(filename);
0366         qCDebug(KFOURINLINE_LOG) << "Deleting" << file.fileName();
0367         file.remove();
0368         grp.deleteEntry("CurrentGame");
0369     }
0370 }
0371 
0372 // Read instance-specific properties.
0373 void KWin4App::readProperties(const KConfigGroup &grp)
0374 {
0375     qCDebug(KFOURINLINE_LOG) << "READ PROPERTIES for GROUP" << grp.name();
0376 
0377     QString filename = grp.readEntry("CurrentGame", QString());
0378     qCDebug(KFOURINLINE_LOG) << "Filename is" << filename;
0379 
0380     if (!filename.isNull() && QFile::exists(filename)) {
0381         qCDebug(KFOURINLINE_LOG) << "Loading" << filename;
0382         // TODO: CRASHES mDoc->load(filename);
0383         qCDebug(KFOURINLINE_LOG) << "Loading" << filename << "done";
0384     }
0385 }
0386 
0387 // Store the current game
0388 void KWin4App::saveProperties()
0389 {
0390     KConfig *config = KSharedConfig::openConfig().data();
0391 
0392     // Program data
0393     KConfigGroup cfg = config->group(QStringLiteral("ProgramData"));
0394     cfg.writeEntry("ThemeIndexNo", mThemeIndexNo);
0395 
0396     mDoc->writeConfig(config);
0397 
0398     config->sync();
0399     qCDebug(KFOURINLINE_LOG) << "SAVED PROPERTIES";
0400 }
0401 
0402 // Load current game back
0403 void KWin4App::readProperties()
0404 {
0405     KConfig *config = KSharedConfig::openConfig().data();
0406 
0407     // Program data
0408     KConfigGroup cfg = config->group(QStringLiteral("ProgramData"));
0409     mThemeIndexNo = cfg.readEntry("ThemeIndexNo", themeIdxFromName(mThemeDefault));
0410     if (mThemeIndexNo >= mThemeFiles.size())
0411         mThemeIndexNo = 0;
0412     qCDebug(KFOURINLINE_LOG) << "Index = " << mThemeIndexNo << " def index=" << themeIdxFromName(mThemeDefault);
0413 
0414     qCDebug(KFOURINLINE_LOG) << "LOADED PROPERTIES";
0415 }
0416 
0417 // Load a game menu
0418 void KWin4App::menuOpenGame()
0419 {
0420     const QString file = (global_debug < 1) ? QFileDialog::getOpenFileName(this) : QStringLiteral("/tmp/kwin.save");
0421     mDoc->load(file, true);
0422     checkMenus();
0423 }
0424 
0425 // Save game menu
0426 void KWin4App::menuSaveGame()
0427 {
0428     const QString file = (global_debug < 1) ? QFileDialog::getSaveFileName(this) : QStringLiteral("/tmp/kwin.save");
0429     mDoc->save(file);
0430 }
0431 
0432 // Received quick start command from view
0433 void KWin4App::quickStart(COLOUR startPlayer, KGameIO::IOMode input0, KGameIO::IOMode input1, int level)
0434 {
0435     if (startPlayer == Yellow) {
0436         Prefs::setStartcolourred(false);
0437         Prefs::setStartcolouryellow(true);
0438     } else if (startPlayer == Red) {
0439         Prefs::setStartcolourred(true);
0440         Prefs::setStartcolouryellow(false);
0441     }
0442     if (level >= 0) {
0443         Prefs::setLevel(level);
0444     }
0445     if (input0 == KGameIO::MouseIO) {
0446         Prefs::setInput0mouse(true);
0447         Prefs::setInput0key(false);
0448         Prefs::setInput0ai(false);
0449     }
0450     if (input0 == KGameIO::ProcessIO) {
0451         Prefs::setInput0mouse(false);
0452         Prefs::setInput0key(false);
0453         Prefs::setInput0ai(true);
0454     }
0455     if (input1 == KGameIO::MouseIO) {
0456         Prefs::setInput1mouse(true);
0457         Prefs::setInput1key(false);
0458         Prefs::setInput1ai(false);
0459     }
0460     if (input1 == KGameIO::ProcessIO) {
0461         Prefs::setInput1mouse(false);
0462         Prefs::setInput1key(false);
0463         Prefs::setInput1ai(true);
0464     }
0465 
0466     // Reload settings
0467     mDoc->loadSettings();
0468 
0469     // Start game (direct call will crash as intro object will be deleted)
0470     QTimer::singleShot(0, this, &KWin4App::menuNewGame);
0471 }
0472 
0473 // Start a new game menu
0474 void KWin4App::menuNewGame()
0475 {
0476     qCDebug(KFOURINLINE_LOG) << "MENU NEW GAME";
0477     // End the intro if it is running
0478     mDoc->setGameStatus(KWin4Doc::End);
0479     // Init the board and Clear the old game out
0480     mDoc->setGameStatus(KWin4Doc::Init);
0481     // Run it
0482     mDoc->setGameStatus(KWin4Doc::Run);
0483     // Display game status
0484     displayStatusMessage(i18n("Game running..."));
0485 }
0486 
0487 // Slot: Noticed that a new game started...update menus
0488 void KWin4App::gameRun()
0489 {
0490     updateStatusNames();
0491     checkMenus(All);
0492 }
0493 
0494 // Abort a running game
0495 void KWin4App::endGame()
0496 {
0497     mDoc->setGameStatus(KWin4Doc::Abort);
0498 }
0499 
0500 // Menu to ask for a game hint
0501 void KWin4App::askForHint()
0502 {
0503     if (mDoc)
0504         mDoc->calculateHint();
0505 }
0506 
0507 // Show statistics dialog
0508 void KWin4App::showStatistics()
0509 {
0510     QPointer<QDialog> dlg = new QDialog(this);
0511     Ui::Statistics ui;
0512     ui.setupUi(dlg);
0513 
0514     ui.p1_name->setText(mDoc->getName(Yellow));
0515     ui.p1_won->display(mDoc->getStatistic(Yellow, TWin));
0516     ui.p1_drawn->display(mDoc->getStatistic(Yellow, TRemis));
0517     ui.p1_lost->display(mDoc->getStatistic(Yellow, TLost));
0518     ui.p1_aborted->display(mDoc->getStatistic(Yellow, TBrk));
0519     ui.p1_sum->display(mDoc->getStatistic(Yellow, TSum));
0520 
0521     ui.p2_name->setText(mDoc->getName(Red));
0522     ui.p2_won->display(mDoc->getStatistic(Red, TWin));
0523     ui.p2_drawn->display(mDoc->getStatistic(Red, TRemis));
0524     ui.p2_lost->display(mDoc->getStatistic(Red, TLost));
0525     ui.p2_aborted->display(mDoc->getStatistic(Red, TBrk));
0526     ui.p2_sum->display(mDoc->getStatistic(Red, TSum));
0527 
0528     if (dlg->exec() == QDialog::Rejected) {
0529         mDoc->resetStatistic();
0530     }
0531     delete dlg;
0532 }
0533 
0534 // Undo menu call
0535 void KWin4App::undoMove()
0536 {
0537     mDoc->undoMove();
0538     // Undo twice if computer is moving to keep player as input
0539     if (mDoc->playedBy(mDoc->getCurrentPlayer()) == KGameIO::ProcessIO) {
0540         mDoc->undoMove();
0541     } else {
0542         // Make sure the current player has the turn
0543         // without this it can happen that the AI still think has the turn and plays
0544         // instead of the human player
0545         mDoc->getPlayer(mDoc->getCurrentPlayer())->setTurn(true);
0546     }
0547 
0548     // Refresh menus
0549     updateStatusNames();
0550     checkMenus(CheckEditMenu);
0551 }
0552 
0553 // Redo menu call
0554 void KWin4App::redoMove()
0555 {
0556     mDoc->redoMove();
0557     // Redo twice if computer is moving to keep player as input
0558     if (mDoc->playedBy(mDoc->getCurrentPlayer()) == KGameIO::ProcessIO) {
0559         mDoc->redoMove();
0560     }
0561     updateStatusNames();
0562     checkMenus(CheckEditMenu);
0563 }
0564 
0565 // Set the given text into the statusbar change status message permanently
0566 void KWin4App::displayStatusMessage(const QString &text)
0567 {
0568     mStatusMsg->setText(text);
0569 }
0570 
0571 // Set the string in the statusbar window for
0572 // the player currently moving change status mover permanently
0573 void KWin4App::displayStatusbarMover(const QString &text)
0574 {
0575     mStatusMover->setText(text);
0576 }
0577 
0578 // Ends the current game.
0579 // Called by the gameover signal
0580 void KWin4App::EndGame(TABLE mode)
0581 {
0582     mDoc->endGame(mode);
0583     mDoc->switchStartPlayer();
0584     updateStatusNames();
0585     checkMenus();
0586 
0587     // Automatically restart game in demo mode
0588     if (global_demo_mode) {
0589         QTimer::singleShot(10000, this, &KWin4App::menuNewGame);
0590     }
0591 }
0592 
0593 // Set the names in the mover field
0594 void KWin4App::updateStatusNames()
0595 {
0596     QString msg;
0597     if (!(mDoc->gameStatus() == KGame::Run))
0598         msg = i18n("No game  ");
0599     else if (mDoc->getCurrentPlayer() == Yellow)
0600         msg = i18n(" %1 - %2 ", mDoc->getName(Yellow), mTheme->colorNamePlayer(0));
0601     else if (mDoc->getCurrentPlayer())
0602         msg = i18n(" %1 - %2 ", mDoc->getName(Red), mTheme->colorNamePlayer(1));
0603     else
0604         msg = i18n("Nobody  ");
0605     displayStatusbarMover(msg);
0606 }
0607 
0608 // Notification that the network connection is lost.
0609 void KWin4App::networkBroken(int /*id*/, int oldstatus, KGame * /*game */)
0610 {
0611     qCDebug(KFOURINLINE_LOG) << "KWin4App::networkBroken(" << oldstatus << ")";
0612 
0613     // Set all input devices back to default
0614     if (mDoc->playedBy(Yellow) == 0)
0615         mDoc->setPlayedBy(Yellow, KGameIO::MouseIO);
0616     if (mDoc->playedBy(Red) == 0)
0617         mDoc->setPlayedBy(Red, KGameIO::MouseIO);
0618 
0619     qCDebug(KFOURINLINE_LOG) << "CurrrentPlayer=" << mDoc->getCurrentPlayer();
0620     qCDebug(KFOURINLINE_LOG) << "   " << mDoc->getPlayer(mDoc->getCurrentPlayer());
0621 
0622     // Activate input device
0623     mDoc->getPlayer(mDoc->getCurrentPlayer())->setTurn(true, true);
0624 
0625     // Issue message
0626     KMessageBox::information(this, i18n("The network game ended!\n"));
0627 
0628     // Restore status
0629     mDoc->setGameStatus(oldstatus);
0630 }
0631 
0632 // A move is done. Update status display.
0633 void KWin4App::moveDone(int /*playerNumber*/)
0634 {
0635     checkMenus(CheckEditMenu);
0636     updateStatusNames();
0637     displayStatusMessage(i18n("Game running..."));
0638 }
0639 
0640 // The game is over or aborted. Set status and display it.
0641 void KWin4App::slotGameOver(int status, KPlayer *p, KGame * /*me*/)
0642 {
0643     qCDebug(KFOURINLINE_LOG) << "KWin4App::slotGameOver";
0644     if (status == -1) // remis
0645     {
0646         EndGame(TRemis);
0647         displayStatusMessage(i18n("The game is drawn. Please restart next round."));
0648     } else if (status == 1) // One of the players won
0649     {
0650         if (p->userId() == Yellow)
0651             EndGame(TWin);
0652         else
0653             EndGame(TLost);
0654         QString msg = i18n("%1 won the game. Please restart next round.", mDoc->getName(((COLOUR)p->userId())));
0655         displayStatusMessage(msg);
0656     } else if (status == 2) // Abort
0657     {
0658         EndGame(TBrk);
0659         QString m = i18n(" Game ended. Please restart next round.");
0660         displayStatusMessage(m);
0661     } else {
0662         qCCritical(KFOURINLINE_LOG) << "Gameover with status" << status << ". This is unexpected and a serious problem";
0663     }
0664     checkMenus(CheckEditMenu);
0665 }
0666 
0667 // Show the network configuration dialog
0668 void KWin4App::configureNetwork()
0669 {
0670     if (mDoc->gameStatus() == KWin4Doc::Intro) {
0671         mDoc->setGameStatus(KWin4Doc::Pause);
0672     }
0673 
0674     QString host = Prefs::host();
0675     int port = Prefs::port();
0676 
0677     // just for testing - should be non-modal
0678     KGameDialog dlg(mDoc, nullptr, i18n("Network Configuration"), this);
0679     dlg.networkConfig()->setDefaultNetworkInfo(host, port);
0680     dlg.networkConfig()->setDiscoveryInfo(QStringLiteral("_kfourinline._tcp"), Prefs::gamename());
0681 
0682     QWidget *box = dlg.configPage();
0683     QLayout *l = box->layout();
0684 
0685     mColorGroup = new QGroupBox(box);
0686     QVBoxLayout *grouplay = new QVBoxLayout(mColorGroup);
0687     connect(dlg.networkConfig(), &KGameDialogNetworkConfig::signalServerTypeChanged, this, &KWin4App::serverTypeChanged);
0688 
0689     QRadioButton *b1 = new QRadioButton(i18n("Black should be played by remote player"), mColorGroup);
0690     QRadioButton *b2 = new QRadioButton(i18n("Red should be played by remote player"), mColorGroup);
0691     grouplay->addWidget(b1);
0692     grouplay->addWidget(b2);
0693     l->addWidget(mColorGroup);
0694     b1->setChecked(true);
0695     remoteChanged(0);
0696 
0697     connect(b1, &QAbstractButton::toggled, this, [this](bool toggled) {
0698         if (toggled)
0699             remoteChanged(0);
0700     });
0701     connect(b2, &QAbstractButton::toggled, this, [this](bool toggled) {
0702         if (toggled)
0703             remoteChanged(1);
0704     });
0705 
0706     dlg.adjustSize();
0707     dlg.exec(); // note: we don't have to check for the result - maybe a bug
0708 }
0709 
0710 // Can't get rid of this function in KGame's current state.
0711 // Can't pass a int signal to a bool slot, so this must be here
0712 void KWin4App::serverTypeChanged(int t)
0713 {
0714     mColorGroup->setDisabled(t);
0715 }
0716 
0717 // The remote player in the network dialog has changed. Adapt priorities.
0718 void KWin4App::remoteChanged(int button)
0719 {
0720     if (button == 0) {
0721         mDoc->getPlayer(Yellow)->setNetworkPriority(0);
0722         mDoc->getPlayer(Red)->setNetworkPriority(10);
0723     } else {
0724         mDoc->getPlayer(Yellow)->setNetworkPriority(10);
0725         mDoc->getPlayer(Red)->setNetworkPriority(0);
0726     }
0727 }
0728 
0729 // Show the chat dialog.
0730 void KWin4App::configureChat()
0731 {
0732     if (!mMyChatDlg) {
0733         mMyChatDlg = new ChatDlg(mDoc, this);
0734         KWin4Player *p = mDoc->getPlayer(Yellow);
0735         if (!p->isVirtual())
0736             mMyChatDlg->setPlayer(mDoc->getPlayer(Yellow));
0737         else
0738             mMyChatDlg->setPlayer(mDoc->getPlayer(Red));
0739         connect(mDoc, &KWin4Doc::signalChatChanged, mMyChatDlg, &ChatDlg::setPlayer);
0740     }
0741 
0742     if (mMyChatDlg->isHidden())
0743         mMyChatDlg->show();
0744     else
0745         mMyChatDlg->hide();
0746 }
0747 
0748 // Show the KGame debug window.
0749 void KWin4App::debugKGame()
0750 {
0751     KGameDebugDialog *debugWindow = new KGameDebugDialog(mDoc, this);
0752     debugWindow->show();
0753 }
0754 
0755 // Show Configure dialog.
0756 void KWin4App::configureSettings()
0757 {
0758     static Ui::Settings ui; // Dialog is internally static anyway
0759     if (KConfigDialog::showDialog(QStringLiteral("settings"))) {
0760         // The dialog need to refresh the buttons as they are not connectable via a signal-slot
0761         // in KConfigDialog
0762         ui.kcfg_startcolourred->setChecked(Prefs::startcolourred());
0763         ui.kcfg_startcolourred->setText(mTheme->colorNamePlayer(0));
0764         ui.kcfg_startcolouryellow->setChecked(Prefs::startcolouryellow());
0765         ui.kcfg_startcolouryellow->setText(mTheme->colorNamePlayer(1));
0766         ui.kcfg_level->setValue(Prefs::level());
0767         ui.Input0->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(0)));
0768         ui.Input1->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(1)));
0769         ui.kcfg_input0mouse->setChecked(Prefs::input0mouse());
0770         ui.kcfg_input0key->setChecked(Prefs::input0key());
0771         ui.kcfg_input0ai->setChecked(Prefs::input0ai());
0772         ui.kcfg_input1mouse->setChecked(Prefs::input1mouse());
0773         ui.kcfg_input1key->setChecked(Prefs::input1key());
0774         ui.kcfg_input1ai->setChecked(Prefs::input1ai());
0775 
0776         return;
0777     }
0778 
0779     KConfigDialog *dialog = new KConfigDialog(this, QStringLiteral("settings"), Prefs::self());
0780     dialog->setFaceType(KPageDialog::Plain);
0781     dialog->button(QDialogButtonBox::Ok)->setDefault(true);
0782     dialog->setModal(true);
0783     // QT5 dialog->setHelp(QString(),"kfourinline");
0784     QWidget *frame = new QWidget(dialog);
0785     ui.setupUi(frame);
0786     ui.kcfg_startcolourred->setText(mTheme->colorNamePlayer(0));
0787     ui.kcfg_startcolouryellow->setText(mTheme->colorNamePlayer(1));
0788     ui.Input0->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(0)));
0789     ui.Input1->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(1)));
0790     dialog->addPage(frame, i18n("General"), QStringLiteral("games-config-options"));
0791     connect(dialog, &KConfigDialog::settingsChanged, mDoc, &KWin4Doc::loadSettings);
0792     dialog->show();
0793 }
0794 
0795 #include "moc_kwin4.cpp"