kexthighscore_gui.cpp
00001 /* 00002 This file is part of the TDE games library 00003 Copyright (C) 2001-2003 Nicolas Hadacek (hadacek@kde.org) 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License version 2 as published by the Free Software Foundation. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kexthighscore_gui.h" 00021 #include "kexthighscore_gui.moc" 00022 00023 #include <tqlayout.h> 00024 #include <tqtextstream.h> 00025 #include <tqheader.h> 00026 #include <tqgrid.h> 00027 #include <tqvgroupbox.h> 00028 00029 #include <tdeapplication.h> 00030 #include <tdemessagebox.h> 00031 #include <kurllabel.h> 00032 #include <kopenwith.h> 00033 #include <krun.h> 00034 #include <tdefiledialog.h> 00035 #include <tdetempfile.h> 00036 #include <tdeio/netaccess.h> 00037 #include <kiconloader.h> 00038 00039 #include "kexthighscore_internal.h" 00040 #include "kexthighscore.h" 00041 #include "kexthighscore_tab.h" 00042 00043 00044 namespace KExtHighscore 00045 { 00046 00047 //----------------------------------------------------------------------------- 00048 ShowItem::ShowItem(TQListView *list, bool highlight) 00049 : TDEListViewItem(list), _highlight(highlight) 00050 {} 00051 00052 void ShowItem::paintCell(TQPainter *p, const TQColorGroup &cg, 00053 int column, int width, int align) 00054 { 00055 TQColorGroup cgrp(cg); 00056 if (_highlight) cgrp.setColor(TQColorGroup::Text, red); 00057 TDEListViewItem::paintCell(p, cgrp, column, width, align); 00058 } 00059 00060 //----------------------------------------------------------------------------- 00061 ScoresList::ScoresList(TQWidget *parent) 00062 : TDEListView(parent) 00063 { 00064 setSelectionMode(TQListView::NoSelection); 00065 setItemMargin(3); 00066 setAllColumnsShowFocus(true); 00067 setSorting(-1); 00068 header()->setClickEnabled(false); 00069 header()->setMovingEnabled(false); 00070 } 00071 00072 void ScoresList::addHeader(const ItemArray &items) 00073 { 00074 addLineItem(items, 0, 0); 00075 } 00076 00077 TQListViewItem *ScoresList::addLine(const ItemArray &items, 00078 uint index, bool highlight) 00079 { 00080 TQListViewItem *item = new ShowItem(this, highlight); 00081 addLineItem(items, index, item); 00082 return item; 00083 } 00084 00085 void ScoresList::addLineItem(const ItemArray &items, 00086 uint index, TQListViewItem *line) 00087 { 00088 uint k = 0; 00089 for (uint i=0; i<items.size(); i++) { 00090 const ItemContainer &container = *items[i]; 00091 if ( !container.item()->isVisible() ) continue; 00092 if (line) line->setText(k, itemText(container, index)); 00093 else { 00094 addColumn( container.item()->label() ); 00095 setColumnAlignment(k, container.item()->alignment()); 00096 } 00097 k++; 00098 } 00099 } 00100 00101 //----------------------------------------------------------------------------- 00102 HighscoresList::HighscoresList(TQWidget *parent) 00103 : ScoresList(parent) 00104 {} 00105 00106 TQString HighscoresList::itemText(const ItemContainer &item, uint row) const 00107 { 00108 return item.pretty(row); 00109 } 00110 00111 void HighscoresList::load(const ItemArray &items, int highlight) 00112 { 00113 clear(); 00114 TQListViewItem *line = 0; 00115 for (int j=items.nbEntries()-1; j>=0; j--) { 00116 TQListViewItem *item = addLine(items, j, j==highlight); 00117 if ( j==highlight ) line = item; 00118 } 00119 if (line) ensureItemVisible(line); 00120 } 00121 00122 //----------------------------------------------------------------------------- 00123 HighscoresWidget::HighscoresWidget(TQWidget *parent) 00124 : TQWidget(parent, "show_highscores_widget"), 00125 _scoresUrl(0), _playersUrl(0), _statsTab(0), _histoTab(0) 00126 { 00127 const ScoreInfos &s = internal->scoreInfos(); 00128 const PlayerInfos &p = internal->playerInfos(); 00129 00130 TQVBoxLayout *vbox = new TQVBoxLayout(this, KDialogBase::spacingHint()); 00131 00132 _tw = new TQTabWidget(this); 00133 connect(_tw, TQT_SIGNAL(currentChanged(TQWidget *)), TQT_SLOT(tabChanged())); 00134 vbox->addWidget(_tw); 00135 00136 // scores tab 00137 _scoresList = new HighscoresList(_tw); 00138 _scoresList->addHeader(s); 00139 _tw->addTab(_scoresList, i18n("Best &Scores")); 00140 00141 // players tab 00142 _playersList = new HighscoresList(_tw); 00143 _playersList->addHeader(p); 00144 _tw->addTab(_playersList, i18n("&Players")); 00145 00146 // statistics tab 00147 if ( internal->showStatistics ) { 00148 _statsTab = new StatisticsTab(_tw); 00149 _tw->addTab(_statsTab, i18n("Statistics")); 00150 } 00151 00152 // histogram tab 00153 if ( p.histogram().size()!=0 ) { 00154 _histoTab = new HistogramTab(_tw); 00155 _tw->addTab(_histoTab, i18n("Histogram")); 00156 } 00157 00158 // url labels 00159 if ( internal->isWWHSAvailable() ) { 00160 KURL url = internal->queryURL(ManagerPrivate::Scores); 00161 _scoresUrl = new KURLLabel(url.url(), 00162 i18n("View world-wide highscores"), this); 00163 connect(_scoresUrl, TQT_SIGNAL(leftClickedURL(const TQString &)), 00164 TQT_SLOT(showURL(const TQString &))); 00165 vbox->addWidget(_scoresUrl); 00166 00167 url = internal->queryURL(ManagerPrivate::Players); 00168 _playersUrl = new KURLLabel(url.url(), 00169 i18n("View world-wide players"), this); 00170 connect(_playersUrl, TQT_SIGNAL(leftClickedURL(const TQString &)), 00171 TQT_SLOT(showURL(const TQString &))); 00172 vbox->addWidget(_playersUrl); 00173 } 00174 } 00175 00176 void HighscoresWidget::changeTab(int i) 00177 { 00178 if ( i!=_tw->currentPageIndex() ) 00179 _tw->setCurrentPage(i); 00180 } 00181 00182 void HighscoresWidget::showURL(const TQString &url) const 00183 { 00184 (void)new KRun(KURL(url)); 00185 } 00186 00187 void HighscoresWidget::load(int rank) 00188 { 00189 _scoresList->load(internal->scoreInfos(), rank); 00190 _playersList->load(internal->playerInfos(), internal->playerInfos().id()); 00191 if (_scoresUrl) 00192 _scoresUrl->setURL(internal->queryURL(ManagerPrivate::Scores).url()); 00193 if (_playersUrl) 00194 _playersUrl->setURL(internal->queryURL(ManagerPrivate::Players).url()); 00195 if (_statsTab) _statsTab->load(); 00196 if (_histoTab) _histoTab->load(); 00197 } 00198 00199 //----------------------------------------------------------------------------- 00200 HighscoresDialog::HighscoresDialog(int rank, TQWidget *parent) 00201 : KDialogBase(internal->nbGameTypes()>1 ? TreeList : Plain, 00202 i18n("Highscores"), Close|User1|User2, Close, 00203 parent, "show_highscores", true, true, 00204 KGuiItem(i18n("Configure..."), "configure"), 00205 KGuiItem(i18n("Export..."))), _rank(rank), _tab(0) 00206 { 00207 _widgets.resize(internal->nbGameTypes(), 0); 00208 00209 if ( internal->nbGameTypes()>1 ) { 00210 for (uint i=0; i<internal->nbGameTypes(); i++) { 00211 TQString title = internal->manager.gameTypeLabel(i, Manager::I18N); 00212 TQString icon = internal->manager.gameTypeLabel(i, Manager::Icon); 00213 TQWidget *w = addVBoxPage(title, TQString(), 00214 BarIcon(icon, TDEIcon::SizeLarge)); 00215 if ( i==internal->gameType() ) createPage(w); 00216 } 00217 00218 connect(this, TQT_SIGNAL(aboutToShowPage(TQWidget *)), 00219 TQT_SLOT(createPage(TQWidget *))); 00220 showPage(internal->gameType()); 00221 } else { 00222 TQVBoxLayout *vbox = new TQVBoxLayout(plainPage()); 00223 createPage(plainPage()); 00224 vbox->addWidget(_widgets[0]); 00225 setMainWidget(_widgets[0]); 00226 } 00227 } 00228 00229 void HighscoresDialog::createPage(TQWidget *page) 00230 { 00231 internal->hsConfig().readCurrentConfig(); 00232 _current = page; 00233 bool several = ( internal->nbGameTypes()>1 ); 00234 int i = (several ? pageIndex(page) : 0); 00235 if ( _widgets[i]==0 ) { 00236 _widgets[i] = new HighscoresWidget(page); 00237 connect(_widgets[i], TQT_SIGNAL(tabChanged(int)), TQT_SLOT(tabChanged(int))); 00238 } 00239 uint type = internal->gameType(); 00240 if (several) internal->setGameType(i); 00241 _widgets[i]->load(uint(i)==type ? _rank : -1); 00242 if (several) setGameType(type); 00243 _widgets[i]->changeTab(_tab); 00244 } 00245 00246 void HighscoresDialog::slotUser1() 00247 { 00248 if ( KExtHighscore::configure(this) ) 00249 createPage(_current); 00250 } 00251 00252 void HighscoresDialog::slotUser2() 00253 { 00254 KURL url = KFileDialog::getSaveURL(TQString(), TQString(), this); 00255 if ( url.isEmpty() ) return; 00256 if ( TDEIO::NetAccess::exists(url, true, this) ) { 00257 KGuiItem gi = KStdGuiItem::save(); 00258 gi.setText(i18n("Overwrite")); 00259 int res = KMessageBox::warningContinueCancel(this, 00260 i18n("The file already exists. Overwrite?"), 00261 i18n("Export"), gi); 00262 if ( res==KMessageBox::Cancel ) return; 00263 } 00264 KTempFile tmp; 00265 internal->exportHighscores(*tmp.textStream()); 00266 tmp.close(); 00267 TDEIO::NetAccess::upload(tmp.name(), url, this); 00268 tmp.unlink(); 00269 } 00270 00271 //----------------------------------------------------------------------------- 00272 LastMultipleScoresList::LastMultipleScoresList( 00273 const TQValueVector<Score> &scores, TQWidget *parent) 00274 : ScoresList(parent), _scores(scores) 00275 { 00276 const ScoreInfos &s = internal->scoreInfos(); 00277 addHeader(s); 00278 for (uint i=0; i<scores.size(); i++) addLine(s, i, false); 00279 } 00280 00281 void LastMultipleScoresList::addLineItem(const ItemArray &si, 00282 uint index, TQListViewItem *line) 00283 { 00284 uint k = 1; // skip "id" 00285 for (uint i=0; i<si.size()-2; i++) { 00286 if ( i==3 ) k = 5; // skip "date" 00287 const ItemContainer *container = si[k]; 00288 k++; 00289 if (line) line->setText(i, itemText(*container, index)); 00290 else { 00291 addColumn( container->item()->label() ); 00292 setColumnAlignment(i, container->item()->alignment()); 00293 } 00294 } 00295 } 00296 00297 TQString LastMultipleScoresList::itemText(const ItemContainer &item, 00298 uint row) const 00299 { 00300 TQString name = item.name(); 00301 if ( name=="rank" ) 00302 return (_scores[row].type()==Won ? i18n("Winner") : TQString()); 00303 TQVariant v = _scores[row].data(name); 00304 if ( name=="name" ) return v.toString(); 00305 return item.item()->pretty(row, v); 00306 } 00307 00308 //----------------------------------------------------------------------------- 00309 TotalMultipleScoresList::TotalMultipleScoresList( 00310 const TQValueVector<Score> &scores, TQWidget *parent) 00311 : ScoresList(parent), _scores(scores) 00312 { 00313 const ScoreInfos &s = internal->scoreInfos(); 00314 addHeader(s); 00315 for (uint i=0; i<scores.size(); i++) addLine(s, i, false); 00316 } 00317 00318 void TotalMultipleScoresList::addLineItem(const ItemArray &si, 00319 uint index, TQListViewItem *line) 00320 { 00321 const PlayerInfos &pi = internal->playerInfos(); 00322 uint k = 1; // skip "id" 00323 for (uint i=0; i<4; i++) { // skip additional fields 00324 const ItemContainer *container; 00325 if ( i==2 ) container = pi.item("nb games"); 00326 else if ( i==3 ) container = pi.item("mean score"); 00327 else { 00328 container = si[k]; 00329 k++; 00330 } 00331 if (line) line->setText(i, itemText(*container, index)); 00332 else { 00333 TQString label = 00334 (i==2 ? i18n("Won Games") : container->item()->label()); 00335 addColumn(label); 00336 setColumnAlignment(i, container->item()->alignment()); 00337 } 00338 } 00339 } 00340 00341 TQString TotalMultipleScoresList::itemText(const ItemContainer &item, 00342 uint row) const 00343 { 00344 TQString name = item.name(); 00345 if ( name=="rank" ) return TQString::number(_scores.size()-row); 00346 if ( name=="nb games" ) 00347 return TQString::number( _scores[row].data("nb won games").toUInt() ); 00348 TQVariant v = _scores[row].data(name); 00349 if ( name=="name" ) return v.toString(); 00350 return item.item()->pretty(row, v); 00351 } 00352 00353 00354 //----------------------------------------------------------------------------- 00355 ConfigDialog::ConfigDialog(TQWidget *parent) 00356 : KDialogBase(Swallow, i18n("Configure Highscores"), 00357 Ok|Apply|Cancel, Cancel, 00358 parent, "configure_highscores", true, true), 00359 _saved(false), _WWHEnabled(0) 00360 { 00361 TQWidget *page = 0; 00362 TQTabWidget *tab = 0; 00363 if ( internal->isWWHSAvailable() ) { 00364 tab = new TQTabWidget(this); 00365 setMainWidget(tab); 00366 page = new TQWidget(tab); 00367 tab->addTab(page, i18n("Main")); 00368 } else { 00369 page = new TQWidget(this); 00370 setMainWidget(page); 00371 } 00372 00373 TQGridLayout *pageTop = 00374 new TQGridLayout(page, 2, 2, spacingHint(), spacingHint()); 00375 00376 TQLabel *label = new TQLabel(i18n("Nickname:"), page); 00377 pageTop->addWidget(label, 0, 0); 00378 _nickname = new TQLineEdit(page); 00379 connect(_nickname, TQT_SIGNAL(textChanged(const TQString &)), 00380 TQT_SLOT(modifiedSlot())); 00381 connect(_nickname, TQT_SIGNAL(textChanged(const TQString &)), 00382 TQT_SLOT(nickNameChanged(const TQString &))); 00383 00384 _nickname->setMaxLength(16); 00385 pageTop->addWidget(_nickname, 0, 1); 00386 00387 label = new TQLabel(i18n("Comment:"), page); 00388 pageTop->addWidget(label, 1, 0); 00389 _comment = new TQLineEdit(page); 00390 connect(_comment, TQT_SIGNAL(textChanged(const TQString &)), 00391 TQT_SLOT(modifiedSlot())); 00392 _comment->setMaxLength(50); 00393 pageTop->addWidget(_comment, 1, 1); 00394 00395 if (tab) { 00396 _WWHEnabled 00397 = new TQCheckBox(i18n("World-wide highscores enabled"), page); 00398 connect(_WWHEnabled, TQT_SIGNAL(toggled(bool)), 00399 TQT_SLOT(modifiedSlot())); 00400 pageTop->addMultiCellWidget(_WWHEnabled, 2, 2, 0, 1); 00401 00402 // advanced tab 00403 TQWidget *page = new TQWidget(tab); 00404 tab->addTab(page, i18n("Advanced")); 00405 TQVBoxLayout *pageTop = 00406 new TQVBoxLayout(page, spacingHint(), spacingHint()); 00407 00408 TQVGroupBox *group = new TQVGroupBox(i18n("Registration Data"), page); 00409 pageTop->addWidget(group); 00410 TQGrid *grid = new TQGrid(2, group); 00411 grid->setSpacing(spacingHint()); 00412 00413 label = new TQLabel(i18n("Nickname:"), grid); 00414 _registeredName = new KLineEdit(grid); 00415 _registeredName->setReadOnly(true); 00416 00417 label = new TQLabel(i18n("Key:"), grid); 00418 _key = new KLineEdit(grid); 00419 _key->setReadOnly(true); 00420 00421 KGuiItem gi = KStdGuiItem::clear(); 00422 gi.setText(i18n("Remove")); 00423 _removeButton = new KPushButton(gi, grid); 00424 connect(_removeButton, TQT_SIGNAL(clicked()), TQT_SLOT(removeSlot())); 00425 } 00426 00427 load(); 00428 enableButtonOK( !_nickname->text().isEmpty() ); 00429 enableButtonApply(false); 00430 } 00431 00432 void ConfigDialog::nickNameChanged(const TQString &text) 00433 { 00434 enableButtonOK( !text.isEmpty() ); 00435 } 00436 00437 00438 void ConfigDialog::modifiedSlot() 00439 { 00440 enableButtonApply(true && !_nickname->text().isEmpty() ); 00441 } 00442 00443 void ConfigDialog::accept() 00444 { 00445 if ( save() ) { 00446 KDialogBase::accept(); 00447 kapp->config()->sync(); // safer 00448 } 00449 } 00450 00451 void ConfigDialog::removeSlot() 00452 { 00453 KGuiItem gi = KStdGuiItem::clear(); 00454 gi.setText(i18n("Remove")); 00455 int res = KMessageBox::warningContinueCancel(this, 00456 i18n("This will permanently remove your " 00457 "registration key. You will not be able to use " 00458 "the currently registered nickname anymore."), 00459 TQString(), gi); 00460 if ( res==KMessageBox::Continue ) { 00461 internal->playerInfos().removeKey(); 00462 _registeredName->clear(); 00463 _key->clear(); 00464 _removeButton->setEnabled(false); 00465 _WWHEnabled->setChecked(false); 00466 modifiedSlot(); 00467 } 00468 } 00469 00470 void ConfigDialog::load() 00471 { 00472 internal->hsConfig().readCurrentConfig(); 00473 const PlayerInfos &infos = internal->playerInfos(); 00474 _nickname->setText(infos.isAnonymous() ? TQString() : infos.name()); 00475 _comment->setText(infos.comment()); 00476 if (_WWHEnabled) { 00477 _WWHEnabled->setChecked(infos.isWWEnabled()); 00478 if ( !infos.key().isEmpty() ) { 00479 _registeredName->setText(infos.registeredName()); 00480 _registeredName->home(false); 00481 _key->setText(infos.key()); 00482 _key->home(false); 00483 } 00484 _removeButton->setEnabled(!infos.key().isEmpty()); 00485 } 00486 } 00487 00488 bool ConfigDialog::save() 00489 { 00490 bool enabled = (_WWHEnabled ? _WWHEnabled->isChecked() : false); 00491 00492 // do not bother the user with "nickname empty" if he has not 00493 // messed with nickname settings ... 00494 TQString newName = _nickname->text(); 00495 if ( newName.isEmpty() && !internal->playerInfos().isAnonymous() 00496 && !enabled ) return true; 00497 00498 if ( newName.isEmpty() ) { 00499 KMessageBox::sorry(this, i18n("Please choose a non empty nickname.")); 00500 return false; 00501 } 00502 if ( internal->playerInfos().isNameUsed(newName) ) { 00503 KMessageBox::sorry(this, i18n("Nickname already in use. Please " 00504 "choose another one")); 00505 return false; 00506 } 00507 00508 int res = 00509 internal->modifySettings(newName, _comment->text(), enabled, this); 00510 if (res) { 00511 load(); // needed to update view when "apply" is clicked 00512 enableButtonApply(false); 00513 } 00514 _saved = true; 00515 return res; 00516 } 00517 00518 //----------------------------------------------------------------------------- 00519 AskNameDialog::AskNameDialog(TQWidget *parent) 00520 : KDialogBase(Plain, i18n("Enter Your Nickname"), Ok | Cancel, Ok, 00521 parent, "ask_name_dialog") 00522 { 00523 internal->hsConfig().readCurrentConfig(); 00524 00525 TQVBoxLayout *top = 00526 new TQVBoxLayout(plainPage(), marginHint(), spacingHint()); 00527 TQLabel *label = 00528 new TQLabel(i18n("Congratulations, you have won!"), plainPage()); 00529 top->addWidget(label); 00530 00531 TQHBoxLayout *hbox = new TQHBoxLayout(top); 00532 label = new TQLabel(i18n("Enter your nickname:"), plainPage()); 00533 hbox->addWidget(label); 00534 _edit = new TQLineEdit(plainPage()); 00535 _edit->setFocus(); 00536 connect(_edit, TQT_SIGNAL(textChanged(const TQString &)), TQT_SLOT(nameChanged())); 00537 hbox->addWidget(_edit); 00538 00539 top->addSpacing(spacingHint()); 00540 _checkbox = new TQCheckBox(i18n("Do not ask again."), plainPage()); 00541 top->addWidget(_checkbox); 00542 00543 nameChanged(); 00544 } 00545 00546 void AskNameDialog::nameChanged() 00547 { 00548 enableButtonOK( !name().isEmpty() 00549 && !internal->playerInfos().isNameUsed(name()) ); 00550 } 00551 00552 } // namespace