diff --git a/Makefile.am b/Makefile.am index 15c26b9..3cebc42 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -SUBDIRS = intl dic game utils wxwin qt po +SUBDIRS = intl dic game utils wxwin qt po extras ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.in b/configure.in index 4ea437c..271c4ec 100644 --- a/configure.in +++ b/configure.in @@ -76,7 +76,7 @@ dnl -------------------------------------------------------------- dnl Checks for header files. dnl -------------------------------------------------------------- AC_HEADER_STDC -AC_CHECK_HEADERS(fcntl.h unistd.h sys/wait.h) +AC_CHECK_HEADERS(fcntl.h unistd.h sys/wait.h sys/stats.h sys/types.h) AC_CHECK_HEADERS(arpa/inet.h netinet/in.h) AC_CHECK_HEADERS([readline/readline.h], [has_readline=1], [has_readline=0]) AM_CONDITIONAL(HAS_READLINE, test "$has_readline" = "1") @@ -108,12 +108,17 @@ dnl -------------------------------------------------------------- dnl Check for the Boost libraries (in fact we only need the headers) AX_BOOST_BASE([1.33.1]) +PKG_CHECK_MODULES(LIBCONFIG, [libconfig++], + [has_libconfig=1 + AC_DEFINE(HAVE_LIBCONFIG, 1, [Define to 1 if you have the libconfig library])], + [has_libconfig=0]) + dnl Check for wxWidgets AC_ARG_ENABLE([wxwidgets],AC_HELP_STRING([--enable-wxwidgets],[wxWidgets interface support (default disabled)])) if test "${enable_wxwidgets}" = "yes" then - AM_PATH_WXCONFIG(2.6.0, [wxWin=1], [wxWin=0], [], [--unicode]) - if test "${wxWin}" != 1; then + AM_PATH_WXCONFIG(2.6.0, [wxWin=1], [wxWin=0], [], [--unicode]) + if test "${wxWin}" != 1; then AC_MSG_ERROR([ wxWidgets (unicode build) must be installed on your system but wx-config script couldn't be found. @@ -123,11 +128,11 @@ then 'wx-config --libs' command) is in LD_LIBRARY_PATH or equivalent variable and wxWidgets version is 2.6.0 or above. ]) - fi - AM_CPPFLAGS="$AM_CPPFLAGS $WX_CPPFLAGS" - AM_CXXFLAGS="$AM_CXXFLAGS $WX_CXXFLAGS_ONLY" - AM_CFLAGS="$AM_CFLAGS $WX_CFLAGS_ONLY" - AM_LDFLAGS="$AM_LDFLAGS $WX_LIBS" + fi + AM_CPPFLAGS="$AM_CPPFLAGS $WX_CPPFLAGS" + AM_CXXFLAGS="$AM_CXXFLAGS $WX_CXXFLAGS_ONLY" + AM_CFLAGS="$AM_CFLAGS $WX_CFLAGS_ONLY" + AM_LDFLAGS="$AM_LDFLAGS $WX_LIBS" fi AM_CONDITIONAL([BUILD_WXWIDGETS], [test "${wxWin}" = "1"]) @@ -206,5 +211,15 @@ game/Makefile utils/Makefile wxwin/Makefile qt/Makefile +extras/Makefile Makefile) AC_OUTPUT + +if test "$has_libconfig" != "1"; then + echo + echo "@@@@@@@@@@@" + echo "Warning!" + echo "libconfig++ was not detected on your system: saving and loading the configuration will be impossible!" + echo "libconfig++ can be downloaded here: http://www.hyperrealm.com/main.php?s=libconfig" + echo "@@@@@@@@@@@" +fi diff --git a/extras/Makefile.am b/extras/Makefile.am new file mode 100644 index 0000000..6ad35e6 --- /dev/null +++ b/extras/Makefile.am @@ -0,0 +1,10 @@ +# Install the desktop icon (at least for Gnome) + +shortcutdir = $(datadir)/applications +shortcut_DATA = eliot.desktop + +icondir = $(datadir)/icons +icon_DATA = eliot.xpm + +EXTRA_DIST = $(shortcut_DATA) $(icon_DATA) + diff --git a/extras/contrib/Makefile b/extras/contrib/Makefile index d65ab90..21caf0b 100644 --- a/extras/contrib/Makefile +++ b/extras/contrib/Makefile @@ -1,4 +1,5 @@ ICONV_VERSION = 1.12 +LIBCONFIG_VERSION = 1.3.1 WX_VERSION = 2.6.4 BOOST_VERSION = 1_34_1 QT_VERSION = 4.4.1 @@ -10,14 +11,14 @@ WGET = wget -c CC = i586-mingw32msvc-gcc CXX = i586-mingw32msvc-g++ CPPFLAGS += -I$(PREFIX)/include -CONFIGURE = CC=$(CC) CXX=$(CXX) CPPFLAGS=$(CPPFLAGS) ./configure --host=i586-mingw32msvc --build=i386-linux --prefix=$(PREFIX) +CONFIGURE = CC="$(CC)" CXX="$(CXX)" CPPFLAGS="$(CPPFLAGS)" ./configure --host=i586-mingw32msvc --build=i386-linux --prefix=$(PREFIX) .PHONY: help all -help: - echo "Usage: make all" +all: .iconv .wxWidgets .boost .qt .libconfig -all: .iconv .wxWidgets .boost .qt +help: + @echo "Usage: make all" ### iconv ### @@ -34,6 +35,20 @@ $(ICONV_DIR): touch $@ +### libconfig ### + +LIBCONFIG_DIR = libconfig-$(LIBCONFIG_VERSION) +LIBCONFIG_ARCHIVE = libconfig-$(LIBCONFIG_VERSION).tar.gz + +$(LIBCONFIG_DIR): + $(WGET) http://www.hyperrealm.com/libconfig/$(LIBCONFIG_ARCHIVE) + tar xvf $(LIBCONFIG_ARCHIVE) + +.libconfig: $(LIBCONFIG_DIR) + (cd $< && CFLAGS=-DLIBCONFIG_STATIC CXXFLAGS=-DLIBCONFIG_STATIC $(CONFIGURE) --enable-static --disable-shared && make && make install) + touch $@ + + ### wxWidgets ### WX_ARCHIVE = wxMSW-$(WX_VERSION).zip @@ -68,7 +83,6 @@ $(BOOST_DIR): touch $@ - ### Qt ### # FIXME: No automated way at the moment :-( diff --git a/extras/eliot.desktop b/extras/eliot.desktop new file mode 100644 index 0000000..4310449 --- /dev/null +++ b/extras/eliot.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Name=Eliot +Comment=A Scrabble (TM) game +Comment[fr]=Un jeu de Scrabble (TM) +Exec=eliot +Icon=eliot.xpm +Terminal=0 +Type=Application +Categories=Game; + diff --git a/extras/eliot.xpm b/extras/eliot.xpm new file mode 100644 index 0000000..a64cadf --- /dev/null +++ b/extras/eliot.xpm @@ -0,0 +1,315 @@ +/* XPM */ +static char * eliot_xpm[] = { +"48 48 264 2", +" c None", +". c #E2E2E2", +"+ c #EFEFEF", +"@ c #EEEFEE", +"# c #EEEEEE", +"$ c #DBDBDB", +"% c #EDEEED", +"& c #D9DAD9", +"* c #FFFFFF", +"= c #CACACA", +"- c #F0F0F0", +"; c #BEBEBE", +"> c #E1E1E1", +", c #C7C7C7", +"' c #BCBCBC", +") c #D3D3D3", +"! c #A3A3A3", +"~ c #F9F9F9", +"{ c #A0A0A0", +"] c #C1C1C1", +"^ c #E0E0E0", +"/ c #B5B5B5", +"( c #D2D2D2", +"_ c #CDCDCD", +": c #B4B4B4", +"< c #B9B9B9", +"[ c #FDFDFD", +"} c #C3C3C3", +"| c #D4D4D4", +"1 c #F5F5F5", +"2 c #969696", +"3 c #EDEDED", +"4 c #A9A9A9", +"5 c #A6A6A6", +"6 c #BFBFBF", +"7 c #A8A8A8", +"8 c #E5E6E5", +"9 c #FBFBFB", +"0 c #E5E2E2", +"a c #E2DFDF", +"b c #E4E3E2", +"c c #E3E3E3", +"d c #DCDCDC", +"e c #E4E5E4", +"f c #E2E3E2", +"g c #E2E4E4", +"h c #CED1D2", +"i c #DEE1E2", +"j c #DEDEDE", +"k c #E5E5E5", +"l c #DFE0DF", +"m c #E4E4E4", +"n c #DFDCDC", +"o c #E4E4E3", +"p c #E0E1E0", +"q c #E0E4E5", +"r c #D5D9D9", +"s c #DFE1E1", +"t c #E4E3E3", +"u c #DEDBDA", +"v c #F6505A", +"w c #DF787D", +"x c #64C0E0", +"y c #1DAEE2", +"z c #20BEF6", +"A c #C3DCE4", +"B c #FAFAFA", +"C c #EAEBEA", +"D c #E3BBBD", +"E c #E19EA2", +"F c #E7E8E7", +"G c #21BDF4", +"H c #51BADF", +"I c #E0868B", +"J c #E3C5C6", +"K c #CC878C", +"L c #E5CFD9", +"M c #CFC6CA", +"N c #7EB9CC", +"O c #52ADCD", +"P c #59BDDF", +"Q c #BACACE", +"R c #AABAD2", +"S c #B5C6E3", +"T c #AAB8CE", +"U c #CEB6B6", +"V c #CDA4A5", +"W c #B2BDCE", +"X c #CECFCF", +"Y c #D1D2D1", +"Z c #59BCDE", +"` c #73B5CC", +" . c #CFC8CB", +".. c #CC8E93", +"+. c #DFCCCD", +"@. c #FF91C5", +"#. c #E5B5CB", +"$. c #EAEAEA", +"%. c #2268E3", +"&. c #1869F6", +"*. c #3171DE", +"=. c #5789DF", +"-. c #DDE0E5", +";. c #E5BED0", +">. c #E5C6D4", +",. c #9A9A9A", +"'. c #CFAABB", +"). c #E5BACE", +"!. c #CFC5CA", +"~. c #D2D3D2", +"{. c #CFD0CF", +"]. c #7B9BD0", +"^. c #7FA3E1", +"/. c #7B9BCC", +"(. c #8DCCE1", +"_. c #9BC1CD", +":. c #AAC5CE", +"<. c #7DA2CC", +"[. c #CCCECF", +"}. c #E3E4E3", +"|. c #CFC9CB", +"1. c #CFC2C8", +"2. c #C9C9C9", +"3. c #E5C9D6", +"4. c #D9E2E5", +"5. c #61BFE0", +"6. c #86CAE1", +"7. c #B4D7E3", +"8. c #E5D3DB", +"9. c #E5B1C9", +"0. c #CFCFCF", +"a. c #CFA4B8", +"b. c #D298B3", +"c. c #E5A6C3", +"d. c #CFC7CA", +"e. c #D4D5D4", +"f. c #CCCFCF", +"g. c #ACD5E3", +"h. c #8EBDCD", +"i. c #82BACC", +"j. c #C3CDCF", +"k. c #E3A5C2", +"l. c #CFA1B7", +"m. c #CFC3C8", +"n. c #89BCCC", +"o. c #C8DADF", +"p. c #ACACAC", +"q. c #D8DBDC", +"r. c #EA85B5", +"s. c #E5D5DC", +"t. c #AFD6E3", +"u. c #8ACBE1", +"v. c #FD90C4", +"w. c #E59DBF", +"x. c #6CC2E0", +"y. c #BBD9E3", +"z. c #D6E1E4", +"A. c #C6CDCF", +"B. c #CFCCCD", +"C. c #D2CCCE", +"D. c #E5DEE1", +"E. c #CF96B0", +"F. c #E591B9", +"G. c #E090B6", +"H. c #C9CECF", +"I. c #CF8DAC", +"J. c #D18BAB", +"K. c #E3DCDF", +"L. c #CFCBCD", +"M. c #C7CECF", +"N. c #DDE0E0", +"O. c #9F9F9F", +"P. c #E59ABD", +"Q. c #FA8FC2", +"R. c #E58EB7", +"S. c #E78AB6", +"T. c #D6D6D6", +"U. c #D9D9D9", +"V. c #D694B3", +"W. c #ED8CB9", +"X. c #E88BB6", +"Y. c #DADBDA", +"Z. c #D689AD", +"`. c #D886AC", +" + c #EBEBEB", +".+ c #F7F8F7", +"++ c #B1C2DD", +"@+ c #1C69EF", +"#+ c #7EA0DB", +"$+ c #DFDFDF", +"%+ c #F2F3F2", +"&+ c #2568DC", +"*+ c #3370D8", +"=+ c #5888D9", +"-+ c #D7DADE", +";+ c #F5F6F5", +">+ c #90ACDC", +",+ c #9FB6DC", +"'+ c #C2C2C2", +")+ c #92B0E2", +"!+ c #A2BAE2", +"~+ c #AEBBCE", +"{+ c #447DDF", +"]+ c #7C9FCC", +"^+ c #C6DDE4", +"/+ c #487ACE", +"(+ c #507ECA", +"_+ c #BDCBCF", +":+ c #C2CCCF", +"<+ c #668ECB", +"[+ c #CACDCF", +"}+ c #CACFCF", +"|+ c #87A7CC", +"1+ c #A1B2CE", +"2+ c #E1E2E1", +"3+ c #BFDAE3", +"4+ c #7BC7E1", +"5+ c #ADADAD", +"6+ c #E2ADB0", +"7+ c #CDADAE", +"8+ c #A3C3CE", +"9+ c #73C4E0", +"0+ c #88BCCC", +"a+ c #90BFCF", +"b+ c #9DD0E2", +"c+ c #C4CDCF", +"d+ c #8CB4C8", +"e+ c #E5C2D2", +"f+ c #9FB4C6", +"g+ c #B6C9CE", +"h+ c #9CCFE0", +"i+ c #8CBDCD", +"j+ c #99C0CD", +"k+ c #CEB1B2", +"l+ c #E0D6D6", +"m+ c #E5CBD7", +"n+ c #E582B1", +"o+ c #E5B9CD", +"p+ c #E7E7E7", +"q+ c #E6E7E6", +"r+ c #CCCCCC", +"s+ c #E8E8E8", +"t+ c #F2F2F2", +"u+ c #989898", +"v+ c #FEFEFE", +"w+ c #E3E4E4", +"x+ c #F1F1F1", +"y+ c #B6B6B6", +"z+ c #DCD9D9", +"A+ c #DADADA", +"B+ c #F7F7F7", +"C+ c #E4D3D4", +"D+ c #E2D8D8", +"E+ c #D5DFE2", +"F+ c #BDCCD1", +"G+ c #CEDFE4", +"H+ c #DFE2E2", +"I+ c #E2DFDE", +"J+ c #E2DCDB", +"K+ c #D3DEE2", +"L+ c #E2D9D9", +"M+ c #F3F0F0", +"N+ c #D7D8D7", +"O+ c #CECFCE", +". + + + @ + + # + @ # + $ @ + # + + # + + % + + # + @ @ + @ # + @ @ + # + @ # + @ @ + # # + + & ", +"+ * * * = * - ; * > , * ' ) * ! ~ * { * * ] * ^ / * ( _ * : < [ } | 1 2 3 = 4 * = 5 * 6 7 * * 8 ", +"+ * 9 0 a b c d e f . g h i e j k k l e 8 f m 0 n o p f e f l e f . q r s f l e f f t a u 1 * 8 ", +"+ + 0 v v w * * 8 * * x y z A * B C * 8 * * D v v E * * 8 * * 8 * F G z H * * 8 * * I v v J * 8 ", +"@ ! 0 v v w * * 8 * * x y z A * B C * 8 * * D v v E * * 8 * * 8 * F G z H * * 8 * * I v v J * 8 ", +"+ * b w w K L L M 8 8 N O P Q 8 p R S T 8 8 U w w V 8 8 W S S X 8 Y Z P ` 8 8 .L L ..w w +.* 8 ", +"+ , 8 * * L @.@.#.* * 8 $.* 8 * B %.&.*.* * 8 * * 8 * * =.&.&.-.* F [ * 8 * * ;.@.@.>.* * 8 * 8 ", +"+ ,.8 * * L @.@.#.* * 8 $.* 8 * B %.&.*.* * 8 * * 8 * * =.&.&.-.* F [ * 8 * * ;.@.@.>.* * 8 * 8 ", +"+ * e 8 8 M #.#.'.).).!.~.8 {.8 p ].^./.(.(._.8 8 :.(.(.<.^.^.[.8 Y }.8 |.).).'.#.#.1.8 8 p * 8 ", +"+ 2.f * * 8 * * ).@.@.3.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 8.@.@.9.* * 8 * * 8 * 8 ", +"+ 0.f * * 8 * * ).@.@.3.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 8.@.@.9.* * 8 * * 8 * 8 ", +"+ * g x x N 8 8 !.3.3.a.b.c.d.8 p e.8 f.g.g.h.x x i.g.g.j.8 8 {.8 Y k.c.l.3.3.m.8 8 n.x x o.* 8 ", +"+ p.q.z z P * * 8 * * c.r.@.s.* B C * 8 * * t.z z u.* * 8 * * 8 * F v.@.w.* * 8 * * x.z z y.* 8 ", +"+ 0.q z z P * * 8 * * c.r.@.s.* B C * 8 * * t.z z u.* * 8 * * 8 * F v.@.w.* * 8 * * x.z z y.* 8 ", +"+ 9 e z.z.A.8 8 {.8 8 B.C.D.E.F.G.e.8 {.8 8 f.z.z.H.8 8 {.8 8 I.F.J.K.D.L.8 8 {.8 8 M.z.z.N.* 8 ", +"+ O.8 * * 8 * * 8 * * 8 $.* P.@.Q.C * 8 * * 8 * * 8 * * 8 * * R.@.S.[ * 8 * * 8 * * 8 * * 8 * 8 ", +"+ . k 3 3 T.3 3 T.3 3 T.U.3 V.W.X.Y.3 T.3 3 T.3 3 T.3 3 T.3 3 Z.W.`. +3 T.3 3 T.3 3 T.3 3 . * 8 ", +"+ j k .+.+++@+@+#+.+.+$+c .+$+.+%+&+@+*+.+.+$+.+.+$+.+.+=+@+@+-+.+> ;+.+$+.+.+>+@+@+,+.+.+m * 8 ", +"+ '+8 * * S &.&.^.* * 8 $.* 8 * B %.&.*.* * 8 * * 8 * * =.&.&.-.* F [ * 8 * * )+&.&.!+* * 8 * 8 ", +"+ * e 8 8 ~+{+{+]+^+^+M.~.8 {.8 p /+{+(+^+^+_+8 8 :+^+^+<+{+{+[+8 Y }.8 }+^+^+|+{+{+1+8 8 p * 8 ", +"@ 0.2+* * 8 * * (.z z g.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 3+z z 4+* * 8 * * 8 * 8 ", +"# 5+Y.* * 8 * * (.z z g.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 3+z z 4+* * 8 * * 8 * 8 ", +"+ * o 6+6+7+8 8 8+9+9+0+a+b+c+8 p e.8 H.9+9+d+e+e+f+9+9+g+8 8 {.8 Y h+b+i+9+9+j+8 8 k+6+6+l+* 8 ", +"+ '+0 v v w * * 8 * * x y z A * B C * 8 * * m+n+n+o+$ ^ 8 p+* 8 6 q+G z H * * 8 * * I v v J * 8 ", +"+ '+0 v v w * * 8 * * x y z A * B C * 8 * * m+v.n+o+$ ^ 8 ) B 8 6 q+G z H * * 8 * * I v v J * 8 ", +"+ * o 6+6+7+8 8 8+9+9+0+a+b+c+8 p e.8 H.9+9+d+e+e+f+9+9+g+8 8 {.8 Y h+b+i+9+9+j+8 8 k+6+6+l+* 8 ", +"+ $+8 * * 8 * * (.z z g.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 3+z z 4+* * 8 * * 8 * 8 ", +"+ # 8 * * 8 * * (.z z g.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 3+z z 4+* * 8 * * 8 * 8 ", +"+ * e 8 8 ~+{+{+]+^+^+M.~.8 {.8 p /+{+(+^+^+_+8 8 :+^+^+<+{+{+[+8 Y }.8 }+^+^+|+{+{+1+8 8 p * 8 ", +"+ r+8 * * S &.&.^.* * 8 $.* 8 * B %.&.*.* * 8 * * 8 * * =.&.&.-.* F [ * 8 * * )+&.&.!+* * 8 * 8 ", +"+ s+k .+.+++@+@+#+.+.+$+c .+$+.+%+&+@+*+.+.+$+.+.+$+.+.+=+@+@+-+.+> ;+.+$+.+.+>+@+@+,+.+.+m * 8 ", +"+ t+}.3 3 T.3 3 T.3 3 T.U.3 V.W.X.Y.3 T.3 3 T.3 3 T.3 3 T.3 3 Z.W.`. +3 T.3 3 T.3 3 T.3 3 . * 8 ", +"+ u+2+* * 8 * * 8 * * 8 $.* P.@.Q.C * 8 * * 8 * * 8 * * 8 * * R.@.S.[ * 8 * * 8 * * 8 * * 8 * 8 ", +"+ v+w+z.z.A.8 8 {.8 8 B.C.D.E.F.G.e.8 {.8 8 f.z.z.H.8 8 {.8 8 I.F.J.K.D.L.8 8 {.8 8 M.z.z.N.* 8 ", +"+ x+q z z P * * 8 * * c.r.@.s.* B C * 8 * * t.z z u.* * 8 * * 8 * F v.@.w.* * 8 * * x.z z y.* 8 ", +"+ } q z z P * * 8 * * c.r.@.s.* B C * 8 * * t.z z u.* * 8 * * 8 * F v.@.w.* * 8 * * x.z z y.* 8 ", +"+ * g x x N 8 8 !.3.3.a.b.c.d.8 p e.8 f.g.g.h.x x i.g.g.j.8 8 {.8 Y k.c.l.3.3.m.8 8 n.x x o.* 8 ", +"# ( Y * * 8 * * ).@.@.3.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 8.@.@.9.* * 8 * * 8 * 8 ", +"% y+r+* * 8 * * ).@.@.3.$.* 8 * B C * 4.z z 5.* * 6.z z 7.* * 8 * F [ * 8.@.@.9.* * 8 * * 8 * 8 ", +"+ * e 8 8 M #.#.'.).).!.~.8 {.8 p ].^./.(.(._.8 8 :.(.(.<.^.^.[.8 Y }.8 |.).).'.#.#.1.8 8 p * 8 ", +"+ p.8 * * L @.@.#.* * 8 $.* 8 * B %.&.*.* * 8 * * 8 * * =.&.&.-.* F [ * 8 * * ;.@.@.>.* * 8 * 8 ", +"+ = 8 * * L @.@.#.* * 8 $.* 8 * B %.&.*.* * 8 * * 8 * * =.&.&.-.* F [ * 8 * * ;.@.@.>.* * 8 * 8 ", +"+ * b w w K L L M 8 8 N O P Q 8 p R S T 8 8 U w w V 8 8 W S S X 8 Y Z P ` 8 8 .L L ..w w +.* 8 ", +"# 4 z+v v w * * 8 * * x y z A * B C * 8 * * D v v E * * 8 * * 8 * F G z H * * 8 * * I v v J * 8 ", +"+ A+0 v v w * * 8 * * x y z A * B C * 8 * * D v v E * * 8 * * 8 * F G z H * * 8 * * I v v J * 8 ", +"+ * B+C+C+D+8 8 f 8 8 E+F+G+H+8 e c 8 f 8 8 I+C+C+J+8 8 f 8 8 f 8 c G+G+K+8 8 f 8 8 L+C+C+M+* 8 ", +"+ * * * * * * * * * * * $.* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8 ", +"N+. . . . . . . . . . . 0.. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . O+"}; diff --git a/game/Makefile.am b/game/Makefile.am index 8a74f60..2acdb2b 100644 --- a/game/Makefile.am +++ b/game/Makefile.am @@ -19,7 +19,7 @@ noinst_LIBRARIES = libgame.a -AM_CPPFLAGS = -I$(top_srcdir)/dic -I../intl -I$(top_srcdir)/intl +AM_CPPFLAGS = -I$(top_srcdir)/dic -I../intl -I$(top_srcdir)/intl @LIBCONFIG_CFLAGS@ libgame_a_SOURCES= \ ai_percent.cpp ai_percent.h \ diff --git a/game/duplicate.cpp b/game/duplicate.cpp index be249ef..e052004 100644 --- a/game/duplicate.cpp +++ b/game/duplicate.cpp @@ -43,7 +43,7 @@ int Duplicate::play(const wstring &iCoord, const wstring &iWord) // Perform all the validity checks, and try to fill a round Round round; int res = checkPlayedWord(iCoord, iWord, round); - if (res != 0 && Settings::Instance().getBool("duplicate-reject-invalid")) + if (res != 0 && Settings::Instance().getBool("duplicate.reject-invalid")) { return res; } @@ -182,7 +182,7 @@ void Duplicate::endTurn() // Handle solo bonus // First check whether there are enough players in the game for the // bonus to apply - int minNbPlayers = Settings::Instance().getInt("duplicate-solo-players"); + int minNbPlayers = Settings::Instance().getInt("duplicate.solo-players"); if (getNPlayers() >= (unsigned int)minNbPlayers && m_players[imax]->getLastMove().getType() == Move::VALID_ROUND) { @@ -200,7 +200,7 @@ void Duplicate::endTurn() if (!otherWithSameScore) { // Give the bonus to player imax - int bonus = Settings::Instance().getInt("duplicate-solo-value"); + int bonus = Settings::Instance().getInt("duplicate.solo-value"); m_players[imax]->addPoints(bonus); // TODO: keep a trace of the solo, so the interface // can be aware of it... diff --git a/game/freegame.cpp b/game/freegame.cpp index f071c2b..c5406d0 100644 --- a/game/freegame.cpp +++ b/game/freegame.cpp @@ -48,7 +48,7 @@ int FreeGame::play(const wstring &iCoord, const wstring &iWord) // Perform all the validity checks, and try to fill a round Round round; int res = checkPlayedWord(iCoord, iWord, round); - if (res != 0 && Settings::Instance().getBool("freegame-reject-invalid")) + if (res != 0 && Settings::Instance().getBool("freegame.reject-invalid")) { return res; } diff --git a/game/settings.cpp b/game/settings.cpp index e2287d1..3c1b9a1 100644 --- a/game/settings.cpp +++ b/game/settings.cpp @@ -18,11 +18,28 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA *****************************************************************************/ +#include "config.h" + #include +#ifdef HAVE_LIBCONFIG +# define LIBCONFIG_STATIC +# include +#endif +#ifdef WIN32 +# include +# include +#else +# if defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H) +# include +# include +# endif +#endif #include "settings.h" #include "game_exception.h" +using namespace libconfig; + Settings *Settings::m_instance = NULL; @@ -44,90 +61,202 @@ void Settings::Destroy() } +namespace +{ + string getConfigFileName() + { + string fileName; +#ifdef WIN32 + char szPath[MAX_PATH]; + // Get the AppData directory + if (SHGetFolderPath(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, + NULL, 0, szPath) == S_OK) + { + fileName = szPath + string("\\eliot"); +#if 1 + strncpy(szPath, fileName.c_str(), MAX_PATH); + // Try to create the directory + // We don't care about the results + CreateDirectory(fileName.c_str(), NULL); +#endif + } + if (fileName != "") + fileName += "\\"; + fileName += "eliot.cfg"; +#else + // Follow the XDG Base Directory Specification (from freedesktop.org) + // XXX: In fact we don't follow it to the letter, because the location + // of the config file could be different when reading and writing. + // But in the case of Eliot it's not very important (we don't try to + // merge config files)... + const char *configDir = getenv("XDG_CONFIG_HOME"); + if (configDir != NULL) + fileName = configDir; + else + { + // Fallback to the default value: $HOME/.config + configDir = getenv("HOME"); + if (configDir) + fileName = configDir + string("/.config"); + } + fileName += "/eliot"; + +#if defined(HAVE_SYS_STAT_H) && defined(HAVE_SYS_TYPES_H) + // Create the directory if it doesn't exist + struct stat sb; + if (fileName != "" && stat(fileName.c_str(), &sb) == -1) + { + // Try to create the directory with mode 0700 + if (mkdir(fileName.c_str(), S_IRWXU)) + { + // The directory could not be created. Too bad... + // Saving the configuration file will definitely fail. + } + } +#endif + + fileName += "/eliot.cfg"; +#endif + return fileName; + } +} + + Settings::Settings() { - // ============== General options ============== +#ifdef HAVE_LIBCONFIG + m_fileName = ::getConfigFileName(); + m_conf = new Config; + // ============== General options ============== // ============== Training mode options ============== - // ============== Duplicate mode options ============== + Setting &dupli = m_conf->getRoot().add("duplicate", Setting::TypeGroup); // Minimum number of players in a duplicate game needed to apply a "solo" bonus // (16 is the ODS value) - m_intHandler.addOption("duplicate-solo-players", 16); + dupli.add("solo-players", Setting::TypeInt) = 16; // Number of points granted for a solo (10 is the ODS value) - m_intHandler.addOption("duplicate-solo-value", 10); + dupli.add("solo-value", Setting::TypeInt) = 10; // If true, Eliot complains when the player does something illegal // If false, the word is accepted (with a score of 0) and the player does // not get a second chance - m_boolHandler.addOption("duplicate-reject-invalid", true); - + dupli.add("reject-invalid", Setting::TypeBoolean) = true; // ============== Freegame mode options ============== + Setting &freegame = m_conf->getRoot().add("freegame", Setting::TypeGroup); // If true, Eliot complains when the player does something illegal // If false, the word is accepted (with a score of 0) and the player does // not get a second chance. // Trying to change letters or to pass the turn in an incorrect way will // be rejected in any case. - m_boolHandler.addOption("freegame-reject-invalid", true); + freegame.add("reject-invalid", Setting::TypeBoolean) = true; + + // Try to read the values from the configuration file + try + { + m_conf->readFile(m_fileName.c_str()); + } + catch (...) + { + // Ignore the exception + } +#endif +} + + +Settings::~Settings() +{ +#ifdef HAVE_LIBCONFIG + delete m_conf; +#endif +} + + +void Settings::save() const +{ +#ifdef HAVE_LIBCONFIG + try + { + m_conf->writeFile(m_fileName.c_str()); + } + catch (FileIOException &e) + { + throw GameException("The configuration file cannot be written (" + + m_fileName + ")"); + } +#endif } void Settings::setBool(const string &iName, bool iValue) { - m_boolHandler.setOption(iName, iValue); + setValue(iName, iValue); } bool Settings::getBool(const string &iName) const { - return m_boolHandler.getOption(iName); +#ifdef HAVE_LIBCONFIG + try + { + return m_conf->lookup(iName); + } + catch (SettingNotFoundException &e) + { + throw GameException("No such option: " + iName); + } +#else + // Dummy implementation + return true; +#endif } void Settings::setInt(const string &iName, int iValue) { - m_intHandler.setOption(iName, iValue); + setValue(iName, iValue); } int Settings::getInt(const string &iName) const { - return m_intHandler.getOption(iName); -} - - -template -void Settings::OptionsHandler::addOption(const string &iName, const T &iValue) -{ - m_options[iName] = iValue; -} - - -template -void Settings::OptionsHandler::setOption(const string &iName, const T &iValue) -{ - typename map::iterator it = m_options.find(iName); - if (it == m_options.end()) +#ifdef HAVE_LIBCONFIG + try + { + return m_conf->lookup(iName); + } + catch (SettingNotFoundException &e) { throw GameException("No such option: " + iName); } - it->second = iValue; +#else + // Dummy implementation + if (iName == "duplicate.solo-players") + return 16; + else if (iName == "duplicate.solo-bonus") + return 10; + return 0; +#endif } -template -const T& Settings::OptionsHandler::getOption(const string &iName) const +template +void Settings::setValue(const string &iName, T iValue) { - typename map::const_iterator it = m_options.find(iName); - if (it == m_options.end()) +#ifdef HAVE_LIBCONFIG + try + { + m_conf->lookup(iName) = iValue; + } + catch (SettingNotFoundException &e) { throw GameException("No such option: " + iName); } - return it->second; +#endif } diff --git a/game/settings.h b/game/settings.h index 1032317..ccea891 100644 --- a/game/settings.h +++ b/game/settings.h @@ -27,18 +27,20 @@ using std::string; using std::map; +namespace libconfig +{ + class Config; +} + /** * This class centralizes the various configuration options of Eliot. * It implements the Singleton pattern. * * Currently, there are few settings, and their initial value is hard-coded. - * In a later phase, this class will be able to export/import settings - * to/from a configuration file, and it should be possible to override - * configuration settings with settings given on the command-line (TODO). - * The boost::program_options library could be useful for this. - * - * This class will also be helpful for the "Settings" dialog box of the GUI. + * It is possible to load/save the settings from/to a configuration file. + * In a later phase, it should be possible to override configuration + * settings with settings given on the command-line (TODO). */ class Settings { @@ -48,6 +50,11 @@ public: /// Destroy the singleton cleanly static void Destroy(); + ~Settings(); + + /// Save the current value of the settinfs to a configuration file + void save() const; + void setBool(const string &iName, bool iValue); bool getBool(const string &iName) const; @@ -56,47 +63,17 @@ public: private: - /** - * This nested class is simply there to handle storage and retrieval - * for options of a particular type (and factorize code) - */ - template - class OptionsHandler - { - public: - /// Set the value of an option - /** - * If the option already exists, its value is replaced, - * otherwise the option is created - */ - void addOption(const string &iName, const T &iValue); - - /** - * Change the value of an existing option. - * An exception is thrown if the option doesn't exist yet - */ - void setOption(const string &iName, const T &iValue); - - /** - * Query the value of an option. - * An exception is thrown if the option doesn't exist - */ - const T& getOption(const string &iName) const; - - private: - map m_options; - }; - - /// Singleton instance static Settings *m_instance; Settings(); - /// The settings can be of various types - OptionsHandler m_boolHandler; - OptionsHandler m_intHandler; - // Add types as needed... + /// Name of the file used to store the settings + string m_fileName; + libconfig::Config *m_conf; + + template + void setValue(const string &iName, T iValue); }; #endif diff --git a/qt/Makefile.am b/qt/Makefile.am index c473f7e..f400486 100644 --- a/qt/Makefile.am +++ b/qt/Makefile.am @@ -76,7 +76,7 @@ eliot_SOURCES = \ main.cpp eliot_SOURCES += $(BUILT_SOURCES) -eliot_LDADD = @QT_LIBS@ ../game/libgame.a ../dic/libdic.a @LIBINTL@ +eliot_LDADD = ../game/libgame.a ../dic/libdic.a @QT_LIBS@ @LIBINTL@ @LIBCONFIG_LIBS@ # Generate a cpp file from the resources resources.cpp: eliot.qrc $(RESOURCES) @@ -104,12 +104,13 @@ BUILT_SOURCES += win32icon.rc eliot_SOURCES += win32icon.rc eliot_LDADD += win32icon.o -win32icon.rc: images/eliot.ico - echo "IDI_ICON1 ICON DISCARDABLE \"$(top_srcdir)/qt/images/eliot.ico\"" > $@ - win32icon.o: win32icon.rc i586-mingw32msvc-windres -o $@ -i $< endif +# This target is out of the conditional, so that make distcheck is happy +win32icon.rc: images/eliot.ico + echo "IDI_ICON1 ICON DISCARDABLE \"$(top_srcdir)/qt/images/eliot.ico\"" > $@ + endif diff --git a/qt/prefs_dialog.cpp b/qt/prefs_dialog.cpp index 5e5155e..f1f2eb7 100644 --- a/qt/prefs_dialog.cpp +++ b/qt/prefs_dialog.cpp @@ -46,9 +46,9 @@ PrefsDialog::PrefsDialog(QWidget *iParent) 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")); + 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) { @@ -57,7 +57,7 @@ PrefsDialog::PrefsDialog(QWidget *iParent) } // Freegame settings - checkBoxFreeRefuseInvalid->setChecked(Settings::Instance().getBool("freegame-reject-invalid")); + checkBoxFreeRefuseInvalid->setChecked(Settings::Instance().getBool("freegame.reject-invalid")); // Training settings // XXX: Hide them until there is something to show @@ -71,6 +71,15 @@ PrefsDialog::PrefsDialog(QWidget *iParent) void PrefsDialog::accept() { updateSettings(); + try + { + Settings::Instance().save(); + } + catch (GameException &e) + { + QMessageBox::warning(this, _q("%1 error").arg(PACKAGE_NAME), + _q("Cannot save the preferences: %1").arg(e.what())); + } QDialog::accept(); } @@ -92,15 +101,15 @@ void PrefsDialog::updateSettings() qs.setValue(kINTF_DIC_PATH, lineEditIntfDicPath->text()); // Duplicate settings - Settings::Instance().setBool("duplicate-reject-invalid", + Settings::Instance().setBool("duplicate.reject-invalid", checkBoxDuplRefuseInvalid->isChecked()); - Settings::Instance().setInt("duplicate-solo-players", + Settings::Instance().setInt("duplicate.solo-players", spinBoxDuplSoloPlayers->value()); - Settings::Instance().setInt("duplicate-solo-value", + Settings::Instance().setInt("duplicate.solo-value", spinBoxDuplSoloValue->value()); // Freegame settings - Settings::Instance().setBool("freegame-reject-invalid", + Settings::Instance().setBool("freegame.reject-invalid", checkBoxFreeRefuseInvalid->isChecked()); // Training settings diff --git a/qt/qtcommon.h b/qt/qtcommon.h index f217009..6a9ad2f 100644 --- a/qt/qtcommon.h +++ b/qt/qtcommon.h @@ -53,6 +53,6 @@ #define _q(s) qfl(_(s)) // Used for QSettings -#define ORGANIZATION "Eliot" +#define ORGANIZATION "eliot" #endif diff --git a/utils/Makefile.am b/utils/Makefile.am index 54f2320..4f62b99 100644 --- a/utils/Makefile.am +++ b/utils/Makefile.am @@ -25,7 +25,7 @@ bin_PROGRAMS = if BUILD_TEXT noinst_PROGRAMS += eliottxt eliottxt_SOURCES = game_io.h game_io.cpp eliottxt.cpp -eliottxt_LDADD = $(top_builddir)/game/libgame.a $(top_builddir)/dic/libdic.a @LIBINTL@ +eliottxt_LDADD = $(top_builddir)/game/libgame.a $(top_builddir)/dic/libdic.a @LIBINTL@ @LIBCONFIG_LIBS@ if HAS_READLINE eliottxt_LDADD += -lreadline endif @@ -34,6 +34,6 @@ endif if BUILD_NCURSES bin_PROGRAMS += eliotcurses eliotcurses_SOURCES = ncurses.cpp ncurses.h -eliotcurses_LDADD = ../game/libgame.a ../dic/libdic.a -lncursesw @LIBINTL@ +eliotcurses_LDADD = ../game/libgame.a ../dic/libdic.a -lncursesw @LIBINTL@ @LIBCONFIG_LIBS@ endif diff --git a/wxwin/Makefile.am b/wxwin/Makefile.am index a04860e..8ec114f 100644 --- a/wxwin/Makefile.am +++ b/wxwin/Makefile.am @@ -36,7 +36,7 @@ wxeliot_SOURCES = \ mainframe.cc mainframe.h \ main.cc ewx.h -wxeliot_LDADD = @WX_LIBS@ ../game/libgame.a ../dic/libdic.a @LIBINTL@ +wxeliot_LDADD = @WX_LIBS@ ../game/libgame.a ../dic/libdic.a @LIBINTL@ @LIBCONFIG_LIBS@ EXTRA_DIST = \ eliot.xpm \