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
33NewGameDialog::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
200NewGameDialog::~NewGameDialog()
201{
202 qDeleteAll(editors);
203}
204
205void 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
231void 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
247void 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
256void 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
273void NewGameDialog::selectionChanged()
274{
275 QListWidgetItem* curItem = courseList->currentItem();
276 remove->setEnabled(curItem && externCourses.contains(curItem->text()));
277}
278
279void 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
311void 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
327void 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
340void NewGameDialog::enableButtons()
341{
342 addButton->setEnabled(!(editors.count() >= startColors.count()));
343}
344
345/////////////////////////
346
347PlayerEditor::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
365void PlayerEditor::removeMe()
366{
367 emit deleteEditor(this);
368}
369
370#include "newgame.moc"
371