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