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 "newgame.h" |
21 | #include "game.h" |
22 | |
23 | #include <QBoxLayout> |
24 | #include <QLabel> |
25 | #include <QListWidget> |
26 | #include <KFileDialog> |
27 | #include <KMessageBox> |
28 | #include <KPushButton> |
29 | #include <KScoreDialog> |
30 | #include <KSeparator> |
31 | #include <KStandardDirs> |
32 | |
33 | NewGameDialog::NewGameDialog(bool enableCourses) |
34 | : KPageDialog() |
35 | { |
36 | setCaption(i18n("New Game" )); |
37 | setButtons(Ok | Cancel); |
38 | setDefaultButton(Ok); |
39 | setMinimumSize(640,310); |
40 | connect(this, SIGNAL(okClicked()), this, SLOT(slotOk())); |
41 | |
42 | setFaceType(KPageDialog::Tree); |
43 | this->enableCourses = enableCourses; |
44 | |
45 | KSharedConfig::Ptr config = KGlobal::config(); |
46 | // following use this group |
47 | KConfigGroup configGroup(config->group(QString("New Game Dialog Mode" ))); |
48 | |
49 | // lots o' colors :) |
50 | startColors << Qt::blue << Qt::red << Qt::yellow << Qt::lightGray << Qt::cyan << Qt::darkBlue << Qt::magenta << Qt::darkGray << Qt::darkMagenta << Qt::darkYellow; |
51 | |
52 | playerPage = new QFrame(); |
53 | addPage(playerPage, i18n("Players" )); |
54 | |
55 | QVBoxLayout *bigLayout = new QVBoxLayout(playerPage); |
56 | bigLayout->setMargin( marginHint() ); |
57 | bigLayout->setSpacing( spacingHint() ); |
58 | |
59 | addButton = new KPushButton(i18n("&New Player" ), playerPage); |
60 | bigLayout->addWidget(addButton); |
61 | |
62 | connect(addButton, SIGNAL(clicked()), this, SLOT(addPlayer())); |
63 | |
64 | scroller = new QScrollArea(playerPage); |
65 | bigLayout->addWidget(scroller); |
66 | playersWidget = new QWidget(playerPage); |
67 | scroller->setWidget(playersWidget); |
68 | new QVBoxLayout(playersWidget); |
69 | |
70 | QMap<QString, QString> entries = config->entryMap("New Game Dialog" ); |
71 | int i = 0; |
72 | for (QMap<QString, QString>::Iterator it = entries.begin(); it != entries.end(); ++it) |
73 | { |
74 | if (i > startColors.count()) |
75 | return; |
76 | |
77 | addPlayer(); |
78 | editors.last()->setName(it.key().right(it.key().length() - 1)); |
79 | editors.last()->setColor(QColor(it.value())); |
80 | ++i; |
81 | } |
82 | |
83 | if (editors.isEmpty()) |
84 | { |
85 | addPlayer(); |
86 | addPlayer(); |
87 | } |
88 | |
89 | enableButtons(); |
90 | KPageWidgetItem *pageItem =0L; |
91 | if (enableCourses) |
92 | { |
93 | coursePage = new QFrame(); |
94 | pageItem = new KPageWidgetItem( coursePage, i18n("Choose Course to Play" ) ); |
95 | pageItem->setHeader(i18n("Course" )); |
96 | addPage(pageItem); |
97 | QVBoxLayout *coursePageLayout = new QVBoxLayout(coursePage); |
98 | coursePageLayout->setMargin( marginHint() ); |
99 | coursePageLayout->setSpacing( spacingHint() ); |
100 | |
101 | QHBoxLayout *hlayout = new QHBoxLayout; |
102 | hlayout->setSpacing( spacingHint() ); |
103 | coursePageLayout->addLayout( hlayout ); |
104 | |
105 | |
106 | // find other courses |
107 | externCourses = configGroup.readEntry("extra" ,QStringList()); |
108 | |
109 | /// course loading |
110 | const QStringList items = externCourses + KGlobal::dirs()->findAllResources("appdata" , "courses/*" ); |
111 | QStringList nameList; |
112 | const QString lastCourse(configGroup.readEntry("course" , "" )); |
113 | int curItem = 0; |
114 | i = 0; |
115 | for (QStringList::const_iterator it = items.begin(); it != items.end(); ++it, ++i) |
116 | { |
117 | QString file = *it; |
118 | CourseInfo curinfo; |
119 | KolfGame::courseInfo(curinfo, file); |
120 | info[file] = curinfo; |
121 | names.append(file); |
122 | nameList.append(curinfo.name); |
123 | |
124 | if (lastCourse == file) |
125 | curItem = i; |
126 | } |
127 | |
128 | const QString newName(i18n("Create New" )); |
129 | info[QString()] = CourseInfo(newName, newName, i18n("You" ), 0, 0); |
130 | names.append(QString()); |
131 | nameList.append(newName); |
132 | |
133 | courseList = new QListWidget(coursePage); |
134 | hlayout->addWidget(courseList); |
135 | courseList->addItems(nameList); |
136 | courseList->setCurrentRow(curItem); |
137 | connect(courseList, SIGNAL(currentRowChanged(int)), this, SLOT(courseSelected(int))); |
138 | connect(courseList, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged())); |
139 | |
140 | QVBoxLayout *detailLayout = new QVBoxLayout; |
141 | detailLayout->setSpacing( spacingHint() ); |
142 | hlayout->addLayout( detailLayout ); |
143 | name = new QLabel(coursePage); |
144 | detailLayout->addWidget(name); |
145 | author = new QLabel(coursePage); |
146 | detailLayout->addWidget(author); |
147 | |
148 | QHBoxLayout *minorLayout = new QHBoxLayout; |
149 | minorLayout->setSpacing( spacingHint() ); |
150 | detailLayout->addLayout( minorLayout ); |
151 | par = new QLabel(coursePage); |
152 | minorLayout->addWidget(par); |
153 | holes = new QLabel(coursePage); |
154 | minorLayout->addWidget(holes); |
155 | |
156 | detailLayout->addStretch(); |
157 | KPushButton *scores = new KPushButton(i18n("Highscores" ), coursePage); |
158 | connect(scores, SIGNAL(clicked()), this, SLOT(showHighscores())); |
159 | detailLayout->addWidget(scores); |
160 | |
161 | detailLayout->addStretch(); |
162 | detailLayout->addWidget(new KSeparator(coursePage)); |
163 | |
164 | minorLayout = new QHBoxLayout; |
165 | minorLayout->setSpacing( spacingHint() ); |
166 | detailLayout->addLayout( minorLayout ); |
167 | |
168 | KPushButton *addCourseButton = new KPushButton(i18n("Add..." ), coursePage); |
169 | minorLayout->addWidget(addCourseButton); |
170 | connect(addCourseButton, SIGNAL(clicked()), this, SLOT(addCourse())); |
171 | |
172 | remove = new KPushButton(i18n("Remove" ), coursePage); |
173 | minorLayout->addWidget(remove); |
174 | connect(remove, SIGNAL(clicked()), this, SLOT(removeCourse())); |
175 | |
176 | courseSelected(curItem); |
177 | selectionChanged(); |
178 | } |
179 | |
180 | // options page |
181 | optionsPage = new QFrame(); |
182 | pageItem = new KPageWidgetItem( optionsPage, i18n("Game Options" ) ); |
183 | pageItem->setHeader(i18n("Options" )); |
184 | addPage(pageItem); |
185 | |
186 | QVBoxLayout *vlayout = new QVBoxLayout(optionsPage); |
187 | vlayout->setMargin( marginHint() ); |
188 | vlayout->setSpacing( spacingHint() ); |
189 | |
190 | mode = new QCheckBox(i18n("&Strict mode" ), optionsPage); |
191 | vlayout->addWidget(mode); |
192 | mode->setChecked(configGroup.readEntry("competition" , false)); |
193 | |
194 | QLabel *desc = new QLabel(i18n("In strict mode, undo, editing, and switching holes is not allowed. This is generally for competition. Only in strict mode are highscores kept." ), optionsPage); |
195 | desc->setTextFormat(Qt::RichText); |
196 | desc->setWordWrap(true); |
197 | vlayout->addWidget(desc); |
198 | } |
199 | |
200 | NewGameDialog::~NewGameDialog() |
201 | { |
202 | qDeleteAll(editors); |
203 | } |
204 | |
205 | void NewGameDialog::slotOk() |
206 | { |
207 | KSharedConfig::Ptr config = KGlobal::config(); |
208 | KConfigGroup configGroup(config->group(QString("New Game Dialog Mode" ))); |
209 | |
210 | configGroup.writeEntry("competition" , mode->isChecked()); |
211 | if (enableCourses) |
212 | { |
213 | configGroup.writeEntry("course" , currentCourse); |
214 | configGroup.writeEntry("extra" , externCourses); |
215 | } |
216 | |
217 | config->deleteGroup("New Game Dialog" ); |
218 | |
219 | PlayerEditor *curEditor = 0; |
220 | int i = 0; |
221 | for (; i < editors.count(); ++i) { |
222 | curEditor = editors.at(i); |
223 | configGroup.writeEntry(QString::number(i) + curEditor->name(), curEditor->color().name()); |
224 | } |
225 | |
226 | config->sync(); |
227 | |
228 | KDialog::accept(); |
229 | } |
230 | |
231 | void NewGameDialog::courseSelected(int index) |
232 | { |
233 | //BUG 274418: select first course if nothing selected (should not happen, but meh) |
234 | if (index < 0) |
235 | index = 0; |
236 | currentCourse = names.at(index); |
237 | |
238 | CourseInfo &curinfo = info[currentCourse]; |
239 | |
240 | name->setText(QString("<strong>%1</strong>" ).arg(curinfo.name)); |
241 | |
242 | author->setText(i18n("By %1" , curinfo.author)); |
243 | par->setText(i18n("Par %1" , curinfo.par)); |
244 | holes->setText(i18n("%1 Holes" , curinfo.holes)); |
245 | } |
246 | |
247 | void NewGameDialog::showHighscores() |
248 | { |
249 | KScoreDialog *scoreDialog = new KScoreDialog(KScoreDialog::Name | KScoreDialog::Custom1 | KScoreDialog::Score, this); |
250 | scoreDialog->addField(KScoreDialog::Custom1, i18n("Par" ), "Par" ); |
251 | scoreDialog->setConfigGroup(info[currentCourse].untranslatedName + QString(" Highscores" )); |
252 | scoreDialog->setComment(i18n("High Scores for %1" , info[currentCourse].name)); |
253 | scoreDialog->show(); |
254 | } |
255 | |
256 | void NewGameDialog::removeCourse() |
257 | { |
258 | QListWidgetItem* curItem = courseList->currentItem(); |
259 | if (!curItem) |
260 | return; |
261 | |
262 | QString file = curItem->text(); |
263 | if (!externCourses.contains(file)) |
264 | return; |
265 | |
266 | names.removeAll(file); |
267 | externCourses.removeAll(file); |
268 | delete courseList->takeItem(courseList->currentRow()); |
269 | |
270 | selectionChanged(); |
271 | } |
272 | |
273 | void NewGameDialog::selectionChanged() |
274 | { |
275 | QListWidgetItem* curItem = courseList->currentItem(); |
276 | remove->setEnabled(curItem && externCourses.contains(curItem->text())); |
277 | } |
278 | |
279 | void NewGameDialog::addCourse() |
280 | { |
281 | const QStringList files = KFileDialog::getOpenFileNames( KUrl("kfiledialog:///kourses" ), |
282 | QString::fromLatin1("application/x-kourse" ), this, i18n("Pick Kolf Course" )); |
283 | |
284 | bool hasDuplicates = false; |
285 | |
286 | for (QStringList::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) |
287 | { |
288 | if (names.contains(*fileIt) > 0) |
289 | { |
290 | hasDuplicates = true; |
291 | continue; |
292 | } |
293 | |
294 | CourseInfo curinfo; |
295 | KolfGame::courseInfo(curinfo, *fileIt); |
296 | info[*fileIt] = curinfo; |
297 | names.prepend(*fileIt); |
298 | externCourses.prepend(*fileIt); |
299 | |
300 | courseList->insertItem(0, new QListWidgetItem(curinfo.name)); |
301 | } |
302 | |
303 | if (hasDuplicates) |
304 | KMessageBox::information(this, i18n("Chosen course is already on course list." )); |
305 | |
306 | courseList->setCurrentItem(0); |
307 | courseSelected(0); |
308 | selectionChanged(); |
309 | } |
310 | |
311 | void NewGameDialog::addPlayer() |
312 | { |
313 | if (editors.count() >= startColors.count()) |
314 | return; |
315 | |
316 | |
317 | PlayerEditor *pe = new PlayerEditor(i18n("Player %1" , editors.count() + 1), startColors.at(editors.count()), playersWidget); |
318 | editors.append(pe); |
319 | pe->show(); |
320 | playersWidget->layout()->addWidget(pe); |
321 | connect(pe, SIGNAL(deleteEditor(PlayerEditor*)), this, SLOT(deleteEditor(PlayerEditor*))); |
322 | |
323 | enableButtons(); |
324 | playersWidget->setMinimumSize(playersWidget->sizeHint()); |
325 | } |
326 | |
327 | void NewGameDialog::deleteEditor(PlayerEditor *editor) |
328 | { |
329 | if (editors.count() < 2) |
330 | return; |
331 | |
332 | editors.removeAll(editor); |
333 | delete editor; |
334 | |
335 | enableButtons(); |
336 | playersWidget->setMinimumSize(playersWidget->sizeHint()); |
337 | playersWidget->resize(playersWidget->sizeHint()); |
338 | } |
339 | |
340 | void NewGameDialog::enableButtons() |
341 | { |
342 | addButton->setEnabled(!(editors.count() >= startColors.count())); |
343 | } |
344 | |
345 | ///////////////////////// |
346 | |
347 | PlayerEditor::PlayerEditor(QString startName, QColor startColor, QWidget *parent) |
348 | : QWidget(parent) |
349 | { |
350 | QHBoxLayout *layout = new QHBoxLayout(this); |
351 | layout->setMargin( KDialog::spacingHint() ); |
352 | |
353 | editor = new KLineEdit(this); |
354 | layout->addWidget(editor); |
355 | editor->setFrame(false); |
356 | editor->setText(startName); |
357 | layout->addStretch(); |
358 | layout->addWidget(colorButton = new KColorButton(startColor, this)); |
359 | colorButton->hide(); |
360 | KPushButton *remove = new KPushButton(i18n("Remove" ), this); |
361 | layout->addWidget(remove); |
362 | connect(remove, SIGNAL(clicked()), this, SLOT(removeMe())); |
363 | } |
364 | |
365 | void PlayerEditor::removeMe() |
366 | { |
367 | emit deleteEditor(this); |
368 | } |
369 | |
370 | #include "newgame.moc" |
371 | |