File indexing completed on 2022-09-20 13:02:20

0001 /*
0002     SPDX-FileCopyrightText: 2008-2010 Stefan Majewsky <majewsky@gmx.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "mainwindow.h"
0008 #include "game.h"
0009 #include "infobar.h"
0010 #include "settings.h"
0011 #include "view.h"
0012 // KDEGames
0013 #include <kdegames_version.h>
0014 #include <KgDifficulty>
0015 #include <KGameRenderer>
0016 #include <KScoreDialog>
0017 #include <KStandardGameAction>
0018 
0019 #include <QPointer>
0020 #include <QTime>
0021 #include <QAction>
0022 #include <KActionMenu>
0023 #include <KActionCollection>
0024 #include <KLocalizedString>
0025 #include <KNotifyConfigWidget>
0026 #include <KStandardAction>
0027 
0028 namespace KDiamond
0029 {
0030 class ThemeProvider : public KgThemeProvider
0031 {
0032 public:
0033     explicit ThemeProvider(QObject *parent = nullptr)
0034         : KgThemeProvider("Theme", parent)
0035     {
0036 #if KDEGAMES_VERSION >= QT_VERSION_CHECK(7, 4, 0)
0037         discoverThemes(QStringLiteral("themes"));
0038 #else
0039         discoverThemes("appdata", QStringLiteral("themes"));
0040 #endif
0041     }
0042 };
0043 
0044 class Renderer : public KGameRenderer
0045 {
0046 public:
0047     Renderer() : KGameRenderer(new ThemeProvider, 10)
0048     {
0049         setFrameSuffix(QStringLiteral("-%1"));
0050     }
0051 };
0052 }
0053 
0054 MainWindow::MainWindow(QWidget *parent)
0055     : KXmlGuiWindow(parent)
0056     , m_gameState(new KDiamond::GameState)
0057     , m_game(nullptr)
0058     , m_view(new KDiamond::View)
0059     , m_infoBar(nullptr)
0060     , m_newAct(new KActionMenu(QIcon::fromTheme(QStringLiteral("document-new")), i18nc("new game", "&New"), this))
0061     , m_newTimedAct(new QAction(i18n("Timed game"), this))
0062     , m_newUntimedAct(new QAction(i18n("Untimed game"), this))
0063     , m_renderer(new KDiamond::Renderer())
0064     , m_selector(m_renderer->themeProvider(), KgThemeSelector::EnableNewStuffDownload)
0065 {
0066     m_renderer->setDefaultPrimaryView(m_view);
0067     //init GUI - "New Action"
0068     m_newAct->setToolTip(i18n("Start a new game"));
0069     m_newAct->setWhatsThis(i18n("Start a new game."));
0070     actionCollection()->addAction(QStringLiteral("game_new"), m_newAct);
0071     actionCollection()->setDefaultShortcuts(m_newAct, KStandardShortcut::openNew());
0072     connect(m_newAct, &KActionMenu::triggered, this, &MainWindow::startGameDispatcher);
0073     m_newAct->addAction(m_newTimedAct);
0074     connect(m_newTimedAct, &QAction::triggered, this, &MainWindow::startGameDispatcher);
0075     m_newAct->addAction(m_newUntimedAct);
0076     connect(m_newUntimedAct, &QAction::triggered, this, &MainWindow::startGameDispatcher);
0077     //init GUI - the other actions
0078     KStandardGameAction::highscores(this, &MainWindow::showHighscores, actionCollection());
0079     m_pauseAct = KStandardGameAction::pause(this, &MainWindow::pausedAction, actionCollection());
0080     KStandardGameAction::quit(this, &QWidget::close, actionCollection());
0081     m_hintAct = KStandardGameAction::hint(nullptr, nullptr, actionCollection());
0082     KStandardAction::preferences(this, &MainWindow::showPreferences, actionCollection());
0083     KStandardAction::configureNotifications(this, &MainWindow::configureNotifications, actionCollection());
0084     //difficulty
0085     KgDifficultyGUI::init(this);
0086     connect(Kg::difficulty(), &KgDifficulty::currentLevelChanged, this, &MainWindow::startGameDispatcher);
0087     //late GUI initialisation
0088     setupGUI(QSize(300, 400)); //TODO: find better solution for a minimum size
0089     setCaption(i18nc("The application's name", "KDiamond"));
0090     setCentralWidget(m_view);
0091     //init statusbar
0092     m_infoBar = new KDiamond::InfoBar(statusBar());
0093     connect(m_gameState, &KDiamond::GameState::stateChanged, this, &MainWindow::stateChange);
0094     connect(m_gameState, &KDiamond::GameState::pointsChanged, m_infoBar, &KDiamond::InfoBar::updatePoints);
0095     connect(m_gameState, &KDiamond::GameState::leftTimeChanged, m_infoBar, &KDiamond::InfoBar::updateRemainingTime);
0096     //init game
0097     startGameDispatcher();
0098 }
0099 
0100 MainWindow::~MainWindow()
0101 {
0102     Settings::self()->save();
0103     delete m_renderer;
0104     delete m_game;
0105     delete m_gameState;
0106 }
0107 
0108 void MainWindow::startGameDispatcher()
0109 {
0110     if (sender() == m_newUntimedAct) {
0111         startGame(KDiamond::UntimedGame);
0112     } else if (sender() == m_newTimedAct) {
0113         startGame(KDiamond::NormalGame);
0114     } else
0115         //attention: this may also be used by KgDifficulty and the ctor
0116     {
0117         startGame(Settings::untimed() ? KDiamond::UntimedGame : KDiamond::NormalGame);
0118     }
0119 }
0120 
0121 void MainWindow::startGame(KDiamond::Mode mode)
0122 {
0123     //delete old board
0124     delete m_game;
0125     //start new game
0126     m_gameState->startNewGame();
0127     m_gameState->setMode(mode);
0128     m_game = new Game(m_gameState, m_renderer);
0129     connect(m_gameState, &KDiamond::GameState::stateChanged, m_game, &Game::stateChange);
0130     connect(m_gameState, &KDiamond::GameState::message, m_game, &Game::message);
0131     connect(m_game, &Game::numberMoves, m_infoBar, &KDiamond::InfoBar::updateMoves);
0132     connect(m_game, &Game::pendingAnimationsFinished, this, &MainWindow::gameIsOver);
0133     connect(m_hintAct, &QAction::triggered, m_game, &Game::showHint);
0134     m_view->setScene(m_game);
0135     //reset status bar
0136     m_infoBar->setUntimed(mode == KDiamond::UntimedGame);
0137     m_infoBar->updatePoints(0);
0138     m_infoBar->updateRemainingTime(KDiamond::GameDuration);
0139 }
0140 
0141 void MainWindow::stateChange(KDiamond::State state)
0142 {
0143     m_pauseAct->setEnabled(state != KDiamond::Finished);
0144     m_pauseAct->setChecked(state == KDiamond::Paused);
0145     m_hintAct->setEnabled(state == KDiamond::Playing);
0146 }
0147 
0148 void MainWindow::gameIsOver()
0149 {
0150     //create score info
0151     KScoreDialog::FieldInfo scoreInfo;
0152     scoreInfo[KScoreDialog::Score].setNum(m_gameState->points());
0153     scoreInfo[KScoreDialog::Custom1] = m_gameState->mode() == KDiamond::UntimedGame ? i18n("Untimed") : i18n("Timed");
0154     //report score
0155     QPointer<KScoreDialog> dialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Score, this);
0156     dialog->addField(KScoreDialog::Custom1, i18n("Mode"), QStringLiteral("mode"));
0157     dialog->initFromDifficulty(Kg::difficulty());
0158     dialog->addScore(scoreInfo);
0159     dialog->exec();
0160     delete dialog;
0161 }
0162 
0163 void MainWindow::showHighscores()
0164 {
0165     //pause game if necessary
0166     m_gameState->setState(KDiamond::Paused);
0167     if (m_gameState->state() != KDiamond::Finished) {
0168         actionCollection()->action(QStringLiteral("game_pause"))->setChecked(true);
0169     }
0170     //show dialog
0171     QPointer<KScoreDialog> dialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Score, this);
0172     dialog->addField(KScoreDialog::Custom1, i18n("Mode"), QStringLiteral("mode"));
0173     dialog->initFromDifficulty(Kg::difficulty());
0174     dialog->exec();
0175     delete dialog;
0176 }
0177 
0178 void MainWindow::showPreferences()
0179 {
0180     m_selector.showAsDialog();
0181 }
0182 
0183 
0184 void MainWindow::pausedAction(bool paused)
0185 {
0186     m_gameState->setState(paused ? KDiamond::Paused : KDiamond::Playing);
0187 }
0188 
0189 void MainWindow::configureNotifications()
0190 {
0191     KNotifyConfigWidget::configure(this);
0192 }
0193