/***************************************************************************
 * C++ Implementation:                                                     *
 * Copyright (C) 2012-2017 by Eduard Kalinowski                            *
 * Germany, Lower Saxony, Hanover                                          *
 * eduard_kalinowski@yahoo.de                                              *
 *                                                                         *
 * HTTraQt is free software; may be distributed and/or modified under the  *
 * terms of the GNU General Public License version 3 as published by the   *
 * Free Software Foundation and appearing in the file LICENSE_GPLv3        *
 * included in the packaging of this file.                                 *
 *                                                                         *
 * 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 Lesser General Public        *
 * License along with HTTraQt. If not, see  http://www.gnu.org/licenses    *
 ***************************************************************************/

#include "../version.h"


#include <QtGui>
#include <QSystemTrayIcon>
#include <QApplication>
#include <QMenu>
#include <QDir>
#include <QFileDialog>
#include <QIcon>
#include <QTreeView>
#include <QSound>
#include <QDBusInterface>

#if USE_QT_VERSION == 5
// Qt5 part
#else
// Qt4 part
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <exception>
#include <assert.h>

//
// #include "htinterface.h"
// #include "htsstrings.h"

#include "includes/translator.h"

#include "includes/httraqt.h"
#include "includes/options.h"

#include "ui_mainForm.h"

#include "includes/buttonPanel.h"
#include "../options/includes/OptionsDialog.h"
#include "includes/AboutDialog.h"
#include "includes/NewProjTab.h"
#include "includes/OptionsTab.h"
#include "includes/StartTab.h"
#include "includes/ConfirmTab.h"
#include "includes/ProgressTab.h"
#include "includes/FinalTab.h"


class OptionsDialog;

class ProgressTab;


bool writeWIniFile(QIODevice &device, const QSettings::SettingsMap &map)
{
    QDataStream out(&device);

    if ( device.isOpen () && ! map.empty() ) {
        QMap<QString, QVariant>::const_iterator it;

        for ( it = map.begin(); it != map.end(); ++it ) {
            QString buffer;
            QString val = it.value().toString();

            if (val.length() > 0) {
                if (val.indexOf("\"") == 0) {
                    val.remove(0, 1);
                }

                if (val.lastIndexOf("\"") == val.length() - 1) {
                    val.remove(val.length() - 1, 1);
                }

                val.replace("\n", "%0d%0a");
            }

            buffer = QString ( "%1=%2\n" ).arg ( it.key(), val );

            if ( ! buffer.isEmpty() ) {
                device.write ( buffer.toStdString().c_str() );
            }

            buffer.clear();
        }

        return true;
    }

    return false;
}


bool readWIniFile(QIODevice &device, QSettings::SettingsMap &map)
{
    QDataStream in(&device);

    if ( device.isOpen () ) {
        if ( !map.empty() ) {
            map.clear();
        }

        while ( ! device.atEnd() ) {
            QByteArray line = device.readLine().trimmed();

            if ( line.startsWith ( "#" )) {
                continue;
            }

            if ( !line.contains ( "=" )) {
                continue;
            }

            int pos = line.indexOf("=");
            QString key = line.left(pos);
            QString val = line.mid(pos + 1);

            if (val.length() > 0) {
                if (val.indexOf("\"") == 0) {
                    val.remove(0, 1);
                }

                if (val.lastIndexOf("\"") == val.length() - 1) {
                    val.remove(val.length() - 1, 1);
                }

                val.replace("%0d%0a", "\n");
                //                 val.remove("%0d%0a");
            }

            if ( ! key.isEmpty() ) {
                if (val.length() > 0) {
                    if ( val.contains ( QRegExp ( "^[0-9]+$" ) ) ) {
                        map.insert ( key, QVariant ( val ).toInt() );
                    } else {
                        map.insert ( key, QVariant ( val ).toString() );
                    }
                }
            }
        }

        return true;
    }

    return false;
}

HTTraQt* mainWidget;

static const QSettings::Format WIniFormat = QSettings:: registerFormat ("ini", readWIniFile, writeWIniFile);

using namespace std;


void MessageTimerBox::showEvent ( QShowEvent * event )
{
    currentTime = 0;

    if (autoClose) {
        this->startTimer(1000);
    }
}


void MessageTimerBox::setDefaultText(const QString &t)
{
    defaultText = t;
}


void MessageTimerBox::setAutoClose(bool b)
{
    autoClose = b;
}


void MessageTimerBox::setTimeout(int t)
{
    timeout = t;
    QString tx;

    tx = defaultText;
    tx.replace("%d", QString::number(timeout));
    setText(tx);
}


void MessageTimerBox::timerEvent(QTimerEvent *event)
{
    QString t;
    currentTime++;
    t = defaultText;
    t.replace("%d", QString::number(timeout - currentTime));

    setText(t);

    if (currentTime >= timeout) {
        this->done(0);
    }
}


int MessageBox::exec(void* p, const QString &title, const QString &text, int ticon)
{
    int ret;
    QMessageBox* msgBox = NULL;

    msgBox = new QMessageBox((QWidget*)p);
    msgBox->setIcon((QMessageBox::Icon)ticon);
    msgBox->setWindowTitle(title);
    msgBox->setText(text);

    if (ticon == QMessageBox::Question) {
        msgBox->setStandardButtons(QMessageBox::Yes | QMessageBox::No);
        msgBox->setButtonText(QMessageBox::Yes, translate(_YES));
        msgBox->setButtonText(QMessageBox::No, translate(_NO));
    } else {
        msgBox->setStandardButtons(QMessageBox::Yes);
        msgBox->setButtonText(QMessageBox::Yes, translate(_OK));
    }

    if (mainWidget->programStyleSheet.length() > 0) {
        msgBox->setStyleSheet(mainWidget->programStyleSheet);
    }

    ret = msgBox->exec();

    delete msgBox;

    return ret;
}


void MyThread::run()
{
    httraq_main();
}


QVariant DirModel::headerData ( int section, Qt::Orientation orientation, int role ) const
{
    if (orientation == Qt::Horizontal) {
        if (role != Qt::DisplayRole) {
            return QVariant();
        }

        switch (section) {
            case 0:
                return mainWidget->currentWorkDir;

            default:
                return QVariant();
        }
    }
}


void HTTraQt::launch()
{
    m_todo = (static_cast<OptionsTab*>(widgets[2]))->comboAction->currentIndex();

    cmdOpt = cmdArgumentsOptions(m_todo);

    writeSettings(false);

    initSInfo();

    // wait time, if entered
    QString hh, mm, ss;
    bool okHH, okMM, okSS;
    int  intHH, intMM, intSS;
    intHH = intMM = intSS = 0;

    hh = (static_cast<ConfirmTab*>(widgets[3]))->labelHH->text(); // HH
    mm = (static_cast<ConfirmTab*>(widgets[3]))->labelMM->text(); // MM
    ss = (static_cast<ConfirmTab*>(widgets[3]))->labelSS->text(); // SS

    pcShutdown = false;
    pcHibernate = false;

    if ((static_cast<ConfirmTab*>(widgets[3]))->groupPCoff->isChecked() == true) {
        pcShutdown = (static_cast<ConfirmTab*>(widgets[3]))->radioShutdown->isChecked();
        pcHibernate = (static_cast<ConfirmTab*>(widgets[3]))->radioHibernate->isChecked();
    }

    if (hh.length() > 0) {
        intHH = hh.toInt(&okHH);
    }

    if (intHH < 0 || intHH > 23) {
        okHH = false;
        intHH = 0;
    }

    if (mm.length() > 0) {
        intMM = mm.toInt(&okMM);
    }

    if (intMM < 0 || intMM > 59) {
        okMM = false;
        intMM = 0;
    }

    if (ss.length() > 0) {
        intSS = ss.toInt(&okSS);
    }

    if (intSS < 0 || intSS > 59) {
        okSS = false;
        intSS = 0;
    }

    if (intHH > 0 || intMM > 0 || intSS > 0) {
        int mSec = 1000 * (intHH * 3600 + intMM * 60 + intSS);
        QTimer::singleShot(mSec, this, SLOT(onStopAll()));
    }

    int result = 0;
    {
        QString projectDir;
        projectDir =  currentWorkDir + "/" + currentProject + "/";

        // on efface le doit.log, pour annuler les parametres anciens et en redéfinir de nouveaux
        // c'est ici une logique qui diffère de la version en ligne de commande
        if (QFile::exists(projectDir + "hts-cache/new.zip") || QFile::exists(projectDir + "hts-cache/new.ndx")) {    // un cache est présent
            QFile fl(projectDir + "hts-cache/doit.log");

            if (fl.exists()) {
                fl.remove();
            }

            if (fl.open(QFile::WriteOnly) == true) {
                fl.close();
            }
        }
    }


    //     if (global_opt != NULL) {
    //         hts_free_opt(global_opt);
    //         global_opt = NULL;
    //     }

    termine = 0;
    termine_requested = 0;

    //     global_opt = hts_create_opt();

    timerProgressUpdate->start(1000); //progress tab ones per second to update

    timerDirRefresh->start(10000); // ones per 10 seconds


    mth = new MyThread;

    connect(mth, SIGNAL(finished ()), this, SLOT(threadFinished()));
    connect(mth, SIGNAL(terminated ()), this, SLOT(threadFinished()));

    mth->start();
}


void HTTraQt::refreshDirModel()
{
    dModel.refresh();
    statusBar()->showMessage("Update dir list", 1000);
}


HTTraQt::HTTraQt(QWidget* parent, Qt::WindowFlags flags)
    : QMainWindow(parent, flags)
{
    setupUi(this);

    mainWidget = this;

    currentAppDir = qApp->applicationDirPath();

    if (currentAppDir.lastIndexOf("/build") > 0) { // build dir detection
        currentAppDir.remove("/build");
    }

    currentLang = "English";

    _singular = new QSharedMemory("HTTraQt", this);


    QFont sysFont = qApp->font();
    sysFont = sysFont;

    fontSize = sysFont.pointSize();

    mth = NULL;

    verbose = true; // for hibernate and shutdown debug messages only!

    readGUISettings();

    mainpix = new QPixmap(":/icons/line.png");
    *mainpix = mainpix->scaled(479, 100);

    QPainter painterPix(mainpix);
    painterPix.drawPixmap(25, 5, QPixmap(":/icons/pump.png"));
    painterPix.drawPixmap(122, 78, QPixmap(":/icons/opensource.png"));
    painterPix.drawPixmap(142, 17, QPixmap(":/icons/name.png"));

    mainicon = new QPixmap(100, 100);
    mainicon->fill(Qt::transparent);
    QPainter painterIcon(mainicon);
    painterIcon.drawPixmap(25, 5, QPixmap(":/icons/pump.png"));

    programStyleSheet = QString().sprintf("font-size: %dpt", fontSize);

    if ( fontSize == -1) {
        fontSize = sysFont.pixelSize();
        programStyleSheet = QString().sprintf("font-size: %dpx", fontSize);
    }

    if (programStyleSheet.length() > 0) {
        setStyleSheet(programStyleSheet);
    }

    if (readLangDir() == false) { // init from langFiles variable in format "filename:language"
        MessageBox::exec(this, translate(_ERR),
                         "Directory with other languages not found\nDefault GUI language is english", QMessageBox::Critical);
    }

    currentTab = 0;

    groupMain->setFont(sysFont);
    groupButtons->setFont(sysFont);
    dirView->setFont(sysFont);

    // this function i need only for converting! normally is disabled
    // old help file format -> new
    //         convertTranslateFiles();

    buttonsWidget = new buttonPanel(this);
    gridLayoutB->addWidget(buttonsWidget);

    widgets[0] = new StartTab(this);
    gridLayoutM->addWidget(widgets[0]);

    widgets[1] = new NewProjTab(this);
    gridLayoutM->addWidget(widgets[1]);

    widgets[2] = new OptionsTab(this);
    gridLayoutM->addWidget(widgets[2]);

    widgets[3] = new ConfirmTab(this);
    gridLayoutM->addWidget(widgets[3]);

    widgets[4] = new ProgressTab(this);
    gridLayoutM->addWidget(widgets[4]);

    widgets[5] = new FinalTab(this);
    gridLayoutM->addWidget(widgets[5]);

    setFontForWidgets();

    timerProgressUpdate = new QTimer(this);
    timerDirRefresh =  new QTimer(this);

    connect(timerProgressUpdate, SIGNAL(timeout()), widgets[4], SLOT(update()));
    connect(timerDirRefresh, SIGNAL(timeout()), this, SLOT(refreshDirModel()));

    // flag de termination

    termine = 0;
    process = NULL;
    termine_requested = 0;
    shell_terminated = 0;
    soft_term_requested = 0;

    setWindowIcon(QIcon(*mainicon));

    dModel.setReadOnly(true);

    dirView->setModel(&dModel);

    setCentralWidget(centralwidget);

    dirView->setColumnHidden(1, true);
    dirView->setColumnHidden(2, true);
    dirView->setColumnHidden(3, true);
    dirView->setAnimated(false);
    dirView->setIndentation(20);
    dirView->setSortingEnabled(true);

    connect(dirView, SIGNAL(expanded(const QModelIndex &)), this, SLOT(treeItemClicked(const QModelIndex &)));
    connect(dirView, SIGNAL(collapsed(const QModelIndex &)), this, SLOT(treeItemClicked(const QModelIndex &)));

    initOptions();

    readSettings(true); // global settings

    statusBar()->showMessage("Current directory: " + currentWorkDir);

    createActions();
    createToolBars();
    createStatusBar();

    createTrayIcon();

    if (getLangTable() == false) {
        MessageBox::exec(this, translate(_ERR),
                         "Can't open language file!\nDefault GUI language is english", QMessageBox::Critical);

        currentLang = "English";
    }

    for (QVector<QAction*>::iterator itL = actLangSelect.begin(); itL != actLangSelect.end(); ++itL) {
        if ((*itL)->text() == currentLang) {
            (*itL)->setChecked(true);
            break;
        }
    }

#if 0

    if(checkInstanceRuns() == true) {
        int res = QMessageBox::question(0, "Warning", "Application already running\nDo you want to continue?", QMessageBox::Yes | QMessageBox::No);

        if (res == QMessageBox::No) {
            exit(-1);
        }
    }

#endif
    setLangGUI();

    activatePage(0);
}


// void HTTraQt::resizeTabs(QResizeEvent* se)
// {
//     qDebug() << "resize";
// }

void HTTraQt::setFontForWidgets()
{
    buttonsWidget->setStyleSheet(programStyleSheet);

    for (int i = 0; i < 6; i++) {
        widgets[i]->setStyleSheet(programStyleSheet);
    }
}


void HTTraQt::clearStatsBuffer(void)
{
    // SInfo.refresh
    for (int i = 0; i < NStatsBuffer; i++) {
        StatsBuffer[i].strStatus = ""; // etat
        StatsBuffer[i].name = "";  // nom
        StatsBuffer[i].file = "";  // fichier
        StatsBuffer[i].url_sav = "";
        StatsBuffer[i].back = 0;
        StatsBuffer[i].size = 0;
        StatsBuffer[i].sizeTotal = 0;
    }
}


void HTTraQt::threadFinished(void)
{
    if (global_opt != NULL) {
        hts_free_opt(global_opt);
        global_opt = NULL;
    }

    buttonsWidget->onNext(); // to log page
    onEndMirror();

    timerProgressUpdate->stop();
    timerDirRefresh->stop();

    /* Aborted mirror or finished? */
    {
        QString projectDir;
        projectDir =  currentWorkDir + "/" + currentProject + "/";

        if (soft_term_requested || termine_requested) {
            QFile fl(projectDir + "hts-cache/interrupted.lock");

            if (fl.open(QFile::WriteOnly) == true) {
                fl.close();
            }
        } else {
            QFile::remove(projectDir + "hts-cache/interrupted.lock");
        }
    }

    delete mth;
    mth = NULL;

    if (pcShutdown == true) {
        shutdown();
    }

    if (pcHibernate == true) {
        hibernate();
    }
}


//
bool HTTraQt::treeItemClicked(const QModelIndex &m)
{
    //     dirView->resizeColumnToContents(0);
}


// true if new project
bool HTTraQt::rebuildWorkDirView()
{
    bool newProj = false;

    if (currentWorkDir.length() == 0) {
        //         currentWorkDir = QDir::homePath() + "/My Web Sites";
        readSettings(true);
    }

    QDir wDir(currentWorkDir);

    if (wDir.exists() == false) {
        wDir.mkpath(currentWorkDir);
        newProj = true;
    }

    dirView->reset();
    dirView->setRootIndex(dModel.index(currentWorkDir));
    dModel.refresh();

    // something in hts-cache?
    if (checkContinue(false) == false) {
        newProj = true;
    }

    return newProj;
}


void HTTraQt::initSInfo()
{
    //     SInfo.ask_refresh = 0;
    SInfo.refresh = 0;
    SInfo.stat_bytes = 0;
    SInfo.stat_time = 0;
    SInfo.lien_n = 0;
    SInfo.lien_tot = 0;
    SInfo.stat_nsocket = 0;
    SInfo.rate = 0;
    SInfo.irate = 0;
    SInfo.ft = 0;
    SInfo.stat_written = 0;
    SInfo.stat_updated = 0;
    SInfo.stat_errors = 0;
    SInfo.stat_warnings = 0;
    SInfo.stat_infos = 0;
    SInfo.stat_timestart = mtime_local();
    SInfo.stat_back = 0;
}


// reprise possible?
bool HTTraQt::checkContinue(bool msg)
{
    QString projectDir;
    projectDir =  currentWorkDir + "/" + currentProject + "/";

    if (QFile::exists(projectDir + "hts-cache/new.zip")  ||
            ((QFile::exists(projectDir + "hts-cache/new.dat")) && (QFile::exists(projectDir + "hts-cache/new.ndx")))) {  // il existe déja un cache précédent.. renommer
        return true;
    }

    if (QFile::exists(projectDir + "hts-cache/old.zip") ||
            ((QFile::exists(projectDir + "hts-cache/old.dat")) && (QFile::exists(projectDir + "hts-cache/old.ndx")))) {  // il existe déja un ancien cache précédent.. renommer
        return true;
    }

    if ( msg == true) {
        MessageBox::exec(this, translate(_ERR), translate(_CANTFIND), QMessageBox::Critical);
    }

    return false;
}


void HTTraQt::afterChangepathlog()
{
    QString st = "";
    char tempo[8192];
    bool modify;
    QString projectDir;
    projectDir =  currentWorkDir + "/" + currentProject + "/";
#if 0

    if (fexist(fconcat(catbuff, tempo, "winprofile.ini"))) {  // un cache est présent
        if (fsize(fconcat(catbuff, tempo, "winprofile.ini")) > 0) { // taille log contrôle>0
            int i;

            for(i = 0; i < (int) strlen(tempo); i++) {
                if (tempo[i] == '/') {
                    tempo[i] = '\\';
                }
            }

            Read_profile(fconcat(catbuff, tempo, "winprofile.ini"), 0);

            // peut on modifier?
            int pos = m_ctl_todo.GetCurSel();

            if ((pos == LAST_ACTION) || (pos == LAST_ACTION - 1) || (pos == 0)) {
                modify = true;
            } else {
                modify = false;
            }

            // existe: update
            if (fexist(fconcat(catbuff, tempo, "hts-cache/new.zip")) ||
                    (fexist(fconcat(catbuff, tempo, "hts-cache/new.dat"))) && (fexist(fconcat(catbuff, tempo, "hts-cache/new.ndx")))
               ) {  // il existe déja un cache précédent.. renommer
                if (modify) {
                    if ((!fexist(fconcat(catbuff, tempo, "hts-in_progress.lock"))) &&
                            (!fexist(fconcat(catbuff, tempo, "hts-cache/interrupted.lock")))
                       ) {
                        m_ctl_todo.SetCurSel(LAST_ACTION);
                    } else {
                        m_ctl_todo.SetCurSel(LAST_ACTION - 1);
                    }
                }

                log_flip = 1;
            } else if (log_flip) {
                if (modify) {
                    m_ctl_todo.SetCurSel(0);
                }

                log_flip = 0;
            }

            OnSelchangetodo();
        }
    } else if (log_flip) {
        m_ctl_todo.SetCurSel(0);
        log_flip = 0;
    }

#endif
}



void HTTraQt::renameOldToNew()
{
    QString projectDir;
    projectDir =  currentWorkDir + "/" + currentProject + "/";

    if (QFile::exists(projectDir + "hts-cache/old.dat") && QFile::exists(projectDir + "hts-cache/old.ndx")) {
        if (QFile::remove(projectDir + "hts-cache/new.dat") == false) {
            MessageBox::exec(this, translate(_ERR), translate(_ERRDELETING), QMessageBox::Warning);
        }

        if ( QFile::remove(projectDir + "hts-cache/new.ndx") == false) {
            MessageBox::exec(this, translate(_ERR), translate(_ERRDELETING), QMessageBox::Warning);
        }
    }

    if (QFile::remove(projectDir + "hts-cache/new.lst") == false ) {
        MessageBox::exec(this, translate(_ERR), translate(_ERRDELETING), QMessageBox::Warning);
    }

    if (QFile::exists(projectDir + "hts-cache/old.zip")) {
        if (QFile::remove(projectDir + "hts-cache/new.zip") == false ) {
            MessageBox::exec(this, translate(_ERR), translate(_ERRDELETING), QMessageBox::Warning);
        }
    }

    QFile::remove(projectDir + "hts-cache/new.txt");
    QFile::rename(projectDir + "hts-cache/old.zip", projectDir + "hts-cache/new.zip");
    QFile::rename(projectDir + "hts-cache/old.dat", projectDir + "hts-cache/new.dat");
    QFile::rename(projectDir + "hts-cache/old.ndx", projectDir + "hts-cache/new.ndx");
    QFile::rename(projectDir + "hts-cache/old.lst", projectDir + "hts-cache/new.lst");
    QFile::rename(projectDir + "hts-cache/old.txt", projectDir + "hts-cache/new.txt");
}


QString HTTraQt::sizeToText(long long int s)
{
    QString t;

    if (s < 0) {
        return QString(" size is wrong!");
    }

    if (s > 1024 && s < 1024 * 1024) {
        t = QString::number(s / 1024) + " kB";
    } else if (s > (1024 * 1024)) {
        t = QString::number(s / (1024 * 1024)) + " MB";
    } else {
        t = QString::number(s / 1024) + " B";
    }

    return t;
}


void HTTraQt::onEndMirror()
{
    QStringList ext = (QStringList() << "zip" << "dat" << "ndx");
    QString oldName, oldShort;
    QString newName, newShort;
    long int oldSize = -1;
    long int newSize = -1;

    //     endInProgress();

    QString projectDir;
    projectDir =  currentWorkDir + "/" + currentProject + "/";

    for (QStringList::iterator iExt = ext.begin(); iExt != ext.end(); ++iExt) {
        QFile oldF;
        QFile newF;
        oldName = projectDir + "hts-cache/old." + (*iExt);
        oldShort = "old."  + (*iExt);
        newName = projectDir + "hts-cache/new." + (*iExt);
        newShort = "new."  + (*iExt);

        oldF.setFileName (oldName);
        newF.setFileName (newName);

        if (oldF.exists() == true && newF.exists() == true ) {
            oldSize = oldF.size();
            newSize = newF.size();
        }

        if (oldSize > 0 && newSize > 0) {
            break;
        }
    }

    if (oldSize == -1) { // nothing to overwrite, project was new
        return;
    }

    if (newSize == -1) {
        MessageBox::exec(this, translate(_ERR), translate(_MIRROR_ERR), QMessageBox::Warning);

        return; // nothing was found
    }
}

void HTTraQt::contextMenuEvent(QContextMenuEvent *)
{
#if 0
    QMenu* contextMenu = new QMenu("boo", this);
    Q_CHECK_PTR(contextMenu);
    QString caption = QString("<font color=darkblue><u><b>"
                              "Context Menu</b></u></font>");
    //caption->setAlignment( Qt::AlignCenter );
    // contextMenu->setTitle( "boo" );
    contextMenu->addMenu(QString("&New"));            //,  SLOT(news()), QKeySequence(Qt::CTRL+Qt::Key_N) );
    contextMenu->addMenu(QString("&Open..."));            //, this, SLOT(open()), CTRL+Key_O );
    contextMenu->addMenu(QString("&Save"));            //, this, SLOT(save()), CTRL+Key_S );

    QMenu *submenu = new QMenu(this);
    Q_CHECK_PTR(submenu);
    submenu->addMenu(QString("&Print to printer"));            //, this, SLOT(printer()) );
    submenu->addMenu(QString("Print to &file"));            //, this, SLOT(file()) );
    submenu->addMenu(QString("Print to fa&x"));            //, this, SLOT(fax()) );
    contextMenu->addMenu(QString("&Print"));            //, submenu );
    contextMenu->exec(QCursor::pos());
    delete contextMenu;
#endif
}


void HTTraQt::displayProgressMsg()
{
    QByteArray msg;
    QString result;
    //   QProcess* actualP = NULL;

    process->setReadChannel(QProcess::StandardError);
    msg = process->readAllStandardError();
    //     if ( msg.length() > 1 ) {
    result = msg.data();
    //       actualP = process;
    //     qDebug() << "displayProgressMsg:" << result ;
    //     }

    //   if ( result.length() < 1 )
    //     return;
}

void HTTraQt::displayOutputMsg()
{
    QString line;

    process->setReadChannel(QProcess::StandardOutput);

    while (process->canReadLine()) {
        line = process->readLine().trimmed();
    }

    //     qDebug() << "displayOutputMsg:" << line ;
}


void HTTraQt::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
}


void HTTraQt::createActions()
{
    //     newProjAct->setShortcut ( tr ( "Ctrl+N" ) );
    newProjAct->setStatusTip(translate(_OPENGUI));
    connect(newProjAct, SIGNAL(triggered()), this, SLOT(newProject()));

    //     openProjAct->setShortcut ( tr ( "Ctrl+O" ) );
    //     openProjAct->setStatusTip(translate("Open project"));
    //     connect(openProjAct, SIGNAL(triggered()), this, SLOT(openProject()));

    //     saveProjAct->setShortcut ( tr ( "Ctrl+S" ) );
    //     saveProjAct->setStatusTip(translate("Save project"));
    //     connect(saveProjAct, SIGNAL(triggered()), this, SLOT(saveProject()));

    //     delProjAct->setShortcut ( tr ( "Ctrl+D" ) );
    //     delProjAct->setStatusTip(translate("Delete a project"));
    //     connect(delProjAct, SIGNAL(triggered()), this, SLOT(deleteProject()));


    browseAct->setShortcut ( tr ( "Ctrl+B" ) );
    browseAct->setStatusTip(translate(_BROWSEEXISTS));
    connect(browseAct, SIGNAL(triggered()), this, SLOT(browseSites()));

    //     loadDefOptAct->setShortcut ( tr ( "Ctrl+L" ) );
    loadDefOptAct->setStatusTip(translate(_LOADDEF));
    connect(loadDefOptAct, SIGNAL(triggered()), this, SLOT(loadDefaultOptions()));

    saveOptAct->setStatusTip(translate(_SAVEDEF));
    connect(saveOptAct, SIGNAL(triggered()), this, SLOT(saveDefaultOptions()));

    //     resetOptToDefAct->setShortcut ( tr ( "Ctrl+R" ) );
    resetOptToDefAct->setStatusTip(translate(_RESETTODEF));
    connect(resetOptToDefAct, SIGNAL(triggered()), this, SLOT(resetToDefault()));

    loadOptAct->setStatusTip(translate(_LOADOPT));
    connect(loadOptAct, SIGNAL(triggered()), this, SLOT(loadOptionsFromFile()));

    //     recentAct->setShortcut ( tr ( "Ctrl+R" ) );
    //     recentAct->setStatusTip(translate("Recent file"));
    //     connect(recentAct, SIGNAL(triggered()), this, SLOT(recent()));

    //     exitAct->setShortcut ( tr ( "Ctrl+X" ) );
    exitAct->setStatusTip(translate(_EXIT));
    connect(exitAct, SIGNAL(triggered()), this, SLOT(quit()));

    saveOptAsAct->setStatusTip(translate(_SAVEOPTAS));
    connect(saveOptAsAct, SIGNAL(triggered()), this, SLOT(saveOptionsAs()));

    //     selectFontAct->setStatusTip(translate(_SEL_FONT));
    //     connect(selectFontAct, SIGNAL(triggered()), this, SLOT(selectFontSize()));

    // fontSizePrefAct->setStatusTip(translate(_SEL_FONT));
    langPrefAct->setStatusTip(translate(_LANGPREF));
    //     fontPrefAct->setStatusTip(translate(_SEL_FONT));
    //     connect(langPrefAct, SIGNAL(triggered()), this, SLOT(langPreference()));

    //     modifyOptAct->setShortcut ( tr ( "Ctrl+M" ) );
    modifyOptAct->setStatusTip(translate(_MODIFYOPT));
    connect(modifyOptAct, SIGNAL(triggered()), this, SLOT(modifyOptions()));

    //     pauseOptAct->setShortcut ( tr ( "Ctrl+P" ) );
    pauseOptAct->setStatusTip(translate(_PAUSETRANSF));
    connect(pauseOptAct, SIGNAL(triggered()), this, SLOT(pauseTransfer()));

    viewLogAct->setStatusTip(translate(_VIEW_LOG));
    connect(viewLogAct, SIGNAL(triggered()), this, SLOT(viewLog()));

    viewErrLogAct->setStatusTip(translate(_VIEWERRLOG));
    connect(viewErrLogAct, SIGNAL(triggered()), this, SLOT(viewErrorLog()));

    //     viewTransferAct->setStatusTip(translate(_VIEWFILETRANSFERS));
    //     connect(viewTransferAct, SIGNAL(triggered()), this, SLOT(viewTransfers()));

    //     hideAct->setShortcut ( tr ( "Ctrl+H" ) );
    hideAct->setStatusTip(translate(_HIDE));
    connect(hideAct, SIGNAL(triggered()), this, SLOT(hideWindow()));

    restAct = new QAction(translate(_OPEN), this);
    //     restAct->setStatusTip(translate(_RESTORE));
    connect(restAct, SIGNAL(triggered()), this, SLOT(restoreWindow()));

    //     winStatusAct->setStatusTip(translate("Status Bar"));
    //     connect(winStatusAct, SIGNAL(triggered()), this, SLOT(windowStatusBar()));

    //     checkAct->setShortcut ( tr ( "Ctrl+U" ) );
    checkAct->setStatusTip(translate(_TOPROJECTPAGE));
    connect(checkAct, SIGNAL(triggered()), this, SLOT(checkUpdates()));

    contentAct->setStatusTip(translate(_CONTENTS));
    connect(contentAct, SIGNAL(triggered()), this, SLOT(contens()));

    stepByStepAct->setStatusTip(translate(_STEPBYSTEP));
    connect(stepByStepAct, SIGNAL(triggered()), this, SLOT(stepByStep()));

    //     aboutAct->setShortcut ( tr ( "Ctrl+A" ) );
    aboutAct->setStatusTip(translate(_ABOUTPROG));
    connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));

    aboutQtAct->setStatusTip(translate(_ABOUTQT));
    aboutQtAct->setFont(sysFont);
    connect(aboutQtAct, SIGNAL(triggered()), this, SLOT(aboutQt()));
}


void HTTraQt::createTrayIcon()
{
    if (!QSystemTrayIcon::isSystemTrayAvailable()) {
        hideAct->setEnabled(false);
        return;
    }

    QApplication::setQuitOnLastWindowClosed(false);

    trayIconMenu = new QMenu(this);

    trayIconMenu->addAction(restAct);
    trayIconMenu->addSeparator();

    trayIconMenu->addAction(modifyOptAct);
    trayIconMenu->addAction(viewLogAct);
    trayIconMenu->addAction(viewErrLogAct); // view err log
    trayIconMenu->addSeparator();

    trayIconMenu->addAction(pauseOptAct); // pause
    trayIconMenu->addAction(aboutAct); // about
    trayIconMenu->addAction(exitAct);

    trayIcon = new QSystemTrayIcon(this);

    connect(trayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
            this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));

    trayIcon->setContextMenu(trayIconMenu);

    trayIcon->setIcon(QIcon(*mainicon));
}


void HTTraQt::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason) {
        case QSystemTrayIcon::Trigger:
            //             qDebug() << "trigger";
            break;

        case QSystemTrayIcon::DoubleClick:
            //             qDebug() << "double";
            emit restoreWindow();
            //          iconComboBox->setCurrentIndex((iconComboBox->currentIndex() + 1)
            //                                        % iconComboBox->count());
            break;

        case QSystemTrayIcon::MiddleClick:
            //             qDebug() << "middle";
            //          showMessage();
            break;

        default:
            ;
    }
}


void HTTraQt::hideWindow()
{
    // to system tray
    trayIcon->show();
    hide();
}


void HTTraQt::restoreWindow()
{
    // to normal
    trayIcon->hide();
    showNormal();
}


void HTTraQt::newProject()
{
    QString app;
    app = qApp->applicationDirPath() + "/httraqt";

    QProcess *myProcess = new QProcess();
    myProcess->start(app);
}


void HTTraQt::browseSites()
{
    QString name = currentWorkDir + "/" + currentProject + "/index.html";

    if (QFile::exists(name) == true ) {
        QDesktopServices::openUrl(QUrl::fromLocalFile(qPrintable( name )));
    }
}


void HTTraQt::loadDefaultOptions()
{
    int ans = MessageBox::exec(this, translate(_QUEST), translate(_LOADDEFAULT), QMessageBox::Question);

    if (ans == QMessageBox::Yes) {
        readSettings(true);
    }
}


void HTTraQt::saveDefaultOptions()
{
    int ans = MessageBox::exec(this, translate(_QUEST), translate(_SAVEDEFAULT), QMessageBox::Question);

    if (ans == QMessageBox::Yes) {
        writeSettings(true); // global options
    }
}


void HTTraQt::resetToDefault()
{
    int ans = MessageBox::exec(this, translate(_QUEST), translate(_RESETDEFAULT), QMessageBox::Question);

    if (ans == QMessageBox::Yes) {
        initOptions();
    }
}



void HTTraQt::loadOptionsFromFile()
{
    QSettings* s;

    QString fileName = QFileDialog::getOpenFileName(this, translate(_OPENFILE),
                       currentWorkDir, "HTTrack Settings (linprofile.ini winprofile.ini)");

    if (fileName.length() == 0) {
        return;
    }

    s = new QSettings(fileName, WIniFormat);

    loadOptions(s);
}


bool HTTraQt::checkInstanceRuns()
{
    if(_singular->attach(QSharedMemory::ReadOnly)) {
        //         _singular->detach();
        return false;
    }

    if(_singular->create(1)) {
        return true;
    }

    return false;
}



void HTTraQt::saveOptionsAs()
{
    QSettings* s;

    QString fileName = QFileDialog::getSaveFileName(this, translate(_SAVEFILE),
                       currentWorkDir, "winprofile.ini");

    if (fileName.length() == 0) {
        return;
    }

    s = new QSettings(fileName, WIniFormat);

    saveOptions(s, false);
}


void HTTraQt::pauseTransfer()
{
    if (pauseOptAct->isChecked() == true) {
        hts_setpause(global_opt, 1);
    } else {
        hts_setpause(global_opt, 0);
    }
}


void HTTraQt::onStopAll()
{
    pauseOptAct->setChecked(false);

    // qDebug() << "onStopAll";
    if (soft_term_requested) {
        termine_requested = 1;
    } else {
        soft_term_requested = 1;
        hts_request_stop(mainWidget->global_opt, 0);
    }
}


void HTTraQt::viewTransfers()
{
}



// this is only possible, if programm installed in home directory, like firefox
// in other case only display information about update,
// normal updates only from repository
void HTTraQt::checkUpdates()
{
    QDesktopServices::openUrl(QUrl("http://httraqt.sourceforge.net/", QUrl::TolerantMode));
}


// zeige hilfe
void HTTraQt::contens()
{
    QDesktopServices::openUrl(QUrl::fromLocalFile(qPrintable( helpDir + "/index.html")));
}


void HTTraQt::stepByStep()
{
    QDesktopServices::openUrl(QUrl::fromLocalFile(qPrintable( helpDir + "/step.html")));
}


void HTTraQt::createToolBars()
{
    //     fileToolBar()->addToolBar(translate("File"));
    //     fileToolBar->addAction(newLetterAct);
    //     fileToolBar->addAction(saveAct);
    //     fileToolBar->addAction(printAct);
    //
    //     editToolBar = addToolBar(translate("Edit"));
    //     editToolBar->addAction(undoAct);
}


void HTTraQt::createStatusBar()
{
    statusBar()->showMessage(translate(_READY), 2000);
}


void HTTraQt::getOptions()
{
    currentOptionsFile = "";

    if (currentProject.length() > 0) {
        QString linname, winname;
        linname = currentWorkDir + "/" + currentProject + "/linprofile.ini";
        winname = currentWorkDir + "/" + currentProject + "/hts-cache/winprofile.ini";

        if (QFile::exists(linname) == true) {
            currentOptionsFile = linname;
        }

        if (QFile::exists(winname) == true) {
            currentOptionsFile = winname;
        }
    }

    if (currentOptionsFile.length() > 0) {
        readSettings(false); // project
    } else {
        readSettings(true); // global
    }
}


void HTTraQt::writeGUISettings(void)
{
    QSettings* s;
    s = new QSettings(QSettings::UserScope, "KarboSoft", "HTTraQt");
    s->setValue("pos", pos());
    s->setValue("size", size());
    s->setValue("WorkDir", currentWorkDir);
    s->setValue("LANGUAGE", currentLang);
    s->setValue("LASTPROJ", currentProject);
    //     s->setValue("FontSize", fontSize);
    //     s->setValue("GUIFont", sysFont);
    // qDebug() << "writeGUISettings";
    int i = 0;

    for (QStringList::Iterator iDir = lastDirs.begin(); iDir != lastDirs.end(); iDir++, i++) {
        if (i > 8) { // max last dirs
            break;
        }

        s->setValue("LASDIR" + QString::number(i), (*iDir));
    }

    s->sync();
}


void HTTraQt::writeSettings(bool global)
{
    QSettings* s;
    QString fname;

    if (global == true) {
        s = new QSettings(QSettings::UserScope, "KarboSoft", "HTTraQt");
        s->setValue("WorkDir", currentWorkDir);
        s->setValue("LANGUAGE", currentLang);
        //                 qDebug() << "writesettings global";
    } else {
        if (currentProject.length() == 0) {
            return;
        }

        fname = currentWorkDir + "/" + currentProject/* + "/hts-cache"*/;
        QDir d(fname);

        if (d.exists() == false) {
            d.mkpath((const QString) fname);
        }

        if (d.mkpath(fname + "/hts-cache") == false) {
            qDebug() << "can not create";
        }

        fname += "/hts-cache/winprofile.ini";
        //         qDebug() << "writesettings local" << fname;
        s = new QSettings(fname, WIniFormat);
    }

    saveOptions(s, global);
}

// to get locale and convert to internal string
QString HTTraQt::getLocaleString()
{
    QString res;
    QLocale lSys = QLocale::system();

    switch (lSys.language()) {
        case QLocale::Byelorussian:
            res = "Belarussian";
            break;

        case QLocale::Bulgarian:
            res = "Bulgarian";
            break;

        case QLocale::Spanish:
            res = "Castellano";
            break;

        case QLocale::Czech:
            res = "Česky";
            break;

        case QLocale::Chinese:
            res = "Chinese-Simplified";
            break;

        case QLocale::Danish:
            res = "Dansk";
            break;

        case QLocale::German:
            res = "Deutsch";
            break;

        case QLocale::Estonian:
            res = "Eesti";
            break;

        case QLocale::C:
            res = "English";
            break;

        case QLocale::Finnish:
            res = "Finnish";
            break;

        case QLocale::French:
            res = "Français";
            break;

        case QLocale::Greek:
            res = "Greek";
            break;

        case QLocale::Italian:
            res = "Italiano";
            break;

        case QLocale::Japanese:
            res = "Japanese";
            break;

        case QLocale::Hungarian:
            res = "Magyar";
            break;

        case QLocale::Netherlands:
            res = "Nederlands";
            break;

        case QLocale::NorwegianNynorsk:
            res = "Norsk";
            break;

        case QLocale::Polish:
            res = "Polski";
            break;

        case QLocale::Brazil:
            res = "Português-Brasil";
            break;

        case QLocale::Portuguese:
            res = "Português";
            break;

        case QLocale::Romanian:
            res = "Romanian";
            break;

        case QLocale::Russian:
            res = "Russian";
            break;

        case QLocale::Slovak:
            res = "Slovak";
            break;

        case QLocale::Slovenian:
            res = "Slovenian";
            break;

        case QLocale::Swedish:
            res = "Svenska";
            break;

        case QLocale::Turkish:
            res = "Turkish";
            break;

        case QLocale::Ukrainian:
            res = "Ukrainian";
            break;

        default:
            res = "English";
            break;
    }

    return res;
}


void HTTraQt::readGUISettings()
{
    QSettings* s;
    s = new QSettings(QSettings::UserScope, "KarboSoft", "HTTraQt");
    QPoint pos = s->value("pos", QPoint(200, 200)).toPoint();
    QSize size = s->value("size", QSize(840, 640)).toSize();
    resize(size);
    move(pos);

    QString l;
    l = getLocaleString();

    currentLang = s->value("LANGUAGE", l).toString();
    currentProject = s->value("LASTPROJ").toString();
    sysFont = sysFont.toString();

    int sz = sysFont.pointSize();

    if ( sz == -1) {
        sz = sysFont.pixelSize();
    }

    fontSize = sz;

    for (int i = 0; i < 8; i++) {
        QString d = s->value("LASDIR" + QString::number(i)).toString();
        QDir dr;

        if (d.length() == 0) {
            break;
        }

        if (dr.exists(d) == true) {
            lastDirs << d;
        }
    }

    QDir dir;
    QStringList dirsLang;
    dirsLang << "/usr/share/httraqt/" << "/usr/local/share/httraqt/" << currentAppDir;

    foreach(QString entry, dirsLang) {
        helpDir = entry + "/help/";

        dir = QDir(helpDir);

        if (dir.exists() == true) {
            break;
        } else {
            helpDir = "";
        }
    }

    foreach(QString entry, dirsLang) {
        langDir = entry + "/lang/";

        dir = QDir(langDir);

        if (dir.exists() == true) {
            break;
        } else {
            langDir = "";
        }
    }
}


void HTTraQt::readSettings(bool global)
{
    QSettings* s;
    QString fname;

    QString text;

    if (global == true) {
        s = new QSettings(QSettings::UserScope, "KarboSoft", "HTTraQt");

        currentWorkDir = s->value(QString("WorkDir"), QString(QDir::homePath() + "/My Web Sites")).toString();
    } else {
        fname = currentWorkDir + "/" + currentProject + "/linprofile.ini";

        if (QFile::exists(fname) == false) { // exists
            fname = currentWorkDir + "/" + currentProject + "/hts-cache/winprofile.ini";

            if (QFile::exists(fname) == false) { // exists
                fname = "";
            }
        }
    }

    if (fname.length() == 0) { // file not found, global settings
        s = new QSettings(QSettings::UserScope, "KarboSoft", "HTTraQt");
    } else {
        s = new QSettings(fname, WIniFormat);
    }

    currentOptionsFile = fname;

    loadOptions(s);
}


void HTTraQt::onCancelAll()
{
}


void HTTraQt::onQuit()
{
    quit();
}


void HTTraQt::activatePage(int pageNum)
{
    switch (pageNum) {
        case 0: { // start tab
            currentTab = 0;

            // actions
            pcShutdown = false;
            pcHibernate = false;

            browseAct->setEnabled(false);

            viewLogAct->setEnabled(false);
            viewErrLogAct->setEnabled(false);
            pauseOptAct->setEnabled(false);
            modifyOptAct->setEnabled(false);

            break;
        }

        case 1: { // new project tab or select project
            //             qDebug() << "seite 1: " << currentWorkDir;
            (static_cast<NewProjTab*>(widgets[1]))->editBasePath->setText(currentWorkDir);
            (static_cast<NewProjTab*>(widgets[1]))->selectProj(currentProject);

            currentTab = 1;

            //actions
            browseAct->setEnabled(false);

            viewLogAct->setEnabled(false);
            viewErrLogAct->setEnabled(false);
            pauseOptAct->setEnabled(false);
            modifyOptAct->setEnabled(false);

            break;
        }

        case 2: { // options tab
            if (currentTab == 1) {   // prüfe, ob die parameter i.o. sind: aus NewProjTab
                if ((static_cast<NewProjTab*>(widgets[1]))->testIt() == false) {   // projektname muss vorhanden sein
                    return;
                }
            }

            bool nProj = rebuildWorkDirView();

            QString url;
            GetProfile("CurrentUrl", url);
            (static_cast<OptionsTab*>(widgets[2]))->textEdit->setText(url);

            QString urlFile;
            GetProfile("CurrentURLList", urlFile);
            (static_cast<OptionsTab*>(widgets[2]))->label1286->setText(urlFile);

            if (nProj == false) {
                (static_cast<OptionsTab*>(widgets[2]))->updateLastAction();
                getOptions();
            } else {
                m_todo = 0;
                (static_cast<OptionsTab*>(widgets[2]))->comboAction->setCurrentIndex(m_todo);
                readSettings(true); // global
                m_todo = 0;
            }

            // wenn projekt existierte, einlesen von diversen settings und url liste.

            if ((m_todo == LAST_ACTION) || (m_todo == LAST_ACTION - 1)) {
                if (checkContinue(true) == false) {
                    return;
                }
            }

            currentTab = 2;

            //actions
            browseAct->setEnabled(false);

            viewLogAct->setEnabled(false);
            viewErrLogAct->setEnabled(false);
            pauseOptAct->setEnabled(false);
            modifyOptAct->setEnabled(false);

            break;
        }

        case 3: { // confirm tab with delay time
            if (currentTab == 2) {   // prüfe, ob die parameter i.o. sind: aus OptionsTab
                if ((static_cast<OptionsTab*>(widgets[2]))->testIt() == false) {    // die url liste muss vorhanden sein
                    MessageBox::exec(this, translate(_NOURL), translate(_URLNOTCOMP), QMessageBox::Critical);

                    return;
                }
            }

            (static_cast<OptionsTab*>(widgets[2]))->updateLastAction();

            QString url = (static_cast<OptionsTab*>(widgets[2]))->textEdit->toPlainText();
            SetProfile("CurrentUrl", url);

            QString urlFile = (static_cast<OptionsTab*>(widgets[2]))->label1286->text();
            SetProfile("CurrentURLList", urlFile);

            (static_cast<ConfirmTab*>(widgets[3]))->groupPCoff->setChecked(false);

            (static_cast<ConfirmTab*>(widgets[3]))->labelHH->clear(); // HH
            (static_cast<ConfirmTab*>(widgets[3]))->labelMM->clear(); // MM
            (static_cast<ConfirmTab*>(widgets[3]))->labelSS->clear(); // SS

            currentTab = 3;

            getMainOptionsFromGUI();
            writeSettings(false); // write project settings

            // check current action, if
            QString prDir;
            prDir =  currentWorkDir + "/" + currentProject + "/";

            //actions
            browseAct->setEnabled(false);

            viewLogAct->setEnabled(false);
            viewErrLogAct->setEnabled(false);
            pauseOptAct->setEnabled(false);
            modifyOptAct->setEnabled(false);

            menuPreferences->setEnabled(true);
            break;
        }

        case 4: { // progress tab

            currentTab = 4;

            //actions
            browseAct->setEnabled(true);

            viewLogAct->setEnabled(true);
            viewErrLogAct->setEnabled(true);
            pauseOptAct->setEnabled(true);
            modifyOptAct->setEnabled(true);

            menuPreferences->setEnabled(false);

            for (int i = 1; i < NStatsBuffer; i++) {
                (static_cast<ProgressTab*>(widgets[4]))->progressSheet->setRowHidden(i, true);
            }

            launch();

            break;
        }

        case 5: { // log tab
            currentTab = 5;

            // actions
            browseAct->setEnabled(true);

            viewLogAct->setEnabled(false);
            viewErrLogAct->setEnabled(false);
            pauseOptAct->setEnabled(false);
            modifyOptAct->setEnabled(false);

            menuPreferences->setEnabled(true);
            break;
        }

        default:
            break;
    }

    for (int i = 0; i <= 5; i++) {
        if (i == pageNum) {
            if (widgets[i]->isHidden() == true) {
                widgets[i]->show();
            }
        } else {
            if (widgets[i]->isHidden() == false) {
                widgets[i]->hide();
            }
        }
    }

    buttonsWidget->onButtons(pageNum);
}


HTTraQt::~HTTraQt()
{
    if(_singular->isAttached()) {
        _singular->detach();
    }

    quit();
}


int HTTraQt::removeFolder(QDir &dir)
{
    int res = 0;
    //list of dirs
    QStringList lstDirs  = dir.entryList(QDir::Dirs | QDir::AllDirs | QDir::NoDotAndDotDot);
    //file list
    QStringList lstFiles = dir.entryList(QDir::Files);

    //rm files
    foreach(QString entry, lstFiles) {
        QString entryAbsPath = dir.absolutePath() + "/" + entry;
        QFile::remove(entryAbsPath);
    }

    //for directories recursive
    foreach(QString entry, lstDirs) {
        QString entryAbsPath = dir.absolutePath() + "/" + entry;
        QDir dr;
        dr = QDir(entryAbsPath);
        removeFolder(dr);
    }

    //deleting of directory
    if (!QDir().rmdir(dir.absolutePath())) {
        res = 1;
    }

    return res;
}


void HTTraQt::viewLog()
{
    QString name = currentWorkDir + "/" + currentProject + "/"  "hts-log.txt";

    // fichier log existe ou on est télécommandé par un !
    if (QFile::exists(name) == true ) {
        QDesktopServices::openUrl(QUrl::fromLocalFile(qPrintable( name )));
        return;
    }

    //     name = currentWorkDir + "/" + currentProject + "/"  "hts-err.txt";
    //
    //     if (QFile::exists(name) == true ) {
    //         QDesktopServices::openUrl(QUrl::fromLocalFile(qPrintable( name )));
    //         return;
    //     }

    QString l = translate(_NOLOGFILES);
    l.replace("%s", currentProject);

    MessageBox::exec(this, translate(_ERROR), l, QMessageBox::Warning);
}


void HTTraQt::viewErrorLog()
{
    QString name = currentWorkDir + "/" + currentProject + "/"  "hts-err.txt";

    if (QFile::exists(name) == true ) {
        QDesktopServices::openUrl(QUrl::fromLocalFile(qPrintable( name )));
        return;
    }

    QString l = translate(_NOLOGFILES);
    l.replace("%s", currentProject);
    MessageBox::exec(this, translate(_ERROR), l, QMessageBox::Warning);
}

#if 0
void HTTraQt::createFontSizeMenu()
{
    fontSizeMenu = menuPreferences->addMenu(translate(_SEL_FONT));
    fsizeGroup = new QActionGroup(this);
    QStringList szList;
    szList << "9" << "10" << "12" << "14" << "16" << "18" << "20";

    foreach(QString entry, szList) {
        QAction *tmpAction = new QAction(entry, fontSizePrefAct);
        tmpAction->setCheckable(true);

        fontSizeMenu->addAction(tmpAction);
        fsizeGroup->addAction(tmpAction);

        if (fontSize == entry.toInt()) {
            tmpAction->setChecked(true);
        }

        actFSizeSelect.push_back(tmpAction);
    }

    connect(fsizeGroup, SIGNAL(triggered(QAction*)), this, SLOT(selectFontSize(QAction*)));
}
#endif



bool HTTraQt::readLangDir()
{
    bool found = false;
    QString lngDirName;
    QStringList dirsLang;
    QDir dir;
    dirsLang << "/usr/share/httraqt/" << "/usr/local/share/httraqt/" << currentAppDir;

    //     dictFormat = 0;

    foreach(QString entry, dirsLang) {
        lngDirName = entry + "/lang/";

        dir = QDir(lngDirName);

        if (dir.exists() == true) {
            found = true;
            break;
        }

        lngDirName = entry + "/language/";
        dir = QDir(lngDirName);

        if (dir.exists() == true) {
            found = true;
            break;
        }
    }

    if(found == false) {
        return false;
    }

    langFiles.clear();

    QStringList fList = dir.entryList(QStringList("*.utf"));

    found = false;

    langMenu = menuPreferences->addMenu(translate(_LANGUAGE));

    langGroup = new QActionGroup(this);


    for (QStringList::Iterator iL = fList.begin(); iL != fList.end(); iL++) {
        QFile fLang(lngDirName + *iL);

        if (fLang.exists() == false) {
            continue;
        }

        QString iconName;

        if (fLang.open(QIODevice::ReadOnly)) {      //wird eingelesen
            QTextStream stream(&fLang);
            stream.setCodec("UTF-8");
            QString line, nm;

            int lines = 0;

            while (!stream.atEnd()) {
                line = stream.readLine(); // line of text excluding '\n'
                lines++;

                if (line == "LANGUAGE_NAME") {
                    line = stream.readLine();
                    lines++;
                    nm = line;
                    continue;
                }

                if (line == "LANGUAGE_ISO") {
                    line = stream.readLine();
                    selectedLang = line;
                    lines++;

                    iconName = lngDirName + "flags/" + line + ".png";

                    found = true;

                    langFiles += (*iL) + ":" + nm;
                    QAction *tmpAction = new QAction(nm, langPrefAct);
                    tmpAction->setCheckable(true);

                    if (QFile::exists(iconName) == true) {
                        QFile flIcon(iconName);

                        if (flIcon.size() < 1024 ) { // checking of filesize
                            tmpAction->setIcon(QIcon(iconName));
                        }
                    }

                    langGroup->addAction(tmpAction);
                    langMenu->addAction(tmpAction);

                    if (currentLang == nm) {
                        tmpAction->setChecked(true);
                    }

                    actLangSelect.push_back(tmpAction);
                    break;
                }

                if (lines > 8) {
                    break;
                }
            }

            fLang.close();

        } else {
            continue;
        }
    }

    connect(langGroup, SIGNAL(triggered(QAction*)), this, SLOT(setLang(QAction*)));

    return (found);
}


void HTTraQt::selectFontSize(QAction* mnu)
{
    QString lngStr;

    lngStr = mnu->text();
    fontSize = lngStr.toInt();

    mnu->setChecked(true);

    int sz = sysFont.pointSize();

    // for lang menu and for fontsize menu
    if ( sz == -1) {
        programStyleSheet = QString().sprintf("font-size: %dpx", fontSize);
    } else {
        programStyleSheet = QString().sprintf("font-size: %dpt", fontSize);
    }

    QString sSheet2 = QString("QMenu { %1; }").arg( programStyleSheet );

    setStyleSheet(programStyleSheet);

    langMenu->setStyleSheet(sSheet2);

    setFontForWidgets();
}


void HTTraQt::setLang(QAction* mnu)
{
    QString lngStr;
    mnu = langGroup->checkedAction();

    lngStr = mnu->text();
    currentLang = lngStr;

    if (getLangTable() == false) {
        qDebug() << "setLang" << false;
    }

    QVector<QAction*>::iterator itL;

    disconnect(langGroup, SIGNAL(triggered(QAction*)), this, SLOT(setLang(QAction*)));

    mnu->setChecked(true);

    connect(langGroup, SIGNAL(triggered(QAction*)), this, SLOT(setLang(QAction*)));

    setLangGUI();
}


void HTTraQt::convertTranslateFiles()
{
    //     bool found = false;
    QString lngDirName = currentAppDir + "/lang/";
    QDir dir(lngDirName);

    QStringList fList = dir.entryList(QStringList("*.utf"));

    for (QStringList::Iterator iL = fList.begin(); iL != fList.end(); iL++) {
        if (loadTranslation(lngDirName + *iL) == false) {
            continue;
        }

        QFile fLang(lngDirName + *iL);
        QTextStream streamInput;

        if (fLang.open(QIODevice::ReadOnly)) {      //wird eingelesen
            streamInput.setDevice(&fLang);
            streamInput.setCodec("UTF-8");
        } else {
            continue;
        }

        // #ifdef TRANSLATE_FILE
        QFile langTrFile(lngDirName + (*iL) + ".new");


        if (langTrFile.open(QIODevice::WriteOnly)) {
            bool trBeg = false;
            QTextStream streamOutput(&langTrFile);
            streamOutput.setCodec("UTF-8");

            while (trBeg == false) {
                QString line;
                line = streamInput.readLine();

                if (line.length() > 0) {
                    if (line.indexOf("OK") == 0 || line.indexOf("Ok") == 0) { // beg of translations detected
                        trBeg = true;
                        break;
                    } else {
                        streamOutput << line << "\r\n";
                    }
                }
            }

            if (trBeg == true) {
                for (int i = 0; engText[i] != ""; i++) {
                    QString ll = translate(i);

                    if (ll.length() > 0) {
                        ll.replace( "\n", "\\r\\n");
                        ll.replace( "\n", "\\n");
                        ll.replace( "\t", "\\t");
                        ll.replace( "/", "\\\\");
                        ll.replace( "&", "&amp;");
                        ll.replace( ">", "&gt;");
                        ll.replace( "<", "&lt;");
                        streamOutput << QString().sprintf("t%03d=", i) << ll << "\r\n";
                    }
                }
            }
        } else {
            qDebug() << "cannot open" <<  langTrFile.fileName();
        }

        langTrFile.close();
        fLang.close();
    }
}

// thanks to Leon
// https://qt-project.org/forums/viewthread/5957
//HIBERNATE
void HTTraQt::hibernate()
{
    int ret;
    MessageTimerBox msgBox;

    bool num;
    int minutes = (static_cast<ConfirmTab*>(widgets[3]))->lineEditCounter->text().toInt(&num);

    if (num == false) {
        minutes = 1;
    }

    msgBox.setDefaultText("Hibernate PC?\nAutoclose in %d seconds...");
    msgBox.setIcon(QMessageBox::Question);
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox.setAutoClose(true);
    msgBox.setTimeout(minutes * 60); //Closes after x minutes
    ret = msgBox.exec();

    if (ret == QMessageBox::No) {
        return;
    }

#ifdef __WIN32__
    // code for win systems
#endif

#ifdef __linux__
    bool gnome_power1 = false;
    bool gnome_power2 = false;
    bool hal_works = false;
    QDBusMessage response;

    gnome_power1 = QProcess::startDetached("gnome-power-cmd.sh hibernate");
    gnome_power2 = QProcess::startDetached("gnome-power-cmd hibernate");

    if(!gnome_power1 && !gnome_power2 && verbose) {
        qWarning() << "W: gnome-power-cmd and gnome-power-cmd.sh didn't work";
    }

    if(!gnome_power1 && !gnome_power2) {
        QDBusInterface powermanagement("org.freedesktop.Hal",
                                       "/org/freedesktop/Hal/devices/computer",
                                       "org.freedesktop.Hal.Device.SystemPowerManagement",
                                       QDBusConnection::systemBus());
        response = powermanagement.call("Hibernate");

        if(response.type() == QDBusMessage::ErrorMessage) {
            if(verbose) {
                qWarning() << "W: " << response.errorName() << ":" << response.errorMessage();
            }
        } else {
            hal_works = true;
        }
    }

    if(!hal_works && !gnome_power1 && !gnome_power2) {
        QDBusInterface powermanagement("org.freedesktop.DeviceKit.Power", "/org/freedesktop/DeviceKit/Power",
                                       "org.freedesktop.DeviceKit.Power", QDBusConnection::systemBus());

        if(response.type() == QDBusMessage::ErrorMessage) {
            if(verbose) {
                qWarning() << "W: " << response.errorName() << ":" << response.errorMessage();
            }
        }
    }

#endif // LINUX

#ifdef __APPLE__

#endif
}


//SHUTDOWN
void HTTraQt::shutdown()
{
    int ret;
    MessageTimerBox msgBox;

    bool num;
    int minutes = (static_cast<ConfirmTab*>(widgets[3]))->lineEditCounter->text().toInt(&num);

    if (num == false) {
        minutes = 1;
    }

    msgBox.setDefaultText("Shutdown PC?\nAutoclose in %d seconds...");
    msgBox.setIcon(QMessageBox::Question);
    msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
    msgBox.setAutoClose(true);
    msgBox.setTimeout(minutes * 60); //Closes after three seconds
    ret = msgBox.exec();

    if (ret == QMessageBox::No) {
        return; // no shutdown
    }

#ifdef __WIN32__
    // code for win systems
#endif

#ifdef __linux__
    bool shutdown_works = false;
    bool gnome_power1 = false;
    bool gnome_power2 = false;
    bool hal_works = false;
    QDBusMessage response;

    QDBusInterface gnomeSessionManager("org.gnome.SessionManager",
                                       "/org/gnome/SessionManager", "org.gnome.SessionManager",
                                       QDBusConnection::sessionBus());
    response = gnomeSessionManager.call("RequestShutdown");

    if(response.type() == QDBusMessage::ErrorMessage) {
        if(verbose) {
            qWarning() << "W: " << response.errorName() << ":" << response.errorMessage();
        }

        gnome_power1 = QProcess::startDetached("gnome-power-cmd.sh shutdown");
        gnome_power2 = QProcess::startDetached("gnome-power-cmd shutdown");

        if(verbose && !gnome_power1 && !gnome_power2) {
            qWarning() << "W: gnome-power-cmd and gnome-power-cmd.sh didn't work";
        }
    } else {
        shutdown_works = true;
    }

    QDBusInterface kdeSessionManager("org.kde.ksmserver", "/KSMServer",
                                     "org.kde.KSMServerInterface", QDBusConnection::sessionBus());
    response = kdeSessionManager.call("logout", 0, 2, 2);

    if(response.type() == QDBusMessage::ErrorMessage) {
        if(verbose) {
            qWarning() << "W: " << response.errorName() << ":" << response.errorMessage();
        }
    } else {
        shutdown_works = true;
    }

    if(!shutdown_works && !gnome_power1 && !gnome_power2) {
        QDBusInterface powermanagement("org.freedesktop.Hal",
                                       "/org/freedesktop/Hal/devices/computer",
                                       "org.freedesktop.Hal.Device.SystemPowerManagement",
                                       QDBusConnection::systemBus());
        response = powermanagement.call("Shutdown");

        if(response.type() == QDBusMessage::ErrorMessage) {
            if(verbose) {
                qWarning() << "W: " << response.errorName() << ":" << response.errorMessage();
            }
        } else {
            hal_works = true;
        }
    }

    if(!hal_works && !shutdown_works && !gnome_power1 && !gnome_power2) {
        QDBusInterface powermanagement("org.freedesktop.ConsoleKit",
                                       "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit.Manager",
                                       QDBusConnection::systemBus());
        response = powermanagement.call("Stop");

        if(response.type() == QDBusMessage::ErrorMessage) {
            if(verbose) {
                qWarning() << "W: " << response.errorName() << ":" << response.errorMessage();
            }

            QProcess::startDetached("sudo shutdown -P now");
        }
    }

#endif // UNIX

#ifdef __APPLE__

#endif
}


bool HTTraQt::getLangTable()
{
    QString lang = currentLang;
    QString fileLang = "";

    for (QStringList::Iterator iLang = langFiles.begin(); iLang != langFiles.end(); iLang++) {
        if ((*iLang).contains(":" + lang) > 0) {
            fileLang = *iLang;
            fileLang.remove(":" + lang);
            break;
        }
    }

    if (fileLang == "") {
        return (false);
    }

    if (QFile::exists(langDir + fileLang) == false) {
        MessageBox::exec(this, translate(_ERROR), "Language file not exists!\n\n"
                         + langDir + "\n\n" + fileLang, QMessageBox::Warning);

        return (false);
    }

    return loadTranslation(langDir + fileLang);
}


void HTTraQt::setLangGUI()
{
    (static_cast<StartTab*>(widgets[0]))->translateTab();
    (static_cast<NewProjTab*>(widgets[1]))->translateTab();
    (static_cast<OptionsTab*>(widgets[2]))->translateTab();
    (static_cast<ConfirmTab*>(widgets[3]))->translateTab();
    (static_cast<ProgressTab*>(widgets[4]))->translateTab();
    (static_cast<FinalTab*>(widgets[5]))->translateTab();

    // actions translate
    translateActions();

    rebuildWorkDirView();
}


void HTTraQt::translateActions(QAction* act, int id)
{
    QString tmp;
    QString str = translate(id);
    int posTab;

    if (str.length() == 0) {
        return;
    }

    posTab = str.indexOf("\\t");
    tmp = translate(id);

    if (posTab > 0) {
        QString shrtcut = str.mid(posTab + 2);
        QStringList tmpC = tmp.split("\\t");
        act->setText(tmpC.at(0));
        act->setFont(sysFont);
        act->setShortcut(shrtcut);
    } else {
        act->setText(tmp);
        act->setFont(sysFont);
    }
}


void HTTraQt::translateActions()
{
    buttonsWidget->translateButtons();

    menuFile->setTitle(translate(_FILE));

    translateActions(newProjAct, _P18);

    translateActions(browseAct, _P23);
    browsProjAct->setStatusTip ( translate ( _BROWSEEXISTS ) );

    translateActions(exitAct, _EXIT);
    //     exitAct->setStatusTip ( tr ( "Exit" ) );

    menuPreferences->setTitle(translate(_PREF));
    //     menuPreferences->setStyleSheet(sSheet);
    translateActions(loadDefOptAct, _LOADDEF);
    //     loadDefOptAct->setStatusTip ( tr ( "Load default options" ) );

    translateActions(saveOptAct, _SAVEDEF);
    //     saveOptAct->setStatusTip ( tr ( "Save default options" ) );

    translateActions(resetOptToDefAct, _RESETTODEF);
    //     resetOptToDefAct->setStatusTip ( tr ( "Reset to default options" ) );

    translateActions(loadOptAct,  _LOADOPT);
    //     loadOptAct->setStatusTip ( tr ( "Load options..." ) );

    //     translateActions(recentAct, "Recent file");
    //     recentAct->setStatusTip ( tr ( "Recent file" ) );

    translateActions(saveOptAsAct, _SAVEOPTAS);
    //     translateActions(selectFontAct, _SEL_FONT);
    //     saveOptAsAct->setStatusTip ( tr ( "Save options as..." ) );
    langMenu->setTitle(translate(_LANGPREF));
    //     fontSizeMenu->setTitle(translate(_SEL_FONT));

    menuMirror->setTitle(translate(_MIRROR));
    // menuMirror->setStyleSheet(sSheet);
    translateActions(modifyOptAct, _MODIFYOPT);
    //     modifyOptAct->setStatusTip ( tr ( "Modify options" ) );

    pauseOptAct->setCheckable(true);
    translateActions(pauseOptAct, _PAUSETRANSF);
    //     pauseOptAct->setStatusTip ( tr ( "Pause transfer" ) );

    menuLog->setTitle(translate(_LOG));
    //     menuLog->setStyleSheet(sSheet);
    translateActions(viewLogAct, _VIEW_LOG);
    //     viewLogAct->setStatusTip ( translate("View log" ) );

    translateActions(viewErrLogAct, _VIEWERRLOG);
    //     viewErrLogAct->setStatusTip ( tr ( "View error log" ) );

    menuWindow->setTitle(translate(_WINDOW));
    //  menuWindow->setStyleSheet(sSheet);
    translateActions(hideAct, _HIDE);
    translateActions(restAct, _OPEN);
    //     hideAct->setStatusTip ( tr ( "Hide" ) );

    menuHelp->setTitle(translate(_HELP));
    //     menuHelp->setStyleSheet(sSheet);
    translateActions(checkAct, _TOPROJECTPAGE);
    translateActions(stepByStepAct, _STEPBYSTEP);
    translateActions(contentAct, _CONTENTS);
    translateActions(aboutAct, _ABOUTPROG);
}


void HTTraQt::quit()
{
    int ans;

    if (pcHibernate == false && pcShutdown == false ) {
        ans = MessageBox::exec(this, translate(_QUIT), translate(_REALLYQUIT), QMessageBox::Question);

        if (ans == QMessageBox::No) {
            return;
        }
    }

    writeGUISettings();

    qApp->quit();
}


void HTTraQt::closeEvent(QCloseEvent* ce)
{
    int ans;

    if (pcHibernate == false && pcShutdown == false ) {
        ans = MessageBox::exec(this, translate(_QUIT), translate(_REALLYQUIT), QMessageBox::Question);

        if (ans == QMessageBox::No) {
            ce->ignore();
            return;
        }
    }

    writeGUISettings();

    //     ce->accept();

    qApp->quit();
    //     return;
}


void HTTraQt::aboutQt()
{
    QMessageBox::aboutQt(this, PROGRAM_NAME);
}


void HTTraQt::about()
{
    AboutDialog *ad;
    ad = new AboutDialog(this);

    ad->exec();
    delete ad;
}


// modifs RX 10/10/98: gestion des ,
QString HTTraQt::change(char* chaine, char c)
{
    int comma = 1;
    int first = 1;
    QString chaine1;

    for (int i = 0; i < (int) strlen(chaine); i++) {
        switch (chaine[i]) {
            case 10:
            case 13:
            case 9:
            case ' ':
            case ',':
                comma = 1;
                break;

            default:

                if (comma) {
                    if (!first) {
                        chaine1 += ' ';
                    } else {
                        first = 0;
                    }

                    chaine1  += c;

                    comma = 0;
                }

                chaine1 += chaine[i];

                break;
        }
    }

    return chaine1;
}


void HTTraQt::getMainOptionsFromGUI()
{
    QString str;
    QStringList sList;

    // str = firstWidget->label1027->currentText();
    // SetProfileString(mainOptions, "Category", str);
    str = (static_cast<OptionsTab*>(widgets[2]))->textEdit->toPlainText();
    SetProfile("CurrentUrl", str);

    //end of combobox
    str = (static_cast<OptionsTab*>(widgets[2]))->label1286->text();
    SetProfile("CurrentURLList", str);
}


void HTTraQt::gOptions(bool dialog)
{
    if (mth == NULL ) {
        return;
    }

    OptionsDialog *oDia;

    if (dialog == true) {
        oDia = new OptionsDialog(this);
        oDia->exec();
    }

    if (global_opt != NULL) {
        getOptStruct(global_opt);
    }

    if (dialog == true) {
        delete oDia;
        writeSettings(false);
    }
}


void HTTraQt::setOptions()
{
    gOptions(false); // without dialog
}


void HTTraQt::modifyOptions()
{
    gOptions(true);
}


void HTTraQt::setMainOptionsToGUI()
{
    QString str;
    QStringList sList;

    readSettings(true);
    // GetProfileString(mainOptions, "Category", str);
    //   str = firstWidget->label1027->Text();
    GetProfile("CurrentUrl", str);
    str.replace(" ", "\n");

    (static_cast<OptionsTab*>(widgets[2]))->textEdit->setText(str);

    str = (static_cast<OptionsTab*>(widgets[2]))->comb01;
    sList = str.split("\n");

    GetProfile("CurrentURLList", str);
    (static_cast<OptionsTab*>(widgets[2]))->label1286->setText(str);
}


bool HTTraQt::RemoveEmptyDir(QString path)
{
    int ans = MessageBox::exec(this, translate(_REMOVE), translate(_SURE), QMessageBox::Question);

    if (ans == QMessageBox::No) {
        return false;
    }

    QDirIterator it(path, QDirIterator::Subdirectories);

    while (it.hasNext()) {
        QString n = it.next();

        if (n == "." || n == "..") {
            continue;
        }

        QString fullPath = path + "/" + n;

        QDir subd(fullPath);

        if (subd.rmdir(fullPath) == false) {
            MessageBox::exec(this, translate(_ERR), translate(_ANYDIRNOTEMPTY), QMessageBox::Warning);

            return false;
        }
    }

    QStringList names;

    QString maske = path + "/*.*";
    QDir d(path);
    names = d.entryList(QStringList("*.*"));

    for (QStringList::Iterator ist = names.begin(); ist != names.end(); ++ist) {
        if (*ist == "." || *ist == "..") {   // is dir
            continue;
        } else {
            d.remove(path + "/" + (*ist));
        }
    }

    if (d.remove(maske) == true) {
        d.rmdir(path);
    }

#ifdef WIN32
    QDir::setCurrent("C:\\");

#else
    QString home = QDir::homePath();

    QDir::setCurrent(home);

#endif

    return true;
}

