/*
Program WinCaml: Graphical User Interface
for interactive use of Caml-Light and Ocaml.
Copyright (C) 2005-2015 Jean Mouric 35700 Rennes France
email: jean.mouric@orange.fr

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 3 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, see <http://www.gnu.org/licenses/>.
*/

// File wx/wxw.cpp

#include "wxw.h"
#include "../wx/resources/res.h"
#include "wx/wx.h"
#include "wx/dnd.h"
#include "wx/msgdlg.h"
#include "wx/colordlg.h"
#include "wx/fontdlg.h"
#include "wx/file.h"
#include "wx/print.h"
#include "wx/printdlg.h"
#include <fstream>
#include <sstream>
#ifndef __WXMSW__
#include <unistd.h>
#endif

static deque<wxMenuItem*>* menuItems;
static wxMenuBar* appMenuBar;
static CRichEdit* searchEdit;
static CFindDialog* findDlg;
static CFindReplaceDialog* findReplaceDlg;
CMDIFrame* mainFrame;
const bool liveSplit = true;

static unsigned char* convert1(const wchar_t *s);
string convert(const wstring& str);
bool getConfigFolderPath(wstring& path);
wstring fromBytes(const string& str);
void removeFileMenuItem(int menuID);
void insertFileMenuItem(int menuID, const wstring& menuTitle);
void insertFileMenuSeparator();
void removeFileMenuSeparator();
bool createDirectory(const wstring& dirPath);
void deleteFile(const wstring& fileName);
void doSleep(int n);
wstring fromLatin1(const string& str);
string fromUnicode(const wxString& wstr, int code);
wstring stringToWString(const string& str);
string toBytes(const wstring& wstr);
string toLatin1(const wstring& str);
wxString toUnicode(const string& str, int code);
wstring toUnicode(const string& str);
string wstringToString(const wstring& wstr);
void loadCursors();
void unloadCursors();

void loadCursors(){}
void unloadCursors(){}

#ifdef __WXMSW__
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow();
#else
#ifndef __WXMAC__
#include <csignal>
void signalHandler(int signum)
{
    wstring path;
    getConfigFolderPath(path);
    deleteFile(path + L"lockfile");
    exit(signum);
}
#endif
#endif

static unsigned char* convert1(const wchar_t *s)
{
	wchar_t* s1 = (wchar_t*)s;
	int i = 0;
	while (*s1++) i++;
    unsigned char*  s2 = (unsigned char*)malloc(i + 1);
	
	unsigned char* res = s2;
	s1 = (wchar_t*)s;
    while (*s1)
    {
		*s2++ = *s1++;
    }
	*s2 = '\0';
	s2 = res;
	while (*s2)
    { //replace bytes of multibyte utf-8 char by ascii char 'x'
		if ((*s2 >> 5) == 6 || ((*s2 >> 4) == 14))
        {
			*s2++ = 'x';
			while ((*s2 >> 6) == 2)
            {
				*s2++ = 'x';
			}
		}
		else
        {
			s2++;
		}
	}
    return res;
}

string convert(const wstring& str)
{
    char* s = (char*)convert1(str.c_str());
    string st = s;
    free(s);
    return st;
}

void aboutMessage(const wstring& msg)
{
    wxMessageBox(msg, "WinCaml");
}

int yesnocancelMessage(const wstring& msg)
{
    wxMessageDialog messageDialog(NULL, msg, "WinCaml", wxYES_NO | wxCANCEL | wxCENTER);
    messageDialog.SetYesNoCancelLabels("Oui", "Non", "Annuler");
    return messageDialog.ShowModal();
}

bool yesnoMessage(const wstring& msg)
{
    wxMessageDialog messageDialog(NULL, msg, "", wxYES_NO | wxCENTER);
    messageDialog.SetYesNoLabels("Oui", "Non");
    return (messageDialog.ShowModal() & wxYES) != 0;
}

void errorMessage(const wstring& msg)
{
    wxMessageDialog messageDialog(NULL, msg, "", wxOK | wxCENTER | wxICON_ERROR);
    messageDialog.ShowModal();
}

void findDialog()
{
    mainFrame->enableMenuItem(EDIT_REPLACE, true);
    if (findDlg && findDlg->isHidden())
    {
        if (findReplaceDlg && !findReplaceDlg->isHidden())
            findReplaceDlg->hide();
        findDlg->init();
        findDlg->show();
    }
    if (findDlg && !findDlg->isHidden()) findDlg->Raise();
    
}

void findReplaceDialog()
{
    mainFrame->enableMenuItem(EDIT_FIND, true);
    if (findReplaceDlg && findReplaceDlg->isHidden())
    {
        if (findDlg && !findDlg->isHidden())
            findDlg->hide();
        findReplaceDlg->init();
        findReplaceDlg->show();
    }
    if (findReplaceDlg && !findReplaceDlg->isHidden()) findReplaceDlg->Raise();
}

void setSearchEdit(CRichEdit* edit)
{
    searchEdit = edit;
}

void closeFindDialog(bool enableMenus)
{
    mainFrame->enableMenuItem(EDIT_FIND, enableMenus);
	mainFrame->enableMenuItem(EDIT_REPLACE, enableMenus);
    if (findDlg)
    {
        findDlg->hide();
    }
    if (findReplaceDlg)
    {
        findReplaceDlg->hide();
    }
}

static wxFontEncoding encodingCode(int encoding)
{
	if (encoding == ENCODING_UNIX || encoding == ENCODING_WIN)
    {
        return wxFONTENCODING_ISO8859_1;
    }
	if (encoding == ENCODING_MAC)
    {
        return wxFONTENCODING_MACROMAN;
    }
    return wxFONTENCODING_UTF8;
}

unsigned long rgb(int r, int g, int b)
{
    wxColour colour(r, g, b);
    return colour.GetRGB();
}

void doSleep(int n)
{
#ifndef __WXMSW__
    usleep(n * 1000);
#else
    ::Sleep(n);
#endif
    
}
string fromUnicode(const wxString& wxstr, int code)
{
    wxCSConv csconv(encodingCode(code));
    size_t dstLen = csconv.FromWChar(NULL, 0, wxstr.c_str());
    if (dstLen == wxCONV_FAILED) return "";
    char *dst = new char[dstLen];
    if (csconv.FromWChar(dst, dstLen, wxstr.c_str()) == wxCONV_FAILED) return "";
    string s(dst);
    delete[] dst;
    return s;
}

static wstring utf8ToWideChar(string str)
{
	if (str == "") return L"";
    wxCSConv csconv(wxFONTENCODING_UTF8);
    size_t dstLen = csconv.ToWChar(NULL, 0, str.c_str());
    if (dstLen == wxCONV_FAILED) return L"";
    wchar_t *dst = new wchar_t[dstLen];
    if (csconv.ToWChar(dst, dstLen, str.c_str()) == wxCONV_FAILED) return L"";
	wxString ret = wxString(dst);
    delete[] dst;
	return wstring(ret);
}

string toLatin1(const wstring& str)
{
	return fromUnicode(utf8ToWideChar(wstringToString(str)), ENCODING_UNIX);
}

static wxString latin1ToWideChar(string str)
{
    wxCSConv csconv(wxFONTENCODING_ISO8859_1);
    size_t dstLen = csconv.ToWChar(NULL, 0, str.c_str());
    if (dstLen == wxCONV_FAILED) return L"";
    wchar_t *dst = new wchar_t[dstLen];
    if (csconv.ToWChar(dst, dstLen, str.c_str()) == wxCONV_FAILED) return L"";
	wxString ret = wxString(dst);
    delete[] dst;
	return ret;
}

wstring fromLatin1(const string& str)
{
	return stringToWString(string(latin1ToWideChar(str).utf8_str()));
}

string toBytes(const wstring& wstr)
{
	return wxString(wstr).ToStdString();
}

#ifdef __WXGTK__
wchar_t macRomanToUnicode[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 196, 197, 199, 201, 209, 214, 220, 225, 224, 226, 228, 227, 229, 231, 233, 232, 234, 235, 237, 236, 238, 239, 241, 243, 242, 244, 246, 245, 250, 249, 251, 252, 8224, 176, 162, 163, 167, 8226, 182, 223, 174, 169, 8482, 180, 168, 8800, 198, 216, 8734, 177, 8804, 8805, 165, 181, 8706, 8721, 8719, 960, 8747, 170, 186, 937, 230, 248, 191, 161, 172, 8730, 402, 8776, 8710, 171, 187, 8230, 160, 192, 195, 213, 338, 339, 8211, 8212, 8220, 8221, 8216, 8217, 247, 9674, 255, 376, 8260, 8364, 8249, 8250, 64257, 64258, 8225, 183, 8218, 8222, 8240, 194, 202, 193, 203, 200, 205, 206, 207, 204, 211, 212, 63743, 210, 218, 219, 217, 305, 710, 732, 175, 728, 729, 730, 184, 733, 731, 711};
#endif

wxString toUnicode(const string& str, int code)
{
#ifdef __WXGTK__
	if (code == ENCODING_MAC)
	{
		wxString ret;
		for (size_t i = 0; i < str.length(); i++)
		{
            unsigned char n = str[i];
			ret += macRomanToUnicode[n];
		}
		return ret;
	}
#endif
	wxCSConv csconv(encodingCode(code));
    size_t dstLen = csconv.ToWChar(NULL, 0, str.c_str());
    if (dstLen == wxCONV_FAILED) return "";
    wchar_t *dst = new wchar_t[dstLen];
    if (csconv.ToWChar(dst, dstLen, str.c_str()) == wxCONV_FAILED) return "";
	wxString ret = wxString(dst);
    delete[] dst;
	return ret;
}

wstring toUnicode(const string& str)
{
	return wstring(latin1ToWideChar(str));
}

static int guessEncoding(string& data, int preferredEncoding)
{
    if (data.length() == 0) return preferredEncoding;
    size_t i;
    size_t j = 0;
    size_t k = 0;
    size_t l = 0;
    size_t m = 0;
    int enc;
    size_t len = data.length();
    for (i = 0; i < len; i++)
    {
        unsigned char c = data[i];
        if (j == 1)
        {
            j = 0;
			if ( c == 10) {k = 1;}
        }
		if (c == 13) j = 1;
        if (c > 127) m = 1;
		if (c > 223) {l = 1;}
    }
	::tuneEndOfLines(data);
	if (m == 0) enc = k == 0 ? preferredEncoding : ENCODING_WIN;
	else if (fromUnicode(toUnicode(data, ENCODING_UTF8), ENCODING_UTF8) == data) return ENCODING_UTF8;
	else if (k == 0 && l == 0) enc = ENCODING_MAC;
	else if (k == 1) enc = ENCODING_WIN;
	else enc = ENCODING_UNIX;
    return enc;
}

wstring fromBytes(const string& str)
{
	return wxString(str).ToStdWstring();
}

string wstringToString(const wstring& wstr)
{
	string s;
	for(size_t i = 0; i < wstr.length(); i++)
	{
		s += wstr[i];
	}
	return s;
}

wstring stringToWString(const string& str)
{
	wstring s;
	for(size_t i = 0; i < str.length(); i++)
	{
		s += str[i];
	}
	return s;
}

void removeFileMenuItem(int cmd)
{
    wxMenu * fileMenu = appMenuBar->GetMenu(0);
    if (fileMenu->FindItem(cmd - FILE_NEW + 1))
    {
        fileMenu->Remove(cmd - FILE_NEW + 1);
    }
}

void insertFileMenuItem(int cmd, const wstring& menuTitle)
{
    appMenuBar->GetMenu(0)->Insert(cmd - FILE_NEW + 2, menuItems->at(cmd - FILE_MRU1));
    menuItems->at(cmd - FILE_MRU1)->SetItemLabel(menuTitle);
}

void insertFileMenuSeparator()
{
    wxMenu* fileMenu = appMenuBar->GetMenu(0);
    wxMenuItem *item = fileMenu->FindItemByPosition(fileMenu->GetMenuItemCount() - 2);
    if (!item->IsSeparator())
    {
        fileMenu->Insert(fileMenu->GetMenuItemCount() - 1, new wxMenuItem());
    }
}

void removeFileMenuSeparator()
{
    wxMenu * fileMenu = appMenuBar->GetMenu(0);
    wxMenuItem *item1 = fileMenu->FindItemByPosition(fileMenu->GetMenuItemCount() - 3);
    wxMenuItem *item2 = fileMenu->FindItemByPosition(fileMenu->GetMenuItemCount() - 2);
    if (item1->IsSeparator())
    {
        fileMenu->Remove(item2);
        delete item2;
    }
}

bool createDirectory(const wstring& dirPath)
{
    if (wxDirExists(dirPath))
    {
        return true;
    }
    return wxMkdir(dirPath);
}

void deleteFile(const wstring& fileName)
{
    wxRemoveFile(fileName);
}

// Class CFileDropTarget  ---------------------------------------------------------------------------------------------

#ifdef __WXMAC__
bool CFileDropTarget::OnDropFiles(wxCoord, wxCoord, const wxArrayString& fileNames)
{
    size_t n = fileNames.GetCount();
    for (size_t i = 0; i < n; i++)
    {
        wstring s = fileNames.Item(i).ToStdWstring();
        string ss = fileNames.Item(i).ToStdString();
        mainFrame->droppedFiles->push_back(new wstring(s));
    }
    mainFrame->onDrop();
    return true;
}
#endif

// Class CToolBar  ----------------------------------------------------------------------------------------------------

#ifndef __WXMAC__
BEGIN_EVENT_TABLE(CToolBar, wxToolBar)
EVT_TOOL_ENTER(1, CToolBar::onToolEnter)
END_EVENT_TABLE()

void CToolBar::onToolEnter(wxCommandEvent&)
{
	CMDIChildFrame* activeChild = mainFrame->getActiveChild();
	if (activeChild)
	{
		mainFrame->setStatus(0, activeChild->textEdit->status());
	}
	else
	{
		mainFrame->setStatus(0, L"");
	}
}
#endif

// Class CMDIFrame  ----------------------------------------------------------------------------------------------------

BEGIN_EVENT_TABLE(CMDIFrame, wxMDIParentFrame)
EVT_ACTIVATE(CMDIFrame::activateEvent)
EVT_CLOSE(CMDIFrame::closeEvent)
EVT_MENU(wxID_EXIT,  CMDIFrame::OnQuit)
EVT_MENU(wxID_ABOUT, CMDIFrame::OnAbout)
EVT_MOVE(CMDIFrame::moveEvent)
EVT_SIZE(CMDIFrame::resizeEvent)
EVT_UPDATE_UI_RANGE(0, 200, CMDIFrame::updateWindowMenu)
#ifndef __WXMAC__
EVT_DROP_FILES(CMDIFrame::dropEvent)
EVT_TIMER(-1, CMDIFrame::onTimerAux)
EVT_MENU_HIGHLIGHT_ALL(CMDIFrame::highlightMenuEvent)
#endif
END_EVENT_TABLE()

#ifndef __WXMAC__
void CMDIFrame::highlightMenuEvent(wxMenuEvent&)
{
	CMDIChildFrame* activeChild = mainFrame->getActiveChild();
	if (activeChild)
	{
		mainFrame->setStatus(0, activeChild->textEdit->status());
	}
	else
	{
		mainFrame->setStatus(0, L"");
	}
}
#endif

wxPrintData* g_printData;
wxPageSetupDialogData* g_pageSetupData;

#ifndef __WXMAC__
CMDIFrame::CMDIFrame(): wxMDIParentFrame(NULL, wxID_ANY, "WinCaml", wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE |wxHSCROLL | wxVSCROLL | wxFRAME_NO_WINDOW_MENU)
#else
CMDIFrame::CMDIFrame(): wxMDIParentFrame(NULL, wxID_ANY, "WinCaml",  wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE  | wxFRAME_NO_WINDOW_MENU)
#endif
{
    mainFrame = this;
#ifdef __WXMSW__
    SetIcon(wxICON(WinCamlIcon));
#endif
    createMenus();
    createToolbar();
    createStatusbar();
    findDlg = NULL;
    findReplaceDlg = NULL;
    findDlg = new CFindDialog(this);
    findDlg->hide();
    findReplaceDlg = new CFindReplaceDialog(this);
    findReplaceDlg->hide();
    
    g_printData = new wxPrintData;
    g_printData->SetPaperId(wxPAPER_A4);
    g_pageSetupData = new wxPageSetupDialogData;
    (*g_pageSetupData) = *g_printData;
    
	droppedFiles = new deque<wstring*>();
#ifndef __WXMAC__
	DragAcceptFiles(true);
	startTimer();
#else
    CFileDropTarget* fileDropTarget = new CFileDropTarget;
    SetDropTarget(fileDropTarget);
#endif
}

void CMDIFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}

void CMDIFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{
    aboutMessage(appName + L" " + version1 + L", interface graphique interactive pour Caml-Light et OCaml\nCopyright (C) 2005 - 2015 Jean Mouric 35700 Rennes France");
}

#ifndef __WXMAC__
void CMDIFrame::startTimer()
{
    timer = new wxTimer(this);
    timer->Start(20);
}

void CMDIFrame::onTimerAux(wxTimerEvent&)
{
    onTimer();
}
void CMDIFrame::onTimer()
{
	wstring path;
    if (!getConfigFolderPath(path)) return;
    wstringstream format(wstringstream::in | wstringstream::out);
    format << path << 1;
    wstring s = format.str();
    fstream fs(toBytes(s).c_str(), fstream::in);
    if (!fs.fail())
    {
        fs.close();
        onOtherInstanceMessage();
        if (IsMaximized())
        {
            openIcon();
        }
        else
        {
            onOtherInstanceMessage();
        }
    }
}
#endif

#ifdef __WXMSW__
#define REDOSHORTCUT "Ctrl+Y"
#else
#define REDOSHORTCUT "Shift+Ctrl+Z"
#endif

void CMDIFrame::createMenus()
{
	enum{FILE, EDIT, VIEW, COLOR, ENCODING, CAML, CAMLTOP, OUTPUT, WINDOW, HELP};
    
    wxString menuNames[][2] =
    {
        {"&Fichier", ""}, {"&Nouveau\t", "Ctrl+N"}, {"&Inclure... \t", "Ctrl+I"}, {"&Ouvrir...\t", "Ctrl+O"}, {"&Fermer\t",  "Ctrl+W"}, {"&Enregistrer\t", "Ctrl+S"}, {"En&registrer sous...", ""}, {"Enre&gistrer au format RTF...", ""}, {"_" , ""}, {"Im&primer...\t", "Ctrl+P"}, {"Mise en p&age...",  ""}, {"_",  ""}, {"MRU1",  "*"}, {"MRU2", "*"}, {"MRU3", "*"}, {"MRU4",  "*"}, {"MRU5",  "*"}, {"MRU6",  "*"}, {"MRU7",  "*"}, {"MRU8",  "*"}, {"_",  "*"}, {"&Quitter",  ""}, {"/",  ""},
        {L"\u00C9&dition",  ""}, {"Annuler\t",  "Ctrl+Z"}, {L"R\u00E9tablir\t",  REDOSHORTCUT}, {"_",  ""}, {"&Couper\t", "Ctrl+X"}, {"Cop&ier\t", "Ctrl+C"}, {"C&oller\t", "Ctrl+V"}, {L"Tout &s\u00E9lectionner\t", "Ctrl+A"}, {"_",  ""}, {"Rec&hercher...\t", "Ctrl+F"}, {"Rechercher et R&emplacer...\t", "Ctrl+H"}, {"_",  ""}, {"Indentation par tabulations",  "$"}, {"Nombre d'espaces par tabulation...",  ""}, {L"Indenter apr\u00E8s in",  "$"}, {"Indenter les filtres",  "$"}, {"Utiliser l'indenteur pour ocaml",  "$"}, {"_",  ""}, {"Inde&nter\t", "Ctrl+J"}, {"/", ""},
#ifdef __WXMAC__
        {L"&Affichage",  ""}, {"Cloison verticale",  ""}, {L"Panneau d'entr\u00E9e seul",  "$"}, {"Panneau de sortie seul",  "$"}, {"Les deux panneaux", "$"}, {"_", ""}, {L"Police de caract\u00E8res en entr\u00E9e...", ""}, {L"Police de caract\u00E8res en sortie...", ""}, {"_", ""}, {L"Retour \u00E0 la ligne en entr\u00E9e", "$"}, {L"Retour \u00E0 la ligne en sortie", "$"}, {"_", ""}, {"Coloration syntaxique", "$"}, {"/", ""},
#else
        
        {L"&Affichage",  ""}, {"Cloison verticale",  ""}, {L"Panneau d'entr\u00E9e seul",  "$"}, {"Panneau de sortie seul",  "$"}, {"Les deux panneaux", "$"}, {"_", ""}, {L"Police de caract\u00E8res en entr\u00E9e...", ""}, {L"Police de caract\u00E8res en sortie...", ""}, {"_", ""}, {L"Retour \u00E0 la ligne en entr\u00E9e", "$"}, {L"Retour \u00E0 la ligne en sortie", "$"}, {"_", ""}, {"Coloration syntaxique", "$"}, {"_", ""}, {"&Barre d'outils", "$"}, {L"Barre d'\u00E9&tat", "$"}, {"/", ""},
#endif
        {L"&Couleurs", ""}, {L"Tampon d'entr\u00E9e...", ""}, {L"Commandes en entr\u00E9e...", ""}, {"Commandes en sortie...", ""}, {"_", ""}, {"Nombres...", ""}, {L"Mots cl\u00E9s...", ""}, {L"D\u00E9limiteurs...", ""}, {L"Op\u00E9rateurs...", ""}, {L"Cha\u00EEnes...", ""}, {"Commentaires...", ""}, {"/", ""},
        {L"&Encodage", ""}, {"Unix", "$"}, {"Mac", "$"}, {"Win", "$"}, {"Utf-8", "$"}, {"_",  ""}, {"Auto", "$"}, {"/", ""},
        {L"Ca&ml", ""}, {"&Envoyer\t", "Ctrl+Return"}, {L"&Envoyer la s\u00E9lection", ""}, {"&Interrompre\t", "Ctrl+K"}, {"&Stop", ""}, {"E&ffacer la sortie", ""}, {"/", ""},
        {L"Cam&lTop", ""}, {"Caml Light", "$"}, {"OCaml", "$"}, {"_", ""}, {L"D\u00E9marrage diff\u00E9r\u00E9", "$"}, {"/", ""},
        {L"&Sortie", ""}, {"Simple", "$"}, {L"Abr\u00E9g\u00E9e", "$"}, {L"Compl\u00E8te", "$"}, {"/", ""},
#ifdef __WXMSW__
        {L"Fe&n\u00EAtre", ""}, {"&Cascade", ""}, {L"&Mosa\u00EFque", ""}, {"/", ""},
#else
        {L"Fe&n\u00EAtre", ""}, {"/", ""},
#endif
        {L"A&ide", ""}, {"&Documentation de Caml-light", ""}, {"D&ocumentation de OCaml", ""}, {"_", ""}, {L"&R\u00E9glages par d\u00E9faut", ""}, {"_", ""},  {"/", ""},
        {"", ""}
    };
    int cmd = 1;
    menuItems = new deque<wxMenuItem*>();
    Bind(wxEVT_COMMAND_MENU_SELECTED, &CMDIFrame::onCommandAux, this, 1, HELP_ABOUT - FILE_NEW + 200);
    appMenuBar = menuBar = new wxMenuBar();
    int m = 0;
    for (int i = 0; menuNames[i][0] != "";)
    {
        int j;
        wxMenu* menu = new wxMenu();
        
#ifdef __WXMAC__
        if (m == COLOR) {
            cmd += 2;
        }
#endif
        
        if (m == WINDOW) {
            windowMenu = menu;
#ifndef __WXMSW__
            cmd += 2;
#endif
        }
        menuBar->Append(menu, menuNames[i][0]);
        for (j = i + 1; menuNames[j][0] != "/"; j++)
        {
            if (menuNames[j][0] != "_")
            {
                if (menuNames[j][1] == "*") {
                    menuItems->push_back(new wxMenuItem(NULL, cmd, menuNames[j][0]));
                }
                else if (menuNames[j][1] == "$")
                {
                    menu->AppendCheckItem(cmd, menuNames[j][0]);
                }
                else
                {
                    menu->Append(cmd, menuNames[j][0] + menuNames[j][1]);
                }
                
                cmd++;
            }
            else
            {
                if (menuNames[j][1] == "*") {
                    menuItems->push_back(new wxMenuItem());
                }
                else
                {
                    menu->AppendSeparator();
                }
            }
        }
        
        if (menuNames[i][0] == "A&ide")
        {
            menu->Append(wxID_ABOUT, L"\u00C0 propos...\tF1", "");
        }
        i = j + 1;
        m++;
    }
    SetMenuBar(menuBar);
}

void CMDIFrame::createToolbar()
{
    int commands[] = {FILE_NEW, FILE_OPEN1, FILE_SAVE, FILE_PRINT, -1, EDIT_CUT, EDIT_COPY, EDIT_PASTE, -1,
        VIEW_SPLIT, VIEW_BOTH, VIEW_INPUTONLY, VIEW_OUTPUTONLY, VIEW_WRAPINPUT, VIEW_WRAPOUTPUT, -1,
        CAML_SEND, EDIT_INDENT, CAML_INTERRUPT, CAML_STOP, CAML_CLEAROUTPUT, -1, HELP_ABOUT, 0};
    wxBitmap tbIcons[19];
    tbIcons[0] = wxMEMORY_BITMAP(new1);
    tbIcons[1] = wxMEMORY_BITMAP(open1);
    tbIcons[2] = wxMEMORY_BITMAP(save1);
    tbIcons[3] = wxMEMORY_BITMAP(print1);
    tbIcons[4] = wxMEMORY_BITMAP(cut1);
    tbIcons[5] = wxMEMORY_BITMAP(copy1);
    tbIcons[6] = wxMEMORY_BITMAP(paste1);
    tbIcons[7] = wxMEMORY_BITMAP(hv1);
    tbIcons[8] = wxMEMORY_BITMAP(inout1);
    tbIcons[9] = wxMEMORY_BITMAP(in1);
    tbIcons[10] = wxMEMORY_BITMAP(out1);
    tbIcons[11] = wxMEMORY_BITMAP(wrapin1);
    tbIcons[12] = wxMEMORY_BITMAP(wrapout1);
    tbIcons[13] = wxMEMORY_BITMAP(send1);
    tbIcons[14] = wxMEMORY_BITMAP(indent1);
    tbIcons[15] = wxMEMORY_BITMAP(interrupt1);
    tbIcons[16] = wxMEMORY_BITMAP(stop1);
    tbIcons[17] = wxMEMORY_BITMAP(clear1);
    tbIcons[18] = wxMEMORY_BITMAP(about1);
    
#ifndef __WXMAC__
    toolbar = new CToolBar(this);
#else
	toolbar = CreateToolBar();
#endif
    
    for(int i = 0, j = 0, k = 0; commands[i] != 0; i++)
    {
        for(j = i; commands[j] != -1 && commands[j] != 0; j++)
        {
            toolbar->AddTool(commands[j] - FILE_NEW + 1, "", tbIcons[k]);
            if (k < 18) k++;
        }
        if (commands[j] == -1)
        {
            toolbar->AddSeparator();
            i = j;
        }
    }
    toolbar->Realize();
    SetToolBar(toolbar);
}

void CMDIFrame::createStatusbar()
{
    int widths[2] = {300, -1};
    statusbar = CreateStatusBar();
    statusbar->SetFieldsCount(2);
    statusbar->SetStatusWidths(2, widths);
}

void CMDIFrame::updateFrame()
{
    if (ToolbarVisible)	toolbar->Show();
    else toolbar->Hide();
    
	if (StatusBarVisible) statusbar->Show();
    else statusbar->Hide();
    
	if (this->IsMaximized())
	{
		this->Maximize(false);
		this->Maximize();
	}
	else
	{
		wxSize sz = this->GetSize();
		this->SetSize(sz.GetWidth(), sz.GetHeight() - 1);
		this->SetSize(sz.GetWidth(), sz.GetHeight());
	}
}

bool CMDIFrame::isIconic()
{
	return IsIconized();
}

void CMDIFrame::openIcon()
{
    Iconize(false);
    Raise();
    SetFocus();
}

void CMDIFrame::moveWindow(int left, int top, int width, int height)
{
    SetSize(left, top, width, height);
}

CMDIChildFrame *CMDIFrame::getActiveChild()
{
#ifdef __WXMSW__
    size_t n = mdiChildren.size();
    for (size_t i = 0; i < n; i++)
	{
        CMDIChildFrame* f = mdiChildren.at(i);
        if (f->IsActive())
		{
				mdiChildren.at(0)->textEdit->SetFocus();
				return mdiChildren.at(0); 
        }
    }
    if (n > 0)
	{
        return mdiChildren.at(0);
    }
#else
    if (mdiChildren.size() > 0)
	{
		if (mdiChildren.at(0)->textEdit && !mdiChildren.at(0)->IsActive())
        {
            mdiChildren.at(0)->textEdit->SetFocus();
        }
        return mdiChildren.at(0);
    }    
#endif
    return NULL;
}

void CMDIFrame::setActiveChild(CMDIChildFrame *childFrame)
{
    childFrame->Raise();
}

void CMDIFrame::enableMenuItem(int cmd, bool on)
{
    if (menuBar->FindItem(cmd - FILE_NEW + 1))
    {
        menuBar->Enable(cmd - FILE_NEW + 1, on);
        toolbar->EnableTool(cmd - FILE_NEW + 1, on);
    }
}

void CMDIFrame::checkMenuItem(int cmd, bool on)
{
    if (menuBar->FindItem(cmd - FILE_NEW + 1))
    {
        menuBar->Check(cmd - FILE_NEW + 1, on);
    }
}

void CMDIFrame::setMenuItemText(int cmd,  const wstring& title, bool enabled)
{
    wxMenuItem* menuItem = menuBar->FindItem(cmd - FILE_NEW + 1);
    menuItem->SetItemLabel(title);
    menuBar->Enable(cmd - FILE_NEW + 1, enabled);
}

void CMDIFrame::setStatus(int index, const wstring& text)
{
    statusbar->SetStatusText(text, index);
}

void CMDIFrame::updateWindowMenu(wxUpdateUIEvent&)
{
    if (windowMenu == NULL) return;
    CMDIChildFrame* f = getActiveChild();
	if (f == NULL) return;
#ifdef __WXMSW__
    for (size_t i = 3; i < windowMenu->GetMenuItemCount(); i++)
#else
        for (size_t i = 0; i < windowMenu->GetMenuItemCount(); i++)
#endif
        {
            wxMenuItem* menuItem = windowMenu->FindItemByPosition(i);
            int id = menuItem->GetId();
            menuItem->Check(id == f->frameId);
        }
}

void CMDIFrame::onOtherInstanceMessage()
{
	wstring path;
    if (!getConfigFolderPath(path)) return;
    wstring path1 = path + L"1";
    fstream fs(toBytes(path1).c_str(), fstream::in);
    if (!fs.fail())
    {
        if (isIconic())
        {
            openIcon();
        }
        char c;
        while (fs.get(c) && c != '\r' && c != '\n')
        {
            string s;
            while (c != '\r' && c != '\n')
            {
                s += c;
                if (!fs.get(c)) break;
            }
            wstring fName = fromBytes(s);
            filePaths.push_back(fName);
        }
        fs.close();
		deleteFile(path1);
        openFiles(filePaths);
    }
}

void CMDIFrame::onCommandAux(wxCommandEvent& event)
{
    int cmd = event.GetId();
    if (cmd > HELP_ABOUT - FILE_NEW + 1)
    {
        CMDIChildFrame* f = NULL;
        for (size_t i = 0; i < mdiChildren.size(); i++)
        {
            if (mdiChildren.at(i)->frameId == cmd)
            {
                f = mdiChildren.at(i);
                break;
            }
        }
        if (f) setActiveChild(f);
        return;
    }
    wxDialog* dlg = NULL;
    cmd += FILE_NEW - 1;
    onCommand(cmd);
    wxTextCtrl* ctrl = NULL;
    if (findDlg && !findDlg->isHidden() && findDlg->m_textFind->HasFocus())
    {
        ctrl = findDlg->m_textFind;
        findDlg->Raise();
        dlg = findDlg;
    }
    else if (findReplaceDlg && !findReplaceDlg->isHidden())
    {
        if (findReplaceDlg->m_textFind->HasFocus())
        {
            ctrl = findReplaceDlg->m_textFind;
            findReplaceDlg->Raise();
        }
        else if (findReplaceDlg->m_textRepl->HasFocus())
        {
            ctrl = findReplaceDlg->m_textRepl;
            findReplaceDlg->Raise();
        }
        dlg = findReplaceDlg;
    }
    if (ctrl)
    {
        dlg->Raise();
        switch(cmd)
        {
            case EDIT_COPY:
                ctrl->Copy();
                return;
            case EDIT_CUT:
                ctrl->Cut();
                return;
            case EDIT_PASTE:
                ctrl->Paste();
                return;
            default:
                break;
        }
    }
    CMDIChildFrame* ac = getActiveChild();
    if (ac)
    {
        ac->onCommand(cmd);
    }
}

void CMDIFrame::onCommand(int)
{
}

void CMDIFrame::openFile(const wstring&)
{
}

void CMDIFrame::openFiles(deque<wstring>&)
{
}

void CMDIFrame::onCascadeWindow()
{
#ifndef __WXMAC__
    Cascade();
#endif
	cascade = true;
	Maximized = false;
}

void CMDIFrame::onTileWindow()
{
#ifndef __WXMAC__
    Tile();
#endif
}

void CMDIFrame::activateEvent(wxActivateEvent&)
{
    onActivate();
}

void CMDIFrame::resizeEvent(wxSizeEvent& event)
{
    frameWidth = event.m_size.GetWidth();
    frameHeight = event.m_size.GetHeight();
    event.Skip();
}

void CMDIFrame::moveEvent(wxMoveEvent& event)
{
    wxPoint pt = GetPosition();
    frameLeft = pt.x;
    frameTop = pt.y;
    event.Skip();
}

void CMDIFrame::closeEvent(wxCloseEvent& event)
{
    if (reviewChanges()) return;
    onClose();
	for (size_t i = 0; i < mdiChildren.size(); i++)
	{
        delete mdiChildren.at(i);
    }
    mdiChildren.erase(mdiChildren.begin(), mdiChildren.end());
    event.Skip();
}

#ifndef __WXMAC__
void CMDIFrame::dropEvent(wxDropFilesEvent& event)
{
	wxString* files = event.GetFiles();
	int n = event.GetNumberOfFiles();
	for (int i = 0; i < n; i++)
	{
		wstring s = files[i].ToStdWstring();
		droppedFiles->push_back(new wstring(s));
	}
    onDrop();
}
#endif

void CMDIFrame::onDrop()
{
}
void CMDIFrame::onClose()
{
#ifndef __WXMAC__
	timer->Stop();
#endif
}

void CMDIFrame::onActivate()
{
	CMDIChildFrame* cf = getActiveChild();
	if (cf)
	{
		cf->onActivate();
	}   
}

void CMDIFrame::onFileClose()
{
	CMDIChildFrame* activeFrame = getActiveChild();
	if (activeFrame)
	{
		if (activeFrame->reviewChange()) return;
		activeFrame->onClose();
	}
    
}

void CMDIFrame::onFileExit()
{
#ifndef __WXMAC__
    timer->Stop();
#endif
	if (reviewChanges()) return;
	onClose();
	for (size_t i = 0; i < mdiChildren.size(); i++)
	{
        delete mdiChildren.at(i);
    }
    mdiChildren.erase(mdiChildren.begin(), mdiChildren.end());
    wxTheApp->Exit();
}
bool CMDIFrame::reviewChanges()
{
	return false;
}

void CMDIFrame::colorDialog(unsigned long& color)
{
    wxColourData colorData;
    colorData.SetColour(color);
    wxColourDialog colorDialog(this, &colorData);
    colorData = colorDialog.GetColourData();
    if (colorDialog.ShowModal() == wxID_OK)
	{
        colorData = colorDialog.GetColourData();
        color = colorData.GetColour().GetRGB();
    }
}

void CMDIFrame::tabDialog(int& spaceNumPerTab)
{
    wxString s = wxString::Format("%d", spaceNumPerTab);
    wxTextEntryDialog textEntryDialog(this, "Nombre d'espaces par tabulation (au plus 8):", "",s);
    if (textEntryDialog.ShowModal() == wxID_OK)
	{
        s = textEntryDialog.GetValue();
        long l = 0L;
        if (s.ToLong(&l))
		{
            int i = (int)l;
            if (i > 0 && i < 9)
			{
                spaceNumPerTab = i;
            }
            else if (i > 8) spaceNumPerTab = 8;
        }
    }
}

bool CMDIFrame::openFileDialog(wstring& fileName)
{
    wxArrayInt fileTypes;
    wxString filter = wxT("Fichiers caml (*.ml *.oml *.mli)|*.ml;*.oml;*.mli");
    wxString fName = "";
    wxFileDialog openFileDialog(this, "Ouvrir le fichier", "Ouvrir", fileName, filter, wxFD_OPEN|wxFD_FILE_MUST_EXIST);
    if (openFileDialog.ShowModal() == wxID_OK)
    {
        fName = openFileDialog.GetPath();
    }
    if (fName != "")
    {
        fileName = fName.ToStdWstring();
        return true;
    }
    return false;
}

bool CMDIFrame::saveFileDialog(wstring& title)
{
    wxString filter = "(*.ml *.oml *.mli)|*.ml;*.oml;*.mli";
    wxString fName = "";
    wxFileDialog saveFileDialog(this, "Enregistrer le fichier", "", title.substr(title.find_last_of(L"/\\") + 1), filter, wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
    if (saveFileDialog.ShowModal() == wxID_OK)
    {
        fName = saveFileDialog.GetPath();
    }
    if (fName != "")
    {
        title = fName.ToStdWstring();
        return true;
    }
    return false;
}

bool CMDIFrame::saveFormattedDocumentDialog(wstring& title)
{
    wxString filter = "*.rtf";
    wxString fName = "";
    wxFileDialog saveFileDialog(this, "Enregistrer au format rtf", "", title.substr(title.find_last_of(L"/\\") + 1), filter, wxFD_SAVE|wxFD_OVERWRITE_PROMPT);
    if (saveFileDialog.ShowModal() == wxID_OK)
    {
        fName = saveFileDialog.GetPath();
    }
    if (fName != "")
    {
        title = fName.ToStdWstring();
        return true;
    }
    return false;
}

void CMDIFrame::printSetUpDialog(int& leftMargin, int& topMargin, int& rightMargin, int& bottomMargin)
{
#if wxUSE_PRINTING_ARCHITECTURE
    (*g_pageSetupData) = * g_printData;
    g_pageSetupData->EnableMargins(true);
    g_pageSetupData->SetMarginTopLeft(wxPoint(leftMargin, topMargin));
    g_pageSetupData->SetMarginBottomRight(wxPoint(rightMargin, bottomMargin));
    wxPageSetupDialog pageSetupDialog(this, g_pageSetupData);
    pageSetupDialog.ShowModal();
    wxPageSetupDialogData pageSetupData = pageSetupDialog.GetPageSetupData();
    wxPoint topLeft = pageSetupData.GetMarginTopLeft();
    leftMargin = topLeft.x;
    topMargin = topLeft.y;
    wxPoint bottomRight = pageSetupData.GetMarginBottomRight();
    rightMargin = bottomRight.x;
    bottomMargin = bottomRight.y;
    (*g_printData) = pageSetupData.GetPrintData();
    (*g_pageSetupData) = pageSetupDialog.GetPageSetupData();
#endif
}

void CMDIFrame::fontDlg(CFont*& font)
{
    wxFontData fontData;
    fontData.SetInitialFont(*font->font);
    wxFontDialog fontDialog(this, fontData);
    fontDialog.SetTitle(L"Police en entr\u00E9e");
    if (fontDialog.ShowModal() == wxID_OK)
	{
        wxFontData retData = fontDialog.GetFontData();
        wxFont fnt = retData.GetChosenFont();
        wxFontStyle fntStyle = fnt.GetStyle();
        font = new CFont(fnt.GetFaceName().ToStdWstring(), fnt.GetPointSize(), fnt.GetWeight() == wxFONTWEIGHT_BOLD, fntStyle == wxFONTSTYLE_ITALIC || fntStyle == wxFONTSTYLE_SLANT);
        font->font = new wxFont(fnt);
    }
}

// Class CMDIChildFrame ------------------------------------------------------------------------------------------------

static int childFrameId = HELP_ABOUT - FILE_NEW + 1;

BEGIN_EVENT_TABLE(CMDIChildFrame, wxMDIChildFrame)
EVT_ACTIVATE(CMDIChildFrame::activateEvent)
EVT_CLOSE(CMDIChildFrame::closeEvent)
EVT_LEFT_DOWN(CMDIChildFrame::mousePressEvent)
EVT_LEFT_UP(CMDIChildFrame::mouseReleaseEvent)
EVT_MOTION(CMDIChildFrame::mouseMoveEvent)
EVT_SIZE(CMDIChildFrame::resizeEvent)
EVT_TIMER(-1, CMDIChildFrame::onTimerAux)
END_EVENT_TABLE()

CMDIChildFrame::CMDIChildFrame(CMDIFrame* mdiFrame, bool maximized): wxMDIChildFrame(mdiFrame, wxID_ANY,"childframe")
{
#ifdef __WXMSW__
    SetIcon(wxICON(WinCamlDoc));
#endif
    saveMaximized = maximized;
#ifdef __WXMAC__
    SetClientSize(mainFrame->xDim, mainFrame->yDim);
#endif
    frameId = ++childFrameId;
#ifdef __WXMSW__
    if (mdiFrame->mdiChildren.size() == 0)
	{
        mdiFrame->windowMenuSeparator = mdiFrame->windowMenu->AppendSeparator();
    }
#endif
    windowMenuItem = mainFrame->windowMenu->AppendCheckItem(frameId, "Sans titre");
    windowMenuItem->Check();
    timer1 = NULL;
}

CMDIChildFrame::~CMDIChildFrame()
{
    if (timer1)
    {
        timer1->Stop();
        //delete timer1;
        timer1 = NULL;
    }
}

void CMDIChildFrame::setTitle(const wstring& title)
{
    wstring s = title.substr(title.find_last_of(L"/\\") + 1);
    SetTitle(s);
    windowMenuItem->SetItemLabel(s);
}

void CMDIChildFrame::drawFocusRect(int, int, int, int)
{
}

void CMDIChildFrame::getClientSize(int& w, int& h)
{
    GetClientSize(&w, &h);
}

void CMDIChildFrame::releaseCapture()
{
#ifdef __WXMSW__
	if (::GetCapture() == this->m_hWnd) ReleaseCapture();
#endif
}

void CMDIChildFrame::setCapture()
{
#ifdef __WXMSW__
	::SetCapture(this->m_hWnd);
#endif
}

void CMDIChildFrame::showDefault()
{
#ifdef __WXMAC__
    mainFrame->SetSize(50, 50, 800, 75);
    SetSize(mainFrame->frameLeft, mainFrame->frameHeight + 52, mainFrame->frameWidth, 600);
#endif
#ifdef __WXMSW__
    Maximize();
#endif
    Show();
}

void CMDIChildFrame::showNormal()
{
    Show();
#ifdef __WXMSW__
	if (mainFrame->cascade) mainFrame->Cascade();
	else mainFrame->Tile();
#endif
#ifdef __WXMAC__
	SetPosition(wxPoint(mainFrame->frameLeft, mainFrame->frameHeight + 52));
    SetClientSize(mainFrame->xDim, mainFrame->yDim);
#endif
}

void CMDIChildFrame::showMaximized()
{
    Maximize();
    Show();
}

void CMDIChildFrame::hide()
{
}

bool CMDIChildFrame::isMaximized()
{
	if (saveMaximized)
	{
		saveMaximized = false;
		return true;
	}
    return IsMaximized();
}

#ifndef __WXGTK__
void CMDIChildFrame::setCursor(int cursor)
{
    wxCursor crs(cursor);
    SetCursor(crs);

}
#else
void CMDIChildFrame::setCursor(int)
{
}
#endif

void CMDIChildFrame::setWindowModified(bool)
{
}

void CMDIChildFrame::onCommand(int)
{
}

void CMDIChildFrame::onFileSaveAs()
{
}

void CMDIChildFrame::onEditCut()
{
}

void CMDIChildFrame::onEditCopy()
{
}

void CMDIChildFrame::onEditPaste()
{
}

void CMDIChildFrame::onEditSelectAll()
{
}

void CMDIChildFrame::startTimer()
{
    timer1 = new wxTimer(this);
    timer1->Start(20);
}

void CMDIChildFrame::activateEvent(wxActivateEvent&)
{
    onActivate();
}

void CMDIChildFrame::resizeEvent(wxSizeEvent& event)
{
    onSize();
    event.Skip();
}

void CMDIChildFrame::mouseMoveEvent(wxMouseEvent& event)
{
    onMouseMove(event.m_x, event.m_y, event.m_leftDown);
    event.Skip();
}

void CMDIChildFrame::mousePressEvent(wxMouseEvent& event)
{
    onLeftButtonDown(event.m_x, event.m_y);
}

void CMDIChildFrame::mouseReleaseEvent(wxMouseEvent& event)
{
    onLeftButtonUp();
    event.Skip();
}

void CMDIChildFrame::closeEvent(wxCloseEvent& event)
{
    if (reviewChange())
    {
        return;
    }
	onClose();
    event.Veto();
}

void CMDIChildFrame::onTimerAux(wxTimerEvent&)
{
    onTimer();
}

void CMDIChildFrame::onTimer()
{
}

void CMDIChildFrame::onMouseMove(int, int, bool)
{
}

void CMDIChildFrame::onLeftButtonDown(int, int)
{
}

void CMDIChildFrame::onLeftButtonUp()
{
}

void CMDIChildFrame::onSize()
{
}

void CMDIChildFrame::onActivate()
{
}

void CMDIChildFrame::onClose()
{
    if (windowMenuItem)
    {
        mainFrame->windowMenu->Remove(windowMenuItem);
        windowMenuItem = NULL;
    }
#ifdef __WXMSW__
    if (mainFrame->windowMenu->GetMenuItemCount() == 3)
    {
        mainFrame->windowMenu->Remove(mainFrame->windowMenuSeparator);
    }
#endif
    onDestroy();
}

void CMDIChildFrame::onDestroy()
{
}

bool CMDIChildFrame::reviewChange()
{
    return false;
}

// Class CRichEdit -----------------------------------------------------------------------------------------------------

BEGIN_EVENT_TABLE(CRichEdit, wxStyledTextCtrl)
EVT_KEY_DOWN(CRichEdit::keyPressEvent)
EVT_LEFT_UP(CRichEdit::mouseReleaseEvent)
#ifndef __WXMAC__
EVT_DROP_FILES(CRichEdit::dropEvent)
#endif
END_EVENT_TABLE()

extern const int COLORCOUNT;

#ifndef __WXMAC__
void CRichEdit::dropEvent(wxDropFilesEvent& event)
{
	wxString* files = event.GetFiles();
	int n = event.GetNumberOfFiles();
	for (int i = 0; i < n; i++)
	{
		wstring s = files[i].ToStdWstring();
		mainFrame->droppedFiles->push_back(new wstring(s));
	}
    mainFrame->onDrop();
}
#endif

CRichEdit::CRichEdit(CMDIChildFrame* win): wxStyledTextCtrl(win)
{
	childFrame = win;
    selectionChanged = true;
#ifndef __WXMAC__
    SetDropTarget(NULL);
    DragAcceptFiles(true);
#else
    CFileDropTarget* fileDropTarget = new CFileDropTarget();
    SetDropTarget(fileDropTarget);
#endif
    UsePopUp(false);
    SetMarginWidth(1, 0);
    SetMarginLeft(5);
    Show();
}

CRichEdit::~CRichEdit()
{
}

void CRichEdit::move(int left, int top, int width, int height)
{
    SetSize(left, top, width, height);
}

void CRichEdit::mouseReleaseEvent(wxMouseEvent& event)
{
    onLeftButtonUp(event.ControlDown());
    event.Skip();
}
void CRichEdit::keyPressEvent(wxKeyEvent& event)
{
#ifdef __WXMAC__
    if (event.GetModifiers() & wxMOD_RAW_CONTROL) {return;}
#endif
    if (event.GetModifiers() == wxMOD_CONTROL && event.GetUnicodeKey() == 'Z') {undo(); return;}
#ifdef __WXMSW__
    if (event.GetModifiers() == wxMOD_CONTROL && event.GetUnicodeKey() == 'Y') {redo(); return;}
#else
    if (event.GetModifiers() == (wxMOD_CONTROL | wxMOD_SHIFT) && event.GetUnicodeKey() == 'Z') {redo(); return;}
#endif
	onKeyDown();
    if (!(event.GetModifiers() == wxMOD_CONTROL))
    {
        onChar(event.GetKeyCode());
    }
    if (event.GetKeyCode() == WXK_RETURN && !(event.GetModifiers() == wxMOD_CONTROL))
    {
        onReturnKeyDown();
    }
	else
    {
        event.Skip();
    }
}

void CRichEdit::keyReleaseEvent(wxKeyEvent&)
{
}

void CRichEdit::onLeftButtonUp(bool)
{
}
void CRichEdit::undo()
{
}

void CRichEdit::redo()
{
}

void CRichEdit::onChar(int)
{
}

void CRichEdit::onKeyDown()
{
}

void CRichEdit::onEnterKeyDown()
{
}

void CRichEdit::onReturnKeyDown()
{
}

void CRichEdit::onKeyUp()
{
}

void CRichEdit::getSelection(size_t& selStart, size_t& selEnd)
{
    long start, end;
    this->GetSelection(&start, &end);
    selStart = start;
    selEnd = end;
}

void CRichEdit::setSelection(size_t selStart, size_t selEnd)
{
    size_t len = getTextLength();
    if (selStart == (size_t)-1 && selEnd == (size_t)-1)
    {
        selStart = selEnd = len;
    }
    else if (selStart > len)
    {
        selStart = selEnd = len;
    }
    else if (selEnd > len)
    {
        selEnd = len;
    }
    SetSelection(selStart, selEnd);
    EnsureCaretVisible();
}

void CRichEdit::setUseTabs(bool IndentWithTabs)
{
    SetUseTabs(IndentWithTabs);
}

void CRichEdit::selectAll()
{
    SetSelection(0, getTextLength());
}

void CRichEdit::replaceAll(const wstring& findWhat, const wstring& replaceWith, int findFlags)
{
    setSelection(0, 0);
	wxString wFindWhat = toUnicode(wstringToString(findWhat), ENCODING_UTF8);
    for(;;)
    {
        searchEdit->SearchAnchor();
        int n = searchEdit->SearchNext(findFlags, wFindWhat);
        if (n == -1)
        {
            break;
        }
        setText(n, findWhat.length(), replaceWith);
        n += findWhat.length();
        searchEdit->setSelection(n, n);
    }
}

size_t CRichEdit::getCaretPosition()
{
    return GetCurrentPos();
}

void CRichEdit::hideSelection()
{
}

void CRichEdit::showSelection()
{
}

size_t CRichEdit::getTextLength()
{
    return GetTextLength(); // return utf-8 byte length
}

wstring CRichEdit::getText()
{
	return stringToWString(fromUnicode(GetText(), ENCODING_UTF8));
}

wstring CRichEdit::getText(size_t start, size_t length)
{
	return stringToWString(fromUnicode(GetTextRange((int)start, (int)(start + length)), ENCODING_UTF8));
}

void CRichEdit::setText(size_t start, size_t length, const wstring& text, unsigned long color)
{
    bool b = GetReadOnly();
    if (b) SetReadOnly(false);
	if (text == L"")
	{
		Replace(start, start + length, L"");
	}
	else
	{
		Replace(start, start + length, toUnicode(wstringToString(text), color == rgb(255, 0, 0) ? ENCODING_UNIX : ENCODING_UTF8));
	}
    setTextColor(start, text.length(), color);
    if (b) SetReadOnly(true);
}

void CRichEdit::setSelectedText(const wstring& s)
{
    int a;
    int b;
    GetSelection(&a, &b);
    setText(a, b - a, s);
}

void CRichEdit::setTabs(int, int spaceCountPerTab)
{
    SetTabWidth(spaceCountPerTab);
}

size_t CRichEdit::visibleTextOffset()
{
    return CharPositionFromPoint(0, 0);
}

size_t CRichEdit::visibleTextEnd()
{
    int i, j;
    GetSize(&i, &j);
    return CharPositionFromPoint(i, j);
}

void CRichEdit::suspendLayout()
{
    // Unused
}

void CRichEdit::resumeLayout()
{
    // Unused
}

void CRichEdit::updateView()
{
    // Unused
}

void CRichEdit::setColors()
{
    for (unsigned int i = 0; i < forecolorCount; i++)
    {
        StyleSetForeground(i, T[i]);
        if (forecolorCount == 7)
        {
            StyleSetForeground(i + forecolorCount, T[i]);
            StyleSetForeground(i + 2 * forecolorCount, T[i]);
            StyleSetForeground(i + 3 * forecolorCount, T[i]);
            StyleSetBackground(i + forecolorCount, T[inputBackground]);
            StyleSetBackground(i + 2 * forecolorCount, T[bufferBackground]);
            StyleSetBackground(i + 3 * forecolorCount, T[matchingBackground]);
        }
    }
}

void CRichEdit::setTextColor(size_t a, size_t l, unsigned long c)
{
    unsigned int i = 0;
    while (T[i] != c && i < forecolorCount - 1)
    {
        i++;
    }
    if (i < forecolorCount) {
        for (size_t j = a; j < a + l; j++)
        {
            unsigned int st = GetStyleAt((int)j);
            if (st == 0) st++;
            StartStyling((int)j, -1);
            SetStyling(1, (st - 1) / forecolorCount * forecolorCount + i);
        }
    }
    if (forecolorCount == 7)
    {
        CRichEdit* te = (CRichEdit*)highlighter->textEdit;
        unsigned long col = a >= te->commandStart && a < te->commandEnd ? te->T[inputBackground] : 0xFFFFFFFF;
        te->setTextBackground(a, l, te->inBuffer && a >= te->commandStart ? te->T[bufferBackground] : col);
    }
}

void CRichEdit::setTextBackground(size_t a, size_t l, unsigned long c)
{
    if (c == 0xFFFFFFFF)
    {
        for (size_t j = a; j < a + l; j++)
        {
            unsigned int st = GetStyleAt((int)j);
            while (st >= forecolorCount)
            {
                st -= forecolorCount;
            }
            StartStyling((int)j, -1);
            SetStyling(1, st);
        }
    }
    else
    {
        unsigned int i = forecolorCount;
        while (T[i] != c && i < forecolorCount + 3)
        {
            i++;
        }
        if (i < forecolorCount + 3)
        {
            i = (i - forecolorCount + 1) * forecolorCount;
            for (size_t j = a; j < a + l; j++)
            {
                unsigned int st = GetStyleAt((int)j);
                StartStyling((int)j, -1);
                int nst = st % 7 + i;
                SetStyling(1, nst);
            }
        }
    }
}

void CRichEdit::setTextDefaultBackground(size_t a, size_t l)
{
    setTextBackground(a, l, 0xFFFFFFFF);
}

void CRichEdit::cut()
{
    Cut();
}

void CRichEdit::copy()
{
    Copy();
}

void CRichEdit::paste()
{
    Paste();
}

int CRichEdit::loadFile(const wstring& fileName, bool guessEnc, int &preferredEncoding)
{
    wxString fName = fileName;
    if (!wxFile::Exists(fName))
    {
        return 0;
    }
    wxFile file(fName);
    size_t length = file.Length();
    if (length == 0)
    {
        return 1;
    }
    char* buffer = (char*)malloc(length + 1);
    if (!buffer)
    {
        return 0;
    }
    file.Read(buffer, length);
    file.Close();
    buffer[length] = 0;
    int encoding = preferredEncoding;
    string s(buffer);
    if (guessEnc)
    {
        encoding = guessEncoding(s, preferredEncoding);
        preferredEncoding = encoding;
    }
    wxString ws = toUnicode(s, encoding);
    SetText(ws);
    int l = GetTextLength();
    SetSelection(l, l);
    EnsureCaretVisible();
    return 1;
}

int CRichEdit::appendFile(const wstring& fileName, int encoding)
{
    wxString fName = fileName;
    if (!wxFile::Exists(fName))
    {
        return 0;
    }
    wxFile file(fName);
    size_t length = file.Length();
    if (length == 0)
    {
        return 0;
    }
    char* buffer = (char*)malloc(length + 1);
    if (!buffer)
    {
        return 0;
    }
    file.Read(buffer, length);
    file.Close();
    buffer[length] = 0;
    string s(buffer);
    wxString ws = toUnicode(s, encoding);
    AppendText(ws);
    return 1;
}

int CRichEdit::saveFile(const wstring& fileName, int encoding)
{
    wxString wxstr = GetText();
#ifdef __WXGTK__
    if (encoding == ENCODING_MAC)
    {
        string s;
        for (size_t i = 0; i < wxstr.Length(); i++)
        {
            wchar_t wc = wxstr[i];
            int j = 0;
            while (macRomanToUnicode[j] != wc)
            {
                j++;
            }
            if (j == 256)
            {
                return 0;
            }
            char c = j;
            s += c;
        }
        wxString fName = fileName;
        wxFile file(fName, wxFile::write);
        file.Write(s.c_str(), s.size());
        file.Close();
        return 1;
    }
#endif
    wxCSConv csconv(encodingCode(encoding));
    size_t dstLen = csconv.FromWChar(NULL, 0, wxstr.c_str());
    if (dstLen == wxCONV_FAILED) return 0;
    char *dst = new char[dstLen];
    if (csconv.FromWChar(dst, dstLen, wxstr.c_str()) == wxCONV_FAILED) return 0;
    string s(dst);
    delete dst;
    if (encoding == ENCODING_WIN && s.size() > 0)
    {
        for (size_t i = s.size() - 1; i > 0; i--)
        {
            if (s.at(i) == '\n') {
                s.insert(i, "\r");
            }
        }
    }
    wxString fName = fileName;
    wxFile file(fName, wxFile::write);
    file.Write(s.c_str(), s.size());
    file.Close();
    return 1;
}

void CRichEdit::focus()
{
	SetFocus();
}

void CRichEdit::setReadOnly(bool b)
{
    SetReadOnly(b);
}

void CRichEdit::updateCursor()
{
    //Unused
}

wstring CRichEdit::status()
{
	return L"";
}

void CRichEdit::saveFormattedDocument(const wstring& fileName)
{
	wxFile file(fileName, wxFile::write);
	stringstream s(stringstream::in | stringstream::out);
	s << "{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1036{\\fonttbl{\\f0\\fnil\\fcharset0" << fnt.GetFaceName() << ";}}";
	s << "{\\colortbl ";
	for (unsigned int i = 0; i < forecolorCount; i ++)
	{
		s << ";\\red" <<  ((int)wxColour(T[i]).Red()) << "\\green" << ((int)wxColour(T[i]).Green()) << "\\blue" << ((int)wxColour(T[i]).Blue());
	}
	s << ";}\\viewkind4\\uc1\\pard\r\n";
	deque<tokenClass*>* tokens = highlighter->getTokenArray();
	string text = fromUnicode(GetText(), ENCODING_UTF8);
    int color0 = -1;
	for (size_t i = 0; i < tokens->size(); i++)
	{
		tokenClass* tk = tokens->at(i);
		string s1 = text.substr(tk->getTokenBegin(), tk->getTokenEnd() - tk->getTokenBegin());
		int color = tk->getTokenColor();
		if (i == 0)
        {
            s << "\\cf" << color + 1 << "\\f0\\fs20 ";
        }
        if (color != color0)
        {
            s << "\\cf" << color + 1 << " ";
            color0 = color;
        }
		if (s1 == "\n")
		{
                s << "\\par\n";
		}
		else
		{
            string s2 = fromUnicode(toUnicode(s1, ENCODING_UTF8), ENCODING_WIN);
            string s3 = "";
            for (size_t i = 0; i < s2.length(); i++)
            {
                if (s2[i] != '\\')
                {
                    s3 += s2[i];
                }
                else
                {
                    s3 += "\\\\";
                }
            }
            s << s3;
		}
	}
	s << "\\cf0\\par\n}";
	file.Write(s.str().c_str(), s.str().size());
	file.Close();
}

void CRichEdit::beginPrint()
{
}

void CRichEdit::endPrint()
{
}

wxPrinter* printer = NULL;

void CRichEdit::printFormattedDialog()
{
    wxPrintDialogData printDialogData(* g_printData);
    
    printer = new wxPrinter(&printDialogData);
    CPrintout printout(this);
    if (!printer->Print(this, &printout, true))
    {
        if (wxPrinter::GetLastError() == wxPRINTER_ERROR)
        {
            wxLogError(wxT("Erreur d'impression"));
        }
    }
    else
    {
        (*g_printData) = printer->GetPrintDialogData().GetPrintData();
    }
}

void CRichEdit::setWrapping(bool on)
{
    SetWrapMode(on ? 1 : 0);
}

size_t CRichEdit::lineFromChar(size_t charIndex)
{
    return LineFromPosition((int)charIndex);
}

size_t CRichEdit::lineFirstChar(size_t lineIndex)
{
    return PositionFromLine((int)lineIndex);
}

void CRichEdit::setFont(CFont* font)
{
    fnt = *font->font;
    this->StyleSetFont(1, fnt);
    this->StyleSetFont(32, fnt);
    int imax = forecolorCount == 7 ? 3 * forecolorCount : forecolorCount;
    for (int i = 0; i < imax; i++)
    {
        this->StyleSetFont(i, fnt);
    }
}
void CRichEdit::onReplace(const wstring&)
{
}
void CRichEdit::onReplaceAll(const wstring&, const wstring&, unsigned long)
{
}
void CRichEdit::onFindClose()
{
	closeFindDialog(true);
}

// Class CFindDialog -----------------------------------------------------------------------------------------------------

BEGIN_EVENT_TABLE(CFindDialog, wxDialog)
EVT_BUTTON(wxID_FIND, CFindDialog::find)
EVT_BUTTON(wxID_CANCEL, CFindDialog::cancel)
EVT_CLOSE(CFindDialog::close)
END_EVENT_TABLE()

CFindDialog::CFindDialog(CMDIFrame* frame): wxDialog(frame, wxID_ANY, "WinCaml")
{
    hidden = true;
    wxBoxSizer *leftsizer = new wxBoxSizer(wxVERTICAL);
    
    wxFlexGridSizer *sizer2Col = new wxFlexGridSizer(3);
    sizer2Col->AddGrowableCol(2);
    sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Chercher:"), wxDefaultPosition, wxSize(80, wxDefaultCoord)), 0,wxALIGN_CENTRE_VERTICAL | wxALIGN_RIGHT);
    sizer2Col->Add(10, 0);
    m_textFind = new wxTextCtrl(this, wxID_ANY, "");
    sizer2Col->Add(m_textFind, 1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
    
    leftsizer->Add(sizer2Col, 0, wxEXPAND | wxALL, 5);
    
    wxBoxSizer *optsizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *chksizer = new wxBoxSizer( wxVERTICAL);
    m_chkWord = new wxCheckBox(this, wxID_ANY, _("Mot entier"));
    chksizer->Add(m_chkWord, 0, wxALL, 3);
    m_chkCase = new wxCheckBox(this, wxID_ANY, _("Respecter la casse"));
    chksizer->Add(m_chkCase, 0, wxALL, 3);
    optsizer->Add(chksizer, 0, wxALL, 10);
    static const wxString searchDirections[] = {_("Haut"), _("Bas")};
    int majorDimension = 0;
    int rbStyle = wxRA_SPECIFY_COLS;
    m_radioDir = new wxRadioBox(this, wxID_ANY, _("Direction"), wxDefaultPosition, wxDefaultSize, WXSIZEOF(searchDirections),searchDirections, majorDimension, rbStyle);
    optsizer->Add(m_radioDir, 0, wxALL, 10);
    
    leftsizer->Add(optsizer);
    
    wxBoxSizer *bttnsizer = new wxBoxSizer(wxVERTICAL);
    wxButton* btn = new wxButton(this, wxID_FIND, "Suivant");
    btn->SetDefault();
    bttnsizer->Add(btn, 0, wxALL, 3);
    bttnsizer->Add(new wxButton(this, wxID_CANCEL, "Annuler"), 0, wxALL, 3);
    
    wxBoxSizer *topsizer = new wxBoxSizer(wxHORIZONTAL);
    topsizer->Add(leftsizer, 1, wxALL, 5);
    topsizer->Add(bttnsizer, 0, wxALL, 5);
    SetAutoLayout(true);
    SetSizer(topsizer);
    topsizer->SetSizeHints(this);
    topsizer->Fit(this);
    
    Centre(wxBOTH);
    
    m_textFind->SetFocus();
}

CFindDialog::~CFindDialog()
{
}

void CFindDialog::init()
{
    size_t selStart, selEnd;
    searchEdit->getSelection(selStart, selEnd);
    m_textFind->Clear();
    m_textFind->AppendText(searchEdit->GetTextRange((int)selStart, (int)selEnd));
}

void CFindDialog::find(wxCommandEvent& WXUNUSED(event))
{
    int findFlags = 0;
    if (m_chkWord->IsChecked())
    {
        findFlags |= wxSTC_FIND_WHOLEWORD;
    }
    if (m_chkCase->IsChecked())
    {
        findFlags |= wxSTC_FIND_MATCHCASE;
    }
    if (m_radioDir->GetSelection() == 0)
    {
        size_t selStart, selEnd;
        searchEdit->getSelection(selStart, selEnd);
        searchEdit->setSelection(selStart, selStart);
        searchEdit->SearchAnchor();
        wxString s = m_textFind->GetValue();
        int n = searchEdit->SearchPrev(findFlags,s);
        if (n != -1)
        {
            searchEdit->setSelection(n, n + s.utf8_str().length());
        }
        else
        {
            wxMessageBox(L"Recherche vers le haut termin\u00E9e");
        }
    }
    else
    {
        size_t selStart, selEnd;
        searchEdit->getSelection(selStart, selEnd);
        searchEdit->setSelection(selEnd, selEnd);
        searchEdit->SearchAnchor();
        wxString s = m_textFind->GetValue();
        int n = searchEdit->SearchNext(findFlags, s);
        if (n != -1)
        {
            searchEdit->setSelection(n, n + s.utf8_str().length());
        }
        else
        {
            wxMessageBox(L"Recherche vers le bas termin\u00E9e");
        }
    }
}

void CFindDialog::cancel(wxCommandEvent& WXUNUSED(event))
{
    searchEdit->onFindClose();
}

void CFindDialog::close(wxCloseEvent& WXUNUSED(event))
{
    searchEdit->onFindClose();
}

// Class CFindReplaceDialog --------------------------------------------------------------------------------------------------

BEGIN_EVENT_TABLE(CFindReplaceDialog, wxDialog)
EVT_BUTTON(wxID_FIND, CFindReplaceDialog::find)
EVT_BUTTON(wxID_REPLACE, CFindReplaceDialog::replace)
EVT_BUTTON(wxID_REPLACE_ALL, CFindReplaceDialog::replaceAll)
EVT_BUTTON(wxID_CANCEL, CFindReplaceDialog::cancel)
EVT_CLOSE(CFindReplaceDialog::close)
END_EVENT_TABLE()

CFindReplaceDialog::CFindReplaceDialog(CMDIFrame* frame): wxDialog(frame, wxID_ANY, "WinCaml")
{
    hidden = true;
    wxBoxSizer *leftsizer = new wxBoxSizer(wxVERTICAL);
    
    wxFlexGridSizer *sizer2Col = new wxFlexGridSizer(3);
    sizer2Col->AddGrowableCol(2);
    sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Chercher:"), wxDefaultPosition, wxSize(100, wxDefaultCoord)), 0,wxALIGN_CENTRE_VERTICAL | wxALIGN_RIGHT);
    sizer2Col->Add(10, 0);
    m_textFind = new wxTextCtrl(this, wxID_ANY, "");
    sizer2Col->Add(m_textFind, 1, wxALIGN_CENTRE_VERTICAL | wxEXPAND);
    sizer2Col->Add(new wxStaticText(this, wxID_ANY, _("Remplacer par:"), wxDefaultPosition, wxSize(100, wxDefaultCoord)), 0,wxALIGN_CENTRE_VERTICAL | wxALIGN_RIGHT | wxTOP, 5);
    sizer2Col->Add(10, 0);
    m_textRepl = new wxTextCtrl(this, wxID_ANY, "");
    sizer2Col->Add(m_textRepl, 1, wxALIGN_CENTRE_VERTICAL | wxEXPAND | wxTOP, 5);
    
    leftsizer->Add(sizer2Col, 0, wxEXPAND | wxALL, 5);
    
    wxBoxSizer *optsizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *chksizer = new wxBoxSizer( wxVERTICAL);
    m_chkWord = new wxCheckBox(this, wxID_ANY, _("Mot entier"));
    chksizer->Add(m_chkWord, 0, wxALL, 3);
    m_chkCase = new wxCheckBox(this, wxID_ANY, _("Respecter la casse"));
    chksizer->Add(m_chkCase, 0, wxALL, 3);
    optsizer->Add(chksizer, 0, wxALL, 10);
    static const wxString searchDirections[] = {_("Haut"), _("Bas")};
    int majorDimension = 0;
    int rbStyle = wxRA_SPECIFY_COLS;
    m_radioDir = new wxRadioBox(this, wxID_ANY, _("Direction"), wxDefaultPosition, wxDefaultSize, WXSIZEOF(searchDirections),searchDirections, majorDimension, rbStyle);
    optsizer->Add(m_radioDir, 0, wxALL, 10);
    
    leftsizer->Add(optsizer);
    
    wxBoxSizer *bttnsizer = new wxBoxSizer(wxVERTICAL);
    wxButton* btn = new wxButton(this, wxID_FIND, "Suivant");
    btn->SetDefault();
    bttnsizer->Add(btn, 0, wxALL, 4);
    bttnsizer->Add(new wxButton(this, wxID_CANCEL, "Annuler"), 0, wxALL, 4);
    bttnsizer->Add(new wxButton(this, wxID_REPLACE, _("Remplacer")), 0, wxALL, 4);
    bttnsizer->Add(new wxButton(this, wxID_REPLACE_ALL, _("Tout remplacer")), 0, wxALL, 4);
    
    wxBoxSizer *topsizer = new wxBoxSizer( wxHORIZONTAL );
    topsizer->Add(leftsizer, 1, wxALL, 5);
    topsizer->Add(bttnsizer, 0, wxALL, 5);
    SetAutoLayout(true);
    SetSizer( topsizer );
    topsizer->SetSizeHints(this);
    topsizer->Fit(this);
    
    Centre(wxBOTH);
    
    m_textFind->SetFocus();
}

CFindReplaceDialog::~CFindReplaceDialog()
{
}

void CFindReplaceDialog::init()
{
    size_t selStart, selEnd;
    searchEdit->getSelection(selStart, selEnd);
    m_textFind->Clear();
    m_textFind->AppendText(searchEdit->GetTextRange((int)selStart, (int)selEnd));
}

void CFindReplaceDialog::find(wxCommandEvent& WXUNUSED(event))
{
    int findFlags = 0;
    if (m_chkWord->IsChecked())
    {
        findFlags |= wxSTC_FIND_WHOLEWORD;
    }
    if (m_chkCase->IsChecked()) {
        findFlags |= wxSTC_FIND_MATCHCASE;
    }
    if (m_radioDir->GetSelection() == 0) {
        size_t selStart, selEnd;
        searchEdit->getSelection(selStart, selEnd);
        searchEdit->setSelection(selStart, selStart);
        searchEdit->SearchAnchor();
        wxString s = m_textFind->GetValue();
        int n = searchEdit->SearchPrev(findFlags,s);
        if (n != -1) {
            searchEdit->setSelection(n, n + s.length());
        }
        else
        {
            wxMessageBox(L"Recherche vers le haut termin\u00E9e");
        }
    }
    else {
        size_t selStart, selEnd;
        searchEdit->getSelection(selStart, selEnd);
        searchEdit->setSelection(selEnd, selEnd);
        searchEdit->SearchAnchor();
        wxString s = m_textFind->GetValue();
        int n = searchEdit->SearchNext(findFlags, s);
        if (n != -1) {
            searchEdit->setSelection(n, n + s.utf8_str().length());
        }
        else
        {
            wxMessageBox(L"Recherche vers le bas termin\u00E9e");
        }
    }
}

void CFindReplaceDialog::replace(wxCommandEvent& WXUNUSED(event))
{
    searchEdit->onReplace(stringToWString(fromUnicode(m_textRepl->GetValue(),ENCODING_UTF8)));
}

void CFindReplaceDialog::replaceAll(wxCommandEvent& WXUNUSED(event))
{
    searchEdit->onReplaceAll(stringToWString(fromUnicode(m_textFind->GetValue(),ENCODING_UTF8)), stringToWString(fromUnicode(m_textRepl->GetValue(),ENCODING_UTF8)));
}

void CFindReplaceDialog::cancel(wxCommandEvent& WXUNUSED(event))
{
    searchEdit->onFindClose();
}

void CFindReplaceDialog::close(wxCloseEvent& WXUNUSED(event))
{
    searchEdit->onFindClose();
}



