/*************************************************************************
**
**    This file is part of the 'forwords' educational programm.
**    Copyright (C) 2024  Alexander Fomin
**
**    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 <https://www.gnu.org/licenses/>.
**
**    Contact: fomin_alex@yahoo.com
**
**************************************************************************/

#include "forwords.h"
#include "ui_forwords.h"
//#include "common.h"

Forwords::Forwords(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::Forwords)
{
    ui->setupUi(this);

    //++++++set window icon++++++++
    QString icon = "";
    QStringList sl = QStringList()<<"/usr/share/icons/hicolor/128x128/apps/"
				  <<"/usr/local/share/icons/hicolor/128x128/apps/";
    QFile file;
    for (int i = 0; i < sl.count(); ++i)
    {
        icon = sl[i]+"forwords.png";
        file.setFileName(icon);
        if(file.exists())
            break;
        icon = "";
    }
    if(icon!="")
    {
        this->setWindowIcon(QIcon(icon));
    }
    //-----------------------------

    menuActGrLang = new QActionGroup(this);

    //++++ init child dialogs ++++
    oTTS = new tts();
    dEdit = new dlgEdit(this);
    dTest1 = new dlgTest1(this);
    dTest3 = new dlgTest3(this);
    dSettings = new dlgSettings(this);
    //----------------------------

    tSpeakTimer.setSingleShot(true);
    tSpeakTimer.stop();

    //++ signals & slots init ++++
    connect(dSettings, SIGNAL(config_changed(QJsonObject)),this,SLOT(on_configChanged(QJsonObject)));
    connect(dSettings, SIGNAL(textToSpeech(QString,QString,QString)),this,SLOT(on_SpeechTest(QString,QString,QString)));
    connect(dSettings, SIGNAL(ttsEngineChanged(QString)),this, SLOT(on_TtsEngineChanged(QString)));
    connect(dEdit, SIGNAL(Savefile()),this,SLOT(on_saveFileClicked()));
    connect(dTest1, SIGNAL(textToSpeech(QString)),this,SLOT(on_TextToSpeech(QString)));
    connect(dTest3,SIGNAL(textToSpeech(QString)),this,SLOT(on_TextToSpeech(QString)));
    connect(&tSpeakTimer, SIGNAL(timeout()),this,SLOT(on_tSpeakTimer_timeOut()));
    //----------------------------

    //++++ privat variables init ++++
    QDir       vDir;
    QString    vS;
    QString    vSIndex;
    vHome = QDir().homePath();
    vConfigDir = vHome + "/.config/ForWords";
    if (not vDir.exists(vConfigDir))
        vDir.mkdir(vConfigDir);
    lTranslationDirs = QStringList()<<vConfigDir<<"/usr/share/forwords/translations"
                                     <<"/usr/local/share/forwords/translations";
    sSpeechEng = "Speech engine - ";
    sSpeechEngNotSet = "Speech engine is not set.";
    //--------------------------------

    //+++ checking Language packs +++
    fGetUiText();
    menuInit();
    //-------------------------------

    //+++++++++++ Reading Config file ++++++++++++
    vFileConfig = new QFile(vConfigDir+"/fwconfig.cfg");
    if (!vFileConfig->exists())
    {
        fConfigInit();
    }
    else
    {
        if(fLoadConfig())
        {
            if(!QDir().exists(vConfig.value("Path").toString()))
                QDir().mkdir(vConfig.value("Path").toString());
            fSetConfig();
        }
        else
        {
            fConfigInit();
        }
    }
    //==============================
}

Forwords::~Forwords()
{
    fSaveConfig();
    delete ui;
}

bool Forwords::fLoadConfig()
{
    QJsonObject obj;
    if (!vFileConfig->open(QIODevice::ReadWrite))
    {
        fShowMsg("Can't open configuration file!!!\nProbably it is corrupt!\nCheck ~/.config/Forwords/fwconfig.cfg\nIf so delete it and reload app.",QMessageBox::Critical);
        return false;
    }
    QJsonDocument confFile = QJsonDocument().fromJson(vFileConfig->readAll());
    vFileConfig->close();
    obj = confFile.toVariant().toJsonObject();
    QJsonValue val = obj.value("appName");
    if (val != QJsonValue::Undefined)
        if (val.toString()=="forwords")
        {
            vConfig.swap(obj);
            return true;
        }
    fShowMsg("Config file is wrong!!!",QMessageBox::Critical);
    return false;
}

void Forwords::fConfigInit()
{
    if (!vConfig.empty())
        vConfig = QJsonObject();
    vConfig.insert("appName",QJsonValue("forwords"));
    vConfig.insert("Path",QJsonValue(vHome + "/ForWords"));
    QDir().mkdir(vConfig.value("Path").toString());
    fSaveConfig();
    fSetConfig();
}

void Forwords::fSetConfig()
{
    vWorkingDir = vConfig.value("Path").toString();
    if(vConfig.keys().contains("interfaceLanguage"))
        fSetUiLanguage(vConfig.value("interfaceLanguage").toString());
    fSpeechInit();
    fSetLanguages();
}

void Forwords::fSaveConfig()
{
    QJsonDocument doc=QJsonDocument(vConfig);

    //++++ Writing changes to config file ++++
    if (vFileConfig->open(QFile::ReadWrite))
    {
        if(!vFileConfig->write(doc.toJson()))
        {
            fShowMsg("Error!!! Can't write to config file",QMessageBox::Critical);
        }
        if(vFileConfig->size()>doc.toJson().size())
            vFileConfig->resize(doc.toJson().size());
        vFileConfig->close();
    }
    else
    {
        fShowMsg("Error!!! Can't open config file",QMessageBox::Critical);
    }
}

void Forwords::menuInit()
{
    vLanguageFiles.clear();
    for (int i = 0; i < lTranslationDirs.count(); ++i)
    {
        vLanguageFiles.append(QDir(lTranslationDirs[i]).entryList(QStringList()<<"*.lp",QDir::Files));
    }
    vLanguageFiles.removeDuplicates();
    menuActionlList.clear();
    for (int i = 0; i < vLanguageFiles.count(); ++i)
    {
        menuActionlList.append(menuLanguages.addAction(vLanguageFiles[i].remove(".lp")));
        menuActionlList[i]->setCheckable(true);
        menuActionlList[i]->setActionGroup(menuActGrLang);
        connect(menuActionlList[i],SIGNAL(triggered(bool)),this,SLOT(on_menuActionTriggered()));
    }
    menuLanguages.addActions(menuActionlList);
    menuLanguages.setTitle("Languages");
    ui->menuAppearance->addMenu(&menuLanguages);

    connect(ui->actionExit,SIGNAL(triggered(bool)),this,SLOT(on_actionExitClicked()));
    connect(ui->actionHelp,SIGNAL(triggered(bool)),this,SLOT(on_actionHelpClicked()));
    connect(ui->actionAbout,SIGNAL(triggered(bool)),this,SLOT(on_actionAboutClicked()));
}

//  search for old formatted topic files
//  and convert them to the current formatt.
void Forwords::fCheckOldVFiles()
{
    QStringList OldFileList, NewFileList;

    //check fo *.tms
    OldFileList = fFileList(vWorkingDir+"/"+ui->cbLanguage->currentText(),"tms");
    int i = OldFileList.count()-1;
    while (i>=0)
    {
        if(ui->cbTopic->findText(OldFileList[i]) >=0)
            OldFileList.removeAt(i);
        --i;
    }
    for (int i = 0; i < OldFileList.count(); ++i)
    {
        fConvertOld(OldFileList[i],"tms");
    }

    //check for *.tma
    OldFileList = fFileList(vWorkingDir+"/"+ui->cbLanguage->currentText(),"tma");
    i = OldFileList.count()-1;
    while (i>=0)
    {
        if(ui->cbTopic->findText(OldFileList[i]) >=0)
            OldFileList.removeAt(i);
        --i;
    }
    for (int i = 0; i < OldFileList.count(); ++i)
    {
        fConvertOld(OldFileList[i],"tma");
    }
}

bool Forwords::fAddLanguageFolder()
{
    if(vWorkingDir.startsWith(vHome))
    {
        QString s = fShowStrInputDlg(this,"Type Language you want to add");
        s.replace(" ","_");
        QStringList sl = QDir(vWorkingDir).entryList(QDir::Dirs);
        if(!sl.contains(s))
        {
            if(!QDir(vWorkingDir).mkdir(s))
            {
                fShowMsg("Can't create language folder",QMessageBox::Critical);
                return false;
            }
            else
            {
                fSetLanguages();
                return true;
            }
        }
    }
    else
    {
        fShowMsg("Your main folder is outside of your home directory!\n"
                 "Choose it within your home directory please.",QMessageBox::Warning);
        return false;
    }
    fShowMsg("Language folder with such name already exists!\n"
             "Choose other name please!",QMessageBox::Warning);
    return false;
}

void Forwords::fSetLanguages()
{
    ui->cbLanguage->clear();
    QStringList sl = fDirList(QDir(vWorkingDir));
    if(sl.count()==1)
        ui->cbLanguage->addItem(sl[0]);
    else
        ui->cbLanguage->addItems(sl);
    if(ui->cbLanguage->count()<1)
    {
        fShowMsg("You don't have any language folders in you working directory!\n"
                 "Add language please.");
        fAddLanguageFolder();
    }
}

bool Forwords::fAddTopic()
{
    if (ui->cbLanguage->count()==0)
    {
        fShowMsg("There is no Language added\nAdd at list one please.");
        return false;
    }
    QString TopicName = fShowStrInputDlg(this,"Type Topic Name here");
    if(TopicName == "")
        return false;
    for (int i = 0; i < ui->cbTopic->count(); ++i)
    {
        if (TopicName==ui->cbTopic->itemText(i))
        {
            fShowMsg("Topic with the same name already exists\n"
                     "Change topic name please!",QMessageBox::Warning);
            return false;
        }
    }
    QFile topicFile;
    topicFile.setFileName(vWorkingDir+"/"+ui->cbLanguage->currentText()+"/"+TopicName+".tof");
    topicFile.open(QIODevice::ReadWrite);
    topicFile.close();
    fSetTopics(ui->cbLanguage->currentText());
    ui->cbTopic->setCurrentText(TopicName);
    return true;
}

//++++++ filename without extention +++++++++
bool Forwords::fOpenTopicFile(QString filename)
{
    QString topicFilePath = vWorkingDir+"/"+ui->cbLanguage->currentText()+"/"+filename+".tof";
    QFile *topicFile = new QFile(topicFilePath);

    if(!topicFile->open(QIODevice::ReadOnly))
    {
        fShowMsg("Can't open Topic File!!!",QMessageBox::Critical);
        return false;
    }

    QByteArray byteArray = topicFile->readAll();
    topicFile->close();
    delete topicFile;

    QString s = QString(byteArray);

    //split lines
    QStringList sl= s.split("\n");

    sl.removeDuplicates();

    //remove empty lines
    int i = sl.count()-1;
    while (i>=0)
    {
        if(sl[i].isEmpty())
            sl.removeAt(i);
        i -= 1;
    }

    //split words of every line, remove line if there are less than 2 words
    QStringList sl1;
    aTopicData.clear();
    for (int i = 0; i < sl.count(); ++i)
    {
        sl1 = sl[i].split("\t");
        int lastInd = sl1.count()-1;
        if(lastInd<1)
            continue;

        //remove excessive strings
        if(lastInd>1)
        {
            while (lastInd>1)
            {
                sl1.removeAt(lastInd);
                --lastInd;
            }
        }
        aTopicData.append(sl1);
    }
    fCheckTopicData();
    return true;
}

//remove all white spaces from the begining and the end. Remove lines with empty words/
void Forwords::fCheckTopicData()
{
    int i = aTopicData.count()-1;
    while (i>=0)
    {
        for (int j = 0; j < 2; ++j)
        {
            aTopicData[i][j] = aTopicData[i][j].trimmed();
            if (aTopicData[i][j].isEmpty())
            {
                aTopicData.removeAt(i);
                break;
            }
        }
        --i;
    }
}

//++++++ file name without extention +++++++++
bool Forwords::fSaveTopicFile(QString filename)
{
    QString topicFilePath = vWorkingDir+"/"+ui->cbLanguage->currentText()+"/"+filename+".tof";
    QFile *topicFile = new QFile(topicFilePath);

    if(!topicFile->open(QIODevice::ReadWrite))
    {
        fShowMsg("Can't open Topic File!!!",QMessageBox::Critical);
        return false;
    }
    fCheckTopicData();
    QString s;
    for (int i = 0; i < aTopicData.count(); ++i)
    {
        s.append(aTopicData[i][0]+"\t"+aTopicData[i][1]+"\n");
    }
    if (topicFile->write(s.toUtf8())==-1)
    {
        fShowMsg("Failed to write topic file!!!",QMessageBox::Critical);
        return false;
    }
    topicFile->close();
    return true;
}

void Forwords::fSetTopics(QString s)
{
    ui->cbTopic->clear();
    ui->cbTopic->addItems(fFileList(vWorkingDir+"/"+s,"tof"));
    if(ui->cbTopic->count()<1)
    {
        fShowMsg("You don't have any topics for your Language!\n"
                 "Add a topic file please.");
        fAddTopic();
    }
    fCheckOldVFiles();
}

void Forwords::fConvertOld(QString filename, QString ext)
{
    QFile file;
    file.setFileName(vWorkingDir+"/"+ui->cbLanguage->currentText()+"/"+filename+"."+ext);
    file.open(QIODevice::ReadOnly);
    QString s = QString(QByteArray(file.readAll()));
    file.close();
    QStringList sl;

    //split lines
    sl= s.split("\n");

    if(ext == "tms")
    {
        sl.removeDuplicates();
        //remove empty lines
        int i = sl.count()-1;
        while (i>=0)
        {
            if(sl[i].isEmpty())
                sl.removeAt(i);
            i -= 1;
        }

        //split words of every line, remove line if there are less than 2 words
        QStringList sl1;
        aTopicData.clear();
        for (int i = 0; i < sl.count(); ++i)
        {
            sl1 = sl[i].split("\t");
            int lastInd = sl1.count()-1;
            if(lastInd<1)
                continue;

            //remove excessive strings
            if(lastInd>1)
            {
                while (lastInd>1)
                {
                    sl1.removeAt(lastInd);
                    --lastInd;
                }
            }
            aTopicData.append(sl1);
        }

        fCheckTopicData();

        //swap coluns
        for (int i = 0; i < aTopicData.count(); ++i)
        {
            aTopicData[i].move(0,1);
        }
    }

    if(ext == "tma")
    {
        QStringList sl1;
        aTopicData.clear();
        int count = sl.count();
        int i = 0;
        int j = 0;
        sl1.clear();

        //put odd lines to the first columt and even lines to second column
        while (i<count)
        {
            if(j>1)
            {
                sl1.clear();
                j=0;
            }
            sl1.append(sl[i]);
            if(j == 1)
                aTopicData.append(sl1);
            ++i;
            ++j;
        }

        fCheckTopicData();

        //swap columns
        for (int i = 0; i < aTopicData.count(); ++i)
        {
            aTopicData[i].move(0,1);
        }
    }

    fSaveTopicFile(filename);
}

void Forwords::fSpeechInit()
{
    QJsonObject joSC;
    QStringList sl, langList;
    langList = fDirList(QDir(vWorkingDir));
    if(vConfig.contains("SpeechConfig"))
    {
        //+++++++ Remove not existing Languages ++++++
        joSC = vConfig.value("SpeechConfig").toObject();
        sl = joSC.keys();
        for (int i = 0; i < langList.count(); ++i)
        {
            if(sl.contains(langList[i]))
            {
                sl.removeAt(sl.indexOf(langList[i]));
            }
        }
        for (int i = 0; i < sl.count(); ++i)
        {
            joSC.remove(sl[i]);
        }
        //=========================
    }
    else
    {
        // create "SpeechConfig"
        vConfig.insert("SpeechConfig",QJsonArray());
    }

    joSC = vConfig.value("SpeechConfig").toObject();
    for (int i = 0; i < langList.count(); ++i)
    {
        //+++++ add missing Languages +++++
        if(!joSC.contains(langList[i]))
        {
            QJsonObject jobj;
            jobj.insert("engine","");
            jobj.insert("voice","");
            joSC.insert(langList[i], QJsonValue(jobj));
        }
        //=================================
        else
        {
            //++++ check existent records for integrity +++++++++
            QJsonObject jobj = joSC.value(langList[i]).toObject();
            QStringList sl = jobj.keys();
            for (int j = sl.count()-1; j >= 0; --j)
            {
                if(sl[j]!="engine" && sl[j]!="voice")
                    jobj.remove(sl[j]);
            }
            if(!jobj.contains("engine"))
                jobj.insert("engine","");
            if(!jobj.contains("voice"))
                jobj.insert("voice","");
            joSC.insert(langList[i], QJsonValue(jobj));
            //====================================================
        }
    }
    vConfig.insert("SpeechConfig",joSC);
}

void Forwords::fStartSpeechTimer(QString str)
{
    int timeout = str.size()*500+500;
    tSpeakTimer.start(timeout);
}

void Forwords::fGetUiText()
{
    QJsonObject uitext;
    dEdit->GetUiText(&uitext);
    dSettings->GetUiText(&uitext);
    dTest1->GetUiText(&uitext);
    dTest3->GetUiText(&uitext);
    QJsonObject jobj;
    jobj.insert("language",QJsonValue(ui->gbLanguage->title()));
    jobj.insert("topic",QJsonValue(ui->gbTopic->title()));
    jobj.insert("edit",QJsonValue(ui->pbEdit->text()));
    jobj.insert("settings",QJsonValue(ui->pbSettings->text()));
    jobj.insert("test1",QJsonValue(ui->pbTest1->text()));
    jobj.insert("test2",QJsonValue(ui->pbTest2->text()));
    jobj.insert("test3",QJsonValue(ui->pbTest3->text()));
    jobj.insert("speechengine",QJsonValue(sSpeechEng));
    jobj.insert("speechnotset",QJsonValue(sSpeechEngNotSet));
    uitext.insert("mainwindow",QJsonValue(jobj));
    QJsonDocument jdoc = QJsonDocument(uitext);
    QFile f;
    f.setFileName(vConfigDir+"/English.lp");
    f.open(QIODeviceBase::ReadWrite);
    f.write(jdoc.toJson());
    f.close();
}

void Forwords::fSetUiLanguage(QString lang)
{
    QFile f;
    QJsonObject uitext;
    QJsonDocument jdoc;
    QString fileName;
    QString s = "/" + lang + ".lp";

    for (int i = 0; i < lTranslationDirs.count(); ++i)
    {
        fileName = lTranslationDirs[i] + s;
        if (f.exists(fileName))
            break;
        if (i == (lTranslationDirs.count()-1))
        {
            fShowMsg("Can't find language pac \'"+lang + "\'");
            return;
        }
    }
    f.setFileName(fileName);
    if(!f.open(QIODeviceBase::ReadOnly))
    {
        fShowMsg("can't open language pack file");
        f.close();
        return;
    }
    jdoc = jdoc.fromJson(f.readAll());
    f.close();
    vConfig.insert("interfaceLanguage",lang);
    uitext = jdoc.object();
    dEdit->SetUiText(&uitext);
    dSettings->SetUiText(&uitext);
    dTest1->SetUiText(&uitext);
    dTest3->SetUiText(&uitext);
    QJsonObject jobj = uitext.value("mainwindow").toObject();
    ui->gbLanguage->setTitle(jobj.value("language").toString());
    ui->gbTopic->setTitle(jobj.value("topic").toString());
    ui->pbEdit->setText(jobj.value("edit").toString());
    ui->pbSettings->setText(jobj.value("settings").toString());
    ui->pbTest1->setText(jobj.value("test1").toString());
    ui->pbTest2->setText(jobj.value("test2").toString());
    ui->pbTest3->setText(jobj.value("test3").toString());
    sSpeechEng = jobj.value("speechengine").toString();
    sSpeechEngNotSet = jobj.value("speechnotset").toString();
}

void Forwords::on_pbAddLanguage_clicked()
{
    if(!fAddLanguageFolder())
    {
        fShowMsg("Failed to add Language!!!",QMessageBox::Critical);
    }
}

void Forwords::on_cbLanguage_currentTextChanged(const QString &arg1)
{
    if(ui->cbLanguage->count()>0)
    {
        fSetTopics(arg1);
        QString engine = vConfig.value("SpeechConfig").toObject().
                         value(ui->cbLanguage->currentText()).toObject().
                         value("engine").toString();
        QString voice = vConfig.value("SpeechConfig").toObject().
                        value(ui->cbLanguage->currentText()).toObject().
                        value("voice").toString();
        if(oTTS->setEngine(engine))
        {
            if(oTTS->setVoice(voice))
            {
                ui->lbTTSinfo->setText(sSpeechEng + engine +
                                       " " + voice);
            }
            else
                ui->lbTTSinfo->setText(sSpeechEngNotSet);
        }
        else
            ui->lbTTSinfo->setText(sSpeechEngNotSet);
    }
}

void Forwords::on_pbAddTopic_clicked()
{
    if(!fAddTopic())
        fShowMsg("Failed to add topic file!!!", QMessageBox::Critical);
}

void Forwords::on_cbTopic_currentTextChanged(const QString &arg1)
{
    if(ui->cbTopic->count()>0)
        fOpenTopicFile(arg1);
}

void Forwords::on_pbEdit_clicked()
{
    fOpenTopicFile(ui->cbTopic->currentText());
    dEdit->EditOpen(&aTopicData);
}

void Forwords::on_saveFileClicked()
{
    fSaveTopicFile(ui->cbTopic->currentText());
}

void Forwords::on_pbTest1_clicked()
{
    if (aTopicData.count()>4)
    {
        oTTS->setEngine(vConfig.value("SpeechConfig").toObject().
                        value(ui->cbLanguage->currentText()).toObject().
                        value("engine").toString());
        oTTS->setVoice(vConfig.value("SpeechConfig").toObject().
                       value(ui->cbLanguage->currentText()).toObject().
                       value("voice").toString());
        dTest1->TestStart(&aTopicData);
    }
    else
        fShowMsg("There is not enough words in current topic to run this test",QMessageBox::Critical);
}

void Forwords::on_pbTest2_clicked()
{
    if (aTopicData.count()>4)
    {
        dTest1->TestStart(&aTopicData,dlgTest1::ReverseTest);
    }
    else
        fShowMsg("There is not enough words in current topic to run this test",QMessageBox::Critical);
}

void Forwords::on_pbTest3_clicked()
{
    if (!aTopicData.isEmpty())
    {
        dTest3->setWindowTitle("Written test");
        dTest3->TestStart(&aTopicData);
    }
    else
        fShowMsg("There are no any words in this topic",QMessageBox::Critical);
}

void Forwords::on_pbSettings_clicked()
{
    dSettings->Open(vConfig,oTTS->getEngines());
}

void Forwords::on_configChanged(QJsonObject obj)
{
    vConfig.swap(obj);
    fSaveConfig();
    fSetConfig();
}

void Forwords::on_TextToSpeech(QString text)
{
    fStartSpeechTimer(text);
    oTTS->speakOut(text);
    tSpeakTimer.stop();
}

void Forwords::on_tSpeakTimer_timeOut()
{
    oTTS->SpeachCancel();
    fShowMsg("A speech timeout!!!\n"
             "There is a sound card problem, apparently.\n"
             "Turning off speech.");
    dTest1->TurnOffSpeech();
}

void Forwords::on_SpeechTest(QString text, QString engine, QString voice)
{
    oTTS->setEngine(engine);
    oTTS->setVoice(voice);
    fStartSpeechTimer(text);
    oTTS->speakOut(text);
    tSpeakTimer.stop();
}

void Forwords::on_menuActionTriggered()
{
    for (int i = 0; i < menuActionlList.count(); ++i)
    {
        if(menuActionlList[i]->isChecked())
        {
            fSetUiLanguage(vLanguageFiles[i]);
            return;
        }
    }
}

void Forwords::on_TtsEngineChanged(QString engine)
{
    oTTS->setEngine(engine);
    dSettings->SetTtsVoices(oTTS->getVoiceList());
}

void Forwords::on_actionExitClicked()
{
    this->close();
}

void Forwords::on_actionHelpClicked()
{
    QStringList mPath;
    QUrl mUrl;
    mPath.append("/usr/share/doc/forwords/manual.html");
    mPath.append("/usr/local/share/doc/forwords/manual.html");
    for (int i = 0; i < 2; ++i)
    {
        if(QFile().exists(mPath[i]))
        {
            mUrl.setUrl("file://"+mPath[i]);
            break;
        }
    }
    vHtmlView.load(mUrl);
    vHtmlView.resize(1024, 700);
    vHtmlView.show();
}

void Forwords::on_actionAboutClicked()
{
    QString s = "About 'forwords':\n"
                "Version 1.0.5\n"
                "This is a very simple and quite effective tool\n"
                "to enhance your foreign vocabulary.\n"
                "Licence: GPL-3.\n"
                "Copyright (C) 2024, Alex Fomin";
    fShowMsg(s,QMessageBox::Information);
}

