MainWindow.cc 53.4 KB
Newer Older
1
/*===================================================================
pixhawk's avatar
pixhawk committed
2 3 4 5
======================================================================*/

/**
 * @file
6
 *   @brief Implementation of class MainWindow
7
 *   @author Lorenz Meier <mail@qgroundcontrol.org>
pixhawk's avatar
pixhawk committed
8 9 10 11 12 13 14 15 16 17 18
 */

#include <QSettings>
#include <QDockWidget>
#include <QNetworkInterface>
#include <QMessageBox>
#include <QDebug>
#include <QTimer>
#include <QHostInfo>

#include "MG.h"
19
#include "QGC.h"
pixhawk's avatar
pixhawk committed
20 21 22 23 24 25 26 27
#include "MAVLinkSimulationLink.h"
#include "SerialLink.h"
#include "UDPLink.h"
#include "MAVLinkProtocol.h"
#include "CommConfigurationWindow.h"
#include "WaypointList.h"
#include "MainWindow.h"
#include "JoystickWidget.h"
pixhawk's avatar
pixhawk committed
28
#include "GAudioOutput.h"
29
#include "QGCToolWidget.h"
30
#include "QGCMAVLinkLogPlayer.h"
31

32
#ifdef QGC_OSG_ENABLED
33
#include "Q3DWidgetFactory.h"
34
#endif
pixhawk's avatar
pixhawk committed
35

lm's avatar
lm committed
36 37 38 39
// FIXME Move
#include "PxQuadMAV.h"
#include "SlugsMAV.h"

pixhawk's avatar
pixhawk committed
40 41 42

#include "LogCompressor.h"

43 44
MainWindow* MainWindow::instance()
{
45 46 47 48
    static MainWindow* _instance = 0;
    if(_instance == 0)
    {
        _instance = new MainWindow();
49

50
        /* Set the application as parent to ensure that this object
51
                 * will be destroyed when the main application exits */
52 53 54
        //_instance->setParent(qApp);
    }
    return _instance;
55 56
}

pixhawk's avatar
pixhawk committed
57 58 59 60 61 62 63
/**
* Create new mainwindow. The constructor instantiates all parts of the user
* interface. It does NOT show the mainwindow. To display it, call the show()
* method.
*
* @see QMainWindow::show()
**/
64
MainWindow::MainWindow(QWidget *parent):
pixhawk's avatar
pixhawk committed
65
        QMainWindow(parent),
66
        toolsMenuActions(),
67
        currentView(VIEW_ENGINEER),
68
        aboutToCloseFlag(false),
69
        changingViewsFlag(false)
pixhawk's avatar
pixhawk committed
70
{
71 72 73 74 75 76 77 78 79 80 81 82 83 84
    if (!settings.contains("CURRENT_VIEW"))
    {
        // Set this view as default view
        settings.setValue("CURRENT_VIEW", currentView);

        // Enable default tools

        // ENABLE UAS LIST
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_UAS_LIST,currentView), true);
        // ENABLE COMMUNICATION CONSOLE
        settings.setValue(buildMenuKey(SUB_SECTION_CHECKED,MainWindow::MENU_DEBUG_CONSOLE,currentView), true);
    }
    else
    {
85 86 87 88
        if (settings.value("CURRENT_VIEW", VIEW_PILOT) != VIEW_PILOT)
        {
            currentView = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt();
        }
89 90
    }

91
    // Check if the settings exist, instantiate defaults if necessary
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

    // OPERATOR VIEW DEFAULT
    QString centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_MAP, VIEW_OPERATOR);
    if (!settings.contains(centralKey))
    {
        settings.setValue(centralKey,true);
    }

    // ENGINEER VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_LINECHART, VIEW_ENGINEER);
    if (!settings.contains(centralKey))
    {
        settings.setValue(centralKey,true);
    }

    // MAVLINK VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_PROTOCOL, VIEW_MAVLINK);
    if (!settings.contains(centralKey))
    {
        settings.setValue(centralKey,true);
    }

    // PILOT VIEW DEFAULT
    centralKey = buildMenuKey(SUB_SECTION_CHECKED, CENTRAL_HUD, VIEW_PILOT);
116 117 118
    if (!settings.contains(centralKey))
    {
        settings.setValue(centralKey,true);
119 120 121 122 123
    }

    QString listKey = buildMenuKey(SUB_SECTION_CHECKED, MENU_UAS_LIST, currentView);
    if (!settings.contains(listKey))
    {
124 125
        settings.setValue(listKey, true);
    }
126

127 128
    settings.sync();

pixhawk's avatar
pixhawk committed
129 130
    // Setup user interface
    ui.setupUi(this);
lm's avatar
lm committed
131
    ui.actionNewCustomWidget->setEnabled(false);
pixhawk's avatar
pixhawk committed
132

133 134
    setVisible(false);

135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
    // Bind together the perspective actions
    QActionGroup* perspectives = new QActionGroup(ui.menuPerspectives);
    perspectives->addAction(ui.actionEngineersView);
    perspectives->addAction(ui.actionMavlinkView);
    perspectives->addAction(ui.actionPilotsView);
    perspectives->addAction(ui.actionOperatorsView);
    perspectives->setExclusive(true);

    // Mark the right one as selected
    if (currentView == VIEW_ENGINEER) ui.actionEngineersView->setChecked(true);
    if (currentView == VIEW_MAVLINK) ui.actionMavlinkView->setChecked(true);
    if (currentView == VIEW_PILOT) ui.actionPilotsView->setChecked(true);
    if (currentView == VIEW_OPERATOR) ui.actionOperatorsView->setChecked(true);

    // The pilot view is not available on startup
    ui.actionPilotsView->setEnabled(false);

152
    buildCommonWidgets();
153

154
    connectCommonWidgets();
155

156
    arrangeCommonCenterStack();
157 158

    configureWindowName();
pixhawk's avatar
pixhawk committed
159 160 161 162

    // Set the application style (not the same as a style sheet)
    // Set the style to Plastique
    qApp->setStyle("plastique");
163

pixhawk's avatar
pixhawk committed
164
    // Set style sheet as last step
165 166 167 168 169 170 171
    QFile* styleSheet = new QFile(":/images/style-mission.css");
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
    {
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
        qApp->setStyleSheet(style);
    }
pixhawk's avatar
pixhawk committed
172

173
    // Create actions
174
    connectCommonActions();
175

176 177 178
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

179
    // Load mavlink view as default widget set
180
    //loadMAVLinkView();
181

lm's avatar
lm committed
182 183
    statusBar()->setSizeGripEnabled(true);

184 185
    // Restore the window position and size
    if (settings.contains(getWindowGeometryKey()))
186 187
    {
        // Restore the window geometry
188
        restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
189 190 191 192 193 194
    }
    else
    {
        // Adjust the size
        adjustSize();
    }
pixhawk's avatar
pixhawk committed
195

196 197 198 199 200 201
    // Populate link menu
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
    foreach(LinkInterface* link, links)
    {
        this->addLink(link);
    }
202

203 204
    connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*)));

lm's avatar
lm committed
205 206
    // Enable and update view
    presentView();
pixhawk's avatar
pixhawk committed
207 208
}

pixhawk's avatar
pixhawk committed
209
MainWindow::~MainWindow()
pixhawk's avatar
pixhawk committed
210
{
lm's avatar
lm committed
211

pixhawk's avatar
pixhawk committed
212 213
}

lm's avatar
lm committed
214 215 216 217 218 219 220 221 222 223 224 225 226
void MainWindow::resizeEvent(QResizeEvent * event)
{
    Q_UNUSED(event);
    if (height() < 800)
    {
        ui.statusBar->setVisible(false);
    }
    else
    {
        ui.statusBar->setVisible(true);
    }
}

227 228 229 230 231 232 233 234 235 236
QString MainWindow::getWindowStateKey()
{
    return QString::number(currentView)+"/windowstate";
}

QString MainWindow::getWindowGeometryKey()
{
    return QString::number(currentView)+"/geometry";
}

lm's avatar
lm committed
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
void MainWindow::buildCustomWidget()
{
    // Show custom widgets only if UAS is connected
    if (UASManager::instance()->getActiveUAS() != NULL)
    {
        // Enable custom widgets
        ui.actionNewCustomWidget->setEnabled(true);

        // Create custom widgets
        QList<QGCToolWidget*> widgets = QGCToolWidget::createWidgetsFromSettings(this);

        if (widgets.size() > 0)
        {
            ui.menuTools->addSeparator();
        }

        for(int i = 0; i < widgets.size(); ++i)
        {
            qDebug() << "ADDING WIDGET #" << i << widgets.at(i);
            // Check if this widget already has a parent, do not create it in this case
            QDockWidget* dock = dynamic_cast<QDockWidget*>(widgets.at(i)->parentWidget());
            if (!dock)
            {
                QDockWidget* dock = new QDockWidget(widgets.at(i)->windowTitle(), this);
                dock->setWidget(widgets.at(i));
                connect(widgets.at(i), SIGNAL(destroyed()), dock, SLOT(deleteLater()));
                QAction* showAction = new QAction(widgets.at(i)->windowTitle(), this);
                connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
                connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
                widgets.at(i)->setMainMenuAction(showAction);
                ui.menuTools->addAction(showAction);
                addDockWidget(Qt::BottomDockWidgetArea, dock);
            }
        }
    }
}

274 275 276 277
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
278
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
279 280

    // Dock widgets
281 282 283
    if (!controlDockWidget)
    {
        controlDockWidget = new QDockWidget(tr("Control"), this);
284
        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
285 286 287
        controlDockWidget->setWidget( new UASControlWidget(this) );
        addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget()), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
    }
288

289 290 291 292
    if (!listDockWidget)
    {
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
293
        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
294 295
        addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget()), MENU_UAS_LIST, Qt::RightDockWidgetArea);
    }
296

297 298 299 300
    if (!waypointsDockWidget)
    {
        waypointsDockWidget = new QDockWidget(tr("Waypoint List"), this);
        waypointsDockWidget->setWidget( new WaypointList(this, NULL) );
301
        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
302 303
        addToToolsMenu (waypointsDockWidget, tr("Waypoints List"), SLOT(showToolWidget()), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
    }
304

305 306 307 308
    if (!infoDockWidget)
    {
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
pixhawk's avatar
pixhawk committed
309
        infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
310 311
        addToToolsMenu (infoDockWidget, tr("Status Details"), SLOT(showToolWidget()), MENU_STATUS, Qt::RightDockWidgetArea);
    }
312

313 314 315 316
    if (!debugConsoleDockWidget)
    {
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
317
        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
318 319
        addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget()), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
    }
320

321 322 323 324 325 326 327 328
    if (!logPlayerDockWidget)
    {
        logPlayerDockWidget = new QDockWidget(tr("MAVLink Log Player"), this);
        logPlayerDockWidget->setWidget( new QGCMAVLinkLogPlayer(mavlink, this) );
        logPlayerDockWidget->setObjectName("MAVLINK_LOG_PLAYER_DOCKWIDGET");
        addToToolsMenu(logPlayerDockWidget, tr("MAVLink Log Replay"), SLOT(showToolWidget()), MENU_MAVLINK_LOG_PLAYER, Qt::RightDockWidgetArea);
    }

329
    // Center widgets
330 331 332 333 334
    if (!mapWidget)
    {
        mapWidget         = new MapWidget(this);
        addToCentralWidgetsMenu (mapWidget, "Maps", SLOT(showCentralWidget()),CENTRAL_MAP);
    }
335

336 337 338 339 340
    if (!protocolWidget)
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addToCentralWidgetsMenu (protocolWidget, "Mavlink Generator", SLOT(showCentralWidget()),CENTRAL_PROTOCOL);
    }
lm's avatar
lm committed
341

Alejandro's avatar
Alejandro committed
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    //TODO temporaly debug
    if (!slugsHilSimWidget)
    {
        slugsHilSimWidget = new QDockWidget(tr("Slugs Hil Sim"), this);
        slugsHilSimWidget->setWidget( new SlugsHilSim(this));
        addToToolsMenu (slugsHilSimWidget, tr("HIL Sim Configuration"), SLOT(showToolWidget()), MENU_SLUGS_HIL, Qt::LeftDockWidgetArea);
    }

    //TODO temporaly debug
    if (!slugsCamControlWidget)
    {
        slugsCamControlWidget = new QDockWidget(tr("Slugs Video Camera Control"), this);
        slugsCamControlWidget->setWidget(new SlugsVideoCamControl(this));
        addToToolsMenu (slugsCamControlWidget, tr("Camera Control"), SLOT(showToolWidget()), MENU_SLUGS_CAMERA, Qt::BottomDockWidgetArea);
    }
lm's avatar
lm committed
357 358 359 360 361
    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu (dataplotWidget, "Data Plot", SLOT(showCentralWidget()),CENTRAL_DATA_PLOT);
    }
362
}
363

364
void MainWindow::buildPxWidgets()
365
{
pixhawk's avatar
pixhawk committed
366 367
    //FIXME: memory of acceptList will never be freed again
    QStringList* acceptList = new QStringList();
lm's avatar
lm committed
368 369 370
    acceptList->append("-105,roll,deg,+105,s");
    acceptList->append("-105,pitch,deg,+105,s");
    acceptList->append("-105,yaw,deg,+105,s");
371

lm's avatar
lm committed
372 373 374
    acceptList->append("-260,rollspeed,deg/s,+260,s");
    acceptList->append("-260,pitchspeed,deg/s,+260,s");
    acceptList->append("-260,yawspeed,deg/s,+260,s");
375

pixhawk's avatar
pixhawk committed
376 377
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
lm's avatar
lm committed
378
    acceptList2->append("0,abs pressure,hPa,65500");
379 380
    acceptList2->append("-999,accel. X,raw,999,s");
    acceptList2->append("-999,accel. Y,raw,999,s");
381

382 383 384 385 386 387
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
        addToCentralWidgetsMenu(linechartWidget, "Line Plots", SLOT(showCentralWidget()), CENTRAL_LINECHART);
    }
388 389


390 391 392 393 394
    if (!hudWidget)
    {
        hudWidget         = new HUD(320, 240, this);
        addToCentralWidgetsMenu(hudWidget, "HUD", SLOT(showCentralWidget()), CENTRAL_HUD);
    }
395

396 397 398 399 400
    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu(dataplotWidget, "Data Plots", SLOT(showCentralWidget()), CENTRAL_DATA_PLOT);
    }
401

402
#ifdef QGC_OSG_ENABLED
403 404 405 406 407
    if (!_3DWidget)
    {
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
        addToCentralWidgetsMenu(_3DWidget, "Local 3D", SLOT(showCentralWidget()), CENTRAL_3D_LOCAL);
    }
408
#endif
409

410
#ifdef QGC_OSGEARTH_ENABLED
411 412 413 414 415
    if (!_3DMapWidget)
    {
        _3DMapWidget = Q3DWidgetFactory::get("MAP3D");
        addToCentralWidgetsMenu(_3DMapWidget, "OSG Earth 3D", SLOT(showCentralWidget()), CENTRAL_OSGEARTH);
    }
416
#endif
lm's avatar
lm committed
417

418
#if (defined _MSC_VER) | (defined Q_OS_MAC)
419 420 421 422 423
    if (!gEarthWidget)
    {
        gEarthWidget = new QGCGoogleEarthView(this);
        addToCentralWidgetsMenu(gEarthWidget, "Google Earth", SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
    }
424

425
#endif
426

pixhawk's avatar
pixhawk committed
427
    // Dock widgets
428

429 430 431 432
    if (!detectionDockWidget)
    {
        detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
        detectionDockWidget->setWidget( new ObjectDetectionView("images/patterns", this) );
pixhawk's avatar
pixhawk committed
433
        detectionDockWidget->setObjectName("OBJECT_DETECTION_DOCK_WIDGET");
434 435
        addToToolsMenu (detectionDockWidget, tr("Object Recognition"), SLOT(showToolWidget()), MENU_DETECTION, Qt::RightDockWidgetArea);
    }
436

437 438 439 440
    if (!parametersDockWidget)
    {
        parametersDockWidget = new QDockWidget(tr("Onboard Parameters"), this);
        parametersDockWidget->setWidget( new ParameterInterface(this) );
pixhawk's avatar
pixhawk committed
441
        parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET");
442 443
        addToToolsMenu (parametersDockWidget, tr("Onboard Parameters"), SLOT(showToolWidget()), MENU_PARAMETERS, Qt::RightDockWidgetArea);
    }
444

445 446 447 448
    if (!watchdogControlDockWidget)
    {
        watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
        watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
pixhawk's avatar
pixhawk committed
449
        watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
450 451
        addToToolsMenu (watchdogControlDockWidget, tr("Process Control"), SLOT(showToolWidget()), MENU_WATCHDOG, Qt::BottomDockWidgetArea);
    }
452

453 454 455 456
    if (!hsiDockWidget)
    {
        hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
        hsiDockWidget->setWidget( new HSIDisplay(this) );
457
        hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
458 459
        addToToolsMenu (hsiDockWidget, tr("HSI"), SLOT(showToolWidget()), MENU_HSI, Qt::BottomDockWidgetArea);
    }
460

461 462
    if (!headDown1DockWidget)
    {
463 464
        headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
        headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
465
        headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
466 467
        addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget()), MENU_HDD_1, Qt::RightDockWidgetArea);
    }
468

469 470 471
    if (!headDown2DockWidget)
    {
        headDown2DockWidget = new QDockWidget(tr("Payload Status"), this);
472
        headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Payload Status", this) );
473
        headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
474 475
        addToToolsMenu (headDown2DockWidget, tr("Payload Status"), SLOT(showToolWidget()), MENU_HDD_2, Qt::RightDockWidgetArea);
    }
476

477 478 479 480
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
481
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
482 483
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
484

485 486 487 488
    if (!headUpDockWidget)
    {
        headUpDockWidget = new QDockWidget(tr("HUD"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
489
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
490 491
        addToToolsMenu (headUpDockWidget, tr("Control Indicator"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
492

pixhawk's avatar
pixhawk committed
493 494
    // Dialogue widgets
    //FIXME: free memory in destructor
495 496 497 498
    if (!joystick)
    {
        joystick    = new JoystickInput();
    }
499

500 501 502 503
}

void MainWindow::buildSlugsWidgets()
{
504 505 506 507 508
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
    }
509

510 511 512 513 514
    if (!headUpDockWidget)
    {
        // Dock widgets
        headUpDockWidget = new QDockWidget(tr("Control Indicator"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
pixhawk's avatar
pixhawk committed
515
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
516 517
        addToToolsMenu (headUpDockWidget, tr("HUD"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
518

519 520 521 522
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
pixhawk's avatar
pixhawk committed
523
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
524 525
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
526

527 528 529 530 531
    if (!slugsDataWidget)
    {
        // Dialog widgets
        slugsDataWidget = new QDockWidget(tr("Slugs Data"), this);
        slugsDataWidget->setWidget( new SlugsDataSensorView(this));
pixhawk's avatar
pixhawk committed
532
        slugsDataWidget->setObjectName("SLUGS_DATA_DOCK_WIDGET");
533 534
        addToToolsMenu (slugsDataWidget, tr("Telemetry Data"), SLOT(showToolWidget()), MENU_SLUGS_DATA, Qt::RightDockWidgetArea);
    }
535

536 537 538 539
    if (!slugsPIDControlWidget)
    {
        slugsPIDControlWidget = new QDockWidget(tr("Slugs PID Control"), this);
        slugsPIDControlWidget->setWidget(new SlugsPIDControl(this));
pixhawk's avatar
pixhawk committed
540
        slugsPIDControlWidget->setObjectName("SLUGS_PID_CONTROL_DOCK_WIDGET");
541 542
        addToToolsMenu (slugsPIDControlWidget, tr("PID Configuration"), SLOT(showToolWidget()), MENU_SLUGS_PID, Qt::LeftDockWidgetArea);
    }
543

544 545 546 547
    if (!slugsHilSimWidget)
    {
        slugsHilSimWidget = new QDockWidget(tr("Slugs Hil Sim"), this);
        slugsHilSimWidget->setWidget( new SlugsHilSim(this));
pixhawk's avatar
pixhawk committed
548
        slugsHilSimWidget->setObjectName("SLUGS_HIL_SIM_DOCK_WIDGET");
549 550
        addToToolsMenu (slugsHilSimWidget, tr("HIL Sim Configuration"), SLOT(showToolWidget()), MENU_SLUGS_HIL, Qt::LeftDockWidgetArea);
    }
551

552 553 554 555
    if (!slugsCamControlWidget)
    {
        slugsCamControlWidget = new QDockWidget(tr("Slugs Video Camera Control"), this);
        slugsCamControlWidget->setWidget(new SlugsVideoCamControl(this));
pixhawk's avatar
pixhawk committed
556
        slugsCamControlWidget->setObjectName("SLUGS_CAM_CONTROL_DOCK_WIDGET");
557 558
        addToToolsMenu (slugsCamControlWidget, tr("Camera Control"), SLOT(showToolWidget()), MENU_SLUGS_CAMERA, Qt::BottomDockWidgetArea);
    }
559
}
560 561 562 563 564


void MainWindow::addToCentralWidgetsMenu ( QWidget* widget,
                                           const QString title,
                                           const char * slotName,
565 566
                                           TOOLS_WIDGET_NAMES centralWidget)
{
567
    QAction* tempAction;
568

569

570
    // Add the separator that will separate tools from central Widgets
571 572
    if (!toolsMenuActions[CENTRAL_SEPARATOR])
    {
573 574 575 576
        tempAction = ui.menuTools->addSeparator();
        toolsMenuActions[CENTRAL_SEPARATOR] = tempAction;
        tempAction->setData(CENTRAL_SEPARATOR);
    }
577

578
    tempAction = ui.menuTools->addAction(title);
579

580 581
    tempAction->setCheckable(true);
    tempAction->setData(centralWidget);
582

583 584 585
    // populate the Hashes
    toolsMenuActions[centralWidget] = tempAction;
    dockWidgets[centralWidget] = widget;
586

587
    QString chKey = buildMenuKey(SUB_SECTION_CHECKED, centralWidget, currentView);
588

589 590
    if (!settings.contains(chKey))
    {
591 592 593
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
    }
594 595 596 597
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
    }
598

599 600
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
601 602 603
}


lm's avatar
lm committed
604 605
void MainWindow::showCentralWidget()
{
606 607 608
    QAction* senderAction = qobject_cast<QAction *>(sender());
    int tool = senderAction->data().toInt();
    QString chKey;
609

610
    // check the current action
611

612 613
    if (senderAction && dockWidgets[tool])
    {
614

615 616
        // uncheck all central widget actions
        QHashIterator<int, QAction*> i(toolsMenuActions);
617 618
        while (i.hasNext())
        {
619
            i.next();
620 621 622
            //qDebug() << "shCW" << i.key() << "read";
            if (i.value() && i.value()->data().toInt() > 255)
            {
623 624 625 626 627 628 629
                i.value()->setChecked(false);

                // update the settings
                chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.value()->data().toInt()), currentView);
                settings.setValue(chKey,false);
            }
        }
630

631
        // check the current action
632
        //qDebug() << senderAction->text();
633
        senderAction->setChecked(true);
634

635 636
        // update the central widget
        centerStack->setCurrentWidget(dockWidgets[tool]);
637

638 639 640
        // store the selected central widget
        chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
        settings.setValue(chKey,true);
641

642 643
        presentView();
    }
644
}
645

lm's avatar
lm committed
646 647 648 649
/**
 * Adds a widget to the tools menu and sets it visible if it was
 * enabled last time.
 */
650
void MainWindow::addToToolsMenu ( QWidget* widget,
651 652 653 654
                                  const QString title,
                                  const char * slotName,
                                  TOOLS_WIDGET_NAMES tool,
                                  Qt::DockWidgetArea location)
lm's avatar
lm committed
655
{
656 657
    QAction* tempAction;
    QString posKey, chKey;
658

659

660 661
    if (toolsMenuActions[CENTRAL_SEPARATOR])
    {
662 663 664
        tempAction = new QAction(title, this);
        ui.menuTools->insertAction(toolsMenuActions[CENTRAL_SEPARATOR],
                                   tempAction);
665 666 667
    }
    else
    {
668 669
        tempAction = ui.menuTools->addAction(title);
    }
670

671 672
    tempAction->setCheckable(true);
    tempAction->setData(tool);
673

674 675 676
    // populate the Hashes
    toolsMenuActions[tool] = tempAction;
    dockWidgets[tool] = widget;
677
    //qDebug() << widget;
678

679
    posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
680

681 682
    if (!settings.contains(posKey))
    {
683 684
        settings.setValue(posKey,location);
        dockWidgetLocations[tool] = location;
685 686 687 688
    }
    else
    {
        dockWidgetLocations[tool] = static_cast <Qt::DockWidgetArea> (settings.value(posKey, Qt::RightDockWidgetArea).toInt());
689
    }
690

691
    chKey = buildMenuKey(SUB_SECTION_CHECKED,tool, currentView);
692

693 694 695 696
    if (!settings.contains(chKey))
    {
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
697
        widget->setVisible(false);
698 699 700 701
    }
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
702
        widget->setVisible(settings.value(chKey, false).toBool());
703
    }
704

705 706
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
707

708 709
//  connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
//          SIGNAL(visibilityChanged(bool)), this, SLOT(updateVisibilitySettings(bool)));
710

711 712
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(updateLocationSettings(Qt::DockWidgetArea)));
713 714 715

}

716 717 718 719
void MainWindow::showToolWidget()
{
    QAction* temp = qobject_cast<QAction *>(sender());
    int tool = temp->data().toInt();
720

721 722 723 724 725 726 727 728 729 730 731
    if (temp && dockWidgets[tool])
    {
        if (temp->isChecked())
        {
            addDockWidget(dockWidgetLocations[tool], qobject_cast<QDockWidget *> (dockWidgets[tool]));
            qobject_cast<QDockWidget *>(dockWidgets[tool])->show();
        }
        else
        {
            removeDockWidget(qobject_cast<QDockWidget *>(dockWidgets[tool]));
        }
732
    }
733

734 735 736
}


737 738 739 740 741
void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
{
    bool tempVisible;
    Qt::DockWidgetArea tempLocation;
    QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
742

743
    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,widget,view), false).toBool();
744

745 746 747 748
    if (tempWidget)
    {
        toolsMenuActions[widget]->setChecked(tempVisible);
    }
749 750


751
    //qDebug() <<  buildMenuKey (SUB_SECTION_CHECKED,widget,view) << tempVisible;
752

753 754
    tempLocation = static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,widget, view), QVariant(Qt::RightDockWidgetArea)).toInt());

755 756 757 758 759 760 761
    //    if (widget == MainWindow::MENU_UAS_LIST)
    //    {
    //        if (!settings.contains(buildMenuKey (SUB_SECTION_LOCATION,widget, view)))
    //        {
    //            tempLocation = Qt::RightDockWidgetArea;
    //        }
    //    }
762

763
    if ((tempWidget != NULL) && tempVisible)
764 765 766 767
    {
        addDockWidget(tempLocation, tempWidget);
        tempWidget->show();
    }
768

769
}
770

771 772 773 774 775 776 777 778 779 780 781 782 783 784
QString MainWindow::buildMenuKey(SETTINGS_SECTIONS section, TOOLS_WIDGET_NAMES tool, VIEW_SECTIONS view)
{
    // Key is built as follows: autopilot_type/section_menu/view/tool/section
    int apType;

    apType = (UASManager::instance() && UASManager::instance()->silentGetActiveUAS())?
             UASManager::instance()->getActiveUAS()->getAutopilotType():
             -1;

    return (QString::number(apType) + "/" +
            QString::number(SECTION_MENU) + "/" +
            QString::number(view) + "/" +
            QString::number(tool) + "/" +
            QString::number(section) + "/" );
785 786
}

787 788
void MainWindow::closeEvent(QCloseEvent *event)
{
789
    settings.setValue(getWindowGeometryKey(), saveGeometry());
790 791
    //settings.setValue("windowState", saveState());
    aboutToCloseFlag = true;
792 793 794 795 796 797
    // Save the last current view in any case
    settings.setValue("CURRENT_VIEW", currentView);
    // Save the current window state, but only if a system is connected (else no real number of widgets would be present)
    if (UASManager::instance()->getActiveUAS()) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
    // Save the current view only if a UAS is connected
    if (UASManager::instance()->getUASList().length() > 0) settings.setValue("CURRENT_VIEW_WITH_UAS_CONNECTED", currentView);
798 799 800
    settings.sync();
    QMainWindow::closeEvent(event);
}
801

802

803 804
void MainWindow::updateVisibilitySettings (bool vis)
{
805
    if (!aboutToCloseFlag && !changingViewsFlag)
806 807 808 809 810 811
    {
        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());

        if (temp)
        {
            QHashIterator<int, QWidget*> i(dockWidgets);
812
        while (i.hasNext()) {
813
                i.next();
814
          if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp) {
815 816
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,vis);
817 818 819 820 821 822
                    toolsMenuActions[i.key()]->setChecked(vis);
                    break;
                }
            }
        }
    }
823 824
}

825 826 827
void MainWindow::updateLocationSettings (Qt::DockWidgetArea location)
{
    QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
828

829 830 831 832 833 834 835 836 837 838 839
    QHashIterator<int, QWidget*> i(dockWidgets);
    while (i.hasNext())
    {
        i.next();
        if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp)
        {
            QString posKey = buildMenuKey (SUB_SECTION_LOCATION,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
            settings.setValue(posKey,location);
            break;
        }
    }
840 841
}

842 843 844
/**
 * Connect the signals and slots of the common window widgets
 */
845
void MainWindow::connectCommonWidgets()
846
{
pixhawk's avatar
pixhawk committed
847 848 849 850 851
    if (infoDockWidget && infoDockWidget->widget())
    {
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
852

pixhawk's avatar
pixhawk committed
853 854 855
    if (mapWidget && waypointsDockWidget->widget())
    {
        // clear path create on the map
856
        connect(waypointsDockWidget->widget(), SIGNAL(clearPathclicked()), mapWidget, SLOT(clearWaypoints()));
pixhawk's avatar
pixhawk committed
857 858
        // add Waypoint widget in the WaypointList widget when mouse clicked
        connect(mapWidget, SIGNAL(captureMapCoordinateClick(QPointF)), waypointsDockWidget->widget(), SLOT(addWaypointMouse(QPointF)));
859 860 861

        // it notifies that a waypoint global goes to do create and a map graphic too
        connect(waypointsDockWidget->widget(), SIGNAL(createWaypointAtMap(QPointF)), mapWidget, SLOT(createWaypointGraphAtMap(QPointF)));
862
    }
Alejandro's avatar
Alejandro committed
863 864 865 866 867 868

    //TODO temporaly debug
    if (slugsHilSimWidget && slugsHilSimWidget->widget()){
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
    }
869
}
870

871 872
void MainWindow::createCustomWidget()
{
873
    //qDebug() << "ADDING CUSTOM WIDGET";
lm's avatar
lm committed
874 875 876 877 878 879 880 881
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", this);

    if (QGCToolWidget::instances()->size() < 2)
    {
        // This is the first widget
        ui.menuTools->addSeparator();
    }

882
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
lm's avatar
lm committed
883
    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
884
    dock->setWidget(tool);
lm's avatar
lm committed
885 886 887 888 889 890
    QAction* showAction = new QAction("Show Unnamed Tool", this);
    connect(dock, SIGNAL(visibilityChanged(bool)), showAction, SLOT(setChecked(bool)));
    connect(showAction, SIGNAL(triggered(bool)), dock, SLOT(setVisible(bool)));
    tool->setMainMenuAction(showAction);
    ui.menuTools->addAction(showAction);
    this->addDockWidget(Qt::BottomDockWidgetArea, dock);
891
    dock->setVisible(true);
892 893 894 895
}

void MainWindow::connectPxWidgets()
{
896
    // No special connections necessary at this point
897 898 899 900
}

void MainWindow::connectSlugsWidgets()
{
901
    if (slugsHilSimWidget && slugsHilSimWidget->widget()){
902 903
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
904 905 906
    }

    if (slugsDataWidget && slugsDataWidget->widget()){
907 908
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsDataWidget->widget(), SLOT(setActiveUAS(UASInterface*)));
909 910
    }

911

912 913
}

914
void MainWindow::arrangeCommonCenterStack()
915
{
916
    centerStack = new QStackedWidget(this);
917
    centerStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
918

pixhawk's avatar
pixhawk committed
919
    if (!centerStack) return;
920

921
    if (mapWidget && (centerStack->indexOf(mapWidget) == -1)) centerStack->addWidget(mapWidget);
lm's avatar
lm committed
922
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
923
    if (protocolWidget && (centerStack->indexOf(protocolWidget) == -1)) centerStack->addWidget(protocolWidget);
924 925 926 927 928 929 930

    setCentralWidget(centerStack);
}

void MainWindow::arrangePxCenterStack()
{

931 932 933 934
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
935

936 937

    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
938

939
#ifdef QGC_OSG_ENABLED
940
    if (_3DWidget && (centerStack->indexOf(_3DWidget) == -1)) centerStack->addWidget(_3DWidget);
941
#endif
942
#ifdef QGC_OSGEARTH_ENABLED
943
    if (_3DMapWidget && (centerStack->indexOf(_3DMapWidget) == -1)) centerStack->addWidget(_3DMapWidget);
944
#endif
945
#if (defined _MSC_VER) | (defined Q_OS_MAC)
946
    if (gEarthWidget && (centerStack->indexOf(gEarthWidget) == -1)) centerStack->addWidget(gEarthWidget);
947
#endif
948 949
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
950 951 952 953 954
}

void MainWindow::arrangeSlugsCenterStack()
{

955 956 957 958
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
959

960 961
    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
962

963 964
}

965 966
void MainWindow::configureWindowName()
{
pixhawk's avatar
pixhawk committed
967 968 969
    QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
    QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
    bool prevAddr = false;
970

pixhawk's avatar
pixhawk committed
971
    windowname.append(" (" + QHostInfo::localHostName() + ": ");
972

pixhawk's avatar
pixhawk committed
973 974 975 976 977 978 979 980 981 982
    for (int i = 0; i < hostAddresses.size(); i++)
    {
        // Exclude loopback IPv4 and all IPv6 addresses
        if (hostAddresses.at(i) != QHostAddress("127.0.0.1") && !hostAddresses.at(i).toString().contains(":"))
        {
            if(prevAddr) windowname.append("/");
            windowname.append(hostAddresses.at(i).toString());
            prevAddr = true;
        }
    }
983

pixhawk's avatar
pixhawk committed
984
    windowname.append(")");
985

pixhawk's avatar
pixhawk committed
986
    setWindowTitle(windowname);
987 988

#ifndef Q_WS_MAC
pixhawk's avatar
pixhawk committed
989
    //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
990 991 992
#endif
}

pixhawk's avatar
pixhawk committed
993
void MainWindow::startVideoCapture()
pixhawk's avatar
pixhawk committed
994 995 996 997 998 999 1000 1001 1002 1003 1004
{
    QString format = "bmp";
    QString initialPath = QDir::currentPath() + tr("/untitled.") + format;

    QString screenFileName = QFileDialog::getSaveFileName(this, tr("Save As"),
                                                          initialPath,
                                                          tr("%1 Files (*.%2);;All Files (*)")
                                                          .arg(format.toUpper())
                                                          .arg(format));
    delete videoTimer;
    videoTimer = new QTimer(this);
1005 1006 1007
    //videoTimer->setInterval(40);
    //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
    //videoTimer->stop();
pixhawk's avatar
pixhawk committed
1008 1009
}

pixhawk's avatar
pixhawk committed
1010
void MainWindow::stopVideoCapture()
pixhawk's avatar
pixhawk committed
1011 1012 1013 1014 1015 1016
{
    videoTimer->stop();

    // TODO Convert raw images to PNG
}

pixhawk's avatar
pixhawk committed
1017
void MainWindow::saveScreen()
pixhawk's avatar
pixhawk committed
1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
{
    QPixmap window = QPixmap::grabWindow(this->winId());
    QString format = "bmp";

    if (!screenFileName.isEmpty())
    {
        window.save(screenFileName, format.toAscii());
    }
}

1028 1029 1030 1031 1032 1033
/**
 * Reload the style sheet from disk. The function tries to load "qgroundcontrol.css" from the application
 * directory (which by default does not exist). If it fails, it will load the bundled default CSS
 * from memory.
 * To customize the application, just create a qgroundcontrol.css file in the application directory
 */
pixhawk's avatar
pixhawk committed
1034
void MainWindow::reloadStylesheet()
pixhawk's avatar
pixhawk committed
1035
{
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
    QString fileName = QCoreApplication::applicationDirPath() + "/style-indoor.css";

    // Let user select style sheet
    fileName = QFileDialog::getOpenFileName(this, tr("Specify stylesheet"), fileName, tr("CSS Stylesheet (*.css);;"));

    if (!fileName.endsWith(".css"))
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(tr("QGroundControl did lot load a new style"));
        msgBox.setInformativeText(tr("No suitable .css file selected. Please select a valid .css file."));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
        return;
    }

pixhawk's avatar
pixhawk committed
1053
    // Load style sheet
1054
    QFile* styleSheet = new QFile(fileName);
1055 1056 1057 1058
    if (!styleSheet->exists())
    {
        styleSheet = new QFile(":/images/style-mission.css");
    }
1059 1060
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
    {
1061 1062
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
pixhawk's avatar
pixhawk committed
1063
        qApp->setStyleSheet(style);
1064 1065 1066
    }
    else
    {
1067 1068 1069 1070 1071 1072 1073
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Information);
        msgBox.setText(tr("QGroundControl did lot load a new style"));
        msgBox.setInformativeText(tr("Stylesheet file %1 was not readable").arg(fileName));
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
pixhawk's avatar
pixhawk committed
1074
    }
1075
    delete styleSheet;
pixhawk's avatar
pixhawk committed
1076 1077
}

1078 1079 1080 1081 1082 1083
/**
 * The status message will be overwritten if a new message is posted to this function
 *
 * @param status message text
 * @param timeout how long the status should be displayed
 */
pixhawk's avatar
pixhawk committed
1084
void MainWindow::showStatusMessage(const QString& status, int timeout)
pixhawk's avatar
pixhawk committed
1085
{
lm's avatar
lm committed
1086
    statusBar()->showMessage(status, timeout);
pixhawk's avatar
pixhawk committed
1087 1088
}

1089 1090 1091 1092 1093 1094
/**
 * The status message will be overwritten if a new message is posted to this function.
 * it will be automatically hidden after 5 seconds.
 *
 * @param status message text
 */
1095
void MainWindow::showStatusMessage(const QString& status)
pixhawk's avatar
pixhawk committed
1096
{
lm's avatar
lm committed
1097
    statusBar()->showMessage(status, 20000);
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
}

void MainWindow::showCriticalMessage(const QString& title, const QString& message)
{
    QMessageBox msgBox(MainWindow::instance());
    msgBox.setIcon(QMessageBox::Critical);
    msgBox.setText(title);
    msgBox.setInformativeText(message);
    msgBox.setStandardButtons(QMessageBox::Ok);
    msgBox.setDefaultButton(QMessageBox::Ok);
    msgBox.exec();
pixhawk's avatar
pixhawk committed
1109 1110
}

lm's avatar
lm committed
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
void MainWindow::showInfoMessage(const QString& title, const QString& message)
{
    QMessageBox msgBox(MainWindow::instance());
    msgBox.setIcon(QMessageBox::Information);
    msgBox.setText(title);
    msgBox.setInformativeText(message);
    msgBox.setStandardButtons(QMessageBox::Ok);
    msgBox.setDefaultButton(QMessageBox::Ok);
    msgBox.exec();
}

pixhawk's avatar
pixhawk committed
1122 1123 1124 1125
/**
* @brief Create all actions associated to the main window
*
**/
1126
void MainWindow::connectCommonActions()
pixhawk's avatar
pixhawk committed
1127 1128 1129 1130 1131 1132
{
    // Connect actions from ui
    connect(ui.actionAdd_Link, SIGNAL(triggered()), this, SLOT(addLink()));

    // Connect internal actions
    connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(UASCreated(UASInterface*)));
1133
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
pixhawk's avatar
pixhawk committed
1134

1135
    // Unmanned System controls
pixhawk's avatar
pixhawk committed
1136 1137 1138 1139 1140 1141 1142
    connect(ui.actionLiftoff, SIGNAL(triggered()), UASManager::instance(), SLOT(launchActiveUAS()));
    connect(ui.actionLand, SIGNAL(triggered()), UASManager::instance(), SLOT(returnActiveUAS()));
    connect(ui.actionEmergency_Land, SIGNAL(triggered()), UASManager::instance(), SLOT(stopActiveUAS()));
    connect(ui.actionEmergency_Kill, SIGNAL(triggered()), UASManager::instance(), SLOT(killActiveUAS()));

    connect(ui.actionConfiguration, SIGNAL(triggered()), UASManager::instance(), SLOT(configureActiveUAS()));

1143
    // Views actions
1144
    connect(ui.actionPilotsView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
1145
    connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
1146
    connect(ui.actionOperatorsView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
1147

1148 1149
    connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
    connect(ui.actionReloadStyle, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
1150

1151
    // Help Actions
1152
    connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
1153
    connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
1154
    connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
1155 1156 1157 1158
}

void MainWindow::connectPxActions()
{
1159
    ui.actionJoystickSettings->setVisible(true);
1160

1161 1162
    // Joystick configuration
    connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
1163 1164 1165 1166 1167

}

void MainWindow::connectSlugsActions()
{
1168

pixhawk's avatar
pixhawk committed
1169 1170
}

1171 1172
void MainWindow::showHelp()
{
1173
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/")))
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not open help in browser");
        msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/user_guide in a browser.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
}

void MainWindow::showCredits()
{
1187
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits/")))
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not open credits in browser");
        msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/credits in a browser.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
}

void MainWindow::showRoadMap()
{
1201
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/roadmap/")))
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Critical);
        msgBox.setText("Could not open roadmap in browser");
        msgBox.setInformativeText("To get to the online help, please open http://qgroundcontrol.org/roadmap in a browser.");
        msgBox.setStandardButtons(QMessageBox::Ok);
        msgBox.setDefaultButton(QMessageBox::Ok);
        msgBox.exec();
    }
}

pixhawk's avatar
pixhawk committed
1213
void MainWindow::configure()
pixhawk's avatar
pixhawk committed
1214 1215 1216 1217
{
    joystickWidget = new JoystickWidget(joystick, this);
}

pixhawk's avatar
pixhawk committed
1218
void MainWindow::addLink()
pixhawk's avatar
pixhawk committed
1219 1220 1221 1222
{
    SerialLink* link = new SerialLink();
    // TODO This should be only done in the dialog itself

1223
    LinkManager::instance()->add(link);
pixhawk's avatar
pixhawk committed
1224 1225
    LinkManager::instance()->addProtocol(link, mavlink);

1226 1227
    // Go fishing for this link's configuration window
    QList<QAction*> actions = ui.menuNetwork->actions();
pixhawk's avatar
pixhawk committed
1228

1229 1230 1231 1232 1233 1234 1235 1236
    foreach (QAction* act, actions)
    {
        if (act->data().toInt() == LinkManager::instance()->getLinks().indexOf(link))
        {
            act->trigger();
            break;
        }
    }
pixhawk's avatar
pixhawk committed
1237 1238
}

pixhawk's avatar
pixhawk committed
1239 1240
void MainWindow::addLink(LinkInterface *link)
{
1241
    LinkManager::instance()->add(link);
1242
    LinkManager::instance()->addProtocol(link, mavlink);
1243

pixhawk's avatar
pixhawk committed
1244 1245 1246
    CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);
    ui.menuNetwork->addAction(commWidget->getAction());

1247 1248
    //qDebug() << "ADDING LINK:" << link->getName() << "ACTION IS: " << commWidget->getAction();

pixhawk's avatar
pixhawk committed
1249 1250 1251 1252
    // Special case for simulationlink
    MAVLinkSimulationLink* sim = dynamic_cast<MAVLinkSimulationLink*>(link);
    if (sim)
    {
1253
        //connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64)));
pixhawk's avatar
pixhawk committed
1254 1255 1256 1257
        connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool)));
    }
}

1258 1259 1260 1261 1262 1263 1264
void MainWindow::setActiveUAS(UASInterface* uas)
{
    // Enable and rename menu
    ui.menuUnmanned_System->setTitle(uas->getUASName());
    if (!ui.menuUnmanned_System->isEnabled()) ui.menuUnmanned_System->setEnabled(true);
}

pixhawk's avatar
pixhawk committed
1265
void MainWindow::UASCreated(UASInterface* uas)
pixhawk's avatar
pixhawk committed
1266
{
1267

pixhawk's avatar
pixhawk committed
1268 1269
    // Connect the UAS to the full user interface

1270 1271
    if (uas != NULL)
    {
1272 1273 1274
        // The pilot view was not available on startup, enable it now
        ui.actionPilotsView->setEnabled(true);

1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304
        QIcon icon;
        // Set matching icon
        switch (uas->getSystemType())
        {
        case 0:
            icon = QIcon(":/images/mavs/generic.svg");
            break;
        case 1:
            icon = QIcon(":/images/mavs/fixed-wing.svg");
            break;
        case 2:
            icon = QIcon(":/images/mavs/quadrotor.svg");
            break;
        case 3:
            icon = QIcon(":/images/mavs/coaxial.svg");
            break;
        case 4:
            icon = QIcon(":/images/mavs/helicopter.svg");
            break;
        case 5:
            icon = QIcon(":/images/mavs/groundstation.svg");
            break;
        default:
            icon = QIcon(":/images/mavs/unknown.svg");
            break;
        }

        ui.menuConnected_Systems->addAction(icon, tr("Select %1 for control").arg(uas->getUASName()), uas, SLOT(setSelected()));

        // FIXME Should be not inside the mainwindow
1305 1306
        if (debugConsoleDockWidget)
        {
pixhawk's avatar
pixhawk committed
1307 1308 1309 1310 1311 1312
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
            if (debugConsole)
            {
                connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)),
                        debugConsole, SLOT(receiveTextMessage(int,int,int,QString)));
            }
1313
        }
1314 1315

        // Health / System status indicator
1316 1317
        if (infoDockWidget)
        {
pixhawk's avatar
pixhawk committed
1318 1319 1320 1321 1322
            UASInfoWidget *infoWidget = dynamic_cast<UASInfoWidget*>(infoDockWidget->widget());
            if (infoWidget)
            {
                infoWidget->addUAS(uas);
            }
1323
        }
1324 1325

        // UAS List
1326 1327
        if (listDockWidget)
        {
pixhawk's avatar
pixhawk committed
1328 1329 1330 1331 1332
            UASListWidget *listWidget = dynamic_cast<UASListWidget*>(listDockWidget->widget());
            if (listWidget)
            {
                listWidget->addUAS(uas);
            }
1333
        }
1334

1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383
        switch (uas->getAutopilotType())
        {
        case (MAV_AUTOPILOT_SLUGS):
            {
                // Build Slugs Widgets
                buildSlugsWidgets();

                // Connect Slugs Widgets
                connectSlugsWidgets();

                // Arrange Slugs Centerstack
                arrangeSlugsCenterStack();

                // Connect Slugs Actions
                connectSlugsActions();

                // FIXME: This type checking might be redundant
                //            if (slugsDataWidget) {
                //              SlugsDataSensorView* dataWidget = dynamic_cast<SlugsDataSensorView*>(slugsDataWidget->widget());
                //              if (dataWidget) {
                //                SlugsMAV* mav2 = dynamic_cast<SlugsMAV*>(uas);
                //                if (mav2) {
                (dynamic_cast<SlugsDataSensorView*>(slugsDataWidget->widget()))->addUAS(uas);
                //                  //loadSlugsView();
                //                  loadGlobalOperatorView();
                //                }
                //              }
                //            }
            }
            break;
        default:
        case (MAV_AUTOPILOT_GENERIC):
        case (MAV_AUTOPILOT_ARDUPILOTMEGA):
        case (MAV_AUTOPILOT_PIXHAWK):
            {
                // Build Pixhawk Widgets
                buildPxWidgets();

                // Connect Pixhawk Widgets
                connectPxWidgets();

                // Arrange Pixhawk Centerstack
                arrangePxCenterStack();

                // Connect Pixhawk Actions
                connectPxActions();
            }
            break;

1384
        loadOperatorView();
1385 1386 1387 1388 1389 1390 1391 1392
        }

        // Change the view only if this is the first UAS

        // If this is the first connected UAS, it is both created as well as
        // the currently active UAS
        if (UASManager::instance()->getActiveUAS() == uas)
        {
1393
            //qDebug() << "UPDATING THE VIEW SINCE THIS IS THE FIRST CONNECTED SYSTEM";
1394 1395

            // Load last view if setting is present
1396
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
1397
            {
1398
                int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
1399 1400
                currentView = (VIEW_SECTIONS) view;
                presentView();
1401 1402 1403 1404 1405

                // Restore the widget positions and size
                if (settings.contains(getWindowStateKey()))
                {
                    restoreState(settings.value(getWindowStateKey()).toByteArray(), QGC::applicationVersion());
1406
            }
1407

1408 1409 1410 1411 1412
            }
            else
            {
                loadEngineerView();
            }
1413
        }
1414

1415
    }
1416 1417

    if (!ui.menuConnected_Systems->isEnabled()) ui.menuConnected_Systems->setEnabled(true);
lm's avatar
lm committed
1418 1419 1420

    // Custom widgets, added last to all menus and layouts
    buildCustomWidget();
pixhawk's avatar
pixhawk committed
1421 1422
}

1423 1424 1425
/**
 * Clears the current view completely
 */
pixhawk's avatar
pixhawk committed
1426
void MainWindow::clearView()
1427
{
1428 1429 1430
    // Save current state
    if (UASManager::instance()->getActiveUAS()) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
    settings.setValue(getWindowGeometryKey(), saveGeometry());
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441

    QAction* temp;

    // Set tool widget visibility settings for this view
    foreach (int key, toolsMenuActions.keys())
    {
        temp = toolsMenuActions[key];
        QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(key), currentView);

        if (temp)
        {
1442
            //qDebug() << "TOOL:" << chKey << "IS:" << temp->isChecked();
1443 1444 1445 1446
            settings.setValue(chKey,temp->isChecked());
        }
        else
        {
1447
            //qDebug() << "TOOL:" << chKey << "IS DEFAULT AND UNCHECKED";
1448 1449 1450 1451
            settings.setValue(chKey,false);
        }
    }

1452
    changingViewsFlag = true;
1453 1454
    // Remove all dock widgets from main window
    QObjectList childList( this->children() );
pixhawk's avatar
pixhawk committed
1455

1456 1457 1458
    QObjectList::iterator i;
    QDockWidget* dockWidget;
    for (i = childList.begin(); i != childList.end(); ++i)
pixhawk's avatar
pixhawk committed
1459
    {
1460 1461
        dockWidget = dynamic_cast<QDockWidget*>(*i);
        if (dockWidget)
pixhawk's avatar
pixhawk committed
1462
        {
1463
            // Remove dock widget from main window
1464 1465
            //this->removeDockWidget(dockWidget);
            dockWidget->setVisible(false);
1466 1467 1468
            // Deletion of dockWidget would also delete all child
            // widgets of dockWidget
            // Is there a way to unset a widget from QDockWidget?
pixhawk's avatar
pixhawk committed
1469 1470
        }
    }
1471
    changingViewsFlag = false;
pixhawk's avatar
pixhawk committed
1472 1473
}

1474
void MainWindow::loadEngineerView()
lm's avatar
lm committed
1475
{
1476 1477
    if (currentView != VIEW_ENGINEER)
    {
1478
    clearView();
lm's avatar
lm committed
1479

1480
    currentView = VIEW_ENGINEER;
lm's avatar
lm committed
1481

1482
    presentView();
1483
    }
lm's avatar
lm committed
1484 1485
}

1486
void MainWindow::loadOperatorView()
lm's avatar
lm committed
1487
{
1488 1489
    if (currentView != VIEW_OPERATOR)
    {
1490 1491 1492
    clearView();

    currentView = VIEW_OPERATOR;
lm's avatar
lm committed
1493

1494
    presentView();
1495
    }
lm's avatar
lm committed
1496 1497
}

1498
void MainWindow::loadPilotView()
1499
{
1500 1501
    if (currentView != VIEW_PILOT)
    {
1502
    clearView();
1503

1504 1505 1506
    currentView = VIEW_PILOT;

    presentView();
1507
    }
1508 1509
}

1510
void MainWindow::loadMAVLinkView()
1511
{
1512 1513
    if (currentView != VIEW_MAVLINK)
    {
1514
    clearView();
pixhawk's avatar
pixhawk committed
1515

1516 1517 1518
    currentView = VIEW_MAVLINK;

    presentView();
1519
    }
1520 1521
}

lm's avatar
lm committed
1522 1523
void MainWindow::presentView()
{
1524
    // LINE CHART
1525
    showTheCentralWidget(CENTRAL_LINECHART, currentView);
1526

1527 1528
    // MAP
    showTheCentralWidget(CENTRAL_MAP, currentView);
pixhawk's avatar
pixhawk committed
1529

1530 1531
    // PROTOCOL
    showTheCentralWidget(CENTRAL_PROTOCOL, currentView);
pixhawk's avatar
pixhawk committed
1532

1533 1534
    // HEAD UP DISPLAY
    showTheCentralWidget(CENTRAL_HUD, currentView);
pixhawk's avatar
pixhawk committed
1535 1536 1537 1538 1539 1540 1541 1542 1543 1544

    // GOOGLE EARTH
    showTheCentralWidget(CENTRAL_GOOGLE_EARTH, currentView);

    // LOCAL 3D VIEW
    showTheCentralWidget(CENTRAL_3D_LOCAL, currentView);

    // GLOBAL 3D VIEW
    showTheCentralWidget(CENTRAL_3D_MAP, currentView);

1545 1546 1547
    // DATA PLOT
    showTheCentralWidget(CENTRAL_DATA_PLOT, currentView);

pixhawk's avatar
pixhawk committed
1548

pixhawk's avatar
pixhawk committed
1549

1550
    // Show docked widgets based on current view and autopilot type
1551

1552 1553
    // UAS CONTROL
    showTheWidget(MENU_UAS_CONTROL, currentView);
1554

1555 1556
    // UAS LIST
    showTheWidget(MENU_UAS_LIST, currentView);
1557

1558 1559
    // WAYPOINT LIST
    showTheWidget(MENU_WAYPOINTS, currentView);
pixhawk's avatar
pixhawk committed
1560

1561 1562
    // UAS STATUS
    showTheWidget(MENU_STATUS, currentView);
1563

1564 1565
    // DETECTION
    showTheWidget(MENU_DETECTION, currentView);
1566

1567 1568
    // DEBUG CONSOLE
    showTheWidget(MENU_DEBUG_CONSOLE, currentView);
1569

1570 1571
    // ONBOARD PARAMETERS
    showTheWidget(MENU_PARAMETERS, currentView);
1572

1573 1574
    // WATCHDOG
    showTheWidget(MENU_WATCHDOG, currentView);
1575

1576 1577 1578 1579 1580
    // HUD
    showTheWidget(MENU_HUD, currentView);
    if (headUpDockWidget)
    {
        HUD* tmpHud = dynamic_cast<HUD*>( headUpDockWidget->widget() );
1581 1582 1583 1584
        if (tmpHud)
        {
            if (settings.value(buildMenuKey (SUB_SECTION_CHECKED,MENU_HUD,currentView)).toBool())
            {
1585
                addDockWidget(static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,MENU_HUD, currentView)).toInt()),
1586
                        headUpDockWidget);
1587
                headUpDockWidget->show();
1588 1589 1590
            }
            else
            {
1591 1592
                headUpDockWidget->hide();
            }
1593
        }
1594
    }
1595

1596

1597 1598
    // RC View
    showTheWidget(MENU_RC_VIEW, currentView);
1599

1600 1601
    // SLUGS DATA
    showTheWidget(MENU_SLUGS_DATA, currentView);
1602

1603 1604
    // SLUGS PID
    showTheWidget(MENU_SLUGS_PID, currentView);
1605

1606 1607
    // SLUGS HIL
    showTheWidget(MENU_SLUGS_HIL, currentView);
1608

1609 1610
    // SLUGS CAMERA
    showTheWidget(MENU_SLUGS_CAMERA, currentView);
1611

1612 1613
    // HORIZONTAL SITUATION INDICATOR
    showTheWidget(MENU_HSI, currentView);
1614

1615 1616 1617 1618 1619
    // HEAD DOWN 1
    showTheWidget(MENU_HDD_1, currentView);

    // HEAD DOWN 2
    showTheWidget(MENU_HDD_2, currentView);
1620

1621 1622 1623
    // MAVLINK LOG PLAYER
    showTheWidget(MENU_MAVLINK_LOG_PLAYER, currentView);

1624
    this->show();
1625

1626
}
1627

1628 1629 1630 1631
void MainWindow::showTheCentralWidget (TOOLS_WIDGET_NAMES centralWidget, VIEW_SECTIONS view)
{
    bool tempVisible;
    QWidget* tempWidget = dockWidgets[centralWidget];
1632

1633
    tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view), false).toBool();
1634
    //qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
1635
    if (toolsMenuActions[centralWidget])
1636
    {
1637
        toolsMenuActions[centralWidget]->setChecked(tempVisible);
1638
    }
1639

1640
    if (centerStack && tempWidget && tempVisible)
1641
    {
1642
        centerStack->setCurrentWidget(tempWidget);
1643
    }
1644 1645
}

1646 1647
void MainWindow::loadDataView(QString fileName)
{
1648
    clearView();
1649 1650 1651 1652 1653

    // Unload line chart
    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(CENTRAL_LINECHART), currentView);
    settings.setValue(chKey,false);

1654
    // Set data plot in settings as current widget and then run usual update procedure
1655
    chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(CENTRAL_DATA_PLOT), currentView);
1656
    settings.setValue(chKey,true);
1657

1658
    presentView();
1659

1660 1661
    // Plot is now selected, now load data from file
    if (dataplotWidget)
1662
    {
1663
        dataplotWidget->loadFile(fileName);
1664
        }
1665 1666 1667 1668 1669 1670 1671
//        QStackedWidget *centerStack = dynamic_cast<QStackedWidget*>(centralWidget());
//        if (centerStack)
//        {
//            centerStack->setCurrentWidget(dataplotWidget);
//            dataplotWidget->loadFile(fileName);
//        }
//    }
1672 1673 1674
}