1 /*
2     This file is part of the KDE games kwin4 program
3     SPDX-FileCopyrightText: 1995-2007 Martin Heni <kde@heni-online.de>
4 
5     SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include "kwin4.h"
9 
10 // own
11 #include "chatdlg.h"
12 #include "kwin4doc.h"
13 #include "kwin4view.h"
14 #include "reflectiongraphicsscene.h"
15 #include "prefs.h"
16 #include "ui_settings.h"
17 #include "ui_statistics.h"
18 #include "kfourinline_debug.h"
19 #include "kgamedialog.h"
20 #include "kgamedialogconfig.h"
21 #include "kgamedebugdialog.h"
22 // KDEGames
23 #define USE_UNSTABLE_LIBKDEGAMESPRIVATE_API
24 #include <libkdegamesprivate/kgame/kgamechat.h>
25 // KF
26 #include <KActionCollection>
27 #include <KConfig>
28 #include <KConfigDialog>
29 #include <KLocalizedString>
30 #include <KMessageBox>
31 #include <KSelectAction>
32 #include <KStandardAction>
33 #include <KStandardGameAction>
34 // Qt
35 #include <QFileDialog>
36 #include <QGroupBox>
37 #include <QIcon>
38 #include <QLayout>
39 #include <QRadioButton>
40 #include <QStatusBar>
41 #include <QTimer>
42 #include <QVBoxLayout>
43 
44 
45 // Abbreviations
46 #define ACTION(x)   (actionCollection()->action(x))
47 #define ID_STATUS_MSG                1003
48 #define ID_STATUS_MOVER              1002
49 
50 
51 #define UPDATE_TIME  25   /* [ms] */
52 
53 // Configuration file
54 #include "config-src.h"
55 
56 // Construct the main application window
KWin4App(QWidget * parent)57 KWin4App::KWin4App(QWidget *parent)
58         : KXmlGuiWindow(parent),
59           mTheme(),
60           mView(),
61           mDoc(),
62           mScene(),
63           mColorGroup(),
64           mMyChatDlg(),
65           mStatusMsg(),
66           mStatusMover()
67 {
68   // Read theme files
69   QStringList themeList;
70   const QString dir = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("grafix"), QStandardPaths::LocateDirectory);
71   const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*.desktop"));
72   for (const QString& file : fileNames)
73     themeList.append(dir + QLatin1Char('/') + file);
74 
75   if (themeList.isEmpty())
76   {
77     KMessageBox::error(this, i18n("Installation error: No theme list found."));
78     QTimer::singleShot(0, this,&QWidget::close);
79     return;
80   }
81 
82   // Read theme files
83   for (int i = 0; i < themeList.size(); i++)
84   {
85     KConfig themeInfo( themeList.at(i), KConfig::SimpleConfig);
86     KConfigGroup themeGroup(&themeInfo, "Theme");
87     QString name   = themeGroup.readEntry("Name", QString());
88     QString file   = themeGroup.readEntry("File", QString());
89     bool isDefault = themeGroup.readEntry("Default", false);
90     if (mThemeDefault.isNull()) mThemeDefault = name;
91     if (isDefault) mThemeDefault = name;
92     mThemeFiles[name] = file;
93     qCDebug(KFOURINLINE_LOG) <<  "Found theme("<<i<<"): " <<themeList.at(i) <<" Name(i18n)="<<name<<" File="<<file << " default="<<isDefault;
94   }
95   mThemeIndexNo = themeIdxFromName(mThemeDefault);
96 
97 
98   // Setup application
99   mDoc = new KWin4Doc(this);
100   qCDebug(KFOURINLINE_LOG) << "Init doc";
101   QString aiEngine = mDoc->findProcessName();
102   qCDebug(KFOURINLINE_LOG) << "Init AI" << aiEngine;
103   if (aiEngine.isEmpty())
104   {
105     KMessageBox::error(this, i18n("Installation error: No AI engine found. Continue without AI."));
106   }
107 
108 
109   // Read properties (before GUI and thememanager but after new document)
110   qCDebug(KFOURINLINE_LOG) << "read prop";
111   readProperties();
112 
113 
114   // Scene
115   mScene  = new ReflectionGraphicsScene(UPDATE_TIME, this);
116 
117 
118   // Theme
119   QString themeFile = themefileFromIdx(mThemeIndexNo);
120   qCDebug(KFOURINLINE_LOG) << "Loading theme" << themeFile << " #"<<mThemeIndexNo;
121   mTheme  = new ThemeManager(themeFile, this);
122   if (mTheme->checkTheme() != 0)
123   {
124     KMessageBox::error(this, i18n("Installation error: Theme file error."));
125     QTimer::singleShot(0, this,&QWidget::close);
126     return;
127   }
128 
129   // View
130   mView   = new KWin4View(UPDATE_TIME, QSize(800,600),mScene,mTheme,this);
131   mDoc->setView(mView);
132   connect(mView, &KWin4View::signalQuickStart, this, &KWin4App::quickStart);
133 
134 
135 
136 
137   // Players (after view)
138   qCDebug(KFOURINLINE_LOG) << "Init pl";
139   mDoc->initPlayers();
140 
141   // Init GUI
142   initGUI();
143   initStatusBar();
144 
145   // Adjust GUI
146   setCentralWidget(mView);
147   setupGUI();
148 
149   // Connect signals
150   connectDocument();
151   // Read global config for document (after initPlayers)
152   mDoc->readConfig(KSharedConfig::openConfig().data());
153 
154   // Check menus
155   checkMenus();
156 
157 
158   // Skip intro?
159   if (global_skip_intro)
160   {
161     menuNewGame();
162   }
163   // Start game automatically in demo mode
164   else if (global_demo_mode)
165   {
166     QTimer::singleShot(11500, this,&KWin4App::menuNewGame);
167   }
168 }
169 
170 
171 // Destruct application
~KWin4App()172 KWin4App::~KWin4App()
173 {
174   qCDebug(KFOURINLINE_LOG) << "~KWin4App()";
175   delete mDoc;
176   delete mView;
177   delete mScene;
178   delete mTheme;
179   delete mMyChatDlg;
180   qCDebug(KFOURINLINE_LOG) << "~KWin4App()";
181 }
182 
183 
184 // Called by Qt when the window is closed
closeEvent(QCloseEvent * event)185 void KWin4App::closeEvent(QCloseEvent *event)
186 {
187   endGame();
188   saveProperties();
189   KXmlGuiWindow::closeEvent(event);
190 }
191 
192 
193 // Retrieve a theme file name from the menu index number
themefileFromIdx(int idx)194 QString KWin4App::themefileFromIdx(int idx)
195 {
196   QStringList list(mThemeFiles.keys());
197   list.sort();
198   QString themeFile = mThemeFiles[list.at(idx)];
199   return themeFile;
200 }
201 
202 
203 // Retrieve a theme idx from a theme name
themeIdxFromName(const QString & name)204 int KWin4App::themeIdxFromName(const QString &name)
205 {
206   QStringList list(mThemeFiles.keys());
207   list.sort();
208   for (int i=0; i < list.size(); ++i)
209   {
210     if (list[i] == name) return i;
211   }
212   qCCritical(KFOURINLINE_LOG) << "Theme index lookup failed for " << name;
213   return 0;
214 }
215 
216 
217 // This method is called from various places
218 // and signals to check, uncheck and enable
219 // or disable all menu items.
220 // The menu parameter can limit this operation
221 // to one or more of the main menus (File,View,...)
checkMenus(CheckFlags menu)222 void KWin4App::checkMenus(CheckFlags menu)
223 {
224   bool localgame=(!mDoc->isNetwork());
225   bool isRunning = (mDoc->gameStatus()==KGame::Run);
226 
227   // Check file menu
228   if (!menu || (menu&CheckFileMenu))
229   {
230     changeAction("move_hint", !(!isRunning && localgame));
231     changeAction("game_new", !isRunning);
232     changeAction("game_save", isRunning);
233     changeAction("game_end", isRunning);
234   }
235 
236   // Edit menu
237   if (!menu || (menu&CheckEditMenu))
238   {
239     if (!isRunning || !localgame)
240     {
241       disableAction("move_undo");
242     }
243     else if (mDoc->getHistoryCnt()==0)
244     {
245       disableAction("move_undo");
246     }
247     else if (mDoc->getCurrentMove()<1 )
248     {
249       disableAction("move_undo");
250     }
251     else
252     {
253       enableAction("move_undo");
254     }
255 
256     // Show redo
257     if (!isRunning || !localgame)
258     {
259       disableAction("move_redo");
260     }
261     else if (mDoc->getHistoryCnt()==mDoc->getMaxMove())
262     {
263       disableAction("move_redo");
264     }
265     else
266     {
267       enableAction("move_redo");
268     }
269   }
270 
271   // Disable some menus in demo mode
272   if (global_demo_mode)
273   {
274     disableAction(KStandardAction::name(KStandardAction::Preferences));
275     disableAction("move_undo");
276     disableAction("move_redo");
277     disableAction("game_new");
278     disableAction("game_end");
279     disableAction("game_save");
280     disableAction("game_open");
281     disableAction("network_conf");
282     disableAction("network_chat");
283     disableAction("statistics");
284     disableAction("move_hint");
285   }
286 }
287 
288 // Create the actions for the menu. This works together with the xml guirc file
initGUI()289 void KWin4App::initGUI()
290 {
291   QAction* action;
292 
293   // Game
294   KStandardGameAction::gameNew(this, &KWin4App::menuNewGame, actionCollection());
295   KStandardGameAction::load(this, &KWin4App::menuOpenGame, actionCollection());
296   KStandardGameAction::save(this, &KWin4App::menuSaveGame, actionCollection());
297   action = KStandardGameAction::end(this, &KWin4App::endGame, actionCollection());
298   action->setWhatsThis(i18n("Ends a currently played game. No winner will be declared."));
299   KStandardGameAction::hint(this, &KWin4App::askForHint, actionCollection());
300   KStandardGameAction::quit(this, &KWin4App::close, actionCollection());
301 
302   action = actionCollection()->addAction( QStringLiteral( "network_conf" ));
303   action->setText(i18n("&Network Configuration..."));
304   connect(action, &QAction::triggered, this, &KWin4App::configureNetwork);
305 
306   action = actionCollection()->addAction( QStringLiteral( "network_chat" ));
307   action->setText(i18n("Network Chat..."));
308   connect(action, &QAction::triggered, this, &KWin4App::configureChat);
309 
310   action = actionCollection()->addAction( QStringLiteral( "statistics" ));
311   action->setIcon(QIcon::fromTheme( QStringLiteral( "view-statistics" )));
312   action->setText(i18n("&Show Statistics"));
313   connect(action, &QAction::triggered, this, &KWin4App::showStatistics);
314   action->setToolTip(i18n("Show statistics."));
315 
316   // Move
317   KStandardGameAction::undo(this, &KWin4App::undoMove, actionCollection());
318   KStandardGameAction::redo(this, &KWin4App::redoMove, actionCollection());
319 
320   KStandardAction::preferences(this, &KWin4App::configureSettings, actionCollection());
321 
322   // Add all theme files to the menu
323   QStringList themes(mThemeFiles.keys());
324   themes.sort();
325 
326   KSelectAction *themeAction = new KSelectAction(i18n("Theme" ), this);
327   actionCollection()->addAction( QStringLiteral( "theme" ) , themeAction );
328   themeAction->setIcon(QIcon::fromTheme( QStringLiteral( "games-config-theme" )));
329   themeAction->setItems(themes);
330   connect(themeAction, &KSelectAction::indexTriggered, this, &KWin4App::changeTheme);
331   qCDebug(KFOURINLINE_LOG) << "Setting current theme item to" << mThemeIndexNo;
332   themeAction->setCurrentItem(mThemeIndexNo);
333 
334   // Debug
335   if (global_debug>0)
336   {
337     action = actionCollection()->addAction( QStringLiteral( "file_debug" ));
338     action->setText(i18n("Debug KGame"));
339     connect(action, &QAction::triggered, this, &KWin4App::debugKGame);
340   }
341 }
342 
343 
344 // Change the theme of the game
changeTheme(int idx)345 void KWin4App::changeTheme(int idx)
346 {
347   mThemeIndexNo = idx;
348   QString themeFile = themefileFromIdx(idx);
349   qCDebug(KFOURINLINE_LOG) << "Select theme" << themeFile;
350   mTheme->updateTheme(themeFile);
351   updateStatusNames();
352 }
353 
354 
355 // Create the status bar with the message part, the player part.
initStatusBar()356 void KWin4App::initStatusBar()
357 {
358   mStatusMsg = new QLabel();
359   mStatusMover = new QLabel();
360   statusBar()->addWidget(mStatusMsg);
361   statusBar()->addPermanentWidget(mStatusMover);
362 
363   displayStatusMessage(i18n("Welcome to Four Wins"));
364 }
365 
366 
367 // Set up the document, i.e. the KGame object
368 // and connect all signals emitted by it
connectDocument()369 void KWin4App::connectDocument()
370 {
371   // KGame signals
372   connect(mDoc, &KWin4Doc::signalGameOver, this, &KWin4App::slotGameOver);
373   connect(mDoc, &KWin4Doc::signalNextPlayer, this, &KWin4App::moveDone);
374   connect(mDoc, &KWin4Doc::signalClientLeftGame, this, &KWin4App::networkBroken);
375   connect(mDoc, &KWin4Doc::signalGameRun, this, &KWin4App::gameRun);
376 }
377 
378 
379 // Enable or disable an action
changeAction(const char * action,bool enable)380 void KWin4App::changeAction(const char* action, bool enable)
381 {
382   if (!action)
383   {
384     return;
385   }
386 
387   QAction* act=actionCollection()->action(QLatin1String(action));
388   if (act)
389   {
390     act->setEnabled(enable);
391   }
392 }
393 
394 
395 // Save instance-specific properties. The function is
saveProperties(KConfigGroup & grp)396 void KWin4App::saveProperties(KConfigGroup& grp)
397 {
398   qCDebug(KFOURINLINE_LOG) << "SAVE PROPERTIES for GROUP" << grp.name();
399 
400   // Save current game?
401   QString name = QStringLiteral("current_game")+grp.name();
402   QString filename = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QLatin1Char('/') + name;
403   bool isRunning = (mDoc->gameStatus()==KGame::Run);
404   if (isRunning)
405   {
406     qCDebug(KFOURINLINE_LOG) << "Saving" << filename;
407     mDoc->save(filename);
408     grp.writeEntry("CurrentGame", filename);
409   }
410   else
411   {
412     QFile file(filename);
413     qCDebug(KFOURINLINE_LOG) << "Deleting" << file.fileName();
414     file.remove();
415     grp.deleteEntry("CurrentGame");
416   }
417 }
418 
419 
420 // Read instance-specific properties.
readProperties(const KConfigGroup & grp)421 void KWin4App::readProperties(const KConfigGroup& grp)
422 {
423   qCDebug(KFOURINLINE_LOG) << "READ PROPERTIES for GROUP" << grp.name();
424 
425   QString filename = grp.readEntry("CurrentGame", QString());
426   qCDebug(KFOURINLINE_LOG) << "Filename is" << filename;
427 
428   if(!filename.isNull() && QFile::exists(filename))
429   {
430     qCDebug(KFOURINLINE_LOG) << "Loading" << filename;
431     // TODO: CRASHES mDoc->load(filename);
432     qCDebug(KFOURINLINE_LOG) << "Loading" << filename << "done";
433   }
434 
435 }
436 
437 
438 // Store the current game
saveProperties()439 void KWin4App::saveProperties()
440 {
441   KConfig *config = KSharedConfig::openConfig().data();
442 
443   // Program data
444   KConfigGroup cfg = config->group("ProgramData");
445   cfg.writeEntry("ThemeIndexNo", mThemeIndexNo);
446 
447   mDoc->writeConfig(config);
448 
449   config->sync();
450   qCDebug(KFOURINLINE_LOG) << "SAVED PROPERTIES";
451 }
452 
453 // Load current game back
readProperties()454 void KWin4App::readProperties()
455 {
456   KConfig *config = KSharedConfig::openConfig().data();
457 
458   // Program data
459   KConfigGroup cfg = config->group("ProgramData");
460   mThemeIndexNo = cfg.readEntry("ThemeIndexNo", themeIdxFromName(mThemeDefault));
461   if (mThemeIndexNo >= mThemeFiles.size()) mThemeIndexNo = 0;
462   qCDebug(KFOURINLINE_LOG) << "Index = " << mThemeIndexNo << " def index=" << themeIdxFromName(mThemeDefault);
463 
464 
465   qCDebug(KFOURINLINE_LOG) << "LOADED PROPERTIES";
466 }
467 
468 
469 // Load a game menu
menuOpenGame()470 void KWin4App::menuOpenGame()
471 {
472   const QString file =
473     (global_debug < 1) ?
474     QFileDialog::getOpenFileName(this) :
475     QStringLiteral("/tmp/kwin.save");
476   mDoc->load(file,true);
477   checkMenus();
478 }
479 
480 // Save game menu
menuSaveGame()481 void KWin4App::menuSaveGame()
482 {
483   const QString file =
484     (global_debug < 1) ?
485     QFileDialog::getSaveFileName(this) :
486     QStringLiteral("/tmp/kwin.save");
487   mDoc->save(file);
488 }
489 
490 
491 // Received quick start command from view
quickStart(COLOUR startPlayer,KGameIO::IOMode input0,KGameIO::IOMode input1,int level)492 void KWin4App::quickStart(COLOUR startPlayer, KGameIO::IOMode input0, KGameIO::IOMode input1, int level)
493 {
494   if (startPlayer == Yellow)
495   {
496     Prefs::setStartcolourred(false);
497     Prefs::setStartcolouryellow(true);
498   }
499   else if (startPlayer == Red)
500   {
501     Prefs::setStartcolourred(true);
502     Prefs::setStartcolouryellow(false);
503   }
504   if (level >= 0)
505   {
506     Prefs::setLevel(level);
507   }
508   if (input0 == KGameIO::MouseIO)
509   {
510     Prefs::setInput0mouse(true);
511     Prefs::setInput0key(false);
512     Prefs::setInput0ai(false);
513   }
514   if (input0 == KGameIO::ProcessIO)
515   {
516     Prefs::setInput0mouse(false);
517     Prefs::setInput0key(false);
518     Prefs::setInput0ai(true);
519   }
520   if (input1 == KGameIO::MouseIO)
521   {
522     Prefs::setInput1mouse(true);
523     Prefs::setInput1key(false);
524     Prefs::setInput1ai(false);
525   }
526   if (input1 == KGameIO::ProcessIO)
527   {
528     Prefs::setInput1mouse(false);
529     Prefs::setInput1key(false);
530     Prefs::setInput1ai(true);
531   }
532 
533   // Reload settings
534   mDoc->loadSettings();
535 
536   // Start game (direct call will crash as intro object will be deleted)
537   QTimer::singleShot(0, this,&KWin4App::menuNewGame);
538 }
539 
540 
541 // Start a new game menu
menuNewGame()542 void KWin4App::menuNewGame()
543 {
544   qCDebug(KFOURINLINE_LOG) << "MENU NEW GAME";
545   // End the intro if it is running
546   mDoc->setGameStatus(KWin4Doc::End);
547   // Init the board and Clear the old game out
548   mDoc->setGameStatus(KWin4Doc::Init);
549   // Run it
550   mDoc->setGameStatus(KWin4Doc::Run);
551   // Display game status
552   displayStatusMessage(i18n("Game running..."));
553 }
554 
555 
556 // Slot: Noticed that a new game started...update menus
gameRun()557 void KWin4App::gameRun()
558 {
559   updateStatusNames();
560   checkMenus(All);
561 }
562 
563 
564 // Abort a running game
endGame()565 void KWin4App::endGame()
566 {
567   mDoc->setGameStatus(KWin4Doc::Abort);
568 }
569 
570 
571 // Menu to ask for a game hint
askForHint()572 void KWin4App::askForHint()
573 {
574   if (mDoc) mDoc->calculateHint();
575 }
576 
577 
578 // Show statistics dialog
showStatistics()579 void KWin4App::showStatistics()
580 {
581   QPointer<QDialog> dlg = new QDialog(this);
582   Ui::Statistics ui;
583   ui.setupUi(dlg);
584 
585   ui.p1_name->setText(mDoc->getName(Yellow));
586   ui.p1_won->display(mDoc->getStatistic(Yellow, TWin));
587   ui.p1_drawn->display(mDoc->getStatistic(Yellow, TRemis));
588   ui.p1_lost->display(mDoc->getStatistic(Yellow, TLost));
589   ui.p1_aborted->display(mDoc->getStatistic(Yellow, TBrk));
590   ui.p1_sum->display(mDoc->getStatistic(Yellow, TSum));
591 
592   ui.p2_name->setText(mDoc->getName(Red));
593   ui.p2_won->display(mDoc->getStatistic(Red, TWin));
594   ui.p2_drawn->display(mDoc->getStatistic(Red, TRemis));
595   ui.p2_lost->display(mDoc->getStatistic(Red, TLost));
596   ui.p2_aborted->display(mDoc->getStatistic(Red, TBrk));
597   ui.p2_sum->display(mDoc->getStatistic(Red, TSum));
598 
599   if(dlg->exec() == QDialog::Rejected)
600   {
601     mDoc->resetStatistic();
602   }
603   delete dlg;
604 }
605 
606 
607 // Undo menu call
undoMove()608 void KWin4App::undoMove()
609 {
610   mDoc->undoMove();
611   // Undo twice if computer is moving to keep player as input
612   if (mDoc->playedBy(mDoc->getCurrentPlayer())==KGameIO::ProcessIO)
613   {
614     mDoc->undoMove();
615   }
616 
617   // Refresh menus
618   updateStatusNames();
619   checkMenus(CheckEditMenu);
620 }
621 
622 // Redo menu call
redoMove()623 void KWin4App::redoMove()
624 {
625   mDoc->redoMove();
626   // Redo twice if computer is moving to keep player as input
627   if (mDoc->playedBy(mDoc->getCurrentPlayer())==KGameIO::ProcessIO)
628   {
629     mDoc->redoMove();
630   }
631   updateStatusNames();
632   checkMenus(CheckEditMenu);
633 }
634 
635 
636 // Set the given text into the statusbar change status message permanently
displayStatusMessage(const QString & text)637 void KWin4App::displayStatusMessage(const QString &text)
638 {
639   mStatusMsg->setText(text);
640 }
641 
642 
643 // Set the string in the statusbar window for
644 // the player currently moving change status mover permanently
displayStatusbarMover(const QString & text)645 void KWin4App::displayStatusbarMover(const QString& text)
646 {
647   mStatusMover->setText(text);
648 }
649 
650 
651 // Ends the current game.
652 // Called by the gameover signal
EndGame(TABLE mode)653 void KWin4App::EndGame(TABLE mode)
654 {
655   mDoc->endGame(mode);
656   mDoc->switchStartPlayer();
657   updateStatusNames();
658   checkMenus();
659 
660   // Automatically restart game in demo mode
661   if (global_demo_mode)
662   {
663     QTimer::singleShot(10000, this,&KWin4App::menuNewGame);
664   }
665 }
666 
667 
668 // Set the names in the mover field
updateStatusNames()669 void KWin4App::updateStatusNames()
670 {
671   QString msg;
672   if (!(mDoc->gameStatus()==KGame::Run))
673     msg=i18n("No game  ");
674   else if (mDoc->getCurrentPlayer()==Yellow)
675     msg=i18n(" %1 - %2 ", mDoc->getName(Yellow), mTheme->colorNamePlayer(0));
676   else if (mDoc->getCurrentPlayer())
677     msg=i18n(" %1 - %2 ", mDoc->getName(Red), mTheme->colorNamePlayer(1));
678   else
679     msg=i18n("Nobody  ");
680   displayStatusbarMover(msg);
681 }
682 
683 // Notification that the network connection is lost.
networkBroken(int,int oldstatus,KGame *)684 void KWin4App::networkBroken(int /*id*/, int oldstatus ,KGame * /*game */)
685 {
686   qCDebug(KFOURINLINE_LOG) <<  "KWin4App::networkBroken("<<oldstatus<<")";
687 
688   // Set all input devices back to default
689   if (mDoc->playedBy(Yellow)==0)
690     mDoc->setPlayedBy(Yellow,KGameIO::MouseIO);
691   if (mDoc->playedBy(Red)==0)
692     mDoc->setPlayedBy(Red,KGameIO::MouseIO);
693 
694   qCDebug(KFOURINLINE_LOG) << "CurrrentPlayer=" << mDoc->getCurrentPlayer();
695   qCDebug(KFOURINLINE_LOG) << "   " <<  mDoc->getPlayer(mDoc->getCurrentPlayer());
696 
697   // Activate input device
698   mDoc->getPlayer(mDoc->getCurrentPlayer())->setTurn(true,true);
699 
700   // Issue message
701   KMessageBox::information(this,i18n("The network game ended!\n"));
702 
703   // Restore status
704   mDoc->setGameStatus(oldstatus);
705 }
706 
707 
708 // A move is done. Update status display.
moveDone(int)709 void KWin4App::moveDone(int /*playerNumber*/)
710 {
711   checkMenus(CheckEditMenu);
712   updateStatusNames();
713   displayStatusMessage(i18n("Game running..."));
714 }
715 
716 // The game is over or aborted. Set status and display it.
slotGameOver(int status,KPlayer * p,KGame *)717 void KWin4App::slotGameOver(int status, KPlayer* p, KGame* /*me*/)
718 {
719   qCDebug(KFOURINLINE_LOG) << "KWin4App::slotGameOver";
720   if (status==-1) // remis
721   {
722     EndGame(TRemis);
723     displayStatusMessage(i18n("The game is drawn. Please restart next round."));
724   }
725   else if (status==1) // One of the players won
726   {
727     if (p->userId()==Yellow)
728       EndGame(TWin);
729     else
730       EndGame(TLost);
731     QString msg=i18n("%1 won the game. Please restart next round.", mDoc->getName(((COLOUR)p->userId())));
732     displayStatusMessage(msg);
733   }
734   else if (status==2) // Abort
735   {
736     EndGame(TBrk);
737     QString  m=i18n(" Game ended. Please restart next round.");
738     displayStatusMessage(m);
739   }
740   else
741   {
742     qCCritical(KFOURINLINE_LOG) << "Gameover with status" << status << ". This is unexpected and a serious problem";
743   }
744   checkMenus(CheckEditMenu);
745 }
746 
747 
748 // Show the network configuration dialog
configureNetwork()749 void KWin4App::configureNetwork()
750 {
751   if (mDoc->gameStatus()==KWin4Doc::Intro)
752   {
753     mDoc->setGameStatus(KWin4Doc::Pause);
754   }
755 
756   QString host = Prefs::host();
757   int port=Prefs::port();
758 
759   // just for testing - should be non-modal
760   KGameDialog dlg(mDoc, nullptr, i18n("Network Configuration"), this);
761   dlg.networkConfig()->setDefaultNetworkInfo(host, port);
762   dlg.networkConfig()->setDiscoveryInfo(QStringLiteral("_kfourinline._tcp"),Prefs::gamename());
763 
764   QWidget *box=dlg.configPage();
765   QLayout *l=box->layout();
766 
767   mColorGroup=new QGroupBox(box);
768   QVBoxLayout *grouplay=new QVBoxLayout(mColorGroup);
769   connect(dlg.networkConfig(), &KGameDialogNetworkConfig::signalServerTypeChanged, this, &KWin4App::serverTypeChanged);
770 
771   QRadioButton *b1 = new QRadioButton(i18n("Black should be played by remote player"), mColorGroup);
772   QRadioButton *b2 = new QRadioButton(i18n("Red should be played by remote player"), mColorGroup);
773   grouplay->addWidget(b1);
774   grouplay->addWidget(b2);
775   l->addWidget(mColorGroup);
776   b1->setChecked(true);
777   remoteChanged(0);
778 
779   connect(b1, &QAbstractButton::toggled, this, [this](bool toggled) { if (toggled) remoteChanged(0); });
780   connect(b2, &QAbstractButton::toggled, this, [this](bool toggled) { if (toggled) remoteChanged(1); });
781 
782   dlg.adjustSize();
783   dlg.exec();// note: we don't have to check for the result - maybe a bug
784 }
785 
786 // Can't get rid of this function in KGame's current state.
787 // Can't pass a int signal to a bool slot, so this must be here
serverTypeChanged(int t)788 void KWin4App::serverTypeChanged(int t)
789 {
790   mColorGroup->setDisabled(t);
791 }
792 
793 
794 // The remote player in the network dialog has changed. Adapt priorities.
remoteChanged(int button)795 void KWin4App::remoteChanged(int button)
796 {
797   if (button==0)
798   {
799     mDoc->getPlayer(Yellow)->setNetworkPriority(0);
800     mDoc->getPlayer(Red)->setNetworkPriority(10);
801   }
802   else
803   {
804     mDoc->getPlayer(Yellow)->setNetworkPriority(10);
805     mDoc->getPlayer(Red)->setNetworkPriority(0);
806   }
807 }
808 
809 
810 // Show the chat dialog.
configureChat()811 void KWin4App::configureChat()
812 {
813   if (!mMyChatDlg)
814   {
815     mMyChatDlg=new ChatDlg(mDoc,this);
816     KWin4Player *p=mDoc->getPlayer(Yellow);
817     if (!p->isVirtual())
818       mMyChatDlg->setPlayer(mDoc->getPlayer(Yellow));
819     else
820       mMyChatDlg->setPlayer(mDoc->getPlayer(Red));
821     connect(mDoc, &KWin4Doc::signalChatChanged, mMyChatDlg, &ChatDlg::setPlayer);
822   }
823 
824   if (mMyChatDlg->isHidden())
825     mMyChatDlg->show();
826   else
827     mMyChatDlg->hide();
828 }
829 
830 
831 // Show the KGame debug window.
debugKGame()832 void KWin4App::debugKGame()
833 {
834   KGameDebugDialog* debugWindow = new KGameDebugDialog(mDoc, this);
835   debugWindow->show();
836 }
837 
838 
839 // Show Configure dialog.
configureSettings()840 void KWin4App::configureSettings()
841 {
842   static Ui::Settings ui; // Dialog is internally static anyway
843   if(KConfigDialog::showDialog(QStringLiteral("settings")))
844   {
845     // The dialog need to refresh the buttons as they are not connectable via a signal-slot
846     // in KConfigDialog
847     ui.kcfg_startcolourred->setChecked(Prefs::startcolourred());
848     ui.kcfg_startcolourred->setText(mTheme->colorNamePlayer(0));
849     ui.kcfg_startcolouryellow->setChecked(Prefs::startcolouryellow());
850     ui.kcfg_startcolouryellow->setText(mTheme->colorNamePlayer(1));
851     ui.kcfg_level->setValue(Prefs::level());
852     ui.Input0->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(0)));
853     ui.Input1->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(1)));
854     ui.kcfg_input0mouse->setChecked(Prefs::input0mouse());
855     ui.kcfg_input0key->setChecked(Prefs::input0key());
856     ui.kcfg_input0ai->setChecked(Prefs::input0ai());
857     ui.kcfg_input1mouse->setChecked(Prefs::input1mouse());
858     ui.kcfg_input1key->setChecked(Prefs::input1key());
859     ui.kcfg_input1ai->setChecked(Prefs::input1ai());
860 
861     return;
862   }
863 
864   KConfigDialog* dialog = new KConfigDialog(this, QStringLiteral("settings"), Prefs::self());
865   dialog->setFaceType(KPageDialog::Plain);
866   dialog->setStandardButtons(QDialogButtonBox::Ok|QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help);
867   dialog->button(QDialogButtonBox::Ok)->setDefault(true);
868   dialog->setModal(true);
869   //QT5 dialog->setHelp(QString(),"kfourinline");
870   QWidget* frame = new QWidget(dialog);
871   ui.setupUi(frame);
872   ui.kcfg_startcolourred->setText(mTheme->colorNamePlayer(0));
873   ui.kcfg_startcolouryellow->setText(mTheme->colorNamePlayer(1));
874   ui.Input0->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(0)));
875   ui.Input1->setTitle(i18n("%1 Plays With", mTheme->colorNamePlayer(1)));
876   dialog->addPage(frame, i18n("General"), QStringLiteral("games-config-options"));
877   connect(dialog, &KConfigDialog::settingsChanged, mDoc, &KWin4Doc::loadSettings);
878   dialog->show();
879 }
880 
881 
882