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