Commits

billforsternz committed 5c31cf0

V2.01a maintenance release

Bug fixes;
-UCI "quit" command now proceeded by "stop", "isready" if engine was thinking.
(this is good practice in general and Houdini in particular would sometimes
ignore the "quit" command because of this problem)
-Directory selection for engine selection and document selection decoupled.
-Keyboard (not just mouse) selection of disjoint games in games dialogs now
works ok.
-Restore to factory defaults now refreshs font, engine, language changes.
-The 3rd and 4th Custom UCI parameters now work properly (thank you Ralph
Moritz).
-For completeness I will also note here a small bug sometimes affecting 4th
line of kibitz text. This bug was present in V2.00a but fixed for V2.00b (the
Komodo edition). So, this bug was fixed just before starting this repository.

New features;
-Ctrl-A now selects all in games dialogs.
-New button to save clipboard or session to a file.

Comments (0)

Files changed (14)

 
 #include "wx/wx.h"
 
-#define MASTER_VERSION "V2.00 working"
+#define MASTER_VERSION "V2.01a working"
+#define DEFAULT_ENGINE "Rybka v2.3.2a.mp.w32.exe"
+// #define MASTER_VERSION "V2.01ak"         // for Komodo version
+// #define DEFAULT_ENGINE "komodo3-32.exe"  // for Komodo version
 
 // Misc
 #define NBR_KIBITZ_LINES 4

src/CentralWorkSaver.cpp

 #include "DebugPrintf.h"
 #include "Session.h"
 #include "Log.h"
+#include "Repository.h"
 #include "Objects.h"
 #include "GameDetailsDialog.h"
 #include "GameLogic.h"
                 }
                 else
                 {
-                    std::string filename;
                     ok = false;
-                    wxFileDialog fd( objs.frame, "Create new .pgn file, or append games to existing .pgn file", "", "", "*.pgn", wxFD_SAVE|wxFD_CHANGE_DIR );
+                    wxFileDialog fd( objs.frame, "Create new .pgn file, or append games to existing .pgn file", "", "", "*.pgn", wxFD_SAVE ); //|wxFD_CHANGE_DIR );
+                    wxString dir = objs.repository->nv.m_doc_dir;
+                    fd.SetDirectory(dir);
                     int answer = fd.ShowModal();
                     if( answer == wxID_CANCEL )
                         any_cancel = true;
                     if( answer == wxID_OK)
                     {
-                        filename = fd.GetPath();
-                        wxString wx_filename = filename.c_str();
+                        wxString dir;
+                        wxFileName::SplitPath( fd.GetPath(), &dir, NULL, NULL );
+                        objs.repository->nv.m_doc_dir = dir;
+                        wxString wx_filename = fd.GetPath();
+                        std::string filename = wx_filename.c_str();
                         if( !::wxFileExists(wx_filename ) )
                         {
                             if( fm == FILE_EXISTS_GAME_NEW )
                             if( !gc->Load(filename) )
                             {
                                 wxString msg="Cannot append to existing file ";
-
                                 msg += wx_filename;
                                 wxMessageBox( msg, "Error reading file", wxOK|wxICON_ERROR );
                                 gc->gds = gds;
 
             case FILE_NEW_GAME_NEW:
             {
-                std::string filename;
                 ok = false;
-                wxFileDialog fd( objs.frame, "Save either to a new or existing .pgn file", "", "", "*.pgn", wxFD_SAVE|wxFD_CHANGE_DIR );
+                wxFileDialog fd( objs.frame, "Save either to a new or existing .pgn file", "", "", "*.pgn", wxFD_SAVE ); //|wxFD_CHANGE_DIR );
+                wxString dir = objs.repository->nv.m_doc_dir;
+                fd.SetDirectory(dir);
                 int answer = fd.ShowModal();
                 if( answer == wxID_CANCEL )
                     any_cancel = true;
                 if( answer == wxID_OK)
                 {
+                    wxString dir;
+                    wxFileName::SplitPath( fd.GetPath(), &dir, NULL, NULL );
+                    objs.repository->nv.m_doc_dir = dir;
                     gd->game_nbr = 0;
-                    std::string filename = fd.GetPath();
-                    wxString wx_filename = filename.c_str();
+                    wxString wx_filename = fd.GetPath();
+                    std::string filename = wx_filename.c_str();
 
                     // If it's a new file, create with single game
                     if( !::wxFileExists( wx_filename ) )

src/EngineDialog.cpp

     wxString path = dat.m_file;
     wxFilePickerCtrl *picker = new wxFilePickerCtrl( this, ID_ENGINE_PICKER, path, wxT("Select UCI Engine"),
         "*.exe", wxDefaultPosition, wxDefaultSize, 
-        wxFLP_USE_TEXTCTRL|wxFLP_OPEN|wxFLP_FILE_MUST_EXIST|wxFLP_CHANGE_DIR );    
+        wxFLP_USE_TEXTCTRL|wxFLP_OPEN|wxFLP_FILE_MUST_EXIST ); //|wxFLP_CHANGE_DIR );    
     box_sizer->Add(picker, 1, wxALIGN_LEFT|wxEXPAND|wxLEFT|wxBOTTOM|wxRIGHT, 5);
 
     // Ponder enabled

src/GameDocument.h

         current_game    = src.current_game; 
         pgn_handle      = src.pgn_handle;
         sort_idx        = src.sort_idx;
-        focus           = src.focus;
+        focus           = false; //src.focus;
         selected        = src.selected;
         game_nbr        = src.game_nbr;
         white           = src.white;          

src/GameLogic.cpp

     Atomic begin;
     if( objs.cws->FileOpen() )
     {
-        wxFileDialog fd( objs.frame, "Select .pgn file", "", "", "*.pgn", wxFD_FILE_MUST_EXIST|wxFD_CHANGE_DIR );
-        if( gc.pgn_filename != "" )
-        {
-            wxString filename = gc.pgn_filename.c_str();
-            wxString dir;
-            wxFileName::SplitPath( filename, &dir, NULL, NULL );
-            fd.SetDirectory(dir);
-        }
+        wxFileDialog fd( objs.frame, "Select .pgn file", "", "", "*.pgn", wxFD_FILE_MUST_EXIST );//|wxFD_CHANGE_DIR );
+        wxString dir = objs.repository->nv.m_doc_dir;
+        fd.SetDirectory(dir);
         if( wxID_OK == fd.ShowModal() )
         {
-            string filename = fd.GetPath();
+            wxString dir;
+            wxFileName::SplitPath( fd.GetPath(), &dir, NULL, NULL );
+            objs.repository->nv.m_doc_dir = dir;
+            wxString wx_filename = fd.GetPath();
+            std::string filename = wx_filename.c_str();
             CmdFileOpenInner( filename );
         }
     }

src/GamesCache.cpp

     }
 }
 
+// Save all as a new file
+void GamesCache::FileSaveAllAsAFile( std::string &filename )
+{
+    renumber = true;   // save session or clipboard in order files are listed
+    FILE *pgn_out = objs.gl->pf.OpenCreate( filename, pgn_handle );
+    if( pgn_out )
+    {
+        FileSaveInner( NULL, NULL, pgn_out );
+        objs.gl->pf.Close(NULL);    // close all handles (gc_clipboard
+                                    //  only needed for ReopenModify())
+    }
+}
+
 // Save common
 void GamesCache::FileSaveInner( GamesCache *gc_clipboard, FILE *pgn_in, FILE *pgn_out )
 {
     bool FileCreate( std::string &filename, GameDocument &gd );
     void FileSave( GamesCache *gc_clipboard );
     void FileSaveAs( std::string &filename, GamesCache *gc_clipboard );
+    void FileSaveAllAsAFile( std::string &filename );
     void FileSaveInner( GamesCache *gc_clipboard, FILE *pgn_in, FILE *pgn_out );
     bool IsLoaded();
     bool IsSynced();

src/PgnDialog.cpp

     EVT_BUTTON( wxID_OK,                PgnDialog::OnOkClick )
     EVT_BUTTON( wxID_CANCEL,            PgnDialog::OnCancel )
     EVT_BUTTON( ID_BOARD2GAME,          PgnDialog::OnBoard2Game )
-    EVT_CHECKBOX( ID_REORDER,             PgnDialog::OnRenumber )
+    EVT_CHECKBOX( ID_REORDER,           PgnDialog::OnRenumber )
     EVT_BUTTON( ID_ADD_TO_CLIPBOARD,    PgnDialog::OnAddToClipboard )
+    EVT_BUTTON( ID_SAVE_ALL_TO_A_FILE,  PgnDialog::OnSaveAllToAFile )
     EVT_BUTTON( ID_PGN_DIALOG_GAME_DETAILS,   PgnDialog::OnEditGameDetails )
     EVT_BUTTON( wxID_COPY,              PgnDialog::OnCopy )
     EVT_BUTTON( wxID_CUT,               PgnDialog::OnCut )
     EVT_BUTTON( wxID_PASTE,             PgnDialog::OnPaste )
     EVT_BUTTON( wxID_SAVE,              PgnDialog::OnSave )
     EVT_BUTTON( wxID_HELP,              PgnDialog::OnHelpClick )
+    EVT_MENU( wxID_SELECTALL, PgnDialog::OnSelectAll )
     EVT_LIST_ITEM_ACTIVATED(ID_PGN_LISTBOX, PgnDialog::OnListSelected)
     EVT_LIST_COL_CLICK(ID_PGN_LISTBOX, PgnDialog::OnListColClick)
 END_EVENT_TABLE()
 {
     list_ctrl = NULL;
     selected_game = NULL;
-    wxAcceleratorEntry entries[4];
+    wxAcceleratorEntry entries[5];
     entries[0].Set(wxACCEL_CTRL,  (int) 'X',     wxID_CUT);
     entries[1].Set(wxACCEL_CTRL,  (int) 'C',     wxID_COPY);
     entries[2].Set(wxACCEL_CTRL,  (int) 'V',     wxID_PASTE);
-    entries[3].Set(wxACCEL_NORMAL,  WXK_DELETE,  wxID_DELETE);
+    entries[3].Set(wxACCEL_CTRL,  (int) 'A',     wxID_SELECTALL);
+    entries[4].Set(wxACCEL_NORMAL,  WXK_DELETE,  wxID_DELETE);
     wxAcceleratorTable accel(4, entries);
     SetAcceleratorTable(accel);
 }
         button_box1->Add(paste, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
     }
 
+    // Save all games to a file
+    if( id==ID_PGN_DIALOG_CLIPBOARD||id==ID_PGN_DIALOG_SESSION )
+    {
+        wxButton* save_all_to_a_file = new wxButton ( this, ID_SAVE_ALL_TO_A_FILE, wxT("Save all to a file"),
+            wxDefaultPosition, wxDefaultSize, 0 );
+        button_box1->Add(save_all_to_a_file, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    }
+
     // Renumber
     if( id==ID_PGN_DIALOG_FILE )
     {
                 gc->gds[i].selected = true;
             if( wxLIST_STATE_FOCUSED & list_ctrl->GetItemState(i,wxLIST_STATE_FOCUSED) )
                 gc->gds[i].focus = true;
+            else
+                gc->gds[i].focus = false;
         }
         GameDocument *gd = GetFocusGame(file_game_idx);
         if( gd )
     }
 }
 
+void PgnDialog::OnSelectAll( wxCommandEvent& WXUNUSED(event) )
+{
+    int gds_nbr = gc->gds.size();
+    for( int i=0; i<gds_nbr; i++ )    
+        list_ctrl->SetItemState( i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED );
+}
+
 void PgnDialog::OnEditGameDetails( wxCommandEvent& WXUNUSED(event) )
 {
     int idx;
     }
 }
 
+void PgnDialog::OnSaveAllToAFile( wxCommandEvent& WXUNUSED(event) )
+{
+    wxFileDialog fd( objs.frame, "Save all listed games to a new .pgn file", "", "", "*.pgn", wxFD_SAVE|wxFD_OVERWRITE_PROMPT );
+    wxString dir = objs.repository->nv.m_doc_dir;
+    fd.SetDirectory(dir);
+    int answer = fd.ShowModal();
+    if( answer == wxID_OK )
+    {
+        wxString dir;
+        wxFileName::SplitPath( fd.GetPath(), &dir, NULL, NULL );
+        objs.repository->nv.m_doc_dir = dir;
+        wxString wx_filename = fd.GetPath();
+        std::string filename = wx_filename.c_str();
+        gc->FileSaveAllAsAFile( filename );
+    }
+}
+
 void PgnDialog::OnAddToClipboard( wxCommandEvent& WXUNUSED(event) )
 {
     CopyOrAdd( false );
     ID_BOARD2GAME           = 10003,
     ID_PGN_DIALOG_GAME_DETAILS  = 10004,
     ID_REORDER              = 10005,
-    ID_ADD_TO_CLIPBOARD     = 10006
+    ID_ADD_TO_CLIPBOARD     = 10006,
+    ID_SAVE_ALL_TO_A_FILE   = 10007
 };
 
 // PgnDialog class declaration
 
     void OnBoard2Game( wxCommandEvent& event );
     void OnRenumber( wxCommandEvent& event );
+    void OnSelectAll( wxCommandEvent& event );
     void OnEditGameDetails( wxCommandEvent& event );
     void OnCopy( wxCommandEvent& event );
     void OnAddToClipboard( wxCommandEvent& event );
+    void OnSaveAllToAFile( wxCommandEvent& event );
     void OnCut( wxCommandEvent& event );
     void OnDelete( wxCommandEvent& event );
     void OnPaste( wxCommandEvent& event );

src/Repository.cpp

 Repository::Repository( bool use_defaults )
 {
     SetDirectories();
+    nv.m_doc_dir  = doc_dir;
     book.m_file   = doc_dir + "\\" + book.m_file;
     log.m_file    = doc_dir + "\\" + log.m_file;
     engine.m_file = exe_dir + "\\Engines\\" + engine.m_file;
         config->Read("NonVolatileCol8",                   &nv.m_col8 );
         config->Read("NonVolatileCol9",                   &nv.m_col9 );
         config->Read("NonVolatileCol10",                  &nv.m_col10 );
+        config->Read("NonVolatileDocDir",                 &nv.m_doc_dir );
     }
 }
 
     config->Write("NonVolatileCol8",                  nv.m_col8 );
     config->Write("NonVolatileCol9",                  nv.m_col9 );
     config->Write("NonVolatileCol10",                 nv.m_col10 );
+    config->Write("NonVolatileDocDir",                nv.m_doc_dir );
 
     // Engine
     config->Write("EngineExeFile",      engine.m_file   );
 
     // Defaults to use in case of error
     wxString name = "Tarrasch";
-    exe_dir = "C:\\Program Files\\Tarrasch";
+    exe_dir = "C:\\Program Files (x86)\\Tarrasch";
 
     // Find directories we plan to use
     wxString doc = stdp.GetDocumentsDir();              // eg "C:\Documents and Settings\Bill\My Documents"
  ****************************************************************************/
 #ifndef REPOSITORY_H
 #define REPOSITORY_H
+#include "Appdefs.h"
 #include "wx/wx.h"
 #include "wx/utils.h"
 #ifdef __VISUALC__
     wxString    m_custom4b;
     EngineConfig()
     {
-        m_file           = "komodo3-32.exe";
+        m_file           = DEFAULT_ENGINE;
         m_ponder         = false;
         m_hash           = 64;
         m_max_cpu_cores  = 1;
     int         m_col8;
     int         m_col9;
     int         m_col10;
+    wxString    m_doc_dir;
     NonVolatile()
     {
         m_x = -1;
         m_col8 = -1;
         m_col9 = -1;
         m_col10 = -1;
+        m_doc_dir = "";
     }
 };
 
 
 Rybka::Stop()
     notes: busy waits for process not running (protection against loop forever), is slow, needs okay
-    ? -> SEND_QUIT -> WAIT_FINISHED
-         (quit)
+    ? -> SEND_QUIT_1 -> SEND_QUIT_2             -> WAIT_FINISHED
+         (tx:stop)      (tx:isready,rx:readyok)    (tx:quit)
+         [stop is optional - only after go infinite/go ponder or if start state is WAIT_EVALUATION]
 
 Rybka::StartThinking()
     notes: kicks off go command, two versions (with/without smoves), needs okay, for playing against engine
     ? -> SEND_PLAY_ENGINE1 -> SEND_PLAY_ENGINE2  -> SEND_PLAY_ENGINE3 -> SEND_PLAY_ENGINE4 -> WAIT_EVALUATION -> READY
          (tx:stop)            (tx:options)          (tx:position)        (:go)                (rx:bestmove)
-         [optional - only after go infinite/go ponder]
+         [stop is optional - only after go infinite/go ponder]
 
 Rybka::Kibitz()
     notes: kicks off go infinite command,  never sends smoves, needs okay
     ? -> SEND_KIBITZ1 -> SEND_KIBITZ2  -> SEND_KIBITZ3 -> SEND_KIBITZ4 -> KIBITZING
          (tx:stop)       (tx:MultiPV)     (tx:position)   (tx:go infinite)
-         [optional - only after go infinite/go ponder]
+         [stop is optional - only after go infinite/go ponder]
 
 Rybka::KibitzStop()
     notes: needs okay, does one Run() immediately
     ? -> SEND_KIBITZ_STOP -> READY
          (tx:stop)
-         [optional - only after go infinite]
+         [stop is optional - only after go infinite]
 
 WAIT_EVALUATION state
     notes: info -> kq_engine_to_move
 static HANDLE ghJob;
 static JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli;
 
+// Doing this "JobObject" stuff is useful because it means that any processes started by
+//  Tarrasch are terminated when Tarrasch terminates - avoids the possibility of zombie
+//  engine processes still running once Tarrasch exits.
 extern void JobBegin()
 {
     ghJob = CreateJobObject( NULL, NULL /*"The Tarrasch Chess GUI Job Object"*/ ); // GLOBAL
                 break;
             unsigned long now_time = GetTickCount();	
             unsigned long elapsed_time = now_time-base_time;
-            if( elapsed_time > 20000 )   // change 5 seconds to 20
+            if( elapsed_time > 20000 )   // 20 seconds
             {
                 okay = false;
                 break;
     else
     {
         DebugPrintf(( "Stop: okay\n" ));
-        NewState( "Stop()", SEND_QUIT );
+        if( gbl_state == WAIT_EVALUATION )
+            last_command_was_go_infinite = true;    // usually only send stop if go infinite, but here if waiting
+                                                    //  for engine to move, also need to send stop
+        NewState( "Stop()", SEND_QUIT_1 );
         unsigned long base_time = GetTickCount();	
+        unsigned long elapsed_time_changed=0;
+        bool first=true;
         for( unsigned long i=0; true /*i<10000*/; i++ )
         {
             bool running = Run();
-            if( !running )
-            {
-                DebugPrintf(( "Stop: not running %lu\n", i ));
-                break;
-            }
             unsigned long now_time = GetTickCount();	
             unsigned long elapsed_time = now_time-base_time;
-            if( elapsed_time > 20000 )   // change 5 seconds to 20
+            if( first || elapsed_time!=elapsed_time_changed )
+                DebugPrintfInner( "Waiting for engine to die: running=%s, elapsed_time=%lu, loops=%lu\n", running?"true":"false", elapsed_time, i );
+            elapsed_time_changed = elapsed_time;
+            first = false;
+            if( !running )
+                break;
+            if( elapsed_time > 20000 )   // 20 seconds
                 break;
             Sleep(0);    
         }
             readyok_basetime = GetTickCount();
             break;
         }
+        case SEND_ISREADY_Q:    // send isready before quit
+        {
+            s = "isready";
+            NewState( "user_hook_in()", WAIT_READYOK_Q );
+            readyok_basetime = GetTickCount();
+            break;
+        }
         case WAIT_READYOK_P:
         case WAIT_READYOK_K:
+        case WAIT_READYOK_Q:
         {
             s = NULL;
             unsigned long now_time = GetTickCount();
-            if( now_time-readyok_basetime > 10000 )     // change 2 seconds to 10
+            if( now_time-readyok_basetime > 10000 )     // 10 seconds
                 NewState( "timeout", readyok_next_state );
             break;
         }
                             {
                                 custom3_first = false;
                                 found_something_to_send = true;
-                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom2a.c_str(), rep->m_custom3b.c_str() );
+                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom3a.c_str(), rep->m_custom3b.c_str() );
                             }
                         }
                         break;
                             {
                                 custom4_first = false;
                                 found_something_to_send = true;
-                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom2a.c_str(), rep->m_custom4b.c_str() );
+                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom4a.c_str(), rep->m_custom4b.c_str() );
                             }
                         }
                         break;
                             {
                                 custom3_first = false;
                                 found_something_to_send = true;
-                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom2a.c_str(), rep->m_custom3b.c_str() );
+                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom3a.c_str(), rep->m_custom3b.c_str() );
                             }
                         }
                         break;
                             {
                                 custom4_first = false;
                                 found_something_to_send = true;
-                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom2a.c_str(), rep->m_custom4b.c_str() );
+                                sprintf( option_buf, "setoption name %s value %s", rep->m_custom4a.c_str(), rep->m_custom4b.c_str() );
                             }
                         }
                         break;
             NewState( "user_hook_in()", KIBITZING );
             break;
         }
-        case SEND_QUIT:
+        case SEND_QUIT_1:
+        {
+            s = NULL;
+            if( last_command_was_go_infinite )
+                s = "stop";
+            NewState( "user_hook_in()", SEND_ISREADY_Q );
+            readyok_next_state = SEND_QUIT_2;
+            break;
+        }
+        case SEND_QUIT_2:
         {
             s = "quit";
             NewState( "user_hook_in()", WAIT_FINISHED );
     {
         case WAIT_READYOK_P:
         case WAIT_READYOK_K:
+        case WAIT_READYOK_Q:
         {
             if( str_pattern(s,"readyok",false) )
                 NewState( "readyok received", readyok_next_state );
                                     break;
             case WAIT_EVALUATION:   s = "WAIT_EVALUATION";
                                     break;
-            case SEND_QUIT:         s = "SEND_QUIT";
+            case SEND_QUIT_1:       s = "SEND_QUIT_1";
+                                    break;
+            case SEND_QUIT_2:       s = "SEND_QUIT_2";
                                     break;
             case WAIT_FINISHED:     s = "WAIT_FINISHED";
                                     break;
                                     break;
             case SEND_ISREADY_P:    s = "SEND_ISREADY_P";
                                     break;
+            case SEND_ISREADY_Q:    s = "SEND_ISREADY_Q";
+                                    break;
             case WAIT_READYOK_K:    s = "WAIT_READYOK_K";
                                     break;
             case WAIT_READYOK_P:    s = "WAIT_READYOK_P";
                                     break;
+            case WAIT_READYOK_Q:    s = "WAIT_READYOK_Q";
+                                    break;
             case SEND_FORCE_STOP:   s = "SEND_FORCE_STOP";
                                     break;
         }
         SEND_PLAY_ENGINE3,
         SEND_PLAY_ENGINE4,
         WAIT_EVALUATION,
-        SEND_QUIT,
+        SEND_QUIT_1,
+        SEND_QUIT_2,
         WAIT_FINISHED,
         SEND_KIBITZ1,
         SEND_KIBITZ2,
         SEND_KIBITZ_STOP,
         SEND_ISREADY_K,
         SEND_ISREADY_P,
+        SEND_ISREADY_Q,
         WAIT_READYOK_K,
         WAIT_READYOK_P,
+        WAIT_READYOK_Q,
         SEND_FORCE_STOP
     };
     RYBKA_STATE gbl_state;
         void OnUpdateTraining(wxUpdateUIEvent &);
     void OnGeneral    (wxCommandEvent &);
         void OnUpdateGeneral (wxUpdateUIEvent &);
+    void RefreshLanguageFont( const char *from, bool before_large_font, bool before_no_italics,
+                              const char *to,   bool after_large_font,  bool after_no_italics );
 
     void OnFileNew (wxCommandEvent &);
         void OnUpdateFileNew( wxUpdateUIEvent &);
         "computing standard) either as an opponent, or to provide "
         "expert commentary."
         "\n\n"
-        "By default Tarrasch uses the Rybka demo engine. Other "
+        "The Tarrasch package includes one or more engines and one of "
+        "these engines is used by default. Other "
         "engines can be separately purchased or downloaded. Use menu "
         "\"Options\" to select an alternative engine if you have one. "
         "You can start a game with the engine at any time, in any "
     bool     old_enabled = objs.repository->book.m_enabled;
     wxString old_file    = objs.repository->book.m_file;
     wxString old_engine_file  = objs.repository->engine.m_file;
+    const char *from = LangCheckDiffBegin();
+    bool before_large_font = objs.repository->general.m_large_font;
+    bool before_no_italics = objs.repository->general.m_no_italics;
     delete objs.repository;
     objs.repository = new Repository(true);
+    LangSet( objs.repository->general.m_notation_language );
     if( objs.repository->engine.m_file != old_engine_file )
         ingame = objs.gl->EngineChanged();
     if( objs.repository->book.m_enabled != old_enabled ||
             objs.canvas->BookUpdate( false );
         }
     }
-    objs.gl->Refresh();
     if( ingame )
     {
         objs.gl->chess_clock.Clocks2Repository();
     else
         objs.gl->chess_clock.Repository2Clocks();
     canvas->RedrawClocks();
+    const char *to = LangCheckDiffEnd();
+    bool after_large_font = objs.repository->general.m_large_font;
+    bool after_no_italics = objs.repository->general.m_no_italics;
+    RefreshLanguageFont( from, before_large_font, before_no_italics,
+                           to,  after_large_font,  after_no_italics );
     SetFocusOnList();
 }
 
                                  dialog.dat.m_notation_language.c_str(),
                                  dialog.dat.m_no_italics,
                                  dialog.dat.m_straight_to_game ));
+        const char *to = LangCheckDiffEnd();
+        bool after_large_font = objs.repository->general.m_large_font;
+        bool after_no_italics = objs.repository->general.m_no_italics;
+        RefreshLanguageFont( from, before_large_font, before_no_italics,
+                             to,   after_large_font,  after_no_italics );
     }
-    const char *to = LangCheckDiffEnd();
-    bool after_large_font = objs.repository->general.m_large_font;
-    bool after_no_italics = objs.repository->general.m_no_italics;
+    SetFocusOnList();
+}
+
+void ChessFrame::RefreshLanguageFont( const char *from, bool before_large_font, bool before_no_italics,
+                                      const char *to,   bool after_large_font,  bool after_no_italics )
+{
     if( after_large_font != before_large_font )
         objs.gl->lb->SetLargeFont( after_large_font );
     bool redisplayed = false;
         objs.gl->gd.Redisplay(pos);
     }
     objs.gl->Refresh();
-    SetFocusOnList();
 }
 
-
 void ChessFrame::OnUpdateGeneral(wxUpdateUIEvent &event )
 {
     bool enabled = objs.gl->UpdateOptions();