00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kexthighscore_gui.h"
00021 #include "kexthighscore_gui.moc"
00022
00023 #include <QLayout>
00024 #include <QTextStream>
00025 #include <QGridLayout>
00026 #include <QHBoxLayout>
00027 #include <QLabel>
00028 #include <QVBoxLayout>
00029 #include <QGroupBox>
00030 #include <QHeaderView>
00031 #include <QtGui/QTabWidget>
00032
00033 #include <kmessagebox.h>
00034 #include <kurllabel.h>
00035 #include <krun.h>
00036 #include <kfiledialog.h>
00037 #include <kvbox.h>
00038 #include <ktemporaryfile.h>
00039 #include <kio/netaccess.h>
00040 #include <kicon.h>
00041 #include <kiconloader.h>
00042 #include <klineedit.h>
00043 #include <kpushbutton.h>
00044
00045 #include "kexthighscore_internal.h"
00046 #include "kexthighscore.h"
00047 #include "kexthighscore_tab.h"
00048
00049
00050 namespace KExtHighscore
00051 {
00052
00053
00054 ShowItem::ShowItem(QTreeWidget *list, bool highlight)
00055 : QTreeWidgetItem(list), _highlight(highlight)
00056 {
00057
00058 if (_highlight) {
00059 for (int i=0; i < columnCount();i++) {
00060 setForeground(i, Qt::red);
00061 }
00062 }
00063 }
00064
00065
00066 ScoresList::ScoresList(QWidget *parent)
00067 : QTreeWidget(parent)
00068 {
00069
00070 setSelectionMode(QTreeWidget::NoSelection);
00071
00072 setAllColumnsShowFocus(true);
00073
00074 header()->setClickable(false);
00075 header()->setMovable(false);
00076 }
00077
00078 void ScoresList::addHeader(const ItemArray &items)
00079 {
00080
00081 addLineItem(items, 0, 0);
00082 }
00083
00084 QTreeWidgetItem *ScoresList::addLine(const ItemArray &items,
00085 uint index, bool highlight)
00086 {
00087
00088 QTreeWidgetItem *item = new ShowItem(this, highlight);
00089 addLineItem(items, index, item);
00090 return item;
00091 }
00092
00093 void ScoresList::addLineItem(const ItemArray &items,
00094 uint index, QTreeWidgetItem *line)
00095 {
00096
00097 uint k = 0;
00098 for (int i=0; i<items.size(); i++) {
00099 const ItemContainer& container = *items[i];
00100 if ( !container.item()->isVisible() ) {
00101 continue;
00102 }
00103 if (line) {
00104 line->setText(k, itemText(container, index));
00105 line->setTextAlignment(k, container.item()->alignment());
00106 }
00107 else {
00108 headerItem()->setText(k, container.item()->label() );
00109 headerItem()->setTextAlignment(k, container.item()->alignment());
00110 }
00111 k++;
00112 }
00113 update();
00114 }
00115
00116
00117 HighscoresList::HighscoresList(QWidget *parent)
00118 : ScoresList(parent)
00119 {
00120
00121 }
00122
00123 QString HighscoresList::itemText(const ItemContainer &item, uint row) const
00124 {
00125
00126 return item.pretty(row);
00127 }
00128
00129 void HighscoresList::load(const ItemArray &items, int highlight)
00130 {
00131
00132 clear();
00133 QTreeWidgetItem *line = 0;
00134 for (int j=items.nbEntries()-1; j>=0; j--) {
00135 QTreeWidgetItem *item = addLine(items, j, j==highlight);
00136 if ( j==highlight ) line = item;
00137 }
00138 scrollTo(indexFromItem(line));
00139 }
00140
00141
00142 HighscoresWidget::HighscoresWidget(QWidget *parent)
00143 : QWidget(parent),
00144 _scoresUrl(0), _playersUrl(0), _statsTab(0), _histoTab(0)
00145 {
00146
00147
00148 setObjectName("show_highscores_widget");
00149 const ScoreInfos &s = internal->scoreInfos();
00150 const PlayerInfos &p = internal->playerInfos();
00151
00152 QVBoxLayout *vbox = new QVBoxLayout(this);
00153 vbox->setSpacing(KDialog::spacingHint());
00154
00155 _tw = new QTabWidget(this);
00156 connect(_tw, SIGNAL(currentChanged(int)), SLOT(tabChanged()));
00157 vbox->addWidget(_tw);
00158
00159
00160 _scoresList = new HighscoresList(0);
00161 _scoresList->addHeader(s);
00162 _tw->addTab(_scoresList, i18n("Best &Scores"));
00163
00164
00165 _playersList = new HighscoresList(0);
00166 _playersList->addHeader(p);
00167 _tw->addTab(_playersList, i18n("&Players"));
00168
00169
00170 if ( internal->showStatistics ) {
00171 _statsTab = new StatisticsTab(0);
00172 _tw->addTab(_statsTab, i18n("Statistics"));
00173 }
00174
00175
00176 if ( p.histogram().size()!=0 ) {
00177 _histoTab = new HistogramTab(0);
00178 _tw->addTab(_histoTab, i18n("Histogram"));
00179 }
00180
00181
00182 if ( internal->isWWHSAvailable() ) {
00183 KUrl url = internal->queryUrl(ManagerPrivate::Scores);
00184 _scoresUrl = new KUrlLabel(url.url(),
00185 i18n("View world-wide highscores"), this);
00186 connect(_scoresUrl, SIGNAL(leftClickedUrl(const QString &)),
00187 SLOT(showURL(const QString &)));
00188 vbox->addWidget(_scoresUrl);
00189
00190 url = internal->queryUrl(ManagerPrivate::Players);
00191 _playersUrl = new KUrlLabel(url.url(),
00192 i18n("View world-wide players"), this);
00193 connect(_playersUrl, SIGNAL(leftClickedUrl(const QString &)),
00194 SLOT(showURL(const QString &)));
00195 vbox->addWidget(_playersUrl);
00196 }
00197 load(-1);
00198 }
00199
00200 void HighscoresWidget::changeTab(int i)
00201 {
00202
00203 if ( i!=_tw->currentIndex() )
00204 _tw->setCurrentIndex(i);
00205 }
00206
00207 void HighscoresWidget::showURL(const QString &url)
00208 {
00209
00210 (void)new KRun(KUrl(url), this);
00211 }
00212
00213 void HighscoresWidget::load(int rank)
00214 {
00215
00216 _scoresList->load(internal->scoreInfos(), rank);
00217 _playersList->load(internal->playerInfos(), internal->playerInfos().id());
00218 if (_scoresUrl)
00219 _scoresUrl->setUrl(internal->queryUrl(ManagerPrivate::Scores).url());
00220 if (_playersUrl)
00221 _playersUrl->setUrl(internal->queryUrl(ManagerPrivate::Players).url());
00222 if (_statsTab) _statsTab->load();
00223 if (_histoTab) _histoTab->load();
00224 }
00225
00226
00227 HighscoresDialog::HighscoresDialog(int rank, QWidget *parent)
00228 : KPageDialog(parent), _rank(rank), _tab(0)
00229 {
00230
00231
00232 setCaption( i18n("Highscores") );
00233 setButtons( Close|User1|User2 );
00234 setDefaultButton( Close );
00235 if ( internal->nbGameTypes()>1 )
00236 setFaceType( KPageDialog::Tree );
00237 else
00238 setFaceType( KPageDialog::Plain );
00239 setButtonGuiItem( User1, KGuiItem(i18n("Configure..."), "configure") );
00240 setButtonGuiItem( User2, KGuiItem(i18n("Export...")) );
00241 connect( this, SIGNAL(user1Clicked()), SLOT(slotUser1()) );
00242 connect( this, SIGNAL(user2Clicked()), SLOT(slotUser2()) );
00243
00244 for (uint i=0; i<internal->nbGameTypes(); i++) {
00245 QString title = internal->manager.gameTypeLabel(i, Manager::I18N);
00246 QString icon = internal->manager.gameTypeLabel(i, Manager::Icon);
00247 HighscoresWidget *hsw = new HighscoresWidget(0);
00248 KPageWidgetItem *pageItem = new KPageWidgetItem( hsw, title);
00249 pageItem->setIcon( KIcon( BarIcon(icon, KIconLoader::SizeLarge) ) );
00250 addPage( pageItem );
00251 _pages.append(pageItem);
00252 connect(hsw, SIGNAL(tabChanged(int)), SLOT(tabChanged(int)));
00253 }
00254
00255 connect(this, SIGNAL( currentPageChanged(KPageWidgetItem *, KPageWidgetItem *)),
00256 SLOT(highscorePageChanged(KPageWidgetItem *, KPageWidgetItem *)));
00257 setCurrentPage(_pages[internal->gameType()]);
00258 }
00259
00260 void HighscoresDialog::highscorePageChanged(KPageWidgetItem* page, KPageWidgetItem* pageold)
00261 {
00262 Q_UNUSED(pageold);
00263
00264 int idx = _pages.indexOf( page );
00265 Q_ASSERT(idx != -1);
00266
00267 internal->hsConfig().readCurrentConfig();
00268 uint type = internal->gameType();
00269 bool several = ( internal->nbGameTypes()>1 );
00270 if (several)
00271 internal->setGameType(idx);
00272 HighscoresWidget *hsw = static_cast<HighscoresWidget*>(page->widget());
00273 hsw->load(uint(idx)==type ? _rank : -1);
00274 if (several) setGameType(type);
00275 hsw->changeTab(_tab);
00276 }
00277
00278 void HighscoresDialog::slotUser1()
00279 {
00280
00281 if ( KExtHighscore::configure(this) )
00282 highscorePageChanged(currentPage(), 0);
00283 }
00284
00285 void HighscoresDialog::slotUser2()
00286 {
00287
00288 KUrl url = KFileDialog::getSaveUrl(KUrl(), QString(), this);
00289 if ( url.isEmpty() ) return;
00290 if ( KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, this) ) {
00291 KGuiItem gi = KStandardGuiItem::save();
00292 gi.setText(i18n("Overwrite"));
00293 int res = KMessageBox::warningContinueCancel(this,
00294 i18n("The file already exists. Overwrite?"),
00295 i18n("Export"), gi);
00296 if ( res==KMessageBox::Cancel ) return;
00297 }
00298 KTemporaryFile tmp;
00299 tmp.open();
00300 QTextStream stream(&tmp);
00301 internal->exportHighscores(stream);
00302 stream.flush();
00303 KIO::NetAccess::upload(tmp.fileName(), url, this);
00304 }
00305
00306
00307 LastMultipleScoresList::LastMultipleScoresList(
00308 const QVector<Score> &scores, QWidget *parent)
00309 : ScoresList(parent), _scores(scores)
00310 {
00311
00312
00313 const ScoreInfos &s = internal->scoreInfos();
00314 addHeader(s);
00315 for (int i=0; i<scores.size(); i++) addLine(s, i, false);
00316 }
00317
00318 void LastMultipleScoresList::addLineItem(const ItemArray &si,
00319 uint index, QTreeWidgetItem *line)
00320 {
00321
00322 uint k = 1;
00323 for (int i=0; i<si.size()-2; i++) {
00324 if ( i==3 ) k = 5;
00325 const ItemContainer& container = *si[k];
00326 k++;
00327 if (line) {
00328 line->setText(i, itemText(container, index));
00329 line->setTextAlignment(i, container.item()->alignment());
00330 }
00331 else {
00332 headerItem()->setText(i, container.item()->label() );
00333 headerItem()->setTextAlignment(i, container.item()->alignment());
00334 }
00335 }
00336 }
00337
00338 QString LastMultipleScoresList::itemText(const ItemContainer &item,
00339 uint row) const
00340 {
00341
00342 QString name = item.name();
00343 if ( name=="rank" )
00344 return (_scores[row].type()==Won ? i18n("Winner") : QString());
00345 QVariant v = _scores[row].data(name);
00346 if ( name=="name" ) return v.toString();
00347 return item.item()->pretty(row, v);
00348 }
00349
00350
00351 TotalMultipleScoresList::TotalMultipleScoresList(
00352 const QVector<Score> &scores, QWidget *parent)
00353 : ScoresList(parent), _scores(scores)
00354 {
00355
00356 const ScoreInfos &s = internal->scoreInfos();
00357 addHeader(s);
00358 for (int i=0; i<scores.size(); i++) addLine(s, i, false);
00359 }
00360
00361 void TotalMultipleScoresList::addLineItem(const ItemArray &si,
00362 uint index, QTreeWidgetItem *line)
00363 {
00364
00365 const PlayerInfos &pi = internal->playerInfos();
00366 uint k = 1;
00367 for (uint i=0; i<4; i++) {
00368 const ItemContainer *container;
00369 if ( i==2 ) container = pi.item("nb games");
00370 else if ( i==3 ) container = pi.item("mean score");
00371 else {
00372 container = si[k];
00373 k++;
00374 }
00375
00376 if (line) {
00377 line->setText(i, itemText(*container, index));
00378 line->setTextAlignment(i, container->item()->alignment());
00379 }
00380 else {
00381 QString label =
00382 (i==2 ? i18n("Won Games") : container->item()->label());
00383 headerItem()->setText(i, label );
00384 headerItem()->setTextAlignment(i, container->item()->alignment());
00385 }
00386 }
00387 }
00388
00389 QString TotalMultipleScoresList::itemText(const ItemContainer &item,
00390 uint row) const
00391 {
00392
00393 QString name = item.name();
00394 if ( name=="rank" ) return QString::number(_scores.size()-row);
00395 if ( name=="nb games" )
00396 return QString::number( _scores[row].data("nb won games").toUInt() );
00397 QVariant v = _scores[row].data(name);
00398 if ( name=="name" ) return v.toString();
00399 return item.item()->pretty(row, v);
00400 }
00401
00402
00403
00404 ConfigDialog::ConfigDialog(QWidget *parent)
00405 : KDialog(parent),
00406 _saved(false), _WWHEnabled(0)
00407 {
00408
00409 setCaption( i18n("Configure Highscores") );
00410 setButtons( Ok|Apply|Cancel );
00411 setDefaultButton( Cancel );
00412 setModal( true );
00413 QWidget *page = 0;
00414 QTabWidget *tab = 0;
00415 if ( internal->isWWHSAvailable() ) {
00416 tab = new QTabWidget(this);
00417 setMainWidget(tab);
00418 page = new QWidget;
00419 tab->addTab(page, i18n("Main"));
00420 } else {
00421 page = new QWidget(this);
00422 setMainWidget(page);
00423 }
00424
00425 QGridLayout *pageTop =
00426 new QGridLayout(page);
00427 pageTop->setMargin(spacingHint());
00428 pageTop->setSpacing(spacingHint());
00429
00430 QLabel *label = new QLabel(i18n("Nickname:"), page);
00431 pageTop->addWidget(label, 0, 0);
00432 _nickname = new QLineEdit(page);
00433 connect(_nickname, SIGNAL(textChanged(const QString &)),
00434 SLOT(modifiedSlot()));
00435 connect(_nickname, SIGNAL(textChanged(const QString &)),
00436 SLOT(nickNameChanged(const QString &)));
00437
00438 _nickname->setMaxLength(16);
00439 pageTop->addWidget(_nickname, 0, 1);
00440
00441 label = new QLabel(i18n("Comment:"), page);
00442 pageTop->addWidget(label, 1, 0);
00443 _comment = new QLineEdit(page);
00444 connect(_comment, SIGNAL(textChanged(const QString &)),
00445 SLOT(modifiedSlot()));
00446 _comment->setMaxLength(50);
00447 pageTop->addWidget(_comment, 1, 1);
00448
00449 if (tab) {
00450 _WWHEnabled
00451 = new QCheckBox(i18n("World-wide highscores enabled"), page);
00452 connect(_WWHEnabled, SIGNAL(toggled(bool)),
00453 SLOT(modifiedSlot()));
00454 pageTop->addWidget(_WWHEnabled, 2, 0, 1, 2 );
00455
00456
00457 QWidget *page = new QWidget;
00458 tab->addTab(page, i18n("Advanced"));
00459 QVBoxLayout *pageTop = new QVBoxLayout(page);
00460 pageTop->setMargin(marginHint());
00461 pageTop->setSpacing(spacingHint());
00462
00463 QGroupBox *group = new QGroupBox(page);
00464 group->setTitle( i18n("Registration Data") );
00465 pageTop->addWidget(group);
00466 QGridLayout *groupLayout = new QGridLayout(group);
00467 groupLayout->setSpacing(spacingHint());
00468
00469 label = new QLabel(i18n("Nickname:"), group);
00470 groupLayout->addWidget(label, 0, 0);
00471 _registeredName = new KLineEdit(group);
00472 _registeredName->setReadOnly(true);
00473 groupLayout->addWidget(_registeredName, 0, 1);
00474
00475 label = new QLabel(i18n("Key:"), group);
00476 groupLayout->addWidget(label, 1, 0);
00477 _key = new KLineEdit(group);
00478 _key->setReadOnly(true);
00479 groupLayout->addWidget(_key, 1, 1);
00480
00481 KGuiItem gi = KStandardGuiItem::clear();
00482 gi.setText(i18n("Remove"));
00483 _removeButton = new KPushButton(gi, group);
00484 groupLayout->addWidget(_removeButton, 2, 0);
00485 connect(_removeButton, SIGNAL(clicked()), SLOT(removeSlot()));
00486 }
00487
00488 load();
00489 enableButtonOk( !_nickname->text().isEmpty() );
00490 enableButtonApply(false);
00491 }
00492
00493 void ConfigDialog::nickNameChanged(const QString &text)
00494 {
00495 enableButtonOk( !text.isEmpty() );
00496 }
00497
00498
00499 void ConfigDialog::modifiedSlot()
00500 {
00501 enableButtonApply(true && !_nickname->text().isEmpty() );
00502 }
00503
00504 void ConfigDialog::accept()
00505 {
00506 if ( save() ) {
00507 KDialog::accept();
00508 KGlobal::config()->sync();
00509 }
00510 }
00511
00512 void ConfigDialog::removeSlot()
00513 {
00514 KGuiItem gi = KStandardGuiItem::clear();
00515 gi.setText(i18n("Remove"));
00516 int res = KMessageBox::warningContinueCancel(this,
00517 i18n("This will permanently remove your "
00518 "registration key. You will not be able to use "
00519 "the currently registered nickname anymore."),
00520 QString(), gi);
00521 if ( res==KMessageBox::Continue ) {
00522 internal->playerInfos().removeKey();
00523 _registeredName->clear();
00524 _key->clear();
00525 _removeButton->setEnabled(false);
00526 _WWHEnabled->setChecked(false);
00527 modifiedSlot();
00528 }
00529 }
00530
00531 void ConfigDialog::load()
00532 {
00533 internal->hsConfig().readCurrentConfig();
00534 const PlayerInfos &infos = internal->playerInfos();
00535 _nickname->setText(infos.isAnonymous() ? QString() : infos.name());
00536 _comment->setText(infos.comment());
00537 if (_WWHEnabled) {
00538 _WWHEnabled->setChecked(infos.isWWEnabled());
00539 if ( !infos.key().isEmpty() ) {
00540 _registeredName->setText(infos.registeredName());
00541 _registeredName->home(false);
00542 _key->setText(infos.key());
00543 _key->home(false);
00544 }
00545 _removeButton->setEnabled(!infos.key().isEmpty());
00546 }
00547 }
00548
00549 bool ConfigDialog::save()
00550 {
00551 bool enabled = (_WWHEnabled ? _WWHEnabled->isChecked() : false);
00552
00553
00554
00555 QString newName = _nickname->text();
00556 if ( newName.isEmpty() && !internal->playerInfos().isAnonymous()
00557 && !enabled ) return true;
00558
00559 if ( newName.isEmpty() ) {
00560 KMessageBox::sorry(this, i18n("Please choose a non empty nickname."));
00561 return false;
00562 }
00563 if ( internal->playerInfos().isNameUsed(newName) ) {
00564 KMessageBox::sorry(this, i18n("Nickname already in use. Please "
00565 "choose another one"));
00566 return false;
00567 }
00568
00569 int res =
00570 internal->modifySettings(newName, _comment->text(), enabled, this);
00571 if (res) {
00572 load();
00573 enableButtonApply(false);
00574 }
00575 _saved = true;
00576 return res;
00577 }
00578
00579
00580 AskNameDialog::AskNameDialog(QWidget *parent)
00581 : KDialog(parent)
00582 {
00583
00584
00585 setCaption( i18n("Enter Your Nickname") );
00586 setButtons( Ok | Cancel );
00587 setDefaultButton( Ok );
00588
00589 internal->hsConfig().readCurrentConfig();
00590 QWidget *main = new QWidget( this );
00591 setMainWidget( main );
00592 QVBoxLayout *top = new QVBoxLayout( main );
00593 top->setMargin( marginHint() );
00594 top->setSpacing( spacingHint() );
00595
00596 QLabel *label =
00597 new QLabel(i18n("Congratulations, you have won!"), main);
00598 top->addWidget(label);
00599
00600 QHBoxLayout *hbox = new QHBoxLayout;
00601 top->addLayout(hbox);
00602 label = new QLabel(i18n("Enter your nickname:"), main);
00603 hbox->addWidget(label);
00604 _edit = new QLineEdit(main);
00605 _edit->setFocus();
00606 connect(_edit, SIGNAL(textChanged(const QString &)), SLOT(nameChanged()));
00607 hbox->addWidget(_edit);
00608
00609 top->addSpacing(spacingHint());
00610 _checkbox = new QCheckBox(i18n("Do not ask again."), main);
00611 top->addWidget(_checkbox);
00612
00613 nameChanged();
00614 }
00615
00616 void AskNameDialog::nameChanged()
00617 {
00618 enableButtonOk( !name().isEmpty()
00619 && !internal->playerInfos().isNameUsed(name()) );
00620 }
00621
00622 }