File indexing completed on 2024-12-22 03:51:29
0001 /* 0002 Copyright (C) 2002-2005, Jason Katz-Brown <jasonkb@mit.edu> 0003 Copyright 2010 Stefan Majewsky <majewsky@gmx.net> 0004 0005 This program is free software; you can redistribute it and/or modify 0006 it under the terms of the GNU General Public License as published by 0007 the Free Software Foundation; either version 2 of the License, or 0008 (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0013 GNU General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; if not, write to the Free Software 0017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 0018 */ 0019 0020 #include "newgame.h" 0021 #include "game.h" 0022 0023 #include <QFileDialog> 0024 #include <QLabel> 0025 #include <QListWidget> 0026 #include <QPushButton> 0027 #include <QStandardPaths> 0028 #include <QVBoxLayout> 0029 0030 #include <KLocalizedString> 0031 #include <KMessageBox> 0032 #include <KSeparator> 0033 #include <KSharedConfig> 0034 0035 #include <KGameHighScoreDialog> 0036 0037 NewGameDialog::NewGameDialog(bool enableCourses) 0038 : KPageDialog() 0039 { 0040 setWindowTitle(i18nc("@title:window", "New Game")); 0041 buttonBox()->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 0042 setMinimumSize(640,310); 0043 connect(buttonBox(), &QDialogButtonBox::accepted, this, &NewGameDialog::slotOk); 0044 0045 setFaceType(KPageDialog::Tree); 0046 this->enableCourses = enableCourses; 0047 0048 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0049 // following use this group 0050 KConfigGroup configGroup(config->group(QStringLiteral("New Game Dialog Mode"))); 0051 0052 // lots o' colors :) 0053 startColors << Qt::blue << Qt::red << Qt::yellow << Qt::lightGray << Qt::cyan << Qt::darkBlue << Qt::magenta << Qt::darkGray << Qt::darkMagenta << Qt::darkYellow; 0054 0055 playerPage = new QFrame(); 0056 addPage(playerPage, i18n("Players")); 0057 0058 QVBoxLayout *bigLayout = new QVBoxLayout(playerPage); 0059 0060 addButton = new QPushButton(i18n("&New Player"), playerPage); 0061 bigLayout->addWidget(addButton); 0062 0063 connect(addButton, &QPushButton::clicked, this, &NewGameDialog::addPlayer); 0064 0065 scroller = new QScrollArea(playerPage); 0066 bigLayout->addWidget(scroller); 0067 playersWidget = new QWidget(playerPage); 0068 scroller->setWidget(playersWidget); 0069 new QVBoxLayout(playersWidget); 0070 0071 QMap<QString, QString> entries = config->entryMap(QStringLiteral("New Game Dialog")); 0072 int i = 0; 0073 for (QMap<QString, QString>::Iterator it = entries.begin(); it != entries.end(); ++it) 0074 { 0075 if (i > startColors.count()) 0076 return; 0077 0078 addPlayer(); 0079 editors.last()->setName(it.key().right(it.key().length() - 1)); 0080 editors.last()->setColor(QColor(it.value())); 0081 ++i; 0082 } 0083 0084 if (editors.isEmpty()) 0085 { 0086 addPlayer(); 0087 addPlayer(); 0088 } 0089 0090 enableButtons(); 0091 KPageWidgetItem *pageItem =nullptr; 0092 if (enableCourses) 0093 { 0094 coursePage = new QFrame(); 0095 pageItem = new KPageWidgetItem( coursePage, i18n("Course") ); 0096 pageItem->setHeader(i18n("Choose Course to Play")); 0097 addPage(pageItem); 0098 QVBoxLayout *coursePageLayout = new QVBoxLayout(coursePage); 0099 0100 QHBoxLayout *hlayout = new QHBoxLayout; 0101 coursePageLayout->addLayout( hlayout ); 0102 0103 0104 // find other courses 0105 externCourses = configGroup.readEntry("extra",QStringList()); 0106 0107 /// course loading 0108 QStringList files; 0109 const QStringList dirs = QStandardPaths::locateAll(QStandardPaths::AppDataLocation, QStringLiteral("courses"), QStandardPaths::LocateDirectory); 0110 for (const QString& dir : dirs) { 0111 const QStringList fileNames = QDir(dir).entryList(QStringList() << QStringLiteral("*"), QDir::Files); 0112 for (const QString& file : fileNames) { 0113 files.append(dir + QLatin1Char('/') + file); 0114 } 0115 } 0116 const QStringList items = externCourses + files; 0117 0118 QStringList nameList; 0119 const QString lastCourse(configGroup.readEntry("course", "")); 0120 int curItem = 0; 0121 i = 0; 0122 for (QStringList::const_iterator it = items.begin(); it != items.end(); ++it, ++i) 0123 { 0124 QString file = *it; 0125 CourseInfo curinfo; 0126 KolfGame::courseInfo(curinfo, file); 0127 info[file] = curinfo; 0128 names.append(file); 0129 nameList.append(curinfo.name); 0130 0131 if (lastCourse == file) 0132 curItem = i; 0133 } 0134 0135 const QString newName(i18n("Create New")); 0136 info[QString()] = CourseInfo(newName, newName, i18n("You"), 0, 0); 0137 names.append(QString()); 0138 nameList.append(newName); 0139 0140 courseList = new QListWidget(coursePage); 0141 hlayout->addWidget(courseList); 0142 courseList->addItems(nameList); 0143 courseList->setCurrentRow(curItem); 0144 connect(courseList, &QListWidget::currentRowChanged, this, &NewGameDialog::courseSelected); 0145 connect(courseList, &QListWidget::itemSelectionChanged, this, &NewGameDialog::selectionChanged); 0146 0147 QVBoxLayout *detailLayout = new QVBoxLayout; 0148 hlayout->addLayout( detailLayout ); 0149 name = new QLabel(coursePage); 0150 detailLayout->addWidget(name); 0151 author = new QLabel(coursePage); 0152 detailLayout->addWidget(author); 0153 0154 QHBoxLayout *minorLayout = new QHBoxLayout; 0155 detailLayout->addLayout( minorLayout ); 0156 par = new QLabel(coursePage); 0157 minorLayout->addWidget(par); 0158 holes = new QLabel(coursePage); 0159 minorLayout->addWidget(holes); 0160 0161 detailLayout->addStretch(); 0162 QPushButton *scores = new QPushButton(i18n("Highscores"), coursePage); 0163 connect(scores, &QPushButton::clicked, this, &NewGameDialog::showHighscores); 0164 detailLayout->addWidget(scores); 0165 0166 detailLayout->addStretch(); 0167 detailLayout->addWidget(new KSeparator(coursePage)); 0168 0169 minorLayout = new QHBoxLayout; 0170 detailLayout->addLayout( minorLayout ); 0171 0172 QPushButton *addCourseButton = new QPushButton(i18n("Add..."), coursePage); 0173 minorLayout->addWidget(addCourseButton); 0174 connect(addCourseButton, &QPushButton::clicked, this, &NewGameDialog::addCourse); 0175 0176 remove = new QPushButton(i18n("Remove"), coursePage); 0177 minorLayout->addWidget(remove); 0178 connect(remove, &QPushButton::clicked, this, &NewGameDialog::removeCourse); 0179 0180 courseSelected(curItem); 0181 selectionChanged(); 0182 } 0183 0184 // options page 0185 optionsPage = new QFrame(); 0186 pageItem = new KPageWidgetItem( optionsPage, i18n("Options") ); 0187 pageItem->setHeader(i18n("Game Options")); 0188 addPage(pageItem); 0189 0190 QVBoxLayout *vlayout = new QVBoxLayout(optionsPage); 0191 0192 mode = new QCheckBox(i18n("&Strict mode"), optionsPage); 0193 vlayout->addWidget(mode); 0194 mode->setChecked(configGroup.readEntry("competition", false)); 0195 0196 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); 0197 desc->setTextFormat(Qt::RichText); 0198 desc->setWordWrap(true); 0199 vlayout->addWidget(desc); 0200 } 0201 0202 NewGameDialog::~NewGameDialog() 0203 { 0204 qDeleteAll(editors); 0205 } 0206 0207 void NewGameDialog::slotOk() 0208 { 0209 KSharedConfig::Ptr config = KSharedConfig::openConfig(); 0210 KConfigGroup configGroup(config->group(QStringLiteral("New Game Dialog Mode"))); 0211 0212 configGroup.writeEntry("competition", mode->isChecked()); 0213 if (enableCourses) 0214 { 0215 configGroup.writeEntry("course", currentCourse); 0216 configGroup.writeEntry("extra", externCourses); 0217 } 0218 0219 config->deleteGroup(QStringLiteral("New Game Dialog")); 0220 0221 PlayerEditor *curEditor = nullptr; 0222 int i = 0; 0223 for (; i < editors.count(); ++i) { 0224 curEditor = editors.at(i); 0225 configGroup.writeEntry(QString::number(i) + curEditor->name(), curEditor->color().name()); 0226 } 0227 0228 config->sync(); 0229 } 0230 0231 void NewGameDialog::courseSelected(int index) 0232 { 0233 //BUG 274418: select first course if nothing selected (should not happen, but meh) 0234 if (index < 0) 0235 index = 0; 0236 currentCourse = names.at(index); 0237 0238 CourseInfo &curinfo = info[currentCourse]; 0239 0240 name->setText(QStringLiteral("<strong>%1</strong>").arg(curinfo.name)); 0241 0242 author->setText(i18n("By %1", curinfo.author)); 0243 par->setText(i18n("Par %1", curinfo.par)); 0244 holes->setText(i18n("%1 Holes", curinfo.holes)); 0245 } 0246 0247 void NewGameDialog::showHighscores() 0248 { 0249 KGameHighScoreDialog *scoreDialog = new KGameHighScoreDialog(KGameHighScoreDialog::Name | KGameHighScoreDialog::Custom1 | KGameHighScoreDialog::Score, this); 0250 scoreDialog->addField(KGameHighScoreDialog::Custom1, i18n("Par"), QStringLiteral("Par")); 0251 scoreDialog->setConfigGroup(qMakePair(QByteArray(info[currentCourse].untranslatedName.toUtf8() + " Highscores"), i18n("High Scores for %1", info[currentCourse].name))); 0252 scoreDialog->setComment(i18n("High Scores for %1", info[currentCourse].name)); 0253 scoreDialog->show(); 0254 } 0255 0256 void NewGameDialog::removeCourse() 0257 { 0258 QListWidgetItem* curItem = courseList->currentItem(); 0259 if (!curItem) 0260 return; 0261 0262 QString file = curItem->text(); 0263 if (!externCourses.contains(file)) 0264 return; 0265 0266 names.removeAll(file); 0267 externCourses.removeAll(file); 0268 delete courseList->takeItem(courseList->currentRow()); 0269 0270 selectionChanged(); 0271 } 0272 0273 void NewGameDialog::selectionChanged() 0274 { 0275 QListWidgetItem* curItem = courseList->currentItem(); 0276 remove->setEnabled(curItem && externCourses.contains(curItem->text())); 0277 } 0278 0279 void NewGameDialog::addCourse() 0280 { 0281 QPointer<QFileDialog> fileLoadDialog = new QFileDialog(this); 0282 fileLoadDialog->setWindowTitle(i18nc("@title:window", "Pick Kolf Course")); 0283 fileLoadDialog->setMimeTypeFilters(QStringList(QStringLiteral("application/x-kourse"))); 0284 fileLoadDialog->setAcceptMode(QFileDialog::AcceptOpen); 0285 fileLoadDialog->setFileMode(QFileDialog::ExistingFile); 0286 fileLoadDialog->exec(); 0287 const QStringList files = fileLoadDialog->selectedFiles(); 0288 delete fileLoadDialog; 0289 0290 bool hasDuplicates = false; 0291 0292 for (QStringList::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) 0293 { 0294 if (names.contains(*fileIt) > 0) 0295 { 0296 hasDuplicates = true; 0297 continue; 0298 } 0299 0300 CourseInfo curinfo; 0301 KolfGame::courseInfo(curinfo, *fileIt); 0302 info[*fileIt] = curinfo; 0303 names.prepend(*fileIt); 0304 externCourses.prepend(*fileIt); 0305 0306 courseList->insertItem(0, new QListWidgetItem(curinfo.name)); 0307 } 0308 0309 if (hasDuplicates) 0310 KMessageBox::information(this, i18n("Chosen course is already on course list.")); 0311 0312 courseList->setCurrentItem(nullptr); 0313 courseSelected(0); 0314 selectionChanged(); 0315 } 0316 0317 void NewGameDialog::addPlayer() 0318 { 0319 if (editors.count() >= startColors.count()) 0320 return; 0321 0322 0323 PlayerEditor *pe = new PlayerEditor(i18n("Player %1", editors.count() + 1), startColors.at(editors.count()), playersWidget); 0324 editors.append(pe); 0325 pe->show(); 0326 playersWidget->layout()->addWidget(pe); 0327 connect(pe, &PlayerEditor::deleteEditor, this, &NewGameDialog::deleteEditor); 0328 0329 enableButtons(); 0330 playersWidget->setMinimumSize(playersWidget->sizeHint()); 0331 } 0332 0333 void NewGameDialog::deleteEditor(PlayerEditor *editor) 0334 { 0335 if (editors.count() < 2) 0336 return; 0337 0338 editors.removeAll(editor); 0339 delete editor; 0340 0341 enableButtons(); 0342 playersWidget->setMinimumSize(playersWidget->sizeHint()); 0343 playersWidget->resize(playersWidget->sizeHint()); 0344 } 0345 0346 void NewGameDialog::enableButtons() 0347 { 0348 addButton->setEnabled(!(editors.count() >= startColors.count())); 0349 } 0350 0351 ///////////////////////// 0352 0353 PlayerEditor::PlayerEditor(const QString &startName, QColor startColor, QWidget *parent) 0354 : QWidget(parent) 0355 { 0356 QHBoxLayout *layout = new QHBoxLayout(this); 0357 0358 editor = new KLineEdit(this); 0359 layout->addWidget(editor); 0360 editor->setFrame(false); 0361 editor->setText(startName); 0362 layout->addStretch(); 0363 layout->addWidget(colorButton = new KColorButton(startColor, this)); 0364 colorButton->hide(); 0365 QPushButton *remove = new QPushButton(i18n("Remove"), this); 0366 layout->addWidget(remove); 0367 connect(remove, &QPushButton::clicked, this, &PlayerEditor::removeMe); 0368 } 0369 0370 void PlayerEditor::removeMe() 0371 { 0372 Q_EMIT deleteEditor(this); 0373 } 0374 0375 #include "moc_newgame.cpp"