1 /***************************************************************************
2 * Copyright 2007 Johannes Bergmeier <johannes.bergmeier@gmx.net> *
3 * Copyright 2015 Ian Wadham <iandw.au@gmail.com> *
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 *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
20 #include "welcomescreen.h"
21
22
23 #include <KConfigGroup>
24 #include <KMessageBox>
25 #include <KSharedConfig>
26
27 #include "ksudokugame.h"
28 #include "globals.h"
29 #include "puzzle.h"
30
31 Q_DECLARE_METATYPE(ksudoku::GameVariant*)
32
33 namespace ksudoku {
34
WelcomeScreen(QWidget * parent,GameVariantCollection * collection)35 WelcomeScreen::WelcomeScreen(QWidget* parent, GameVariantCollection* collection)
36 : QFrame(parent), m_collection(collection)
37 {
38 setupUi(this); // Get gameListWidget by loading from welcomescreen.ui.
39
40 // Set the screen to display a multi-column list of puzzle-types, with
41 // vertical scrolling. GameVariantDelegate::sizeHint() calculates the
42 // number of columns and their width when it works out the size of the
43 // item's display-area.
44
45 QItemDelegate* delegate =
46 new GameVariantDelegate(this, gameListWidget->viewport());
47 gameListWidget->setWrapping(true);
48 gameListWidget->setResizeMode(QListView::Adjust);
49 gameListWidget->setUniformItemSizes(true);
50 gameListWidget->setFlow(QListView::LeftToRight);
51
52 // Avoid a resize loop (with the scrollbar appearing and disappearing)
53 // if ever the number of items and display-columns hits a bad combo.
54 gameListWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
55
56 gameListWidget->setModel(m_collection);
57 gameListWidget->setItemDelegate(delegate);
58 gameListWidget->setVerticalScrollMode(QListView::ScrollPerPixel);
59 gameListWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
60 gameListWidget->setSelectionMode(QAbstractItemView::SingleSelection);
61
62 // Get the previous puzzle configuration.
63 KConfigGroup gameGroup (KSharedConfig::openConfig(), "KSudokuGame");
64 m_selectedPuzzle = gameGroup.readEntry("SelectedPuzzle", 0);
65 m_difficulty = gameGroup.readEntry("Difficulty", (int) VeryEasy);
66 m_symmetry = gameGroup.readEntry("Symmetry" , (int) CENTRAL);
67
68 // This has to be a deferred call (presumably to allow the view's setup
69 // to complete), otherwise the selection fails to appear.
70 QMetaObject::invokeMethod (this, "setSelectedVariant",
71 Qt::QueuedConnection,
72 Q_ARG (int, m_selectedPuzzle));
73
74 connect(gameListWidget->selectionModel(), &QItemSelectionModel::currentChanged, this, &WelcomeScreen::onCurrentVariantChange);
75
76 connect(getNewGameButton, &QPushButton::clicked, this, &WelcomeScreen::getNewVariant);
77 // TODO disabled due to missing per-game config dialog
78 // connect(configureGameButton, SIGNAL(clicked(bool)), this, SLOT(configureVariant()));
79 // connect(playGameButton, SIGNAL(clicked(bool)), this, SLOT(playVariant())); // Disable old create-game code.
80 // connect(gameListWidget, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(playVariant())); // Disable old create-game code.
81
82 connect(startEmptyButton, &QPushButton::clicked, this, &WelcomeScreen::startEmptyGame);
83 connect(puzzleGeneratorButton, &QPushButton::clicked, this, &WelcomeScreen::generatePuzzle);
84 connect(gameListWidget, &QListView::doubleClicked, this, &WelcomeScreen::generatePuzzle);
85
86 // GHNS is not implemented yet, so don't show an unuseful button
87 getNewGameButton->hide();
88 }
89
selectedVariant() const90 GameVariant* WelcomeScreen::selectedVariant() const {
91 QModelIndex index = gameListWidget->currentIndex();
92 return m_collection->variant(index);
93 }
94
setSelectedVariant(int row)95 void WelcomeScreen::setSelectedVariant(int row) {
96 gameListWidget->setCurrentIndex(gameListWidget->model()->index(row,0));
97 }
98
difficulty() const99 int WelcomeScreen::difficulty() const {
100 return m_difficulty;
101 }
102
setDifficulty(int difficulty)103 void WelcomeScreen::setDifficulty(int difficulty) {
104 m_difficulty = difficulty;
105 }
106
symmetry() const107 int WelcomeScreen::symmetry() const {
108 return m_symmetry;
109 }
110
setSymmetry(int symmetry)111 void WelcomeScreen::setSymmetry(int symmetry) {
112 m_symmetry = symmetry;
113 }
114
onCurrentVariantChange()115 void WelcomeScreen::onCurrentVariantChange() {
116 GameVariant* variant = selectedVariant();
117 if(!variant) {
118 // TODO disabled due to missing per-game config dialog
119 // configureGameButton->setEnabled(false);
120 // playGameButton->setEnabled(false);
121 puzzleGeneratorButton->setEnabled(false);
122 return;
123 }
124
125 // TODO disabled due to missing per-game config dialog
126 // configureGameButton->setEnabled(variant->canConfigure());
127 startEmptyButton->setEnabled(variant->canStartEmpty());
128 // playGameButton->setEnabled(true);
129 puzzleGeneratorButton->setEnabled(true);
130 }
131
getNewVariant()132 void WelcomeScreen::getNewVariant() {
133 KMessageBox::information(this, i18n("GetNewVariant not implemented"), QLatin1String(""));
134 }
135
configureVariant()136 void WelcomeScreen::configureVariant() {
137 GameVariant* variant = selectedVariant();
138 if(!variant) return;
139
140 variant->configure();
141 }
142
startEmptyGame()143 void WelcomeScreen::startEmptyGame() {
144 GameVariant* variant = selectedVariant();
145 if(!variant) {
146 KMessageBox::sorry(this, i18n("Please select a puzzle variant."), i18n("Unable to start puzzle"));
147 return;
148 }
149
150 Game game = variant->startEmpty();
151 if (! game.isValid()) {
152 KMessageBox::sorry(this, i18n("Unable to create an empty puzzle of the chosen variant; please try another."), i18n("Unable to start puzzle"));
153 return;
154 }
155
156 Q_EMIT newGameStarted(game, variant);
157 }
158
playVariant()159 void WelcomeScreen::playVariant() {
160 return; // Disable old game-creation code.
161 GameVariant* variant = selectedVariant();
162 if(!variant) {
163 KMessageBox::sorry(this, i18n("Please select a puzzle variant."), i18n("Unable to start puzzle"));
164 return;
165 }
166
167 Game game = variant->createGame(difficulty(), 0);
168 if(!game.isValid()) {
169 KMessageBox::sorry(this, i18n("Unable to start a puzzle of the chosen variant; please try another."), i18n("Unable to start puzzle"));
170 return;
171 }
172
173 Q_EMIT newGameStarted(game, variant);
174 }
175
generatePuzzle()176 void WelcomeScreen::generatePuzzle() {
177 GameVariant* variant = selectedVariant();
178 if(!variant) {
179 KMessageBox::sorry(this, i18n("Please select a puzzle variant."), i18n("Unable to start puzzle"));
180 return;
181 }
182
183 Game game = variant->createGame(difficulty(), symmetry());
184 if(!game.isValid()) {
185 KMessageBox::sorry(this, i18n("Unable to generate a puzzle of the chosen variant; please try another."), i18n("Unable to start puzzle"));
186 return;
187 }
188
189 // Save the selected puzzle configuration.
190 QModelIndex index = gameListWidget->currentIndex();
191 m_selectedPuzzle = index.row();
192
193 KConfigGroup gameGroup (KSharedConfig::openConfig(), "KSudokuGame");
194 gameGroup.writeEntry("SelectedPuzzle", m_selectedPuzzle);
195 gameGroup.writeEntry("Difficulty", m_difficulty);
196 gameGroup.writeEntry("Symmetry" , m_symmetry);
197 gameGroup.sync(); // Ensure that the entry goes to disk.
198
199 // If the user abandoned puzzle-generation, stay on the Welcome Screen
200 // and allow the user to change the Difficulty, etc. of the puzzle.
201 if (game.puzzle()->hasSolution()) {
202 Q_EMIT newGameStarted(game, variant); // OK, start playing.
203 }
204 }
205
206 }
207
208
209