1/****************************************************************
2Copyright (c) 1998 Sandro Sigala <ssigala@globalnet.it>
3Copyright (c) 2001 Waldo Bastian <bastian@kde.org>
4Copyright (c) 2007 Matt Williams <matt@milliams.com>
5All rights reserved.
6
7Permission to use, copy, modify, and distribute this software
8and its documentation for any purpose and without fee is hereby
9granted, provided that the above copyright notice appear in all
10copies and that both that the copyright notice and this
11permission notice and warranty disclaimer appear in supporting
12documentation, and that the name of the author not be used in
13advertising or publicity pertaining to distribution of the
14software without specific, written prior permission.
15
16The author disclaim all warranties with regard to this
17software, including all implied warranties of merchantability
18and fitness. In no event shall the author be liable for any
19special, indirect or consequential damages or any damages
20whatsoever resulting from loss of use, data or profits, whether
21in an action of contract, negligence or other tortious action,
22arising out of or in connection with the use or performance of
23this software.
24****************************************************************/
25
26#ifndef KSCOREDIALOG_H
27#define KSCOREDIALOG_H
28
29#include <libkdegames_export.h>
30
31#include <QtCore/QMap>
32#include <QtCore/QFlags>
33
34#include <kdialog.h>
35
36class KLocalizedString;
37class KgDifficulty;
38
39/**
40 * \class KScoreDialog kscoredialog.h <KScoreDialog>
41 *
42 * @short A simple high score implementation
43 *
44 * This class can be used both for displaying the current high scores
45 * and also for adding new highscores. It is the recommended way of
46 * implementing a simple highscore table.
47 *
48 * To display the current highscores it is simply a case of creating
49 * a KScoreDialog object and calling exec(). This example code will
50 * display the Name and Score (the score is always added automatically
51 * unless hidden @ref hideField since it is used for sorting) of the
52 * top 10 players:
53 * \code
54 * KScoreDialog ksdialog(this);
55 * ksdialog.exec();
56 * \endcode
57 *
58 * To add a new highscore, e.g. at the end of a game you simply create an
59 * object with the @ref Fields you want to write (i.e. KScoreDialog::Name |
60 * KScoreDialog::Score), call addScore and then (optionally) display
61 * the dialog.
62 * This code will allow you to add a highscore with a Name and Score
63 * field. If it's the first time a player has a score on the table, they
64 * will be prompted for their name but subsequent times they will have
65 * their name filled in automatically.
66 * \code
67 * KScoreDialog ksdialog(this);
68 * ksdialog.addScore(playersScore);
69 * ksdialog.exec();
70 * \endcode
71 *
72 * Or if you want to fill the name in from the code you can pass a default
73 * name by doing
74 * \code
75 * KScoreDialog::FieldInfo scoreInfo;
76 * scoreInfo[KScoreDialog::Name] = "Matt";
77 * scoreInfo[KScoreDialog::Score].setNum(playersScore);
78 * ksdialog.addScore(scoreInfo);
79 * \endcode
80 *
81 * If you want to add an extra field (e.g. the number of moves taken) then
82 * do
83 * \code
84 * KScoreDialog::FieldInfo scoreInfo;
85 * scoreInfo[KScoreDialog::Name] = "Matt";
86 * scoreInfo[KScoreDialog::Score].setNum(playersScore);
87 *
88 * ksdialog.addField(KScoreDialog::Custom1, "Num of Moves", "moves");
89 * scoreInfo[KScoreDialog::Custom1].setNum(42);
90 *
91 * ksdialog.addScore(scoreInfo);
92 * \endcode
93 * You can define up to 5 Custom fields.
94 * @author Matt Williams <matt@milliams.com>
95 */
96class KDEGAMES_EXPORT KScoreDialog : public KDialog
97{
98 Q_OBJECT
99
100 public:
101 ///Highscore fields
102 enum Fields {
103 Name = 1 << 0,
104 Level = 1 << 1,
105 Date = 1 << 2,
106 Time = 1 << 3,
107 Score = 1 << 4,
108
109 Custom1 = 1 << 10, ///<Field for custom information
110 Custom2 = 1 << 11,
111 Custom3 = 1 << 12,
112 Custom4 = 1 << 13,
113 Custom5 = 1 << 14,
114
115 Max = 1 << 30 ///<Only for setting a maximum
116 };
117
118 ///Flags for setting preferences for adding scores
119 enum AddScoreFlag
120 {
121 AskName = 0x1, /**< Promt the player for their name */
122 LessIsMore = 0x2 /**< A lower numerical score means higher placing on the table */
123 };
124 Q_DECLARE_FLAGS(AddScoreFlags, AddScoreFlag)
125
126 typedef QMap<int, QString> FieldInfo;
127
128 /**
129 * @param fields Bitwise OR of the @ref Fields that should be listed (Score is always present)
130 * @param parent passed to parent QWidget constructor.
131 */
132 explicit KScoreDialog(int fields=Name, QWidget *parent=0);
133
134 ~KScoreDialog();
135
136 /**
137 * The group name must be passed though I18N_NOOP() in order for the
138 * group name to be translated. i.e.
139 * \code ksdialog.setConfigGroup(I18N_NOOP("Easy")); \endcode
140 * If you set a group, it will be prefixed in the config file by
141 * 'KHighscore_' otherwise the group will simply be 'KHighscore'.
142 *
143 * @param group to use for reading/writing highscores from/to.
144 * @deprecated since 4.1
145 */
146 void KDE_DEPRECATED setConfigGroup(const QString& group = QString());
147 //void setConfigGroup(const QString& group, const QString& i18nName);
148
149 /**
150 * The group name must be passed though ki18n() in order for the
151 * group name to be translated. i.e.
152 * \code ksdialog.setConfigGroup(ki18n("Easy")); \endcode
153 * If you set a group, it will be prefixed in the config file by
154 * 'KHighscore_' otherwise the group will simply be 'KHighscore'.
155 *
156 * @param group to use for reading/writing highscores from/to.
157 */
158 void setConfigGroup(const QPair<QByteArray, QString>& group);
159
160 /**
161 * You must add the translations of all group names to the dialog. This
162 * is best done by passing the name through ki18n().
163 * The group set through setConfigGroup(const KLocalizedString& group)
164 * will be added automatically
165 *
166 * @param group the translated group name
167 */
168 void addLocalizedConfigGroupName(const QPair<QByteArray, QString>& group);
169
170 /**
171 * You must add the translations of all group names to the dialog. This
172 * is best done by passing the name through ki18n().
173 * The group set through setConfigGroup(const KLocalizedString& group)
174 * will be added automatically.
175 *
176 * This function can be used directly with KGameDifficulty::localizedLevelStrings().
177 *
178 * @param group the list of translated group names
179 */
180 void addLocalizedConfigGroupNames(const QMap<QByteArray, QString>& groups);
181
182 /**
183 * Hide some config groups so that they are not shown on the dialog
184 * (but are still stored in the configuration file).
185 * \code
186 * ksdialog.setHiddenConfigGroups(QList<QByteArray>() << "Very Easy" << "Easy");
187 * \endcode
188 *
189 * @param hiddenGroups the list of group names you want to hide
190 *
191 * @since KDE 4.6
192 */
193 void setHiddenConfigGroups(const QList<QByteArray>& hiddenGroups);
194
195 /**
196 * It is a good idea giving config group weigths, otherwise tabs
197 * get ordered by their tab name that is not probably what you want.
198 *
199 * This function can be used directly with KGameDifficulty::levelWeights().
200 *
201 * @param group the list of untranslated group names and their weights
202 *
203 * @since KDE 4.2
204 */
205 void setConfigGroupWeights(const QMap<int, QByteArray>& weights);
206
207 /**
208 * @param comment to add when showing high-scores.
209 * The comment is only used once.
210 */
211 void setComment(const QString& comment);
212
213 /**
214 * Define an extra FieldInfo entry.
215 * @param field id of this field @ref Fields e.g. KScoreDialog::Custom1
216 * @param header text shown in the header in the dialog for this field. e.g. "Number of Moves"
217 * @param key unique key used to store this field. e.g. "moves"
218 */
219 void addField(int field, const QString& header, const QString& key);
220
221 /**
222 * Hide a field so that it is not shown on the table (but is still stored in the configuration file).
223 * @param field id of this field @ref Fields e.g. KScoreDialog::Score
224 */
225 void hideField(int field);
226
227 /**
228 * Adds a new score to the list.
229 *
230 * @param newInfo info about the score.
231 * @param flags set whether the user should be prompted for their name and how the scores should be sorted
232 *
233 * @returns The highscore position if the score was good enough to
234 * make it into the list (1 being topscore) or 0 otherwise.
235 */
236 int addScore(const FieldInfo& newInfo = FieldInfo(), const AddScoreFlags& flags=0);
237
238 /**
239 * Convenience function for ease of use.
240 *
241 * @param newScore the score of the player.
242 * @param flags set whether the user should be prompted for their name and how the scores should be sorted
243 *
244 * @returns The highscore position if the score was good enough to
245 * make it into the list (1 being topscore) or 0 otherwise.
246 */
247 int addScore(int newScore, const AddScoreFlags& flags=0);
248
249 /**
250 * @returns the current best score in the group
251 */
252 int highScore();
253
254 /**
255 * Assume that config groups (incl. current selection) are equal to
256 * difficulty levels, and initialize them. This is usually equal to the
257 * following code using KGameDifficulty:
258 * @code
259 * addLocalizedConfigGroupNames(KGameDifficulty::localizedLevelStrings());
260 * setConfigGroupWeights(KGameDifficulty::levelWeights());
261 * setConfigGroup(KGameDifficulty::localizedLevelString());
262 * @endcode
263 */
264 void initFromDifficulty(const KgDifficulty* difficulty, bool setConfigGroup = true);
265
266 ///Display the dialog as non-modal
267 virtual void show();
268 ///Display the dialog as modal
269 virtual void exec();
270
271 private Q_SLOTS:
272 void slotGotReturn();
273 void slotGotName();
274 void slotForgetScore();
275
276 private:
277 void keyPressEvent(QKeyEvent *ev);
278
279 private:
280 class KScoreDialogPrivate;
281 KScoreDialogPrivate* const d;
282};
283Q_DECLARE_OPERATORS_FOR_FLAGS(KScoreDialog::AddScoreFlags)
284
285#endif //KSCOREDIALOG_H
286