From 14c49c4f56792a934bcdc4efceebbd429d858571 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Sun, 6 Nov 2011 15:56:37 -0600 Subject: Actually move the kde files that were renamed in the last commit --- libtdegames/highscore/INSTALL | 12 + libtdegames/highscore/Makefile.am | 19 + libtdegames/highscore/kconfigrawbackend.cpp | 62 ++ libtdegames/highscore/kconfigrawbackend.h | 58 ++ libtdegames/highscore/kexthighscore.cpp | 289 ++++++++ libtdegames/highscore/kexthighscore.h | 367 ++++++++++ libtdegames/highscore/kexthighscore_gui.cpp | 552 ++++++++++++++ libtdegames/highscore/kexthighscore_gui.h | 215 ++++++ libtdegames/highscore/kexthighscore_internal.cpp | 868 +++++++++++++++++++++++ libtdegames/highscore/kexthighscore_internal.h | 277 ++++++++ libtdegames/highscore/kexthighscore_item.cpp | 312 ++++++++ libtdegames/highscore/kexthighscore_item.h | 317 +++++++++ libtdegames/highscore/kexthighscore_tab.cpp | 281 ++++++++ libtdegames/highscore/kexthighscore_tab.h | 121 ++++ libtdegames/highscore/kfilelock.cpp | 88 +++ libtdegames/highscore/kfilelock.h | 53 ++ libtdegames/highscore/khighscore.cpp | 262 +++++++ libtdegames/highscore/khighscore.h | 312 ++++++++ libtdegames/highscore/kscoredialog.cpp | 411 +++++++++++ libtdegames/highscore/kscoredialog.h | 126 ++++ 20 files changed, 5002 insertions(+) create mode 100644 libtdegames/highscore/INSTALL create mode 100644 libtdegames/highscore/Makefile.am create mode 100644 libtdegames/highscore/kconfigrawbackend.cpp create mode 100644 libtdegames/highscore/kconfigrawbackend.h create mode 100644 libtdegames/highscore/kexthighscore.cpp create mode 100644 libtdegames/highscore/kexthighscore.h create mode 100644 libtdegames/highscore/kexthighscore_gui.cpp create mode 100644 libtdegames/highscore/kexthighscore_gui.h create mode 100644 libtdegames/highscore/kexthighscore_internal.cpp create mode 100644 libtdegames/highscore/kexthighscore_internal.h create mode 100644 libtdegames/highscore/kexthighscore_item.cpp create mode 100644 libtdegames/highscore/kexthighscore_item.h create mode 100644 libtdegames/highscore/kexthighscore_tab.cpp create mode 100644 libtdegames/highscore/kexthighscore_tab.h create mode 100644 libtdegames/highscore/kfilelock.cpp create mode 100644 libtdegames/highscore/kfilelock.h create mode 100644 libtdegames/highscore/khighscore.cpp create mode 100644 libtdegames/highscore/khighscore.h create mode 100644 libtdegames/highscore/kscoredialog.cpp create mode 100644 libtdegames/highscore/kscoredialog.h (limited to 'libtdegames/highscore') diff --git a/libtdegames/highscore/INSTALL b/libtdegames/highscore/INSTALL new file mode 100644 index 00000000..5f9116cf --- /dev/null +++ b/libtdegames/highscore/INSTALL @@ -0,0 +1,12 @@ +Installation notes for the highscore files ; this is only relevant if you +configured libtdegames with option --enable-highscore-dir=DIR (usually DIR is +/var/games) for using system-wide highscore files. + +For each game using the highscore system : + +- the game executable "mygame" should be installed sgid "games" + +- an empty file "mygame.scores" should be created in the directory pointed by +the configuration option. It should be owned by group "games" with read and +write permissions and should -not- be world readable (since it can contains +possibly sensitive information associating username with game usage). diff --git a/libtdegames/highscore/Makefile.am b/libtdegames/highscore/Makefile.am new file mode 100644 index 00000000..6fa18cc0 --- /dev/null +++ b/libtdegames/highscore/Makefile.am @@ -0,0 +1,19 @@ +noinst_LTLIBRARIES = libkhighscore.la + +INCLUDES = $(all_includes) + +libkhighscore_la_SOURCES = kconfigrawbackend.cpp \ + kfilelock.cpp khighscore.cpp kscoredialog.cpp \ + kexthighscore_item.cpp kexthighscore_internal.cpp \ + kexthighscore_tab.cpp kexthighscore_gui.cpp \ + kexthighscore.cpp + +include_HEADERS = khighscore.h kscoredialog.h \ + kexthighscore_item.h kexthighscore.h + +noinst_HEADERS = kconfigrawbackend.h \ + kfilelock.h kexthighscore_internal.h kexthighscore_tab.h \ + kexthighscore_gui.h + +METASOURCES = kconfigrawbackend.moc khighscore.moc kscoredialog.moc \ + kexthighscore_tab.moc kexthighscore_gui.moc diff --git a/libtdegames/highscore/kconfigrawbackend.cpp b/libtdegames/highscore/kconfigrawbackend.cpp new file mode 100644 index 00000000..c2643056 --- /dev/null +++ b/libtdegames/highscore/kconfigrawbackend.cpp @@ -0,0 +1,62 @@ +/* + This file is part of the KDE games library + Copyright (C) 2003 Nicolas Hadacek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kconfigrawbackend.h" +#include "kconfigrawbackend.moc" + +#include +#include + + +KConfigRawBackEnd::KConfigRawBackEnd(KConfigBase *_config, int fd) + : KConfigINIBackEnd(_config, TQString(), "config", false), + _fd(fd), _stream(0) +{ + _file.open(IO_ReadOnly, _fd); +} + +KConfigRawBackEnd::~KConfigRawBackEnd() +{ + if (_stream) fclose(_stream); +} + +bool KConfigRawBackEnd::parseConfigFiles() +{ + _file.reset(); + parseSingleConfigFile(_file); + return true; +} + +void KConfigRawBackEnd::sync(bool bMerge) +{ + // write-sync is only necessary if there are dirty entries + if ( !pConfig->isDirty() || pConfig->isReadOnly() ) return; + + _file.reset(); + KEntryMap aTempMap; + getEntryMap(aTempMap, false, bMerge ? &_file : 0); + + if ( _stream==0 ) { + _stream = fdopen(_fd, "w"); + if ( _stream==0 ) return; + } + ftruncate(_fd, 0); + writeEntries(_stream, aTempMap); + fflush(_stream); +} diff --git a/libtdegames/highscore/kconfigrawbackend.h b/libtdegames/highscore/kconfigrawbackend.h new file mode 100644 index 00000000..6a1ea4b9 --- /dev/null +++ b/libtdegames/highscore/kconfigrawbackend.h @@ -0,0 +1,58 @@ +/* + This file is part of the KDE games library + Copyright (C) 2003 Nicolas Hadacek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef _KCONFIGRAWBACKEND_H +#define _KCONFIGRAWBACKEND_H + +#include + +#include +#include + + +class KConfigRawBackEnd : public KConfigINIBackEnd +{ +public: + KConfigRawBackEnd(KConfigBase *_config, int fd); + ~KConfigRawBackEnd(); + + bool parseConfigFiles(); + + void sync(bool bMerge = true); + +private: + int _fd; + FILE *_stream; + TQFile _file; + + class KConfigRawBackEndPrivate; + KConfigRawBackEndPrivate *d; +}; + +class KRawConfig : public KSimpleConfig +{ + Q_OBJECT + TQ_OBJECT +public: + KRawConfig(int fd, bool readOnly) + : KSimpleConfig(new KConfigRawBackEnd(this, fd), readOnly) {} +}; + + +#endif diff --git a/libtdegames/highscore/kexthighscore.cpp b/libtdegames/highscore/kexthighscore.cpp new file mode 100644 index 00000000..d352a266 --- /dev/null +++ b/libtdegames/highscore/kexthighscore.cpp @@ -0,0 +1,289 @@ +/* + This file is part of the KDE games library + Copyright (C) 2001-2004 Nicolas Hadacek (hadacek@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kexthighscore.h" + +#include + +#include + +#include "kexthighscore_internal.h" +#include "kexthighscore_gui.h" + + +namespace KExtHighscore +{ + +//----------------------------------------------------------------------------- +ManagerPrivate *internal = 0; + +uint gameType() +{ + internal->checkFirst(); + return internal->gameType(); +} + +void setGameType(uint type) +{ + internal->setGameType(type); +} + +bool configure(TQWidget *parent) +{ + internal->checkFirst(); + ConfigDialog *cd = new ConfigDialog(parent); + cd->exec(); + bool saved = cd->hasBeenSaved(); + delete cd; + return saved; +} + +void show(TQWidget *parent, int rank) +{ + HighscoresDialog *hd = new HighscoresDialog(rank, parent); + hd->exec(); + delete hd; +} + +void submitScore(const Score &score, TQWidget *widget) +{ + int rank = internal->submitScore(score, widget, + internal->showMode!=Manager::NeverShow); + + switch (internal->showMode) { + case Manager::AlwaysShow: + show(widget, -1); + break; + case Manager::ShowForHigherScore: + if ( rank!=-1) show(widget, rank); + break; + case Manager::ShowForHighestScore: + if ( rank==0 ) show(widget, rank); + break; + case Manager::NeverShow: + break; + } +} + +void show(TQWidget *widget) +{ + internal->checkFirst(); + show(widget, -1); +} + +Score lastScore() +{ + internal->checkFirst(); + internal->hsConfig().readCurrentConfig(); + uint nb = internal->scoreInfos().maxNbEntries(); + return internal->readScore(nb-1); +} + +Score firstScore() +{ + internal->checkFirst(); + internal->hsConfig().readCurrentConfig(); + return internal->readScore(0); +} + + +//----------------------------------------------------------------------------- +Manager::Manager(uint nbGameTypes, uint maxNbEntries) +{ + Q_ASSERT(nbGameTypes); + Q_ASSERT(maxNbEntries); + if (internal) + kdFatal(11002) << "A highscore object already exists" << endl; + internal = new ManagerPrivate(nbGameTypes, *this); + internal->init(maxNbEntries); +} + +Manager::~Manager() +{ + delete internal; + internal = 0; +} + +void Manager::setTrackLostGames(bool track) +{ + internal->trackLostGames = track; +} + +void Manager::setTrackDrawGames(bool track) +{ + internal->trackDrawGames = track; +} + +void Manager::setShowStatistics(bool show) +{ + internal->showStatistics = show; +} + +void Manager::showStatistics(bool show) +{ + internal->showStatistics = show; +} + +void Manager::setShowDrawGamesStatistic(bool show) +{ + internal->showDrawGames = show; +} + +void Manager::setWWHighscores(const KURL &url, const TQString &version) +{ + Q_ASSERT( url.isValid() ); + internal->serverURL = url; + const char *HS_WW_URL = "ww hs url"; + ConfigGroup cg; + if ( cg.config()->hasKey(HS_WW_URL) ) + internal->serverURL = cg.config()->readEntry(HS_WW_URL); + else cg.config()->writeEntry(HS_WW_URL, url.url()); + internal->version = version; +} + +void Manager::setScoreHistogram(const TQMemArray &scores, + ScoreTypeBound type) +{ + Q_ASSERT( scores.size()>=2 ); + for (uint i=0; iplayerInfos().createHistoItems(scores, type==ScoreBound); +} + +void Manager::setShowMode(ShowMode mode) +{ + internal->showMode = mode; +} + +void Manager::setScoreType(ScoreType type) +{ + switch (type) { + case Normal: + return; + case MinuteTime: { + Item *item = createItem(ScoreDefault); + item->setPrettyFormat(Item::MinuteTime); + setScoreItem(0, item); + + item = createItem(MeanScoreDefault); + item->setPrettyFormat(Item::MinuteTime); + setPlayerItem(MeanScore, item); + + item = createItem(BestScoreDefault); + item->setPrettyFormat(Item::MinuteTime); + setPlayerItem(BestScore, item); + return; + } + } +} + +void Manager::submitLegacyScore(const Score &score) const +{ + internal->submitLocal(score); +} + +bool Manager::isStrictlyLess(const Score &s1, const Score &s2) const +{ + return s1.score()setPrettyFormat(Item::OneDecimal); + item->setPrettySpecial(Item::DefaultNotDefined); + break; + case BestScoreDefault: + item = new Item((uint)0, i18n("Best Score"), TQt::AlignRight); + item->setPrettySpecial(Item::DefaultNotDefined); + break; + case ElapsedTime: + item = new Item((uint)0, i18n("Elapsed Time"), TQt::AlignRight); + item->setPrettyFormat(Item::MinuteTime); + item->setPrettySpecial(Item::ZeroNotDefined); + break; + } + return item; +} + +void Manager::setScoreItem(uint worstScore, Item *item) +{ + item->setDefaultValue(worstScore); + internal->scoreInfos().setItem("score", item); + internal->playerInfos().item("mean score") + ->item()->setDefaultValue(double(worstScore)); + internal->playerInfos().item("best score") + ->item()->setDefaultValue(worstScore); +} + +void Manager::addScoreItem(const TQString &name, Item *item) +{ + internal->scoreInfos().addItem(name, item, true); +} + +void Manager::setPlayerItem(PlayerItemType type, Item *item) +{ + const Item *scoreItem = internal->scoreInfos().item("score")->item(); + uint def = scoreItem->defaultValue().toUInt(); + TQString name; + switch (type) { + case MeanScore: + name = "mean score"; + item->setDefaultValue(double(def)); + break; + case BestScore: + name = "best score"; + item->setDefaultValue(def); + break; + } + internal->playerInfos().setItem(name, item); +} + +TQString Manager::gameTypeLabel(uint gameType, LabelType type) const +{ + if ( gameType!=0 ) + kdFatal(11002) << "You need to reimplement KExtHighscore::Manager for " + << "multiple game types" << endl; + switch (type) { + case Icon: + case Standard: + case I18N: break; + case WW: return "normal"; + } + return TQString(); +} + +void Manager::addToQueryURL(KURL &url, const TQString &item, + const TQString &content) +{ + Q_ASSERT( !item.isEmpty() && url.queryItem(item).isNull() ); + + TQString query = url.query(); + if ( !query.isEmpty() ) query += '&'; + query += item + '=' + KURL::encode_string(content); + url.setQuery(query); +} + +} // namescape diff --git a/libtdegames/highscore/kexthighscore.h b/libtdegames/highscore/kexthighscore.h new file mode 100644 index 00000000..5809a896 --- /dev/null +++ b/libtdegames/highscore/kexthighscore.h @@ -0,0 +1,367 @@ +/* + This file is part of the KDE games library + Copyright (C) 2001-2004 Nicolas Hadacek (hadacek@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXTHIGHSCORE_H +#define KEXTHIGHSCORE_H + +#include "kexthighscore_item.h" + +#include +#include + +class TQTabWidget; + + +namespace KExtHighscore +{ + +class Score; +class Item; + +class ManagerPrivate; +extern ManagerPrivate *internal; + +/** + * Get the current game type. + */ +KDE_EXPORT uint gameType(); + +/** + * Set the current game type. + */ +KDE_EXPORT void setGameType(uint gameType); + +/** + * Configure the highscores. + * @return true if the configuration has been modified and saved + */ +KDE_EXPORT bool configure(TQWidget *parent); + +/** + * Show the highscores lists. + */ +KDE_EXPORT void show(TQWidget *parent); + +/** + * Submit a score. See @ref Manager for usage example. + * + * @param widget a widget used as parent for error message box. + */ +KDE_EXPORT void submitScore(const Score &score, TQWidget *widget); + +/** + * @return the last score in the local list of highscores. The worst possible + * score if there are less items than the maximum number. + */ +KDE_EXPORT Score lastScore(); + +/** + * @return the first score in the local list of highscores (the worst possible + * score if there is no entry). + */ +KDE_EXPORT Score firstScore(); + +/** + * This class manages highscores and players entries (several players can + * share the same highscores list if the libkdegame library is built to + * support a common highscores file; NOTE that to correctly implement such + * feature we probably need a locking mechanism in @ref KHighscore). + * + * You need one instance of this class during the application lifetime ; in + * main() just insert + * \code + * KExtHighscore::Manager highscoresManager; + * \endcode + * with the needed arguments. Use the derived class if you need to + * reimplement some of the default methods. + * + * This class has three functions : + *
    + *
  • Update the highscores list when new entries are submitted
  • + *
  • Display the highscores list and the players list
  • + *
  • Send query to an optionnal web server to support world-wide + * highscores
  • + *
+ * + * The highscores and the players lists contain several items described by + * the @ref Item class. + * + * The highscores list contains by default : + *
    + *
  • the player name (automatically set from the config value)
  • + *
  • the score value
  • + *
  • the time and date of the highscore (automatically set)
  • + *
+ * You can replace the score item (for e.g. displaying it differently) with + * setScoreItem or add an item with addScoreItem. + * + * The players list contains : + *
    + *
  • the player name (as defined by the user in the configuration + * dialog)
  • + *
  • the number of games played
  • + *
  • the mean score
  • + *
  • the best score
  • + *
  • the best score time and date
  • + *
  • the player comment (as defined by the user in the + * configuration dialog)
  • + *
+ * You can replace the best score and the mean score items + * by calling setPlayerItem. + * + * To submit a new score at game end, just construct a Score, set the + * score data and then call submitScore(). + * \code + * KExtHighscore::Score score(KExtHighscore::Won); + * score.setScore(myScore); + * KExtHighscore::submitScore(score, widget); + * \endcode + * You only need to set the score value with Score::setScore() + * and the value of the items that you have optionnally added + * with Score::setData() ; player name and date are set automatically. + */ +class KDE_EXPORT Manager +{ + public: + /** + * Constructor + * + * @param nbGameTypes the number of different game types (usually one). + * For example KMines has easy, normal and expert levels. + * @param maxNbEntries the maximum numbers of highscores entries (by game + * types) + */ + Manager(uint nbGameTypes = 1, uint maxNbEntries = 10); + virtual ~Manager(); + + /** + * Set the world-wide highscores. + * By default there is no world-wide highscores. + * + * Note: should be called at construction time. + * + * @param url the web server url + * @param version the game version which is sent to the web server (it can + * be useful for backward compatibility on the server side). + */ + void setWWHighscores(const KURL &url, const TQString &version); + + /** + * Set if the number of lost games should be track for the world-wide + * highscores statistics. By default, there is no tracking. + * False by default. + * + * Note: should be called at construction time. + */ + void setTrackLostGames(bool track); + + /** + * @since 3.3 + * Set if the number of "draw" games should be track for the world-wide + * highscores statistics. By default, there is no tracking. + * False by default. + * + * Note: should be called at construction time. + */ + void setTrackDrawGames(bool track); + + /** + * @since 3.3 + * Set if the statistics tab should be shown in the highscores dialog. + * You only want to show this tab if it makes sense to lose or to win the + * game (for e.g. it makes no sense for a tetris game but it does for a + * minesweeper game). + * False by default. + * + * Note: should be called at construction time. + */ + void setShowStatistics(bool show); + + /** @obsolete */ + // KDE4 remove this + void showStatistics(bool show) KDE_DEPRECATED; + + /** + * @since 3.3 + * Set if draw games statistics should be shown (enable this if + * draws are possible in your game). + * False by default. + */ + void setShowDrawGamesStatistic(bool show); + + enum ScoreTypeBound { ScoreNotBound, ScoreBound }; + /** + * Set the ranges for the score histogram. + * + * Note: should be called at construction time. + */ + void setScoreHistogram(const TQMemArray &scores, ScoreTypeBound type); + + /** + * Enumerate different conditions under which to show the + * high score dialog. + */ + enum ShowMode { AlwaysShow, ///< Always show the dialog + NeverShow, ///< Never show the dialog + ShowForHigherScore, ///< Show if score has improved + ShowForHighestScore ///< Only for the top spot + }; + /** + * Set how the highscores dialog is shown at game end. + * By default, the mode is ShowForHigherScore. + * + * Note: should be called at construction time. + */ + void setShowMode(ShowMode mode); + + /** + * Score type (@see setScoreType). + * @p Normal default score (unsigned integer without upper bound) + * @p MinuteTime score by time bound at 3599 seconds (for e.g. kmines) + */ + enum ScoreType { Normal, MinuteTime }; + /** + * Set score type. Helper method to quickly set the type of score. + * By default the type is Normal. + * + * Note: should be called at construction time. + */ + void setScoreType(ScoreType type); + + /** + * Some predefined item types. + * @p ScoreDefault default item for the score in the highscores list. + * @p MeanScoreDefault default item for the mean score (only show one decimal and + * 0 is shown as "--". + * @p BestScoreDefault default item for the best score (0 is shown as "--"). + * @p ElapsedTime optionnal item for elapsed time (maximum value is 3599 seconds). + */ + enum ItemType { ScoreDefault, MeanScoreDefault, BestScoreDefault, + ElapsedTime }; + /** + * Create a predefined item. + */ + static Item *createItem(ItemType type); + + /** + * Replace the default score item in the highscores list by the given one. + * @p worstScore is the worst possible score. By default it is 0. + * + * Note : This method should be called at construction time. + */ + void setScoreItem(uint worstScore, Item *item); + + /** + * Add an item in the highscores list (it will add a column to this list). + * + * Note : This method should be called at construction time. + */ + void addScoreItem(const TQString &name, Item *item); + + enum PlayerItemType { MeanScore, BestScore }; + /** + * Replace an item in the players list. + * + * Note : This method should be called at construction time. + */ + void setPlayerItem(PlayerItemType type, Item *item); + + /** + * @return true if the first score is strictly worse than the second one. + * By default return
s1.score(). You can reimplement
+     * this method if additional items added to @ref Score can further
+     * differentiate the scores (for e.g. the time spent).
+     *
+     * Note that you do not need to use directly this method, simply write
+     * 
s1 since the operator calls this method.
+     */
+    virtual bool isStrictlyLess(const Score &s1, const Score &s2) const;
+
+    /**
+     * Possible type of label (@see gameTypeLabel).
+     * @p Standard label used in config file.
+     * @p I18N label used to display the game type.
+     * @p WW label used when contacting the world-wide highscores server.
+     * @p Icon label used to load the icon corresponding to the game type.
+     */
+    enum LabelType { Standard, I18N, WW, Icon };
+
+    /**
+     * @return the label corresponding to the game type. The default
+     * implementation works only for one game type : you need to reimplement
+     * this method if the number of game types is more than one.
+     */
+    virtual TQString gameTypeLabel(uint gameType, LabelType type) const;
+
+ protected:
+    /**
+     * This method is called once for each player (ie for each user). You
+     * can reimplement it to convert old style highscores to the new mechanism
+     * (@see submitLegacyScore). By default this method does nothing.
+     *
+     * @param gameType the game type
+     */
+    virtual void convertLegacy(uint gameType) { Q_UNUSED(gameType); }
+
+    /**
+     * This method should be called from @ref convertLegacy. It is used
+     * to submit an old highscore (it will not be send over the network).
+     * For each score do something like:
+     * \code
+     * Score score(Won);
+     * score.setScore(oldScore);
+     * score.setData("name", name);
+     * submitLegacyScore(score);
+     * \endcode
+     * Note that here you can set the player "name" and the highscore "date"
+     * if they are known.
+     */
+    void submitLegacyScore(const Score &score) const;
+
+    /**
+     * This method is called before submitting a score to the world-wide
+     * highscores server. You can reimplement this method to add an entry
+     * with @ref addToQueryURL. By default this method does nothing.
+     *
+     * @param url the URL to query
+     * @param score the score to be submitted.
+     */
+    virtual void additionalQueryItems(KURL &url, const Score &score) const
+        { Q_UNUSED(url); Q_UNUSED(score); }
+
+    /**
+     * Add an entry to the url to be submitted (@see additionalQueryItems).
+     *
+     * @param url the URL to query
+     * @param item the item name
+     * @param content the item content
+     */
+    static void addToQueryURL(KURL &url, const TQString &item,
+                              const TQString &content);
+
+    friend class ManagerPrivate;
+
+ private:
+    Manager(const Manager &);
+    Manager &operator =(const Manager &);
+};
+
+} // namespace
+
+#endif
diff --git a/libtdegames/highscore/kexthighscore_gui.cpp b/libtdegames/highscore/kexthighscore_gui.cpp
new file mode 100644
index 00000000..02ea99b6
--- /dev/null
+++ b/libtdegames/highscore/kexthighscore_gui.cpp
@@ -0,0 +1,552 @@
+/*
+    This file is part of the KDE games library
+    Copyright (C) 2001-2003 Nicolas Hadacek (hadacek@kde.org)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License version 2 as published by the Free Software Foundation.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "kexthighscore_gui.h"
+#include "kexthighscore_gui.moc"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "kexthighscore_internal.h"
+#include "kexthighscore.h"
+#include "kexthighscore_tab.h"
+
+
+namespace KExtHighscore
+{
+
+//-----------------------------------------------------------------------------
+ShowItem::ShowItem(TQListView *list, bool highlight)
+    : KListViewItem(list), _highlight(highlight)
+{}
+
+void ShowItem::paintCell(TQPainter *p, const TQColorGroup &cg,
+                         int column, int width, int align)
+{
+    TQColorGroup cgrp(cg);
+    if (_highlight) cgrp.setColor(TQColorGroup::Text, red);
+    KListViewItem::paintCell(p, cgrp, column, width, align);
+}
+
+//-----------------------------------------------------------------------------
+ScoresList::ScoresList(TQWidget *parent)
+    : KListView(parent)
+{
+    setSelectionMode(TQListView::NoSelection);
+    setItemMargin(3);
+    setAllColumnsShowFocus(true);
+    setSorting(-1);
+    header()->setClickEnabled(false);
+    header()->setMovingEnabled(false);
+}
+
+void ScoresList::addHeader(const ItemArray &items)
+{
+    addLineItem(items, 0, 0);
+}
+
+TQListViewItem *ScoresList::addLine(const ItemArray &items,
+                                   uint index, bool highlight)
+{
+    TQListViewItem *item = new ShowItem(this, highlight);
+    addLineItem(items, index, item);
+    return item;
+}
+
+void ScoresList::addLineItem(const ItemArray &items,
+                             uint index, TQListViewItem *line)
+{
+    uint k = 0;
+    for (uint i=0; iisVisible() ) continue;
+        if (line) line->setText(k, itemText(container, index));
+        else {
+            addColumn( container.item()->label() );
+            setColumnAlignment(k, container.item()->tqalignment());
+        }
+        k++;
+    }
+}
+
+//-----------------------------------------------------------------------------
+HighscoresList::HighscoresList(TQWidget *parent)
+    : ScoresList(parent)
+{}
+
+TQString HighscoresList::itemText(const ItemContainer &item, uint row) const
+{
+    return item.pretty(row);
+}
+
+void HighscoresList::load(const ItemArray &items, int highlight)
+{
+    clear();
+    TQListViewItem *line = 0;
+    for (int j=items.nbEntries()-1; j>=0; j--) {
+        TQListViewItem *item = addLine(items, j, j==highlight);
+        if ( j==highlight ) line = item;
+    }
+    if (line) ensureItemVisible(line);
+}
+
+//-----------------------------------------------------------------------------
+HighscoresWidget::HighscoresWidget(TQWidget *parent)
+    : TQWidget(parent, "show_highscores_widget"),
+      _scoresUrl(0), _playersUrl(0), _statsTab(0), _histoTab(0)
+{
+    const ScoreInfos &s = internal->scoreInfos();
+    const PlayerInfos &p = internal->playerInfos();
+
+    TQVBoxLayout *vbox = new TQVBoxLayout(this, KDialogBase::spacingHint());
+
+    _tw = new TQTabWidget(this);
+    connect(_tw, TQT_SIGNAL(currentChanged(TQWidget *)), TQT_SLOT(tabChanged()));
+    vbox->addWidget(_tw);
+
+    // scores tab
+    _scoresList = new HighscoresList(_tw);
+    _scoresList->addHeader(s);
+    _tw->addTab(_scoresList, i18n("Best &Scores"));
+
+    // players tab
+    _playersList = new HighscoresList(_tw);
+    _playersList->addHeader(p);
+    _tw->addTab(_playersList, i18n("&Players"));
+
+    // statistics tab
+    if ( internal->showStatistics ) {
+        _statsTab = new StatisticsTab(_tw);
+        _tw->addTab(_statsTab, i18n("Statistics"));
+    }
+
+    // histogram tab
+    if ( p.histogram().size()!=0 ) {
+        _histoTab = new HistogramTab(_tw);
+        _tw->addTab(_histoTab, i18n("Histogram"));
+    }
+
+    // url labels
+    if ( internal->isWWHSAvailable() ) {
+        KURL url = internal->queryURL(ManagerPrivate::Scores);
+        _scoresUrl = new KURLLabel(url.url(),
+                                   i18n("View world-wide highscores"), this);
+        connect(_scoresUrl, TQT_SIGNAL(leftClickedURL(const TQString &)),
+                TQT_SLOT(showURL(const TQString &)));
+        vbox->addWidget(_scoresUrl);
+
+        url = internal->queryURL(ManagerPrivate::Players);
+        _playersUrl = new KURLLabel(url.url(),
+                                    i18n("View world-wide players"), this);
+        connect(_playersUrl, TQT_SIGNAL(leftClickedURL(const TQString &)),
+                TQT_SLOT(showURL(const TQString &)));
+        vbox->addWidget(_playersUrl);
+    }
+}
+
+void HighscoresWidget::changeTab(int i)
+{
+    if ( i!=_tw->currentPageIndex() )
+        _tw->setCurrentPage(i);
+}
+
+void HighscoresWidget::showURL(const TQString &url) const
+{
+    (void)new KRun(KURL(url));
+}
+
+void HighscoresWidget::load(int rank)
+{
+    _scoresList->load(internal->scoreInfos(), rank);
+    _playersList->load(internal->playerInfos(), internal->playerInfos().id());
+    if (_scoresUrl)
+        _scoresUrl->setURL(internal->queryURL(ManagerPrivate::Scores).url());
+    if (_playersUrl)
+        _playersUrl->setURL(internal->queryURL(ManagerPrivate::Players).url());
+    if (_statsTab) _statsTab->load();
+    if (_histoTab) _histoTab->load();
+}
+
+//-----------------------------------------------------------------------------
+HighscoresDialog::HighscoresDialog(int rank, TQWidget *parent)
+    : KDialogBase(internal->nbGameTypes()>1 ? TreeList : Plain,
+                  i18n("Highscores"), Close|User1|User2, Close,
+                  parent, "show_highscores", true, true,
+                  KGuiItem(i18n("Configure..."), "configure"),
+                  KGuiItem(i18n("Export..."))), _rank(rank), _tab(0)
+{
+    _widgets.resize(internal->nbGameTypes(), 0);
+
+    if ( internal->nbGameTypes()>1 ) {
+        for (uint i=0; inbGameTypes(); i++) {
+            TQString title = internal->manager.gameTypeLabel(i, Manager::I18N);
+            TQString icon = internal->manager.gameTypeLabel(i, Manager::Icon);
+            TQWidget *w = addVBoxPage(title, TQString(),
+                                     BarIcon(icon, KIcon::SizeLarge));
+            if ( i==internal->gameType() ) createPage(w);
+        }
+
+        connect(this, TQT_SIGNAL(aboutToShowPage(TQWidget *)),
+                TQT_SLOT(createPage(TQWidget *)));
+        showPage(internal->gameType());
+    } else {
+        TQVBoxLayout *vbox = new TQVBoxLayout(plainPage());
+        createPage(plainPage());
+        vbox->addWidget(_widgets[0]);
+        setMainWidget(_widgets[0]);
+    }
+}
+
+void HighscoresDialog::createPage(TQWidget *page)
+{
+    internal->hsConfig().readCurrentConfig();
+    _current = page;
+    bool several = ( internal->nbGameTypes()>1 );
+    int i = (several ? pageIndex(page) : 0);
+    if ( _widgets[i]==0 ) {
+        _widgets[i] = new HighscoresWidget(page);
+        connect(_widgets[i], TQT_SIGNAL(tabChanged(int)), TQT_SLOT(tabChanged(int)));
+    }
+    uint type = internal->gameType();
+    if (several) internal->setGameType(i);
+    _widgets[i]->load(uint(i)==type ? _rank : -1);
+    if (several) setGameType(type);
+    _widgets[i]->changeTab(_tab);
+}
+
+void HighscoresDialog::slotUser1()
+{
+    if ( KExtHighscore::configure(this) )
+        createPage(_current);
+}
+
+void HighscoresDialog::slotUser2()
+{
+    KURL url = KFileDialog::getSaveURL(TQString(), TQString(), this);
+    if ( url.isEmpty() ) return;
+    if ( KIO::NetAccess::exists(url, true, this) ) {
+        KGuiItem gi = KStdGuiItem::save();
+        gi.setText(i18n("Overwrite"));
+        int res = KMessageBox::warningContinueCancel(this,
+                                 i18n("The file already exists. Overwrite?"),
+                                 i18n("Export"), gi);
+        if ( res==KMessageBox::Cancel ) return;
+    }
+    KTempFile tmp;
+    internal->exportHighscores(*tmp.textStream());
+    tmp.close();
+    KIO::NetAccess::upload(tmp.name(), url, this);
+    tmp.unlink();
+}
+
+//-----------------------------------------------------------------------------
+LastMultipleScoresList::LastMultipleScoresList(
+                            const TQValueVector &scores, TQWidget *parent)
+    : ScoresList(parent), _scores(scores)
+{
+    const ScoreInfos &s = internal->scoreInfos();
+    addHeader(s);
+    for (uint i=0; isetText(i, itemText(*container, index));
+        else {
+            addColumn(  container->item()->label() );
+            setColumnAlignment(i, container->item()->tqalignment());
+        }
+    }
+}
+
+TQString LastMultipleScoresList::itemText(const ItemContainer &item,
+                                         uint row) const
+{
+    TQString name = item.name();
+    if ( name=="rank" )
+        return (_scores[row].type()==Won ? i18n("Winner") : TQString());
+    TQVariant v = _scores[row].data(name);
+    if ( name=="name" ) return v.toString();
+    return item.item()->pretty(row, v);
+}
+
+//-----------------------------------------------------------------------------
+TotalMultipleScoresList::TotalMultipleScoresList(
+                            const TQValueVector &scores, TQWidget *parent)
+    : ScoresList(parent), _scores(scores)
+{
+    const ScoreInfos &s = internal->scoreInfos();
+    addHeader(s);
+    for (uint i=0; iplayerInfos();
+    uint k = 1; // skip "id"
+    for (uint i=0; i<4; i++) { // skip additional fields
+        const ItemContainer *container;
+        if ( i==2 ) container = pi.item("nb games");
+        else if ( i==3 ) container = pi.item("mean score");
+        else {
+            container = si[k];
+            k++;
+        }
+        if (line) line->setText(i, itemText(*container, index));
+        else {
+            TQString label =
+                (i==2 ? i18n("Won Games") : container->item()->label());
+            addColumn(label);
+            setColumnAlignment(i, container->item()->tqalignment());
+        }
+    }
+}
+
+TQString TotalMultipleScoresList::itemText(const ItemContainer &item,
+                                          uint row) const
+{
+    TQString name = item.name();
+    if ( name=="rank" ) return TQString::number(_scores.size()-row);
+    if ( name=="nb games" )
+        return TQString::number( _scores[row].data("nb won games").toUInt() );
+    TQVariant v = _scores[row].data(name);
+    if ( name=="name" ) return v.toString();
+    return item.item()->pretty(row, v);
+}
+
+
+//-----------------------------------------------------------------------------
+ConfigDialog::ConfigDialog(TQWidget *parent)
+    : KDialogBase(Swallow, i18n("Configure Highscores"),
+                  Ok|Apply|Cancel, Cancel,
+                  parent, "configure_highscores", true, true),
+      _saved(false), _WWHEnabled(0)
+{
+    TQWidget *page = 0;
+    TQTabWidget *tab = 0;
+    if ( internal->isWWHSAvailable() ) {
+        tab = new TQTabWidget(this);
+        setMainWidget(tab);
+        page = new TQWidget(tab);
+        tab->addTab(page, i18n("Main"));
+    } else {
+        page = new TQWidget(this);
+        setMainWidget(page);
+    }
+
+    TQGridLayout *pageTop =
+        new TQGridLayout(page, 2, 2, spacingHint(), spacingHint());
+
+    TQLabel *label = new TQLabel(i18n("Nickname:"), page);
+    pageTop->addWidget(label, 0, 0);
+    _nickname = new TQLineEdit(page);
+    connect(_nickname, TQT_SIGNAL(textChanged(const TQString &)),
+            TQT_SLOT(modifiedSlot()));
+    connect(_nickname, TQT_SIGNAL(textChanged(const TQString &)),
+            TQT_SLOT(nickNameChanged(const TQString &)));
+
+    _nickname->setMaxLength(16);
+    pageTop->addWidget(_nickname, 0, 1);
+
+    label = new TQLabel(i18n("Comment:"), page);
+    pageTop->addWidget(label, 1, 0);
+    _comment = new TQLineEdit(page);
+    connect(_comment, TQT_SIGNAL(textChanged(const TQString &)),
+            TQT_SLOT(modifiedSlot()));
+    _comment->setMaxLength(50);
+    pageTop->addWidget(_comment, 1, 1);
+
+    if (tab) {
+        _WWHEnabled
+            = new TQCheckBox(i18n("World-wide highscores enabled"), page);
+        connect(_WWHEnabled, TQT_SIGNAL(toggled(bool)),
+                TQT_SLOT(modifiedSlot()));
+        pageTop->addMultiCellWidget(_WWHEnabled, 2, 2, 0, 1);
+
+        // advanced tab
+        TQWidget *page = new TQWidget(tab);
+        tab->addTab(page, i18n("Advanced"));
+        TQVBoxLayout *pageTop =
+            new TQVBoxLayout(page, spacingHint(), spacingHint());
+
+        TQVGroupBox *group = new TQVGroupBox(i18n("Registration Data"), page);
+        pageTop->addWidget(group);
+        TQGrid *grid = new TQGrid(2, group);
+        grid->setSpacing(spacingHint());
+
+        label = new TQLabel(i18n("Nickname:"), grid);
+        _registeredName = new KLineEdit(grid);
+        _registeredName->setReadOnly(true);
+
+        label = new TQLabel(i18n("Key:"), grid);
+        _key = new KLineEdit(grid);
+        _key->setReadOnly(true);
+
+        KGuiItem gi = KStdGuiItem::clear();
+        gi.setText(i18n("Remove"));
+        _removeButton = new KPushButton(gi, grid);
+        connect(_removeButton, TQT_SIGNAL(clicked()), TQT_SLOT(removeSlot()));
+    }
+
+    load();
+    enableButtonOK( !_nickname->text().isEmpty() );
+    enableButtonApply(false);
+}
+
+void ConfigDialog::nickNameChanged(const TQString &text)
+{
+    enableButtonOK( !text.isEmpty() );
+}
+
+
+void ConfigDialog::modifiedSlot()
+{
+    enableButtonApply(true && !_nickname->text().isEmpty() );
+}
+
+void ConfigDialog::accept()
+{
+    if ( save() ) {
+        KDialogBase::accept();
+        kapp->config()->sync(); // safer
+    }
+}
+
+void ConfigDialog::removeSlot()
+{
+    KGuiItem gi = KStdGuiItem::clear();
+    gi.setText(i18n("Remove"));
+    int res = KMessageBox::warningContinueCancel(this,
+                               i18n("This will permanently remove your "
+                               "registration key. You will not be able to use "
+                               "the currently registered nickname anymore."),
+                               TQString(), gi);
+    if ( res==KMessageBox::Continue ) {
+        internal->playerInfos().removeKey();
+        _registeredName->clear();
+        _key->clear();
+        _removeButton->setEnabled(false);
+        _WWHEnabled->setChecked(false);
+        modifiedSlot();
+    }
+}
+
+void ConfigDialog::load()
+{
+    internal->hsConfig().readCurrentConfig();
+    const PlayerInfos &infos = internal->playerInfos();
+    _nickname->setText(infos.isAnonymous() ? TQString() : infos.name());
+    _comment->setText(infos.comment());
+    if (_WWHEnabled) {
+        _WWHEnabled->setChecked(infos.isWWEnabled());
+        if ( !infos.key().isEmpty() ) {
+            _registeredName->setText(infos.registeredName());
+            _registeredName->home(false);
+            _key->setText(infos.key());
+            _key->home(false);
+        }
+        _removeButton->setEnabled(!infos.key().isEmpty());
+    }
+}
+
+bool ConfigDialog::save()
+{
+    bool enabled = (_WWHEnabled ? _WWHEnabled->isChecked() : false);
+
+    // do not bother the user with "nickname empty" if he has not
+    // messed with nickname settings ...
+    TQString newName = _nickname->text();
+    if ( newName.isEmpty() && !internal->playerInfos().isAnonymous()
+         && !enabled ) return true;
+
+    if ( newName.isEmpty() ) {
+        KMessageBox::sorry(this, i18n("Please choose a non empty nickname."));
+        return false;
+    }
+    if ( internal->playerInfos().isNameUsed(newName) ) {
+        KMessageBox::sorry(this, i18n("Nickname already in use. Please "
+                                      "choose another one"));
+        return false;
+    }
+
+    int res =
+        internal->modifySettings(newName, _comment->text(), enabled, this);
+    if (res) {
+        load(); // needed to update view when "apply" is clicked
+        enableButtonApply(false);
+    }
+    _saved = true;
+    return res;
+}
+
+//-----------------------------------------------------------------------------
+AskNameDialog::AskNameDialog(TQWidget *parent)
+    : KDialogBase(Plain, i18n("Enter Your Nickname"), Ok | Cancel, Ok,
+                  parent, "ask_name_dialog")
+{
+    internal->hsConfig().readCurrentConfig();
+
+    TQVBoxLayout *top =
+        new TQVBoxLayout(plainPage(), marginHint(), spacingHint());
+    TQLabel *label =
+        new TQLabel(i18n("Congratulations, you have won!"), plainPage());
+    top->addWidget(label);
+
+    TQHBoxLayout *hbox = new TQHBoxLayout(top);
+    label = new TQLabel(i18n("Enter your nickname:"), plainPage());
+    hbox->addWidget(label);
+    _edit = new TQLineEdit(plainPage());
+    _edit->setFocus();
+    connect(_edit, TQT_SIGNAL(textChanged(const TQString &)), TQT_SLOT(nameChanged()));
+    hbox->addWidget(_edit);
+
+    top->addSpacing(spacingHint());
+    _checkbox = new TQCheckBox(i18n("Do not ask again."),  plainPage());
+    top->addWidget(_checkbox);
+
+    nameChanged();
+}
+
+void AskNameDialog::nameChanged()
+{
+    enableButtonOK( !name().isEmpty()
+                    && !internal->playerInfos().isNameUsed(name()) );
+}
+
+} // namespace
diff --git a/libtdegames/highscore/kexthighscore_gui.h b/libtdegames/highscore/kexthighscore_gui.h
new file mode 100644
index 00000000..f6b2336a
--- /dev/null
+++ b/libtdegames/highscore/kexthighscore_gui.h
@@ -0,0 +1,215 @@
+/*
+    This file is part of the KDE games library
+    Copyright (C) 2001-02 Nicolas Hadacek (hadacek@kde.org)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License version 2 as published by the Free Software Foundation.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXTHIGHSCORE_GUI_H
+#define KEXTHIGHSCORE_GUI_H
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include "kexthighscore.h"
+
+
+namespace KExtHighscore
+{
+
+class ItemContainer;
+class ItemArray;
+class Score;
+class AdditionalTab;
+
+//-----------------------------------------------------------------------------
+class ShowItem : public KListViewItem
+{
+ public:
+    ShowItem(TQListView *, bool highlight);
+
+ protected:
+    virtual void paintCell(TQPainter *, const TQColorGroup &, int column,
+						   int width, int align);
+
+ private:
+    bool _highlight;
+};
+
+class ScoresList : public KListView
+{
+ Q_OBJECT
+  TQ_OBJECT
+ public:
+    ScoresList(TQWidget *parent);
+
+    void addHeader(const ItemArray &);
+
+ protected:
+    TQListViewItem *addLine(const ItemArray &, uint index, bool highlight);
+    virtual TQString itemText(const ItemContainer &, uint row) const = 0;
+
+ private:
+    virtual void addLineItem(const ItemArray &, uint index,
+                             TQListViewItem *item);
+};
+
+//-----------------------------------------------------------------------------
+class HighscoresList : public ScoresList
+{
+ Q_OBJECT
+  TQ_OBJECT
+ public:
+    HighscoresList(TQWidget *parent);
+
+    void load(const ItemArray &, int highlight);
+
+ protected:
+    TQString itemText(const ItemContainer &, uint row) const;
+};
+
+class HighscoresWidget : public TQWidget
+{
+ Q_OBJECT
+  TQ_OBJECT
+ public:
+    HighscoresWidget(TQWidget *parent);
+
+    void load(int rank);
+
+ signals:
+    void tabChanged(int i);
+
+ public slots:
+    void changeTab(int i);
+
+ private slots:
+    void showURL(const TQString &) const;
+    void tabChanged() { emit tabChanged(_tw->currentPageIndex()); }
+
+ private:
+    TQTabWidget     *_tw;
+    HighscoresList *_scoresList, *_playersList;
+    KURLLabel      *_scoresUrl, *_playersUrl;
+    AdditionalTab  *_statsTab, *_histoTab;
+};
+
+class HighscoresDialog : public KDialogBase
+{
+ Q_OBJECT
+  TQ_OBJECT
+ public:
+    HighscoresDialog(int rank, TQWidget *parent);
+
+ private slots:
+    void slotUser1();
+    void slotUser2();
+    void tabChanged(int i) { _tab = i; }
+    void createPage(TQWidget *);
+
+ private:
+    int _rank, _tab;
+    TQWidget *_current;
+    TQValueVector _widgets;
+};
+
+//-----------------------------------------------------------------------------
+class LastMultipleScoresList : public ScoresList
+{
+    Q_OBJECT
+  TQ_OBJECT
+public:
+    LastMultipleScoresList(const TQValueVector &, TQWidget *parent);
+
+private:
+    void addLineItem(const ItemArray &, uint index, TQListViewItem *line);
+    TQString itemText(const ItemContainer &, uint row) const;
+
+private:
+    const TQValueVector &_scores;
+};
+
+class TotalMultipleScoresList : public ScoresList
+{
+    Q_OBJECT
+  TQ_OBJECT
+public:
+    TotalMultipleScoresList(const TQValueVector &, TQWidget *parent);
+
+private:
+    void addLineItem(const ItemArray &, uint index, TQListViewItem *line);
+    TQString itemText(const ItemContainer &, uint row) const;
+
+private:
+    const TQValueVector &_scores;
+};
+
+//-----------------------------------------------------------------------------
+class ConfigDialog : public KDialogBase
+{
+ Q_OBJECT
+  TQ_OBJECT
+ public:
+    ConfigDialog(TQWidget *parent);
+
+    bool hasBeenSaved() const { return _saved; }
+
+ private slots:
+    void modifiedSlot();
+    void removeSlot();
+    void accept();
+    void slotApply() { save(); }
+    void nickNameChanged(const TQString &);
+
+ private:
+    bool         _saved;
+    TQCheckBox   *_WWHEnabled;
+    TQLineEdit   *_nickname, *_comment;
+    KLineEdit   *_key, *_registeredName;
+    KPushButton *_removeButton;
+
+    void load();
+    bool save();
+};
+
+//-----------------------------------------------------------------------------
+class AskNameDialog : public KDialogBase
+{
+ Q_OBJECT
+  TQ_OBJECT
+ public:
+    AskNameDialog(TQWidget *parent);
+
+    TQString name() const { return _edit->text(); }
+    bool dontAskAgain() const { return _checkbox->isChecked(); }
+
+ private slots:
+    void nameChanged();
+
+ private:
+    TQLineEdit *_edit;
+    TQCheckBox *_checkbox;
+};
+
+} // namespace
+
+#endif
diff --git a/libtdegames/highscore/kexthighscore_internal.cpp b/libtdegames/highscore/kexthighscore_internal.cpp
new file mode 100644
index 00000000..a679002c
--- /dev/null
+++ b/libtdegames/highscore/kexthighscore_internal.cpp
@@ -0,0 +1,868 @@
+/*
+    This file is part of the KDE games library
+    Copyright (C) 2001-2004 Nicolas Hadacek (hadacek@kde.org)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License version 2 as published by the Free Software Foundation.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "kexthighscore_internal.h"
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "config.h"
+#include "kexthighscore.h"
+#include "kexthighscore_gui.h"
+#include "kemailsettings.h"
+
+
+namespace KExtHighscore
+{
+
+//-----------------------------------------------------------------------------
+const char ItemContainer::ANONYMOUS[] = "_";
+const char ItemContainer::ANONYMOUS_LABEL[] = I18N_NOOP("anonymous");
+
+ItemContainer::ItemContainer()
+    : _item(0)
+{}
+
+ItemContainer::~ItemContainer()
+{
+    delete _item;
+}
+
+void ItemContainer::setItem(Item *item)
+{
+    delete _item;
+    _item = item;
+}
+
+TQString ItemContainer::entryName() const
+{
+    if ( _subGroup.isEmpty() ) return _name;
+    return _name + "_" + _subGroup;
+}
+
+TQVariant ItemContainer::read(uint i) const
+{
+    Q_ASSERT(_item);
+
+    TQVariant v = _item->defaultValue();
+    if ( isStored() ) {
+        internal->hsConfig().setHighscoreGroup(_group);
+        v = internal->hsConfig().readPropertyEntry(i+1, entryName(), v);
+    }
+    return _item->read(i, v);
+}
+
+TQString ItemContainer::pretty(uint i) const
+{
+    Q_ASSERT(_item);
+    return _item->pretty(i, read(i));
+}
+
+void ItemContainer::write(uint i, const TQVariant &value) const
+{
+    Q_ASSERT( isStored() );
+    Q_ASSERT( internal->hsConfig().isLocked() );
+    internal->hsConfig().setHighscoreGroup(_group);
+    internal->hsConfig().writeEntry(i+1, entryName(), value);
+}
+
+uint ItemContainer::increment(uint i) const
+{
+    uint v = read(i).toUInt() + 1;
+    write(i, v);
+    return v;
+}
+
+//-----------------------------------------------------------------------------
+ItemArray::ItemArray()
+    : _group(""), _subGroup("") // no null groups
+{}
+
+ItemArray::~ItemArray()
+{
+    for (uint i=0; iname()==name ) return i;
+    return -1;
+}
+
+const ItemContainer *ItemArray::item(const TQString &name) const
+{
+    int i = findIndex(name);
+    if ( i==-1 ) kdError(11002) << k_funcinfo << "no item named \"" << name
+                                << "\"" << endl;
+    return at(i);
+}
+
+ItemContainer *ItemArray::item(const TQString &name)
+{
+    int i = findIndex(name);
+    if ( i==-1 ) kdError(11002) << k_funcinfo << "no item named \"" << name
+                                << "\"" << endl;
+    return at(i);
+}
+
+void ItemArray::setItem(const TQString &name, Item *item)
+{
+    int i = findIndex(name);
+    if ( i==-1 ) kdError(11002) << k_funcinfo << "no item named \"" << name
+                                << "\"" << endl;
+    bool stored = at(i)->isStored();
+    bool canHaveSubGroup = at(i)->canHaveSubGroup();
+    _setItem(i, name, item, stored, canHaveSubGroup);
+}
+
+void ItemArray::addItem(const TQString &name, Item *item,
+                        bool stored, bool canHaveSubGroup)
+{
+    if ( findIndex(name)!=-1 )
+        kdError(11002) << "item already exists \"" << name << "\"" << endl;
+    uint i = size();
+    resize(i+1);
+    at(i) = new ItemContainer;
+    _setItem(i, name, item, stored, canHaveSubGroup);
+}
+
+void ItemArray::_setItem(uint i, const TQString &name, Item *item,
+                         bool stored, bool canHaveSubGroup)
+{
+    at(i)->setItem(item);
+    at(i)->setName(name);
+    at(i)->setGroup(stored ? _group : TQString());
+    at(i)->setSubGroup(canHaveSubGroup ? _subGroup : TQString());
+}
+
+void ItemArray::setGroup(const TQString &group)
+{
+    Q_ASSERT( !group.isNull() );
+    _group = group;
+    for (uint i=0; iisStored() ) at(i)->setGroup(group);
+}
+
+void ItemArray::setSubGroup(const TQString &subGroup)
+{
+    Q_ASSERT( !subGroup.isNull() );
+    _subGroup = subGroup;
+    for (uint i=0; icanHaveSubGroup() ) at(i)->setSubGroup(subGroup);
+}
+
+void ItemArray::read(uint k, Score &data) const
+{
+    for (uint i=0; iisStored() ) continue;
+        data.setData(at(i)->name(), at(i)->read(k));
+    }
+}
+
+void ItemArray::write(uint k, const Score &data, uint nb) const
+{
+    for (uint i=0; iisStored() ) continue;
+        for (uint j=nb-1; j>k; j--)  at(i)->write(j, at(i)->read(j-1));
+        at(i)->write(k, data.data(at(i)->name()));
+    }
+}
+
+void ItemArray::exportToText(TQTextStream &s) const
+{
+    for (uint k=0; kitem();
+            if ( item->isVisible() ) {
+                if ( i!=0 ) s << '\t';
+                if ( k==0 ) s << item->label();
+                else s << at(i)->pretty(k-1);
+            }
+        }
+        s << endl;
+    }
+}
+
+//-----------------------------------------------------------------------------
+class ScoreNameItem : public NameItem
+{
+ public:
+    ScoreNameItem(const ScoreInfos &score, const PlayerInfos &infos)
+        : _score(score), _infos(infos) {}
+
+    TQString pretty(uint i, const TQVariant &v) const {
+        uint id = _score.item("id")->read(i).toUInt();
+        if ( id==0 ) return NameItem::pretty(i, v);
+        return _infos.prettyName(id-1);
+    }
+
+ private:
+    const ScoreInfos  &_score;
+    const PlayerInfos &_infos;
+};
+
+//-----------------------------------------------------------------------------
+ScoreInfos::ScoreInfos(uint maxNbEntries, const PlayerInfos &infos)
+    : _maxNbEntries(maxNbEntries)
+{
+    addItem("id", new Item((uint)0));
+    addItem("rank", new RankItem, false);
+    addItem("name", new ScoreNameItem(*this, infos));
+    addItem("score", Manager::createItem(Manager::ScoreDefault));
+    addItem("date", new DateItem);
+}
+
+uint ScoreInfos::nbEntries() const
+{
+    uint i = 0;
+    for (; i<_maxNbEntries; i++)
+        if ( item("score")->read(i)==item("score")->item()->defaultValue() )
+            break;
+    return i;
+}
+
+//-----------------------------------------------------------------------------
+const char *HS_ID              = "player id";
+const char *HS_REGISTERED_NAME = "registered name";
+const char *HS_KEY             = "player key";
+const char *HS_WW_ENABLED      = "ww hs enabled";
+
+PlayerInfos::PlayerInfos()
+{
+    setGroup("players");
+
+    // standard items
+    addItem("name", new NameItem);
+    Item *it = new Item((uint)0, i18n("Games Count"),TQt::AlignRight);
+    addItem("nb games", it, true, true);
+    it = Manager::createItem(Manager::MeanScoreDefault);
+    addItem("mean score", it, true, true);
+    it = Manager::createItem(Manager::BestScoreDefault);
+    addItem("best score", it, true, true);
+    addItem("date", new DateItem, true, true);
+    it = new Item(TQString(), i18n("Comment"), TQt::AlignLeft);
+    addItem("comment", it);
+
+    // statistics items
+    addItem("nb black marks", new Item((uint)0), true, true); // legacy
+    addItem("nb lost games", new Item((uint)0), true, true);
+    addItem("nb draw games", new Item((uint)0), true, true);
+    addItem("current trend", new Item((int)0), true, true);
+    addItem("max lost trend", new Item((uint)0), true, true);
+    addItem("max won trend", new Item((uint)0), true, true);
+
+    struct passwd *pwd = getpwuid(getuid());
+    TQString username = pwd->pw_name;
+#ifdef HIGHSCORE_DIRECTORY
+    internal->hsConfig().setHighscoreGroup("players");
+    for (uint i=0; ;i++) {
+        if ( !internal->hsConfig().hasEntry(i+1, "username") ) {
+            _newPlayer = true;
+            _id = i;
+            break;
+        }
+        if ( internal->hsConfig().readEntry(i+1, "username")==username ) {
+            _newPlayer = false;
+            _id = i;
+            return;
+        }
+    }
+#endif
+    internal->hsConfig().lockForWriting();
+	KEMailSettings emailConfig;
+	emailConfig.setProfile(emailConfig.defaultProfileName());
+	TQString name = emailConfig.getSetting(KEMailSettings::RealName);
+	if ( name.isEmpty() || isNameUsed(name) ) name = username;
+	if ( isNameUsed(name) ) name= TQString(ItemContainer::ANONYMOUS);
+#ifdef HIGHSCORE_DIRECTORY
+    internal->hsConfig().writeEntry(_id+1, "username", username);
+    item("name")->write(_id, name);
+#endif
+
+    ConfigGroup cg;
+    _oldLocalPlayer = cg.config()->hasKey(HS_ID);
+    _oldLocalId = cg.config()->readUnsignedNumEntry(HS_ID);
+#ifdef HIGHSCORE_DIRECTORY
+    if (_oldLocalPlayer) { // player already exists in local config file
+        // copy player data
+        TQString prefix = TQString("%1_").tqarg(_oldLocalId+1);
+        TQMap entries =
+            cg.config()->entryMap("KHighscore_players");
+        TQMap::const_iterator it;
+        for (it=entries.begin(); it!=entries.end(); ++it) {
+            TQString key = it.key();
+            if ( key.find(prefix)==0 ) {
+                TQString name = key.right(key.length()-prefix.length());
+                if ( name!="name" || !isNameUsed(it.data()) )
+                    internal->hsConfig().writeEntry(_id+1, name, it.data());
+            }
+        }
+    }
+#else
+    _newPlayer = !_oldLocalPlayer;
+    if (_oldLocalPlayer) _id = _oldLocalId;
+    else {
+        _id = nbEntries();
+        cg.config()->writeEntry(HS_ID, _id);
+        item("name")->write(_id, name);
+    }
+#endif
+    _bound = true;
+    internal->hsConfig().writeAndUnlock();
+}
+
+void PlayerInfos::createHistoItems(const TQMemArray &scores, bool bound)
+{
+    Q_ASSERT( _histogram.size()==0 );
+    _bound = bound;
+    _histogram = scores;
+    for (uint i=1; ihsConfig().setHighscoreGroup("players");
+    TQStringList list = internal->hsConfig().readList("name", -1);
+    return list.count();
+}
+
+TQString PlayerInfos::key() const
+{
+    ConfigGroup cg;
+    return cg.config()->readEntry(HS_KEY, TQString());
+}
+
+bool PlayerInfos::isWWEnabled() const
+{
+    ConfigGroup cg;
+    return cg.config()->readBoolEntry(HS_WW_ENABLED, false);
+}
+
+TQString PlayerInfos::histoName(uint i) const
+{
+    const TQMemArray &sh = _histogram;
+    Q_ASSERT( iincrement(_id);
+    switch (score.type()) {
+    case Lost:
+        item("nb lost games")->increment(_id);
+        break;
+    case Won: break;
+    case Draw:
+        item("nb draw games")->increment(_id);
+        break;
+    };
+
+    // update mean
+    if ( score.type()==Won ) {
+        uint nbWonGames = nbGames - item("nb lost games")->read(_id).toUInt()
+                        - item("nb draw games")->read(_id).toUInt()
+                        - item("nb black marks")->read(_id).toUInt(); // legacy
+        double mean = (nbWonGames==1 ? 0.0
+                       : item("mean score")->read(_id).toDouble());
+        mean += (double(score.score()) - mean) / nbWonGames;
+        item("mean score")->write(_id, mean);
+    }
+
+    // update best score
+    Score best = score; // copy optionnal fields (there are not taken into account here)
+    best.setScore( item("best score")->read(_id).toUInt() );
+    if ( bestwrite(_id, score.score());
+        item("date")->write(_id, score.data("date").toDateTime());
+    }
+
+    // update trends
+    int current = item("current trend")->read(_id).toInt();
+    switch (score.type()) {
+    case Won: {
+        if ( current<0 ) current = 0;
+        current++;
+        uint won = item("max won trend")->read(_id).toUInt();
+        if ( (uint)current>won ) item("max won trend")->write(_id, current);
+        break;
+    }
+    case Lost: {
+        if ( current>0 ) current = 0;
+        current--;
+        uint lost = item("max lost trend")->read(_id).toUInt();
+        uint clost = -current;
+        if ( clost>lost ) item("max lost trend")->write(_id, clost);
+        break;
+    }
+    case Draw:
+        current = 0;
+        break;
+    }
+    item("current trend")->write(_id, current);
+
+    // update histogram
+    if ( score.type()==Won ) {
+        const TQMemArray &sh = _histogram;
+        for (uint i=1; iincrement(_id);
+                break;
+            }
+    }
+}
+
+bool PlayerInfos::isNameUsed(const TQString &newName) const
+{
+    if ( newName==name() ) return false; // own name...
+    for (uint i=0; iread(i).toString().lower() ) return true;
+    if ( newName==i18n(ItemContainer::ANONYMOUS_LABEL) ) return true;
+    return false;
+}
+
+void PlayerInfos::modifyName(const TQString &newName) const
+{
+    item("name")->write(_id, newName);
+}
+
+void PlayerInfos::modifySettings(const TQString &newName,
+                                 const TQString &comment, bool WWEnabled,
+                                 const TQString &newKey) const
+{
+    modifyName(newName);
+    item("comment")->write(_id, comment);
+    ConfigGroup cg;
+    cg.config()->writeEntry(HS_WW_ENABLED, WWEnabled);
+    if ( !newKey.isEmpty() ) cg.config()->writeEntry(HS_KEY, newKey);
+    if (WWEnabled) cg.config()->writeEntry(HS_REGISTERED_NAME, newName);
+}
+
+TQString PlayerInfos::registeredName() const
+{
+    ConfigGroup cg;
+    return cg.config()->readEntry(HS_REGISTERED_NAME, TQString());
+}
+
+void PlayerInfos::removeKey()
+{
+    ConfigGroup cg;
+
+    // save old key/nickname
+    uint i = 0;
+    TQString str = "%1 old #%2";
+    TQString sk;
+    do {
+        i++;
+        sk = str.tqarg(HS_KEY).tqarg(i);
+    } while ( !cg.config()->readEntry(sk, TQString()).isEmpty() );
+    cg.config()->writeEntry(sk, key());
+    cg.config()->writeEntry(str.tqarg(HS_REGISTERED_NAME).tqarg(i),
+                            registeredName());
+
+    // clear current key/nickname
+    cg.config()->deleteEntry(HS_KEY);
+    cg.config()->deleteEntry(HS_REGISTERED_NAME);
+    cg.config()->writeEntry(HS_WW_ENABLED, false);
+}
+
+//-----------------------------------------------------------------------------
+ManagerPrivate::ManagerPrivate(uint nbGameTypes, Manager &m)
+    : manager(m), showStatistics(false), showDrawGames(false),
+      trackLostGames(false), trackDrawGames(false), 
+      showMode(Manager::ShowForHigherScore),
+      _first(true), _nbGameTypes(nbGameTypes), _gameType(0)
+{}
+
+void ManagerPrivate::init(uint maxNbEntries)
+{
+    _hsConfig = new KHighscore(false, 0);
+    _playerInfos = new PlayerInfos;
+    _scoreInfos = new ScoreInfos(maxNbEntries, *_playerInfos);
+}
+
+ManagerPrivate::~ManagerPrivate()
+{
+    delete _scoreInfos;
+    delete _playerInfos;
+    delete _hsConfig;
+}
+
+KURL ManagerPrivate::queryURL(QueryType type, const TQString &newName) const
+{
+    KURL url = serverURL;
+    TQString nameItem = "nickname";
+    TQString name = _playerInfos->registeredName();
+    bool withVersion = true;
+    bool key = false;
+    bool level = false;
+
+	switch (type) {
+        case Submit:
+            url.addPath("submit.php");
+            level = true;
+            key = true;
+            break;
+        case Register:
+            url.addPath("register.php");
+            name = newName;
+            break;
+        case Change:
+            url.addPath("change.php");
+            key = true;
+            if ( newName!=name )
+                Manager::addToQueryURL(url, "new_nickname", newName);
+            break;
+        case Players:
+            url.addPath("players.php");
+            nameItem = "highlight";
+            withVersion = false;
+            break;
+        case Scores:
+            url.addPath("highscores.php");
+            withVersion = false;
+            if ( _nbGameTypes>1 ) level = true;
+            break;
+	}
+
+    if (withVersion) Manager::addToQueryURL(url, "version", version);
+    if ( !name.isEmpty() ) Manager::addToQueryURL(url, nameItem, name);
+    if (key) Manager::addToQueryURL(url, "key", _playerInfos->key());
+    if (level) {
+        TQString label = manager.gameTypeLabel(_gameType, Manager::WW);
+        if ( !label.isEmpty() ) Manager::addToQueryURL(url, "level", label);
+    }
+
+    return url;
+}
+
+// strings that needs to be translated (coming from the highscores server)
+const char *DUMMY_STRINGS[] = {
+    I18N_NOOP("Undefined error."),
+    I18N_NOOP("Missing argument(s)."),
+    I18N_NOOP("Invalid argument(s)."),
+
+    I18N_NOOP("Unable to connect to MySQL server."),
+    I18N_NOOP("Unable to select database."),
+    I18N_NOOP("Error on database query."),
+    I18N_NOOP("Error on database insert."),
+
+    I18N_NOOP("Nickname already registered."),
+    I18N_NOOP("Nickname not registered."),
+    I18N_NOOP("Invalid key."),
+    I18N_NOOP("Invalid submit key."),
+
+    I18N_NOOP("Invalid level."),
+    I18N_NOOP("Invalid score.")
+};
+
+const char *UNABLE_TO_CONTACT =
+    I18N_NOOP("Unable to contact world-wide highscore server");
+
+bool ManagerPrivate::doQuery(const KURL &url, TQWidget *parent,
+                                TQDomNamedNodeMap *map)
+{
+    KIO::http_update_cache(url, true, 0); // remove cache !
+
+    TQString tmpFile;
+    if ( !KIO::NetAccess::download(url, tmpFile, parent) ) {
+        TQString details = i18n("Server URL: %1").tqarg(url.host());
+        KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
+        return false;
+    }
+
+	TQFile file(tmpFile);
+	if ( !file.open(IO_ReadOnly) ) {
+        KIO::NetAccess::removeTempFile(tmpFile);
+        TQString details = i18n("Unable to open temporary file.");
+        KMessageBox::detailedSorry(parent, i18n(UNABLE_TO_CONTACT), details);
+        return false;
+    }
+
+	TQTextStream t(&file);
+	TQString content = t.read().stripWhiteSpace();
+	file.close();
+    KIO::NetAccess::removeTempFile(tmpFile);
+
+	TQDomDocument doc;
+    if ( doc.setContent(content) ) {
+        TQDomElement root = doc.documentElement();
+        TQDomElement element = root.firstChild().toElement();
+        if ( element.tagName()=="success" ) {
+            if (map) *map = element.attributes();
+            return true;
+        }
+        if ( element.tagName()=="error" ) {
+            TQDomAttr attr = element.attributes().namedItem("label").toAttr();
+            if ( !attr.isNull() ) {
+                TQString msg = i18n(attr.value().latin1());
+                TQString caption = i18n("Message from world-wide highscores "
+                                       "server");
+                KMessageBox::sorry(parent, msg, caption);
+                return false;
+            }
+        }
+    }
+    TQString msg = i18n("Invalid answer from world-wide highscores server.");
+    TQString details = i18n("Raw message: %1").tqarg(content);
+    KMessageBox::detailedSorry(parent, msg, details);
+    return false;
+}
+
+bool ManagerPrivate::getFromQuery(const TQDomNamedNodeMap &map,
+                                  const TQString &name, TQString &value,
+                                  TQWidget *parent)
+{
+    TQDomAttr attr = map.namedItem(name).toAttr();
+    if ( attr.isNull() ) {
+	    KMessageBox::sorry(parent,
+               i18n("Invalid answer from world-wide "
+                    "highscores server (missing item: %1).").tqarg(name));
+		return false;
+    }
+    value = attr.value();
+    return true;
+}
+
+Score ManagerPrivate::readScore(uint i) const
+{
+    Score score(Won);
+    _scoreInfos->read(i, score);
+    return score;
+}
+
+int ManagerPrivate::rank(const Score &score) const
+{
+    uint nb = _scoreInfos->nbEntries();
+    uint i = 0;
+	for (; imaxNbEntries() ? (int)i : -1);
+}
+
+bool ManagerPrivate::modifySettings(const TQString &newName,
+                                    const TQString &comment, bool WWEnabled,
+                                    TQWidget *widget)
+{
+    TQString newKey;
+    bool newPlayer = false;
+
+    if (WWEnabled) {
+        newPlayer = _playerInfos->key().isEmpty()
+                    || _playerInfos->registeredName().isEmpty();
+        KURL url = queryURL((newPlayer ? Register : Change), newName);
+        Manager::addToQueryURL(url, "comment", comment);
+
+        TQDomNamedNodeMap map;
+        bool ok = doQuery(url, widget, &map);
+        if ( !ok || (newPlayer && !getFromQuery(map, "key", newKey, widget)) )
+            return false;
+    }
+
+    bool ok = _hsConfig->lockForWriting(widget); // no GUI when locking
+    if (ok) {
+        // check again name in case the config file has been changed...
+        // if it has, it is unfortunate because the WWW name is already
+        // committed but should be very rare and not really problematic
+        ok = ( !_playerInfos->isNameUsed(newName) );
+        if (ok)
+            _playerInfos->modifySettings(newName, comment, WWEnabled, newKey);
+        _hsConfig->writeAndUnlock();
+    }
+    return ok;
+}
+
+void ManagerPrivate::convertToGlobal()
+{
+    // read old highscores
+    KHighscore *tmp = _hsConfig;
+    _hsConfig = new KHighscore(true, 0);
+    TQValueVector scores(_scoreInfos->nbEntries());
+    for (uint i=0; ilockForWriting();
+    for (uint i=0; ioldLocalId()+1 )
+            submitLocal(scores[i]);
+    _hsConfig->writeAndUnlock();
+}
+
+void ManagerPrivate::setGameType(uint type)
+{
+    if (_first) {
+        _first = false;
+        if ( _playerInfos->isNewPlayer() ) {
+            // convert legacy highscores
+            for (uint i=0; i<_nbGameTypes; i++) {
+                setGameType(i);
+                manager.convertLegacy(i);
+            }
+
+#ifdef HIGHSCORE_DIRECTORY
+            if ( _playerInfos->isOldLocalPlayer() ) {
+                // convert local to global highscores
+                for (uint i=0; i<_nbGameTypes; i++) {
+                    setGameType(i);
+                    convertToGlobal();
+                }
+            }
+#endif
+        }
+    }
+
+    Q_ASSERT( type<_nbGameTypes );
+    _gameType = kMin(type, _nbGameTypes-1);
+    TQString str = "scores";
+    TQString lab = manager.gameTypeLabel(_gameType, Manager::Standard);
+    if ( !lab.isEmpty() ) {
+        _playerInfos->setSubGroup(lab);
+        str += "_" + lab;
+    }
+    _scoreInfos->setGroup(str);
+}
+
+void ManagerPrivate::checkFirst()
+{
+    if (_first) setGameType(0);
+}
+
+int ManagerPrivate::submitScore(const Score &ascore,
+                                TQWidget *widget, bool askIfAnonymous)
+{
+    checkFirst();
+
+    Score score = ascore;
+    score.setData("id", _playerInfos->id() + 1);
+    score.setData("date", TQDateTime::tqcurrentDateTime());
+
+    // ask new name if anonymous and winner
+    const char *dontAskAgainName = "highscore_ask_name_dialog";
+    TQString newName;
+    KMessageBox::ButtonCode dummy;
+    if ( score.type()==Won && askIfAnonymous && _playerInfos->isAnonymous()
+     && KMessageBox::shouldBeShownYesNo(dontAskAgainName, dummy) ) {
+         AskNameDialog d(widget);
+         if ( d.exec()==TQDialog::Accepted ) newName = d.name();
+         if ( d.dontAskAgain() )
+             KMessageBox::saveDontShowAgainYesNo(dontAskAgainName,
+                                                 KMessageBox::No);
+    }
+
+    int rank = -1;
+    if ( _hsConfig->lockForWriting(widget) ) { // no GUI when locking
+        // check again new name in case the config file has been changed...
+        if ( !newName.isEmpty() && !_playerInfos->isNameUsed(newName) )
+             _playerInfos->modifyName(newName);
+
+        // commit locally
+        _playerInfos->submitScore(score);
+        if ( score.type()==Won ) rank = submitLocal(score);
+        _hsConfig->writeAndUnlock();
+    }
+
+    if ( _playerInfos->isWWEnabled() )
+        submitWorldWide(score, widget);
+
+    return rank;
+}
+
+int ManagerPrivate::submitLocal(const Score &score)
+{
+    int r = rank(score);
+    if ( r!=-1 ) {
+        uint nb = _scoreInfos->nbEntries();
+        if ( nb<_scoreInfos->maxNbEntries() ) nb++;
+        _scoreInfos->write(r, score, nb);
+    }
+    return r;
+}
+
+bool ManagerPrivate::submitWorldWide(const Score &score,
+                                     TQWidget *widget) const
+{
+    if ( score.type()==Lost && !trackLostGames ) return true;
+    if ( score.type()==Draw && !trackDrawGames ) return true;
+
+    KURL url = queryURL(Submit);
+    manager.additionalQueryItems(url, score);
+    int s = (score.type()==Won ? score.score() : (int)score.type());
+    TQString str =  TQString::number(s);
+    Manager::addToQueryURL(url, "score", str);
+    KMD5 context(TQString(_playerInfos->registeredName() + str).latin1());
+    Manager::addToQueryURL(url, "check", context.hexDigest());
+
+    return doQuery(url, widget);
+}
+
+void ManagerPrivate::exportHighscores(TQTextStream &s)
+{
+    uint tmp = _gameType;
+
+    for (uint i=0; i<_nbGameTypes; i++) {
+        setGameType(i);
+        if ( _nbGameTypes>1 ) {
+            if ( i!=0 ) s << endl;
+            s << "--------------------------------" << endl;
+            s << "Game type: "
+              << manager.gameTypeLabel(_gameType, Manager::I18N)
+              << endl;
+            s << endl;
+        }
+        s << "Players list:" << endl;
+        _playerInfos->exportToText(s);
+        s << endl;
+        s << "Highscores list:" << endl;
+        _scoreInfos->exportToText(s);
+    }
+
+    setGameType(tmp);
+}
+
+} // namespace
diff --git a/libtdegames/highscore/kexthighscore_internal.h b/libtdegames/highscore/kexthighscore_internal.h
new file mode 100644
index 00000000..0bd4f9ef
--- /dev/null
+++ b/libtdegames/highscore/kexthighscore_internal.h
@@ -0,0 +1,277 @@
+/*
+    This file is part of the KDE games library
+    Copyright (C) 2001-2004 Nicolas Hadacek (hadacek@kde.org)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License version 2 as published by the Free Software Foundation.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXTHIGHSCORE_INTERNAL_H
+#define KEXTHIGHSCORE_INTERNAL_H
+
+#include 
+#include 
+#include 
+#include 
+
+#include "khighscore.h"
+#include "kexthighscore.h"
+
+class TQTextStream;
+class TQTabWidget;
+class TQDomNamedNodeMap;
+
+
+namespace KExtHighscore
+{
+
+class PlayerInfos;
+class Score;
+class Manager;
+
+
+//-----------------------------------------------------------------------------
+class RankItem : public Item
+{
+ public:
+    RankItem()
+        : Item((uint)0, i18n("Rank"), TQt::AlignRight) {}
+
+    TQVariant read(uint rank, const TQVariant &) const  { return rank; }
+    TQString pretty(uint rank, const TQVariant &) const
+        { return TQString::number(rank+1); }
+};
+
+class NameItem : public Item
+{
+ public:
+    NameItem()
+        : Item(TQString(), i18n("Name"), TQt::AlignLeft) {
+            setPrettySpecial(Anonymous);
+    }
+};
+
+class DateItem : public Item
+{
+ public:
+    DateItem()
+        : Item(TQDateTime(), i18n("Date"), TQt::AlignRight) {
+            setPrettyFormat(DateTime);
+    }
+};
+
+class SuccessPercentageItem : public Item
+{
+ public:
+    SuccessPercentageItem()
+        : Item((double)-1, i18n("Success"), TQt::AlignRight) {
+            setPrettyFormat(Percentage);
+            setPrettySpecial(NegativeNotDefined);
+    }
+};
+
+//-----------------------------------------------------------------------------
+class ItemContainer
+{
+ public:
+    ItemContainer();
+    ~ItemContainer();
+
+    void setItem(Item *item);
+    const Item *item() const { return _item; }
+    Item *item() { return _item; }
+
+    void setName(const TQString &name) { _name = name; }
+    TQString name() const { return _name; }
+
+    void setGroup(const TQString &group) { _group = group; }
+    bool isStored() const { return !_group.isNull(); }
+
+    void setSubGroup(const TQString &subGroup) { _subGroup = subGroup; }
+    bool canHaveSubGroup() const { return !_subGroup.isNull(); }
+
+    static const char ANONYMOUS[]; // name assigned to anonymous players
+    static const char ANONYMOUS_LABEL[];
+
+    TQVariant read(uint i) const;
+    TQString pretty(uint i) const;
+    void write(uint i, const TQVariant &value) const;
+    // for UInt TQVariant (return new value)
+    uint increment(uint i) const;
+
+ private:
+    Item    *_item;
+    TQString  _name, _group, _subGroup;
+
+    TQString entryName() const;
+
+    ItemContainer(const ItemContainer &);
+    ItemContainer &operator =(const ItemContainer &);
+};
+
+//-----------------------------------------------------------------------------
+/**
+ * Manage a bunch of @ref Item which are saved under the same group
+ * in KHighscores config file.
+ */
+class ItemArray : public TQMemArray
+{
+ public:
+    ItemArray();
+    virtual ~ItemArray();
+
+    virtual uint nbEntries() const = 0;
+
+    const ItemContainer *item(const TQString &name) const;
+    ItemContainer *item(const TQString &name);
+
+    void addItem(const TQString &name, Item *, bool stored = true,
+                 bool canHaveSubGroup = false);
+    void setItem(const TQString &name, Item *);
+    int findIndex(const TQString &name) const;
+
+    void setGroup(const TQString &group);
+    void setSubGroup(const TQString &subGroup);
+
+    void read(uint k, Score &data) const;
+    void write(uint k, const Score &data, uint maxNbLines) const;
+
+    void exportToText(TQTextStream &) const;
+
+ private:
+    TQString _group, _subGroup;
+
+    void _setItem(uint i, const TQString &name, Item *, bool stored,
+                  bool canHaveSubGroup);
+
+    ItemArray(const ItemArray &);
+    ItemArray &operator =(const ItemArray &);
+};
+
+//-----------------------------------------------------------------------------
+class ScoreInfos : public ItemArray
+{
+ public:
+    ScoreInfos(uint maxNbEntries, const PlayerInfos &infos);
+
+    uint nbEntries() const;
+    uint maxNbEntries() const { return _maxNbEntries; }
+
+ private:
+    uint _maxNbEntries;
+};
+
+//-----------------------------------------------------------------------------
+class ConfigGroup : public KConfigGroupSaver
+{
+ public:
+    ConfigGroup(const TQString &group = TQString())
+        : KConfigGroupSaver(kapp->config(), group) {}
+};
+
+//-----------------------------------------------------------------------------
+class PlayerInfos : public ItemArray
+{
+ public:
+    PlayerInfos();
+
+    bool isNewPlayer() const { return _newPlayer; }
+    bool isOldLocalPlayer() const { return _oldLocalPlayer; }
+    uint nbEntries() const;
+    TQString name() const { return item("name")->read(_id).toString(); }
+    bool isAnonymous() const;
+    TQString prettyName() const { return prettyName(_id); }
+    TQString prettyName(uint id) const { return item("name")->pretty(id); }
+    TQString registeredName() const;
+    TQString comment() const { return item("comment")->pretty(_id); }
+    bool isWWEnabled() const;
+    TQString key() const;
+    uint id() const { return _id; }
+    uint oldLocalId() const { return _oldLocalId; }
+
+    void createHistoItems(const TQMemArray &scores, bool bound);
+    TQString histoName(uint i) const;
+    uint histoSize() const;
+    const TQMemArray &histogram() const { return _histogram; }
+
+    void submitScore(const Score &) const;
+    // return true if the nickname is already used locally
+    bool isNameUsed(const TQString &name) const;
+    void modifyName(const TQString &newName) const;
+    void modifySettings(const TQString &newName, const TQString &comment,
+                        bool WWEnabled, const TQString &newKey) const;
+    void removeKey();
+
+ private:
+    bool _newPlayer, _bound, _oldLocalPlayer;
+    uint _id, _oldLocalId;
+    TQMemArray _histogram;
+};
+
+//-----------------------------------------------------------------------------
+class ManagerPrivate
+{
+ public:
+    ManagerPrivate(uint nbGameTypes, Manager &manager);
+    void init(uint maxNbentries);
+    ~ManagerPrivate();
+
+    bool modifySettings(const TQString &newName, const TQString &comment,
+                        bool WWEnabled, TQWidget *widget);
+
+    void setGameType(uint type);
+    void checkFirst();
+    int submitLocal(const Score &score);
+    int submitScore(const Score &score, TQWidget *widget, bool askIfAnonymous);
+    Score readScore(uint i) const;
+
+    uint gameType() const        { return _gameType; }
+    uint nbGameTypes() const     { return _nbGameTypes; }
+    bool isWWHSAvailable() const { return !serverURL.isEmpty(); }
+    ScoreInfos &scoreInfos()     { return *_scoreInfos; }
+    PlayerInfos &playerInfos()   { return *_playerInfos; }
+    KHighscore &hsConfig()       { return *_hsConfig; }
+    enum QueryType { Submit, Register, Change, Players, Scores };
+    KURL queryURL(QueryType type, const TQString &newName=TQString()) const;
+
+    void exportHighscores(TQTextStream &);
+
+    Manager &manager;
+    KURL     serverURL;
+    TQString  version;
+    bool     showStatistics, showDrawGames, trackLostGames, trackDrawGames;
+    Manager::ShowMode showMode;
+
+ private:
+    KHighscore   *_hsConfig;
+    PlayerInfos  *_playerInfos;
+    ScoreInfos   *_scoreInfos;
+    bool          _first;
+    const uint    _nbGameTypes;
+    uint          _gameType;
+
+    // return -1 if not a local best score
+    int rank(const Score &score) const;
+
+    bool submitWorldWide(const Score &score, TQWidget *parent) const;
+    static bool doQuery(const KURL &url, TQWidget *parent,
+                        TQDomNamedNodeMap *map = 0);
+    static bool getFromQuery(const TQDomNamedNodeMap &map, const TQString &name,
+                             TQString &value, TQWidget *parent);
+    void convertToGlobal();
+};
+
+} // namespace
+
+#endif
diff --git a/libtdegames/highscore/kexthighscore_item.cpp b/libtdegames/highscore/kexthighscore_item.cpp
new file mode 100644
index 00000000..4b48a0ee
--- /dev/null
+++ b/libtdegames/highscore/kexthighscore_item.cpp
@@ -0,0 +1,312 @@
+/*
+    This file is part of the KDE games library
+    Copyright (C) 2001-2003 Nicolas Hadacek (hadacek@kde.org)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License version 2 as published by the Free Software Foundation.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#include "kexthighscore_item.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include "khighscore.h"
+#include "kexthighscore_internal.h"
+#include "kexthighscore_gui.h"
+
+
+namespace KExtHighscore
+{
+
+//-----------------------------------------------------------------------------
+Item::Item(const TQVariant &def, const TQString &label, int tqalignment)
+    : _default(def), _label(label), _tqalignment(tqalignment),
+      _format(NoFormat), _special(NoSpecial)
+{}
+
+Item::~Item()
+{}
+
+TQVariant Item::read(uint, const TQVariant &value) const
+{
+    return value;
+}
+
+void Item::setPrettyFormat(Format format)
+{
+    bool buint = ( _default.type()==TQVariant::UInt );
+    bool bdouble = ( _default.type()==TQVariant::Double );
+    bool bnum = ( buint || bdouble || _default.type()==TQVariant::Int );
+
+    switch (format) {
+    case OneDecimal:
+    case Percentage:
+        Q_ASSERT(bdouble);
+        break;
+    case MinuteTime:
+        Q_ASSERT(bnum);
+        break;
+    case DateTime:
+    	Q_ASSERT( _default.type()==TQVariant::DateTime );
+	break;
+    case NoFormat:
+        break;
+    }
+
+    _format = format;
+}
+
+void Item::setPrettySpecial(Special special)
+{
+    bool buint = ( _default.type()==TQVariant::UInt );
+    bool bnum = ( buint || _default.type()==TQVariant::Double
+                  || _default.type()==TQVariant::Int );
+
+    switch (special) {
+    case ZeroNotDefined:
+        Q_ASSERT(bnum);
+        break;
+    case NegativeNotDefined:
+        Q_ASSERT(bnum && !buint);
+        break;
+    case DefaultNotDefined:
+        break;
+    case Anonymous:
+        Q_ASSERT( _default.type()==TQVariant::String );
+        break;
+    case NoSpecial:
+        break;
+    }
+
+     _special = special;
+}
+
+TQString Item::timeFormat(uint n)
+{
+    Q_ASSERT( n<=3600 && n!=0 );
+    n = 3600 - n;
+    return TQString::number(n / 60).rightJustify(2, '0') + ':'
+        + TQString::number(n % 60).rightJustify(2, '0');
+}
+
+TQString Item::pretty(uint, const TQVariant &value) const
+{
+    switch (_special) {
+    case ZeroNotDefined:
+        if ( value.toUInt()==0 ) return "--";
+        break;
+    case NegativeNotDefined:
+        if ( value.toInt()<0 ) return "--";
+        break;
+    case DefaultNotDefined:
+        if ( value==_default ) return "--";
+        break;
+    case Anonymous:
+        if ( value.toString()==ItemContainer::ANONYMOUS )
+            return i18n(ItemContainer::ANONYMOUS_LABEL);
+        break;
+    case NoFormat:
+        break;
+    }
+
+    switch (_format) {
+    case OneDecimal:
+        return TQString::number(value.toDouble(), 'f', 1);
+    case Percentage:
+        return TQString::number(value.toDouble(), 'f', 1) + "%";
+    case MinuteTime:
+        return timeFormat(value.toUInt());
+    case DateTime:
+        if ( value.toDateTime().isNull() ) return "--";
+        return KGlobal::locale()->formatDateTime(value.toDateTime());
+    case NoSpecial:
+        break;
+    }
+
+    return value.toString();
+}
+
+//-----------------------------------------------------------------------------
+Score::Score(ScoreType type)
+    : _type(type)
+{
+    const ItemArray &items = internal->scoreInfos();
+    for (uint i=0; iname()] = items[i]->item()->defaultValue();
+}
+
+Score::~Score()
+{}
+
+const TQVariant &Score::data(const TQString &name) const
+{
+    Q_ASSERT( _data.contains(name) );
+    return _data[name];
+}
+
+void Score::setData(const TQString &name, const TQVariant &value)
+{
+    Q_ASSERT( _data.contains(name) );
+    Q_ASSERT( _data[name].type()==value.type() );
+    _data[name] = value;
+}
+
+bool Score::isTheWorst() const
+{
+    Score s;
+    return score()==s.score();
+}
+
+bool Score::operator <(const Score &score)
+{
+    return internal->manager.isStrictlyLess(*this, score);
+}
+
+TQDataStream &operator <<(TQDataStream &s, const Score &score)
+{
+    s << (TQ_UINT8)score.type();
+    s << score._data;
+    return s;
+}
+
+TQDataStream &operator >>(TQDataStream &s, Score &score)
+{
+    TQ_UINT8 type;
+    s >> type;
+    score._type = (ScoreType)type;
+    s >> score._data;
+    return s;
+}
+
+//-----------------------------------------------------------------------------
+MultiplayerScores::MultiplayerScores()
+{}
+
+MultiplayerScores::~MultiplayerScores()
+{}
+
+void MultiplayerScores::clear()
+{
+    Score score;
+    for (uint i=0; i<_scores.size(); i++) {
+        _nbGames[i] = 0;
+        TQVariant name = _scores[i].data("name");
+        _scores[i] = score;
+        _scores[i].setData("name", name);
+        _scores[i]._data["mean score"] = double(0);
+        _scores[i]._data["nb won games"] = uint(0);
+    }
+}
+
+void MultiplayerScores::setPlayerCount(uint nb)
+{
+    _nbGames.resize(nb);
+    _scores.resize(nb);
+    clear();
+}
+
+void MultiplayerScores::setName(uint i, const TQString &name)
+{
+    _scores[i].setData("name", name);
+}
+
+void MultiplayerScores::addScore(uint i, const Score &score)
+{
+    TQVariant name = _scores[i].data("name");
+    double mean = _scores[i].data("mean score").toDouble();
+    uint won = _scores[i].data("nb won games").toUInt();
+    _scores[i] = score;
+    _scores[i].setData("name", name);
+    _nbGames[i]++;
+    mean += (double(score.score()) - mean) / _nbGames[i];
+    _scores[i]._data["mean score"] = mean;
+    if ( score.type()==Won ) won++;
+    _scores[i]._data["nb won games"] = won;
+}
+
+void MultiplayerScores::show(TQWidget *parent)
+{
+    // check consistency
+    if ( _nbGames.size()<2 ) kdWarning(11002) << "less than 2 players" << endl;
+    else {
+        bool ok = true;
+        uint nb = _nbGames[0];
+        for (uint i=1; i<_nbGames.size(); i++)
+            if ( _nbGames[i]!=nb ) ok = false;
+        if (!ok)
+           kdWarning(11002) << "players have not same number of games" << endl;
+    }
+
+    // order the players according to the number of won games
+    TQValueVector ordered;
+    for (uint i=0; i<_scores.size(); i++) {
+        uint won = _scores[i].data("nb won games").toUInt();
+        double mean = _scores[i].data("mean score").toDouble();
+        TQValueVector::iterator it;
+        for(it = ordered.begin(); it!=ordered.end(); ++it) {
+            uint cwon = (*it).data("nb won games").toUInt();
+            double cmean = (*it).data("mean score").toDouble();
+            if ( wonaddWidget(vbox);
+    if ( _nbGames[0]==0 ) (void)new TQLabel(i18n("No game played."), vbox);
+    else {
+        (void)new TQLabel(i18n("Scores for last game:"), vbox);
+        (void)new LastMultipleScoresList(ordered, vbox);
+    }
+
+    if ( _nbGames[0]>1 ) {
+        vbox = new TQVBox(dialog.plainPage());
+        hbox->addWidget(vbox);
+        (void)new TQLabel(i18n("Scores for the last %1 games:")
+                         .tqarg(_nbGames[0]), vbox);
+        (void)new TotalMultipleScoresList(ordered, vbox);
+    }
+
+    dialog.enableButtonSeparator(false);
+    dialog.exec();
+}
+
+TQDataStream &operator <<(TQDataStream &s, const MultiplayerScores &score)
+{
+    s << score._scores;
+    s << score._nbGames;
+    return s;
+}
+
+TQDataStream &operator >>(TQDataStream &s, MultiplayerScores &score)
+{
+    s >> score._scores;
+    s >> score._nbGames;
+    return s;
+}
+
+} // namespace
diff --git a/libtdegames/highscore/kexthighscore_item.h b/libtdegames/highscore/kexthighscore_item.h
new file mode 100644
index 00000000..b32f32e7
--- /dev/null
+++ b/libtdegames/highscore/kexthighscore_item.h
@@ -0,0 +1,317 @@
+/*
+    This file is part of the KDE games library
+    Copyright (C) 2001-2003 Nicolas Hadacek (hadacek@kde.org)
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License version 2 as published by the Free Software Foundation.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public License
+    along with this library; see the file COPYING.LIB.  If not, write to
+    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+    Boston, MA 02110-1301, USA.
+*/
+
+#ifndef KEXTHIGHSCORE_ITEM_H
+#define KEXTHIGHSCORE_ITEM_H
+
+#include 
+#include 
+#include 
+#include 
+#include 
+class TQWidget;
+
+
+namespace KExtHighscore
+{
+
+//-----------------------------------------------------------------------------
+/**
+ * This class defines how to convert and how to display
+ * a highscore element (such as the score, the date, ...) or a player
+ * info (such as the player name, the best score, ...).
+ */
+class KDE_EXPORT Item
+{
+ public:
+    /**
+     * Possible display format.
+     * 
    + *
  • @p NoFormat : no formatting (default)
  • + *
  • @p OneDecimal : with one decimal (only for Double)
  • + *
  • @p Percentage : with one decimal + % (only for Double)
  • + *
  • @p MinuteTime : MM:SS ie 3600 is 00:00, 1 is 59:59 and 0 is + * undefined (only for UInt, Int and Double)
  • + *
  • @p DateTime : date and time according to locale (only for + * DateTime)
  • + *
+ */ + enum Format { NoFormat, OneDecimal, Percentage, MinuteTime, + DateTime }; + + /** + * Possible special value for display format. + *
    + *
  • @p NoSpecial : no special value ; a null DateTime is replaced by + * "--" (default)
  • + *
  • ZeroNotDefined : 0 is replaced by "--" (only for UInt, Int and + * Double)
  • + *
  • @p NegativeNotDefined : negative values are replaced by "--" (only + * for Int and Double)
  • + *
  • @p DefaultNotDefined : default value is replaced by "--"
  • + *
  • @p Anonymous : replace the special value ItemBase::ANONYMOUS + * by i18n("anonymous") (only for String)
  • + *
+ */ + enum Special { NoSpecial, ZeroNotDefined, NegativeNotDefined, + DefaultNotDefined, Anonymous }; + + /** + * Constructor. + * + * @param def default value ; the TQVariant also gives the type of data. + * Be sure to cast the value to the required type (for e.g. with uint). + * @param label the label corresponding to the item. If empty, the item + * is not shown. + * @param tqalignment the tqalignment of the item. + */ + Item(const TQVariant &def = TQVariant::Invalid, + const TQString &label = TQString(), int tqalignment = TQt::AlignRight); + + virtual ~Item(); + + /** + * Set the display format. + * @see Format + */ + void setPrettyFormat(Format format); + + /** + * Set the special value for display. + * @see Special + */ + void setPrettySpecial(Special special); + + /** + * @return if the item is shown. + */ + bool isVisible() const { return !_label.isEmpty(); } + + /** + * Set the label. + */ + void setLabel(const TQString &label) { _label = label; } + + /** + * @return the label. + */ + TQString label() const { return _label; } + + /** + * @return the tqalignment. + */ + int tqalignment() const { return _tqalignment; } + + /** + * Set default value. + */ + void setDefaultValue(const TQVariant &value) { _default = value; } + + /** + * @return the default value. + */ + const TQVariant &defaultValue() const { return _default; } + + /** + * @return the converted value (by default the value is left + * unchanged). Most of the time you don't need to reimplement this method. + * + * @param i the element index ("rank" for score / "id" for player) + * @param value the value to convert + */ + virtual TQVariant read(uint i, const TQVariant &value) const; + + /** + * @return the string to be displayed. You may need to reimplement this + * method for special formatting (different from the standard ones). + * + * @param i the element index ("rank" for score / "id" for player) + * @param value the value to convert + */ + virtual TQString pretty(uint i, const TQVariant &value) const; + + private: + TQVariant _default; + TQString _label; + int _tqalignment; + Format _format; + Special _special; + + class ItemPrivate; + ItemPrivate *d; + + static TQString timeFormat(uint); +}; + +//----------------------------------------------------------------------------- +/** + * Possible score type. + * @p Won the game has been won. + * @p Lost the game has been lost or has been aborted. + * @p Draw the game is a draw. + */ +enum ScoreType { Won = 0, Lost = -1, Draw = -2 }; + +/** + * This class contains data for a score. You should not inherit from + * this class but reimplement the methods in Highscores. + */ +class KDE_EXPORT Score +{ + public: + Score(ScoreType type = Won); + + ~Score(); + + /** + * @return the game type. + */ + ScoreType type() const { return _type; } + + /** + * Set the game type. + */ + void setType(ScoreType type) { _type = type; } + + /** + * @return the data associated with the named Item. + */ + const TQVariant &data(const TQString &name) const; + + /** + * Set the data associated with the named Item. Note that the + * value should have the type of the default value of the + * Item. + */ + void setData(const TQString &name, const TQVariant &value); + + /** + * @return the score value. + * + * Equivalent to
data("score").toUInt()
. + */ + uint score() const { return data("score").toUInt(); } + + /** + * Set the score value. + * + * Equivalent to
setData("score", score)
. + */ + void setScore(uint score) { setData("score", score); } + + /** + * @return true if this is the worst possible score (ie the default + * argument of ScoreItem). + */ + bool isTheWorst() const; + + /** + * Comparison operator. + * + * @see Manager::isStrictlyLess + */ + bool operator <(const Score &score); + + private: + ScoreType _type; + TQMap _data; + + class ScorePrivate; + ScorePrivate *d; + + friend class MultiplayerScores; + + friend TQDataStream &operator <<(TQDataStream &stream, const Score &score); + friend TQDataStream &operator >>(TQDataStream &stream, Score &score); +}; + +KDE_EXPORT TQDataStream &operator <<(TQDataStream &stream, const Score &score); +KDE_EXPORT TQDataStream &operator >>(TQDataStream &stream, Score &score); + +/** + * This class is used to store and show scores for multiplayer games. + * + * Example of use: + * Initialize the class: + *
+ * KExtHighscore::MultiScore ms(2);
+ * ms.setPlayerName(0, "player 1");
+ * ms.setPlayerName(1, "player 2");
+ * 
+ * At the end of each game, add the score of each players: + *
+ * KExtHighscore::Score score(KExtHighscore::Won);
+ * score.setScore(100);
+ * ms.addScore(0, score);
+ * score.setType(KExtHighscore::Lost);
+ * score.setScore(20);
+ * ms.addScore(1, score);
+ * 
+ */ +class KDE_EXPORT MultiplayerScores +{ + public: + MultiplayerScores(); + + ~MultiplayerScores(); + + /** + * Set the number of players and clear the scores. + */ + void setPlayerCount(uint nb); + + /** + * Set the name of player. + */ + void setName(uint player, const TQString &name); + + /** + * Add the score of player. + */ + void addScore(uint player, const Score &score); + + /** + * Clear all scores. + */ + void clear(); + + /** + * Show scores. + */ + void show(TQWidget *parent); + + private: + TQValueVector _nbGames; + TQValueVector _scores; + + class MultiplayerScoresPrivate; + MultiplayerScoresPrivate *d; + + friend TQDataStream &operator <<(TQDataStream &stream, + const MultiplayerScores &score); + friend TQDataStream &operator >>(TQDataStream &stream, + MultiplayerScores &score); +}; + +KDE_EXPORT TQDataStream &operator <<(TQDataStream &stream, const MultiplayerScores &score); +KDE_EXPORT TQDataStream &operator >>(TQDataStream &stream, MultiplayerScores &score); + +} // namespace + +#endif diff --git a/libtdegames/highscore/kexthighscore_tab.cpp b/libtdegames/highscore/kexthighscore_tab.cpp new file mode 100644 index 00000000..d47b35a6 --- /dev/null +++ b/libtdegames/highscore/kexthighscore_tab.cpp @@ -0,0 +1,281 @@ +/* + This file is part of the KDE games library + Copyright (C) 2002 Nicolas Hadacek (hadacek@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kexthighscore_tab.h" +#include "kexthighscore_tab.moc" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kexthighscore.h" +#include "kexthighscore_internal.h" + + +namespace KExtHighscore +{ + +//----------------------------------------------------------------------------- +PlayersCombo::PlayersCombo(TQWidget *parent, const char *name) + : TQComboBox(parent, name) +{ + const PlayerInfos &p = internal->playerInfos(); + for (uint i = 0; i'); + connect(this, TQT_SIGNAL(activated(int)), TQT_SLOT(activatedSlot(int))); +} + +void PlayersCombo::activatedSlot(int i) +{ + const PlayerInfos &p = internal->playerInfos(); + if ( i==(int)p.nbEntries() ) emit allSelected(); + else if ( i==(int)p.nbEntries()+1 ) emit noneSelected(); + else emit playerSelected(i); +} + +void PlayersCombo::load() +{ + const PlayerInfos &p = internal->playerInfos(); + for (uint i = 0; iaddWidget(label); + _combo = new PlayersCombo(this); + connect(_combo, TQT_SIGNAL(playerSelected(uint)), + TQT_SLOT(playerSelected(uint))); + connect(_combo, TQT_SIGNAL(allSelected()), TQT_SLOT(allSelected())); + hbox->addWidget(_combo); + hbox->addStretch(1); +} + +void AdditionalTab::init() +{ + uint id = internal->playerInfos().id(); + _combo->setCurrentItem(id); + playerSelected(id); +} + +void AdditionalTab::allSelected() +{ + display(internal->playerInfos().nbEntries()); +} + +TQString AdditionalTab::percent(uint n, uint total, bool withBraces) +{ + if ( n==0 || total==0 ) return TQString(); + TQString s = TQString("%1%").tqarg(100.0 * n / total, 0, 'f', 1); + return (withBraces ? TQString("(") + s + ")" : s); +} + +void AdditionalTab::load() +{ + _combo->load(); +} + + +//----------------------------------------------------------------------------- +const char *StatisticsTab::COUNT_LABELS[Nb_Counts] = { + I18N_NOOP("Total:"), I18N_NOOP("Won:"), I18N_NOOP("Lost:"), + I18N_NOOP("Draw:") +}; +const char *StatisticsTab::TREND_LABELS[Nb_Trends] = { + I18N_NOOP("Current:"), I18N_NOOP("Max won:"), I18N_NOOP("Max lost:") +}; + +StatisticsTab::StatisticsTab(TQWidget *parent) + : AdditionalTab(parent, "statistics_tab") +{ + // construct GUI + TQVBoxLayout *top = static_cast(tqlayout()); + + TQHBoxLayout *hbox = new TQHBoxLayout(top); + TQVBoxLayout *vbox = new TQVBoxLayout(hbox); + TQVGroupBox *group = new TQVGroupBox(i18n("Game Counts"), this); + vbox->addWidget(group); + TQGrid *grid = new TQGrid(3, group); + grid->setSpacing(KDialogBase::spacingHint()); + for (uint k=0; kshowDrawGames ) continue; + (void)new TQLabel(i18n(COUNT_LABELS[k]), grid); + _nbs[k] = new TQLabel(grid); + _percents[k] = new TQLabel(grid); + } + + group = new TQVGroupBox(i18n("Trends"), this); + vbox->addWidget(group); + grid = new TQGrid(2, group); + grid->setSpacing(KDialogBase::spacingHint()); + for (uint k=0; kaddStretch(1); + top->addStretch(1); +} + +void StatisticsTab::load() +{ + AdditionalTab::load(); + const PlayerInfos &pi = internal->playerInfos(); + uint nb = pi.nbEntries(); + _data.resize(nb+1); + for (uint i=0; i<_data.size()-1; i++) { + _data[i].count[Total] = pi.item("nb games")->read(i).toUInt(); + _data[i].count[Lost] = pi.item("nb lost games")->read(i).toUInt() + + pi.item("nb black marks")->read(i).toUInt(); // legacy + _data[i].count[Draw] = pi.item("nb draw games")->read(i).toUInt(); + _data[i].count[Won] = _data[i].count[Total] - _data[i].count[Lost] + - _data[i].count[Draw]; + _data[i].trend[CurrentTrend] = + pi.item("current trend")->read(i).toInt(); + _data[i].trend[WonTrend] = pi.item("max won trend")->read(i).toUInt(); + _data[i].trend[LostTrend] = + -(int)pi.item("max lost trend")->read(i).toUInt(); + } + + for (uint k=0; kshowDrawGames ) continue; + _nbs[k]->setText(TQString::number(d.count[k])); + _percents[k]->setText(percent(d, Count(k))); + } + for (uint k=0; k0 ) s = '+'; + int prec = (i==internal->playerInfos().nbEntries() ? 1 : 0); + _trends[k]->setText(s + TQString::number(d.trend[k], 'f', prec)); + } +} + +//----------------------------------------------------------------------------- +HistogramTab::HistogramTab(TQWidget *parent) + : AdditionalTab(parent, "histogram_tab") +{ + // construct GUI + TQVBoxLayout *top = static_cast(tqlayout()); + + _list = new KListView(this); + _list->setSelectionMode(TQListView::NoSelection); + _list->setItemMargin(3); + _list->setAllColumnsShowFocus(true); + _list->setSorting(-1); + _list->header()->setClickEnabled(false); + _list->header()->setMovingEnabled(false); + top->addWidget(_list); + + _list->addColumn(i18n("From")); + _list->addColumn(i18n("To")); + _list->addColumn(i18n("Count")); + _list->addColumn(i18n("Percent")); + for (uint i=0; i<4; i++) _list->setColumnAlignment(i, AlignRight); + _list->addColumn(TQString()); + + const Item *sitem = internal->scoreInfos().item("score")->item(); + const PlayerInfos &pi = internal->playerInfos(); + const TQMemArray &sh = pi.histogram(); + for (uint k=1; kpretty(0, sh[k-1]); + TQString s2; + if ( k==sh.size() ) s2 = "..."; + else if ( sh[k]!=sh[k-1]+1 ) s2 = sitem->pretty(0, sh[k]); + (void)new KListViewItem(_list, s1, s2); + } +} + +void HistogramTab::load() +{ + AdditionalTab::load(); + const PlayerInfos &pi = internal->playerInfos(); + uint n = pi.nbEntries(); + uint s = pi.histoSize() - 1; + _counts.resize((n+1) * s); + _data.fill(0, n+1); + for (uint k=0; kread(i).toUInt(); + _counts[i*s + k] = nb; + _counts[n*s + k] += nb; + _data[i] += nb; + _data[n] += nb; + } + } + + init(); +} + +void HistogramTab::display(uint i) +{ + const PlayerInfos &pi = internal->playerInfos(); + TQListViewItem *item = _list->firstChild(); + uint s = pi.histoSize() - 1; + for (int k=s-1; k>=0; k--) { + uint nb = _counts[i*s + k]; + item->setText(2, TQString::number(nb)); + item->setText(3, percent(nb, _data[i])); + uint width = (_data[i]==0 ? 0 : tqRound(150.0 * nb / _data[i])); + TQPixmap pixmap(width, 10); + pixmap.fill(blue); + item->setPixmap(4, pixmap); + item = item->nextSibling(); + } +} + +} // namespace diff --git a/libtdegames/highscore/kexthighscore_tab.h b/libtdegames/highscore/kexthighscore_tab.h new file mode 100644 index 00000000..d59afeb5 --- /dev/null +++ b/libtdegames/highscore/kexthighscore_tab.h @@ -0,0 +1,121 @@ +/* + This file is part of the KDE games library + Copyright (C) 2002 Nicolas Hadacek (hadacek@kde.org) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef KEXTHIGHSCORE_TAB_H +#define KEXTHIGHSCORE_TAB_H + +#include +#include + +class TQLabel; +class KListView; + + +namespace KExtHighscore +{ + +//----------------------------------------------------------------------------- +class PlayersCombo : public TQComboBox +{ + Q_OBJECT + TQ_OBJECT + public: + PlayersCombo(TQWidget *parent = 0, const char *name = 0); + + void load(); + + signals: + void playerSelected(uint i); + void allSelected(); + void noneSelected(); + + private slots: + void activatedSlot(int i); +}; + +//----------------------------------------------------------------------------- +class AdditionalTab : public TQWidget +{ + Q_OBJECT + TQ_OBJECT + public: + AdditionalTab(TQWidget *parent, const char *name); + + virtual void load(); + + private slots: + void playerSelected(uint i) { display(i) ; } + void allSelected(); + + protected: + void init(); + static TQString percent(uint n, uint total, bool withBraces = false); + virtual void display(uint i) = 0; + + private: + PlayersCombo *_combo; +}; + +//----------------------------------------------------------------------------- +class StatisticsTab : public AdditionalTab +{ + Q_OBJECT + TQ_OBJECT + public: + StatisticsTab(TQWidget *parent); + + void load(); + + private: + enum Count { Total = 0, Won, Lost, Draw, Nb_Counts }; + static const char *COUNT_LABELS[Nb_Counts]; + enum Trend { CurrentTrend = 0, WonTrend, LostTrend, Nb_Trends }; + static const char *TREND_LABELS[Nb_Trends]; + struct Data { + uint count[Nb_Counts]; + double trend[Nb_Trends]; + }; + TQMemArray _data; + TQLabel *_nbs[Nb_Counts], *_percents[Nb_Counts], *_trends[Nb_Trends]; + + TQString percent(const Data &, Count) const; + void display(uint i); +}; + +//----------------------------------------------------------------------------- +class HistogramTab : public AdditionalTab +{ + Q_OBJECT + TQ_OBJECT + public: + HistogramTab(TQWidget *parent); + + void load(); + + private: + TQMemArray _counts; + TQMemArray _data; + KListView *_list; + + void display(uint i); +}; + +} // namespace + +#endif diff --git a/libtdegames/highscore/kfilelock.cpp b/libtdegames/highscore/kfilelock.cpp new file mode 100644 index 00000000..7dc83b96 --- /dev/null +++ b/libtdegames/highscore/kfilelock.cpp @@ -0,0 +1,88 @@ +/* + This file is part of the KDE games library + Copyright (C) 2003 Nicolas Hadacek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kfilelock.h" + +#include +#include +#include + +#include + + +KFileLock::KFileLock(int fd) + : _fd(fd), _locked(false) +{} + +int KFileLock::lock() +{ + kdDebug(11002) << "lock fd=" << _fd << endl; +#ifdef F_SETLK +# ifndef SEEK_SET +# define SEEK_SET 0 +# endif + struct flock lock_data; + lock_data.l_type = F_WRLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = lock_data.l_len = 0; + if ( fcntl(_fd, F_SETLK, &lock_data)==-1 ) { + if ( errno==EAGAIN ) return -2; + return -1; + } +#else +# ifdef LOCK_EX + if ( flock (_fd, LOCK_EX|LOCK_NB)==-1 ) { + if ( errno==EWOULDBLOCK ) return -2; + return -1; + } +# else + if ( lockf(_fd, F_TLOCK, 0)==-1 ) { + if ( errno==EACCES ) return -2; + return -1; + } +# endif +#endif + _locked = true; + return 0; +} + +KFileLock::~KFileLock() +{ + unlock(); +} + +void KFileLock::unlock() +{ + if ( !_locked ) return; + kdDebug(11002) << "unlock" << endl; +# ifdef F_SETLK + struct flock lock_data; + lock_data.l_type = F_UNLCK; + lock_data.l_whence = SEEK_SET; + lock_data.l_start = lock_data.l_len = 0; + (void)fcntl(_fd, F_SETLK, &lock_data); +# else +# ifdef F_ULOCK + lockf(_fd, F_ULOCK, 0); +# else + flock(_fd, LOCK_UN); +# endif +# endif + _locked = false; +} diff --git a/libtdegames/highscore/kfilelock.h b/libtdegames/highscore/kfilelock.h new file mode 100644 index 00000000..2e1841ba --- /dev/null +++ b/libtdegames/highscore/kfilelock.h @@ -0,0 +1,53 @@ +/* + This file is part of the KDE games library + Copyright (C) 2003 Nicolas Hadacek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +#ifndef KFILELOCK_H +#define KFILELOCK_H + + +class KFileLock +{ +public: + KFileLock(int fd); + + /** Call unlock(). */ + ~KFileLock(); + + /** @return the file descriptor. */ + int fd() const { return _fd; } + + /* + * Lock the file. + * @return 0 on success, -1 on failure (no permission) and -2 if another + * process is currently locking the file. + */ + int lock(); + + /** Unlock the file. */ + void unlock(); + + /** @return true if we currently lock the file. */ + bool isLocked() const { return _locked; } + +private: + int _fd; + bool _locked; +}; + + +#endif diff --git a/libtdegames/highscore/khighscore.cpp b/libtdegames/highscore/khighscore.cpp new file mode 100644 index 00000000..6d696020 --- /dev/null +++ b/libtdegames/highscore/khighscore.cpp @@ -0,0 +1,262 @@ +/* + This file is part of the KDE games library + Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) + Copyright (C) 2003 Nicolas Hadacek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/* + $Id$ +*/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "khighscore.h" +#include "kconfigrawbackend.h" +#include "kfilelock.h" + +#define GROUP "KHighscore" + +class KHighscorePrivate +{ +public: + KHighscorePrivate() {} + + TQString group; + bool global; +}; + +KFileLock *KHighscore::_lock = 0; +KRawConfig *KHighscore::_config = 0; +static KStaticDeleter lockSD; +static KStaticDeleter configSD; + + +KHighscore::KHighscore(TQObject* parent) + : TQObject(parent) +{ + init(true); +} + +KHighscore::KHighscore(bool forceLocal, TQObject* parent) + : TQObject(parent) +{ + init(forceLocal); +} + +void KHighscore::init(bool forceLocal) +{ + d = new KHighscorePrivate; +#ifdef HIGHSCORE_DIRECTORY + d->global = !forceLocal; + if ( d->global && _lock==0 ) + kdFatal(11002) << "KHighscore::init should be called before!!" << endl; +#else + d->global = false; + Q_UNUSED(forceLocal); +#endif + readCurrentConfig(); +} + +bool KHighscore::isLocked() const +{ + return (d->global ? _lock->isLocked() : true); +} + +void KHighscore::readCurrentConfig() +{ + if ( d->global ) _config->reparseConfiguration(); +} + +void KHighscore::init(const char *appname) +{ +#ifdef HIGHSCORE_DIRECTORY + const TQString filename = TQString::fromLocal8Bit("%1/%2.scores") + .tqarg(HIGHSCORE_DIRECTORY).tqarg(appname); + int fd = open(filename.local8Bit(), O_RDWR); + if ( fd<0 ) kdFatal(11002) << "cannot open global highscore file \"" + << filename << "\"" << endl; + lockSD.setObject(_lock, new KFileLock(fd)); + configSD.setObject(_config, new KRawConfig(fd, true)); // read-only + + // drop the effective gid + int gid = getgid(); + setregid(gid, gid); +#else + Q_UNUSED(appname); +#endif +} + +bool KHighscore::lockForWriting(TQWidget *widget) +{ + if ( isLocked() ) return true; + + bool first = true; + for (;;) { + kdDebug(11002) << "try locking" << endl; + // lock the highscore file (it should exist) + int result = _lock->lock(); + bool ok = ( result==0 ); + kdDebug(11002) << "locking system-wide highscore file res=" + << result << " (ok=" << ok << ")" << endl; + if (ok) { + readCurrentConfig(); + _config->setReadOnly(false); + return true; + } + + if ( !first ) { + KGuiItem item = KStdGuiItem::cont(); + item.setText(i18n("Retry")); + int res = KMessageBox::warningContinueCancel(widget, i18n("Cannot access the highscore file. Another user is probably currently writing to it."), TQString(), item, "ask_lock_global_highscore_file"); + if ( res==KMessageBox::Cancel ) break; + } else sleep(1); + first = false; + } + return false; +} + +void KHighscore::writeAndUnlock() +{ + if ( !d->global ) { + kapp->config()->sync(); + return; + } + if ( !isLocked() ) return; + + kdDebug(11002) << "unlocking" << endl; + _config->sync(); // write config + _lock->unlock(); + _config->setReadOnly(true); +} + +KHighscore::~KHighscore() +{ + writeAndUnlock(); + delete d; +} + +KConfig* KHighscore::config() const +{ + return (d->global ? _config : kapp->config()); +} + +void KHighscore::writeEntry(int entry, const TQString& key, const TQVariant& value) +{ + Q_ASSERT( isLocked() ); + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + cg.config()->writeEntry(confKey, value); +} + +void KHighscore::writeEntry(int entry, const TQString& key, int value) +{ + Q_ASSERT( isLocked() ); + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + cg.config()->writeEntry(confKey, value); +} + +void KHighscore::writeEntry(int entry, const TQString& key, const TQString &value) +{ + Q_ASSERT (isLocked() ); + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + cg.config()->writeEntry(confKey, value); +} + +TQVariant KHighscore::readPropertyEntry(int entry, const TQString& key, const TQVariant& pDefault) const +{ + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + return cg.config()->readPropertyEntry(confKey, pDefault); +} + +TQString KHighscore::readEntry(int entry, const TQString& key, const TQString& pDefault) const +{ + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + return cg.config()->readEntry(confKey, pDefault); +} + +int KHighscore::readNumEntry(int entry, const TQString& key, int pDefault) const +{ + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + return cg.config()->readNumEntry(confKey, pDefault); +} + +bool KHighscore::hasEntry(int entry, const TQString& key) const +{ + KConfigGroupSaver cg(config(), group()); + TQString confKey = TQString("%1_%2").tqarg(entry).tqarg(key); + return cg.config()->hasKey(confKey); +} + +TQStringList KHighscore::readList(const TQString& key, int lastEntry) const +{ + TQStringList list; + for (int i = 1; hasEntry(i, key) && ((lastEntry > 0) ? (i <= lastEntry) : true); i++) { + list.append(readEntry(i, key)); + } + return list; +} + +void KHighscore::writeList(const TQString& key, const TQStringList& list) +{ + for (int unsigned i = 1; i <= list.count(); i++) { + writeEntry(i, key, list[i - 1]); + } +} + +void KHighscore::setHighscoreGroup(const TQString& group) +{ + d->group = group; +} + +const TQString& KHighscore::highscoreGroup() const +{ + return d->group; +} + +TQString KHighscore::group() const +{ + if ( highscoreGroup().isNull() ) + return (d->global ? TQString() : GROUP); + return (d->global ? highscoreGroup() + : TQString("%1_%2").tqarg(GROUP).tqarg(highscoreGroup())); +} + +bool KHighscore::hasTable() const +{ return config()->hasGroup(group()); } + +void KHighscore::sync() +{ + writeAndUnlock(); +} + +#include "khighscore.moc" diff --git a/libtdegames/highscore/khighscore.h b/libtdegames/highscore/khighscore.h new file mode 100644 index 00000000..b7b6fb5e --- /dev/null +++ b/libtdegames/highscore/khighscore.h @@ -0,0 +1,312 @@ +/* + This file is part of the KDE games library + Copyright (C) 2001 Andreas Beckermann (b_mann@gmx.de) + Copyright (C) 2003 Nicolas Hadacek + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +/* + $Id$ +*/ +#ifndef __KHIGHSCORE_H__ +#define __KHIGHSCORE_H__ + +#include +#include +#include +class KConfig; +class KFileLock; +class KRawConfig; +class KHighscorePrivate; + +/** + * @short Class for managing highscore tables + * + * This is the KDE class for saving and reading highscore tables. It offers the + * possibility for system-wide highscore tables (configure with e.g. + * --enable-highscore-dir=/var/games) and a theoretically unlimited number of + * entries. + * + * You can specify different "keys" for an entry - just like the KConfig + * keys. But it will be prefixed with the number of the entry. For example you + * will probably use something like this to save the name of the player on the + * top of the list (ie the winner): + * \code + * highscore->writeEntry(1, "name", myPlayer->name()); + * \endcode + * Note that it doesn't really matter if you use "0" or "1" as the first entry + * of the list as long as your program always uses the same for the first + * entry. I recommend to use "1", as several convenience methods use this. + * + * You can also specify different groups using setHighscoreGroup. Just + * like the keys mentioned above the groups behave like groups in KConfig + * but are prefixed with "KHighscore_". The default group is just "KHighscore". + * You might use this e.g. to create different highscore tables like + * \code + * table->setHighscoreGroup("Easy"); + * // write the highscores for level "easy" to the table + * writeEasyHighscores(table); + * + * table->setHighscore("Player_1"); + * // write player specific highscores to the table + * writePlayerHighscores(table); + * \endcode + * As you can see above you can also use this to write the highscores of a + * single player, so the "best times" of a player. To write highscores for a + * specific player in a specific level you will have to use a more complex way: + * \code + * TQString group = TQString("%1_%2").tqarg(player).tqarg(level); + * table->setGroup(group); + * writeHighscore(table, player, level); + * \endcode + * + * Also note that you MUST NOT mark the key or the group for translation! I.e. + * don't use i18n() for the keys or groups! Here is the code to read the above + * written entry: + * \code + * TQString firstName = highscore->readEntry(0, "name"); + * \endcode + * Easy, what? + * @author Andreas Beckermann + **/ +class KDE_EXPORT KHighscore : public TQObject +{ + Q_OBJECT + TQ_OBJECT +public: + /** @obsolete + * Constructor. The highscore file is forced to be local to support + * games using the old behaviour. + */ + KHighscore(TQObject* parent = 0); + + /** + * Constructor. + * + * @param forceLocal if true, the local highscore file is used even + * when the configuration has been set to use a system-wide file. This + * is convenient for converting highscores from legacy applications. + * @param parent parent widget for this widget + * @since 3.2 + */ + KHighscore(bool forceLocal, TQObject *parent); + + /** + * Read the current state of the highscore file. Remember that when + * it's not locked for writing, this file can change at any time. + * (This method is only useful for a system-wide highscore file). + * @since 3.2 + */ + void readCurrentConfig(); + + /** @since 3.2 + * This method open the system-wide highscore file using the effective + * group id of the game executable (which should be "games"). The + * effective group id is completely dropped afterwards. + * + * Note: this method should be called in main() before creating a + * KApplication and doing anything else (KApplication checks that the + * program is not suid/sgid and will exit the program for security + * reason if it is the case). + */ + static void init(const char *appname); + + /** @since 3.2 + * Lock the system-wide highscore file for writing (does nothing and + * return true if the local file is used). + * You should perform writing without GUI interaction to avoid + * blocking and don't forget to unlock the file as soon as possible + * with writeAndUnlock(). + * + * If the config file cannot be locked, + * the method waits for 1 second and, if it failed again, displays + * a message box asking for retry or cancel. + * @param widget used as the parent of the message box. + * + * @return false on error or if the config file is locked by another + * process. In such case, the config stays read-only. + */ + bool lockForWriting(TQWidget *widget = 0); + + /** + * Effectively write and unlock the system-wide highscore file + * (@see lockForWriting). + * If using a local highscore file, it will sync the config. + * @since 3.2 + */ + void writeAndUnlock(); + + /** + * @return true if the highscore file is locked or if a local + * file is used. + * @since 3.2 + */ + bool isLocked() const; + + /** + * Destructor. + * If necessary, write and unlock the highscore file. + */ + ~KHighscore(); + + /** + * @param entry The number of the entry / the placing of the player + * @param key A key for this entry. E.g. "name" for the name of the + * player. Nearly the same as the usual keys in KConfig - but they + * are prefixed with the entry number + * @param value The value of this entry + **/ + void writeEntry(int entry, const TQString& key, const TQString& value); + + /** + * This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + **/ + void writeEntry(int entry, const TQString& key, int value); + + /** + * This is an overloaded member function, provided for convenience. + * It differs from the above function only in what argument(s) it accepts. + * See KConfigBase documentation for allowed TQVariant::Type. + **/ + void writeEntry(int entry, const TQString& key, const TQVariant &value); + + /** + * Reads an entry from the highscore table. + * @param entry The number of the entry / the placing to be read + * @param key The key of the entry. E.g. "name" for the name of the + * player. Nearly the same as the usual keys in KConfig - but they + * are prefixed with the entry number + * @param pDefault This will be used as default value if the key+pair + * entry can't be found. + * @return The value of this entry+key pair or pDefault if the entry+key + * pair doesn't exist + **/ + TQString readEntry(int entry, const TQString& key, const TQString& pDefault = TQString()) const; + + /** + * Read a numeric value. + * @param entry The number of the entry / the placing to be read + * @param key The key of the entry. E.g. "name" for the name of the + * player. Nearly the same as the usual keys in KConfig - but they + * are prefixed with the entry number + * @param pDefault This will be used as default value if the key+pair + * entry can't be found. + * @return The value of this entry+key pair or pDefault if the entry+key + * pair doesn't exist + **/ + int readNumEntry(int entry, const TQString& key, int pDefault = -1) const; + + /** + * Read a TQVariant entry. + * See KConfigBase documentation for allowed TQVariant::Type. + * + * @return the value of this entry+key pair or pDefault if the entry+key + * pair doesn't exist or + */ + TQVariant readPropertyEntry(int entry, const TQString &key, const TQVariant &pDefault) const; + + /** + * @return True if the highscore table conatins the entry/key pair, + * otherwise false + **/ + bool hasEntry(int entry, const TQString& key) const; + + /** + * Reads a list of entries from the highscore table starting at 1 until + * lastEntry. If an entry between those numbers doesn't exist the + * function aborts reading even if after the missing entry is an + * existing one. The first entry of the list is the first placing, the + * last on is the last placing. + * @return A list of the entries of this key. You could also call + * readEntry(i, key) where i is from 1 to 20. Note that this function + * depends on "1" as the first entry! + * @param key The key of the entry. E.g. "name" for the name of the + * player. Nearly the same as the usual keys in KConfig - but they + * are prefixed with the entry number + * @param lastEntry the last entry which will be includes into the list. + * 1 will include a list with maximal 1 entry - 20 a list with maximal + * 20 entries. If lastEntry is <= 0 then rading is only stopped when when an + * entry does not exist. + **/ + TQStringList readList(const TQString& key, int lastEntry = 20) const; + + /** + * Writes a list of entries to the highscore table. + * + * The first entry is prefixed with "1". Using this method is a short + * way of calling writeEntry(i, key, list[i]) from i = 1 to + * list.count() + * @param key A key for the entry. E.g. "name" for the name of the + * player. Nearly the same as the usual keys in KConfig - but they + * are prefixed with the entry number + * @param list The list of values + **/ + void writeList(const TQString& key, const TQStringList& list); + + /** + * @return Whether a highscore table exists. You can use this + * function to indicate whether KHighscore created a highscore table + * before and - if not - read your old (non-KHighscore) table instead. + * This way you can safely read an old table and save it using + * KHighscore without losing any data + **/ + bool hasTable() const; + + /** @obsolete + * This does the same as writeAndUnlock(). + */ + void sync(); + + /** + * Set the new highscore group. The group is being prefixed with + * "KHighscore_" in the table. + * @param groupname The new groupname. E.g. use "easy" for the easy + * level of your game. If you use TQString() (the default) the + * default group is used. + **/ + void setHighscoreGroup(const TQString& groupname = TQString()); + + /** + * @return The currently used group. This doesn't contain the prefix + * ("KHighscore_") but the same as setHighscoreGroup uses. The + * default is TQString() + **/ + const TQString& highscoreGroup() const; + +protected: + /** + * @return A groupname to be used in KConfig. Used internally to + * prefix the value from highscoreGroup() with "KHighscore_" + **/ + TQString group() const; + + /** + * @return A pointer to the KConfig object to be used. This is + * either kapp->config() (default) or a KSimpleConfig object for + * a system-wide highscore file. + **/ + KConfig* config() const; + + void init(bool forceLocal); + +private: + KHighscorePrivate* d; + + static KFileLock *_lock; // lock on system-wide highscore file + static KRawConfig *_config; // config for system-wide highscore file +}; + +#endif diff --git a/libtdegames/highscore/kscoredialog.cpp b/libtdegames/highscore/kscoredialog.cpp new file mode 100644 index 00000000..e799883b --- /dev/null +++ b/libtdegames/highscore/kscoredialog.cpp @@ -0,0 +1,411 @@ +/**************************************************************** +Copyright (c) 1998 Sandro Sigala . +Copyright (c) 2001 Waldo Bastian +All rights reserved. + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of the author not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +The author disclaim all warranties with regard to this +software, including all implied warranties of merchantability +and fitness. In no event shall the author be liable for any +special, indirect or consequential damages or any damages +whatsoever resulting from loss of use, data or profits, whether +in an action of contract, negligence or other tortious action, +arising out of or in connection with the use or performance of +this software. +****************************************************************/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "kscoredialog.h" + +class KScoreDialog::KScoreDialogPrivate +{ +public: + TQPtrList scores; + TQWidget *page; + TQGridLayout *tqlayout; + TQLineEdit *edit; + TQPtrVector stack; + TQPtrVector labels; + TQLabel *commentLabel; + TQString comment; + int fields; + int newName; + int latest; + int nrCols; + bool loaded; + TQString configGroup; + + TQMap col; + TQMap header; + TQMap key; + TQString player; +}; + + +KScoreDialog::KScoreDialog(int fields, TQWidget *parent, const char *oname) + : KDialogBase(parent, oname, true, i18n("High Scores"), Ok, Ok, true) +{ + d = new KScoreDialogPrivate(); + d->edit = 0; + d->fields = fields; + d->newName = -1; + d->latest = -1; + d->loaded = false; + d->nrCols = 0; + d->configGroup = "High Score"; + + d->scores.setAutoDelete(true); + d->header[Name] = i18n("Name"); + d->key[Name] = "Name"; + + d->header[Date] = i18n("Date"); + d->key[Date] = "Date"; + + d->header[Level] = i18n("Level"); + d->key[Level] = "Level"; + + d->header[Score] = i18n("Score"); + d->key[Score] = "Score"; + d->page = makeMainWidget(); + + connect(this, TQT_SIGNAL(okClicked()), TQT_SLOT(slotGotName())); +} + +KScoreDialog::~KScoreDialog() +{ + delete d; +} + +void KScoreDialog::setConfigGroup(const TQString &group) +{ + d->configGroup = group; + d->loaded = false; +} + +void KScoreDialog::setComment(const TQString &comment) +{ + d->comment = comment; +} + +void KScoreDialog::addField(int field, const TQString &header, const TQString &key) +{ + d->fields |= field; + d->header[field] = header; + d->key[field] = key; +} + +void KScoreDialog::setupDialog() +{ + d->nrCols = 1; + + for(int field = 1; field < d->fields; field = field * 2) + { + if (d->fields & field) + d->col[field] = d->nrCols++; + } + + d->tqlayout = new TQGridLayout(d->page, 15, d->nrCols, marginHint() + 20, spacingHint()); + d->tqlayout->addRowSpacing(4, 15); + + d->commentLabel = new TQLabel(d->page); + d->commentLabel->tqsetAlignment(AlignVCenter | AlignHCenter); + d->tqlayout->addMultiCellWidget(d->commentLabel, 1, 1, 0, d->nrCols-1); + + TQFont bold = font(); + bold.setBold(true); + + TQLabel *label; + d->tqlayout->addColSpacing(0, 50); + label = new TQLabel(i18n("Rank"), d->page); + d->tqlayout->addWidget(label, 3, 0); + label->setFont(bold); + + for(int field = 1; field < d->fields; field = field * 2) + { + if (d->fields & field) + { + d->tqlayout->addColSpacing(d->col[field], 50); + + label = new TQLabel(d->header[field], d->page); + d->tqlayout->addWidget(label, 3, d->col[field], field <= Name ? AlignLeft : AlignRight); + label->setFont(bold); + } + } + + KSeparator *sep = new KSeparator(Qt::Horizontal, d->page); + d->tqlayout->addMultiCellWidget(sep, 4, 4, 0, d->nrCols-1); + + d->labels.resize(d->nrCols * 10); + d->stack.resize(10); + + TQString num; + for (int i = 1; i <= 10; ++i) { + TQLabel *label; + num.setNum(i); + label = new TQLabel(i18n("#%1").tqarg(num), d->page); + d->labels.insert((i-1)*d->nrCols + 0, label); + d->tqlayout->addWidget(label, i+4, 0); + if (d->fields & Name) + { + TQWidgetStack *stack = new TQWidgetStack(d->page); + d->stack.insert(i-1, stack); + d->tqlayout->addWidget(stack, i+4, d->col[Name]); + label = new TQLabel(d->page); + d->labels.insert((i-1)*d->nrCols + d->col[Name], label); + stack->addWidget(label); + stack->raiseWidget(label); + } + for(int field = Name * 2; field < d->fields; field = field * 2) + { + if (d->fields & field) + { + label = new TQLabel(d->page); + d->labels.insert((i-1)*d->nrCols + d->col[field], label); + d->tqlayout->addWidget(label, i+4, d->col[field], AlignRight); + } + } + } +} + +void KScoreDialog::aboutToShow() +{ + if (!d->loaded) + loadScores(); + + if (!d->nrCols) + setupDialog(); + + d->commentLabel->setText(d->comment); + if (d->comment.isEmpty()) + { + d->commentLabel->setMinimumSize(TQSize(1,1)); + d->commentLabel->hide(); + d->tqlayout->addRowSpacing(0, -15); + d->tqlayout->addRowSpacing(2, -15); + } + else + { + d->commentLabel->setMinimumSize(d->commentLabel->tqsizeHint()); + d->commentLabel->show(); + d->tqlayout->addRowSpacing(0, -10); + d->tqlayout->addRowSpacing(2, 10); + } + d->comment = TQString(); + + TQFont normal = font(); + TQFont bold = normal; + bold.setBold(true); + + TQString num; + for (int i = 1; i <= 10; ++i) { + TQLabel *label; + num.setNum(i); + FieldInfo *score = d->scores.at(i-1); + label = d->labels[(i-1)*d->nrCols + 0]; + if (i == d->latest) + label->setFont(bold); + else + label->setFont(normal); + + if (d->fields & Name) + { + if (d->newName == i) + { + TQWidgetStack *stack = d->stack[i-1]; + d->edit = new TQLineEdit(d->player, stack); + d->edit->setMinimumWidth(40); + stack->addWidget(d->edit); + stack->raiseWidget(d->edit); + d->edit->setFocus(); + connect(d->edit, TQT_SIGNAL(returnPressed()), + this, TQT_SLOT(slotGotReturn())); + } + else + { + label = d->labels[(i-1)*d->nrCols + d->col[Name]]; + if (i == d->latest) + label->setFont(bold); + else + label->setFont(normal); + label->setText((*score)[Name]); + } + + } + for(int field = Name * 2; field < d->fields; field = field * 2) + { + if (d->fields & field) + { + label = d->labels[(i-1)*d->nrCols + d->col[field]]; + if (i == d->latest) + label->setFont(bold); + else + label->setFont(normal); + label->setText((*score)[field]); + } + } + } + d->latest = -1; + setFixedSize(tqminimumSizeHint()); +} + +void KScoreDialog::loadScores() +{ + TQString key, value; + d->loaded = true; + d->scores.clear(); + KConfigGroup config(kapp->config(), d->configGroup.utf8()); + + d->player = config.readEntry("LastPlayer"); + + TQString num; + for (int i = 1; i <= 10; ++i) { + num.setNum(i); + FieldInfo *score = new FieldInfo(); + for(int field = 1; field < d->fields; field = field * 2) + { + if (d->fields & field) + { + key = "Pos" + num + d->key[field]; + (*score)[field] = config.readEntry(key, "-"); + } + } + d->scores.append(score); + } +} + +void KScoreDialog::saveScores() +{ + TQString key, value; + KConfigGroup config(kapp->config(), d->configGroup.utf8()); + + config.writeEntry("LastPlayer", d->player); + + TQString num; + for (int i = 1; i <= 10; ++i) { + num.setNum(i); + FieldInfo *score = d->scores.at(i-1); + for(int field = 1; field < d->fields; field = field * 2) + { + if (d->fields & field) + { + key = "Pos" + num + d->key[field]; + config.writeEntry(key, (*score)[field]); + } + } + } + kapp->config()->sync(); +} + +int KScoreDialog::addScore(int newScore, const FieldInfo &newInfo, bool askName) +{ + return addScore(newScore, newInfo, askName, false); +} + +int KScoreDialog::addScore(int newScore, const FieldInfo &newInfo, bool askName, bool lessIsMore) +{ + if (!d->loaded) + loadScores(); + FieldInfo *score = d->scores.first(); + int i = 1; + for(; score; score = d->scores.next(), i++) + { + bool ok; + int num_score = (*score)[Score].toLong(&ok); + if (lessIsMore && !ok) + num_score = 1 << 30; + if (((newScore > num_score) && !lessIsMore) || + ((newScore < num_score) && lessIsMore)) + { + score = new FieldInfo(newInfo); + (*score)[Score].setNum(newScore); + d->scores.insert(i-1, score); + d->scores.remove(10); + d->latest = i; + if (askName) + d->newName = i; + else + saveScores(); + if (i == 1) + d->comment = i18n("Excellent!\nYou have a new high score!"); + else + d->comment = i18n("Well done!\nYou made it to the high score list!"); + return i; + } + } + return 0; +} + +void KScoreDialog::show() +{ + aboutToShow(); + KDialogBase::show(); +} + +void KScoreDialog::slotGotReturn() +{ + TQTimer::singleShot(0, this, TQT_SLOT(slotGotName())); +} + +void KScoreDialog::slotGotName() +{ + if (d->newName == -1) return; + + d->player = d->edit->text(); + + (*d->scores.at(d->newName-1))[Name] = d->player; + saveScores(); + + TQFont bold = font(); + bold.setBold(true); + + TQLabel *label = d->labels[(d->newName-1)*d->nrCols + d->col[Name]]; + label->setFont(bold); + label->setText(d->player); + d->stack[(d->newName-1)]->raiseWidget(label); + delete d->edit; + d->edit = 0; + d->newName = -1; +} + +int KScoreDialog::highScore() +{ + if (!d->loaded) + loadScores(); + + return (*d->scores.first())[Score].toInt(); +} + +void KScoreDialog::keyPressEvent( TQKeyEvent *ev) +{ + if ((d->newName != -1) && (ev->key() == Key_Return)) + { + ev->ignore(); + return; + } + KDialogBase::keyPressEvent(ev); +} + + +#include "kscoredialog.moc" diff --git a/libtdegames/highscore/kscoredialog.h b/libtdegames/highscore/kscoredialog.h new file mode 100644 index 00000000..99a9f70b --- /dev/null +++ b/libtdegames/highscore/kscoredialog.h @@ -0,0 +1,126 @@ +/**************************************************************** +Copyright (c) 1998 Sandro Sigala . +Copyright (c) 2001 Waldo Bastian +All rights reserved. + +Permission to use, copy, modify, and distribute this software +and its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name of the author not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +The author disclaim all warranties with regard to this +software, including all implied warranties of merchantability +and fitness. In no event shall the author be liable for any +special, indirect or consequential damages or any damages +whatsoever resulting from loss of use, data or profits, whether +in an action of contract, negligence or other tortious action, +arising out of or in connection with the use or performance of +this software. +****************************************************************/ + +#ifndef KSCOREDIALOG_H +#define KSCOREDIALOG_H + +#include +#include + +#include +#include +class TQGridLayout; +class TQLineEdit; +class TQWidgetStack; + +/** + * A simple high score dialog. + */ +class KDE_EXPORT KScoreDialog : public KDialogBase { + Q_OBJECT + TQ_OBJECT + +public: + enum Fields { Name = 1 << 0, + Level = 1 << 1, + + Custom1 = 1 << 10, + Custom2 = 1 << 11, + Custom3 = 1 << 12, + + Date = 1 << 27, + Time = 1 << 28, + Score = 1 << 29 }; + + typedef TQMap FieldInfo; + + /** + * @param fields Which fields should be listed. + * @param parent passed to parent TQWidget constructor + * @param name passed to parent TQWidget constructor + */ + KScoreDialog(int fields, TQWidget *parent=0, const char *name=0); + + ~KScoreDialog(); + + /** + * @param group to use for reading/writing highscores from/to. By default + * the class will use "High Score" + */ + void setConfigGroup(const TQString &group); + + /** + * @param comment to add when showing high-scores. + * The comment is only used once. + */ + void setComment(const TQString &comment); + + /** + * Define an extra FieldInfo entry. + * @param field Id of this field + * @param header Header shown in the dialog for this field + * @param key used to store this field with. + */ + void addField(int field, const TQString &header, const TQString &key); + + /** + * Adds a new score to the list. + * + * @param newScore the score of this game. + * @param newInfo additional info about the score. + * @param askName Whether to prompt for the players name. + * @param lessIsMore If true, the lowest score is the best score. + * + * @returns The highscore position if the score was good enough to + * make it into the list (1 being topscore) or 0 otherwise. + */ + int addScore(int newScore, const FieldInfo &newInfo, bool askName, bool lessIsMore); + int addScore(int newScore, const FieldInfo &newInfo, bool askName=true); + + /** + * Returns the current best score. + */ + int highScore(); + + virtual void show(); + +private slots: + void slotGotReturn(); + void slotGotName(); + +private: + /* read scores */ + void loadScores(); + void saveScores(); + + void aboutToShow(); + void setupDialog(); + void keyPressEvent( TQKeyEvent *ev); + +private: + class KScoreDialogPrivate; + KScoreDialogPrivate *d; +}; + +#endif // !KSCOREDIALOG_H -- cgit v1.2.1