1/*
2 Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu>
3 Copyright 2010 Stefan Majewsky <majewsky@gmx.net>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18*/
19
20#include "kolf.h"
21#include "editor.h"
22#include "landscape.h"
23#include "newgame.h"
24#include "objects.h"
25#include "obstacles.h"
26#include "scoreboard.h"
27
28#include <KActionCollection>
29#include <KFileDialog>
30#include <KIO/NetAccess>
31#include <KMessageBox>
32#include <KScoreDialog>
33#include <KSelectAction>
34#include <KStandardDirs>
35#include <KStatusBar>
36#include <KStandardAction>
37#include <KStandardGameAction>
38#include <KStandardGuiItem>
39#include <KToggleAction>
40
41#include <QGridLayout>
42#include <QTimer>
43
44KolfWindow::KolfWindow()
45 : KXmlGuiWindow(0)
46{
47 setObjectName( QLatin1String("Kolf" ));
48 competition = false;
49 game = 0;
50 editor = 0;
51 spacer = 0;
52 scoreboard = 0;
53 isTutorial = false;
54
55 setupActions();
56
57 m_itemFactory.registerType<Kolf::Slope>("slope", i18n("Slope"));
58 m_itemFactory.registerType<Kolf::Puddle>("puddle", i18n("Puddle"));
59 m_itemFactory.registerType<Kolf::Wall>("wall", i18n("Wall"));
60 m_itemFactory.registerType<Kolf::Cup>("cup", i18n("Cup"), true); //true == addOnNewHole
61 m_itemFactory.registerType<Kolf::Sand>("sand", i18n("Sand"));
62 m_itemFactory.registerType<Kolf::Windmill>("windmill", i18n("Windmill"));
63 m_itemFactory.registerType<Kolf::BlackHole>("blackhole", i18n("Black Hole"));
64 m_itemFactory.registerType<Kolf::Floater>("floater", i18n("Floater"));
65 m_itemFactory.registerType<Kolf::Bridge>("bridge", i18n("Bridge"));
66 m_itemFactory.registerType<Kolf::Sign>("sign", i18n("Sign"));
67 m_itemFactory.registerType<Kolf::Bumper>("bumper", i18n("Bumper"));
68 //NOTE: The plugin mechanism has been removed because it is not used anyway.
69
70 filename = QString();
71 dummy = new QWidget(this);
72 setCentralWidget(dummy);
73 layout = new QGridLayout(dummy);
74
75 resize(420, 480);
76}
77
78KolfWindow::~KolfWindow()
79{
80}
81
82void KolfWindow::setupActions()
83{
84 // Game
85 newAction = KStandardGameAction::gameNew(this, SLOT(newGame()), actionCollection());
86 endAction = KStandardGameAction::end(this, SLOT(closeGame()), actionCollection());
87 KStandardGameAction::quit(this, SLOT(close()), actionCollection());
88
89 saveAction = actionCollection()->addAction(KStandardAction::Save, "game_save", this, SLOT(save()));
90 saveAction->setText(i18n("Save &Course"));
91 saveAsAction = actionCollection()->addAction(KStandardAction::SaveAs, "game_save_as", this, SLOT(saveAs()));
92 saveAsAction->setText(i18n("Save &Course As..."));
93
94 saveGameAction = actionCollection()->addAction("savegame");
95 saveGameAction->setText(i18n("&Save Game"));
96 connect(saveGameAction, SIGNAL(triggered(bool)), SLOT(saveGame()));
97 saveGameAsAction = actionCollection()->addAction("savegameas");
98 saveGameAsAction->setText(i18n("&Save Game As..."));
99 connect(saveGameAsAction, SIGNAL(triggered(bool)), SLOT(saveGameAs()));
100
101 loadGameAction = KStandardGameAction::load(this, SLOT(loadGame()), actionCollection());
102 highScoreAction = KStandardGameAction::highscores(this, SLOT(showHighScores()), actionCollection());
103
104 // Hole
105 editingAction = new KToggleAction(KIcon( QLatin1String( "document-properties") ), i18n("&Edit"), this);
106 actionCollection()->addAction("editing", editingAction);
107 connect(editingAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
108 editingAction->setShortcut(Qt::CTRL+Qt::Key_E);
109 newHoleAction = actionCollection()->addAction("newhole");
110 newHoleAction->setIcon(KIcon( QLatin1String( "document-new" )));
111 newHoleAction->setText(i18n("&New"));
112 connect(newHoleAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
113 newHoleAction->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_N);
114 clearHoleAction = actionCollection()->addAction("clearhole");
115 clearHoleAction->setIcon(KIcon( QLatin1String( "edit-clear-locationbar-ltr" )));
116 clearHoleAction->setText(KStandardGuiItem::clear().text());
117 connect(clearHoleAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
118 clearHoleAction->setShortcut(Qt::CTRL+Qt::Key_Delete);
119 resetHoleAction = actionCollection()->addAction("resethole");
120 resetHoleAction->setText(i18n("&Reset"));
121 connect(resetHoleAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
122 resetHoleAction->setShortcut(Qt::CTRL+Qt::Key_R);
123 undoShotAction = KStandardAction::undo(this, SLOT(emptySlot()), this);
124 actionCollection()->addAction("undoshot", undoShotAction);
125 undoShotAction->setText(i18n("&Undo Shot"));
126 //replayShotAction = new KAction(i18n("&Replay Shot"), 0, this, SLOT(emptySlot()), actionCollection(), "replay");
127
128 // Go
129 holeAction = new KSelectAction(i18n("Switch to Hole"), this);
130 actionCollection()->addAction("switchhole", holeAction);
131 connect(holeAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
132 nextAction = actionCollection()->addAction("nexthole");
133 nextAction->setIcon(KIcon( QLatin1String( "go-next" )));
134 nextAction->setText(i18n("&Next Hole"));
135 connect(nextAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
136 nextAction->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::Forward));
137 prevAction = actionCollection()->addAction("prevhole");
138 prevAction->setIcon(KIcon( QLatin1String( "go-previous" )));
139 prevAction->setText(i18n("&Previous Hole"));
140 connect(prevAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
141 prevAction->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::Back));
142 firstAction = actionCollection()->addAction("firsthole");
143 firstAction->setIcon(KIcon( QLatin1String( "go-home" )));
144 firstAction->setText(i18n("&First Hole"));
145 connect(firstAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
146 firstAction->setShortcuts(KStandardShortcut::shortcut(KStandardShortcut::Begin));
147 lastAction = actionCollection()->addAction("lasthole");
148 lastAction->setText(i18n("&Last Hole"));
149 connect(lastAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
150 lastAction->setShortcut(Qt::CTRL+Qt::SHIFT+Qt::Key_End); // why not KStandardShortcut::End (Ctrl+End)?
151 randAction = actionCollection()->addAction("randhole");
152 randAction->setIcon(KIcon( QLatin1String( "go-jump" )));
153 randAction->setText(i18n("&Random Hole"));
154 connect(randAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
155
156 // Settings
157 useMouseAction = new KToggleAction(i18n("Enable &Mouse for Moving Putter"), this);
158 actionCollection()->addAction("usemouse", useMouseAction);
159 connect(useMouseAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
160 connect(useMouseAction, SIGNAL(toggled(bool)), this, SLOT(useMouseChanged(bool)));
161 KConfigGroup configGroup(KGlobal::config(), "Settings");
162 useMouseAction->setChecked(configGroup.readEntry("useMouse", true));
163
164 useAdvancedPuttingAction = new KToggleAction(i18n("Enable &Advanced Putting"), this);
165 actionCollection()->addAction("useadvancedputting", useAdvancedPuttingAction);
166 connect(useAdvancedPuttingAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
167 connect(useAdvancedPuttingAction, SIGNAL(toggled(bool)), this, SLOT(useAdvancedPuttingChanged(bool)));
168 useAdvancedPuttingAction->setChecked(configGroup.readEntry("useAdvancedPutting", false));
169
170 showInfoAction = new KToggleAction(KIcon( QLatin1String( "help-about")), i18n("Show &Info"), this);
171 actionCollection()->addAction("showinfo", showInfoAction);
172 connect(showInfoAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
173 showInfoAction->setShortcut(Qt::CTRL+Qt::Key_I);
174 connect(showInfoAction, SIGNAL(toggled(bool)), this, SLOT(showInfoChanged(bool)));
175 showInfoAction->setChecked(configGroup.readEntry("showInfo", true));
176
177 showGuideLineAction = new KToggleAction(i18n("Show Putter &Guideline"), this);
178 actionCollection()->addAction("showguideline", showGuideLineAction);
179 connect(showGuideLineAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
180 connect(showGuideLineAction, SIGNAL(toggled(bool)), this, SLOT(showGuideLineChanged(bool)));
181 showGuideLineAction->setChecked(configGroup.readEntry("showGuideLine", true));
182
183 KToggleAction *act = new KToggleAction(i18n("Enable All Dialog Boxes"), this);
184 actionCollection()->addAction("enableAll", act);
185 connect(act, SIGNAL(triggered(bool)), SLOT(enableAllMessages()));
186
187 soundAction = new KToggleAction(i18n("Play &Sounds"), this);
188 actionCollection()->addAction("sound", soundAction);
189 connect(soundAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
190 connect(soundAction, SIGNAL(toggled(bool)), this, SLOT(soundChanged(bool)));
191 soundAction->setChecked(configGroup.readEntry("sound", true));
192
193 aboutAction = actionCollection()->addAction("aboutcourse");
194 aboutAction->setText(i18n("&About Course"));
195 connect(aboutAction, SIGNAL(triggered(bool)), SLOT(emptySlot()));
196 tutorialAction = actionCollection()->addAction("tutorial");
197 tutorialAction->setText(i18n("&Tutorial"));
198 connect(tutorialAction, SIGNAL(triggered(bool)), SLOT(tutorial()));
199
200 setupGUI();
201}
202
203bool KolfWindow::queryClose()
204{
205 if (game)
206 if (game->askSave(true))
207 return false;
208 return true;
209}
210
211void KolfWindow::startNewGame()
212{
213 NewGameDialog *dialog = 0;
214 int firstHole = 1;
215
216 if (loadedGame.isNull())
217 {
218 dialog = new NewGameDialog(filename.isNull());
219 if (dialog->exec() != QDialog::Accepted)
220 goto end;
221 }
222
223 players.clear();
224 delete scoreboard;
225 scoreboard = new ScoreBoard(dummy);
226 layout->addWidget(scoreboard, 1, 0);
227 scoreboard->show();
228
229 if (loadedGame.isNull())
230 {
231 PlayerEditor *curEditor = 0;
232 int newId = 1;
233 for (curEditor = dialog->players()->at(newId-1); newId <= dialog->players()->count(); ++newId)
234 {
235 players.append(Player());
236 players.last().ball()->setColor(dialog->players()->at(newId-1)->color());
237 players.last().setName(dialog->players()->at(newId-1)->name());
238 players.last().setId(newId);
239 }
240
241 competition = dialog->competition();
242 filename = filename.isNull()? dialog->course() : filename;
243 }
244 else
245 {
246 KConfig config(loadedGame);
247 KConfigGroup configGroup(config.group("0 Saved Game"));
248
249 if (isTutorial)
250 filename = KGlobal::dirs()->findResource("appdata", "tutorial.kolf");
251 else
252 filename = configGroup.readEntry("Course", QString());
253
254 if (filename.isNull())
255 return;
256
257 competition = configGroup.readEntry("Competition", false);
258 firstHole = configGroup.readEntry("Current Hole", 1);
259
260 players.clear();
261 KolfGame::scoresFromSaved(&config, players);
262 }
263
264 for (PlayerList::Iterator it = players.begin(); it != players.end(); ++it)
265 scoreboard->newPlayer((*it).name());
266
267 delete spacer;
268 spacer = 0;
269 delete game;
270 game = new KolfGame(m_itemFactory, &players, filename, dummy);
271 game->setStrict(competition);
272
273 connect(game, SIGNAL(newHole(int)), scoreboard, SLOT(newHole(int)));
274 connect(game, SIGNAL(scoreChanged(int,int,int)), scoreboard, SLOT(setScore(int,int,int)));
275 connect(game, SIGNAL(parChanged(int,int)), scoreboard, SLOT(parChanged(int,int)));
276 connect(game, SIGNAL(modifiedChanged(bool)), this, SLOT(updateModified(bool)));
277 connect(game, SIGNAL(newPlayersTurn(Player*)), this, SLOT(newPlayersTurn(Player*)));
278 connect(game, SIGNAL(holesDone()), this, SLOT(gameOver()));
279 connect(game, SIGNAL(checkEditing()), this, SLOT(checkEditing()));
280 connect(game, SIGNAL(editingStarted()), this, SLOT(editingStarted()));
281 connect(game, SIGNAL(editingEnded()), this, SLOT(editingEnded()));
282 connect(game, SIGNAL(inPlayStart()), this, SLOT(inPlayStart()));
283 connect(game, SIGNAL(inPlayEnd()), this, SLOT(inPlayEnd()));
284 connect(game, SIGNAL(maxStrokesReached(QString)), this, SLOT(maxStrokesReached(QString)));
285 connect(game, SIGNAL(largestHole(int)), this, SLOT(updateHoleMenu(int)));
286 connect(game, SIGNAL(titleChanged(QString)), this, SLOT(titleChanged(QString)));
287 connect(game, SIGNAL(newStatusText(QString)), this, SLOT(newStatusText(QString)));
288 connect(game, SIGNAL(currentHole(int)), this, SLOT(setCurrentHole(int)));
289 connect(holeAction, SIGNAL(triggered(QString)), game, SLOT(switchHole(QString)));
290 connect(nextAction, SIGNAL(triggered(bool)), game, SLOT(nextHole()));
291 connect(prevAction, SIGNAL(triggered(bool)), game, SLOT(prevHole()));
292 connect(firstAction, SIGNAL(triggered(bool)), game, SLOT(firstHole()));
293 connect(lastAction, SIGNAL(triggered(bool)), game, SLOT(lastHole()));
294 connect(randAction, SIGNAL(triggered(bool)), game, SLOT(randHole()));
295 connect(editingAction, SIGNAL(triggered(bool)), game, SLOT(toggleEditMode()));
296 connect(newHoleAction, SIGNAL(triggered(bool)), game, SLOT(addNewHole()));
297 connect(clearHoleAction, SIGNAL(triggered(bool)), game, SLOT(clearHole()));
298 connect(resetHoleAction, SIGNAL(triggered(bool)), game, SLOT(resetHole()));
299 connect(undoShotAction, SIGNAL(triggered(bool)), game, SLOT(undoShot()));
300 //connect(replayShotAction, SIGNAL(triggered(bool)), game, SLOT(replay()));
301 connect(aboutAction, SIGNAL(triggered(bool)), game, SLOT(showInfoDlg()));
302 connect(useMouseAction, SIGNAL(toggled(bool)), game, SLOT(setUseMouse(bool)));
303 connect(useAdvancedPuttingAction, SIGNAL(toggled(bool)), game, SLOT(setUseAdvancedPutting(bool)));
304 connect(soundAction, SIGNAL(toggled(bool)), game, SLOT(setSound(bool)));
305 connect(showGuideLineAction, SIGNAL(toggled(bool)), game, SLOT(setShowGuideLine(bool)));
306 connect(showInfoAction, SIGNAL(toggled(bool)), game, SLOT(setShowInfo(bool)));
307
308 game->setUseMouse(useMouseAction->isChecked());
309 game->setUseAdvancedPutting(useAdvancedPuttingAction->isChecked());
310 game->setShowInfo(showInfoAction->isChecked());
311 game->setShowGuideLine(showGuideLineAction->isChecked());
312 game->setSound(soundAction->isChecked());
313
314 layout->addWidget(game, 0, 0);//, Qt::AlignCenter);
315
316 game->show();
317 game->setFocus();
318
319 setEditingEnabled(true);
320 endAction->setEnabled(true);
321 setHoleMovementEnabled(true);
322 setHoleOtherEnabled(true);
323 aboutAction->setEnabled(true);
324 highScoreAction->setEnabled(true);
325 saveAction->setEnabled(true);
326 saveAsAction->setEnabled(true);
327 saveGameAction->setEnabled(true);
328 saveGameAsAction->setEnabled(true);
329
330 clearHoleAction->setEnabled(false);
331 newHoleAction->setEnabled(false);
332 newAction->setEnabled(false);
333 loadGameAction->setEnabled(false);
334 tutorialAction->setEnabled(false);
335
336 // so game can do stuff that needs to be done
337 // after things above are connected
338 game->startFirstHole(firstHole);
339
340 end:
341 delete dialog;
342}
343
344void KolfWindow::newGame()
345{
346 isTutorial = false;
347 filename = QString();
348 startNewGame();
349}
350
351void KolfWindow::tutorial()
352{
353 QString newfilename = KGlobal::dirs()->findResource("appdata", "tutorial.kolfgame");
354 if (newfilename.isNull())
355 return;
356
357 filename = QString();
358 loadedGame = newfilename;
359 isTutorial = true;
360
361 startNewGame();
362
363 loadedGame = QString();
364}
365
366void KolfWindow::closeGame()
367{
368 if (game)
369 {
370 if (game->askSave(true))
371 return;
372 game->pause();
373 }
374
375 filename = QString();
376
377 editingEnded();
378 delete game;
379 game = 0;
380 loadedGame = QString();
381
382 editingAction->setChecked(false);
383 setEditingEnabled(false);
384 endAction->setEnabled(false);
385 aboutAction->setEnabled(false);
386 highScoreAction->setEnabled(false);
387 saveAction->setEnabled(false);
388 saveAsAction->setEnabled(false);
389 saveGameAction->setEnabled(false);
390 saveGameAsAction->setEnabled(false);
391 setHoleMovementEnabled(false);
392 setHoleOtherEnabled(false);
393
394 clearHoleAction->setEnabled(false);
395 newHoleAction->setEnabled(false);
396 newAction->setEnabled(true);
397 loadGameAction->setEnabled(true);
398 tutorialAction->setEnabled(true);
399
400 titleChanged(QString());
401 updateModified(false);
402
403 QTimer::singleShot(100, this, SLOT(createSpacer()));
404}
405
406void KolfWindow::createSpacer()
407{
408 // make a player to play the spacer hole
409 spacerPlayers.clear();
410 spacerPlayers.append(Player());
411 spacerPlayers.last().ball()->setColor(Qt::yellow);
412 spacerPlayers.last().setName("player");
413 spacerPlayers.last().setId(1);
414
415 delete spacer;
416 spacer = new KolfGame(m_itemFactory, &spacerPlayers, KGlobal::dirs()->findResource("appdata", "intro"), dummy);
417 spacer->setSound(false);
418 layout->addWidget(spacer, 0, 0);//, Qt::AlignCenter);
419 spacer->ignoreEvents(true);
420
421 spacer->show();
422 spacer->startFirstHole(1);
423 spacer->hidePutter();
424}
425
426void KolfWindow::gameOver()
427{
428 int curPar = 0;
429 int lowScore = INT_MAX; // let's hope it doesn't stay this way!
430 int curScore = 1;
431
432 // names of people who had the lowest score
433 QStringList names;
434
435 HighScoreList highScores;
436 int scoreBoardIndex = 1;
437
438 while (curScore != 0)
439 {
440 QString curName;
441
442 // name taken as a reference and filled out
443 curScore = scoreboard->total(scoreBoardIndex, curName);
444
445 scoreBoardIndex++;
446
447 if (curName == i18n("Par"))
448 {
449 curPar = curScore;
450 curScore = 0;
451 continue;
452 }
453
454 if (curScore == 0)
455 continue;
456
457 // attempt to add everybody to the highscore list
458 // (ignored if we aren't competing down below)
459 highScores.append(HighScore(curName, curScore));
460
461 if (curScore < lowScore)
462 {
463 names.clear();
464 lowScore = curScore;
465 names.append(curName);
466 }
467 else if (curScore == lowScore)
468 names.append(curName);
469 }
470
471 // only announce a winner if more than two entries
472 // (player and par) are on the scoreboard + one to go past end
473 // + 1 for koodoo
474 if (scoreBoardIndex > 4)
475 {
476 if (names.count() > 1)
477 {
478 QString winners = names.join( i18n(" and " ));
479 KMessageBox::information(this, i18n("%1 tied", winners));
480 }
481 else
482 KMessageBox::information(this, i18n("%1 won!", names.first()));
483 }
484
485 if (competition)
486 {
487 // deal with highscores
488 // KScoreDialog makes it very easy :-))
489
490 KScoreDialog *scoreDialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Custom1 | KScoreDialog::Score, this);
491 scoreDialog->addField(KScoreDialog::Custom1, i18n("Par"), "Par");
492
493 CourseInfo courseInfo;
494 game->courseInfo(courseInfo, game->curFilename());
495
496 scoreDialog->setConfigGroup(courseInfo.untranslatedName + QString(" Highscores"));
497
498 for (HighScoreList::Iterator it = highScores.begin(); it != highScores.end(); ++it)
499 {
500 KScoreDialog::FieldInfo info;
501 info[KScoreDialog::Name] = (*it).name;
502 info[KScoreDialog::Score].setNum((*it).score);
503 info[KScoreDialog::Custom1] = QString::number(curPar);
504
505 scoreDialog->addScore(info, KScoreDialog::LessIsMore);
506 }
507
508 scoreDialog->setComment(i18n("High Scores for %1", courseInfo.name));
509 scoreDialog->show();
510 }
511
512 QTimer::singleShot(700, this, SLOT(closeGame()));
513}
514
515void KolfWindow::showHighScores()
516{
517 KScoreDialog *scoreDialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Custom1 | KScoreDialog::Score, this);
518 scoreDialog->addField(KScoreDialog::Custom1, i18n("Par"), "Par");
519
520 CourseInfo courseInfo;
521 game->courseInfo(courseInfo, game->curFilename());
522
523 scoreDialog->setConfigGroup(courseInfo.untranslatedName + QString(" Highscores"));
524 scoreDialog->setComment(i18n("High Scores for %1", courseInfo.name));
525 scoreDialog->show();
526}
527
528void KolfWindow::save()
529{
530 if (filename.isNull())
531 {
532 saveAs();
533 return;
534 }
535
536 if (game) {
537 game->save();
538 game->setFocus();
539 }
540}
541
542void KolfWindow::saveAs()
543{
544 QString newfilename = KFileDialog::getSaveFileName( KUrl("kfiledialog:///kourses"),
545 "application/x-kourse", this, i18n("Pick Kolf Course to Save To"));
546 if (!newfilename.isNull())
547 {
548 filename = newfilename;
549 game->setFilename(filename);
550 game->save();
551 game->setFocus();
552 }
553}
554
555void KolfWindow::saveGameAs()
556{
557 QString newfilename = KFileDialog::getSaveFileName( KUrl("kfiledialog:///savedkolf"),
558 "application/x-kolf", this, i18n("Pick Saved Game to Save To"));
559 if (newfilename.isNull())
560 return;
561
562 loadedGame = newfilename;
563
564 saveGame();
565}
566
567void KolfWindow::saveGame()
568{
569 if (loadedGame.isNull())
570 {
571 saveGameAs();
572 return;
573 }
574
575 KConfig config(loadedGame);
576 KConfigGroup configGroup(config.group("0 Saved Game"));
577
578 configGroup.writeEntry("Competition", competition);
579 configGroup.writeEntry("Course", filename);
580
581 game->saveScores(&config);
582
583 configGroup.sync();
584}
585
586void KolfWindow::loadGame()
587{
588 loadedGame = KFileDialog::getOpenFileName( KUrl("kfiledialog:///savedkolf"),
589 QLatin1String("application/x-kolf"), this, i18n("Pick Kolf Saved Game"));
590
591 if (loadedGame.isNull())
592 return;
593
594 isTutorial = false;
595 startNewGame();
596}
597
598// called by main for command line files
599void KolfWindow::openUrl(KUrl url)
600{
601 QString target;
602 if (KIO::NetAccess::download(url, target, this))
603 {
604 isTutorial = false;
605 QString mimeType = KMimeType::findByPath(target)->name();
606 if (mimeType == "application/x-kourse")
607 filename = target;
608 else if (mimeType == "application/x-kolf")
609 loadedGame = target;
610 else
611 {
612 closeGame();
613 return;
614 }
615
616 QTimer::singleShot(10, this, SLOT(startNewGame()));
617 }
618 else
619 closeGame();
620}
621
622void KolfWindow::newPlayersTurn(Player *player)
623{
624 tempStatusBarText = i18n("%1's turn", player->name());
625
626 if (showInfoAction->isChecked())
627 statusBar()->showMessage(tempStatusBarText, 5 * 1000);
628 else
629 statusBar()->showMessage(tempStatusBarText);
630
631 scoreboard->setCurrentCell(player->id() - 1, game->currentHole() - 1);
632}
633
634void KolfWindow::newStatusText(const QString &text)
635{
636 if (text.isEmpty())
637 statusBar()->showMessage(tempStatusBarText);
638 else
639 statusBar()->showMessage(text);
640}
641
642void KolfWindow::editingStarted()
643{
644 delete editor;
645 editor = new Editor(m_itemFactory, dummy);
646 editor->setObjectName( QLatin1String( "Editor" ) );
647 connect(editor, SIGNAL(addNewItem(QString)), game, SLOT(addNewObject(QString)));
648 connect(editor, SIGNAL(changed()), game, SLOT(setModified()));
649 connect(editor, SIGNAL(addNewItem(QString)), this, SLOT(setHoleFocus()));
650 connect(game, SIGNAL(newSelectedItem(CanvasItem*)), editor, SLOT(setItem(CanvasItem*)));
651
652 scoreboard->hide();
653
654 layout->addWidget(editor, 1, 0);
655 editor->show();
656
657 clearHoleAction->setEnabled(true);
658 newHoleAction->setEnabled(true);
659 setHoleOtherEnabled(false);
660
661 game->setFocus();
662}
663
664void KolfWindow::editingEnded()
665{
666 delete editor;
667 editor = 0;
668
669 if (scoreboard)
670 scoreboard->show();
671
672 clearHoleAction->setEnabled(false);
673 newHoleAction->setEnabled(false);
674 setHoleOtherEnabled(true);
675
676 if (game)
677 game->setFocus();
678}
679
680void KolfWindow::inPlayStart()
681{
682 setEditingEnabled(false);
683 setHoleOtherEnabled(false);
684 setHoleMovementEnabled(false);
685}
686
687void KolfWindow::inPlayEnd()
688{
689 setEditingEnabled(true);
690 setHoleOtherEnabled(true);
691 setHoleMovementEnabled(true);
692}
693
694void KolfWindow::maxStrokesReached(const QString &name)
695{
696 KMessageBox::sorry(this, i18n("%1's score has reached the maximum for this hole.", name));
697}
698
699void KolfWindow::updateHoleMenu(int largest)
700{
701 QStringList items;
702 for (int i = 1; i <= largest; ++i)
703 items.append(QString::number(i));
704
705 // setItems for some reason enables the action
706 bool shouldbe = holeAction->isEnabled();
707 holeAction->setItems(items);
708 holeAction->setEnabled(shouldbe);
709}
710
711void KolfWindow::setHoleMovementEnabled(bool yes)
712{
713 if (competition)
714 yes = false;
715
716 holeAction->setEnabled(yes);
717
718 nextAction->setEnabled(yes);
719 prevAction->setEnabled(yes);
720 firstAction->setEnabled(yes);
721 lastAction->setEnabled(yes);
722 randAction->setEnabled(yes);
723}
724
725void KolfWindow::setHoleOtherEnabled(bool yes)
726{
727 if (competition)
728 yes = false;
729
730 resetHoleAction->setEnabled(yes);
731 undoShotAction->setEnabled(yes);
732 //replayShotAction->setEnabled(yes);
733}
734
735void KolfWindow::setEditingEnabled(bool yes)
736{
737 editingAction->setEnabled(competition? false : yes);
738}
739
740void KolfWindow::checkEditing()
741{
742 editingAction->setChecked(true);
743}
744
745void KolfWindow::updateModified(bool mod)
746{
747 courseModified = mod;
748 titleChanged(title);
749}
750
751void KolfWindow::titleChanged(const QString &newTitle)
752{
753 title = newTitle;
754 setCaption(title, courseModified);
755}
756
757void KolfWindow::useMouseChanged(bool yes)
758{
759 KConfigGroup configGroup(KGlobal::config(), "Settings"); configGroup.writeEntry("useMouse", yes); configGroup.sync();
760}
761
762void KolfWindow::useAdvancedPuttingChanged(bool yes)
763{
764 KConfigGroup configGroup(KGlobal::config(), "Settings"); configGroup.writeEntry("useAdvancedPutting", yes); configGroup.sync();
765}
766
767void KolfWindow::showInfoChanged(bool yes)
768{
769 KConfigGroup configGroup(KGlobal::config(), "Settings"); configGroup.writeEntry("showInfo", yes); configGroup.sync();
770}
771
772void KolfWindow::showGuideLineChanged(bool yes)
773{
774 KConfigGroup configGroup(KGlobal::config(), "Settings"); configGroup.writeEntry("showGuideLine", yes); configGroup.sync();
775}
776
777void KolfWindow::soundChanged(bool yes)
778{
779 KConfigGroup configGroup(KGlobal::config(), "Settings"); configGroup.writeEntry("sound", yes); configGroup.sync();
780}
781
782void KolfWindow::enableAllMessages()
783{
784 KMessageBox::enableAllMessages();
785}
786
787void KolfWindow::setCurrentHole(int hole)
788{
789 if (!holeAction || holeAction->items().count() < hole)
790 return;
791 // Golf is 1-based, KListAction is 0-based
792 holeAction->setCurrentItem(hole - 1);
793}
794
795#include "kolf.moc"
796