mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-12-27 08:29:26 -05:00
87344de7d4
git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@1850 b45a01b8-16f6-495d-af2f-9b41ad6348cc
575 lines
15 KiB
C++
575 lines
15 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2002-2003 Andi Peredri *
|
|
* andi@ukr.net *
|
|
* Copyright (C) 2004-2005 Artur Wiebe *
|
|
* wibix@gmx.de *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program 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 General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, write to the *
|
|
* Free Software Foundation, Inc., *
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
***************************************************************************/
|
|
|
|
#include <QLayout>
|
|
#include <QApplication>
|
|
#include <QMenuBar>
|
|
#include <QToolBar>
|
|
#include <QDir>
|
|
#include <QMessageBox>
|
|
#include <QFileDialog>
|
|
#include <QCloseEvent>
|
|
#include <QFontDialog>
|
|
#include <QDebug>
|
|
|
|
#include "pdn.h"
|
|
#include "toplevel.h"
|
|
#include "newgamedlg.h"
|
|
#include "view.h"
|
|
#include "common.h"
|
|
|
|
#define CFG_THEME_PATH CFG_KEY"ThemePath"
|
|
#define CFG_FILENAME CFG_KEY"Filename"
|
|
#define CFG_KEEPDIALOG CFG_KEY"ShowKeepDialog"
|
|
#define CFG_NOTATION CFG_KEY"Notation"
|
|
#define CFG_NOT_ABOVE CFG_KEY"NotationAbove"
|
|
#define CFG_NOT_FONT CFG_KEY"NotationFont"
|
|
#define CFG_CLEAR_LOG CFG_KEY"ClearLogOnNewRound"
|
|
|
|
|
|
myTopLevel::myTopLevel()
|
|
{
|
|
setWindowTitle(APPNAME);
|
|
setWindowIcon(QIcon(":/icons/biglogo.png"));
|
|
|
|
m_newgame = new myNewGameDlg(this);
|
|
make_central_widget();
|
|
make_actions();
|
|
restore_settings();
|
|
|
|
/*
|
|
* new computer game.
|
|
*/
|
|
m_view->newGame(m_newgame->rules(), m_newgame->freePlacement(),
|
|
m_newgame->name(),
|
|
m_newgame->isWhite(), m_newgame->opponent(),
|
|
m_newgame->opponentName(), m_newgame->skill());
|
|
|
|
if(layout())
|
|
layout()->setSizeConstraint(QLayout::SetFixedSize);
|
|
}
|
|
|
|
|
|
void myTopLevel::make_actions()
|
|
{
|
|
// game menu actions
|
|
gameNew = new QAction(QIcon(":/icons/logo.png"), tr("&New..."), this);
|
|
gameNew->setShortcut(tr("CTRL+N", "File|New"));
|
|
connect(gameNew, SIGNAL(triggered()), this, SLOT(slot_new_game()));
|
|
|
|
gameNextRound = new QAction(QIcon(":/icons/next.png"),
|
|
tr("&Next Round"), this);
|
|
connect(gameNextRound, SIGNAL(triggered()),
|
|
this, SLOT(slot_next_round()));
|
|
|
|
gameStop = new QAction(QIcon(":/icons/stop.png"), tr("&Stop"), this);
|
|
connect(gameStop, SIGNAL(triggered()), m_view, SLOT(slotStopGame()));
|
|
|
|
gameOpen = new QAction(QIcon(":/icons/fileopen.png"), tr("&Open..."),
|
|
this);
|
|
gameOpen->setShortcut(tr("CTRL+O", "File|Open"));
|
|
connect(gameOpen, SIGNAL(triggered()), this, SLOT(slot_open_game()));
|
|
|
|
gameSave = new QAction(QIcon(":/icons/filesave.png"), tr("&Save..."),
|
|
this);
|
|
gameSave->setShortcut(tr("CTRL+S", "File|Save"));
|
|
connect(gameSave, SIGNAL(triggered()), this, SLOT(slot_save_game()));
|
|
|
|
QAction* gameQuit = new QAction(QIcon(":/icons/exit.png"), tr("&Quit"),
|
|
this);
|
|
gameQuit->setShortcut(tr("CTRL+Q", "File|Quit"));
|
|
connect(gameQuit, SIGNAL(triggered()),
|
|
this, SLOT(close()));
|
|
// QApplication::instance(), SLOT(quit()));
|
|
|
|
// view menu actions
|
|
viewNotation = new QAction(tr("&Show Notation"), this);
|
|
viewNotation->setCheckable(true);
|
|
connect(viewNotation, SIGNAL(toggled(bool)),
|
|
this, SLOT(slot_notation(bool)));
|
|
|
|
viewNotationAbove = new QAction(tr("Show notation &above men"), this);
|
|
viewNotationAbove->setCheckable(true);
|
|
connect(viewNotationAbove, SIGNAL(toggled(bool)),
|
|
this, SLOT(slot_notation(bool)));
|
|
|
|
// settings menu
|
|
settingsKeep = new QAction(tr("&Confirm aborting current game"), this);
|
|
settingsKeep->setCheckable(true);
|
|
//
|
|
settingsClearLog = new QAction(tr("Clear &log on new round"), this);
|
|
settingsClearLog->setCheckable(true);
|
|
connect(settingsClearLog, SIGNAL(toggled(bool)),
|
|
m_view, SLOT(slotClearLog(bool)));
|
|
//
|
|
QAction* settingsNotationFont = new QAction(tr("&Notation font..."),
|
|
this);
|
|
connect(settingsNotationFont, SIGNAL(triggered()),
|
|
this, SLOT(slot_notation_font()));
|
|
|
|
// help menu actions
|
|
QAction* helpRules = new QAction(tr("&Rules of Play"), this);
|
|
helpRules->setShortcut(tr("F1", "Help|Help"));
|
|
connect(helpRules, SIGNAL(triggered()), this, SLOT(slot_help()));
|
|
|
|
QAction* helpAbout = new QAction(QIcon(":/icons/logo.png"),
|
|
tr("&About")+" "APPNAME, this);
|
|
connect(helpAbout, SIGNAL(triggered()), this, SLOT(slot_about()));
|
|
|
|
QAction* helpAboutQt = new QAction(tr("About &Qt"), this);
|
|
connect(helpAboutQt, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
|
|
|
|
|
|
/*
|
|
* toolbar
|
|
*/
|
|
QToolBar* tb = addToolBar(tr("&Toolbar"));
|
|
tb->setMovable(false);
|
|
tb->addAction(gameNew);
|
|
tb->addAction(gameOpen);
|
|
tb->addAction(gameSave);
|
|
tb->addSeparator();
|
|
tb->addAction(gameNextRound);
|
|
tb->addAction(gameStop);
|
|
|
|
|
|
/*
|
|
* menus
|
|
*/
|
|
QMenu* gameMenu = menuBar()->addMenu(tr("&Game"));
|
|
gameMenu->addAction(gameNew);
|
|
gameMenu->addAction(gameOpen);
|
|
gameMenu->addAction(gameSave);
|
|
gameMenu->addSeparator();
|
|
gameMenu->addAction(gameNextRound);
|
|
gameMenu->addAction(gameStop);
|
|
gameMenu->addSeparator();
|
|
gameMenu->addAction(gameQuit);
|
|
|
|
viewMenu = menuBar()->addMenu(tr("&View"));
|
|
viewMenu->addAction(tb->toggleViewAction());
|
|
viewMenu->addSeparator();
|
|
viewMenu->addAction(viewNotation);
|
|
viewMenu->addAction(viewNotationAbove);
|
|
|
|
QMenu* settingsMenu = menuBar()->addMenu(tr("&Settings"));
|
|
settingsMenu->addAction(settingsKeep);
|
|
settingsMenu->addSeparator();
|
|
settingsMenu->addAction(settingsNotationFont);
|
|
settingsMenu->addSeparator();
|
|
settingsMenu->addAction(settingsClearLog);
|
|
|
|
QMenu* helpMenu = menuBar()->addMenu(tr("&Help"));
|
|
helpMenu->addAction(helpRules);
|
|
helpMenu->addSeparator();
|
|
helpMenu->addAction(helpAbout);
|
|
helpMenu->addAction(helpAboutQt);
|
|
|
|
|
|
/*
|
|
* THEMES. create a default theme.
|
|
*/
|
|
QActionGroup* themes_grp = new QActionGroup(this);
|
|
themes_grp->setExclusive(true);
|
|
|
|
QAction* default_theme = new QAction(tr(DEFAULT_THEME), themes_grp);
|
|
default_theme->setCheckable(true);
|
|
m_themes[default_theme] = DEFAULT_THEME;
|
|
default_theme->setChecked(true);
|
|
set_theme(default_theme);//FIXME TODO
|
|
themes_grp->addAction(default_theme);
|
|
|
|
viewMenu->addSeparator();
|
|
viewMenu->addAction(default_theme);
|
|
read_themes(themes_grp,
|
|
viewMenu,QDir::homePath()+"/"USER_PATH"/"THEME_DIR);
|
|
//TODO-hardcoded
|
|
read_themes(themes_grp,
|
|
viewMenu, PREFIX"/share/kcheckers/"THEME_DIR);
|
|
|
|
connect(themes_grp, SIGNAL(triggered(QAction*)),
|
|
this, SLOT(set_theme(QAction*)));
|
|
}
|
|
|
|
|
|
void myTopLevel::read_themes(QActionGroup* menu_grp, QMenu* menu,
|
|
const QString& path)
|
|
{
|
|
QDir sharedir(path);
|
|
QStringList themes = sharedir.entryList(QDir::Dirs|QDir::Readable);
|
|
themes.removeAll(".");
|
|
themes.removeAll("..");
|
|
|
|
for(QStringList::iterator it=themes.begin(); it!=themes.end(); ++it) {
|
|
sharedir.cd(*it);
|
|
|
|
QString theme_dir = sharedir.absolutePath();
|
|
QString errtext;
|
|
|
|
QStringList files
|
|
= sharedir.entryList(QDir::Files|QDir::Readable);
|
|
|
|
// all files are there.
|
|
if(files.count()!=8 ||
|
|
files.indexOf(THEME_TILE1) == -1 ||
|
|
files.indexOf(THEME_TILE2) == -1 ||
|
|
files.indexOf(THEME_FRAME) == -1 ||
|
|
files.indexOf(THEME_MANBLACK) == -1 ||
|
|
files.indexOf(THEME_MANWHITE) == -1 ||
|
|
files.indexOf(THEME_KINGBLACK) == -1 ||
|
|
files.indexOf(THEME_KINGWHITE) == -1 ||
|
|
files.indexOf(THEME_FILE) == -1) {
|
|
// TODO not translated.
|
|
errtext += "Wrong number of files. ";
|
|
}
|
|
files.removeAll(THEME_FILE);
|
|
|
|
// check pic size.
|
|
QSize size = QPixmap(theme_dir+"/"+files[0]).size();
|
|
if(size.width()>MAX_TILE_SIZE || size.height()>MAX_TILE_SIZE)
|
|
// TODO not translated.
|
|
errtext += "Picture(s) too big. ";
|
|
|
|
if(size.width()==0 || size.height()==0)
|
|
// TODO not translated.
|
|
errtext += "Width/Height is zero. ";
|
|
|
|
// check pics all the same size.
|
|
foreach(QString file, files) {
|
|
if(QPixmap(theme_dir+"/"+file).size() != size) {
|
|
// TODO not translated.
|
|
errtext += "Pictures are different in size. ";
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(errtext.length()) {
|
|
// TODO not translated.
|
|
qWarning() << endl << "Theme in"
|
|
<< sharedir.absolutePath() << endl << errtext;
|
|
|
|
} else {
|
|
QString themename = sharedir.dirName();
|
|
|
|
/*TODO
|
|
QFile file(theme_dir+"/"+THEME_FILE);
|
|
if(file.open(QFile::ReadOnly)) {
|
|
QTextStream ts(&file);
|
|
if(!ts.atEnd())
|
|
themename = ts.readLine();
|
|
// try go get locale theme name
|
|
// TODO
|
|
QString locale = QString("[%1]=").arg(QTextCodec::locale());
|
|
while(!ts.atEnd()) {
|
|
QString line = ts.readLine();
|
|
if(line.startsWith(locale)) {
|
|
themename = line.mid(locale.length());
|
|
break;
|
|
}
|
|
}
|
|
file.close();
|
|
}
|
|
*/
|
|
//
|
|
QAction* action = new QAction(themename, this);
|
|
menu_grp->addAction(action);
|
|
menu->addAction(action);
|
|
action->setCheckable(true);
|
|
m_themes[action] = theme_dir;
|
|
}
|
|
|
|
sharedir.cdUp();
|
|
}
|
|
}
|
|
|
|
|
|
void myTopLevel::restore_settings()
|
|
{
|
|
QSettings cfg(APPNAME, APPNAME);
|
|
|
|
QString theme_path = cfg.value(CFG_THEME_PATH, DEFAULT_THEME)
|
|
.toString();
|
|
for(myThemeMap::iterator it = m_themes.begin(); it!=m_themes.end();it++)
|
|
if(it.value() == theme_path) {
|
|
it.key()->setChecked(true);
|
|
set_theme(it.key());
|
|
break;
|
|
}
|
|
|
|
filename = cfg.value(CFG_FILENAME).toString();
|
|
|
|
viewNotation->setChecked(cfg.value(CFG_NOTATION, false).toBool());
|
|
viewNotationAbove->setChecked(cfg.value(CFG_NOT_ABOVE, true).toBool());
|
|
slot_notation(true); // here: arg is ignored by the function
|
|
|
|
bool clear_log = cfg.value(CFG_CLEAR_LOG, true).toBool();
|
|
settingsClearLog->setChecked(clear_log);
|
|
m_view->slotClearLog(clear_log);
|
|
|
|
//
|
|
settingsKeep->setChecked(cfg.value(CFG_KEEPDIALOG, true).toBool());
|
|
|
|
QFont cfont;
|
|
if(cfont.fromString(cfg.value(CFG_NOT_FONT, "").toString()))
|
|
m_view->setNotationFont(cfont);
|
|
|
|
// new game
|
|
m_newgame->readSettings(&cfg);
|
|
}
|
|
|
|
|
|
void myTopLevel::make_central_widget()
|
|
{
|
|
m_view = new myView(this);
|
|
|
|
connect(m_view, SIGNAL(working(bool)),
|
|
this, SLOT(slot_working(bool)));
|
|
|
|
setCentralWidget(m_view);
|
|
}
|
|
|
|
|
|
void myTopLevel::warning(const QString& text)
|
|
{
|
|
QMessageBox::warning(this, tr("Error")+" - "APPNAME, text);
|
|
}
|
|
|
|
|
|
void myTopLevel::information(const QString& caption, const QString& text)
|
|
{
|
|
QDialog* dlg = new QDialog(this);
|
|
dlg->setModal(true);
|
|
dlg->setWindowTitle(caption+" - "APPNAME);
|
|
|
|
// logo left
|
|
QLabel* logo = new QLabel(dlg);
|
|
logo->setPixmap(QPixmap(":/icons/dialog.png"));
|
|
|
|
// text editor
|
|
QTextEdit* te = new QTextEdit(text, dlg);
|
|
te->setReadOnly(true);
|
|
te->setMinimumWidth(m_view->width()-100);
|
|
te->setMinimumHeight(m_view->height()-200);
|
|
|
|
// close button
|
|
QPushButton* button = new QPushButton(tr("&Close"), dlg);
|
|
connect(button, SIGNAL(clicked()), dlg, SLOT(accept()));
|
|
|
|
// Layout.
|
|
QHBoxLayout* hb = new QHBoxLayout();
|
|
hb->addWidget(logo, 0, Qt::AlignTop);
|
|
hb->addWidget(te, 1);
|
|
|
|
QHBoxLayout* hb_button = new QHBoxLayout();
|
|
hb_button->addStretch();
|
|
hb_button->addWidget(button);
|
|
|
|
QVBoxLayout* vb = new QVBoxLayout(dlg);
|
|
vb->addLayout(hb, 1);
|
|
vb->addSpacing(5);
|
|
vb->addLayout(hb_button);
|
|
|
|
// go
|
|
dlg->exec();
|
|
delete dlg;
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_save_game()
|
|
{
|
|
QString fn = QFileDialog::getSaveFileName(this,
|
|
tr("Save Game")+" - "APPNAME, filename, "PDN Files (*."EXT")");
|
|
if(!fn.isEmpty()) {
|
|
if(fn.right(3)!=EXT)
|
|
fn += "."EXT;
|
|
|
|
if(m_view->savePdn(fn))
|
|
filename = fn;
|
|
else
|
|
warning(tr("Could not save: ")+filename);
|
|
}
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_open_game()
|
|
{
|
|
QString fn = QFileDialog::getOpenFileName(this,
|
|
tr("Open Game")+" - "APPNAME, filename, "PDN Files (*."EXT")");
|
|
if(!fn.isEmpty())
|
|
open(fn);
|
|
}
|
|
|
|
|
|
void myTopLevel::open(const QString& fn)
|
|
{
|
|
if(m_view->openPdn(fn))
|
|
filename = fn;
|
|
}
|
|
|
|
|
|
void myTopLevel::closeEvent(QCloseEvent* e)
|
|
{
|
|
if(!keep_game()) {
|
|
store_settings();
|
|
e->accept();
|
|
} else {
|
|
e->ignore();
|
|
}
|
|
}
|
|
|
|
|
|
void myTopLevel::store_settings()
|
|
{
|
|
QSettings config(APPNAME, APPNAME);
|
|
|
|
for(myThemeMap::iterator it=m_themes.begin(); it!=m_themes.end(); it++)
|
|
if(it.key()->isChecked()) {
|
|
config.setValue(CFG_THEME_PATH, it.value());
|
|
break;
|
|
}
|
|
|
|
config.setValue(CFG_FILENAME, filename);
|
|
|
|
config.setValue(CFG_NOTATION, viewNotation->isChecked());
|
|
config.setValue(CFG_NOT_ABOVE, viewNotationAbove->isChecked());
|
|
|
|
config.setValue(CFG_KEEPDIALOG, settingsKeep->isChecked());
|
|
config.setValue(CFG_NOT_FONT, m_view->notationFont().toString());
|
|
config.setValue(CFG_CLEAR_LOG, settingsClearLog->isChecked());
|
|
|
|
// new game
|
|
m_newgame->writeSettings(&config);
|
|
}
|
|
|
|
|
|
void myTopLevel::set_theme(QAction* action)
|
|
{
|
|
QString path = m_themes[action];
|
|
m_view->setTheme(path);
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_help()
|
|
{
|
|
QString text =
|
|
tr("<p>In the beginning of game you have 12 checkers (men). "
|
|
"The men move forward only. The men can capture:"
|
|
"<ul>"
|
|
"<li>by jumping forward only (english rules);"
|
|
"<li>by jumping forward or backward (russian rules)."
|
|
"</ul>"
|
|
"<p>A man which reaches the far side of the board becomes a king. "
|
|
"The kings move forward or backward:"
|
|
"<ul>"
|
|
"<li>to one square only (english rules);"
|
|
"<li>to any number of squares (russian rules)."
|
|
"</ul>"
|
|
"<p>The kings capture by jumping forward or backward. "
|
|
"Whenever a player is able to make a capture he must do so.");
|
|
|
|
information(tr("Rules of Play"), text);
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_about()
|
|
{
|
|
QString text =
|
|
APPNAME", a board game.<br>Version "VERSION"<br><br>"
|
|
COPYRIGHT"<br>"
|
|
"<a href=\""HOMEPAGE"\">"HOMEPAGE"</a><br><br>"
|
|
"Contributors:<br>"CONTRIBS"<br><br>"
|
|
"This program is distributed under the terms "
|
|
"of the GNU General Public License.";
|
|
|
|
information(tr("About"), text);
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_new_game()
|
|
{
|
|
if(keep_game())
|
|
return;
|
|
|
|
if(m_newgame->exec()==QDialog::Accepted) {
|
|
m_view->newGame(m_newgame->rules(), m_newgame->freePlacement(),
|
|
m_newgame->name(),
|
|
m_newgame->isWhite(), m_newgame->opponent(),
|
|
m_newgame->opponentName(), m_newgame->skill());
|
|
}
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_working(bool working)
|
|
{
|
|
bool disable = !working;
|
|
|
|
gameNew->setEnabled(disable);
|
|
gameSave->setEnabled(disable);
|
|
|
|
gameNextRound->setEnabled(disable);// FIXME !m_view->isAborted());
|
|
gameOpen->setEnabled(disable);
|
|
gameStop->setEnabled(!disable);
|
|
|
|
m_view->setEnabled(disable);
|
|
}
|
|
|
|
|
|
bool myTopLevel::keep_game()
|
|
{
|
|
if(!settingsKeep->isChecked() || m_view->isAborted())
|
|
return false;
|
|
|
|
int answer = QMessageBox::question(this, tr("Abort Game?")+" - "APPNAME,
|
|
tr("Current game will be lost if you continue.\n"
|
|
"Do you really want to discard it?"),
|
|
QMessageBox::Yes, QMessageBox::No);
|
|
|
|
if(answer == QMessageBox::Yes)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_next_round()
|
|
{
|
|
if(!keep_game())
|
|
m_view->slotNextRound();
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_notation_font()
|
|
{
|
|
bool ok;
|
|
QFont font = QFontDialog::getFont(&ok, m_view->notationFont(), this);
|
|
if(ok)
|
|
m_view->setNotationFont(font);
|
|
}
|
|
|
|
|
|
void myTopLevel::slot_notation(bool)
|
|
{
|
|
m_view->setNotation(viewNotation->isChecked(),
|
|
viewNotationAbove->isChecked());
|
|
}
|
|
|