/*
 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 Qt.cpp

#include "Qt.h"
#include <fstream>
#include <sstream>
#include <QToolBar>
#ifdef QT5
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPageSetupDialog>
#include <QtPrintSupport/QPrintDialog>
#endif
#ifndef Q_OS_WIN
#include <unistd.h>
#endif
static QList<QAction*>* actionList;
#ifndef QT_NO_PRINTER
static QPrinter* printer;
#if defined(QT5) && defined(Q_OS_MAC)
static QPageSetupDialog* dlg;
static QPrinter::Orientation orientation = QPrinter::Portrait;
#endif
#endif
static CRichEdit* searchEdit;
static CFindDialog* findDlg;
static CFindReplaceDialog* findReplaceDlg;
CMDIFrame* mainFrame;
const bool liveSplit = true;

string convert(const wstring& str);
string toLatin1(const wstring& str);
bool getConfigFolderPath(wstring& path);

#ifdef Q_OS_WIN
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow();
#else
#ifndef Q_OS_MAC
#include <csignal>
void signalHandler(int signum)
{
    wstring path;
    getConfigFolderPath(path);
    QFile::remove(QString::fromStdWString(path + L"lockfile"));
    exit(signum);
}
#endif
#endif

#ifdef _MSC_VER
inline QString fromStdWString(const wstring& wstr)
{
    return sizeof(wchar_t) == sizeof(QChar) ? QString::fromUtf16(reinterpret_cast<const ushort *>(wstr.c_str()), (int)wstr.size())
                                            : QString::fromUcs4(reinterpret_cast<const uint *>(wstr.c_str()), (int)wstr.size());
}
inline wstring toStdWString(const QString& s)
{
    wstring str;
    str.resize(s.length());
#if _MSC_VER >= 1400
    // VS2005 crashes if the string is empty
    if (!s.length())
        return str;
#endif
    str.resize(s.toWCharArray(&(*str.begin())));
    return str;
}
#else
QString fromStdWString(const wstring& wstr)
{
    return QString::fromStdWString(wstr);
}
inline std::wstring toStdWString(const QString& s)
{
    return s.toStdWString();
}
#endif

string convert(const wstring& str)
{
    return toLatin1(str);
}

void aboutMessage(const wstring& msg)
{
#ifdef QT5
    QString title = "À propos de " + ::fromStdWString(appName);
#else
    QString title = "\xC0 propos de " + QString::fromStdWString(appName);
#endif
    QMessageBox::information(mainFrame, title, ::fromStdWString(msg));
}
int yesnocancelMessage(const wstring& msg)
{
    QString title = "Message de " + ::fromStdWString(appName);
    return QMessageBox::warning(mainFrame, title, ::fromStdWString(msg), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
}
bool yesnoMessage(const wstring& msg)
{
    QString title = "Message de " + ::fromStdWString(appName);
    return QMessageBox::warning(mainFrame, title, ::fromStdWString(msg), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes;
}
void errorMessage(const wstring& msg)
{
    QString title = "Message de " + ::fromStdWString(appName);
    QMessageBox::warning(mainFrame, title, ::fromStdWString(msg));
}
void findDialog()
{
    mainFrame->enableMenuItem(EDIT_REPLACE, true);
    if (findReplaceDlg) findReplaceDlg->hide();
    if (findDlg)
    {
        findDlg->init();
    }
}
void findReplaceDialog()
{
    mainFrame->enableMenuItem(EDIT_FIND, true);
    if (findDlg) findDlg->hide();
    if (findReplaceDlg)
    {
        findReplaceDlg->init();
    }
}
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 const char* encodingName(int encoding)
{
	if (encoding == ENCODING_UNIX || encoding == ENCODING_WIN)
    {
        return "ISO 8859-1";
    }
	if (encoding == ENCODING_MAC)
    {
        return "macroman";
    }
    return "UTF-8";
}
unsigned long rgb(int r, int g, int b)
{
    return qRgb(r, g, b);
}
void doSleep(int n)
{
#ifndef Q_OS_WIN
    usleep(n * 1000);
#else
    ::Sleep(n);
#endif

}
void setCursor(int)
{
}
void loadCursors()
{
}
void unloadCursors()
{
}
static string fromUnicode(const wstring& wstr, int code)
{
    QTextCodec* codec = QTextCodec::codecForName(::encodingName(code));
    return codec->fromUnicode(::fromStdWString(wstr)).constData();
}
string toLatin1(const wstring& wstr)
{
	return fromUnicode(wstr, ENCODING_UNIX);
}
string toBytes(const wstring& wstr)
{
#ifdef Q_OS_WIN
    return fromUnicode(wstr, ENCODING_WIN);
#else
	return fromUnicode(wstr, ENCODING_UTF8);
#endif
}
static wstring toUnicode(const string& str, int code)
{
    QTextCodec* codec = QTextCodec::codecForName(::encodingName(code));
    return ::toStdWString(codec->toUnicode(str.c_str()));
}
wstring fromLatin1(const string& str)
{
	return toUnicode(str, ENCODING_UNIX);
}
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)
{
#ifdef Q_OS_WIN
    return toUnicode(str, ENCODING_WIN);
#else
	return toUnicode(str, ENCODING_UTF8);
#endif
}
void removeFileMenuItem(int menuID)
{
    actionList->at(menuID - FILE_NEW)->setVisible(false);
}
void insertFileMenuItem(int menuID, const wstring& menuTitle)
{
    size_t pos = menuTitle.find_last_of(L"/\\");
    actionList->at(menuID - FILE_NEW)->setText(::fromStdWString(menuTitle.substr(pos + 1)));
    actionList->at(menuID - FILE_NEW)->setVisible(true);
}
void insertFileMenuSeparator()
{
}
void removeFileMenuSeparator()
{
}
bool createDirectory(const wstring& dirPath)
{
    QString path = ::fromStdWString(dirPath);
    return QDir().mkpath(path);
}
void deleteFile(const wstring& fileName)
{
    QFile::remove(::fromStdWString(fileName));
}

CMDIApp::CMDIApp(int &argc, char* argv[]): QApplication(argc, argv)
{
#ifdef Q_OS_WIN
	::ShowWindow(::GetConsoleWindow(), SW_HIDE);
#endif
alreadyExists = false;
#ifndef Q_OS_MAC
#ifndef Q_OS_WIN
    signal(SIGINT, signalHandler);
    signal(SIGTERM, signalHandler);
    signal(SIGKILL, signalHandler);
    signal(SIGHUP, signalHandler);
    signal(SIGSEGV, signalHandler);
    signal(SIGBUS, signalHandler);
    signal(SIGABRT, signalHandler);
#endif
    argC = argc;
    argV = argv;
    wstring path;
    if (getConfigFolderPath(path))
    {
        createDirectory(path);
        fstream fs((toBytes(path) + "lockfile").c_str(), fstream::in);
        if (!fs.fail())
        {
            fs.close();
            alreadyExists = true;
        }
        else
        {
            fstream fs1((toBytes(path) + "lockfile").c_str(), fstream::out);
            if (!fs1.fail()) fs1.close();
            alreadyExists = false;
        }
    }
	if (!alreadyExists)
    {
        if (argc == 2 && QString(argv[1]) == "init")
        {
#ifdef QT5
            if (QMessageBox::question(NULL, "WinCaml", "Rétablir les réglages d'origine ?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
#else
            if (QMessageBox::question(NULL, "WinCaml", "R\xE9tablir les r\xE9glages d'origine ?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes)
#endif
            {
                wstring path;
                if (getConfigFolderPath(path))
                {
                    path +=  appName + version + L".txt";
                    deleteFile(path.c_str());
                }
            }
        }
    }
	else
    {
        fstream fs((toBytes(path) + "0").c_str(), fstream::out);
        if (!fs.fail())
        {
            for (int i = 1; i < argc; i++)
            {
#ifdef Q_OS_WIN
				string s(argv[i]);
				string s1;
				string::iterator it;
				for (it=s.begin(); it < s.end(); it++)
				{
					s1 += *it == '\\' ? '/' : *it;
				}
				fs << s1.c_str() << endl;
#else
                fs << argv[i] << endl;
#endif
            }
            fs.close();
            while (!QFile::rename(::fromStdWString(path + L"0"), ::fromStdWString(path + L"1")))
                  ;
        }
    }
#endif
}
CMDIApp::~CMDIApp(){}
int CMDIApp::run(CMDIFrame& frame)
{
    Q_INIT_RESOURCE(WinCaml);
    QString locale = QLocale::system().name();
    QTranslator translator;
	translator.load(QString(":/qt_") + locale);
    installTranslator(&translator);

    frame.setWindowTitle("WinCaml[*]");
#ifndef Q_OS_MAC
    for (int i = 1; i < argC; i++)
    {
#ifdef Q_OS_WIN
		wstring ws = fromBytes(argV[i]);
		wstring ws1;
		wstring::iterator it;
		for (it=ws.begin(); it < ws.end(); it++)
		{
			ws1 += *it == L'\\' ? L'/' : *it;
		}
		frame.openFile(ws1);
#else
		frame.openFile(fromBytes(argV[i]));
#endif
    }
#endif
    frame.show();
	setWindowIcon(QIcon(":/WinCaml.ico"));
	int res = exec();
#ifndef Q_OS_MAC
    wstring path;
    if (getConfigFolderPath(path))
    {
        QFile::remove(::fromStdWString(path + L"lockfile"));
    }
#else
    mdiFrame = &frame;
#endif
    return res;
}
#ifdef Q_OS_MAC
bool CMDIApp::event(QEvent* event)
{
    switch (event->type())
    {
    case QEvent::ApplicationActivate:
        if (QDir::currentPath() == "/") QDir::setCurrent(qApp->applicationDirPath() + "/../../..");
        return QApplication::event(event);
    case QEvent::FileOpen:
        mdiFrame->openFile(static_cast<QFileOpenEvent *>(event)->file().toStdWString());
        if (mdiFrame->isIconic())
        {
            mdiFrame->openIcon();
        }
        return true;
    default:
        return QApplication::event(event);
    }
}
#endif
CMDIFrame::CMDIFrame()
{
    windowMenu = NULL;
    cascade = true;
    findDlg = NULL;
    findReplaceDlg = NULL;
    actionList = new QList<QAction*>();
    createMDIClient();
    droppedFiles = new deque<wstring*>();
    setAcceptDrops(true);
    frameLeft = 50;
    frameTop = 50;
    frameWidth = 800;
    frameHeight = 600;
    createMenus();
    createToolbar();
    createStatusbar();
    findDlg = new CFindDialog(this);
    findReplaceDlg = new CFindReplaceDialog(this);
#ifndef QT_NO_PRINTER
#if defined(QT5) && defined(Q_OS_MAC)
    dlg = new QPageSetupDialog(this);
    printer = dlg->printer();
#endif
#endif
    mainFrame = this;
	startTimer();
}
CMDIFrame::~CMDIFrame()
{
}
void CMDIFrame::createMDIClient()
{
    mdiArea = new QMdiArea();
    mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    mdiArea->setActivationOrder(QMdiArea::StackingOrder);
    setCentralWidget(mdiArea);
    connect(mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(onActivate(QMdiSubWindow*)));
    windowMapper = new QSignalMapper(this);
    connect(windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*)));
}
void CMDIFrame::startTimer()
{
    QTimer* timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()));
    timer->start(100);
}
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();
        if (isMinimized())
        {
            openIcon();
        }
        else
        {
            onOtherInstanceMessage();
        }
    }
}
void CMDIFrame::createMenus()
{
	enum{FILE, EDIT, VIEW, COLOR, ENCODING, CAML, CAMLTOP, OUTPUT, WINDOW, HELP};
#ifdef Q_OS_MAC
#define FR_SHORTCUT "Ctrl+R"
#else
#define FR_SHORTCUT "Ctrl+H"
#endif
#ifdef QT5
    QString menuNames[][2] =
    {
		{"&Fichier", ""}, {"&Nouveau\t", "Ctrl+N"}, {"&Inclure... \t", "Ctrl+I"}, {"&Ouvrir...\t", "Ctrl+O"}, {"&Fermer",  ""}, {"&Enregistrer\t", "Ctrl+S"}, {"En&registrer sous...", ""}, {"Enre&gistrer au format ODF...", ""}, {"_" , ""}, {"Im&primer...\t", "Ctrl+P"}, {"Mise en p&age...",  ""}, {"_",  ""}, {"MRU1",  ""}, {"MRU2", ""}, {"MRU3", ""}, {"MRU4",  ""}, {"MRU5",  ""}, {"MRU6",  ""}, {"MRU7",  ""}, {"MRU8",  ""}, {"_",  ""}, {"&Quitter",  ""}, {"/",  ""},
        {"É&dition",  ""}, {"Annuler",  ""}, {"Rétablir",  ""}, {"_",  ""}, {"&Couper\t", "Ctrl+X"}, {"Cop&ier\t", "Ctrl+C"}, {"C&oller\t", "Ctrl+V"}, {"Tout &sélectionner\t", "Ctrl+A"}, {"_",  ""}, {"Rec&hercher...\t", "Ctrl+F"}, {"Rechercher et R&emplacer...\t", FR_SHORTCUT}, {"_",  ""}, {"Indentation par tabulations",  ""}, {"Nombre d'espaces par tabulation...",  ""}, {"Indenter après in",  ""}, {"Indenter les filtres",  ""}, {"Utiliser l'indenteur pour ocaml",  ""}, {"_",  ""}, {"Inde&nter\t", "Ctrl+J"}, {"/", ""},
        {"&Affichage",  ""}, {"Cloison verticale",  ""}, {"Panneau d'entrée seul",  ""}, {"Panneau de sortie seul",  ""}, {"Les deux panneaux", ""}, {"_", ""}, {"Police de caractères en entrée...", ""}, {"Police de caractères en sortie...", ""}, {"_", ""}, {"Retour à la ligne en entrée", ""}, {"Retour à la ligne en sortie", ""}, {"_", ""}, {"Coloration syntaxique", ""}, {"_", ""}, {"&Barre d'outils", ""}, {"Barre d'é&tat", ""}, {"/", ""},
        {"&Couleurs", ""}, {"Tampon d'entrée...", ""}, {"Commandes en entrée...", ""}, {"Commandes en sortie...", ""}, {"_", ""}, {"Nombres...", ""}, {"Mots clés...", ""}, {"Délimiteurs...", ""}, {"Opérateurs...", ""}, {"Chaînes...", ""}, {"Commentaires...", ""}, {"/", ""},
		{"&Encodage", ""}, {"Unix", ""}, {"Mac", ""}, {"Win", ""}, {"Utf-8", ""}, {"_",  ""}, {"Auto", ""}, {"/", ""},
        {"Ca&ml", ""}, {"&Envoyer\t", "Ctrl+Ret"}, {"Envoyer la sélection", ""}, {"&Interrompre\t", "Ctrl+K"}, {"&Stop", ""}, {"E&ffacer la sortie", ""}, {"/", ""},
        {"Cam&lTop", ""}, {"Caml Light", ""}, {"OCaml", ""}, {"_", ""}, {"Démarrage différé", ""}, {"/", ""},
        {"&Sortie", ""}, {"Simple", ""}, {"Abrégée", ""}, {"Complète", ""}, {"/", ""},
		{"Fe&nêtre", ""}, {"&Cascade", ""}, {"&Mosaïque", ""}, {"/", ""},
        {"A&ide", ""}, {"&Documentation de Caml-light", ""}, {"D&ocumentation de OCaml", ""}, {"_", ""}, {"&Réglages par défaut", ""}, {"_", ""}, {"À &propos de WinCaml...", ""}, {"/", ""},
        {"", ""}
    };
#else
    QString menuNames[][2] =
    {
        {"&Fichier", ""}, {"&Nouveau\t", "Ctrl+N"}, {"&Inclure... \t", "Ctrl+I"}, {"&Ouvrir...\t", "Ctrl+O"}, {"&Fermer",  ""}, {"&Enregistrer\t", "Ctrl+S"}, {"En&registrer sous...", ""}, {"Enre&gistrer au format ODF...", ""}, {"_" , ""}, {"Im&primer...\t", "Ctrl+P"}, {"Mise en p&age...",  ""}, {"_",  ""}, {"MRU1",  ""}, {"MRU2", ""}, {"MRU3", ""}, {"MRU4",  ""}, {"MRU5",  ""}, {"MRU6",  ""}, {"MRU7",  ""}, {"MRU8",  ""}, {"_",  ""}, {"&Quitter",  ""}, {"/",  ""},
        {"\xC9""&dition",  ""}, {"Annuler",  ""}, {"R\xE9tablir",  ""}, {"_",  ""}, {"&Couper\t", "Ctrl+X"}, {"Cop&ier\t", "Ctrl+C"}, {"C&oller\t", "Ctrl+V"}, {"Tout &s\xE9lectionner\t", "Ctrl+A"}, {"_",  ""}, {"Rec&hercher...\t", "Ctrl+F"}, {"Rechercher et R&emplacer...\t", FR_SHORTCUT}, {"_",  ""}, {"Indentation par tabulations",  ""}, {"Nombre d'espaces par tabulation...",  ""}, {"Indenter apr\xE8s in",  ""}, {"Indenter les filtres",  ""}, {"Utiliser l'indenteur pour ocaml",  ""}, {"_",  ""}, {"Inde&nter\t", "Ctrl+J"}, {"/", ""},
        {"&Affichage",  ""}, {"Cloison verticale",  ""}, {"Panneau d'entr\xE9""e seul",  ""}, {"Panneau de sortie seul",  ""}, {"Les deux panneaux", ""}, {"_", ""}, {"Police de caract\xE8res en entr\xE9""e...", ""}, {"Police de caract\xE8res en sortie...", ""}, {"_", ""}, {"Retour \xE0 la ligne en entr\xE9""e", ""}, {"Retour \xE0 la ligne en sortie", ""}, {"_", ""}, {"Coloration syntaxique", ""}, {"_", ""}, {"&Barre d'outils", ""}, {"Barre d'\xE9&tat", ""}, {"/", ""},
        {"&Couleurs", ""}, {"Tampon d'entr\xE9""e...", ""}, {"Commandes en entr\xE9""e...", ""}, {"Commandes en sortie...", ""}, {"_", ""}, {"Nombres...", ""}, {"Mots cl\xE9s...", ""}, {"D\xE9limiteurs...", ""}, {"Op\xE9rateurs...", ""}, {"Cha\xEEnes...", ""}, {"Commentaires...", ""}, {"/", ""},
        {"&Encodage", ""}, {"Unix", ""}, {"Mac", ""}, {"Win", ""}, {"Utf-8", ""}, {"_",  ""}, {"Auto", ""}, {"/", ""},
        {"Ca&ml", ""}, {"&Envoyer\t", "Ctrl+Ret"}, {"Envoyer la s\xE9lection", ""}, {"&Interrompre\t", "Ctrl+K"}, {"&Stop", ""}, {"E&ffacer la sortie", ""}, {"/", ""},
        {"Cam&lTop", ""}, {"Caml Light", ""}, {"OCaml", ""}, {"_", ""}, {"D\xE9marrage diff\xE9r\xE9", ""}, {"/", ""},
        {"&Sortie", ""}, {"Simple", ""}, {"Abr\xE9g\xE9""e", ""}, {"Compl\xE8te", ""}, {"/", ""},
        {"Fe&n\xEAtre", ""}, {"&Cascade", ""}, {"&Mosa\xEFque", ""}, {"/", ""},
        {"A&ide", ""}, {"&Documentation de Caml-light", ""}, {"D&ocumentation de OCaml", ""}, {"_", ""}, {"&R\xE9glages par d\xE9""faut", ""}, {"_", ""}, {"\xC0 &propos de WinCaml...", ""}, {"/", ""},
        {"", ""}
    };
#endif
    int cmd = FILE_NEW;
    QSignalMapper* signalMapper = new QSignalMapper(this);
    connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(onCommandAux(int)));
    for (int i = 0, m = 0; menuNames[i][0] != ""; m++)
    {
        int j;
        QMenu* menu = menuBar()->addMenu(menuNames[i][0]);
        if (m == WINDOW)
        {
            windowMenu = menu;
        }
        for (j = i + 1; menuNames[j][0] != "/"; j++)
        {
            if (menuNames[j][0] != "_")
            {

//#if defined(Q_OS_MAC) && defined(QT5) || (defined(Q_OS_LINUX) && defined(QT4_8))
#if (defined(Q_OS_LINUX) && defined(QT4_8))
                QAction* action = new QAction(menuNames[j][0], this);

#else

                QAction* action = new QAction(menuNames[j][0] + menuNames[j][1], this);
#endif
               QString s = menuNames[j][1];
               if (s != "" && s != "Ctrl+Ret")
                    action->setShortcut(s);
                actionList->append(action);
                menu->addAction(action);
                signalMapper->setMapping(action, cmd);
                connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
                cmd++;
            }
            else
            {
                menu->addSeparator();
            }
        }
        i = j + 1;
    }
    actionList->at(EDIT_UNDO - FILE_NEW)->setShortcuts(QKeySequence::Undo);
    actionList->at(EDIT_REDO - FILE_NEW)->setShortcuts(QKeySequence::Redo);
    actionList->at(CAML_SEND - FILE_NEW)->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return));
    connect(windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));
}
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};

	QString icons[] = {"new.png", "open.png", "save.png", "print.png","cut.png", "copy.png", "paste.png",
					   "hv.png", "inout.png", "in.png", "out.png", "wrapin.png", "wrapout.png",
					   "send.png", "indent.png", "interrupt.png", "stop.png", "clear.png", "about.png"};
	toolbar = addToolBar("WinCaml");
    toolbar->setIconSize(QSize(20, 15));
    toolbar->setMovable(false);
    toolbar->setFloatable(false);

    for(int i = 0, j = 0, k = 0; commands[i] != 0; i++)
    {
        for(j = i; commands[j] != -1 && commands[j] != 0; j++)
        {
            QAction* action = actionList->at(commands[j] - FILE_NEW);
			action->setIcon(QIcon(":/" + icons[k++]));
			toolbar->addAction(action);
        }
        if (commands[j] == -1)
        {
            toolbar->addSeparator();
            i = j;
        }
    }
}
void CMDIFrame::createStatusbar()
{
    for (int i = 0; i < 2; i++)
    {
        statusBar()->addWidget(&status[i]);
        status[i].setText("");
    }
}
void CMDIFrame::updateFrame()
{
	toolbar->setVisible(ToolbarVisible);
	statusBar()->setVisible(StatusBarVisible);
}
bool CMDIFrame::isIconic()
{
	return isMinimized();
}
void CMDIFrame::openIcon()
{
	raise();
	setWindowState(Qt::WindowActive);
}
void CMDIFrame::moveWindow(int left, int top, int width, int height)
{
	move(left, top);
	resize(width, height);
}
CMDIChildFrame *CMDIFrame::getActiveChild()
{
	if (QMdiSubWindow *activeSubWindow = mdiArea->activeSubWindow())
	{
		return (CMDIChildFrame *)activeSubWindow->widget();
	}
	return NULL;
}
void CMDIFrame::setActiveChild(CMDIChildFrame *childFrame)
{
	foreach (QMdiSubWindow *window, mdiArea->subWindowList())
	{
		if (window->widget() == childFrame)
		{
			mdiArea->setActiveSubWindow(window);
			break;
		}
	}
}
void CMDIFrame::setActiveSubWindow(QWidget *window)
{
	QMdiSubWindow *subWindow = qobject_cast<QMdiSubWindow *>(window);
	if (!subWindow)
	{
		return;
	}
	mdiArea->setActiveSubWindow(subWindow);
}
void CMDIFrame::enableMenuItem(int cmd, bool on)
{
	actionList->at(cmd - FILE_NEW)->setEnabled(on);
}
void CMDIFrame::checkMenuItem(int cmd, bool on)
{
	actionList->at(cmd - FILE_NEW)->setCheckable(true);
	actionList->at(cmd - FILE_NEW)->setChecked(on);
}
void CMDIFrame::setMenuItemText(int cmd,  const wstring& title, bool enabled)
{
    actionList->at(cmd - FILE_NEW)->setText(::fromStdWString(title));
    actionList->at(cmd - FILE_NEW)->setEnabled(enabled);
}
void CMDIFrame::setStatus(int index, const wstring& text)
{
#ifdef Q_OS_MAC
	QFont font(status[index].font().family(), 10);
	status[index].setFont(font);
#endif
    status[index].setText(::fromStdWString(text));
    status[index].update();
}
void CMDIFrame::updateWindowMenu()
{
    if (windowMenu == NULL) return;

    windowMenu->clear();
    windowMenu->addAction(actionList->at(WINDOW_CASCADE - FILE_NEW));
    windowMenu->addAction(actionList->at(WINDOW_TILE - FILE_NEW));

    QList<QMdiSubWindow *> windowList = mdiArea->subWindowList();
    if (!windowList.isEmpty())
    {
        windowMenu->addSeparator();
        for (int i = 0; i < windowList.size(); ++i)
        {
            CMDIChildFrame *childFrame = (CMDIChildFrame *)windowList.at(i)->widget();
            size_t pos = childFrame->title.find_last_of(L"/\\");
            QString text = QString("%1 %2").arg(i + 1).arg(::fromStdWString(childFrame->title.substr(pos + 1)));
            QAction *action  = windowMenu->addAction(text);
            action->setCheckable(true);
			action->setChecked(childFrame == getActiveChild());
            connect(action, SIGNAL(triggered()), windowMapper, SLOT(map()));
            windowMapper->setMapping(action, windowList.at(i));
        }
    }
}
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(int cmd)
{
    onCommand(cmd);
    QLineEdit* ctrl = NULL;
    if (findDlg && findDlg->isEnabled() && findDlg->lineEdit1->hasFocus())
    {
        ctrl = findDlg->lineEdit1;
    }
    else if (findReplaceDlg && findReplaceDlg->isEnabled())
    {
        if (findReplaceDlg->lineEdit1->hasFocus())
        {
            ctrl = findReplaceDlg->lineEdit1;
        }
        else if (findReplaceDlg->lineEdit2->hasFocus())
        {
            ctrl = findReplaceDlg->lineEdit2;
        }
    }
    if (ctrl)
    {
        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()
{
    cascade = true;
	Maximized = false;
    mdiArea->cascadeSubWindows();
	int w = width();
	int h = height();
    foreach (QMdiSubWindow *window, mdiArea->subWindowList())
    {
		window->resize(w * 3 / 4, h * 2 / 3);
    }
}
void CMDIFrame::onTileWindow()
{
	cascade = false;
	mdiArea->tileSubWindows();
	Maximized = false;
}
void CMDIFrame::dragEnterEvent(QDragEnterEvent *event)
{
	if (event->mimeData()->hasUrls())
		event->acceptProposedAction();
}
void CMDIFrame::dropEvent(QDropEvent *event)
{
	foreach (QUrl url, event->mimeData()->urls())
	{
        droppedFiles->push_back(new wstring(::toStdWString(url.toLocalFile())));
    }
	onDrop();
}
void CMDIFrame::resizeEvent(QResizeEvent *event)
{
    onSize();
    frameWidth = event->size().width();
    frameHeight = event->size().height();
}
void CMDIFrame::moveEvent(QMoveEvent *)
{
    frameLeft = pos().x();
    frameTop = pos().y();
}
void CMDIFrame::closeEvent(QCloseEvent* event)
{
    if (reviewChanges())
    {
        event->ignore();
#if defined(Q_OS_MAC) && defined(QT5_0)
        hide();
        QTimer::singleShot(0,this,SLOT(show()));
#endif
        return;
    }
    onClose();
    mdiArea->closeAllSubWindows();
    QMainWindow::closeEvent(event);
}
void CMDIFrame::onDrop()
{
}
void CMDIFrame::onClose()
{
}
void CMDIFrame::onMove(size_t left, size_t top)
{
	frameLeft = (long)left;
	frameTop = (long)top;
}
void CMDIFrame::onSize()
{
}
void CMDIFrame::onActivate(QMdiSubWindow*)
{
	if (getActiveChild())
	{
		getActiveChild()->onActivate();
	}
}
void CMDIFrame::onFileClose()
{
	CMDIChildFrame* activeFrame = getActiveChild();
	if (activeFrame)
	{
		if (activeFrame->reviewChange()) return;
        mdiArea->removeSubWindow(activeFrame->subWindow);
        activeFrame->onClose();
		activeFrame = getActiveChild();
		if (activeFrame && Maximized)
			activeFrame->showMaximized();
	}
}
void CMDIFrame::onFileExit()
{
    if (reviewChanges()) return;
	onClose();
	qApp->exit();
}
bool CMDIFrame::reviewChanges()
{
	return false;
}
void CMDIFrame::colorDialog(unsigned long& color)
{
    QColor c(color);
	c = QColorDialog::getColor(c, this, "Couleurs", QColorDialog::DontUseNativeDialog);
    if (c.isValid()) color = c.rgb();
}
void CMDIFrame::tabDialog(int& spaceNumPerTab)
{
    bool ok;
	int i = QInputDialog::getInt(this, "", "Nombre d'espaces par tabulation:", spaceNumPerTab, 0, 8, 1, &ok);
    if (ok) spaceNumPerTab = i;
}
bool CMDIFrame::openFileDialog(wstring& fileName)
{
    QString filter = "(*.ml *.oml *.mli)";
    QString fName = QFileDialog::getOpenFileName(this, "", "", filter, 0);
    fileName = ::toStdWString(fName);
    return fName != "";
}
bool CMDIFrame::saveFileDialog(wstring& title)
{
    QString filter = "(*.ml *.oml *.mli)";
    QString s = QFileDialog::getSaveFileName(this, "Enregistrer sous", ::fromStdWString(title), filter, &filter);
    if (s.isEmpty())
    {
        return false;
    }
    title = ::toStdWString(s);
    return true;
}
bool CMDIFrame::saveFormattedDocumentDialog(wstring& title)
{
    QString filter = "(*.odf)";
    QString s = QFileDialog::getSaveFileName(this, "Enregistrer sous", ::fromStdWString(title), filter, &filter);
    if (s.isEmpty())
    {
        return false;
    }
    title = ::toStdWString(s);
    return true;
}
void CMDIFrame::printSetUpDialog(int& leftMargin, int& topMargin, int& rightMargin, int& bottomMargin)
{
#ifndef QT_NO_PRINTER
#if defined(QT5) && defined(Q_OS_LINUX)
    QMessageBox::information(mainFrame, "WinCaml", "Le dialogue de mise en page est accessible à partir du dialogue d'impression");
    return;
#endif
#if defined(QT5) && defined(Q_OS_MAC)
    qreal left, top, right, bottom;
    left = 0.005 + leftMargin;
    top = 0.005 + topMargin;
    right = 0.005 + rightMargin;
    bottom = 0.005 + bottomMargin;
    printer->setPageMargins(left, top, right, bottom, QPrinter::Millimeter);
    printer->setOrientation(orientation);
    if (dlg->exec() == QDialog::Accepted)
    {
        printer->getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter);
        leftMargin = (int)(left + 0.005);
        topMargin = (int)(top + 0.005);
        rightMargin = (int)(right + 0.005);
        bottomMargin = (int)(bottom + 0.005);
        orientation = printer->orientation();
    }
#else
    if (!printer) printer = new QPrinter(QPrinter::HighResolution);
    qreal left, top, right, bottom;
    left = 0.005 + leftMargin;
    top = 0.005 + topMargin;
    right = 0.005 + rightMargin;
    bottom = 0.005 + bottomMargin;
    printer->setPageMargins(left, top, right, bottom, QPrinter::Millimeter);
    QPageSetupDialog *dlg = new QPageSetupDialog(printer, this);
	dlg->setWindowTitle("Mise en page");
    if (dlg->exec() == QDialog::Accepted)
    {
        printer->getPageMargins(&left, &top, &right, &bottom, QPrinter::Millimeter);
        leftMargin = (int)(left + 0.005);
        topMargin = (int)(top + 0.005);
        rightMargin = (int)(right + 0.005);
        bottomMargin = (int)(bottom + 0.005);
    }
    delete dlg;
#endif
#endif
}
void CMDIFrame::fontDlg(CFont*& font)
{
#ifdef QT5
	QFont f = QFontDialog::getFont(NULL, *font->qfont, (QWidget*)this, "Police en entrée", 0);
#else
    QFont f = QFontDialog::getFont(NULL, *font->qfont, (QWidget*)this, "Police en entr\xE9""e", 0);
#endif
    QList<QMdiSubWindow*> windowList = mdiArea->subWindowList(QMdiArea::StackingOrder);
    if (!windowList.isEmpty() && !mainFrame->getActiveChild())
    {
        mdiArea->setActiveSubWindow(windowList.last());
    }
    font = new CFont(::toStdWString(f.family()), f.pointSize(), f.bold(), f.italic());
    font->qfont = new QFont(f);
}

CMDIChildFrame::CMDIChildFrame(CMDIFrame* mdiFrame, bool maximized)
{
	saveMaximized = maximized;
    setMouseTracking(true);
	subWindow = mdiFrame->mdiArea->addSubWindow(this);
    subWindow->resize(600, 400);
	subWindow->setWindowIcon(QIcon(":/WinCamlDoc.png"));
	setAttribute(Qt::WA_DeleteOnClose);
}
CMDIChildFrame::~CMDIChildFrame()
{
}
void CMDIChildFrame::setTitle(const wstring& title)
{
    QWidget::setWindowTitle(::fromStdWString(title.substr(title.find_last_of(L"/\\") + 1)) + "[*]");
}
void CMDIChildFrame::drawFocusRect(int, int, int, int)
{
}
void CMDIChildFrame::getClientSize(int& w, int& h)
{
	w = width();
	h = height();
}
void CMDIChildFrame::releaseCapture()
{
}
void CMDIChildFrame::setCapture()
{
}
void CMDIChildFrame::showNormal()
{
    QWidget::showNormal();
}
void CMDIChildFrame::showDefault()
{
    QWidget::showMaximized();
}
void CMDIChildFrame::showMaximized()
{
    QWidget::showMaximized();
}
void CMDIChildFrame::hide()
{
	QWidget::setVisible(false);
}
bool CMDIChildFrame::isMaximized()
{
	if (saveMaximized)
	{
		saveMaximized = false;
		return true;
	}
	return QWidget::isMaximized();
}
void CMDIChildFrame::setCursor(int cursor)
{
	QWidget::setCursor((Qt::CursorShape)cursor);
}
void CMDIChildFrame::setWindowModified(bool modified)
{
	QWidget::setWindowModified(modified);
}
void CMDIChildFrame::onCommand(int)
{
}
void CMDIChildFrame::onFileSaveAs()
{
}
void CMDIChildFrame::onEditCut()
{
}
void CMDIChildFrame::onEditCopy()
{
}
void CMDIChildFrame::onEditPaste()
{
}
void CMDIChildFrame::onEditSelectAll()
{
}
void CMDIChildFrame::startTimer()
{
    timer = new QTimer(this);
	connect(timer, SIGNAL(timeout()), this, SLOT(onTimer()));
	timer->start(20);
}
void CMDIChildFrame::resizeEvent(QResizeEvent*)
{
	onSize();
}
void CMDIChildFrame::mouseMoveEvent(QMouseEvent *event)
{
    bool leftButtonDown = (event->buttons() & Qt::LeftButton) ==  Qt::LeftButton;
    onMouseMove(event->x(), event->y(), leftButtonDown);
}
void CMDIChildFrame::mousePressEvent(QMouseEvent *event )
{
    bool leftButtonDown = (event->buttons() & Qt::LeftButton) ==  Qt::LeftButton;
    if (leftButtonDown)
        onLeftButtonDown(event->x(), event->y());
}
void CMDIChildFrame::mouseReleaseEvent(QMouseEvent * )
{
    onLeftButtonUp();
}
void CMDIChildFrame::closeEvent(QCloseEvent *event)
{
	if (reviewChange()) {event->ignore(); return;}
	onClose();
	QWidget::closeEvent(event);
}
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()
{
   onDestroy();
}
void CMDIChildFrame::onDestroy()
{
    if (timer)
    {
        timer->stop();
        delete timer;
        timer = NULL;
    }
}
bool CMDIChildFrame::reviewChange()
{
    return false;
}

CRichEdit::CRichEdit(CMDIChildFrame* win): QPlainTextEdit(win)
{
	childFrame = win;
    setAcceptDrops(false);
    setLineWrapMode(NoWrap);
    setUndoRedoEnabled(false);
	setMouseTracking(true);
	selectionChanged = true;
    show();
}
CRichEdit::~CRichEdit()
{
}
void CRichEdit::move(int left, int top, int width, int height)
{
	QPlainTextEdit::move(left, top);
	resize(width, height);
}
void CRichEdit::mouseReleaseEvent(QMouseEvent *event)
{
    bool ctrlKeyDown = (event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier;
    onLeftButtonUp(ctrlKeyDown);
	QPlainTextEdit::mouseReleaseEvent(event);
}
void CRichEdit::mouseMoveEvent(QMouseEvent *event)
{
	childFrame->setCursor(Qt::ArrowCursor);
	QPlainTextEdit::mouseMoveEvent(event);
}
void CRichEdit::keyPressEvent(QKeyEvent *event)
{
	if (event->matches(QKeySequence::Undo))
	{
		undo();
		return;
	}
	if (event->matches(QKeySequence::Redo))
	{
		redo();
		return;
	}
	onKeyDown();
	onChar(event->key());
	if (event->key() == Qt::Key_Return) onReturnKeyDown();
	else QPlainTextEdit::keyPressEvent(event);
}
void CRichEdit::keyReleaseEvent(QKeyEvent* event)
{
	onKeyUp();
	QPlainTextEdit::keyReleaseEvent(event);
}
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)
{
    selStart = textCursor().selectionStart();
    selEnd = textCursor().selectionEnd();
}
void CRichEdit::setSelection(size_t selStart, size_t selEnd)
{
    size_t len = toPlainText().length();
    if (selStart > len)
    {
        selStart = selEnd = len;
    }
    else if (selEnd > len)
    {
        selEnd = len;
    }
    QTextCursor cursor = textCursor();
    cursor.setPosition((int)selStart);
    cursor.setPosition((int)selEnd, QTextCursor::KeepAnchor);
    setTextCursor(cursor);
}
void CRichEdit::setUseTabs(bool)
{
}
void CRichEdit::selectAll()
{
    QTextCursor tc = textCursor();
    tc.select(QTextCursor::Document);
    setTextCursor(tc);
}
void CRichEdit::replace(size_t a, size_t l, wstring s)
{
    setText(a, l, s);
}
void CRichEdit::replaceAll(const wstring& findWhat, const wstring& replaceWith, unsigned long flags)
{
    if (isReadOnly()) return;
    size_t pos = 0;
    setSelection(0, 0);
    for(;;)
    {
        QTextCursor tc = document()->find(::fromStdWString(findWhat), textCursor(), (QTextDocument::FindFlags)(uint)flags);
        if (tc.isNull()) break;
        tc.insertText(::fromStdWString(replaceWith));
        pos = tc.position();
    }
    setSelection(pos, pos);
}
size_t CRichEdit::getCaretPosition()
{
    return textCursor().selectionEnd();
}
void CRichEdit::hideSelection()
{
}
void CRichEdit::showSelection()
{
}
size_t CRichEdit::getTextLength()
{
    QString text = toPlainText();
    return text.length();
}
wstring CRichEdit::getText()
{
    QString text = toPlainText();
    return ::toStdWString(text);

}
wstring CRichEdit::getText(size_t start, size_t length)
{
    QString text = toPlainText();
    return ::toStdWString(text.mid((int)start, (int)length));
}
void CRichEdit::setText(size_t start, size_t length, const wstring& text, unsigned long color)
{
    QTextCursor crs = textCursor();
    crs.setPosition((int)start);
    crs.setPosition((int)(start + length), QTextCursor::KeepAnchor);
    QTextCharFormat cf;
    cf.setForeground(QColor(color));
    setTextCursor(crs);
    crs.insertText(::fromStdWString(text), cf);
}
void CRichEdit::setSelectedText(const wstring& s)
{
    int a = textCursor().selectionStart();
    int l = textCursor().selectionEnd() - a;
    setText(a, l, s);
    QTextCursor crs = textCursor();
    crs.setPosition(a);
    crs.setPosition(a + (int)s.length(), QTextCursor::KeepAnchor);
}
void CRichEdit::setTabs(int, int spaceCountPerTab)
{
    QFontMetrics fm = fontMetrics();
    int w = fm.averageCharWidth();
    setTabStopWidth(w * spaceCountPerTab);
}
size_t CRichEdit::visibleTextOffset()
{
    return firstVisibleBlock().position();
}
size_t CRichEdit::visibleTextEnd()
{
    return cursorForPosition(viewport()->rect().bottomRight()).position();
}
void CRichEdit::suspendLayout()
{
    textCursor().beginEditBlock();
}
void CRichEdit::resumeLayout()
{
    textCursor().endEditBlock();
}
void CRichEdit::updateView()
{
    update();
}
void CRichEdit::setTextColor(size_t a, size_t l, unsigned long c)
{
    QTextCursor crs = textCursor();
    crs.setPosition((int)a);
    crs.setPosition((int)(a + l), QTextCursor::KeepAnchor);
    QTextCharFormat cf;
    cf.setForeground(QColor(c));
    crs.mergeCharFormat(cf);
}
void  CRichEdit::setBackground(unsigned long color)
{
    setTextBackground(0, toPlainText().length(), color);
}
void CRichEdit::setTextBackground(size_t a, size_t l, unsigned long c)
{
    QTextCursor crs = textCursor();
    crs.setPosition((int)a);
    crs.setPosition((int)(a + l), QTextCursor::KeepAnchor);
    QTextCharFormat cf;
    cf.setBackground(QColor(c));
    crs.mergeCharFormat(cf);
}
void CRichEdit::setTextDefaultBackground(size_t a, size_t l)
{
    setTextBackground(a, l, 0xFFFFFFFF);
}
void CRichEdit::setColors()
{
    
}
void CRichEdit::cut()
{
    QPlainTextEdit::cut();
}
void CRichEdit::copy()
{
    QPlainTextEdit::copy();
}
void CRichEdit::paste()
{
    QPlainTextEdit::paste();
}
int CRichEdit::loadFile(const wstring& fileName, bool guessEnc, int &preferredEncoding)
{
    QString fName = ::fromStdWString(fileName);
    QFile file(fName);
    if (!file.open(QFile::ReadOnly))
    {
        return 0;
    }
    QByteArray bA = file.readAll();
    QString str;
    if (guessEnc)
    {
        QTextCodec* codec = QTextCodec::codecForName("UTF-8");
        str = codec->toUnicode(bA);
        string ba = bA.data();
		int encoding = ENCODING_UTF8;
        if (str.length() >= bA.size())
        {
            encoding = guessEncoding(ba, preferredEncoding);
			codec = QTextCodec::codecForName(::encodingName(encoding));
            str = codec->toUnicode(bA);
        }
        preferredEncoding = encoding;
    }
    else
    {
		QTextCodec* codec = QTextCodec::codecForName(::encodingName(preferredEncoding));
        str = codec->toUnicode(bA);
    }
    setPlainText(str);

    QTextCursor cursor = textCursor();
    cursor.setPosition(toPlainText().length());
    setTextCursor(cursor);
    ensureCursorVisible();

    return 1;
}
int CRichEdit::appendFile(const wstring& fileName, int encoding)
{
    QString fName = ::fromStdWString(fileName);
    QFile file(fName);

    if (!file.open(QFile::ReadOnly))
    {
		QMessageBox::warning(this, "WinCaml", QString("Impossible de lire le fichier %1:\n%2.").arg(fName).arg(file.errorString()));
        return 0;
    }
    QByteArray bA = file.readAll();
	QTextCodec* codec = QTextCodec::codecForName(::encodingName(encoding));
    QString str = codec->toUnicode(bA);
    appendPlainText(str);
    file.close();
    return 1;
}
int CRichEdit::saveFile(const wstring& fileName, int encoding)
{
    QString fName = QString::fromStdWString(fileName);
    QFile file(fName);
    if (!file.open(QFile::WriteOnly))
    {
        QMessageBox::warning(this, "WinCaml", QString("Impossible d'enregistrer le fichier %1:\n%2.").arg(fName).arg(file.errorString()));
        return 0;
    }
	QTextCodec* codec= QTextCodec::codecForName(::encodingName(encoding));
    QByteArray bA = codec->fromUnicode(toPlainText());
	if (encoding == ENCODING_WIN)
    {
        bA.replace('\n', "\r\n");
    }
    file.write(bA);
    return 1;
}
void CRichEdit::focus()
{
}
void CRichEdit::setReadOnly(bool b)
{
    QPlainTextEdit::setReadOnly(b);
}
void CRichEdit::updateCursor()
{
    horizontalScrollBar()->setCursor(ARROW);
    verticalScrollBar()->setCursor(ARROW);
}
wstring CRichEdit::status()
{
	return L"";
}
void CRichEdit::saveFormattedDocument(const wstring& fileName)
{
    QTextDocumentWriter docWriter;
    docWriter.setFileName(::fromStdWString(fileName));
    docWriter.setFormat("odf");
	docWriter.write(document());
}
void CRichEdit::beginPrint()
{
}
void CRichEdit::endPrint()
{
}
void CRichEdit::printFormattedDialog()
{
#ifndef QT_NO_PRINTER
    if (!printer) printer = new QPrinter(QPrinter::HighResolution);
    QPrintDialog *dlg = new QPrintDialog(printer, this);
    dlg->setOption(QAbstractPrintDialog::PrintPageRange, false);
    if (textCursor().hasSelection())
    {
        dlg->setOption(QAbstractPrintDialog::PrintSelection, true);
    }
	else
	{
		dlg->setOption(QAbstractPrintDialog::PrintSelection, false);
		dlg->setPrintRange(QAbstractPrintDialog::AllPages);
	}
	dlg->setWindowTitle("Imprimer");
    if (dlg->exec() == QDialog::Accepted)
    {
        beginPrint();
		LineWrapMode lwm = lineWrapMode();
        setLineWrapMode(QPlainTextEdit::WidgetWidth);
        print(printer);
        setLineWrapMode(lwm);
        endPrint();
    }
    delete dlg;
#endif
}
void CRichEdit::setWrapping(bool on)
{
	setLineWrapMode(on ? WidgetWidth : NoWrap);
}
size_t CRichEdit::lineFromChar(size_t charIndex)
{
	return document()->findBlock((int)charIndex).firstLineNumber();
}
size_t CRichEdit::lineFirstChar(size_t lineIndex)
{
	return document()->findBlockByNumber((int)lineIndex).position();
}
void CRichEdit::setFont(CFont* font)
{
    QPlainTextEdit::setFont(*font->qfont);
}
void CRichEdit::onFindNext(const wstring& findWhat, QTextDocument::FindFlags flags)
{
    QTextCursor tc = document()->find(::fromStdWString(findWhat), textCursor(), flags);
    if (!tc.isNull())
    {
        setTextCursor(tc);
    }
    else
    {
#ifdef QT5
		QMessageBox::information(this, "WinCaml", "Recherche terminée!");
#else
        QMessageBox::information(this, "WinCaml", "Recherche termin\xE9""e!");
#endif
    }
}
void CRichEdit::onReplace(const wstring&)
{
}
void CRichEdit::onReplaceAll(const wstring&, const wstring&, unsigned long)
{
}
void CRichEdit::onFindClose()
{
	closeFindDialog(true);
}

CFindDialog::CFindDialog(CMDIFrame* frame): QDialog(frame)
{
    hidden = true;
	label1 = new QLabel("Rechercher:");
    lineEdit1 = new QLineEdit;
    label1->setBuddy(lineEdit1);

	findButton = new QPushButton("Suivant");
    findButton->setDefault(true);

    topLeftLayout = new QHBoxLayout;
    topLeftLayout->addWidget(label1);
    topLeftLayout->addWidget(lineEdit1);

    mainLayout = new QGridLayout;
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    mainLayout->addLayout(topLeftLayout, 0, 0);
    mainLayout->addWidget(findButton, 0, 1);

    checkBox1 = new QCheckBox("Mot entier uniquement");
    checkBox2 = new QCheckBox("Respecter la casse");
    layout1 = new QVBoxLayout;
    layout1->addWidget(checkBox1, 1, 0);
    layout1->addWidget(checkBox2, 2, 0);
    mainLayout->addLayout(layout1, 1, 0);

    QGroupBox* groupBox = new QGroupBox("Direction");
    layout2 = new QHBoxLayout;
    radioButton1 = new QRadioButton("haut");
    radioButton2 = new QRadioButton("bas");
    layout2->addWidget(radioButton1);
    layout2->addWidget(radioButton2);
    groupBox->setLayout(layout2);
    mainLayout->addWidget(groupBox, 1, 1);
    radioButton1->setChecked(true);

    setLayout(mainLayout);

	setWindowTitle("Rechercher");
    connect(findButton, SIGNAL(clicked()), this, SLOT(find()));
    connect(lineEdit1, SIGNAL(textEdited(QString)), this, SLOT(sync(QString)));
    connect(checkBox1, SIGNAL(clicked()), this, SLOT(sync()));
    connect(checkBox2, SIGNAL(clicked()), this, SLOT(sync()));
}
CFindDialog::~CFindDialog()
{
}
void CFindDialog::init()
{
    size_t selStart, selEnd;
    searchEdit->getSelection(selStart, selEnd);
    if (lineEdit1)
    {
        if (findReplaceDlg)
        {
            if (findReplaceDlg->IsHidden() && findDlg->IsHidden())
            {
                lineEdit1->setText(::fromStdWString(searchEdit->getText(selStart, selEnd - selStart)));
            }
            else if (!findReplaceDlg->IsHidden())
            {
                lineEdit1->setText(findReplaceDlg->lineEdit1->text());
            }
        }
    }
    hide();
    Show();
}
void CFindDialog::find()
{
    QTextDocument::FindFlags findFlags = 0;
    if (checkBox1->isChecked()) findFlags |= QTextDocument::FindWholeWords;
    if (checkBox2->isChecked()) findFlags |= QTextDocument::FindCaseSensitively;
    if (radioButton1->isChecked()) findFlags |= QTextDocument::FindBackward;
    searchEdit->onFindNext(::toStdWString(lineEdit1->text()), findFlags);
}
void CFindDialog::sync(QString s)
{
    if (findReplaceDlg)
    {
        findReplaceDlg->lineEdit1->setText(s);
        findReplaceDlg->checkBox1->setChecked(checkBox1->isChecked());
        findReplaceDlg->checkBox2->setChecked(checkBox2->isChecked());
    }
}
void CFindDialog::sync()
{
    if (findReplaceDlg)
    {
        findReplaceDlg->checkBox1->setChecked(checkBox1->isChecked());
        findReplaceDlg->checkBox2->setChecked(checkBox2->isChecked());
    }
}
void CFindDialog::closeEvent(QCloseEvent*)
{
    searchEdit->onFindClose();
}

CFindReplaceDialog::CFindReplaceDialog(CMDIFrame* frame): QDialog(frame)
{
    hidden = true;
	label1 = new QLabel("Rechercher:");
    lineEdit1 = new QLineEdit;
    label1->setBuddy(lineEdit1);

	label2 = new QLabel("Remplacer par:");
    lineEdit2 = new QLineEdit;
    label2->setBuddy(lineEdit2);

	findButton = new QPushButton("Suivant");
    findButton->setDefault(true);

	replaceButton = new QPushButton("Remplacer");

	replaceAllButton = new QPushButton("Tout remplacer");

    topLeftLayout = new QHBoxLayout;
    topLeftLayout->addWidget(label1);
    topLeftLayout->addWidget(lineEdit1);

    bottomLeftLayout = new QHBoxLayout;
    bottomLeftLayout->addWidget(label2);
    bottomLeftLayout->addWidget(lineEdit2);

    mainLayout = new QGridLayout;
    mainLayout->setSizeConstraint(QLayout::SetFixedSize);
    mainLayout->addLayout(topLeftLayout, 0, 0);
    mainLayout->addLayout(bottomLeftLayout, 1, 0);
    mainLayout->addWidget(findButton, 0, 1);
    mainLayout->addWidget(replaceButton, 1, 1);
    mainLayout->addWidget(replaceAllButton, 2, 1);

    checkBox1 = new QCheckBox("Mot entier uniquement");
    checkBox2 = new QCheckBox("Respecter la casse");
    layout1 = new QHBoxLayout;
    layout1->addWidget(checkBox1, 1, 0);
    layout1->addWidget(checkBox2, 2, 0);
    mainLayout->addLayout(layout1, 2, 0);

    setLayout(mainLayout);

	setWindowTitle("Rechercher/Remplacer");
    connect(findButton, SIGNAL(clicked()), this, SLOT(find()));
    connect(replaceButton, SIGNAL(clicked()), this, SLOT(replace()));
    connect(replaceAllButton, SIGNAL(clicked()), this, SLOT(replaceAll()));
    connect(lineEdit1, SIGNAL(textEdited(QString)), this, SLOT(sync(QString)));
    connect(checkBox1, SIGNAL(clicked()), this, SLOT(sync()));
    connect(checkBox2, SIGNAL(clicked()), this, SLOT(sync()));
}
CFindReplaceDialog::~CFindReplaceDialog()
{
}
void CFindReplaceDialog::init()
{
    findFlags = 0;
    size_t selStart, selEnd;
    searchEdit->getSelection(selStart, selEnd);
    if (lineEdit1)
    {
        if (findDlg)
        {
            if (findDlg->IsHidden() && findReplaceDlg->IsHidden())
            {
                lineEdit1->setText(::fromStdWString(searchEdit->getText(selStart, selEnd - selStart)));                }
            else if (!findDlg->IsHidden())
            {
                lineEdit1->setText(findDlg->lineEdit1->text());
            }
        }
    }
    hide();
    Show();
}
void CFindReplaceDialog::find()
{
    findFlags = 0;
    if (checkBox1->isChecked()) findFlags |= QTextDocument::FindWholeWords;
    if (checkBox2->isChecked()) findFlags |= QTextDocument::FindCaseSensitively;
    searchEdit->onFindNext(::toStdWString(lineEdit1->text()), findFlags);
}
void CFindReplaceDialog::replace()
{
    searchEdit->onReplace(::toStdWString(lineEdit2->text()));
}
void CFindReplaceDialog::replaceAll()
{
    findFlags = 0;
    if (checkBox1->isChecked()) findFlags |= QTextDocument::FindWholeWords;
    if (checkBox2->isChecked()) findFlags |= QTextDocument::FindCaseSensitively;
    searchEdit->onReplaceAll(::toStdWString(lineEdit1->text()), ::toStdWString(lineEdit2->text()), findFlags);
}
void CFindReplaceDialog::sync(QString s)
{
    if (findDlg)
    {
        findDlg->lineEdit1->setText(s);
        findDlg->checkBox1->setChecked(checkBox1->isChecked());
        findDlg->checkBox2->setChecked(checkBox2->isChecked());
    }
}
void CFindReplaceDialog::sync()
{
    if (findDlg)
    {
        findDlg->checkBox1->setChecked(checkBox1->isChecked());
        findDlg->checkBox2->setChecked(checkBox2->isChecked());
    }
}
void CFindReplaceDialog::closeEvent(QCloseEvent*)
{
    searchEdit->onFindClose();
}

CFont::CFont(const wstring& fontName, int fontSize, bool fntBold, bool fntItalic)
{
    qfont = new QFont(::fromStdWString(fontName), fontSize);
    qfont->setBold(fntBold);
    qfont->setItalic(fntItalic);
    fntName = new wstring(fontName);
	fntSize = fontSize;
    bold = fntBold;
    italic = fntItalic;
}
CFont::~CFont()
{
	delete qfont;
	delete fntName;
}
