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"