/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include "uPlot.h"

#include <QAction>
#include <QComboBox>
#include <QCursor>
//#include <QDebug>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QMessageBox>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QSettings>
#include <QSplitter>
#include <QStatusBar>
#include <QStringList>
#include <QTabWidget>
#include <QTimer>
#include <QToolBar>
#include <QToolButton>
#include <QUndoStack>
#include <QUndoView>
#include <QVBoxLayout>
#include <QWidgetAction>

#include "MgQPlotScene.h"
#include "MgQRootItem.h"
#include "MgQSceneItem.h"

#include "CursorCoordinate.h"
#include "ExportDialog.h"
#include "MvQAbout.h"
#include "MvQApplication.h"
#include "MvQDataWidget.h"
#include "MvQKeyProfileTree.h"
#include "MvQLayerModel.h"
#include "MvQLayerWidget.h"
#include "MvQMagnifier.h"
#include "MvQPlotView.h"
#include "MvQProgressBarPanel.h"
#include "MvQProgressManager.h"
#include "MvQStepModel.h"
#include "MvQStepWidget.h"
#include "MvQFeatureWidget.h"
#include "MvQTreeView.h"
#include "MvQZoomStackWidget.h"
#include "MvQMethods.h"

#include "LayerControlWidget.h"
#include "LocationLabelWidget.h"
#include "MvKeyProfile.h"

#include "MagPlusService.h"
#include "ObjectList.h"
#include "PlotModView.h"
#include "Root.h"
#include "ShareTargets.h"

void MvQSceneComboBox::hidePopup()
{
    QComboBox::hidePopup();
    emit cursorLeft();
}


uPlot::uPlot(QWidget* parent) :
    uPlotBase(parent),
    //				progressItem_(0),
    weatherRoom_(false)
{
    setAttribute(Qt::WA_DeleteOnClose);

    setWindowTitle("Metview - uPlot");

    // Initial size
    setInitialSize(1100, 700);

#ifdef METVIEW_WEATHER_ROOM
    // Check if weather room is enabled
    if (char* wr = getenv("MV_WEATHER_ROOM")) {
        if (strcmp(wr, "1") == 0)
            weatherRoom_ = true;
    }
#endif

    //---------------------
    // The view
    //---------------------

    connect(plotView_, SIGNAL(zoomActionStarted(MgQSceneItem*)),
            this, SLOT(slotSetActiveScene(MgQSceneItem*)));

    //-------------------
    // Frames widget
    //-------------------

    stepWidget_ = new MvQStepWidget;

    // connect(stepWidget_->view(),SIGNAL(activated(QModelIndex)),
    connect(stepWidget_->view(), SIGNAL(selectionChanged(QModelIndex)),
            this, SLOT(slotStepTo(QModelIndex)));

    // TODO: figure out if the connect can have any usgae
#if 0
    connect(stepWidget_, SIGNAL(keyProfileChanged(MvKeyProfile*)),
            plotView_, SLOT(slotFrameProfileChanged(MvKeyProfile*)));
#endif

    //-------------------
    // Layer content swidget
    //-------------------

    layerWidget_ = new MvQLayerWidget(plotScene_, plotView_);

    connect(layerWidget_, SIGNAL(layerTransparencyChanged(QString, int)),
            this, SLOT(slotLayerTransparencyChanged(QString, int)));

    connect(layerWidget_, SIGNAL(layerVisibilityChanged(QString, bool)),
            this, SLOT(slotLayerVisibilityChanged(QString, bool)));

    connect(layerWidget_, SIGNAL(layerStackingOrderChanged(QList<QPair<QString, int> >)),
            this, SLOT(slotLayerStackingOrderChanged(QList<QPair<QString, int> >)));

    connect(layerWidget_, SIGNAL(sendDropRequest(MvRequest*)),
            QApplication::instance(), SLOT(processDropRequest(MvRequest*)));

    //-------------------
    // Layers data widget
    //-------------------

    dataWidget_ = new MvQDataWidget(plotScene_, plotView_);

    //-------------------------------
    // Layer control widget
    // Contains both the layer contents and data
    //
    //-------------------------------

    layerControlWidget_ = new LayerControlWidget(layerWidget_, dataWidget_, this);

    //-------------------------------
    // Meteorological Symbol widget
    //-------------------------------

    symbolWidget_ = new MvQFeatureWidget(plotView_);

    //-----------------------------------
    // Control widget
    //-----------------------------------

    controlWidget_ = new QWidget(this);
    auto* controlLayout = new QVBoxLayout;
    controlLayout->setContentsMargins(0, 0, 0, 0);
    controlWidget_->setLayout(controlLayout);

    // Scene selection
    sceneWidget_ = new QWidget(this);
    auto* label = new QLabel(tr("Active scene:"), this);
    sceneCb_ = new MvQSceneComboBox(this);

    auto* hb = new QHBoxLayout;
    sceneWidget_->setLayout(hb);
    hb->addWidget(label);
    hb->addWidget(sceneCb_);
    hb->addStretch(1.);

    sceneWidget_->hide();
    controlLayout->addWidget(sceneWidget_);

    connect(sceneCb_, SIGNAL(activated(int)),
            this, SLOT(slotSetActiveSceneByIndex(int)));

    connect(sceneCb_, SIGNAL(highlighted(int)),
            this, SLOT(slotHighlightScene(int)));

    connect(sceneCb_, SIGNAL(cursorLeft()),
            this, SLOT(slotNotHighlightScene()));

    // Control tab containing the widgets defined above
    controlTab_ = new QTabWidget(this);
    controlLayout->addWidget(controlTab_, 1);

    controlTab_->addTab(stepWidget_, tr("Frames"));
    controlTab_->addTab(layerControlWidget_, tr("Layers"));
    // controlTab_->addTab(layerWidget_, tr("Layers"));
    // controlTab_->addTab(dataWidget_, tr("Data"));

    controlTab_->addTab(symbolWidget_, tr("Symbols"));

    // feature undo/redo
    undoStack_ = new QUndoStack(this);
    undoStack_->setUndoLimit(500);
    plotView_->setUndoStack(undoStack_);

#ifdef MVQ_FEATURE_DEV_MODE_
    // Feature edit
    // auto featureDevW = new QWidget(this);
    //    auto featureDevVb = new QVBoxLayout(featureDevW);
    //    featureDevVb->setContentsMargins(0,0,0,0);

    auto featureInfoW = new QPlainTextEdit(this);
    plotView_->setFeatureInfoWidget(featureInfoW);
    // featureDevVb->addWidget(featureInfoW);

    auto undoStackView = new QUndoView(undoStack_, this);
    // featureDevVb->addWidget(undoStackView);

    auto* devTab = new QTabWidget(this);
    devTab->addTab(undoStackView, tr("History"));
    devTab->addTab(featureInfoW, tr("Info"));

    controlTab_->addTab(devTab, tr("Dev"));
#endif

    connect(controlTab_, SIGNAL(currentChanged(int)),
            this, SLOT(slotControlTabChanged(int)));

    stepWidget_->init(plotScene_, "");

    // Plot rescale
    connect(this, SIGNAL(plotScaleChanged()),
            this, SLOT(slotPlotScaleChanged()));

    // Setup the actions
    setupFileActions();
    setupShareActions();
    setupViewActions();
    setupAnimationActions();
    setupZoomActions();
    setupToolsActions();
    setupEditActions();
    setupHelpActions();
    setupMenus(menuItems_);
    setupProgressBarActions();

    //------------------------------
    // uPlot area
    //------------------------------

    mainSplitter_ = new QSplitter(this);
    mainSplitter_->setOpaqueResize(false);

    plotLayout_ = new QVBoxLayout();
    plotLayout_->setContentsMargins(0, 0, 0, 0);
    plotLayout_->setSpacing(0);

    auto* plotW = new QWidget(this);
    plotW->setLayout(plotLayout_);
    plotLayout_->addWidget(plotView_);

    mainSplitter_->addWidget(plotW);
    mainSplitter_->addWidget(controlWidget_);
    mainSplitter_->setCollapsible(1, false);

    // Define the whole lot as central widget
    setCentralWidget(mainSplitter_);

    // Read qt geometry settings
    readSettings();
}

uPlot::~uPlot()
{
    // Save qt geometry settings
    writeSettings();
}

void uPlot::setupFileActions()
{
    // Print
    auto* actionPrint = new QAction(this);
    actionPrint->setObjectName(QString::fromUtf8("actionPrint"));
    QIcon icon;
    icon.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/print.svg")), QIcon::Normal, QIcon::Off);
    actionPrint->setIcon(icon);
    actionPrint->setText(tr("&Print"));
    actionPrint->setShortcut(tr("Ctrl+P"));

    // Export
    auto* actionExport = new QAction(this);
    actionExport->setObjectName(QString::fromUtf8("actionExport"));
    QIcon icon1;
    icon1.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/export.svg")), QIcon::Normal, QIcon::Off);
    actionExport->setIcon(icon1);
    actionExport->setText(tr("&Export"));
    actionExport->setShortcut(tr("Ctrl+S"));

    // Generate Macro
    auto* actionMacro = new QAction(this);
    actionMacro->setObjectName(QString::fromUtf8("actionMacro"));
    QIcon icon2;
    icon2.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/generate_macro.svg")), QIcon::Normal, QIcon::Off);
    actionMacro->setIcon(icon2);
    actionMacro->setText(tr("Generate &Macro"));
    actionMacro->setShortcut(tr("Ctrl+M"));

    // Exit
    /*QAction* actionExit = new QAction(this);
        actionExit->setObjectName(QString::fromUtf8("actionExit"));
    actionExit->setText(tr("Exit"));
    fileActions_.push_back(actionExit);*/

    connect(actionExport, SIGNAL(triggered()),
            this, SLOT(slotLoadExportDialog()));

    connect(actionPrint, SIGNAL(triggered()),
            this, SLOT(slotLoadPrintDialog()));

    connect(actionMacro, SIGNAL(triggered()),
            this, SLOT(slotGenerateMacro()));

    MvQMainWindow::MenuType menuType = MvQMainWindow::FileMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionExport));
    menuItems_[menuType].push_back(new MvQMenuItem(actionPrint));
    menuItems_[menuType].push_back(new MvQMenuItem(actionMacro));
}

void uPlot::setupShareActions()
{
    MvQMainWindow::MenuType menuType = MvQMainWindow::ShareMenu;

#ifdef METVIEW_WEATHER_ROOM
    // Weather room connection
    if (weatherRoom_) {
        // Add video wall export action
        QAction* actionWroom = new QAction(this);
        actionWroom->setObjectName(QString::fromUtf8("actionWroom"));
        actionWroom->setIcon(QPixmap(QString::fromUtf8(":/uPlot/videowall.svg")));
        actionWroom->setText(tr("Export to video wall"));

        connect(actionWroom, SIGNAL(triggered()),
                this, SLOT(slotLoadWeatherRoomDialog()));

        menuItems_[menuType].push_back(new MvQMenuItem(actionWroom, MvQMenuItem::MenuTarget));

        // Add video wall synchronisation action
        QAction* actionWroomSync = new QAction(this);
        actionWroomSync->setObjectName(QString::fromUtf8("actionWroomSync"));
        actionWroomSync->setCheckable(true);
        actionWroomSync->setChecked(false);
        QIcon icon;
        icon.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/videowall_sync.svg")), QIcon::Normal, QIcon::Off);
        actionWroomSync->setIcon(icon);
        actionWroomSync->setText(tr("Synchronise to video wall"));

        connect(actionWroomSync, SIGNAL(toggled(bool)),
                this, SLOT(slotEnableWroomSync(bool)));

        menuItems_[menuType].push_back(new MvQMenuItem(actionWroomSync, MvQMenuItem::MenuTarget));
    }
#endif

#ifdef METVIEW_SHARE_PLOT
    ShareTargetManager* sts = ShareTargetManager::instance();

    // Add a separator
    if (sts->size() > 0) {
        QAction* actionSt = new QAction(this);
        actionSt->setSeparator(true);
        menuItems_[menuType].push_back(new MvQMenuItem(actionSt, MvQMenuItem::MenuTarget));
    }

    // Add share icons to the ui
    for (size_t i = 0; i < sts->size(); i++) {
        ShareTarget* st = sts->at(i);

        // Add action
        QAction* actionSt = new QAction(this);
        actionSt->setObjectName(QString::fromUtf8(st->name().c_str()));
        std::string iconname = ":/uPlot/" + st->icon();
        actionSt->setIcon(QPixmap(QString::fromUtf8(iconname.c_str())));
        actionSt->setText(tr(st->name().c_str()));
        actionSt->setData((int)i);

        connect(actionSt, SIGNAL(triggered()),
                this, SLOT(slotShareTarget()));

        menuItems_[menuType].push_back(new MvQMenuItem(actionSt, MvQMenuItem::MenuTarget));
    }
#endif

    // Metview-ecCharts connection
    if (getenv("METVIEW_ECCHARTS")) {
        // Generate ecCharts layer
        auto* actionEcCharts = new QAction(this);
        actionEcCharts->setObjectName(QString::fromUtf8("actionEcCharts"));
        QIcon icon3;
        icon3.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/videowall.svg")), QIcon::Normal, QIcon::Off);
        actionEcCharts->setIcon(icon3);
        actionEcCharts->setText(tr("&Export ecCharts"));
        actionEcCharts->setShortcut(tr("Ctrl+E"));

        connect(actionEcCharts, SIGNAL(triggered()),
                this, SLOT(slotLoadEcChartsDialog()));

        menuItems_[menuType].push_back(new MvQMenuItem(actionEcCharts));
    }
}

void uPlot::setupToolsActions()
{
    // Magnfier
    auto* actionMagnifier = new QAction(this);
    actionMagnifier->setObjectName(QString::fromUtf8("actionMagnifier"));
    actionMagnifier->setCheckable(true);
    QIcon icon3;
    icon3.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/magnifier.svg")), QIcon::Normal, QIcon::Off);
    actionMagnifier->setIcon(icon3);
    actionMagnifier->setText(tr("&Magnifier"));

    // Cursor data
    auto* actionCursorData = new QAction(this);
    actionCursorData->setObjectName(QString::fromUtf8("actionCursorData"));
    actionCursorData->setCheckable(true);
    QIcon icon1;
    icon1.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/gunsight.svg")), QIcon::Normal, QIcon::Off);
    actionCursorData->setIcon(icon1);
    actionCursorData->setText(tr("&Cursor data"));

    // reset cursor data
    auto* actionCursorDataReset = new QAction(this);
    actionCursorDataReset->setObjectName(QString::fromUtf8("actionCursorDataReset"));
    actionCursorDataReset->setText(tr("&Reset cursor data"));

    // Antialias
    actionAntialias_ = new QAction(this);
    actionAntialias_->setObjectName(QString::fromUtf8("actionAntialias"));
    actionAntialias_->setCheckable(true);
    actionAntialias_->setChecked(true);

    // no signal is atatched to this action yet,
    // so we need to call this function for a proper init
    slotEnableAntialias(true);
    QIcon icon2;
    icon2.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/antialias.svg")), QIcon::Normal, QIcon::Off);
    actionAntialias_->setIcon(icon2);
    actionAntialias_->setText(tr("Antialias"));
    actionAntialias_->setShortcut(tr("Ctrl+L"));

    // Magnifier
    connect(actionMagnifier, SIGNAL(toggled(bool)),
            plotView_, SLOT(slotSetEnableMagnifier(bool)));

    connect(plotView_, SIGNAL(magnifierIsEnabledProgramatically(bool)),
            actionMagnifier, SLOT(setChecked(bool)));

    // Cursor data
    connect(actionCursorData, SIGNAL(toggled(bool)),
            plotView_, SLOT(slotSetEnableCursorData(bool)));

    connect(actionCursorDataReset, SIGNAL(triggered()),
            plotView_, SLOT(slotResetCursorData()));

    connect(plotView_, SIGNAL(cursorDataCoordsChanged(CursorCoordinate)),
            locationLabel_, SLOT(setLocation(CursorCoordinate)));


    connect(actionAntialias_, SIGNAL(toggled(bool)),
            this, SLOT(slotEnableAntialias(bool)));

    MvQMainWindow::MenuType menuType = MvQMainWindow::ToolsMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionMagnifier));
    menuItems_[menuType].push_back(new MvQMenuItem(actionCursorData));
    menuItems_[menuType].push_back(new MvQMenuItem(actionCursorDataReset, MvQMenuItem::MenuTarget));
    menuItems_[menuType].push_back(new MvQMenuItem(actionAntialias_));
}

void uPlot::setupViewActions()
{
    QAction* action = nullptr;

    // Sidebar
    actionControlPanel_ = new QAction(this);
    actionControlPanel_->setObjectName(QString::fromUtf8("actionControlPanel"));
    actionControlPanel_->setCheckable(true);
    actionControlPanel_->setChecked(true);  //!!!
    actionControlPanel_->setText(tr("&Sidebar"));
    QIcon icon2;
    icon2.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/sidebar.svg")), QIcon::Normal, QIcon::Off);
    actionControlPanel_->setIcon(icon2);

    // Active scene highlight
    action = new QAction(this);
    action->setObjectName(QString::fromUtf8("actionHighlightScene"));
    QIcon icon4;
    icon4.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/highlight_scene.svg")), QIcon::Normal, QIcon::Off);
    action->setIcon(icon4);
    action->setText(tr("&Highlight active scene"));
    action->setCheckable(true);
    action->setChecked(false);  //!!!
    actionHighlightScene_ = action;

    connect(actionControlPanel_, SIGNAL(toggled(bool)),
            this, SLOT(slotShowControlPanel(bool)));

    connect(actionHighlightScene_, SIGNAL(toggled(bool)),
            this, SLOT(slotHighlightActiveScene(bool)));

    auto* sep = new QAction(this);
    sep->setSeparator(true);

    auto* sep1 = new QAction(this);
    sep1->setSeparator(true);

    //location
    locationLabel_ = new metview::uplot::LocationLabelWidget(this);
    statusBar()->addPermanentWidget(locationLabel_);

    MvQMainWindow::MenuType menuType = MvQMainWindow::ViewMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionControlPanel_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionHighlightScene_));
    menuItems_[menuType].push_back(new MvQMenuItem(sep));
    menuItems_[menuType].push_back(new MvQMenuItem(locationLabel_->viewAction(), MvQMenuItem::MenuTarget));
    menuItems_[menuType].push_back(new MvQMenuItem(sep1));

    uPlotBase::setupViewActions();
}

void uPlot::setupAnimationActions()
{
    // Play
    actionPlay_ = new QAction(this);
    actionPlay_->setObjectName(QString::fromUtf8("actionPlay"));
    QIcon icon5;
    icon5.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_play.svg")), QIcon::Normal, QIcon::Off);
    actionPlay_->setIcon(icon5);
    actionPlay_->setText(tr("&Play"));
    // animationActions_.push_back(actionPlay_);

    // Stop
    actionStop_ = new QAction(this);
    actionStop_->setObjectName(QString::fromUtf8("actionStop"));
    QIcon icon6;
    icon6.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_stop.svg")), QIcon::Normal, QIcon::Off);
    actionStop_->setIcon(icon6);
    actionStop_->setText(tr("&Stop"));
    // animationActions_.push_back(actionStop_);

    // Prev
    actionPrevious_ = new QAction(this);
    actionPrevious_->setObjectName(QString::fromUtf8("actionPrevious"));
    QIcon icon8;
    icon8.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_prev.svg")), QIcon::Normal, QIcon::Off);
    actionPrevious_->setIcon(icon8);
    actionPrevious_->setText(tr("P&revious"));
    actionPrevious_->setShortcut(tr("Left"));
    // animationActions_.push_back(actionPrevious_);

    // Next
    actionNext_ = new QAction(this);
    actionNext_->setObjectName(QString::fromUtf8("actionNext"));
    QIcon icon7;
    icon7.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_next.svg")), QIcon::Normal, QIcon::Off);
    actionNext_->setIcon(icon7);
    actionNext_->setText(tr("&Next"));
    actionNext_->setShortcut(tr("Right"));
    // animationActions_.push_back(actionNext_);

    // First
    actionFirst_ = new QAction(this);
    actionFirst_->setObjectName(QString::fromUtf8("actionFirst"));
    QIcon icon9;
    icon9.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_start.svg")), QIcon::Normal, QIcon::Off);
    actionFirst_->setIcon(icon9);
    actionFirst_->setText(tr("&First"));
    actionFirst_->setShortcut(tr("Home"));
    // animationActions_.push_back(actionFirst_);

    // Last
    actionLast_ = new QAction(this);
    actionLast_->setObjectName(QString::fromUtf8("actionLast"));
    QIcon icon10;
    icon10.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/player_end.svg")), QIcon::Normal, QIcon::Off);
    actionLast_->setIcon(icon10);
    actionLast_->setText(tr("&Last"));
    actionLast_->setShortcut(tr("End"));
    // animationActions_.push_back(actionLast_);


    connect(actionPlay_, SIGNAL(triggered()),
            this, SLOT(slotPlay()));

    connect(actionStop_, SIGNAL(triggered()),
            this, SLOT(slotStop()));

    connect(actionNext_, SIGNAL(triggered()),
            this, SLOT(slotToNext()));

    connect(actionPrevious_, SIGNAL(triggered()),
            this, SLOT(slotToPrev()));

    connect(actionFirst_, SIGNAL(triggered()),
            this, SLOT(slotToFirst()));

    connect(actionLast_, SIGNAL(triggered()),
            this, SLOT(slotToLast()));


    // Animation speed
    float fval[] = {0.5, 0.7, 1, 1.5, 2, 3, 4, 5, 10};
    for (float& i : fval) {
        speed_.push_back(i);
    }

    actSpeedIndex_ = 2;

    timer_ = new QTimer(this);
    timer_->setInterval(1000. / speed_[actSpeedIndex_]);
    connect(timer_, SIGNAL(timeout()), this, SLOT(slotToNext()));

    auto* speedPb = new QPushButton;

    speedPb->setText(tr("Speed"));
    speedPb->setObjectName("speedPb");

    auto* menuSpeed = new QMenu("&Animation");

    speedPb->setMenu(menuSpeed);

    speedSlider_ = new QSlider(Qt::Vertical);
    speedSlider_->setMaximumWidth(100);
    speedSlider_->setMinimum(0);
    speedSlider_->setMaximum(speed_.size() - 1);
    speedSlider_->setSliderPosition(actSpeedIndex_);
    speedSlider_->setSingleStep(1);
    speedSlider_->setPageStep(1);
    speedSlider_->setTickInterval(1);
    speedSlider_->setTickPosition(QSlider::TicksBelow);
    speedSlider_->setToolTip("Animation speed");

    speedLabel_ = new QLabel;
    speedLabel_->setText("Speed: 1 fr/s");
    // toolBarAnimation->addWidget(speedLabel_);

    // QVBoxLayout *vl = new QVBoxLayout;
    // vl->addWidget(speedSlider_);
    // vl->addWidget(speedLabel_);

    auto* wa = new QWidgetAction(menuSpeed);
    wa->setDefaultWidget(speedSlider_);
    menuSpeed->addAction(wa);

    wa = new QWidgetAction(menuSpeed);
    wa->setDefaultWidget(speedLabel_);
    menuSpeed->addAction(wa);


    connect(speedSlider_, SIGNAL(valueChanged(int)), this, SLOT(slotSetSpeed(int)));


    // Active scene highlight
    auto* action = new QAction(this);
    action->setObjectName(QString::fromUtf8("actionAnimatedScenes"));
    QIcon icon4;
    icon4.addPixmap(QPixmap(QString::fromUtf8(":/uPlot/connectAnimations.svg")), QIcon::Normal, QIcon::Off);
    action->setIcon(icon4);
    action->setText(tr("&Animate all scenes"));
    action->setCheckable(true);
    action->setChecked(true);
    actionAnimatedScenes_ = action;

    //
    actionPlay_->setEnabled(false);
    actionStop_->setEnabled(false);
    actionFirst_->setEnabled(false);
    actionNext_->setEnabled(false);
    actionPrevious_->setEnabled(false);
    actionLast_->setEnabled(false);

    connect(actionAnimatedScenes_, SIGNAL(toggled(bool)),
            this, SLOT(slotAnimatedScenes(bool)));

    MvQMainWindow::MenuType menuType = MvQMainWindow::AnimationMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionPlay_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionStop_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionPrevious_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionNext_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionFirst_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionLast_));
    menuItems_[menuType].push_back(new MvQMenuItem(speedPb));
    menuItems_[menuType].push_back(new MvQMenuItem(actionAnimatedScenes_, MvQMenuItem::MenuTarget));
}


void uPlot::setupEditActions()
{
    // redo
    actionRedo_ = undoStack_->createRedoAction(this, tr("&Redo"));
    actionRedo_->setShortcuts(QKeySequence::Redo);
    actionRedo_->setIcon(QPixmap(":/uPlot/redo.svg"));

    // undo
    actionUndo_ = undoStack_->createUndoAction(this, tr("&Undo"));
    actionUndo_->setShortcuts(QKeySequence::Undo);
    actionUndo_->setIcon(QPixmap(":/uPlot/undo.svg"));

    MvQMainWindow::MenuType menuType = MvQMainWindow::EditMenu;

    menuItems_[menuType].push_back(new MvQMenuItem(actionUndo_));
    menuItems_[menuType].push_back(new MvQMenuItem(actionRedo_));
}


void uPlot::setupProgressBarActions()
{
    // TODO: This should one be visible when we use it!!!!
    // TODO: should be created via a the menuIt ems mechanism
    //  Create a toolbar to handle the progress bar
    auto progressToolbar = new QToolBar("Progress bar Toolbar", this);
    progressToolbar->setObjectName("progressbar");

    addToolBar(progressToolbar);

    // Create a progress bar
    progressBar_ = new MvQProgressBarPanel(progressToolbar);
}

bool uPlot::setDropTarget(QPoint globalPos)
{
    MgQSceneItem* item = nullptr;

    QPointF scenePos = plotView_->mapToScene(plotView_->mapFromGlobal(globalPos));

    /*if(layerWidget_->layerAtGlobalPos(globalPos) != -1)
    {
        return false;
    }
    else
    {
        if(activeScene_)
        {
            if(activeScene_->sceneBoundingRect().contains(scenePos))
                return true;
        }
    }*/

    if (activeScene_) {
        if (activeScene_->sceneBoundingRect().contains(scenePos))
            return true;
    }

    item = plotScene_->findSceneItem(scenePos);
    if (item || plotScene_->sceneItems().count() == 0) {
        slotSetActiveScene(item);
        return true;
    }
    else {
        return false;
    }

    return false;
}

bool uPlot::setDropTargetInView(QPoint pos)
{
    MgQSceneItem* item = nullptr;

    QPointF scenePos = plotView_->mapToScene(pos);

    if (activeScene_) {
        if (activeScene_->sceneBoundingRect().contains(scenePos))
            return true;
    }

    item = plotScene_->findSceneItem(scenePos);
    if (item || plotScene_->sceneItems().count() == 0) {
        slotSetActiveScene(item);
        return true;
    }
    else {
        return false;
    }

    return false;
}

void uPlot::newRequestForDriversBegin()
{
    plotScene_->saveStateBeforeNewRequest();

    // Frames
    stepWidget_->stepDataIsAboutToChange();

    // Layer contents
    layerWidget_->layersAreAboutToChange();

    // Layer data
    dataWidget_->layersAreAboutToChange();

    // Magnifier
    plotView_->resetBegin();

    if (activeScene_) {
        prevActiveSceneId_ = activeScene_->layout().id();
        if (prevActiveSceneId_.empty()) {
            MgQLayoutItem* projItem = activeScene_->firstProjectorItem();
            prevActiveSceneId_ = projItem->layout().id();
        }
    }
    else {
        prevActiveSceneId_.clear();
    }

    activeScene_ = nullptr;

    controlWidget_->setEnabled(false);

    loadStarted();
}


void uPlot::newRequestForDriversEnd()
{
    controlWidget_->setEnabled(true);

    // Select the active scene
    if (!activeScene_) {
        if (!prevActiveSceneId_.empty()) {
            foreach (MgQSceneItem* item, plotScene_->sceneItems()) {
                MgQLayoutItem* projItem = item->firstProjectorItem();
                if (item->layout().id() == prevActiveSceneId_) {
                    activeScene_ = item;
                    break;
                }
                else if (item->layout().id().empty() && projItem &&
                         prevActiveSceneId_ == projItem->layout().id()) {
                    activeScene_ = item;
                    break;
                }
            }
        }


        if (!activeScene_ && plotScene_->sceneItems().count() > 0) {
            activeScene_ = plotScene_->sceneItems().back();
        }
    }

    // Resize without rendering!!
    changeSize(sizeCombo_->itemData(sizeCombo_->currentIndex(), Qt::UserRole).toInt(), false);

    // Load steps/layers and generate layer thumbnails - No rendering at this point!
    // It tries to set the current step for all the scenes!
    // The current step should be correctly set at least for the active scene.
    plotScene_->updateAfterNewRequest();

    // Zoom stack - generate thumbnail for the new area
    zoomStackWidget_->reset(activeScene_, false);
    updateZoomActionState();

    // Layer contents
    layerWidget_->reset(activeScene_);

    // Layer data - will set the current step for the data widgets!
    dataWidget_->reset(activeScene_);

    // Update scene combobox
    if (plotScene_->sceneItems().count() <= 1) {
        sceneWidget_->hide();
        sceneCb_->clear();
    }
    else {
        // Scene combo
        sceneCb_->clear();
        for (int i = 0; i < plotScene_->sceneItems().count(); i++) {
            sceneCb_->addItem(tr("Scene ") + QString::number(i + 1));
        }
        int actIndex = plotScene_->sceneItems().indexOf(activeScene_);
        if (actIndex != -1)
            sceneCb_->setCurrentIndex(actIndex);

        sceneWidget_->show();
    }

    // Generate animated scenes list
    if (plotScene_->sceneItems().count() <= 1) {
        animatedScenes_.clear();
    }
    else {
        actionAnimatedScenes_->setEnabled(true);
        slotAnimatedScenes(actionAnimatedScenes_->isChecked());
    }

    // Frames - no rendering!!
    // At this point the current step should be correctly set for the active scene!!

    // non of these updates can call resetEnd()
    ignoreResetEnd_ = true;

    stepWidget_->reset(activeScene_);
    if (activeScene_) {
        // Update the view
        stepWidget_->setViewToCurrentStep();

        // Set the correct step for the aminated scenes. No rendering involved!
        stepWidget_->updateStepForScenes(animatedScenes_);
    }

    // Animation buttons
    updateAnimationActionState();

    // NOW RENDER IT! We render the whole scene into the pixmap cache at this point!
    plotScene_->sceneItemChanged();

    // Update magnifier, cursordata etc
    ignoreResetEnd_ = false;
    plotView_->resetEnd();

    // Udate scene selection
    if (plotScene_->sceneItems().count() <= 1) {
        actionHighlightScene_->setEnabled(false);
    }
    else {
        actionHighlightScene_->setEnabled(true);
        slotHighlightActiveScene(actionHighlightScene_->isChecked());
    }


    loadFinished();

    // Emit a signal that the plot window has been updated
    emit plotWindowUpdated();
}


void uPlot::slotShowControlPanel(bool status)
{
    if (status) {
        controlWidget_->show();
    }
    else {
        controlWidget_->hide();
    }
}


//===============================================
//
// Animaton
//
//===============================================

void uPlot::slotToPrev()
{
    if (stepWidget_->currentStep() > 0) {
        slotStepTo(stepWidget_->currentStep() - 1);
    }
}

void uPlot::slotToNext()
{
    if (stepWidget_->currentStep() < stepWidget_->stepNum() - 1) {
        slotStepTo(stepWidget_->currentStep() + 1);
    }
    else if (timer_->isActive()) {
        slotToFirst();
    }
}

void uPlot::slotToLast()
{
    if (stepWidget_->currentStep() < stepWidget_->stepNum() - 1) {
        slotStepTo(stepWidget_->stepNum() - 1);
    }
}

void uPlot::slotToFirst()
{
    if (stepWidget_->currentStep() > 0) {
        slotStepTo(0);
    }
}

void uPlot::slotPlay()
{
    timer_->start();
    updateAnimationActionState();
}

void uPlot::slotStop()
{
    timer_->stop();
    updateAnimationActionState();
}

void uPlot::slotStepTo(const QModelIndex& index)
{
    slotStepTo(index.row());
}

void uPlot::slotStepTo(int fr)
{
    plotView_->resetBegin();

    if (fr == stepWidget_->setCurrentStep(fr, animatedScenes_)) {
        updateAnimationActionState();
        stepWidget_->setViewToCurrentStep();
        layerWidget_->slotFrameChanged();
        dataWidget_->slotFrameChanged();
    }

    if (!ignoreResetEnd_) {
        plotView_->resetEnd();
    }
}

void uPlot::slotSetSpeed(int sp)
{
    if (actSpeedIndex_ != sp) {
        actSpeedIndex_ = sp;
        timer_->setInterval(1000. / speed_[actSpeedIndex_]);

        QString s = "Speed: ";
        s.append(QString::number(speed_[actSpeedIndex_]));
        s.append(" fr/s");
        speedLabel_->setText(s);
    }
}

void uPlot::updateAnimationActionState()
{
    if (stepWidget_->stepNum() < 2) {
        actionPlay_->setEnabled(false);
        actionStop_->setEnabled(false);
        actionFirst_->setEnabled(false);
        actionNext_->setEnabled(false);
        actionPrevious_->setEnabled(false);
        actionLast_->setEnabled(false);
        return;
    }
    else {
        if (timer_->isActive() == true) {
            actionPlay_->setEnabled(false);
            actionStop_->setEnabled(true);
        }
        else {
            actionPlay_->setEnabled(true);
            actionStop_->setEnabled(false);
        }
    }

    if (timer_->isActive() == false) {
        if (stepWidget_->currentStep() == 0) {
            actionFirst_->setEnabled(false);
            actionNext_->setEnabled(true);
            actionPrevious_->setEnabled(false);
            actionLast_->setEnabled(true);
        }
        else if (stepWidget_->currentStep() == stepWidget_->stepNum() - 1) {
            actionFirst_->setEnabled(true);
            actionNext_->setEnabled(false);
            actionPrevious_->setEnabled(true);
            actionLast_->setEnabled(false);
        }
        else {
            actionFirst_->setEnabled(true);
            actionNext_->setEnabled(true);
            actionPrevious_->setEnabled(true);
            actionLast_->setEnabled(true);
        }
    }
    else {
        actionFirst_->setEnabled(false);
        actionNext_->setEnabled(false);
        actionPrevious_->setEnabled(false);
        actionLast_->setEnabled(false);
    }
}
int uPlot::currentStep()
{
    return stepWidget_->currentStep();
}

int uPlot::stepNum()
{
    return stepWidget_->stepNum();
}

//=================================
//
// Active scene selection
//
//=================================

void uPlot::slotSelectActiveScene()
{
    // actionSelectScene_->setEnabled(false);
    // plotView_->slotSelectScene();
}

void uPlot::slotActiveSceneSelected(QPointF /*scenePos*/)
{
    // MgQSceneItem *item=plotScene_->findSceneItem(scenePos);

    // setActiveScene(item);
    // identifyScene(item);
    // actionSelectScene_->setEnabled(true);
}

void uPlot::slotHighlightActiveScene(bool bval)
{
    plotScene_->highlightSceneItem(activeScene_, bval);
}

void uPlot::slotAnimatedScenes(bool bval)
{
    if (bval) {
        animatedScenes_ = plotScene_->sceneItems();
    }
    else {
        animatedScenes_.clear();
    }
}


void uPlot::slotSetActiveSceneByIndex(int index)
{
    if (index < 0 || index >= plotScene_->sceneItems().count())
        return;

    slotSetActiveScene(plotScene_->sceneItems().at(index));
}

void uPlot::slotSetActiveScene(MgQSceneItem* activeScene)
{
    if (!activeScene)
        return;

    if (activeScene_ == activeScene)
        return;

    activeScene_ = activeScene;

    // Zoom stack
    zoomStackWidget_->reset(activeScene_, true);
    updateZoomActionState();

    layerWidget_->layersAreAboutToChange();
    layerWidget_->reset(activeScene_);

    dataWidget_->layersAreAboutToChange();
    dataWidget_->reset(activeScene_);

    // stepWidget_->stepDataIsAboutToChange();
    stepWidget_->reset(activeScene_);

    slotHighlightActiveScene(actionHighlightScene_->isChecked());

    // Remove the highlight rectangle activated by the scene combo box!
    slotNotHighlightScene();

    updateAnimationActionState();

    sceneCb_->setCurrentIndex(plotScene_->sceneItems().indexOf(activeScene));

    // Emit a signal that the plot windows has been updated
    // emit plotWindowUpdated();  ???????????????
}


void uPlot::slotHighlightScene(int index)
{
    if (index < 0 || index >= plotScene_->sceneItems().count())
        return;

    MgQSceneItem* item = plotScene_->sceneItems().at(index);

    plotScene_->highlightSceneItemForBrief(item, true);
}

void uPlot::slotNotHighlightScene()
{
    plotScene_->highlightSceneItemForBrief(nullptr, false);
}


void uPlot::slotLayerUpdate()
{
    // Notify the scene about the change in the layer status
    // plotScene_->updateLayers(layerWidget_->model()->layers());
    plotScene_->update();
}

void uPlot::progressMessage(const std::string& /*m*/)
{
#ifdef METVIEW_EXPERIMENTAL

#if 0
	if(progressItem_ && progressItem_->isVisible())
	{
		progressItem_->progress();
		QCoreApplication::sendPostedEvents(plotScene_,0);  
	}
#endif
#endif
}

void uPlot::loadStarted()
{
#ifdef METVIEW_EXPERIMENTAL
#if 0
	if(!progressItem_)
	{
	  	progressItem_=new MvQProgressItem;
		progressItem_->setVisible(false);
		plotScene_->addItem(progressItem_);
	}
	
	progressItem_->setRect(plotScene_->sceneRect());
	progressItem_->startProgress();
	progressItem_->setVisible(true);
#endif
#endif
}

void uPlot::loadFinished()
{
#ifdef METVIEW_EXPERIMENTAL
#if 0
	if(progressItem_)
	{	
		progressItem_->setVisible(false);
	}
#endif
#endif
}

void uPlot::slotLayerTransparencyChanged(QString sid, int value)
{
    int id = sid.toInt();
    owner_->UpdateLayerTransparency(id, value);
}

void uPlot::slotLayerVisibilityChanged(QString sid, bool onoff)
{
    int id = sid.toInt();
    owner_->UpdateLayerVisibility(id, onoff);
}

void uPlot::slotLayerStackingOrderChanged(QList<QPair<QString, int> > lorder)
{
    for (auto& i : lorder) {
        int id = i.first.toInt();
        int value = i.second;
        owner_->UpdateLayerStackingOrder(id, value);
    }
}

void uPlot::slotPlotScaleChanged()
{
    dataWidget_->slotPlotScaleChanged();
}

void uPlot::slotControlTabChanged(int /*index*/)
{
#if 0
    if (index == 2) {
        dataWidget_->resetLayerList();
    }
#endif
}

void uPlot::slotAddRibbonEditor(QWidget* w)
{
    plotLayout_->insertWidget(0, w);
}

void uPlot::writeSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV4-uPlot");

    //!!
    settings.clear();

    settings.beginGroup("main");
    settings.setValue("geometry", saveGeometry());
    settings.setValue("state", saveState());
    settings.setValue("mainSplitter", mainSplitter_->saveState());

    settings.setValue("stepKeyProfileName", stepWidget_->currentKeyProfile());
    settings.setValue("currentControlTabIndex", controlTab_->currentIndex());
    settings.setValue("antialias", actionAntialias_->isChecked());
    settings.setValue("controlPanel", actionControlPanel_->isChecked());
    settings.setValue("highlightScene", actionHighlightScene_->isChecked());
    settings.setValue("animatedScenes", actionAnimatedScenes_->isChecked());

    locationLabel_->writeSettings(settings);

    settings.setValue("sizeIndex", sizeCombo_->currentIndex());
    int sizeId = sizeCombo_->itemData(sizeCombo_->currentIndex(), Qt::UserRole).toInt();
    settings.setValue("sizeId", sizeId);

    settings.endGroup();

    dataWidget_->writeSettings(settings);
    symbolWidget_->writeSettings(settings);
}

void uPlot::readSettings()
{
    QSettings settings(MVQ_QSETTINGS_DEFAULT_ARGS, "MV4-uPlot");

    settings.beginGroup("main");
    restoreGeometry(settings.value("geometry").toByteArray());
    restoreState(settings.value("state").toByteArray());

    if (settings.contains("mainSplitter")) {
        mainSplitter_->restoreState(settings.value("mainSplitter").toByteArray());
    }
    else {
        Q_ASSERT(mainSplitter_->count() == 2);
        if (mainSplitter_->count() == 2) {
            int w = size().width();
            if (w > 0) {
                auto sLst = mainSplitter_->sizes();
                if (w > 800) {
                    sLst[1] = 250;
                    sLst[0] = w - 250;
                }
                else {
                    sLst[1] = w / 4;
                    sLst[0] = w - w / 4;
                }
                mainSplitter_->setSizes(sLst);
            }
        }
    }

    stepWidget_->setCurrentKeyProfile(settings.value("stepKeyProfileName").toString());
    controlTab_->setCurrentIndex(settings.value("currentControlTabIndex").toInt());

    if (settings.value("antialias").isNull()) {
        actionAntialias_->setChecked(true);
    }
    else {
        actionAntialias_->setChecked(settings.value("antialias").toBool());
    }

    if (settings.value("controlPanel").isNull()) {
        actionControlPanel_->setChecked(true);
    }
    else {
        actionControlPanel_->setChecked(settings.value("controlPanel").toBool());
    }

    if (settings.value("highlightScene").isNull()) {
        actionHighlightScene_->setChecked(false);
    }
    else {
        actionHighlightScene_->setChecked(settings.value("highlightScene").toBool());
    }

    if (settings.value("animatedScenes").isNull()) {
        actionAnimatedScenes_->setChecked(true);
    }
    else {
        actionAnimatedScenes_->setChecked(settings.value("animatedScenes").toBool());
    }

    locationLabel_->readSettings(settings);

    if (settings.value("sizeIndex").isNull()) {
        sizeCombo_->setCurrentIndex(5);
    }
    else {
        int current = settings.value("sizeIndex").toInt();
        if (current == customSizeItemIndex_) {
            if (!settings.value("sizeId").isNull()) {
                int sizeId = settings.value("sizeId").toInt();
                setCustomSize(sizeId);
            }
            else {
                sizeCombo_->setCurrentIndex(0);
            }
        }
        else {
            sizeCombo_->setCurrentIndex(settings.value("sizeIndex").toInt());
        }
    }


    settings.endGroup();

    dataWidget_->readSettings(settings);
    symbolWidget_->readSettings(settings);
}

void uPlot::slotShareTarget()
{
#ifdef METVIEW_SHARE_PLOT
    // Get a reference to the icon/button selected by the user
    QAction* ac = static_cast<QAction*>(sender());
    if (!ac)
        return;

    // Get the specific share target selected by the user
    QVariant qv = ac->data();
    ShareTarget* st = ShareTargetManager::instance()->at(qv.toInt());

    // Create progress manager
    MvQProgressManager* pm = new MvQProgressManager(stepWidget_->stepNum(), progressBar_);

    // Retrieve current plot request without output formats
    MvRequest req;
    owner_->GetAllRequests(req, true);

    // Get extra information from the user interface
    // The plotting function will be performed by the share target
    // ShareTarget class should delete point pm
    st->dialog(req, pm);
#endif
}

