You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
553 lines
18 KiB
C++
553 lines
18 KiB
C++
/*
|
|
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 <qlayout.h>
|
|
#include <qtextstream.h>
|
|
#include <qheader.h>
|
|
#include <qgrid.h>
|
|
#include <qvgroupbox.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(QListView *list, bool highlight)
|
|
: KListViewItem(list), _highlight(highlight)
|
|
{}
|
|
|
|
void ShowItem::paintCell(QPainter *p, const QColorGroup &cg,
|
|
int column, int width, int align)
|
|
{
|
|
QColorGroup cgrp(cg);
|
|
if (_highlight) cgrp.setColor(QColorGroup::Text, red);
|
|
KListViewItem::paintCell(p, cgrp, column, width, align);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ScoresList::ScoresList(QWidget *parent)
|
|
: KListView(parent)
|
|
{
|
|
setSelectionMode(QListView::NoSelection);
|
|
setItemMargin(3);
|
|
setAllColumnsShowFocus(true);
|
|
setSorting(-1);
|
|
header()->setClickEnabled(false);
|
|
header()->setMovingEnabled(false);
|
|
}
|
|
|
|
void ScoresList::addHeader(const ItemArray &items)
|
|
{
|
|
addLineItem(items, 0, 0);
|
|
}
|
|
|
|
QListViewItem *ScoresList::addLine(const ItemArray &items,
|
|
uint index, bool highlight)
|
|
{
|
|
QListViewItem *item = new ShowItem(this, highlight);
|
|
addLineItem(items, index, item);
|
|
return item;
|
|
}
|
|
|
|
void ScoresList::addLineItem(const ItemArray &items,
|
|
uint index, QListViewItem *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()->alignment());
|
|
}
|
|
k++;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HighscoresList::HighscoresList(QWidget *parent)
|
|
: ScoresList(parent)
|
|
{}
|
|
|
|
QString HighscoresList::itemText(const ItemContainer &item, uint row) const
|
|
{
|
|
return item.pretty(row);
|
|
}
|
|
|
|
void HighscoresList::load(const ItemArray &items, int highlight)
|
|
{
|
|
clear();
|
|
QListViewItem *line = 0;
|
|
for (int j=items.nbEntries()-1; j>=0; j--) {
|
|
QListViewItem *item = addLine(items, j, j==highlight);
|
|
if ( j==highlight ) line = item;
|
|
}
|
|
if (line) ensureItemVisible(line);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
HighscoresWidget::HighscoresWidget(QWidget *parent)
|
|
: QWidget(parent, "show_highscores_widget"),
|
|
_scoresUrl(0), _playersUrl(0), _statsTab(0), _histoTab(0)
|
|
{
|
|
const ScoreInfos &s = internal->scoreInfos();
|
|
const PlayerInfos &p = internal->playerInfos();
|
|
|
|
QVBoxLayout *vbox = new QVBoxLayout(this, KDialogBase::spacingHint());
|
|
|
|
_tw = new QTabWidget(this);
|
|
connect(_tw, SIGNAL(currentChanged(QWidget *)), 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, SIGNAL(leftClickedURL(const QString &)),
|
|
SLOT(showURL(const QString &)));
|
|
vbox->addWidget(_scoresUrl);
|
|
|
|
url = internal->queryURL(ManagerPrivate::Players);
|
|
_playersUrl = new KURLLabel(url.url(),
|
|
i18n("View world-wide players"), this);
|
|
connect(_playersUrl, SIGNAL(leftClickedURL(const QString &)),
|
|
SLOT(showURL(const QString &)));
|
|
vbox->addWidget(_playersUrl);
|
|
}
|
|
}
|
|
|
|
void HighscoresWidget::changeTab(int i)
|
|
{
|
|
if ( i!=_tw->currentPageIndex() )
|
|
_tw->setCurrentPage(i);
|
|
}
|
|
|
|
void HighscoresWidget::showURL(const QString &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, QWidget *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; i<internal->nbGameTypes(); i++) {
|
|
QString title = internal->manager.gameTypeLabel(i, Manager::I18N);
|
|
QString icon = internal->manager.gameTypeLabel(i, Manager::Icon);
|
|
QWidget *w = addVBoxPage(title, QString::null,
|
|
BarIcon(icon, KIcon::SizeLarge));
|
|
if ( i==internal->gameType() ) createPage(w);
|
|
}
|
|
|
|
connect(this, SIGNAL(aboutToShowPage(QWidget *)),
|
|
SLOT(createPage(QWidget *)));
|
|
showPage(internal->gameType());
|
|
} else {
|
|
QVBoxLayout *vbox = new QVBoxLayout(plainPage());
|
|
createPage(plainPage());
|
|
vbox->addWidget(_widgets[0]);
|
|
setMainWidget(_widgets[0]);
|
|
}
|
|
}
|
|
|
|
void HighscoresDialog::createPage(QWidget *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], SIGNAL(tabChanged(int)), 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(QString::null, QString::null, 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 QValueVector<Score> &scores, QWidget *parent)
|
|
: ScoresList(parent), _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, QListViewItem *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()->alignment());
|
|
}
|
|
}
|
|
}
|
|
|
|
QString LastMultipleScoresList::itemText(const ItemContainer &item,
|
|
uint row) const
|
|
{
|
|
QString name = item.name();
|
|
if ( name=="rank" )
|
|
return (_scores[row].type()==Won ? i18n("Winner") : QString::null);
|
|
QVariant v = _scores[row].data(name);
|
|
if ( name=="name" ) return v.toString();
|
|
return item.item()->pretty(row, v);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
TotalMultipleScoresList::TotalMultipleScoresList(
|
|
const QValueVector<Score> &scores, QWidget *parent)
|
|
: ScoresList(parent), _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, QListViewItem *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 {
|
|
QString label =
|
|
(i==2 ? i18n("Won Games") : container->item()->label());
|
|
addColumn(label);
|
|
setColumnAlignment(i, container->item()->alignment());
|
|
}
|
|
}
|
|
}
|
|
|
|
QString TotalMultipleScoresList::itemText(const ItemContainer &item,
|
|
uint row) const
|
|
{
|
|
QString name = item.name();
|
|
if ( name=="rank" ) return QString::number(_scores.size()-row);
|
|
if ( name=="nb games" )
|
|
return QString::number( _scores[row].data("nb won games").toUInt() );
|
|
QVariant v = _scores[row].data(name);
|
|
if ( name=="name" ) return v.toString();
|
|
return item.item()->pretty(row, v);
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
ConfigDialog::ConfigDialog(QWidget *parent)
|
|
: KDialogBase(Swallow, i18n("Configure Highscores"),
|
|
Ok|Apply|Cancel, Cancel,
|
|
parent, "configure_highscores", true, true),
|
|
_saved(false), _WWHEnabled(0)
|
|
{
|
|
QWidget *page = 0;
|
|
QTabWidget *tab = 0;
|
|
if ( internal->isWWHSAvailable() ) {
|
|
tab = new QTabWidget(this);
|
|
setMainWidget(tab);
|
|
page = new QWidget(tab);
|
|
tab->addTab(page, i18n("Main"));
|
|
} else {
|
|
page = new QWidget(this);
|
|
setMainWidget(page);
|
|
}
|
|
|
|
QGridLayout *pageTop =
|
|
new QGridLayout(page, 2, 2, spacingHint(), spacingHint());
|
|
|
|
QLabel *label = new QLabel(i18n("Nickname:"), page);
|
|
pageTop->addWidget(label, 0, 0);
|
|
_nickname = new QLineEdit(page);
|
|
connect(_nickname, SIGNAL(textChanged(const QString &)),
|
|
SLOT(modifiedSlot()));
|
|
connect(_nickname, SIGNAL(textChanged(const QString &)),
|
|
SLOT(nickNameChanged(const QString &)));
|
|
|
|
_nickname->setMaxLength(16);
|
|
pageTop->addWidget(_nickname, 0, 1);
|
|
|
|
label = new QLabel(i18n("Comment:"), page);
|
|
pageTop->addWidget(label, 1, 0);
|
|
_comment = new QLineEdit(page);
|
|
connect(_comment, SIGNAL(textChanged(const QString &)),
|
|
SLOT(modifiedSlot()));
|
|
_comment->setMaxLength(50);
|
|
pageTop->addWidget(_comment, 1, 1);
|
|
|
|
if (tab) {
|
|
_WWHEnabled
|
|
= new QCheckBox(i18n("World-wide highscores enabled"), page);
|
|
connect(_WWHEnabled, SIGNAL(toggled(bool)),
|
|
SLOT(modifiedSlot()));
|
|
pageTop->addMultiCellWidget(_WWHEnabled, 2, 2, 0, 1);
|
|
|
|
// advanced tab
|
|
QWidget *page = new QWidget(tab);
|
|
tab->addTab(page, i18n("Advanced"));
|
|
QVBoxLayout *pageTop =
|
|
new QVBoxLayout(page, spacingHint(), spacingHint());
|
|
|
|
QVGroupBox *group = new QVGroupBox(i18n("Registration Data"), page);
|
|
pageTop->addWidget(group);
|
|
QGrid *grid = new QGrid(2, group);
|
|
grid->setSpacing(spacingHint());
|
|
|
|
label = new QLabel(i18n("Nickname:"), grid);
|
|
_registeredName = new KLineEdit(grid);
|
|
_registeredName->setReadOnly(true);
|
|
|
|
label = new QLabel(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, SIGNAL(clicked()), SLOT(removeSlot()));
|
|
}
|
|
|
|
load();
|
|
enableButtonOK( !_nickname->text().isEmpty() );
|
|
enableButtonApply(false);
|
|
}
|
|
|
|
void ConfigDialog::nickNameChanged(const QString &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."),
|
|
QString::null, 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() ? QString::null : 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 ...
|
|
QString 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(QWidget *parent)
|
|
: KDialogBase(Plain, i18n("Enter Your Nickname"), Ok | Cancel, Ok,
|
|
parent, "ask_name_dialog")
|
|
{
|
|
internal->hsConfig().readCurrentConfig();
|
|
|
|
QVBoxLayout *top =
|
|
new QVBoxLayout(plainPage(), marginHint(), spacingHint());
|
|
QLabel *label =
|
|
new QLabel(i18n("Congratulations, you have won!"), plainPage());
|
|
top->addWidget(label);
|
|
|
|
QHBoxLayout *hbox = new QHBoxLayout(top);
|
|
label = new QLabel(i18n("Enter your nickname:"), plainPage());
|
|
hbox->addWidget(label);
|
|
_edit = new QLineEdit(plainPage());
|
|
_edit->setFocus();
|
|
connect(_edit, SIGNAL(textChanged(const QString &)), SLOT(nameChanged()));
|
|
hbox->addWidget(_edit);
|
|
|
|
top->addSpacing(spacingHint());
|
|
_checkbox = new QCheckBox(i18n("Do not ask again."), plainPage());
|
|
top->addWidget(_checkbox);
|
|
|
|
nameChanged();
|
|
}
|
|
|
|
void AskNameDialog::nameChanged()
|
|
{
|
|
enableButtonOK( !name().isEmpty()
|
|
&& !internal->playerInfos().isNameUsed(name()) );
|
|
}
|
|
|
|
} // namespace
|