• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

libkdegames/highscore

kscoredialog.cpp

Go to the documentation of this file.
00001 /****************************************************************
00002 Copyright (c) 1998 Sandro Sigala <ssigala@globalnet.it>.
00003 Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
00004 Copyright (c) 2007 Matt Williams <matt@milliams.com>
00005 All rights reserved.
00006 
00007 Permission to use, copy, modify, and distribute this software
00008 and its documentation for any purpose and without fee is hereby
00009 granted, provided that the above copyright notice appear in all
00010 copies and that both that the copyright notice and this
00011 permission notice and warranty disclaimer appear in supporting
00012 documentation, and that the name of the author not be used in
00013 advertising or publicity pertaining to distribution of the
00014 software without specific, written prior permission.
00015 
00016 The author disclaim all warranties with regard to this
00017 software, including all implied warranties of merchantability
00018 and fitness.  In no event shall the author be liable for any
00019 special, indirect or consequential damages or any damages
00020 whatsoever resulting from loss of use, data or profits, whether
00021 in an action of contract, negligence or other tortious action,
00022 arising out of or in connection with the use or performance of
00023 this software.
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         //QList<FieldInfo*> scores;
00056         QMap<QByteArray, GroupScores> scores; 
00057         KTabWidget *tabWidget;
00058         //QWidget *page;
00059         //QGridLayout *layout;
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; //index of the newname to add (groupKey, position)
00068         QPair<QByteArray, int> latest; //index of the latest addition (groupKey, position)
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         //Q-Pointer
00082         KScoreDialogPrivate(KScoreDialog* parent):q(parent){}
00083         KScoreDialog* const q;
00084         
00085         //Functions
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; //Make 'Score' field automatic (it can be hidden if necessary)
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     //Set up the default table headers
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     //d->page = new QWidget(this);
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)  //DEPRECATED!
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; //untranslated string
00157     addLocalizedConfigGroupName(group); //add the translation to the list
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) //if this string is the same as the untranslated version in the list
00192         {
00193             return translatedGroupNames.value(groupKey); //return the translated string for the current locale
00194         }
00195     }
00196     //If it wasn't found then just try i18n( to see if it happens to be in the database
00197     return i18n(name); //FIXME?
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 Create the widgets and layouts etc. for the dialog
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()) //If the group doesn't have a name, use a default.
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         //layout->setObjectName("ScoreTab-"+groupName);
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 ) ) //If it's used and not hidden
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); //Fill up column zero
00282             layout->addWidget(label, i+4, 0);
00283             if (fields & Name) //If we have a Name field
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 ) ) //Maybe disable for Name?
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 Fill the dialog with the correct data
00307 */
00308 
00309 void KScoreDialog::KScoreDialogPrivate::aboutToShow()
00310 {
00311     if (!loaded)
00312         loadScores();
00313     
00314     if (!nrCols)
00315         setupDialog();
00316     
00317     int tabIndex=0; //Index of the current tab
00318     int newScoreTabIndex=0; //The index of the tab of the group with the new score
00319     foreach(const QByteArray &groupKey, scores.keys())
00320     {
00321         //Only display the comment on the page with the new score (or) this one if there's only one tab
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             //kDebug() << "groupName:" << groupName << "id:" << i-1;
00357             
00358             FieldInfo score = scores[groupKey].at(i-1);
00359             label = labels[groupKey].at((i-1)*nrCols + 0); //crash! FIXME
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()); //NOTE Remove this line to make dialog resizable
00405     tabWidget->setCurrentIndex(newScoreTabIndex);
00406 }
00407 
00408 void KScoreDialog::KScoreDialogPrivate::loadScores()
00409 {
00410     scores.clear();
00411     
00412     QStringList groupList = highscoreObject->groupList(); //List of the group names actually in the config file
00413     numberOfPages = groupList.size(); //how many groups are in the config fileo
00414     
00415     QList<QByteArray> groupKeyList; //This will be a list of all the groups in the config fie
00416     for(int i = 0; i < numberOfPages; i++)
00417     {
00418         groupKeyList << groupList.at(i).toUtf8(); //Convert all the QStrings to QByteArrays
00419     }
00420     
00421     QByteArray tempCurrentGroup = configGroup; //temp to store the user-set group name
00422     
00423     if (groupKeyList.count(configGroup) == 0) //If the current group doesn't have any entries, add it to the list to process
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");  //FIXME
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); //reset to the user-set group name
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; //Temporarily set this so loadScores() knows not to delete this group
00491     if (!d->loaded)
00492         d->loadScores();
00493     d->latest.first = "Null"; //and reset it.
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); //First look at the score in the config file
00499         bool ok; //will be false if there isn't any score yet in position i
00500         int num_score = score[Score].toLong(&ok); //test if the stored score is a number
00501         
00502         score = FieldInfo(newInfo); //now look at the submitted score
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()) //If we don't have a name, prompt the player.
00516             {
00517                 if(!d->player.isEmpty()) //d->player should be filled out by d->loadScores()
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"

libkdegames/highscore

Skip menu "libkdegames/highscore"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • kblackbox
  • kgoldrunner
  • kmahjongg
  • ksquares
  • libkdegames
  •   highscore
  •   kgame
  •   kggzgames
  •   kggzmod
  •   kggznet
  • libkmahjongg
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal