/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2024 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK 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 Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

// -- Application Imp stuff
#include "ImpMainWindow.h"

// -- Core stuff
#include <Application.h>
#include <ExtensionManager.h>
#include <SettingsDialog.h>
#include <Component.h>
#include <Action.h>
#include <Viewer.h>
#include <Core.h> // for getActionDirectories()
#include <Property.h>
#include <PropertyObject.h>
#include <Log.h>

using namespace camitk;

// -- QT stuff
#include <QAction>
#include <QFileDialog>
#include <QPixmap>
#include <QWhatsThis>
#include <QMenu>
#include <QToolBar>
#include <QMenuBar>
#include <QStatusBar>
#include <QDockWidget>
#include <QStackedWidget>
#include <QTranslator>

// ------------- constructor -----------------
ImpMainWindow::ImpMainWindow() : MainWindow("imp") {
    // set the specific actions state machine icon
    setWindowIcon(QPixmap(":/applicationIcon"));

    fileOpenDataDirectoryMenu = nullptr;

    // init all other GUI
    initActions();
    initMenuBar();
    initToolBar();

    // initialize architecture
    updateActionStates();

    // now add the different viewers
    Viewer* medicalImageViewer = Application::getViewer("Medical Image Viewer");

    if (medicalImageViewer != nullptr) {
        setCentralViewer(medicalImageViewer);
    }
    else {
        CAMITK_ERROR(tr("Cannot find \"Medical Image Viewer\". This viewer is mandatory for running camitk-imp."))
    }

    Viewer* explorer = Application::getViewer("Explorer");

    if (explorer != nullptr) {
        addDockViewer(Qt::LeftDockWidgetArea, explorer);
    }
    else {
        CAMITK_ERROR(tr("Cannot find \"Explorer\" viewer. This viewer is mandatory for running camitk-imp."))
    }

    Viewer* frameExplorer = Application::getViewer("Frame Explorer");

    if (frameExplorer != nullptr) {
        addDockViewer(Qt::LeftDockWidgetArea, frameExplorer);
    }
    else {
        CAMITK_ERROR(tr("Cannot find \"Frame Explorer\" viewer. This viewer is mandatory for running camitk-imp."))
    }

    Viewer* propertyExplorer = Application::getViewer("Property Explorer");

    if (frameExplorer != nullptr) {
        addDockViewer(Qt::LeftDockWidgetArea, propertyExplorer);
    }
    else {
        CAMITK_ERROR(tr("Cannot find \"Property Explorer\" viewer. This viewer is mandatory for running camitk-imp."))
    }

    Viewer* actionViewer = Application::getViewer("Action Viewer");

    if (actionViewer != nullptr) {
        addDockViewer(Qt::RightDockWidgetArea, actionViewer);
        showDockViewer(actionViewer, false);
    }
    else {
        CAMITK_ERROR(tr("Cannot find \"Action Viewer\". This viewer is mandatory for running camitk-imp."))
    }

    // Merge Explorer and FrameExplorer viewers in one layout
    QDockWidget* dockWidgetExplorer = dockWidgetMap.value(explorer, nullptr);
    QDockWidget* dockWidgetFrameExplorer = dockWidgetMap.value(frameExplorer, nullptr);

    if (dockWidgetExplorer != nullptr && dockWidgetFrameExplorer != nullptr) {
        tabifyDockWidget(dockWidgetExplorer, dockWidgetFrameExplorer);
        dockWidgetExplorer->raise();
    }

    showStatusBar(true);
}

// ------------- destructor -----------------
ImpMainWindow::~ImpMainWindow() {
}

// ------------- aboutToShow -----------------
void ImpMainWindow::aboutToShow() {
    MainWindow::aboutToShow(); // calls init settings

    // now that initSettings was called, populate the recent document menu
    updateRecentDocumentsMenu();

    // check autoload for files and load if needed
    if (Application::getPropertyObject()->getPropertyValue("Auto Load Last Opened Component").toBool() && Application::getRecentDocuments().size() > 0) {
        Application::open(Application::getRecentDocuments().last().absoluteFilePath());
    }
}

// ------------- refresh -----------------
void ImpMainWindow::refresh() {
    MainWindow::refresh();

    // update all the action states
    updateActionStates();

    // update menu
    updateRecentDocumentsMenu();
}

// ------------- addDockViewer -----------------
void ImpMainWindow::addDockViewer(Qt::DockWidgetArea dockingArea, Viewer* theViewer) {
    MainWindow::addDockViewer(dockingArea, theViewer);
    // update the menu
    updateViewMenu();
}

// ------------- setCentralViewer -----------------
void ImpMainWindow::setCentralViewer(Viewer* theViewer) {
    MainWindow::setCentralViewer(theViewer);
    // update the menu
    updateViewMenu();
}

// ------------- initActions -----------------
void ImpMainWindow::initActions() {
    //-- Check for applications level action (file, edit and help)
    QStringList applicationLevelNames = {"File Application Level Actions", "Edit Application Level Actions", "Help Application Level Actions"};
    QMap<QString, ActionExtension*> applicationLevelActionExtensions;
    QListIterator<ActionExtension*> it(ExtensionManager::getActionExtensionsList());

    while (it.hasNext() && applicationLevelActionExtensions.size() < 3) {
        ActionExtension* current = it.next();

        int i = 0;
        while (i < applicationLevelNames.size() && current->getName() != applicationLevelNames.at(i)) {
            i++;
        }
        if (i < applicationLevelNames.size()) {
            applicationLevelActionExtensions.insert(applicationLevelNames.at(i), current);
        }
    }

    if (applicationLevelActionExtensions.size() < 3) {
        for (QString name : applicationLevelNames) {
            if (!applicationLevelActionExtensions.contains(name)) {
                CAMITK_ERROR(tr("Application error: the \"%1\" action extension is required by camitk-imp but could not be found\nIn any of the following extension directories:\n - %2\nPlease check your CamiTK configuration and/or installation using \"camitk-config --config\"").arg(name, Core::getActionDirectories().join("\n - ")))
                exit(EXIT_FAILURE);
            }
        }
    }

    //--- actions of the File menu
    // get the CamiTK actions
    fileOpen = Application::getAction("Open")->getQAction();
    workspaceOpen = Application::getAction("Open Workspace File")->getQAction();
    fileClose = Application::getAction("Close")->getQAction();
    fileCloseAll = Application::getAction("Close All")->getQAction();
    fileSave = Application::getAction("Save")->getQAction();
    fileSaveAs = Application::getAction("Save As")->getQAction();
    fileSaveAll = Application::getAction("Save All")->getQAction();
    workspaceSave = Application::getAction("Save Workspace")->getQAction();
    fileQuit = Application::getAction("Quit")->getQAction();

    recentDocumentSeparator = new QAction(tr("Recent Documents"), this);
    recentDocumentSeparator->setSeparator(true);
    recentDocumentSeparator->setVisible(false);

    for (int i = 0; i < Application::getMaxRecentDocuments(); i++) {
        recentDocumentActions.append(new QAction(this));
        recentDocumentActions.last()->setVisible(false);
        connect(recentDocumentActions.last(), SIGNAL(triggered()), this, SLOT(openRecentDocuments()));
    }

    //--- actions of the Edit menu
    editClearSelection = Application::getAction("Clear Selection")->getQAction();

    // settings
    editApplicationSettings = new QAction(tr("&Preferences..."), this);
    editApplicationSettings->setShortcut(tr("Ctrl+P"));
    editApplicationSettings->setStatusTip(tr("Edit the preferences"));
    editApplicationSettings->setWhatsThis(tr("Preferences\n\nEdit the settings and preferences of imp"));
    connect(editApplicationSettings, SIGNAL(triggered()), this, SLOT(editSettings()));

    // save history as SCXML
    saveHistory = new QAction(tr("&Save History"), this);
    saveHistory->setStatusTip(tr("Save the history of actions processed as an SCXML file."));
    saveHistory->setWhatsThis(tr("Save the history of actions processed as an SCXML file."));
    connect(saveHistory, SIGNAL(triggered()), this, SLOT(saveHistoryAsSCXML()));

    //--- actions of the View menu
    viewMenuBar = new QAction(tr("Menu bar"), this);
    viewMenuBar->setCheckable(true);
    viewMenuBar->setChecked(true);
    viewMenuBar->setStatusTip(tr("Hide/show the menu bar (Ctrl-M to show again)."));
    viewMenuBar->setWhatsThis(tr("Hide/show the menu bar (Ctrl-M to show again)."));
    viewMenuBar->setShortcut(tr("Ctrl+M"));
    // global shortcut, NOTE: the action should also be added as an ImpMainWindow action, otherwise the shortcut will not work when
    // the menu bar is hidden! (see initMenuBar() method)
    viewMenuBar->setShortcutContext(Qt::ApplicationShortcut);
    connect(viewMenuBar, SIGNAL(triggered()), this, SLOT(toggleMenuBar()));
    // NOTE: viewMenuBar can be used to hide the menu bar, if the menu bar is not visible,
    // since Qt4, it does not receive any event (and thus there is no way to set the menu
    // visible again! Which is quite annoying).
    // To prevent this, the viewMenuBar action has to be added to the QMainWindow as well
    // This should be done everytime the shortcut context is set
    // to Qt::ApplicationShortcut using setShortcutContext(Qt::ApplicationShortcut);
    this->addAction(viewMenuBar);

    viewStatusBar = new QAction(tr("Status bar"), this);
    viewStatusBar->setCheckable(true);
    viewStatusBar->setChecked(true);
    viewStatusBar->setStatusTip(tr("Hide/show the status bar."));
    viewStatusBar->setWhatsThis(tr("Hide/show the status bar."));
    connect(viewStatusBar, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool)));

    viewResetWindows = new QAction(tr("Reset Windows"), this);
    viewResetWindows->setStatusTip(tr("Reset all windows in the initial state"));
    connect(viewResetWindows, SIGNAL(triggered()), this, SLOT(resetWindows()));

    //--- actions of the Help menu
    helpAboutApp = Application::getAction("About...")->getQAction();
    helpShowConsole = Application::getAction("Toggle Log Console")->getQAction();
    changeLanguage = Application::getAction("Change Language")->getQAction();

}

// ------------- initMenuBar -----------------
void ImpMainWindow::initMenuBar() {
    // -- file
    fileMenu = new QMenu(tr("&File"));
    fileMenu->addAction(fileOpen);
    fileMenu->addAction(workspaceOpen);

    updateOpenDirectoryMenu();

    fileMenu->addAction(fileClose);
    fileMenu->addAction(fileCloseAll);
    fileMenu->addSeparator();
    fileMenu->addAction(fileSave);
    fileMenu->addAction(fileSaveAs);
    fileMenu->addAction(fileSaveAll);
    fileMenu->addAction(workspaceSave);
    fileMenu->addSeparator();
    fileMenu->addAction(saveHistory);
    fileMenu->addAction(recentDocumentSeparator);

    foreach (QAction* recentAction, recentDocumentActions) {
        fileMenu->addAction(recentAction);
    }

    fileMenu->addSeparator();
    fileMenu->addSeparator();
    fileMenu->addAction(fileQuit);


    // -- edit
    QMenu* editMenu = new QMenu(tr("&Edit"));
    editMenu->addAction(editClearSelection);
    editMenu->addSeparator();
    editMenu->addAction(editApplicationSettings);


    // -- View menu
    viewMenu = new QMenu(tr("&View"));

    // -- help
    QMenu* helpMenu = new QMenu(tr("&Help"));
    QAction* whatsThisAction = QWhatsThis::createAction(this);
    whatsThisAction->setStatusTip(tr("What's This and Viewer Keyboard Shortcuts."));
    whatsThisAction->setWhatsThis(tr("What's This and Viewer Keyboard Shortcuts."));
    helpMenu->addAction(whatsThisAction);
    this->addAction(whatsThisAction);
    helpMenu->addSeparator();
    helpMenu->addAction(helpShowConsole);
    helpMenu->addAction(Application::getAction("Logger Parameters")->getQAction());
    helpMenu->addSeparator();
    helpMenu->addAction(changeLanguage);
    helpMenu->addSeparator();
    helpMenu->addAction(helpAboutApp);

    // -- action
    actionMenu = new QMenu(tr("&Actions"));

    // -- add everything in the menu bar
    menuBar()->addMenu(fileMenu);
    menuBar()->addMenu(editMenu);
    menuBar()->addMenu(viewMenu);
    menuBar()->addMenu(actionMenu);
    menuBar()->addSeparator();
    menuBar()->addMenu(helpMenu);

}

//--------------------------initToolBar-------------------------------
void ImpMainWindow::initToolBar() {
    mainToolbar = addToolBar("Main Toolbar");
    // ensure object name is set for saving the state
    mainToolbar->setObjectName("ImpMainWindow Main Toolbar");
    mainToolbar->addAction(fileOpen);
    mainToolbar->addAction(fileSave);
    mainToolbar->addAction(QWhatsThis::createAction(this));
}

// ------------------------ updateActionStates ----------------------------
void ImpMainWindow::updateActionStates() {
    unsigned int nrOfSelectedItems = Application::getSelectedComponents().size();
    bool selectedIsTopLevel = (nrOfSelectedItems > 0 && Application::getSelectedComponents().last()->isTopLevel());
    unsigned int nrOfComponents = Application::getTopLevelComponents().size();

    //-- update file menu
    fileCloseAll->setEnabled(nrOfComponents > 0);
    fileSaveAll->setEnabled(nrOfComponents > 0);
    fileSave->setEnabled(selectedIsTopLevel && Application::getSelectedComponents().first()->getTopLevelComponent()->getModified());    // save available only if needed
    fileSaveAs->setEnabled(nrOfSelectedItems > 0);     // no need to be top level to be saved as in a compatible format
    fileClose->setEnabled(selectedIsTopLevel);

    //-- update edit menu
    editClearSelection->setEnabled(nrOfSelectedItems > 0);

    //-- update the action menu
    actionMenu->clear();
    actionMenu->setEnabled(false);

    if (nrOfSelectedItems > 0) {
        // use the selection to populate the menu
        Component* comp = Application::getSelectedComponents().last();

        if (comp) {
            QMenu* compActionsMenu = comp->getActionMenu();

            if (compActionsMenu) {
                actionMenu->addActions(compActionsMenu->actions());
                actionMenu->setEnabled(true);
            }
        }
    }
    else {
        // add all generic actions
        ActionList allActions = Application::getActions(NULL);

        foreach (Action* action, allActions) {
            actionMenu->addAction(action->getQAction());
            actionMenu->setEnabled(true);
        }
    }

    // update the application window title
    if (nrOfSelectedItems > 0) {
        setWindowSubtitle(Application::getSelectedComponents().last()->getFileName() + ((Application::getSelectedComponents().last()->getTopLevelComponent()->getModified()) ? "*" : ""));
    }
    else {
        setWindowSubtitle("");
    }
}

// ------------- showToolbar -----------------
void ImpMainWindow::showToolbar(bool b) {
    mainToolbar->setVisible(b);
}

// ------------- toggleMenuBar -----------------
void ImpMainWindow::toggleMenuBar() {
    bool menuBarVisible = menuBar()->isVisible();

    if (menuBarVisible) {
        // warn the user first
        CAMITK_WARNING(tr("Hide menu: the menu is going to be hidden. There is only one way to make it reappear: you need to press CTRL+M again."))
    }

    menuBar()->setVisible(!menuBarVisible);
    viewMenuBar->blockSignals(true);
    viewMenuBar->setChecked(!menuBarVisible);
    viewMenuBar->blockSignals(false);
}

// ------------- showStatusBar -----------------
void ImpMainWindow::showStatusBar(bool b) {
    MainWindow::showStatusBar(b);
}

// ------------------------ resetWindows ----------------------------
void ImpMainWindow::resetWindows() {
    for (QMap<Viewer*, QDockWidget*>::iterator it = dockWidgetMap.begin(); it != dockWidgetMap.end(); ++it) {
        if (it.key()->getName() == "Explorer") {
            removeDockWidget(it.value());
            addDockWidget(Qt::LeftDockWidgetArea, it.value());
            it.value()->show();
        }
        else {
            if (it.key()->getName() == "Frame Explorer") {
                removeDockWidget(it.value());
                addDockWidget(Qt::LeftDockWidgetArea, it.value());
                it.value()->show();
            }
            else {
                if (it.key()->getName() == "Property Explorer") {
                    removeDockWidget(it.value());
                    addDockWidget(Qt::LeftDockWidgetArea, it.value());
                    it.value()->show();
                }
                else {
                    if (it.key()->getName() == "Action Viewer") {
                        removeDockWidget(it.value());
                        addDockWidget(Qt::RightDockWidgetArea, it.value());
                        it.value()->show();
                    }
                }
            }
        }
    }

    // Merge Explorer and FrameExplorer viewers in one layout
    QDockWidget* dockWidgetExplorer = dockWidgetMap.value(Application::getViewer("Explorer"), NULL);
    QDockWidget* dockWidgetFrameExplorer = dockWidgetMap.value(Application::getViewer("Frame Explorer"), NULL);

    if (dockWidgetExplorer && dockWidgetFrameExplorer) {
        tabifyDockWidget(dockWidgetExplorer, dockWidgetFrameExplorer);
        dockWidgetExplorer->raise();
    }

    showStatusBar(true);
    menuBar()->setVisible(true);
    showToolbar(true);

    // reset geometry to default
    resize(1024, 768);
    move(0, 0);
}

// ------------- openDataDirectory -----------------
void ImpMainWindow::openDataDirectory(QString plugin) {
    QString pluginName = plugin;

    statusBar()->showMessage(tr(QString("Opening " + pluginName + " directory...").toStdString().c_str()));

    // Open more than one file
    QString dir = QFileDialog::getExistingDirectory(this, tr(QString("Choose a " + pluginName + " directory ").toStdString().c_str()), Application::getLastUsedDirectory().absolutePath());

    if (!dir.isEmpty()) {
        // set waiting cursor
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));

        // instantiate a Component to represent the data contained in the directory
        Component* comp = Application::openDirectory(dir, pluginName);

        if (!comp) {
            statusBar()->showMessage(tr("Error loading directory:") + dir);
        }
        else {
            // TODO add to recent document and manage directories as recent documents
            statusBar()->showMessage(tr(QString("Directory " + dir + " successfully loaded").toStdString().c_str()));

            // refresh all
            refresh();
        }

        // restore the normal cursor
        QApplication::restoreOverrideCursor();
        getProgressBar()->setValue(0.0);
    }
}

// ------------- updateViewMenu -----------------
void ImpMainWindow::updateViewMenu() {
    // From Qt documentation:
    // "Removes all the menu's actions. Actions owned by the menu and not shown in any other widget are deleted"
    // this will therefore automatically delete the toggle central viewer's action
    viewMenu->clear();

    // insert viewers menu
    foreach (Viewer* v, viewers) {
        QMenu* viewerMenu = v->getMenu();

        if (viewerMenu) {
            viewMenu->addMenu(viewerMenu);
        }
    }

    viewMenu->addSeparator();

    QMenu* toggleCentralWidgetMenu = viewMenu->addMenu(tr("Toggle Central Viewer"));

    // add other viewers that are not initially part of imp, but that are
    // added by supplementary viewer extensions
    foreach (Viewer* viewer, Application::getViewers()) {
        // only control the embedded viewer that are not already embedded somewhere or is already in the centralViewer stack
        if (viewer->getType() == Viewer::EMBEDDED && (viewer->getEmbedder() == centralWidget()->layout() || viewer->getEmbedder() == nullptr)) {
            // viewerAction is own by viewMenu, viewMenu->clear() will delete it
            QAction* viewerAction = toggleCentralWidgetMenu->addAction(viewer->getName());
            viewerAction->setCheckable(true);
            viewerAction->setChecked(viewer == centralViewer);
            viewerAction->setIcon(viewer->getIcon());
            QString tipString = "Hide/show the " + viewer->getName() + " in the central viewer";
            viewerAction->setStatusTip(tr(tipString.toStdString().c_str()));
            viewerAction->setWhatsThis(tr(tipString.toStdString().c_str()));
            // add the toggle action slot using C++11 lambda so that everything is contained inside viewMenu
            connect(viewerAction, &QAction::toggled, this, [ this, viewer ](bool) {
                setCentralViewer(viewer);
            });
        }
    }

    // insert viewers on/off actions
    QMenu* toggleDockedMenu = viewMenu->addMenu(tr("Toggle Docked Viewers"));

    toggleDockedMenu->addAction(viewResetWindows);

    foreach (Viewer* viewer, Application::getViewers()) {
        // add the
        if (viewer->getType() == Viewer::DOCKED) {
            QDockWidget* dockWidget = dockWidgetMap.value(viewer);

            if (dockWidget != nullptr) {
                dockWidget->toggleViewAction()->setIcon(viewer->getIcon());
                toggleDockedMenu->addAction(dockWidget->toggleViewAction());
            }
            else {
                // add a specific action to add this viewer in the right dock area
                // viewerAction is own by viewMenu, viewMenu->clear() will delete it
                QAction* viewerDockAction = toggleDockedMenu->addAction(viewer->getName());
                viewerDockAction->setCheckable(true);
                viewerDockAction->setChecked(false);
                viewerDockAction->setIcon(viewer->getIcon());
                QString tipString = "Hide/show the " + viewer->getName() + " inside a dock";
                viewerDockAction->setStatusTip(tr(tipString.toStdString().c_str()));
                viewerDockAction->setWhatsThis(tr(tipString.toStdString().c_str()));
                // add the toggle action slot using C++11 lambda so that everything is contained inside viewMenu
                connect(viewerDockAction, &QAction::toggled, this, [ this, viewer ](bool) {
                    addDockViewer(Qt::RightDockWidgetArea, viewer);
                });
            }
        }
    }

    // insert generic on/off actions
    QMenu* otherToggleMenu = viewMenu->addMenu(tr("Other Toggle"));
    otherToggleMenu->addAction(viewMenuBar);
    otherToggleMenu->addAction(viewStatusBar);
    otherToggleMenu->addAction(mainToolbar->toggleViewAction());
}

// ------------------------------ slotEditSettings -------------------------------
void ImpMainWindow::editSettings() {
    statusBar()->showMessage(tr("Edit application preferences..."));
    // ask the ImpMainWindowDoc to show the settings

    // create the dialog
    SettingsDialog settingsDialog;

    // show the properties of the CamiTK application
    settingsDialog.editSettings(dynamic_cast<Application*>(qApp)->getPropertyObject());

    // edit all viewers that have properties
    foreach (Viewer* v, viewers) {
        QObject* viewerProp = v->getPropertyObject();

        if (viewerProp) {
            settingsDialog.editSettings(viewerProp);
        }
    }

    // execute the dialog
    if (settingsDialog.exec() == QDialog::Accepted) {
        // update recent docs
        updateRecentDocumentsMenu();
    }

    // check if there are anything to change in the data directory menu (for data directory manager)
    ImpMainWindow::updateOpenDirectoryMenu();
}

// ------------- setApplicationConsole -----------------
void ImpMainWindow::redirectToConsole(bool visible) {
    MainWindow::redirectToConsole(visible);
    helpShowConsole->setEnabled(visible);
}


// ------------------------------ slotRecentDocuments -------------------------------
void ImpMainWindow::openRecentDocuments() {
    QAction* action = qobject_cast<QAction*> (sender());

    if (action) {
        // check if this recent document still exists!
        if (QFileInfo::exists(action->data().toString())) {
            Action* openFileAction = Application::getAction("Open File");
            openFileAction->setProperty("File Name", action->data().toString()); // avoid opening a dialog, as the file path is already know
            openFileAction->applyAndRegister();
        }
        else {
            CAMITK_WARNING(tr("Open Recent Documents: document \"%1\" does not exist anymore.").arg(action->data().toString()))
        }
    }

}

// ------------------------------ updateRecentDocumentsMenu -------------------------------
void ImpMainWindow::updateRecentDocumentsMenu() {
    const QList<QFileInfo>& recentDocuments = Application::getRecentDocuments();
    recentDocumentSeparator->setVisible(recentDocuments.size() > 0);

    int id = 0;

    for (int i = recentDocuments.size() - 1; i >= 0 && id < Application::getMaxRecentDocuments(); i--, id++) {
        QString text = tr("&%1 %2").arg(id + 1).arg(recentDocuments[i].fileName());
        recentDocumentActions[id]->setText(text);
        recentDocumentActions[id]->setData(recentDocuments[i].absoluteFilePath());
        recentDocumentActions[id]->setStatusTip(recentDocuments[i].absoluteFilePath());
        recentDocumentActions[id]->setWhatsThis(recentDocuments[i].absoluteFilePath());
        recentDocumentActions[id]->setVisible(true);
    }

    for (; id < recentDocumentActions.size(); id++) {
        recentDocumentActions[id]->setVisible(false);
    }
}

// ------------------------------ saveHistoryAsSCXML -------------------------------
void ImpMainWindow::saveHistoryAsSCXML() {
    Application::saveHistoryAsSXML();
}

// ------------------------- updateOpenDirectoryMenu ---------------------------
void ImpMainWindow::updateOpenDirectoryMenu() {
    QStringList dirExt = ExtensionManager::getDataDirectoryExtNames();

    if (dirExt.size() > 1) {
        if (fileOpenDataDirectoryMenu == nullptr) {
            fileOpenDataDirectoryMenu = new QMenu("Open Data Directory");
            fileMenu->addMenu(fileOpenDataDirectoryMenu);
        }
        else {
            disconnect(fileOpenDataDirectoryMenu, 0, 0, 0);
            fileOpenDataDirectoryMenu->clear();
        }

        fileOpenDataDirectoryMenu->setIcon(QPixmap(":/fileOpen"));

        for (auto& dirExtName : qAsConst(dirExt)) {
            QAction* openDirectory = new QAction(dirExtName, this);
            openDirectory->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
            openDirectory->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
            connect(openDirectory, &QAction::triggered, this, [ this, dirExtName ]() {
                this->openDataDirectory(dirExtName);
            });

            fileOpenDataDirectoryMenu->addAction(openDirectory);

        }
    }
    else if (dirExt.size() == 1) {
        // if it exists, remove the default directory extension menu (that has only one submenu)
        // from the file "open" action list
        bool updateAction = false;
        QList<QAction*> menuActions = fileMenu->actions();
        int indexAction = 0;

        while (indexAction < menuActions.size() && !updateAction) {
            if (menuActions.at(indexAction)->text().contains(" Directory")) {
                emit menuActions.at(indexAction)->destroyed();
                updateAction = true;
            }

            indexAction++;
        }

        // create the single open directory action
        QString dirExtName = dirExt.at(0);
        QAction* openDirectoryAction = new QAction("Open " + dirExtName + " Directory", this);

        if (!updateAction) {
            // there was no specific menu, just add the single "open directory" action in the file menu
            fileMenu->addAction(openDirectoryAction);
        }

        openDirectoryAction->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
        openDirectoryAction->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));

        connect(openDirectoryAction, &QAction::triggered, this, [ this, dirExtName ]() {
            this->openDataDirectory(dirExtName);
        });

        openDirectoryAction->setIcon(QPixmap(":/fileOpen"));
    }
    else {
        fileOpenDataDirectoryMenu = new QMenu("No plugins loaded to Open Data Directory");
        fileOpenDataDirectoryMenu->setIcon(QPixmap(":/fileOpen"));
        fileOpenDataDirectoryMenu->setEnabled(false);
        fileMenu->addMenu(fileOpenDataDirectoryMenu);
    }
}
