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