Qt interface:

- Initialize the random numbers generator, and print the seed value
 - Handle properly Qt builds without STL support
 - Save the position of the main window
 - Got rid of the useless toolbar
 - Better size of the preferences dialog
 - Hopefully fixed translation issues on Windows
 - The Settings class throws an exception when asked for a non-existing setting
This commit is contained in:
Olivier Teulière 2008-09-05 21:31:30 +00:00
parent f5bde7fb4e
commit 990f4c5212
16 changed files with 304 additions and 106 deletions

View file

@ -45,7 +45,7 @@
#include <cerrno>
#include <cstring>
// For ntohl & Co.
// For htonl & Co.
#ifdef WIN32
# include <winsock2.h>
#else
@ -63,6 +63,9 @@
#else
# define _(String) String
#endif
#ifdef WIN32
# include <windows.h>
#endif
#include "hashtable.h"
#include "encoding.h"
@ -438,7 +441,17 @@ int main(int argc, char* argv[])
#if ENABLE_NLS
// Set the message domain
bindtextdomain(PACKAGE, LOCALEDIR);
#ifdef WIN32
// Get the absolute path, as returned by GetFullPathName()
char localeDir[MAX_PATH];
GetFullPathName(argv[0], MAX_PATH, localeDir, NULL);
char *pos = strrchr(localeDir, L'\\');
if (pos)
*pos = '\0';
#else
static const char *localeDir = LOCALEDIR;
#endif
bindtextdomain(PACKAGE, localeDir);
textdomain(PACKAGE);
#endif

View file

@ -41,6 +41,9 @@
#else
# define _(String) String
#endif
#ifdef WIN32
# include <windows.h>
#endif
#include "header.h"
#include "encoding.h"
@ -125,7 +128,17 @@ int main(int argc, char *argv[])
#if ENABLE_NLS
// Set the message domain
bindtextdomain(PACKAGE, LOCALEDIR);
#ifdef WIN32
// Get the absolute path, as returned by GetFullPathName()
char localeDir[MAX_PATH];
GetFullPathName(argv[0], MAX_PATH, localeDir, NULL);
char *pos = strrchr(localeDir, L'\\');
if (pos)
*pos = '\0';
#else
static const char *localeDir = LOCALEDIR;
#endif
bindtextdomain(PACKAGE, localeDir);
textdomain(PACKAGE);
#endif

View file

@ -38,6 +38,9 @@
#else
# define _(String) String
#endif
#ifdef WIN32
# include <windows.h>
#endif
#include "dic.h"
#include "dic_exception.h"
@ -61,7 +64,17 @@ int main(int argc, char* argv[])
#if ENABLE_NLS
// Set the message domain
bindtextdomain(PACKAGE, LOCALEDIR);
#ifdef WIN32
// Get the absolute path, as returned by GetFullPathName()
char localeDir[MAX_PATH];
GetFullPathName(argv[0], MAX_PATH, localeDir, NULL);
char *pos = strrchr(localeDir, L'\\');
if (pos)
*pos = '\0';
#else
static const char *localeDir = LOCALEDIR;
#endif
bindtextdomain(PACKAGE, localeDir);
textdomain(PACKAGE);
#endif

View file

@ -1,7 +1,7 @@
ICONV_VERSION = 1.12
WX_VERSION = 2.6.4
BOOST_VERSION = 1_34_1
QT_VERSION = 4.3.3
QT_VERSION = 4.4.1
PREFIX = $(shell pwd)/inst
WGET = wget -c
@ -72,14 +72,14 @@ $(BOOST_DIR):
### Qt ###
# FIXME: No automated way at the moment :-(
QT_ARCHIVE = qt-win-opensource-$(QT_VERSION)-mingw.exe
QT_ARCHIVE = qt4-$(QT_VERSION)-win32-bin.tar.bz2
QT_DIR = qt4-$(QT_VERSION)-win32-bin
$(QT_ARCHIVE):
$(WGET) ftp://ftp.trolltech.com/qt/source/qt-win-opensource-4.3.3-mingw.exe
$(QT_DIR):
$(WGET) http://download.videolan.org/pub/videolan/testing/contrib/$(QT_ARCHIVE)
tar xjf $(QT_ARCHIVE)
.qt: $(QT_ARCHIVE)
@echo "=============== Important note ==============="
@echo "You need to install $(QT_ARCHIVE) yourself using wine!"
@echo "=============================================="
.qt: $(QT_DIR)
(cd $<; mkdir -p $(PREFIX)/bin; mkdir -p $(PREFIX)/include; mkdir -p $(PREFIX)/lib/pkgconfig; rm -f $(PREFIX)/lib/pkgconfig/Qt*; sed 's,@@PREFIX@@,$(PREFIX),' lib/pkgconfig/QtCore.pc.in > $(PREFIX)/lib/pkgconfig/QtCore.pc; sed 's,@@PREFIX@@,$(PREFIX),' lib/pkgconfig/QtGui.pc.in > $(PREFIX)/lib/pkgconfig/QtGui.pc; cp -r include/* $(PREFIX)/include; cp lib/*a $(PREFIX)/lib; mkdir -p $(PREFIX)/share/qt4/translations; cp -r share/translations/* $(PREFIX)/share/qt4/translations)
touch $@

View file

@ -22,28 +22,29 @@ noinst_LIBRARIES = libgame.a
AM_CPPFLAGS = -I$(top_srcdir)/dic -I../intl -I$(top_srcdir)/intl
libgame_a_SOURCES= \
ai_percent.cpp ai_percent.h \
ai_player.h \
bag.cpp bag.h \
coord.cpp coord.h \
cross.cpp cross.h \
board.cpp board.h \
board_cross.cpp \
board_search.cpp \
duplicate.cpp duplicate.h \
freegame.cpp freegame.h \
game.cpp game.h \
game_factory.cpp game_factory.h \
game_io.cpp \
move.cpp move.h \
player.cpp player.h \
pldrack.cpp pldrack.h \
rack.cpp rack.h \
results.cpp results.h \
round.cpp round.h \
settings.cpp settings.h \
training.cpp training.h \
turn.cpp turn.h \
history.cpp history.h \
debug.h
ai_percent.cpp ai_percent.h \
ai_player.h \
bag.cpp bag.h \
coord.cpp coord.h \
cross.cpp cross.h \
board.cpp board.h \
board_cross.cpp \
board_search.cpp \
duplicate.cpp duplicate.h \
freegame.cpp freegame.h \
game.cpp game.h \
game_exception.cpp game_exception.h \
game_factory.cpp game_factory.h \
game_io.cpp \
move.cpp move.h \
player.cpp player.h \
pldrack.cpp pldrack.h \
rack.cpp rack.h \
results.cpp results.h \
round.cpp round.h \
settings.cpp settings.h \
training.cpp training.h \
turn.cpp turn.h \
history.cpp history.h \
debug.h

36
game/game_exception.cpp Normal file
View file

@ -0,0 +1,36 @@
/*****************************************************************************
* Eliot
* Copyright (C) 2007 Olivier Teulière
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#include "game_exception.h"
using namespace std;
GameException::GameException(const string &iMessage)
: m_message(iMessage)
{
}
const char *GameException::what() const throw()
{
return m_message.c_str();
}

45
game/game_exception.h Normal file
View file

@ -0,0 +1,45 @@
/*****************************************************************************
* Eliot
* Copyright (C) 2007 Olivier Teulière
* Authors: Olivier Teulière <ipkiss @@ gmail.com>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#ifndef _GAME_EXCEPTION_H_
#define _GAME_EXCEPTION_H_
#include <exception>
#include <string>
/**
* Exception class for the Game library.
* It simply inherits from the standard exception and overrides
* its what() method.
*/
class GameException: public std::exception
{
public:
GameException(const std::string &iMessage);
~GameException() throw() {}
virtual const char *what() const throw();
private:
std::string m_message;
};
#endif

View file

@ -21,6 +21,7 @@
#include <cstdlib>
#include "settings.h"
#include "game_exception.h"
Settings *Settings::m_instance = NULL;
@ -113,8 +114,7 @@ void Settings::OptionsHandler<T>::setOption(const string &iName, const T &iValue
typename map<string, T>::iterator it = m_options.find(iName);
if (it == m_options.end())
{
// FIXME: throw an exception object instead
throw 1;
throw GameException("No such option: " + iName);
}
it->second = iValue;
}
@ -126,8 +126,7 @@ const T& Settings::OptionsHandler<T>::getOption(const string &iName) const
typename map<string, T>::const_iterator it = m_options.find(iName);
if (it == m_options.end())
{
// FIXME: throw an exception object instead
throw 1;
throw GameException("No such option: " + iName);
}
return it->second;
}

View file

@ -24,6 +24,9 @@
#include <QLocale>
#include <QTranslator>
#include "main_window.h"
#ifdef WIN32
# include <windows.h>
#endif
int main(int argc, char **argv)
{
@ -37,24 +40,33 @@ int main(int argc, char **argv)
#ifdef ENABLE_NLS
// Set the message domain
bindtextdomain(PACKAGE, LOCALEDIR);
#ifdef WIN32
// Get the absolute path, as returned by GetFullPathName()
char localeDir[MAX_PATH];
GetFullPathName(argv[0], MAX_PATH, localeDir, NULL);
char *pos = strrchr(localeDir, L'\\');
if (pos)
*pos = '\0';
#else
static const char *localeDir = LOCALEDIR;
#endif
bindtextdomain(PACKAGE, localeDir);
textdomain(PACKAGE);
// Translations for Qt's own strings
QTranslator translator;
// Set the path for the translation file
#if !defined( WIN32 )
QString path = QString(QT4LOCALEDIR);
#ifdef WIN32
QString path = localeDir;
#else
QString path = QString(LOCALEDIR) + "/qt4/";
QString path = QString(QT4LOCALEDIR);
#endif
QString lang = QLocale::system().name();
translator.load(path + "qt_" + lang);
translator.load(path + "/qt_" + lang);
app.installTranslator(&translator);
#endif
MainWindow qmain;
qmain.move(200, 200);
qmain.show();
return app.exec();
}

View file

@ -60,12 +60,29 @@
#include "coord.h"
const char *MainWindow::m_windowName = "MainWindow";
MainWindow::MainWindow(QWidget *iParent)
: QMainWindow(iParent), m_dic(NULL), m_game(NULL), m_newGameDialog(NULL),
m_prefsDialog(NULL), m_bagWindow(NULL), m_boardWindow(NULL),
m_historyWindow(NULL), m_dicToolsWindow(NULL), m_dicNameLabel(NULL)
{
m_ui.setupUi(this);
readSettings();
// Initialize the random numbers generator
// Note: This must be done _after_ creating the QMenuBar object,
// because on Gnome QMenuBar calls gconftool2, which for some reason
// calls srand() internally...
// This could be disabled using QApplication::setDesktopSettingsAware(),
// but we would lose the desktop integration...
unsigned int val = time(NULL);
srand(val);
#ifdef DEBUG
// Make it easier to reproduce bugs
cout << "Rand seed: " << val << endl;
#endif
QObject::connect(this, SIGNAL(gameChanged(const Game*)),
this, SLOT(updateForGame(const Game*)));
@ -216,7 +233,7 @@ void MainWindow::updateStatusBar(const Dictionary *iDic)
void MainWindow::displayErrorMsg(QString iMsg, QString iContext)
{
if (iContext == "")
iContext = PACKAGE_NAME;
iContext = _q("%1 error").arg(PACKAGE_NAME);
QMessageBox::warning(this, iContext, iMsg);
}
@ -239,10 +256,33 @@ void MainWindow::closeEvent(QCloseEvent *event)
m_historyWindow->close();
if (m_dicToolsWindow)
m_dicToolsWindow->close();
writeSettings();
event->accept();
}
void MainWindow::writeSettings() const
{
QSettings settings(ORGANIZATION, PACKAGE_NAME);
settings.beginGroup(m_windowName);
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings(ORGANIZATION, PACKAGE_NAME);
settings.beginGroup(m_windowName);
QSize size = settings.value("size").toSize();
if (size.isValid())
resize(size);
move(settings.value("pos", QPoint(200, 200)).toPoint());
settings.endGroup();
}
void MainWindow::on_action_GameNew_triggered()
{
if (m_dic == NULL)

View file

@ -97,6 +97,8 @@ private:
/// Dialog for the preferences
PrefsDialog *m_prefsDialog;
static const char * m_windowName;
/// Auxiliary windows
//@{
AuxWindow *m_bagWindow;
@ -108,6 +110,11 @@ private:
/// Label indicationg the name of the current dictionary
QLabel *m_dicNameLabel;
/// Save window state
void writeSettings() const;
/// Restore window state
void readSettings();
/// Destroy the current game (if any) and the associated widgets
void destroyCurrentGame();

View file

@ -22,8 +22,10 @@
#include <QtCore/QSettings>
#include <QtGui/QFileDialog>
#include <QtGui/QMessageBox>
#include "prefs_dialog.h"
#include "game_exception.h"
#include "settings.h"
@ -36,15 +38,23 @@ PrefsDialog::PrefsDialog(QWidget *iParent)
{
setupUi(this);
// Interface settings
QSettings qs(ORGANIZATION, PACKAGE_NAME);
checkBoxIntfAlignHistory->setChecked(qs.value(kINTF_ALIGN_HISTORY).toBool());
lineEditIntfDicPath->setText(qs.value(kINTF_DIC_PATH, "").toString());
try
{
// Interface settings
QSettings qs(ORGANIZATION, PACKAGE_NAME);
checkBoxIntfAlignHistory->setChecked(qs.value(kINTF_ALIGN_HISTORY).toBool());
lineEditIntfDicPath->setText(qs.value(kINTF_DIC_PATH, "").toString());
// Duplicate settings
checkBoxDuplRefuseInvalid->setChecked(Settings::Instance().getBool("duplicate-reject-invalid"));
spinBoxDuplSoloPlayers->setValue(Settings::Instance().getInt("duplicate-solo-players"));
spinBoxDuplSoloValue->setValue(Settings::Instance().getInt("duplicate-solo-value"));
// Duplicate settings
checkBoxDuplRefuseInvalid->setChecked(Settings::Instance().getBool("duplicate-reject-invalid"));
spinBoxDuplSoloPlayers->setValue(Settings::Instance().getInt("duplicate-solo-players"));
spinBoxDuplSoloValue->setValue(Settings::Instance().getInt("duplicate-solo-value"));
}
catch (GameException &e)
{
QMessageBox::warning(this, _q("%1 error").arg(PACKAGE_NAME),
_q("Cannot load preferences: %1").arg(e.what()));
}
// Freegame settings
checkBoxFreeRefuseInvalid->setChecked(Settings::Instance().getBool("freegame-reject-invalid"));
@ -69,30 +79,38 @@ void PrefsDialog::updateSettings()
{
bool shouldEmitUpdate = false;
// Interface settings
QSettings qs(ORGANIZATION, PACKAGE_NAME);
if (qs.value(kINTF_ALIGN_HISTORY).toBool() != checkBoxIntfAlignHistory->isChecked())
try
{
// We need to redraw the history widget
shouldEmitUpdate = true;
qs.setValue(kINTF_ALIGN_HISTORY, checkBoxIntfAlignHistory->isChecked());
// Interface settings
QSettings qs(ORGANIZATION, PACKAGE_NAME);
if (qs.value(kINTF_ALIGN_HISTORY).toBool() != checkBoxIntfAlignHistory->isChecked())
{
// We need to redraw the history widget
shouldEmitUpdate = true;
qs.setValue(kINTF_ALIGN_HISTORY, checkBoxIntfAlignHistory->isChecked());
}
qs.setValue(kINTF_DIC_PATH, lineEditIntfDicPath->text());
// Duplicate settings
Settings::Instance().setBool("duplicate-reject-invalid",
checkBoxDuplRefuseInvalid->isChecked());
Settings::Instance().setInt("duplicate-solo-players",
spinBoxDuplSoloPlayers->value());
Settings::Instance().setInt("duplicate-solo-value",
spinBoxDuplSoloValue->value());
// Freegame settings
Settings::Instance().setBool("freegame-reject-invalid",
checkBoxFreeRefuseInvalid->isChecked());
// Training settings
}
catch (GameException &e)
{
QMessageBox::warning(this, _q("%1 error").arg(PACKAGE_NAME),
_q("Cannot save preferences: %1").arg(e.what()));
}
qs.setValue(kINTF_DIC_PATH, lineEditIntfDicPath->text());
// Duplicate settings
Settings::Instance().setBool("duplicate-reject-invalid",
checkBoxDuplRefuseInvalid->isChecked());
Settings::Instance().setInt("duplicate-solo-players",
spinBoxDuplSoloPlayers->value());
Settings::Instance().setInt("duplicate-solo-value",
spinBoxDuplSoloValue->value());
// Freegame settings
Settings::Instance().setBool("freegame-reject-invalid",
checkBoxFreeRefuseInvalid->isChecked());
// Training settings
if (shouldEmitUpdate)
emit gameUpdated();

View file

@ -22,6 +22,7 @@
#define QT_COMMON_H_
#include "config.h"
#include <QtCore/QString>
#if ENABLE_NLS
# include <libintl.h>
@ -40,13 +41,13 @@
#define qfl(s) QString::fromLocal8Bit(s)
#define qtl(s) (s).toLocal8Bit().data()
// Convert to/from std::wstring
#ifdef WIN32
#include "encoding.h"
#define qfw(s) qfl(convertToMb(s).c_str())
#define qtw(s) convertToWc(qtl(s))
#ifdef QT_NO_STL
# include "encoding.h"
# define qfw(s) qfl(convertToMb(s).c_str())
# define qtw(s) convertToWc(qtl(s))
#else
#define qfw(s) QString::fromStdWString(s)
#define qtw(s) (s).toStdWString().data()
# define qfw(s) QString::fromStdWString(s)
# define qtw(s) (s).toStdWString().data()
#endif
// Translation macro to use gettext
#define _q(s) qfu(_(s))

View file

@ -20,9 +20,9 @@
<property name="geometry" >
<rect>
<x>0</x>
<y>37</y>
<y>26</y>
<width>747</width>
<height>557</height>
<height>568</height>
</rect>
</property>
<layout class="QVBoxLayout" >
@ -126,25 +126,6 @@
</rect>
</property>
</widget>
<widget class="QToolBar" name="toolBar" >
<property name="geometry" >
<rect>
<x>0</x>
<y>26</y>
<width>747</width>
<height>11</height>
</rect>
</property>
<property name="windowTitle" >
<string>toolBar</string>
</property>
<attribute name="toolBarArea" >
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak" >
<bool>false</bool>
</attribute>
</widget>
<action name="action_SettingsChooseDic" >
<property name="text" >
<string>_("Choose dictionary...")</string>

View file

@ -5,7 +5,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>343</width>
<width>401</width>
<height>432</height>
</rect>
</property>
@ -30,6 +30,12 @@
</item>
<item>
<widget class="QLineEdit" name="lineEditIntfDicPath" >
<property name="minimumSize" >
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="toolTip" >
<string>_("Enter the dictionary path (mandatory to start a game)")</string>
</property>

View file

@ -24,6 +24,9 @@
#else
# define _(String) String
#endif
#ifdef WIN32
# include <windows.h>
#endif
#include <ctype.h>
#include <cstring> // For strlen
@ -1118,7 +1121,17 @@ int main(int argc, char ** argv)
#if ENABLE_NLS
// Set the message domain
bindtextdomain(PACKAGE, LOCALEDIR);
#ifdef WIN32
// Get the absolute path, as returned by GetFullPathName()
char localeDir[MAX_PATH];
GetFullPathName(argv[0], MAX_PATH, localeDir, NULL);
char *pos = strrchr(localeDir, L'\\');
if (pos)
*pos = '\0';
#else
static const char *localeDir = LOCALEDIR;
#endif
bindtextdomain(PACKAGE, localeDir);
textdomain(PACKAGE);
#endif