/*  Copyright (c) MediaArea.net SARL. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license that can
 *  be found in the License.html file in the root of the source tree.
 */

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "easyviewwidget.h"
#include "prefs.h"
#include "about.h"
#include "export.h"
#include "sheetview.h"
#include "sheet.h"
#include "configtreetext.h"
#include "custom.h"

#include <QDropEvent>
#include <QFileDialog>
#include <QMessageBox>
#include <QDir>
#include <QMimeData>
#include <QActionGroup>
#include <QTextBrowser>
#include <QLabel>
#include <QSettings>
#include <QDomDocument>
#include <QTreeWidget>
#include <QToolButton>
#include <QToolBar>
#include <QMainWindow>
#include <QMenuBar>
#include <QTranslator>
#include <QFontDatabase>
#include <QPushButton>
#include <QDesktopServices>
#include <QStyleHints>
/*
#include <qwt/qwt_plot.h>
#include <qwt/qwt_plot_curve.h>
#include <qwt/qwt_plot_picker.h>
*/

#include <memory>
#include <ZenLib/Ztring.h>
#include <ZenLib/ZtringListList.h>
#include <ZenLib/ZtringListListF.h>
using namespace ZenLib;
#define wstring2QString(_DATA) \
    QString::fromUtf8(Ztring(_DATA).To_UTF8().c_str())
#define QString2wstring(_DATA) \
    Ztring().From_UTF8(_DATA.toUtf8())

#define VERSION "26.05"

#ifndef MEDIAINFO_HTML_NO
#include "htmlwidget.h"
#endif

#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) //UWP Application
#include <QtPlatformHeaders/QWindowsWindowFunctions>
#include <ZenLib/Os_Utils.h>

//TODO: Use public Qt API when available (see Qt bug #49299)
#include <QtCore/private/qeventdispatcher_winrt_p.h>

#include <wrl.h>
#include <windows.foundation.h>
#include <windows.storage.h>
#include <windows.storage.pickers.h>
#include <windows.storage.accesscache.h>
#include <windows.storage.streams.h>

using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace ABI::Windows::Foundation;
using namespace ABI::Windows::Foundation::Collections;
using namespace ABI::Windows::Storage;
using namespace ABI::Windows::Storage::Pickers;
using namespace ABI::Windows::Storage::AccessCache;
using namespace ABI::Windows::Storage::Streams;

static inline HRESULT showFilesPicker(ComPtr<IAsyncOperation<IVectorView<StorageFile*>*> >& AsyncFiles)
{
    ComPtr<IFileOpenPicker> Picker;
    HRESULT ToReturn;

    if (FAILED(ToReturn = ActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FileOpenPicker).Get(), &Picker)) || !Picker)
    {
        qDebug() << "WinRT: unable to initialize picker";
        return ToReturn;
    }

    if (FAILED(ToReturn = Picker->put_ViewMode(PickerViewMode_Thumbnail)))
    {
        qDebug() << "WinRT: Unable to set view mode";
        return ToReturn;
    }

    if (FAILED(ToReturn = Picker->put_SuggestedStartLocation(PickerLocationId_VideosLibrary)))
    {
        qDebug() << "WinRT: Unable to set location";
        return ToReturn;
    }

    ComPtr<IVector<HSTRING> > FileTypes;

    if (FAILED(ToReturn = Picker->get_FileTypeFilter(&FileTypes)) || !FileTypes)
    {
        qDebug() << "WinRT: Unable to get files filter";
        return ToReturn;
    }

    if (FAILED(ToReturn = FileTypes->Append(HString::MakeReference(L"*").Get())))
    {
        qDebug() << "WinRT: Unable to append files filter";
        return ToReturn;
    }

    if (FAILED(ToReturn = Picker->PickMultipleFilesAsync(&AsyncFiles)) || !AsyncFiles)
    {
        qDebug() << "WinRT: unable to pick files";
        return ToReturn;
    }

    return ToReturn;
}

static inline HRESULT showFolderPicker(ComPtr<IAsyncOperation<StorageFolder*> >& AsyncFolder)
{
    ComPtr<IFolderPicker> Picker;
    HRESULT ToReturn;

    if (FAILED(ToReturn = ActivateInstance(HString::MakeReference(RuntimeClass_Windows_Storage_Pickers_FolderPicker).Get(), &Picker)) || !Picker)
    {
        qDebug() << "WinRT: unable to initialize picker";
        return ToReturn;
    }

    if (FAILED(ToReturn = Picker->put_SuggestedStartLocation(PickerLocationId_VideosLibrary)))
    {
        qDebug() << "WinRT: Unable to set location";
        return ToReturn;
    }

    ComPtr<IVector<HSTRING> > FileTypes;

    if (FAILED(ToReturn = Picker->get_FileTypeFilter(&FileTypes)) || !FileTypes)
    {
        qDebug() << "WinRT: Unable to get files filter";
        return ToReturn;
    }

    if (FAILED(ToReturn = FileTypes->Append(HString::MakeReference(L"*").Get())))
    {
        qDebug() << "WinRT: Unable to append files filter";
        return ToReturn;
    }

    if (FAILED(ToReturn = Picker->PickSingleFolderAsync(&AsyncFolder)) || !AsyncFolder)
    {
        qDebug() << "WinRT: unable to pick folder";
        return ToReturn;
    }

    return ToReturn;
}
#endif

MainWindow::MainWindow(const QStringList& filesnames, int viewasked, QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    C = new Core();

#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) //Setup UI for winRT
    setMenuBar(new QMenuBar(0));
#else
    setWindowTitle("MediaInfo");
#endif

    translator = new QTranslator(this);
    settings = new QSettings("MediaArea.net", "MediaInfo", this);
    defaultSettings();
    applySettings();

    if( (viewasked>=0) && (viewasked<NB_VIEW) )
        view=ViewMode(viewasked);
    else
        view = (ViewMode)settings->value("defaultView",VIEW_EASY).toInt();

#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) //Setup UI for winRT
    addToolBar(Qt::LeftToolBarArea, ui->toolBar);
    ui->toolBar->setFloatable(false);
    ui->toolBar->setMovable(false);
    ui->menuBar->hide();
#endif

    //tests
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
    ui->actionQuit->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::WindowClose));
    ui->actionClose_All->setIcon(QIcon::fromTheme(QIcon::ThemeIcon::WindowClose));
#else
    ui->actionQuit->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
    ui->actionClose_All->setIcon(style()->standardIcon(QStyle::SP_DialogCloseButton));
#endif
    ui->actionOpen->setIcon(QIcon(":/icon/openfile.svg"));
    ui->actionOpen_Folder->setIcon(QIcon(":/icon/opendir.svg"));
    ui->actionAbout->setIcon(QIcon(":/icon/about.svg"));
    ui->actionExport->setIcon(QIcon(":/icon/export.svg"));

    menuView = new QMenu(this);
    QActionGroup* menuItemGroup = new QActionGroup(this);
    for(int v=VIEW_EASY;v<NB_VIEW;v++) {
        QAction* action = new QAction(nameView((ViewMode)v), menuItemGroup);
        action->setCheckable(true);
        #if defined(MEDIAINFO_HTML_NO)
        if (v==VIEW_HTML || v==VIEW_GRAPH)
            action->setEnabled(false);
        #endif

        if(view==v)
            action->setChecked(true);
        action->setProperty("view",v);
        ui->menuView->addAction(action);
        menuView->addAction(action);
    }
    connect(menuItemGroup,SIGNAL(triggered(QAction*)),this,SLOT(actionView_toggled(QAction*)));

    buttonView = new QToolButton();
    buttonView->setText("view");
    buttonView->setIcon(QIcon(":/icon/view.svg"));
    connect(buttonView, SIGNAL(clicked()), this, SLOT(buttonViewClicked()));
    ui->toolBar->addWidget(buttonView);

    ui->toolBar->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(ui->toolBar,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(toolBarOptions(QPoint)));
    connect(ui->toolBar,SIGNAL(toolButtonStyleChanged(Qt::ToolButtonStyle)),buttonView,SLOT(setToolButtonStyle(Qt::ToolButtonStyle)));

    timer=NULL;
    progressDialog=NULL;

    refreshDisplay();

    if(filesnames.count()>0) {
        openFiles(filesnames);
    }

    /*
    qDebug() << "0.7 " << "0.7.5 " << isNewer("0.7","0.7.5");
    qDebug() << "0.7.4 " << "0.7.5 " << isNewer("0.7.4","0.7.5");
    qDebug() << "0.7.5 " << "0.7.4 " << isNewer("0.7.5","0.7.4");
    qDebug() << "0.7.4 " << "0.7 " << isNewer("0.7.4","0.7");
    qDebug() << "0.7.5 " << "0.7.5 " << isNewer("0.7.5","0.7.5");
    */

#ifdef NEW_VERSION
    if(settings->value("checkForNewVersion",true).toBool()) {
        checkForNewVersion();
    }
#endif

}

MainWindow::~MainWindow()
{
    delete C;
    delete ui;
}

#ifdef NEW_VERSION
bool MainWindow::isNewer(const QString& distant, const QString& local) {
    QStringList local_list = local.split(".");
    QStringList distant_list = distant.split(".");
    int i;
    for(i=0;i<local_list.size();i++) {
        if(i>=distant_list.size())
            return false;
        if(local_list[i].toInt()>distant_list[i].toInt())
            return false;
        else if (local_list[i].toInt()<distant_list[i].toInt())
            return true;
    }
    return !(i>=distant_list.size());
}

void MainWindow::checkForNewVersion() {
    QString version = VERSION;
    QUrl url = QUrl("http://MediaArea.net/MediaInfo_check/changelog_"+version+".bin");
    version_file = "";
    reply = qnam.get(QNetworkRequest(url));
    qDebug() << "downloading " << url.toString();

    connect(reply, SIGNAL(finished()), this, SLOT(httpFinished()));
    connect(reply, SIGNAL(readyRead()), this, SLOT(httpReadyRead()));

}

void MainWindow::httpFinished()
{
    if (reply->error()) {
        qDebug() << "Download failed";
    } else {
        qDebug() << "Downloaded file to temp string.";
    }

    ZtringListList X;
    X.Write(version_file.toStdString().c_str());
    if (isNewer(wstring2QString(X("NewVersion")),QString(VERSION))) {
        qDebug() << "New version is available.";
        qDebug() << "latest is " << wstring2QString(X("NewVersion")).toStdString().c_str();
        ui->menuBar->addAction(tr("Update to new version"),this,SLOT(updateToNewVersion()));
    } else {
        qDebug() << "No new version available.";
        qDebug() << "latest is " << wstring2QString(X("NewVersion")).toStdString().c_str();
    }

    reply->deleteLater();
    reply = 0;
    version_file = "";
}

void MainWindow::updateToNewVersion() {
    qDebug() << "Update asked";
}

void MainWindow::httpReadyRead()
{
    version_file.append(reply->readAll());
}
#endif //NEW_VERSION

void MainWindow::toolBarOptions(QPoint p) {
#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) //QMenu crashes on UWP
    Q_UNUSED(p);

    return;
#else
    QMenu menu("toolbar options",ui->toolBar);
    QMenu *menuI = new QMenu(tr("Icon size"));
    QMenu *menuT = new QMenu(tr("Text position"));

    menu.addMenu(menuT);
    QString textsT[NBNAMES] = {tr("Icons only"),tr("Text only"),tr("Text under icons"),tr("Text beside icons")};
    QAction* actionsT[NBNAMES+1];
    const Qt::ToolButtonStyle styles[NBNAMES] = {Qt::ToolButtonIconOnly,Qt::ToolButtonTextOnly,Qt::ToolButtonTextUnderIcon,Qt::ToolButtonTextBesideIcon};
    for(int i=0;i<NBNAMES;i++) {
        actionsT[i] = menuT->addAction(textsT[i]);
    }
    actionsT[NBNAMES] = menuT->addAction(tr("Default"));

    menu.addMenu(menuI);
    const QString textsI[NBSIZES] = {tr("Small"),tr("Medium"),tr("Big"),tr("Huge")};
    QAction* actionsI[NBNAMES+1];
    QSize sizes[NBSIZES+1] = {QSize(16,16),QSize(22,22),QSize(32,32),QSize(48,48)};
    for(int i=0;i<NBSIZES;i++) {
        actionsI[i] = menuI->addAction(textsI[i]+"("+QString::number(sizes[i].width())+"x"+QString::number(sizes[i].height())+")");
    }
    actionsI[NBSIZES] = menuI->addAction(tr("Default"));

    const QAction* a = menu.exec(ui->toolBar->mapToGlobal(p));
    if(a) {
        for(int i=0;i<NBSIZES;i++) {
            if(a==actionsI[i]) {
                settings->setValue("iconSize",sizes[i]);
                break;
            }
        }
        if(a==actionsI[NBSIZES]) {
            settings->remove("iconSize");
        }
        for(int i=0;i<NBNAMES;i++) {
            if(a==actionsT[i]) {
                settings->setValue("iconStyle",styles[i]);
                break;
            }
        }
        if(a==actionsT[NBNAMES]) {
            settings->remove("iconStyle");
        }
    }

    ui->toolBar->setToolButtonStyle(Qt::ToolButtonStyle(settings->value("iconStyle",Qt::ToolButtonIconOnly).toInt()));
    ui->toolBar->setIconSize(settings->value("iconSize",QSize(32,32)).toSize());

    delete menuT;
    delete menuI;
#endif
}

QString MainWindow::shortName(QDir d, QString name) {
    //Elminating unuseful info from filenames
    return d.relativeFilePath(name);
}

QString MainWindow::shortName(Core*C, QString name) {
    //Elminating unuseful info from filenames
    return shortName(getCommonDir(C),name);
}

QDir MainWindow::getCommonDir(Core*C) {
    QList<QStringList> list;
    QStringList dirName;
    unsigned fileCount = (unsigned)C->Count_Get();
    if(fileCount==0)
        return QDir::home();
    for(unsigned filePos=0;filePos<fileCount;filePos++)
        list.append(QDir::toNativeSeparators(wstring2QString(C->Get(filePos,Stream_General, 0, __T("CompleteName")))).split(QDir::separator ()));
    if(!list.isEmpty())
        for(int i=0;i<list[0].size()-1;++i) {
            int j;
            for(j=1;(j<list.size())&&(list[j].size()>i);++j) {
                if(list[j][i]!=list[0][i])
                    break;
            }
            if((j<list.size())&&(list[j].size()>=i))
                break;
            else
                dirName.append(list[0][i]);
        }
    QDir dir(dirName.join(QDir::separator ()));
    return dir;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    QFile file;
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        // force refresh of text of view button on toolbar
        buttonView->setText(tr("View"));
        ui->toolBar->setToolButtonStyle(Qt::ToolButtonStyle(Qt::ToolButtonIconOnly));
        ui->toolBar->setToolButtonStyle(Qt::ToolButtonStyle(settings->value("iconStyle",Qt::ToolButtonIconOnly).toInt()));
        // update texts of view menu items
        for(int v=VIEW_EASY;v<NB_VIEW;v++) {
            ui->menuView->actions().at(v)->setText(nameView((ViewMode)v));
        }
        // set MediaInfoLib language
        file.setFileName(":/languages/Plugin/Language/" + settings->value("language", "en").toString() + ".csv");
        if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
            QTextStream in(&file);
            QString fileContent = in.readAll();
            C->MI->Option_Static(__T("Language"), fileContent.toStdWString());
            file.close();
        }
        // refresh titlebar and MediaInfoLib output
        refreshDisplay();
        break;
    default:
        break;
    }
}

void MainWindow::closeEvent(QCloseEvent *e)
{
    settings->setValue("geometry", saveGeometry());
    settings->setValue("windowState", saveState());
    QMainWindow::closeEvent(e);
}

void MainWindow::openFiles(QStringList fileNames) {
    //Configuring
    if(fileNames.isEmpty())
        return;
    // Process input paths/filenames/URLs
    for (int i = 0; i < fileNames.size(); ++i) {
        // Skip processing if is a network URL
        QUrl url(fileNames[i]);
        if (url.isValid())
            if (!url.scheme().isEmpty())
                if (url.scheme().startsWith("http", Qt::CaseInsensitive) ||
                    url.scheme().startsWith("ftp", Qt::CaseInsensitive) ||
                    url.scheme().startsWith("sftp", Qt::CaseInsensitive))
                    continue;
        // Resolve to target if is a Windows .lnk shortcut
        QFileInfo fileInfo(fileNames[i]);
        if (fileInfo.suffix().compare("lnk", Qt::CaseInsensitive) == 0 && !fileInfo.symLinkTarget().isEmpty())
            fileNames[i] = fileInfo.symLinkTarget();
        // Convert directory separators to native separators for file paths
        fileNames[i] = QDir::toNativeSeparators(fileNames[i]);
    }
    C->Menu_File_Open_Files_Begin(settings->value("closeBeforeOpen",true).toBool(), true);
    for (int Pos=0; Pos<fileNames.size(); Pos++)
        C->Menu_File_Open_Files_Continue(QString2wstring(fileNames[Pos]));
    openTimerInit();
}

void MainWindow::openTimerInit ()
{
    progressDialog=new QProgressDialog(tr("Opening files..."), tr("Abort Opening"), 0, 10000, this);
    progressDialog->setWindowModality(Qt::WindowModal);
    progressDialog->setMinimumDuration(0);
    progressDialog->setWindowTitle("MediaInfo");

    if (timer==NULL)
    {
        timer=new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(updateProgressBar()));
        timer->start(100);
    }
}

void MainWindow::updateProgressBar ()
{
    if (progressDialog==NULL)
        return;

    progressDialog->setValue((int)C->State_Get());

    if (C->State_Get()==10000 || progressDialog->wasCanceled())
    {
        progressDialog->hide();
        timer->stop();

        //Cancel MediaInfoLib parsing if canceled
        if (progressDialog->wasCanceled())
            C->Menu_File_Open_Files_Begin(true);

        delete progressDialog; progressDialog=NULL;
        delete timer; timer=NULL;

        //Showing
        refreshDisplay();
    }
}

void MainWindow::openDir(QString dirName) {

    if(dirName.isEmpty())
        return;

    //Configuring
    dirName = QDir::toNativeSeparators(dirName);
    C->Menu_File_Open_Files_Begin(settings->value("closeBeforeOpen",true).toBool(), true);
    C->Menu_File_Open_Directory(QString2wstring(dirName));
    openTimerInit();
}

void MainWindow::refreshDisplay() {
    QFont font;
    if (!settings->value("monoFont", "").toString().isEmpty()) {
        font.fromString(settings->value("monoFont", "").toString());
        font.setFamilies(QStringList({ font.family(), "Cascadia Mono", "Courier New", "Malgun Gothic", "MS Gothic", "NSimSun", "Mono" }));
    } else {
        font.setFamilies(QStringList({ "Cascadia Mono", "Courier New", "Malgun Gothic", "MS Gothic", "NSimSun", "Mono" }));
    }
    font.setStyleHint(QFont::TypeWriter);

    ui->actionAdapt_columns_to_content->setVisible(false);
    ui->actionReset_field_sizes->setVisible(false);
    QWidget* viewWidget;
    ui->actionExport->setEnabled(C->Count_Get()>0);
    ui->actionClose_All->setEnabled(C->Count_Get()>0);
    std::unique_ptr<QDomDocument> xis;

    C->Menu_Option_Preferences_Option(__T("Enable_Ffmpeg"), settings->value("enableFFmpeg",false).toBool() ? __T("1") : __T("0"));

    switch(settings->value("displayCaptions",1).toInt()) {
    case 0:
        C->Menu_Option_Preferences_Option(__T("File_DisplayCaptions"),__T("Content"));
        break;
    case 1:
        C->Menu_Option_Preferences_Option(__T("File_DisplayCaptions"),__T("Command"));
        break;
    case 2:
        C->Menu_Option_Preferences_Option(__T("File_DisplayCaptions"),__T("Stream"));
        break;
    }

    if(C->Count_Get()<=0) {
#if defined(_WIN32) && defined(WINAPI_FAMILY) && WINAPI_FAMILY==WINAPI_FAMILY_APP //UWP Application
        viewWidget = new QLabel(tr("You must at least open 1 file.\nOpen a file or a directory."));
#else
        viewWidget = new QLabel(tr("You must at least open 1 file.\nOpen a file or a directory, or simply drag n drop files in the window."));
        setWindowTitle(tr("MediaInfo"));
#endif
        static_cast<QLabel*>(viewWidget)->setAlignment(Qt::AlignCenter);
    }
    else
    {
        switch(view) {
            default:
            case VIEW_TEXT:
                C->Menu_View_Text();
                C->Menu_Option_Preferences_Option(__T("Inform_Version"), settings->value("informVersion",false).toBool() ? __T("1") : __T("0"));
                C->Menu_Option_Preferences_Option(__T("Inform_Timestamp"), settings->value("informTimestamp",false).toBool() ? __T("1") : __T("0"));
                viewWidget = new QTextBrowser();
                static_cast<QTextBrowser*>(viewWidget)->setFont(font);
                if(ConfigTreeText::getIndex()==0)
                    static_cast<QTextBrowser*>(viewWidget)->setText(wstring2QString(C->Inform_Get()));
                else {
                    for (size_t FilePos=0; FilePos<C->Count_Get(); FilePos++) {
                        for (int streamKind=0;streamKind<4;streamKind++) {
                            if(!ConfigTreeText::getConfigTreeText()->getFields(streamKind).isEmpty())
                                static_cast<QTextBrowser*>(viewWidget)->append("\n"+wstring2QString(C->Get(FilePos, (stream_t)streamKind, 0, __T("StreamKind/String"), Info_Text)));
                            for (size_t streamPos=Stream_General; streamPos<C->Count_Get(FilePos, (stream_t)streamKind); streamPos++)
                            {
                                foreach(const QString& field, ConfigTreeText::getConfigTreeText()->getFields(streamKind)) {
                                    QString A=wstring2QString(C->Get(FilePos, (stream_t)streamKind, streamPos, QString2wstring(field)));
                                    QString B=wstring2QString(C->Get(FilePos, (stream_t)streamKind, streamPos, QString2wstring(field), Info_Name_Text));
                                    if (B.isEmpty())
                                        B=wstring2QString(C->Get(FilePos, (stream_t)streamKind, streamPos, QString2wstring(field), Info_Name));
                                    static_cast<QTextBrowser*>(viewWidget)->append(B+" : "+A);
                                }
                            }
                        }
                    }
                }
                break;
            case VIEW_CSV:
                C->Menu_View_CSV();
                viewWidget = new QTextBrowser();
                static_cast<QTextBrowser*>(viewWidget)->setText(wstring2QString(C->Inform_Get()));
                break;
            case VIEW_PBCORE:
                C->Menu_View_PBCore();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_PBCORE2:
                C->Menu_View_PBCore2();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_EBUCORE_1_5:
                C->Menu_View_EBUCore_1_5();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_EBUCORE_1_6:
                C->Menu_View_EBUCore_1_6();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_EBUCORE_1_8_ps:
                C->Menu_View_EBUCore_1_8_ps();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_EBUCORE_1_8_sp:
                C->Menu_View_EBUCore_1_8_sp();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_EBUCORE_1_8_ps_JSON:
                C->Menu_View_EBUCore_1_8_ps_json();
                viewWidget = new QTextBrowser();
                static_cast<QTextBrowser*>(viewWidget)->setText(wstring2QString(C->Inform_Get()));
                break;
            case VIEW_EBUCORE_1_8_sp_JSON:
                C->Menu_View_EBUCore_1_8_sp_json();
                viewWidget = new QTextBrowser();
                static_cast<QTextBrowser*>(viewWidget)->setText(wstring2QString(C->Inform_Get()));
                break;
            case VIEW_FIMS_1_1:
                C->Menu_View_FIMS_1_1();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_FIMS_1_2:
                C->Menu_View_FIMS_1_2();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_FIMS_1_3:
                C->Menu_View_FIMS_1_3();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_NISO_Z39_87:
                C->Menu_View_NISO_Z39_87();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_MPEG7_Strict:
                C->Menu_View_MPEG7_Strict();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;

            case VIEW_MPEG7_Relaxed:
                C->Menu_View_MPEG7_Relaxed();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;

            case VIEW_MPEG7_Extended:
                C->Menu_View_MPEG7_Extended();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;

            case VIEW_XML:
                C->Menu_View_XML();
                viewWidget = new QTextBrowser();
                xis.reset(new QDomDocument());
                xis->setContent(wstring2QString(C->Inform_Get()));
                static_cast<QTextBrowser*>(viewWidget)->setText(xis->toString(4));
                break;
            case VIEW_JSON:
                C->Menu_View_JSON();
                viewWidget = new QTextBrowser();
                static_cast<QTextBrowser*>(viewWidget)->setText(wstring2QString(C->Inform_Get()));
                break;
            case VIEW_EASY:
                C->Menu_View_Easy();
                viewWidget = new EasyViewWidget(C);
                break;
            case VIEW_HTML:
                #ifndef MEDIAINFO_HTML_NO
                    C->Menu_View_HTML();
                    viewWidget = new HTMLViewWidget(C, settings);
                #endif
                break;
            case VIEW_GRAPH:
                #ifndef MEDIAINFO_HTML_NO
                    C->Menu_View_Graph_Svg();
                    viewWidget = new HTMLViewWidget(C, settings);
                #endif
                break;
            case VIEW_TREE:
                C->Menu_View_Tree();
                viewWidget = showTreeView(ui->actionAdvanced_Mode->isChecked());
                break;
            case VIEW_SHEET:
                C->Menu_View_Sheet();
                viewWidget = new SheetView(C,this,&font);
                ui->actionReset_field_sizes->setVisible(true);
                if(!Sheet::getSheet()->getAdaptColumns())
                    ui->actionAdapt_columns_to_content->setVisible(true);
                connect(ui->actionReset_field_sizes, SIGNAL(triggered()), static_cast<SheetView*>(viewWidget), SLOT(resetColumnsSizes()));
                connect(ui->actionAdapt_columns_to_content, SIGNAL(triggered()), static_cast<SheetView*>(viewWidget), SLOT(adaptColumnsToContent()));
                break;
            case VIEW_CUSTOM:
                C->Menu_View_Text();
                viewWidget = showCustomView(ui->actionAdvanced_Mode->isChecked());
                break;
        }

#if !defined(_WIN32) || !defined(WINAPI_FAMILY) || WINAPI_FAMILY!=WINAPI_FAMILY_APP //UWP Application
        if(C->Count_Get()==1)
            setWindowTitle("MediaInfo - "+shortName(C,wstring2QString(C->Get(0, Stream_General, 0, __T("CompleteName")))));
        else
            setWindowTitle(QString("MediaInfo - %1 ").arg((int)C->Count_Get())+tr("files","window title"));
#endif
    }

    // Check if conformance glossary button should show
    bool showGlossaryButton = false;
    if (C->Count_Get() > 0) {
        size_t FilePos = 0;
        size_t AudioCount = C->Count_Get(FilePos, Stream_Audio, -1);
        for (size_t AudioPos = 0; AudioPos < AudioCount; ++AudioPos) {
            if (C->Get(FilePos, Stream_Audio, AudioPos, __T("ConformanceErrors")) != __T("") ||
                C->Get(FilePos, Stream_Audio, AudioPos, __T("ConformanceWarnings")) != __T("")) {
                showGlossaryButton = true;
                break;
            }
        }
    }
    if (showGlossaryButton) {
        // Show conformance glossary button below viewWidget
        QWidget* compositeViewWidget = new QWidget(this);
        QVBoxLayout* vLayout = new QVBoxLayout(compositeViewWidget);
        QPushButton* footerButton = new QPushButton(tr("Go to conformance errors and warnings glossary page"));
        connect(footerButton, SIGNAL(clicked()), this, SLOT(footerButtonClicked()));
        vLayout->addWidget(viewWidget);
        vLayout->addWidget(footerButton);
        compositeViewWidget->setLayout(vLayout);
        setCentralWidget(compositeViewWidget);
    }
    else
        // Show just the viewWidget
        setCentralWidget(viewWidget);
}

QTreeWidget* MainWindow::showTreeView(bool completeDisplay) {
    QTreeWidget* treeWidget = new QTreeWidget();
    //treeWidget->setHeaderHidden(true);
    treeWidget->setColumnCount(2);
    QStringList headers = QStringList(tr("key"));
    headers.append(tr("value"));
    treeWidget->setHeaderLabels(headers);
    unsigned fileCount = (unsigned)C->Count_Get();
    QDir dir = getCommonDir(C);

    C->Menu_Option_Preferences_Option(__T("File_ExpandSubs"), __T("1"));
    for (size_t filePos=0; filePos<fileCount; filePos++) {
        //Pour chaque fichier
        QTreeWidgetItem* treeItem = new QTreeWidgetItem(treeWidget,QStringList(shortName(dir,wstring2QString(C->Get(filePos, Stream_General, 0, __T("CompleteName"))))));
        treeWidget->addTopLevelItem(treeItem);

        for (int streamKind=(int)Stream_General; streamKind<(int)Stream_Max; streamKind++)
        {
            //Pour chaque type de flux
            QString StreamKindText=wstring2QString(C->Get(filePos, (stream_t)streamKind, 0, __T("StreamKind/String"), Info_Text));
            size_t StreamsCount=C->Count_Get(filePos, (stream_t)streamKind);
            for (size_t streamPos=Stream_General; streamPos<StreamsCount; streamPos++)
            {
                //Pour chaque stream
                QString A=StreamKindText;
                QString B=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, __T("StreamKindPos"), Info_Text));
                if (!B.isEmpty())
                {
                    A+=" #"+B;
                }
                QTreeWidgetItem* node = new QTreeWidgetItem(treeItem,QStringList(A));
                node->setExpanded(true);
                treeItem->addChild(node);

                QVector<QTreeWidgetItem*> tree;
                tree.append(node);

                if(ConfigTreeText::getIndex()==0) {
                    size_t ChampsCount=C->Count_Get(filePos, (stream_t)streamKind, streamPos);
                    for (size_t Champ_Pos=0; Champ_Pos<ChampsCount; Champ_Pos++)
                    {
                        if ((completeDisplay || C->Get(filePos, (stream_t)streamKind, streamPos, Champ_Pos, Info_Options)[InfoOption_ShowInInform]==__T('Y')) && C->Get(filePos, (stream_t)streamKind, streamPos, Champ_Pos, Info_Text)!=__T(""))
                        {
                            QString D=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, Champ_Pos, Info_Text));
                            D+=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, Champ_Pos, Info_Measure_Text));

                            QString E=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, Champ_Pos, Info_Name_Text));
                            if (E.isEmpty())
                                E=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, Champ_Pos, Info_Name)); //Texte n'existe pas

                            int level=0;
                            while (level < E.length() && E[level]==QChar(' '))
                                level++;

                            if (level)
                                E=E.mid(level);

                            if (level==tree.count() && tree.back()->childCount())
                            {
                                tree.append(tree.back()->child(tree.back()->childCount()-1));
                                if (tree.back()->columnCount()>1 && tree.back()->text(1)=="Yes")
                                    tree.back()->setText(1, "");
                            }
                            else if (level<tree.count()-1)
                            {
                                tree.resize(level+1);
                            }

                            QStringList sl = QStringList(E);
                            sl.append(D);
                            tree.back()->addChild(new QTreeWidgetItem(tree.back(),sl));
                        }
                    }
                } else {
                    foreach(const QString& field, ConfigTreeText::getConfigTreeText()->getFields(streamKind)) {
                        QString D=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, QString2wstring(field), Info_Text));
                        D+=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, QString2wstring(field), Info_Measure_Text));
                        QString E=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, QString2wstring(field), Info_Name_Text));
                        if (E.isEmpty())
                            E=wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, QString2wstring(field), Info_Name));

                        int level=0;
                        while (level < E.length() && E[level]==QChar(' '))
                            level++;

                        if (level)
                            E=E.mid(level);

                        if (level==tree.count() && tree.back()->childCount())
                            tree.append(tree.back()->child(tree.back()->childCount()-1));
                        else if (level<tree.count()-1)
                            tree.resize(level+1);

                        QStringList sl = QStringList(E);
                        sl.append(D);
                        tree.back()->addChild(new QTreeWidgetItem(tree.back(),sl));
                    }
                }
            }
        }
    }
    C->Menu_Option_Preferences_Option(__T("File_ExpandSubs"), __T("0"));
    if(C->Count_Get()<=1 && treeWidget->topLevelItem(0))
    {
        treeWidget->topLevelItem(0)->setExpanded(true);
    }
    treeWidget->resizeColumnToContents(0);
    treeWidget->resizeColumnToContents(1);

    connect(treeWidget, &QTreeWidget::expanded, [treeWidget]() { treeWidget->resizeColumnToContents(0); treeWidget->resizeColumnToContents(1); });
    connect(treeWidget, &QTreeWidget::collapsed, [treeWidget]() { treeWidget->resizeColumnToContents(0); treeWidget->resizeColumnToContents(1); });

    return treeWidget;
}

QTextBrowser* MainWindow::showCustomView(bool forcePlainText) {
    QTextBrowser* qtb = new QTextBrowser();


    unsigned fileCount = (unsigned)C->Count_Get();
    QString page = Custom::getCustom()->getPage();
    QStringList files;
    for (size_t filePos=0; filePos<fileCount; filePos++) {
        //Pour chaque fichier
        files.append(Custom::getCustom()->getFile());
        for (int streamKind=(int)Stream_General; streamKind<(int)Stream_Max; streamKind++)
        {
            //Pour chaque type de flux

            QStringList streams;
            size_t StreamsCount=C->Count_Get(filePos, (stream_t)streamKind);
            for (size_t streamPos=Stream_General; streamPos<StreamsCount; streamPos++)
            {
                //Pour chaque stream
                streams.append(Custom::getCustom()->getStream(streamKind));
                QString key;
                while(( key = streams.back().section("%",1,1))!="") {
                    qDebug() << "etude de" << key << " - " << streams.back();
                    QString info = wstring2QString(C->Get(filePos, (stream_t)streamKind, streamPos, QString2wstring(key), Info_Text));
                    info.replace("%","#POURCENTAGE#");
                    if(streams.back().indexOf("%"+key+"%")==-1)
                        break;
                    streams.back().replace("%"+key+"%",info);
                }
                streams.back().replace("#POURCENTAGE#","%");
            }
            files.back().replace("%"+wstring2QString(C->StreamName((stream_t)streamKind))+"%",streams.join(""));
        }
    }
    page.replace("%Files%",files.join(""));
    if(forcePlainText)
        qtb->setPlainText(page);
    else
        qtb->setText(page);

    return qtb;
}

void MainWindow::defaultSettings() {
    /*if(!settings->contains("showMenu"))
        settings->setValue("showMenu",true);
    if(!settings->contains("showToolBar"))
        settings->setValue("showToolBar",true);
    if(!settings->contains("closeBeforeOpen"))
        settings->setValue("closeBeforeOpen",true);
    if(!settings->contains("defaultView"))
        settings->setValue("defaultView",VIEW_EASY);
    if(!settings->contains("checkForNewVersion"))
        settings->setValue("checkForNewVersion",true);
    if(!settings->contains("rememberToolBarPosition"))
        settings->setValue("rememberToolBarPosition",true);*/
    Sheet::load(settings);
    if(Sheet::getNbSheets()==0) {
        Sheet::add("example");
        Sheet::setDefault(0);
        Sheet::getSheet()->addColumn(tr("File Name").toStdString().c_str(),300,Stream_General,"CompleteName");
        Sheet::getSheet()->addColumn(tr("Format").toStdString().c_str(),100,Stream_General,"Format");
        Sheet::getSheet()->addColumn(tr("Video Codec List").toStdString().c_str(),100,Stream_General,"Video_Codec_List");
        Sheet::getSheet()->addColumn(tr("Audio Codec List").toStdString().c_str(),100,Stream_General,"Audio_Codec_List");
        Sheet::getSheet()->addColumn(tr("Text Codec List").toStdString().c_str(),100,Stream_General,"Text_Codec_List");
        Sheet::getSheet()->addColumn(tr("Video Format").toStdString().c_str(),100,Stream_Video,"Format");
        Sheet::getSheet()->addColumn(tr("Audio Duration").toStdString().c_str(),100,Stream_Audio,"Duration");
        Sheet::getSheet()->addColumn(tr("Text Width").toStdString().c_str(),100,Stream_Text,"Width");
    }
    ConfigTreeText::load(settings);
    if(ConfigTreeText::getNbConfigTreeTexts()==0) {
        ConfigTreeText::add("Default");
        ConfigTreeText::setDefault(0);
    }
    Custom::load(settings);
    if(Custom::getNbCustoms()==0) {
        Custom::add("Default");
        Custom::setDefault(0);
    }

}

void MainWindow::applySettings() {
    if(settings->value("rememberGeometry",false).toBool())
        restoreGeometry(settings->value("geometry").toByteArray());
    if(settings->value("showToolbar",true).toBool() && settings->value("rememberToolBarPosition",true).toBool())
        restoreState(settings->value("windowState").toByteArray());
    ui->menuBar->setVisible(settings->value("showMenu",true).toBool());
    ui->toolBar->setVisible(settings->value("showToolbar",true).toBool());
    ui->toolBar->setToolButtonStyle(Qt::ToolButtonStyle(settings->value("iconStyle",Qt::ToolButtonIconOnly).toInt()));
    ui->toolBar->setIconSize(settings->value("iconSize",QSize(32,32)).toSize());

#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
    qApp->styleHints()->setColorScheme(static_cast<Qt::ColorScheme>(settings->value("colorTheme",static_cast<int>(Qt::ColorScheme::Unknown)).toInt()));
#endif

    C->Menu_Option_Preferences_Option(__T("LegacyStreamDisplay"), settings->value("legacyStreamDisplay",false).toBool() ? __T("1") : __T("0"));
    C->Menu_Option_Preferences_Option(__T("Cover_Data"), settings->value("coverData",false).toBool() ? __T("base64") : __T(""));
    C->Menu_Option_Preferences_Option(__T("File_TestContinuousFileNames"), settings->value("testContinuousFileNames",false).toBool() ? __T("1") : __T("0"));

    qApp->removeTranslator(translator);
    if (translator->load(settings->value("language", "en").toString(), ":/languages/Translations"))
        qApp->installTranslator(translator);
}

void MainWindow::dropEvent(QDropEvent *event)
{
#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) // Qt don't provide StorageFile access for d&d
    event->ignore();
#else
    QStringList files;
    for(int i=0;i<event->mimeData()->urls().size();i++) {
        files.push_back(event->mimeData()->urls().at(i).toLocalFile());
        qDebug() << "adding " << files.last().toStdString().c_str() << "to the list";
    }
    openFiles(files);
    event->acceptProposedAction();
#endif
}

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) // Qt don't provide StorageFIle access for d&d
    event->ignore();
#else
    event->acceptProposedAction();
#endif
}

void MainWindow::on_actionOpen_triggered()
{
    QStringList fileNames;
#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) //UWP Application
    ComPtr<IAsyncOperation<IVectorView<StorageFile*>*> > AsyncFiles;
    ComPtr<IVectorView<StorageFile*> > Files;
    unsigned int Count = 0;

    if (FAILED(QEventDispatcherWinRT::runOnXamlThread(std::bind(&showFilesPicker, std::ref(AsyncFiles)))) ||
        !AsyncFiles ||
        FAILED(Await(AsyncFiles)) ||
        FAILED(AsyncFiles->GetResults(&Files)) ||
        !Files ||
        FAILED(Files->get_Size(&Count)))
        return;

    for (unsigned int Pos = 0; Pos<Count; ++Pos)
    {
        ComPtr<IStorageFile> File;
        ComPtr<IStorageItem> Item;
        HString HPath;
        QString Path;

        if (FAILED(Files->GetAt(Pos, &File)) ||
            !File ||
            FAILED(File->QueryInterface(IID_PPV_ARGS(&Item))) ||
            !Item ||
            FAILED(Item->get_Path(HPath.GetAddressOf())))
            continue;

        Path = QString().fromUtf16((ushort*)WindowsGetStringRawBuffer(HPath.Get(), NULL));

        if (Path.isEmpty())
            continue;

        UINT32 Size=0;
        PCWSTR PathBuf = WindowsGetStringRawBuffer(HPath.Get(), &Size);

        Add_Item_To_FUA(HStringReference(PathBuf, Size), Item);

        fileNames += Path;
    }
#else
    fileNames = QFileDialog::getOpenFileNames(this, tr("Open File(s)"), getCommonDir(C).absolutePath());
#endif
    openFiles(fileNames);
}

void MainWindow::on_actionQuit_triggered()
{
    this->close();
}

void MainWindow::on_actionOpen_Folder_triggered()
{
    QString dirName;
#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) //UWP Application
    ComPtr<IAsyncOperation<StorageFolder*> > AsyncFolder;
    ComPtr<IStorageFolder> Folder;
    ComPtr<IStorageItem> Item;

    if (FAILED(QEventDispatcherWinRT::runOnXamlThread(std::bind(&showFolderPicker, std::ref(AsyncFolder)))) ||
        !AsyncFolder ||
        FAILED(Await(AsyncFolder)) ||
        FAILED(AsyncFolder->GetResults(&Folder)) ||
        !Folder)
        return;

    HString HPath;
    QString Path;

    if (FAILED(Folder->QueryInterface(IID_PPV_ARGS(&Item))) ||
        !Item ||
        FAILED(Item->get_Path(HPath.GetAddressOf())))
        return;

    Path = QString().fromUtf16((ushort*)WindowsGetStringRawBuffer(HPath.Get(), NULL));

    if (Path.isEmpty())
        return;

    UINT32 Size=0;
    PCWSTR PathBuf = WindowsGetStringRawBuffer(HPath.Get(), &Size);

    Add_Item_To_FUA(HStringReference(PathBuf, Size), Item);

    dirName = Path;
#else
    dirName = QFileDialog::getExistingDirectory(this,tr("Open Folder"), getCommonDir(C).absolutePath());
#endif
    openDir(dirName);
}

void MainWindow::on_actionAbout_triggered()
{
    About a(this);
    a.exec();
}

void MainWindow::on_actionKnown_formats_triggered()
{
    C->Menu_Help_Info_Formats();
    QTextBrowser* textBrowser = new QTextBrowser();
    textBrowser->setText(wstring2QString(C->Text_Get()));
    setCentralWidget(textBrowser);
}

void MainWindow::on_actionKnown_codecs_triggered()
{
    C->Menu_Help_Info_Codecs();
    QTextBrowser* textBrowser = new QTextBrowser();
    textBrowser->setText(wstring2QString(C->Text_Get()));
    setCentralWidget(textBrowser);
}

void MainWindow::on_actionKnown_parameters_triggered()
{
    C->Menu_Help_Info_Parameters();
    QTextBrowser* textBrowser = new QTextBrowser();
    textBrowser->setText(wstring2QString(C->Text_Get()));
    setCentralWidget(textBrowser);
}

void MainWindow::actionView_toggled(QAction* view)
{
    this->view = (ViewMode)view->property("view").toInt();
    refreshDisplay();
}

void MainWindow::on_actionPreferences_triggered()
{
    ViewMode oldView = (ViewMode)settings->value("defaultView",VIEW_EASY).toInt();
    Preferences p(settings,C,this);
    if(p.exec() == QDialog::Accepted) {
        p.saveSettings();
        settings->setValue("geometry", saveGeometry()); // we save positions and geometry as they might be restored in the applySettings function
        settings->setValue("windowState", saveState());
        applySettings();
        if(settings->value("defaultView",VIEW_EASY)!=oldView) {
            this->view = (ViewMode)settings->value("defaultView",VIEW_EASY).toInt();
            refreshDisplay();
        }
    }
}

void MainWindow::on_actionExport_triggered()
{
    QString name;
    if(C->Count_Get()==1)
        name = wstring2QString(C->Get(0, Stream_General, 0, __T("CompleteName")))+".txt";
    else
        name = getCommonDir(C).absoluteFilePath("MediaInfo.txt");
    Export e(name,settings->value("exportMode",Export::TEXT).toInt(),this);
    if(e.exec() == QDialog::Accepted) {
        QFile file(e.getFileName());

        if(file.fileName().isEmpty())
            return;

        if(!file.open(e.getOpenMode()))
            QMessageBox::warning(this,"Error","The file cannot be open");
        C->Menu_Debug_Complete(e.isAdvancedChecked());
        switch(e.getExportMode()) {
        case Export::TEXT:
            C->Menu_View_Text();
            if(e.getExportConfig()==0)
                file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            else {
                for (size_t FilePos=0; FilePos<C->Count_Get(); FilePos++) {
                    for (int streamKind=0;streamKind<4;streamKind++) {
                        if(!ConfigTreeText::getConfigTreeText()->getFields(streamKind).isEmpty())
                            file.write(("\n"+wstring2QString(C->Get(FilePos, (stream_t)streamKind, 0, __T("StreamKind/String"), Info_Text))+"\n").toStdString().c_str());
                        for (size_t streamPos=Stream_General; streamPos<C->Count_Get(FilePos, (stream_t)streamKind); streamPos++)
                        {
                            foreach(const QString& field, ConfigTreeText::getConfigTreeText()->getFields(streamKind)) {
                                QString A=wstring2QString(C->Get(FilePos, (stream_t)streamKind, streamPos, QString2wstring(field)));
                                file.write((field+" : "+A+"\n").toStdString().c_str());
                            }
                        }
                    }
                }
            }
            break;
        case Export::HTML:
            C->Menu_View_HTML();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::GRAPH:
            C->Menu_Option_Preferences_Inform(__T("Graph_Svg"));
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::XML:
            C->Menu_View_XML();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::JSON:
            C->Menu_View_JSON();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::PBCORE:
            C->Menu_View_PBCore();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::PBCORE2:
            C->Menu_View_PBCore2();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::EBUCORE_1_5:
            C->Menu_View_EBUCore_1_5();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::EBUCORE_1_6:
            C->Menu_View_EBUCore_1_6();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::EBUCORE_1_8_ps:
            C->Menu_View_EBUCore_1_8_ps();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::EBUCORE_1_8_sp:
            C->Menu_View_EBUCore_1_8_sp();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::EBUCORE_1_8_ps_JSON:
            C->Menu_View_EBUCore_1_8_ps_json();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::EBUCORE_1_8_sp_JSON:
            C->Menu_View_EBUCore_1_8_sp_json();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::FIMS_1_1:
            C->Menu_View_FIMS_1_1();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::FIMS_1_2:
            C->Menu_View_FIMS_1_2();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::FIMS_1_3:
            C->Menu_View_FIMS_1_3();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::NISO_Z39_87:
            C->Menu_View_NISO_Z39_87();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::MPEG7_Strict:
            C->Menu_View_MPEG7_Strict();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::MPEG7_Relaxed:
            C->Menu_View_MPEG7_Relaxed();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::MPEG7_Extended:
            C->Menu_View_MPEG7_Extended();
            file.write(wstring2QString(C->Inform_Get()).toStdString().c_str());
            break;
        case Export::CSV:
        {
            auto MediaInfo_Complete{ e.isAdvancedChecked() };
            auto ToExport{ C->MI };
            auto CSV_{ e.getCSVOptions() };

            //General
            ZtringListListF CSV;
            ZtringListList Parameters;
            Parameters.Write(MediaInfo::Option_Static(__T("Info_Parameters_CSV")));
            int Pos_Start=1;
            int Pos_End=(int)Parameters.Find(__T("Video"))-1;
            int CSV_Pos=0;

            for (int I1=0; I1<Pos_End-Pos_Start; I1++)
                if (MediaInfo_Complete || ToExport->Get(0, Stream_General, 0, I1, Info_Options)[InfoOption_ShowInInform]==__T('Y'))
                {
                    CSV(0, CSV_Pos)=Ztring(__T("General "))+Parameters(Pos_Start+I1, 0);
                    for (size_t FilePos=0; FilePos<ToExport->Count_Get(); FilePos++)
                        CSV(1+FilePos, CSV_Pos)=ToExport->Get(FilePos, Stream_General, 0, I1);
                    CSV_Pos++;
                }

            //Video
            Pos_Start=Pos_End+2;
            Pos_End=(int)Parameters.Find(__T("Audio"))-1;

            for (int I1=0; I1<Pos_End-Pos_Start; I1++)
            {
                for (int Count=0; Count<CSV_.Stream_Video; Count++)
                    if (MediaInfo_Complete || ToExport->Get(0, Stream_Video, 0, I1, Info_Options)[InfoOption_ShowInInform]==__T('Y'))
                    {
                        CSV(0, CSV_Pos)=Ztring(__T("Video "))+Ztring::ToZtring(Count)+__T(" ")+Parameters(Pos_Start+I1, 0);
                        for (size_t FilePos=0; FilePos<ToExport->Count_Get(); FilePos++)
                            CSV(1+FilePos, CSV_Pos)=ToExport->Get(FilePos, Stream_Video, 0, I1);
                        CSV_Pos++;
                    }
            }

            //Audio
            Pos_Start=Pos_End+2;
            Pos_End=(int)Parameters.Find(__T("Text"))-1;
            for (int Count=0; Count<CSV_.Stream_Audio; Count++)
            {
                for (int I1=0; I1<Pos_End-Pos_Start; I1++)
                    if (MediaInfo_Complete || ToExport->Get(0, Stream_Audio, 0, I1, Info_Options)[InfoOption_ShowInInform]==__T('Y'))
                    {
                        CSV(0, CSV_Pos)=Ztring(__T("Audio "))+Ztring::ToZtring(Count)+__T(" ")+Parameters(Pos_Start+I1, 0);
                        for (size_t FilePos=0; FilePos<ToExport->Count_Get(); FilePos++)
                            CSV(1+FilePos, CSV_Pos)=ToExport->Get(FilePos, Stream_Audio, Count, I1);
                        CSV_Pos++;
                    }
            }

            //Text
            Pos_Start=Pos_End+2;
            Pos_End=(int)Parameters.Find(__T("Chapters"))-1;
            for (int Count=0; Count<CSV_.Stream_Text; Count++)
            {
                for (int I1=0; I1<Pos_End-Pos_Start; I1++)
                    if (MediaInfo_Complete || ToExport->Get(0, Stream_Text, 0, I1, Info_Options)[InfoOption_ShowInInform]==__T('Y'))
                    {
                        CSV(0, CSV_Pos)=Ztring(__T("Text "))+Ztring::ToZtring(Count)+__T(" ")+Parameters(Pos_Start+I1, 0);
                        for (size_t FilePos=0; FilePos<ToExport->Count_Get(); FilePos++)
                            CSV(1+FilePos, CSV_Pos)=ToExport->Get(FilePos, Stream_Text, Count, I1);
                        CSV_Pos++;
                    }
            }

            //Chapters
            Pos_Start=Pos_End+2;
            Pos_End=(int)Parameters.size()-1;
            for (int Count=0; Count<CSV_.Stream_Other; Count++)
            {
                for (int I1=0; I1<Pos_End-Pos_Start; I1++)
                    if (MediaInfo_Complete || ToExport->Get(0, Stream_Other, 0, I1, Info_Options)[InfoOption_ShowInInform]==__T('Y'))
                    {
                        CSV(0, CSV_Pos)=Ztring(__T("Chapters "))+Ztring::ToZtring(Count)+__T(" ")+Parameters(Pos_Start+I1, 0);
                        for (size_t FilePos=0; FilePos<ToExport->Count_Get(); FilePos++)
                            CSV(1+FilePos, CSV_Pos)=ToExport->Get(FilePos, Stream_Other, Count, I1);
                        CSV_Pos++;
                    }
            }

            //Separators
            Ztring Separator_Col=CSV_.Separator_Col.toStdString().c_str();
            if (Separator_Col==__T("(Tab)"))
                Separator_Col=__T("\t");
            Ztring Separator_Line=CSV_.Separator_Line.toStdString().c_str();
            if (Separator_Line==__T("(Default)"))
            #ifdef WIN32
                Separator_Line=__T("\r\n");
            #else
                Separator_Line=__T("\n");
            #endif //WIN32
            Separator_Line.FindAndReplace(__T("\\r"), __T("\r"));
            Separator_Line.FindAndReplace(__T("\\n"), __T("\n"));
            Ztring Quote=CSV_.Quote.toStdString().c_str();
            CSV.Separator_Set(0, Separator_Line);
            CSV.Separator_Set(1, Separator_Col);
            CSV.Quote_Set(Quote);

            if (e.getOpenMode() == QIODevice::Append)
                CSV.Delete(0);
            file.write(CSV.Read().To_UTF8().c_str());
            file.write(Separator_Line.To_UTF8().c_str());

            break;
        }
        default:
            QMessageBox::warning(this,"Error","Please signal this error to the MediaInfo project team : Unkown export mode");
            break;
        }

        settings->setValue("exportMode",e.getExportMode());
    }
}

void MainWindow::on_actionAdvanced_Mode_toggled(bool checked)
{
    C->Menu_Debug_Complete(checked);
    refreshDisplay();
}

void MainWindow::on_actionFull_Parse_toggled(bool checked)
{
    C->MI->Option_Static(__T("ParseSpeed"), checked?__T("1"):__T("0.5"));
    refreshDisplay();
}

void MainWindow::on_actionTrace_toggled(bool checked)
{
    C->MI->Option_Static(__T("Trace_Level"), checked?__T("1"):__T("0"));
    ui->menuView->actions().at(VIEW_TEXT)->trigger();
}

void MainWindow::on_actionClose_All_triggered()
{
    C->Menu_File_Open_Files_Begin(true);
    refreshDisplay();
}

void MainWindow::buttonViewClicked()
{
#if defined(_WIN32) && defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP) // Menu bug
    Sleep(200);
    menuView->show();
    menuView->hide();

    QPoint p;
    p.setX(ui->toolBar->rect().right() + 5);
    p.setY(buttonView->rect().center().y());
    menuView->exec(p);
#else
    menuView->exec(buttonView->mapToGlobal(QPoint(0, 0)));
#endif
}

void MainWindow::footerButtonClicked()
{
    const Ztring Inform_Save = C->Menu_Option_Preferences_Option(__T("Inform_Get"), __T(""));
    C->Menu_Option_Preferences_Inform(__T("Conformance_JSON"));
    const QString URL = wstring2QString(C->Inform_Get());
    C->Menu_Option_Preferences_Inform(Inform_Save);
    QDesktopServices::openUrl(QUrl(URL));
}
