File indexing completed on 2024-05-12 04:04:33

0001 /*
0002     Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu>
0003     Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
0004 
0005     This program is free software; you can redistribute it and/or modify
0006     it under the terms of the GNU General Public License as published by
0007     the Free Software Foundation; either version 2 of the License, or
0008     (at your option) any later version.
0009 
0010     This program is distributed in the hope that it will be useful,
0011     but WITHOUT ANY WARRANTY; without even the implied warranty of
0012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013     GNU General Public License for more details.
0014 
0015     You should have received a copy of the GNU General Public License
0016     along with this program; if not, write to the Free Software
0017     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0018 */
0019 
0020 #include "kolf.h"
0021 #include "editor.h"
0022 #include "landscape.h"
0023 #include "newgame.h"
0024 #include "objects.h"
0025 #include "obstacles.h"
0026 #include "scoreboard.h"
0027 
0028 #include <KGameHighScoreDialog>
0029 #include <KGameStandardAction>
0030 
0031 #include <KActionCollection>
0032 #include <KIO/FileCopyJob>
0033 #include <KJobWidgets>
0034 #include <KLocalizedString>
0035 #include <KMessageBox>
0036 #include <KSelectAction>
0037 #include <KSharedConfig>
0038 #include <KStandardAction>
0039 #include <KStandardGuiItem>
0040 #include <KToggleAction>
0041 
0042 #include <QFileDialog>
0043 #include <QGridLayout>
0044 #include <QMimeDatabase>
0045 #include <QStandardPaths>
0046 #include <QStatusBar>
0047 #include <QTemporaryFile>
0048 #include <QTimer>
0049 
0050 KolfWindow::KolfWindow()
0051     : KXmlGuiWindow(nullptr)
0052 {
0053     setObjectName( QStringLiteral("Kolf" ));
0054     competition = false;
0055     game = nullptr;
0056     editor = nullptr;
0057     spacer = nullptr;
0058     scoreboard = nullptr;
0059     isTutorial = false;
0060 
0061     setupActions();
0062 
0063     m_itemFactory.registerType<Kolf::Slope>(QStringLiteral("slope"), i18n("Slope"));
0064     m_itemFactory.registerType<Kolf::Puddle>(QStringLiteral("puddle"), i18n("Puddle"));
0065     m_itemFactory.registerType<Kolf::Wall>(QStringLiteral("wall"), i18n("Wall"));
0066     m_itemFactory.registerType<Kolf::Cup>(QStringLiteral("cup"), i18n("Cup"), true); //true == addOnNewHole
0067     m_itemFactory.registerType<Kolf::Sand>(QStringLiteral("sand"), i18n("Sand"));
0068     m_itemFactory.registerType<Kolf::Windmill>(QStringLiteral("windmill"), i18n("Windmill"));
0069     m_itemFactory.registerType<Kolf::BlackHole>(QStringLiteral("blackhole"), i18n("Black Hole"));
0070     m_itemFactory.registerType<Kolf::Floater>(QStringLiteral("floater"), i18n("Floater"));
0071     m_itemFactory.registerType<Kolf::Bridge>(QStringLiteral("bridge"), i18n("Bridge"));
0072     m_itemFactory.registerType<Kolf::Sign>(QStringLiteral("sign"), i18n("Sign"));
0073     m_itemFactory.registerType<Kolf::Bumper>(QStringLiteral("bumper"), i18n("Bumper"));
0074     //NOTE: The plugin mechanism has been removed because it is not used anyway.
0075 
0076     filename = QString();
0077     dummy = new QWidget(this);
0078     setCentralWidget(dummy);
0079     layout = new QGridLayout(dummy);
0080 
0081     resize(420, 480);
0082 }
0083 
0084 KolfWindow::~KolfWindow()
0085 {
0086 }
0087 
0088 void KolfWindow::setupActions()
0089 {
0090     // Game
0091     newAction = KGameStandardAction::gameNew(this, &KolfWindow::newGame, actionCollection());
0092     endAction = KGameStandardAction::end(this, &KolfWindow::closeGame, actionCollection());
0093     KGameStandardAction::quit(this, &KolfWindow::close, actionCollection());
0094 
0095     saveAction = actionCollection()->addAction(KStandardAction::Save, QStringLiteral("game_save"), this, &KolfWindow::save);
0096     saveAction->setText(i18n("Save &Course"));
0097     saveAsAction = actionCollection()->addAction(KStandardAction::SaveAs, QStringLiteral("game_save_as"), this, &KolfWindow::saveAs);
0098     saveAsAction->setText(i18n("Save &Course As..."));
0099 
0100     saveGameAction = actionCollection()->addAction(QStringLiteral("savegame"));
0101     saveGameAction->setText(i18n("&Save Game"));
0102     connect(saveGameAction, &QAction::triggered, this, &KolfWindow::saveGame);
0103     saveGameAsAction = actionCollection()->addAction(QStringLiteral("savegameas"));
0104     saveGameAsAction->setText(i18n("&Save Game As..."));
0105     connect(saveGameAsAction, &QAction::triggered, this, &KolfWindow::saveGameAs);
0106 
0107     loadGameAction = KGameStandardAction::load(this, &KolfWindow::loadGame, actionCollection());
0108     highScoreAction = KGameStandardAction::highscores(this, &KolfWindow::showHighScores, actionCollection());
0109 
0110     // Hole
0111     editingAction = new KToggleAction(QIcon::fromTheme( QStringLiteral( "document-properties") ), i18n("&Edit"), this);
0112     actionCollection()->addAction(QStringLiteral("editing"), editingAction);
0113     connect(editingAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0114     KActionCollection::setDefaultShortcut(editingAction, Qt::CTRL|Qt::Key_E);
0115     newHoleAction = actionCollection()->addAction(QStringLiteral("newhole"));
0116     newHoleAction->setIcon(QIcon::fromTheme( QStringLiteral( "document-new" )));
0117     newHoleAction->setText(i18n("&New"));
0118     connect(newHoleAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0119     KActionCollection::setDefaultShortcut(newHoleAction, Qt::CTRL|Qt::SHIFT|Qt::Key_N);
0120     clearHoleAction = actionCollection()->addAction(QStringLiteral("clearhole"));
0121     clearHoleAction->setIcon(QIcon::fromTheme( QStringLiteral( "edit-clear-locationbar-ltr" )));
0122     clearHoleAction->setText(KStandardGuiItem::clear().text());
0123     connect(clearHoleAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0124     KActionCollection::setDefaultShortcut(clearHoleAction, Qt::CTRL|Qt::Key_Delete);
0125     resetHoleAction = actionCollection()->addAction(QStringLiteral("resethole"));
0126     resetHoleAction->setText(i18n("&Reset"));
0127     connect(resetHoleAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0128     KActionCollection::setDefaultShortcut(resetHoleAction, Qt::CTRL|Qt::Key_R);
0129     undoShotAction = KStandardAction::undo(this, &KolfWindow::emptySlot, this);
0130     actionCollection()->addAction(QStringLiteral("undoshot"), undoShotAction);
0131     undoShotAction->setText(i18n("&Undo Shot"));
0132     //replayShotAction = new QAction(i18n("&Replay Shot"), 0, this, SLOT(emptySlot()), actionCollection(), "replay");
0133 
0134     // Go
0135     holeAction = new KSelectAction(i18n("Switch to Hole"), this);
0136     actionCollection()->addAction(QStringLiteral("switchhole"), holeAction);
0137     connect(holeAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0138     nextAction = actionCollection()->addAction(QStringLiteral("nexthole"));
0139     nextAction->setIcon(QIcon::fromTheme( QStringLiteral( "go-next" )));
0140     nextAction->setText(i18n("&Next Hole"));
0141     connect(nextAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0142     KActionCollection::setDefaultShortcuts(nextAction, KStandardShortcut::forward());
0143     prevAction = actionCollection()->addAction(QStringLiteral("prevhole"));
0144     prevAction->setIcon(QIcon::fromTheme( QStringLiteral( "go-previous" )));
0145     prevAction->setText(i18n("&Previous Hole"));
0146     connect(prevAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0147     KActionCollection::setDefaultShortcuts(prevAction, KStandardShortcut::back());
0148     firstAction = actionCollection()->addAction(QStringLiteral("firsthole"));
0149     firstAction->setIcon(QIcon::fromTheme( QStringLiteral( "go-home" )));
0150     firstAction->setText(i18n("&First Hole"));
0151     connect(firstAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0152     KActionCollection::setDefaultShortcuts(firstAction, KStandardShortcut::begin());
0153     lastAction = actionCollection()->addAction(QStringLiteral("lasthole"));
0154     lastAction->setText(i18n("&Last Hole"));
0155     connect(lastAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0156     KActionCollection::setDefaultShortcut(lastAction, Qt::CTRL|Qt::SHIFT|Qt::Key_End); // why not KStandardShortcut::End (Ctrl+End)?
0157     randAction = actionCollection()->addAction(QStringLiteral("randhole"));
0158     randAction->setIcon(QIcon::fromTheme( QStringLiteral( "go-jump" )));
0159     randAction->setText(i18n("&Random Hole"));
0160     connect(randAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0161 
0162     // Settings
0163     useMouseAction = new KToggleAction(i18n("Enable &Mouse for Moving Putter"), this);
0164     actionCollection()->addAction(QStringLiteral("usemouse"), useMouseAction);
0165     connect(useMouseAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0166     connect(useMouseAction, &QAction::toggled, this, &KolfWindow::useMouseChanged);
0167     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("Settings"));
0168     useMouseAction->setChecked(configGroup.readEntry("useMouse", true));
0169 
0170     useAdvancedPuttingAction = new KToggleAction(i18n("Enable &Advanced Putting"), this);
0171     actionCollection()->addAction(QStringLiteral("useadvancedputting"), useAdvancedPuttingAction);
0172     connect(useAdvancedPuttingAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0173     connect(useAdvancedPuttingAction, &QAction::toggled, this, &KolfWindow::useAdvancedPuttingChanged);
0174     useAdvancedPuttingAction->setChecked(configGroup.readEntry("useAdvancedPutting", false));
0175 
0176     showInfoAction = new KToggleAction(QIcon::fromTheme( QStringLiteral( "help-about")), i18n("Show &Info"), this);
0177     actionCollection()->addAction(QStringLiteral("showinfo"), showInfoAction);
0178     connect(showInfoAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0179     KActionCollection::setDefaultShortcut(showInfoAction, Qt::CTRL|Qt::Key_I);
0180     connect(showInfoAction, &QAction::toggled, this, &KolfWindow::showInfoChanged);
0181     showInfoAction->setChecked(configGroup.readEntry("showInfo", true));
0182 
0183     showGuideLineAction = new KToggleAction(i18n("Show Putter &Guideline"), this);
0184     actionCollection()->addAction(QStringLiteral("showguideline"), showGuideLineAction);
0185     connect(showGuideLineAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0186     connect(showGuideLineAction, &QAction::toggled, this, &KolfWindow::showGuideLineChanged);
0187     showGuideLineAction->setChecked(configGroup.readEntry("showGuideLine", true));
0188 
0189     KToggleAction *act = new KToggleAction(i18n("Enable All Dialog Boxes"), this);
0190     actionCollection()->addAction(QStringLiteral("enableAll"), act);
0191     connect(act, &QAction::triggered, this, &KolfWindow::enableAllMessages);
0192 
0193     soundAction = new KToggleAction(i18n("Play &Sounds"), this);
0194     actionCollection()->addAction(QStringLiteral("sound"), soundAction);
0195     connect(soundAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0196     connect(soundAction, &QAction::toggled, this, &KolfWindow::soundChanged);
0197     soundAction->setChecked(configGroup.readEntry("sound", true));
0198 
0199     aboutAction = actionCollection()->addAction(QStringLiteral("aboutcourse"));
0200     aboutAction->setText(i18n("&About Course..."));
0201     connect(aboutAction, &QAction::triggered, this, &KolfWindow::emptySlot);
0202     tutorialAction = actionCollection()->addAction(QStringLiteral("tutorial"));
0203     tutorialAction->setText(i18n("&Tutorial"));
0204     connect(tutorialAction, &QAction::triggered, this, &KolfWindow::tutorial);
0205 
0206     setupGUI();
0207 }
0208 
0209 bool KolfWindow::queryClose()
0210 {
0211     if (game)
0212         if (game->askSave(true))
0213             return false;
0214     return true;
0215 }
0216 
0217 void KolfWindow::startNewGame()
0218 {
0219         NewGameDialog *dialog = nullptr;
0220     int firstHole = 1;
0221 
0222     if (loadedGame.isNull())
0223     {
0224         dialog = new NewGameDialog(filename.isNull());
0225                 if (dialog->exec() != QDialog::Accepted) {
0226                     delete dialog;
0227                     return;
0228                }
0229     }
0230 
0231     players.clear();
0232     delete scoreboard;
0233     scoreboard = new ScoreBoard(dummy);
0234     layout->addWidget(scoreboard, 1, 0);
0235     scoreboard->show();
0236 
0237     if (loadedGame.isNull())
0238     {
0239         for (int newId = 1; newId <= dialog->players()->count(); ++newId)
0240         {
0241             players.append(Player());
0242             players.last().ball()->setColor(dialog->players()->at(newId-1)->color());
0243             players.last().setName(dialog->players()->at(newId-1)->name());
0244             players.last().setId(newId);
0245         }
0246 
0247         competition = dialog->competition();
0248         filename = filename.isNull()? dialog->course() : filename;
0249     }
0250     else
0251     {
0252         KConfig config(loadedGame);
0253         KConfigGroup configGroup(config.group(QStringLiteral("0 Saved Game")));
0254 
0255         if (isTutorial)
0256             filename = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("tutorial.kolf"));
0257         else
0258             filename = configGroup.readEntry("Course", QString());
0259 
0260         if (filename.isNull())
0261             return;
0262 
0263         competition = configGroup.readEntry("Competition", false);
0264         firstHole = configGroup.readEntry("Current Hole", 1);
0265 
0266         players.clear();
0267         KolfGame::scoresFromSaved(&config, players);
0268     }
0269 
0270     for (PlayerList::Iterator it = players.begin(); it != players.end(); ++it)
0271         scoreboard->newPlayer((*it).name());
0272 
0273     delete spacer;
0274         spacer = nullptr;
0275     delete game;
0276         game = new KolfGame(m_itemFactory, &players, filename, dummy);
0277     game->setStrict(competition);
0278 
0279     connect(game, &KolfGame::newHole, scoreboard, &ScoreBoard::newHole);
0280     connect(game, &KolfGame::scoreChanged, scoreboard, &ScoreBoard::setScore);
0281     connect(game, &KolfGame::parChanged, scoreboard, &ScoreBoard::parChanged);
0282     connect(game, &KolfGame::modifiedChanged, this, &KolfWindow::updateModified);
0283     connect(game, &KolfGame::newPlayersTurn, this, &KolfWindow::newPlayersTurn);
0284     connect(game, &KolfGame::holesDone, this, &KolfWindow::gameOver);
0285     connect(game, &KolfGame::checkEditing, this, &KolfWindow::checkEditing);
0286     connect(game, &KolfGame::editingStarted, this, &KolfWindow::editingStarted);
0287     connect(game, &KolfGame::editingEnded, this, &KolfWindow::editingEnded);
0288     connect(game, &KolfGame::inPlayStart, this, &KolfWindow::inPlayStart);
0289     connect(game, &KolfGame::inPlayEnd, this, &KolfWindow::inPlayEnd);
0290     connect(game, &KolfGame::maxStrokesReached, this, &KolfWindow::maxStrokesReached);
0291     connect(game, &KolfGame::largestHole, this, &KolfWindow::updateHoleMenu);
0292     connect(game, &KolfGame::titleChanged, this, &KolfWindow::titleChanged);
0293     connect(game, &KolfGame::newStatusText, this, &KolfWindow::newStatusText);
0294         connect(game, qOverload<int>(&KolfGame::currentHole), this,
0295                 &KolfWindow::setCurrentHole);
0296         connect(holeAction, &QAction::triggered, game,
0297                 qOverload<int>(&KolfGame::switchHole));
0298         connect(nextAction, &QAction::triggered, game, &KolfGame::nextHole);
0299     connect(prevAction, &QAction::triggered, game, &KolfGame::prevHole);
0300     connect(firstAction, &QAction::triggered, game, &KolfGame::firstHole);
0301     connect(lastAction, &QAction::triggered, game, &KolfGame::lastHole);
0302     connect(randAction, &QAction::triggered, game, &KolfGame::randHole);
0303     connect(editingAction, &QAction::triggered, game, &KolfGame::toggleEditMode);
0304     connect(newHoleAction, &QAction::triggered, game, &KolfGame::addNewHole);
0305     connect(clearHoleAction, &QAction::triggered, game, &KolfGame::clearHole);
0306     connect(resetHoleAction, &QAction::triggered, game, &KolfGame::resetHole);
0307     connect(undoShotAction, &QAction::triggered, game, &KolfGame::undoShot);
0308     //connect(replayShotAction, &QAction::triggered, game, &KolfGame::replay);
0309     connect(aboutAction, &QAction::triggered, game, &KolfGame::showInfoDlg);
0310     connect(useMouseAction, &QAction::toggled, game, &KolfGame::setUseMouse);
0311     connect(useAdvancedPuttingAction, &QAction::toggled, game, &KolfGame::setUseAdvancedPutting);
0312     connect(soundAction, &QAction::toggled, game, &KolfGame::setSound);
0313     connect(showGuideLineAction, &QAction::toggled, game, &KolfGame::setShowGuideLine);
0314     connect(showInfoAction, &QAction::toggled, game, &KolfGame::setShowInfo);
0315 
0316     game->setUseMouse(useMouseAction->isChecked());
0317     game->setUseAdvancedPutting(useAdvancedPuttingAction->isChecked());
0318     game->setShowInfo(showInfoAction->isChecked());
0319     game->setShowGuideLine(showGuideLineAction->isChecked());
0320     game->setSound(soundAction->isChecked());
0321 
0322     layout->addWidget(game, 0, 0);//, Qt::AlignCenter);
0323 
0324     game->show();
0325     game->setFocus();
0326 
0327     setEditingEnabled(true);
0328     endAction->setEnabled(true);
0329     setHoleMovementEnabled(true);
0330     setHoleOtherEnabled(true);
0331     aboutAction->setEnabled(true);
0332     highScoreAction->setEnabled(true);
0333     saveAction->setEnabled(true);
0334     saveAsAction->setEnabled(true);
0335     saveGameAction->setEnabled(true);
0336     saveGameAsAction->setEnabled(true);
0337 
0338     clearHoleAction->setEnabled(false);
0339     newHoleAction->setEnabled(false);
0340     newAction->setEnabled(false);
0341     loadGameAction->setEnabled(false);
0342     tutorialAction->setEnabled(false);
0343 
0344     // so game can do stuff that needs to be done
0345     // after things above are connected
0346     game->startFirstHole(firstHole);
0347     delete dialog;
0348 }
0349 
0350 void KolfWindow::newGame()
0351 {
0352     isTutorial = false;
0353     filename = QString();
0354     startNewGame();
0355 }
0356 
0357 void KolfWindow::tutorial()
0358 {
0359     QString newfilename = QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("tutorial.kolfgame"));
0360     if (newfilename.isNull())
0361             return;
0362 
0363     filename = QString();
0364     loadedGame = newfilename;
0365     isTutorial = true;
0366 
0367     startNewGame();
0368 
0369     loadedGame = QString();
0370 }
0371 
0372 void KolfWindow::closeGame()
0373 {
0374     if (game)
0375     {
0376         if (game->askSave(true))
0377             return;
0378         game->pause();
0379     }
0380 
0381     filename = QString();
0382 
0383     editingEnded();
0384     delete game;
0385     game = nullptr;
0386     loadedGame = QString();
0387 
0388     editingAction->setChecked(false);
0389     setEditingEnabled(false);
0390     endAction->setEnabled(false);
0391     aboutAction->setEnabled(false);
0392     highScoreAction->setEnabled(false);
0393     saveAction->setEnabled(false);
0394     saveAsAction->setEnabled(false);
0395     saveGameAction->setEnabled(false);
0396     saveGameAsAction->setEnabled(false);
0397     setHoleMovementEnabled(false);
0398     setHoleOtherEnabled(false);
0399 
0400     clearHoleAction->setEnabled(false);
0401     newHoleAction->setEnabled(false);
0402     newAction->setEnabled(true);
0403     loadGameAction->setEnabled(true);
0404     tutorialAction->setEnabled(true);
0405 
0406     titleChanged(QString());
0407     updateModified(false);
0408 
0409     QTimer::singleShot(100, this, &KolfWindow::createSpacer);
0410 }
0411 
0412 void KolfWindow::createSpacer()
0413 {
0414     // make a player to play the spacer hole
0415     spacerPlayers.clear();
0416     spacerPlayers.append(Player());
0417     spacerPlayers.last().ball()->setColor(Qt::yellow);
0418     spacerPlayers.last().setName(QStringLiteral("player"));
0419     spacerPlayers.last().setId(1);
0420 
0421     delete spacer;
0422     spacer = new KolfGame(m_itemFactory, &spacerPlayers, QStandardPaths::locate(QStandardPaths::AppDataLocation, QStringLiteral("intro")), dummy);
0423     spacer->setSound(false);
0424     layout->addWidget(spacer, 0, 0);//, Qt::AlignCenter);
0425     spacer->ignoreEvents(true);
0426 
0427     spacer->show();
0428     spacer->startFirstHole(1);
0429     spacer->hidePutter();
0430 }
0431 
0432 void KolfWindow::gameOver()
0433 {
0434     int curPar = 0;
0435     int lowScore = INT_MAX; // let's hope it doesn't stay this way!
0436     int curScore = 1;
0437 
0438     // names of people who had the lowest score
0439     QStringList names;
0440 
0441     HighScoreList highScores;
0442     int scoreBoardIndex = 1;
0443 
0444     while (curScore != 0)
0445     {
0446         QString curName;
0447 
0448         // name taken as a reference and filled out
0449         curScore = scoreboard->total(scoreBoardIndex, curName);
0450 
0451         scoreBoardIndex++;
0452 
0453         if (curName == i18n("Par"))
0454         {
0455             curPar = curScore;
0456             curScore = 0;
0457             continue;
0458         }
0459 
0460         if (curScore == 0)
0461             continue;
0462 
0463         // attempt to add everybody to the highscore list
0464         // (ignored if we aren't competing down below)
0465         highScores.append(HighScore(curName, curScore));
0466 
0467         if (curScore < lowScore)
0468         {
0469             names.clear();
0470             lowScore = curScore;
0471             names.append(curName);
0472         }
0473         else if (curScore == lowScore)
0474             names.append(curName);
0475     }
0476 
0477     // only announce a winner if more than two entries
0478     // (player and par) are on the scoreboard + one to go past end
0479     // + 1 for koodoo
0480     if (scoreBoardIndex > 4)
0481     {
0482         if (names.count() > 1)
0483         {
0484             QString winners = names.join( i18n(" and " ));
0485             KMessageBox::information(this, i18n("%1 tied", winners));
0486         }
0487         else
0488             KMessageBox::information(this, i18n("%1 won!", names.first()));
0489     }
0490 
0491     if (competition)
0492     {
0493         // deal with highscores
0494         // KGameHighScoreDialog makes it very easy :-))
0495 
0496         KGameHighScoreDialog *scoreDialog = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Custom1 | KGameHighScoreDialog::Score, this);
0497         scoreDialog->addField(KGameHighScoreDialog::Custom1, i18n("Par"), QStringLiteral("Par"));
0498 
0499         CourseInfo courseInfo;
0500         game->courseInfo(courseInfo, game->curFilename());
0501 
0502         scoreDialog->setConfigGroup(qMakePair(QByteArray(courseInfo.untranslatedName.toUtf8() + " Highscores"), i18n("High Scores for %1", courseInfo.name)));
0503 
0504         for (HighScoreList::Iterator it = highScores.begin(); it != highScores.end(); ++it)
0505         {
0506             KGameHighScoreDialog::FieldInfo info;
0507                         info[KGameHighScoreDialog::Name] = (*it).name;
0508                         info[KGameHighScoreDialog::Score].setNum((*it).score);
0509             info[KGameHighScoreDialog::Custom1] = QString::number(curPar);
0510 
0511                         scoreDialog->addScore(info, KGameHighScoreDialog::LessIsMore);
0512         }
0513 
0514         scoreDialog->setComment(i18n("High Scores for %1", courseInfo.name));
0515         scoreDialog->show();
0516     }
0517 
0518     QTimer::singleShot(700, this, &KolfWindow::closeGame);
0519 }
0520 
0521 void KolfWindow::showHighScores()
0522 {
0523     KGameHighScoreDialog *scoreDialog = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Custom1 | KGameHighScoreDialog::Score, this);
0524     scoreDialog->addField(KGameHighScoreDialog::Custom1, i18n("Par"), QStringLiteral("Par"));
0525 
0526     CourseInfo courseInfo;
0527     game->courseInfo(courseInfo, game->curFilename());
0528 
0529     scoreDialog->setConfigGroup(qMakePair(QByteArray(courseInfo.untranslatedName.toUtf8() + " Highscores"), i18n("High Scores for %1", courseInfo.name)));
0530     scoreDialog->setComment(i18n("High Scores for %1", courseInfo.name));
0531     scoreDialog->show();
0532 }
0533 
0534 void KolfWindow::save()
0535 {
0536     if (filename.isNull())
0537     {
0538         saveAs();
0539         return;
0540     }
0541 
0542     if (game) {
0543         game->save();
0544         game->setFocus();
0545     }
0546 }
0547 
0548 void KolfWindow::saveAs()
0549 {
0550     QPointer<QFileDialog> fileSaveDialog = new QFileDialog(this);
0551     fileSaveDialog->setWindowTitle(i18nc("@title:window", "Pick Kolf Course to Save To"));
0552     fileSaveDialog->setMimeTypeFilters(QStringList(QStringLiteral("application/x-kourse")));
0553     fileSaveDialog->setAcceptMode(QFileDialog::AcceptSave);
0554     if (fileSaveDialog->exec() == QDialog::Accepted) {
0555         QUrl newfile = fileSaveDialog->selectedUrls().first();
0556         if (!newfile.isEmpty()) {
0557             filename = newfile.toLocalFile();
0558             game->setFilename(filename);
0559             game->save();
0560             game->setFocus();
0561         }
0562     }
0563     delete fileSaveDialog;
0564 }
0565 
0566 void KolfWindow::saveGameAs()
0567 {
0568         QPointer<QFileDialog> fileSaveDialog = new QFileDialog(this);
0569         fileSaveDialog->setWindowTitle(i18nc("@title:window", "Pick Saved Game to Save To"));
0570         fileSaveDialog->setMimeTypeFilters(QStringList(QStringLiteral("application/x-kolf")));
0571         fileSaveDialog->setAcceptMode(QFileDialog::AcceptSave);
0572         if (fileSaveDialog->exec() == QDialog::Accepted) {
0573             QUrl newfile = fileSaveDialog->selectedUrls().first();
0574             if (newfile.isEmpty()) {
0575                 return;
0576             }
0577             else {
0578                 loadedGame = newfile.toLocalFile();
0579                 saveGame();
0580             }
0581         }
0582         delete fileSaveDialog;
0583 }
0584 
0585 void KolfWindow::saveGame()
0586 {
0587     if (loadedGame.isNull())
0588     {
0589         saveGameAs();
0590         return;
0591     }
0592 
0593     KConfig config(loadedGame);
0594     KConfigGroup configGroup(config.group(QStringLiteral("0 Saved Game")));
0595 
0596     configGroup.writeEntry("Competition", competition);
0597     configGroup.writeEntry("Course", filename);
0598 
0599     game->saveScores(&config);
0600 
0601     configGroup.sync();
0602 }
0603 
0604 void KolfWindow::loadGame()
0605 {
0606     QPointer<QFileDialog> fileLoadDialog = new QFileDialog(this);
0607     fileLoadDialog->setWindowTitle(i18nc("@title:window", "Pick Kolf Saved Game"));
0608     fileLoadDialog->setMimeTypeFilters(QStringList(QStringLiteral("application/x-kolf")));
0609     fileLoadDialog->setAcceptMode(QFileDialog::AcceptOpen);
0610     fileLoadDialog->setFileMode(QFileDialog::ExistingFile);
0611     if (fileLoadDialog->exec() == QDialog::Accepted) {
0612         loadedGame = fileLoadDialog->selectedUrls().first().toLocalFile();
0613         if (loadedGame.isEmpty()) {
0614             return;
0615         }
0616         else {
0617             isTutorial = false;
0618             startNewGame();
0619         }
0620     }
0621     delete fileLoadDialog;
0622 }
0623 
0624 // called by main for command line files
0625 void KolfWindow::openUrl(const QUrl &url)
0626 {
0627     QTemporaryFile tempFile;
0628     tempFile.open();
0629     KIO::FileCopyJob *job = KIO::file_copy(url, QUrl::fromLocalFile(tempFile.fileName()), -1, KIO::Overwrite);
0630     KJobWidgets::setWindow(job, this);
0631     job->exec();
0632     if (!job->error())
0633     {
0634         isTutorial = false;
0635         QMimeDatabase db;
0636         QString mimeType = db.mimeTypeForFile(tempFile.fileName()).name();
0637         if (mimeType == QLatin1String("application/x-kourse"))
0638             filename = tempFile.fileName();
0639         else if (mimeType == QLatin1String("application/x-kolf"))
0640             loadedGame = tempFile.fileName();
0641         else
0642         {
0643             closeGame();
0644             return;
0645         }
0646 
0647         QTimer::singleShot(10, this, &KolfWindow::startNewGame);
0648     }
0649     else
0650         closeGame();
0651 }
0652 
0653 void KolfWindow::newPlayersTurn(Player *player)
0654 {
0655     tempStatusBarText = i18n("%1's turn", player->name());
0656 
0657     if (showInfoAction->isChecked())
0658         statusBar()->showMessage(tempStatusBarText, 5 * 1000);
0659     else
0660         statusBar()->showMessage(tempStatusBarText);
0661 
0662     scoreboard->setCurrentCell(player->id() - 1, game->currentHole() - 1);
0663 }
0664 
0665 void KolfWindow::newStatusText(const QString &text)
0666 {
0667     if (text.isEmpty())
0668         statusBar()->showMessage(tempStatusBarText);
0669     else
0670         statusBar()->showMessage(text);
0671 }
0672 
0673 void KolfWindow::editingStarted()
0674 {
0675     delete editor;
0676     editor = new Editor(m_itemFactory, dummy);
0677     editor->setObjectName( QStringLiteral( "Editor" ) );
0678     connect(editor, &Editor::addNewItem, game, &KolfGame::addNewObject);
0679     connect(editor, &Editor::changed, game, &KolfGame::setModified);
0680     connect(editor, &Editor::addNewItem, this, &KolfWindow::setHoleFocus);
0681     connect(game, &KolfGame::newSelectedItem, editor, &Editor::setItem);
0682 
0683     scoreboard->hide();
0684 
0685     layout->addWidget(editor, 1, 0);
0686     editor->show();
0687 
0688     clearHoleAction->setEnabled(true);
0689     newHoleAction->setEnabled(true);
0690     setHoleOtherEnabled(false);
0691 
0692     game->setFocus();
0693 }
0694 
0695 void KolfWindow::editingEnded()
0696 {
0697     delete editor;
0698     editor = nullptr;
0699 
0700     if (scoreboard)
0701         scoreboard->show();
0702 
0703     clearHoleAction->setEnabled(false);
0704     newHoleAction->setEnabled(false);
0705     setHoleOtherEnabled(true);
0706 
0707     if (game)
0708         game->setFocus();
0709 }
0710 
0711 void KolfWindow::inPlayStart()
0712 {
0713     setEditingEnabled(false);
0714     setHoleOtherEnabled(false);
0715     setHoleMovementEnabled(false);
0716 }
0717 
0718 void KolfWindow::inPlayEnd()
0719 {
0720     setEditingEnabled(true);
0721     setHoleOtherEnabled(true);
0722     setHoleMovementEnabled(true);
0723 }
0724 
0725 void KolfWindow::maxStrokesReached(const QString &name)
0726 {
0727     KMessageBox::information(this, i18n("%1's score has reached the maximum for this hole.", name));
0728 }
0729 
0730 void KolfWindow::updateHoleMenu(int largest)
0731 {
0732     QStringList items;
0733     for (int i = 1; i <= largest; ++i)
0734         items.append(QString::number(i));
0735 
0736     // setItems for some reason enables the action
0737     bool shouldbe = holeAction->isEnabled();
0738     holeAction->setItems(items);
0739     holeAction->setEnabled(shouldbe);
0740 }
0741 
0742 void KolfWindow::setHoleMovementEnabled(bool yes)
0743 {
0744     if (competition)
0745         yes = false;
0746 
0747     holeAction->setEnabled(yes);
0748 
0749     nextAction->setEnabled(yes);
0750     prevAction->setEnabled(yes);
0751     firstAction->setEnabled(yes);
0752     lastAction->setEnabled(yes);
0753     randAction->setEnabled(yes);
0754 }
0755 
0756 void KolfWindow::setHoleOtherEnabled(bool yes)
0757 {
0758     if (competition)
0759         yes = false;
0760 
0761     resetHoleAction->setEnabled(yes);
0762     undoShotAction->setEnabled(yes);
0763     //replayShotAction->setEnabled(yes);
0764 }
0765 
0766 void KolfWindow::setEditingEnabled(bool yes)
0767 {
0768     editingAction->setEnabled(competition? false : yes);
0769 }
0770 
0771 void KolfWindow::checkEditing()
0772 {
0773     editingAction->setChecked(true);
0774 }
0775 
0776 void KolfWindow::updateModified(bool mod)
0777 {
0778     courseModified = mod;
0779     titleChanged(title);
0780 }
0781 
0782 void KolfWindow::titleChanged(const QString &newTitle)
0783 {
0784     title = newTitle;
0785     setCaption(title, courseModified);
0786 }
0787 
0788 void KolfWindow::useMouseChanged(bool yes)
0789 {
0790     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("Settings")); configGroup.writeEntry("useMouse", yes); configGroup.sync();
0791 }
0792 
0793 void KolfWindow::useAdvancedPuttingChanged(bool yes)
0794 {
0795     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("Settings")); configGroup.writeEntry("useAdvancedPutting", yes); configGroup.sync();
0796 }
0797 
0798 void KolfWindow::showInfoChanged(bool yes)
0799 {
0800     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("Settings")); configGroup.writeEntry("showInfo", yes); configGroup.sync();
0801 }
0802 
0803 void KolfWindow::showGuideLineChanged(bool yes)
0804 {
0805     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("Settings")); configGroup.writeEntry("showGuideLine", yes); configGroup.sync();
0806 }
0807 
0808 void KolfWindow::soundChanged(bool yes)
0809 {
0810     KConfigGroup configGroup(KSharedConfig::openConfig(), QStringLiteral("Settings")); configGroup.writeEntry("sound", yes); configGroup.sync();
0811 }
0812 
0813 void KolfWindow::enableAllMessages()
0814 {
0815     KMessageBox::enableAllMessages();
0816 }
0817 
0818 void KolfWindow::setCurrentHole(int hole)
0819 {
0820     if (!holeAction || holeAction->items().count() < hole)
0821         return;
0822     // Golf is 1-based, KListAction is 0-based
0823     holeAction->setCurrentItem(hole - 1);
0824 }
0825 
0826 #include "moc_kolf.cpp"