00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "kscoredialog.h"
00027 #include "khighscore.h"
00028
00029 #include <KConfig>
00030 #include <KLocale>
00031 #include <KSeparator>
00032 #include <KGlobal>
00033 #include <KConfigGroup>
00034 #include <KTabWidget>
00035 #include <KDebug>
00036
00037 #include <QtCore/QTimer>
00038 #include <QtCore/QList>
00039 #include <QtGui/QGridLayout>
00040 #include <QtGui/QKeyEvent>
00041 #include <QtGui/QLabel>
00042 #include <QtGui/QLayout>
00043 #include <QtGui/QLineEdit>
00044 #include <QtGui/QStackedWidget>
00045
00046 #define DEFAULT_GROUP_NAME I18N_NOOP("High Scores")
00047
00048 typedef QList<KScoreDialog::FieldInfo> GroupScores;
00049
00050 class KScoreDialog::KScoreDialogPrivate
00051 {
00052 public:
00053
00054 QMap<QString, GroupScores> scores;
00055 KTabWidget *tabWidget;
00056
00057
00058 QLineEdit *edit;
00059 QMap<QString, QList<QStackedWidget*> > stack;
00060 QMap<QString, QList<QLabel*> > labels;
00061 QLabel *commentLabel;
00062 QString comment;
00063 int fields;
00064 int hiddenFields;
00065 QPair<QString, int> newName;
00066 QPair<QString, int> latest;
00067 int nrCols;
00068 int numberOfPages;
00069 bool loaded;
00070 QString configGroup;
00071 KHighscore* highscoreObject;
00072
00073 QMap<int, int> col;
00074 QMap<int, QString> header;
00075 QMap<int, QString> key;
00076 QString player;
00077
00078
00079 KScoreDialogPrivate(KScoreDialog* parent):q(parent){}
00080 KScoreDialog* const q;
00081
00082
00083 void loadScores();
00084 void saveScores();
00085
00086 void setupDialog();
00087 void setupGroup(QString& groupName);
00088 void aboutToShow();
00089 };
00090
00091
00092 KScoreDialog::KScoreDialog(int fields, QWidget *parent)
00093 : KDialog(parent), d(new KScoreDialogPrivate(this))
00094 {
00095 setCaption( i18n(DEFAULT_GROUP_NAME) );
00096 setModal( true );
00097 d->highscoreObject = new KHighscore();
00098 d->edit = 0;
00099 fields |= Score;
00100 d->fields = fields;
00101 d->hiddenFields = 0;
00102 d->newName = QPair<QString,int>(QString(),-1);
00103 d->latest = QPair<QString,int>("Null",-1);
00104 d->loaded = false;
00105 d->nrCols = 0;
00106 d->numberOfPages=0;
00107 d->configGroup=QString();
00108
00109
00110 d->header[Name] = i18n("Name");
00111 d->key[Name] = "Name";
00112 d->header[Date] = i18n("Date");
00113 d->key[Date] = "Date";
00114 d->header[Level] = i18n("Level");
00115 d->key[Level] = "Level";
00116 d->header[Score] = i18n("Score");
00117 d->key[Score] = "Score";
00118 d->header[Time] = i18n("Time");
00119 d->key[Time] = "Time";
00120
00121
00122
00123 d->tabWidget = new KTabWidget(this);
00124 d->tabWidget->setTabPosition(QTabWidget::West);
00125
00126 setMainWidget(d->tabWidget);
00127 if(d->newName.second == -1)
00128 setButtons(Close);
00129 else
00130 {
00131 setButtons(Ok|Cancel);
00132 connect(this, SIGNAL(okClicked()), SLOT(slotGotName()));
00133 }
00134 }
00135
00136 KScoreDialog::~KScoreDialog()
00137 {
00138 delete d->highscoreObject;
00139
00140 delete d;
00141 }
00142
00143 void KScoreDialog::setConfigGroup(const QString &group)
00144 {
00145 d->configGroup = group;
00146 d->loaded = false;
00147 }
00148
00149 void KScoreDialog::setComment(const QString &comment)
00150 {
00151 d->comment = comment;
00152 }
00153
00154 void KScoreDialog::addField(int field, const QString &header, const QString &key)
00155 {
00156 d->fields |= field;
00157 d->header[field] = header;
00158 d->key[field] = key;
00159 }
00160
00161 void KScoreDialog::hideField(int field)
00162 {
00163 d->hiddenFields |= field;
00164 }
00165
00166
00167
00168
00169
00170 void KScoreDialog::KScoreDialogPrivate::setupDialog()
00171 {
00172 nrCols = 1;
00173 for(int field = 1; field < fields; field = field * 2)
00174 {
00175 if ( (fields & field) && !(hiddenFields & field ) )
00176 col[field] = nrCols++;
00177 }
00178
00179 tabWidget->clear();
00180 foreach(QString groupName, scores.keys())
00181 setupGroup(groupName);
00182 }
00183
00184 void KScoreDialog::KScoreDialogPrivate::setupGroup(QString& groupName)
00185 {
00186 if(groupName.isEmpty())
00187 tabWidget->addTab(new QWidget(q), i18n(DEFAULT_GROUP_NAME));
00188 else
00189 tabWidget->addTab(new QWidget(q), i18n(groupName.toUtf8()));
00190 tabWidget->setCurrentIndex(tabWidget->count()-1);
00191
00192 QGridLayout* layout = new QGridLayout( tabWidget->widget( tabWidget->currentIndex() ) );
00193
00194 layout->setMargin(marginHint()+20);
00195 layout->setSpacing(spacingHint());
00196 layout->addItem(new QSpacerItem(0, 15), 4, 0);
00197
00198 commentLabel = new QLabel(tabWidget);
00199 commentLabel->setAlignment(Qt::AlignVCenter | Qt::AlignHCenter);
00200
00201 QFont bold = q->font();
00202 bold.setBold(true);
00203
00204 QLabel *label;
00205 layout->addItem(new QSpacerItem(50, 0), 0, 0);
00206 label = new QLabel(i18n("Rank"), tabWidget->widget(tabWidget->currentIndex()));
00207 layout->addWidget(label, 3, 0);
00208 label->setFont(bold);
00209
00210 for(int field = 1; field < fields; field = field * 2)
00211 {
00212 if ( (fields & field) && !(hiddenFields & field ) )
00213 {
00214 layout->addItem( new QSpacerItem( 50, 0 ), 0, col[field] );
00215 label = new QLabel(header[field], tabWidget->widget(tabWidget->currentIndex()));
00216 layout->addWidget(label, 3, col[field], field <= Name ? Qt::AlignLeft : Qt::AlignRight);
00217 label->setFont(bold);
00218 }
00219 }
00220
00221 KSeparator *sep = new KSeparator(Qt::Horizontal, tabWidget->widget(tabWidget->currentIndex()));
00222 layout->addWidget(sep, 4, 0, 1, nrCols);
00223
00224 QString num;
00225 for (int i = 1; i <= 10; ++i)
00226 {
00227 QLabel *label;
00228 num.setNum(i);
00229 label = new QLabel(i18n("#%1", num), tabWidget->widget(tabWidget->currentIndex()));
00230 labels[groupName].insert((i-1)*nrCols + 0, label);
00231 layout->addWidget(label, i+4, 0);
00232 if (fields & Name)
00233 {
00234 QStackedWidget *localStack = new QStackedWidget(tabWidget->widget(tabWidget->currentIndex()));
00235 stack[groupName].insert(i-1, localStack);
00236 layout->addWidget(localStack, i+4, col[Name]);
00237 label = new QLabel(localStack);
00238 labels[groupName].insert((i-1)*nrCols + col[Name], label);
00239 localStack->addWidget(label);
00240 localStack->setCurrentWidget(label);
00241 }
00242 for(int field = Name * 2; field < fields; field = field * 2)
00243 {
00244 if ( (fields & field) && !(hiddenFields & field ) )
00245 {
00246 label = new QLabel(tabWidget->widget(tabWidget->currentIndex()));
00247 labels[groupName].insert((i-1)*nrCols + col[field], label);
00248 layout->addWidget(label, i+4, col[field], Qt::AlignRight);
00249 }
00250 }
00251 }
00252 }
00253
00254
00255
00256
00257
00258 void KScoreDialog::KScoreDialogPrivate::aboutToShow()
00259 {
00260 if (!loaded)
00261 loadScores();
00262
00263 if (!nrCols)
00264 setupDialog();
00265
00266 int tabIndex=0;
00267 int newScoreTabIndex=0;
00268 foreach(QString groupName, scores.keys())
00269 {
00270
00271 if((latest.first == tabWidget->tabText(tabIndex)) || ( latest.first.isEmpty() && tabWidget->tabText(tabIndex) == i18n(DEFAULT_GROUP_NAME) ))
00272 {
00273 newScoreTabIndex=tabIndex;
00274 commentLabel->setText(comment);
00275 if (comment.isEmpty())
00276 {
00277 commentLabel->setMinimumSize(QSize(1,1));
00278 commentLabel->hide();
00279 QGridLayout* layout = qobject_cast<QGridLayout*>(tabWidget->widget(newScoreTabIndex)->layout());
00280 layout->addItem( new QSpacerItem( 0, -15 ), 0, 0 );
00281 layout->addItem( new QSpacerItem( 0, -15 ), 2, 0 );
00282 }
00283 else
00284 {
00285 QGridLayout* layout = qobject_cast<QGridLayout*>(tabWidget->widget(newScoreTabIndex)->layout());
00286 layout->addWidget(commentLabel, 1, 0, 1, nrCols);
00287 commentLabel->setMinimumSize(commentLabel->sizeHint());
00288 commentLabel->show();
00289 layout->addItem( new QSpacerItem( 0, -10 ), 0, 0 );
00290 layout->addItem( new QSpacerItem( 0, 10 ), 2, 0 );
00291 }
00292 comment.clear();
00293 }
00294
00295 QFont normal = q->font();
00296 QFont bold = normal;
00297 bold.setBold(true);
00298
00299 QString num;
00300 for (int i = 1; i <= 10; ++i)
00301 {
00302 QLabel *label;
00303 num.setNum(i);
00304
00305
00306
00307 FieldInfo score = scores[groupName].at(i-1);
00308 label = labels[groupName].at((i-1)*nrCols + 0);
00309 if ( (i == latest.second) && (groupName == latest.first) )
00310 label->setFont(bold);
00311 else
00312 label->setFont(normal);
00313
00314 if (fields & Name)
00315 {
00316 if ( (newName.second == i) && (groupName == newName.first) )
00317 {
00318 QStackedWidget *localStack = stack[groupName].at(i-1);
00319 edit = new QLineEdit(player, localStack);
00320 edit->setMinimumWidth(40);
00321 localStack->addWidget(edit);
00322 localStack->setCurrentWidget(edit);
00323 edit->setFocus();
00324 connect(edit, SIGNAL(returnPressed()), q, SLOT(slotGotReturn()));
00325 }
00326 else
00327 {
00328 label = labels[groupName].at((i-1)*nrCols + col[Name]);
00329 if ( (i == latest.second) && (groupName == latest.first) )
00330 label->setFont(bold);
00331 else
00332 label->setFont(normal);
00333 label->setText(score[Name]);
00334 }
00335
00336 }
00337 for(int field = Name * 2; field < fields; field = field * 2)
00338 {
00339 if ( (fields & field) && !(hiddenFields & field ) )
00340 {
00341 label = labels[groupName].at((i-1)*nrCols + col[field]);
00342 if ( (i == latest.second) && (groupName == latest.first) )
00343 label->setFont(bold);
00344 else
00345 label->setFont(normal);
00346 label->setText(score[field]);
00347 }
00348 }
00349 }
00350 tabIndex++;
00351 }
00352 latest = QPair<QString,int>(QString(),-1);
00353 q->setFixedSize(q->minimumSizeHint());
00354 tabWidget->setCurrentIndex(newScoreTabIndex);
00355 }
00356
00357 void KScoreDialog::KScoreDialogPrivate::loadScores()
00358 {
00359 scores.clear();
00360
00361 QStringList groupList = highscoreObject->groupList();
00362 numberOfPages = groupList.size();
00363
00364 QString tempCurrentGroup = configGroup;
00365
00366 if (groupList.count(configGroup) == 0)
00367 {
00368 kDebug(11002) << "The current high score group \"" << configGroup << "\" isn't in the list, adding it";
00369 groupList << configGroup;
00370 setupGroup(configGroup);
00371 }
00372
00373 foreach(QString groupName, groupList)
00374 {
00375 highscoreObject->setHighscoreGroup(groupName);
00376 player = highscoreObject->readEntry(0, "LastPlayer");
00377
00378 for (int i = 1; i <= 10; ++i)
00379 {
00380 FieldInfo score;
00381 for(int field = 1; field < fields; field = field * 2)
00382 {
00383 if (fields & field)
00384 {
00385 score[field] = highscoreObject->readEntry(i, key[field], QString("-"));
00386 }
00387 }
00388 scores[groupName].append(score);
00389 }
00390 }
00391 highscoreObject->setHighscoreGroup(tempCurrentGroup);
00392 foreach(QString groupName, scores.keys())
00393 {
00394 if( (scores[groupName][0].value(Score)=="-") && (scores.size() > 1) && (latest.first != groupName) )
00395 {
00396 kDebug(11002) << "Removing group \"" << groupName << "\" since it's unused.";
00397 scores.remove(groupName);
00398 }
00399 }
00400 loaded = true;
00401 }
00402
00403 void KScoreDialog::KScoreDialogPrivate::saveScores()
00404 {
00405 highscoreObject->setHighscoreGroup(configGroup.toUtf8());
00406
00407 highscoreObject->writeEntry(0,"LastPlayer", player);
00408
00409 for (int i = 1; i <= 10; ++i)
00410 {
00411 FieldInfo score = scores[configGroup].at(i-1);
00412 for(int field = 1; field < fields; field = field * 2)
00413 {
00414 if (fields & field)
00415 {
00416 highscoreObject->writeEntry(i, key[field], score[field]);
00417 }
00418 }
00419 }
00420 highscoreObject->writeAndUnlock();
00421 }
00422
00423 int KScoreDialog::addScore(const FieldInfo& newInfo, const AddScoreFlags& flags)
00424 {
00425 bool askName=false, lessIsMore=false;
00426 if(flags.testFlag(KScoreDialog::AskName))
00427 askName = true;
00428 if(flags.testFlag(KScoreDialog::LessIsMore))
00429 lessIsMore = true;
00430
00431 d->latest.first = d->configGroup;
00432 if (!d->loaded)
00433 d->loadScores();
00434 d->latest.first = "Null";
00435
00436 for(int i=0; i<d->scores[d->configGroup].size(); i++)
00437 {
00438 FieldInfo score = d->scores[d->configGroup].at(i);
00439 bool ok;
00440 int num_score = score[Score].toLong(&ok);
00441 if (lessIsMore && !ok)
00442 num_score = 1 << 30;
00443
00444 score = FieldInfo(newInfo);
00445 int newScore = score[Score].toInt();
00446 if (((newScore > num_score) && !lessIsMore) ||
00447 ((newScore < num_score) && lessIsMore))
00448 {
00449
00450 d->latest = QPair<QString,int>(d->configGroup,i+1);
00451 d->scores[d->configGroup].insert(i, score);
00452 d->scores[d->configGroup].removeAt(10);
00453
00454 if(score[Name].isEmpty())
00455 askName = true;
00456
00457 if (askName)
00458 {
00459 d->player=score[Name];
00460 d->newName = QPair<QString,int>(d->configGroup,i+1);
00461 }
00462 else
00463 d->saveScores();
00464
00465 if (i == 0)
00466 d->comment = i18n("Excellent!\nYou have a new high score!");
00467 else
00468 d->comment = i18n("Well done!\nYou made it to the high score list!");
00469 return i+1;
00470 }
00471 }
00472 return 0;
00473 }
00474
00475 int KScoreDialog::addScore(int newScore, const AddScoreFlags& flags)
00476 {
00477 FieldInfo scoreInfo;
00478 scoreInfo[Score]=QString::number(newScore);
00479 return addScore(scoreInfo, AskName | flags);
00480 }
00481
00482 void KScoreDialog::show()
00483 {
00484 d->aboutToShow();
00485 KDialog::show();
00486 }
00487
00488 void KScoreDialog::exec()
00489 {
00490 d->aboutToShow();
00491 KDialog::exec();
00492 }
00493
00494 void KScoreDialog::slotGotReturn()
00495 {
00496 QTimer::singleShot(0, this, SLOT(slotGotName()));
00497 }
00498
00499 void KScoreDialog::slotGotName()
00500 {
00501 if (d->newName.second == -1) return;
00502
00503 d->player = d->edit->text();
00504
00505 d->scores[d->newName.first][d->newName.second-1][Name] = d->player;
00506 d->saveScores();
00507
00508 QFont bold = font();
00509 bold.setBold(true);
00510
00511 QLabel *label = d->labels[d->newName.first].at((d->newName.second-1)*d->nrCols + d->col[Name]);
00512 label->setFont(bold);
00513 label->setText(d->player);
00514 d->stack[d->newName.first].at((d->newName.second-1))->setCurrentWidget(label);
00515 delete d->edit;
00516 d->edit = 0;
00517 d->newName = QPair<QString,int>(QString(),-1);
00518 }
00519
00520 int KScoreDialog::highScore()
00521 {
00522 if (!d->loaded)
00523 d->loadScores();
00524
00525 if (!d->scores[d->configGroup].isEmpty())
00526 return d->scores[d->configGroup].first()[Score].toInt();
00527 else
00528 return 0;
00529 }
00530
00531 void KScoreDialog::keyPressEvent(QKeyEvent *ev)
00532 {
00533 if ((d->newName.second != -1) && (ev->key() == Qt::Key_Return))
00534 {
00535 ev->ignore();
00536 return;
00537 }
00538 KDialog::keyPressEvent(ev);
00539 }
00540
00541 #include "kscoredialog.moc"