You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegames/libkdegames/highscore/kexthighscore_gui.cpp

553 lines
18 KiB

/*
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 <tqlayout.h>
#include <tqtextstream.h>
#include <tqheader.h>
#include <tqgrid.h>
#include <tqvgroupbox.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <kurllabel.h>
#include <kopenwith.h>
#include <krun.h>
#include <kfiledialog.h>
#include <ktempfile.h>
#include <kio/netaccess.h>
#include <kiconloader.h>
#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 *tqparent)
: KListView(tqparent)
{
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; i<items.size(); i++) {
const ItemContainer &container = *items[i];
if ( !container.item()->isVisible() ) continue;
if (line) line->setText(k, itemText(container, index));
else {
addColumn( container.item()->label() );
setColumnAlignment(k, container.item()->tqalignment());
}
k++;
}
}
//-----------------------------------------------------------------------------
HighscoresList::HighscoresList(TQWidget *tqparent)
: ScoresList(tqparent)
{}
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 *tqparent)
: TQWidget(tqparent, "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 *tqparent)
: KDialogBase(internal->nbGameTypes()>1 ? TreeList : Plain,
i18n("Highscores"), Close|User1|User2, Close,
tqparent, "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; i<internal->nbGameTypes(); 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<Score> &scores, TQWidget *tqparent)
: ScoresList(tqparent), _scores(scores)
{
const ScoreInfos &s = internal->scoreInfos();
addHeader(s);
for (uint i=0; i<scores.size(); i++) addLine(s, i, false);
}
void LastMultipleScoresList::addLineItem(const ItemArray &si,
uint index, TQListViewItem *line)
{
uint k = 1; // skip "id"
for (uint i=0; i<si.size()-2; i++) {
if ( i==3 ) k = 5; // skip "date"
const ItemContainer *container = si[k];
k++;
if (line) line->setText(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<Score> &scores, TQWidget *tqparent)
: ScoresList(tqparent), _scores(scores)
{
const ScoreInfos &s = internal->scoreInfos();
addHeader(s);
for (uint i=0; i<scores.size(); i++) addLine(s, i, false);
}
void TotalMultipleScoresList::addLineItem(const ItemArray &si,
uint index, TQListViewItem *line)
{
const PlayerInfos &pi = internal->playerInfos();
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 *tqparent)
: KDialogBase(Swallow, i18n("Configure Highscores"),
Ok|Apply|Cancel, Cancel,
tqparent, "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 *tqparent)
: KDialogBase(Plain, i18n("Enter Your Nickname"), Ok | Cancel, Ok,
tqparent, "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