MainWindow.cc 47.7 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

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

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

pixhawk's avatar
pixhawk committed
39 40 41

#include "LogCompressor.h"

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

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

pixhawk's avatar
pixhawk committed
56 57 58 59 60 61 62
/**
* 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()
**/
63
MainWindow::MainWindow(QWidget *parent):
pixhawk's avatar
pixhawk committed
64
        QMainWindow(parent),
65
        toolsMenuActions(),
66
        currentView(VIEW_ENGINEER),
67
        aboutToCloseFlag(false),
pixhawk's avatar
pixhawk committed
68
        settings()
pixhawk's avatar
pixhawk committed
69
{
70 71
    // Get current settings
    settings.sync();
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
    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
    {
        currentView = (VIEW_SECTIONS) settings.value("CURRENT_VIEW", currentView).toInt();
    }

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

    // 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);
115 116 117
    if (!settings.contains(centralKey))
    {
        settings.setValue(centralKey,true);
118 119 120 121 122
    }

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

126 127
    settings.sync();

pixhawk's avatar
pixhawk committed
128 129 130
    // Setup user interface
    ui.setupUi(this);

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
    // 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);


149
    buildCommonWidgets();
150

151
    connectCommonWidgets();
152

153
    arrangeCommonCenterStack();
154 155

    configureWindowName();
pixhawk's avatar
pixhawk committed
156 157

    // Add status bar
158
    //setStatusBar(createStatusBar());
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
    // Add option for custom widgets
    connect(ui.actionNewCustomWidget, SIGNAL(triggered()), this, SLOT(createCustomWidget()));
177 178 179
    // Allow to mute audio
    ui.actionMuteAudioOutput->setChecked(GAudioOutput::instance()->isMuted());
    connect(ui.actionMuteAudioOutput, SIGNAL(triggered(bool)), GAudioOutput::instance(), SLOT(mute(bool)));
180

181 182 183
    // Set dock options
    setDockOptions(AnimatedDocks | AllowTabbedDocks | AllowNestedDocks);

184
    // Load mavlink view as default widget set
185
    //loadMAVLinkView();
186

lm's avatar
lm committed
187 188
    statusBar()->setSizeGripEnabled(true);

189 190
    // Restore the window position and size
    if (settings.contains(getWindowGeometryKey()))
191 192
    {
        // Restore the window geometry
193
        restoreGeometry(settings.value(getWindowGeometryKey()).toByteArray());
194 195 196 197 198 199
    }
    else
    {
        // Adjust the size
        adjustSize();
    }
pixhawk's avatar
pixhawk committed
200

201 202 203 204 205 206
    // Populate link menu
    QList<LinkInterface*> links = LinkManager::instance()->getLinks();
    foreach(LinkInterface* link, links)
    {
        this->addLink(link);
    }
207

lm's avatar
lm committed
208 209
    // Enable and update view
    presentView();
pixhawk's avatar
pixhawk committed
210 211
}

pixhawk's avatar
pixhawk committed
212
MainWindow::~MainWindow()
pixhawk's avatar
pixhawk committed
213
{
lm's avatar
lm committed
214

pixhawk's avatar
pixhawk committed
215 216
}

217 218 219 220 221 222 223 224 225 226
QString MainWindow::getWindowStateKey()
{
    return QString::number(currentView)+"/windowstate";
}

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

227 228 229 230
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
231
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
232 233

    // Dock widgets
234 235 236 237 238 239
    if (!controlDockWidget)
    {
        controlDockWidget = new QDockWidget(tr("Control"), this);
        controlDockWidget->setWidget( new UASControlWidget(this) );
        addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget()), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
    }
240

241 242 243 244 245 246
    if (!listDockWidget)
    {
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
        addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget()), MENU_UAS_LIST, Qt::RightDockWidgetArea);
    }
247

248 249 250 251 252 253
    if (!waypointsDockWidget)
    {
        waypointsDockWidget = new QDockWidget(tr("Waypoint List"), this);
        waypointsDockWidget->setWidget( new WaypointList(this, NULL) );
        addToToolsMenu (waypointsDockWidget, tr("Waypoints List"), SLOT(showToolWidget()), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
    }
254

255 256 257 258 259 260
    if (!infoDockWidget)
    {
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
        addToToolsMenu (infoDockWidget, tr("Status Details"), SLOT(showToolWidget()), MENU_STATUS, Qt::RightDockWidgetArea);
    }
261

262 263 264 265 266 267
    if (!debugConsoleDockWidget)
    {
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
        addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget()), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
    }
268

269
    // Center widgets
270 271 272 273 274
    if (!mapWidget)
    {
        mapWidget         = new MapWidget(this);
        addToCentralWidgetsMenu (mapWidget, "Maps", SLOT(showCentralWidget()),CENTRAL_MAP);
    }
275

276 277 278 279 280
    if (!protocolWidget)
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addToCentralWidgetsMenu (protocolWidget, "Mavlink Generator", SLOT(showCentralWidget()),CENTRAL_PROTOCOL);
    }
lm's avatar
lm committed
281 282 283 284 285 286

    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu (dataplotWidget, "Data Plot", SLOT(showCentralWidget()),CENTRAL_DATA_PLOT);
    }
287
}
288

289
void MainWindow::buildPxWidgets()
290
{
pixhawk's avatar
pixhawk committed
291 292
    //FIXME: memory of acceptList will never be freed again
    QStringList* acceptList = new QStringList();
lm's avatar
lm committed
293 294 295
    acceptList->append("-105,roll,deg,+105,s");
    acceptList->append("-105,pitch,deg,+105,s");
    acceptList->append("-105,yaw,deg,+105,s");
296

lm's avatar
lm committed
297 298 299
    acceptList->append("-260,rollspeed,deg/s,+260,s");
    acceptList->append("-260,pitchspeed,deg/s,+260,s");
    acceptList->append("-260,yawspeed,deg/s,+260,s");
300

pixhawk's avatar
pixhawk committed
301 302
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
lm's avatar
lm committed
303 304 305
    acceptList2->append("0,abs pressure,hPa,65500");
    acceptList2->append("-2000,accel. X,raw,2000,s");
    acceptList2->append("-2000,accel. Y,raw,2000,s");
306

307 308 309 310 311 312
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
        addToCentralWidgetsMenu(linechartWidget, "Line Plots", SLOT(showCentralWidget()), CENTRAL_LINECHART);
    }
313 314


315 316 317 318 319
    if (!hudWidget)
    {
        hudWidget         = new HUD(320, 240, this);
        addToCentralWidgetsMenu(hudWidget, "HUD", SLOT(showCentralWidget()), CENTRAL_HUD);
    }
320

321 322 323 324 325
    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu(dataplotWidget, "Data Plots", SLOT(showCentralWidget()), CENTRAL_DATA_PLOT);
    }
326

327
#ifdef QGC_OSG_ENABLED
328 329 330 331 332
    if (!_3DWidget)
    {
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
        addToCentralWidgetsMenu(_3DWidget, "Local 3D", SLOT(showCentralWidget()), CENTRAL_3D_LOCAL);
    }
333
#endif
334

335
#ifdef QGC_OSGEARTH_ENABLED
336 337 338 339 340
    if (!_3DMapWidget)
    {
        _3DMapWidget = Q3DWidgetFactory::get("MAP3D");
        addToCentralWidgetsMenu(_3DMapWidget, "OSG Earth 3D", SLOT(showCentralWidget()), CENTRAL_OSGEARTH);
    }
341
#endif
lm's avatar
lm committed
342

343
#if (defined _MSC_VER) | (defined Q_OS_MAC)
344 345 346 347 348
    if (!gEarthWidget)
    {
        gEarthWidget = new QGCGoogleEarthView(this);
        addToCentralWidgetsMenu(gEarthWidget, "Google Earth", SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
    }
349

350
#endif
351

pixhawk's avatar
pixhawk committed
352
    // Dock widgets
353

354 355 356 357 358 359
    if (!detectionDockWidget)
    {
        detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
        detectionDockWidget->setWidget( new ObjectDetectionView("images/patterns", this) );
        addToToolsMenu (detectionDockWidget, tr("Object Recognition"), SLOT(showToolWidget()), MENU_DETECTION, Qt::RightDockWidgetArea);
    }
360

361 362 363 364 365 366
    if (!parametersDockWidget)
    {
        parametersDockWidget = new QDockWidget(tr("Onboard Parameters"), this);
        parametersDockWidget->setWidget( new ParameterInterface(this) );
        addToToolsMenu (parametersDockWidget, tr("Onboard Parameters"), SLOT(showToolWidget()), MENU_PARAMETERS, Qt::RightDockWidgetArea);
    }
367

368 369 370 371 372 373
    if (!watchdogControlDockWidget)
    {
        watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
        watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
        addToToolsMenu (watchdogControlDockWidget, tr("Process Control"), SLOT(showToolWidget()), MENU_WATCHDOG, Qt::BottomDockWidgetArea);
    }
374

375 376 377 378 379 380
    if (!hsiDockWidget)
    {
        hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
        hsiDockWidget->setWidget( new HSIDisplay(this) );
        addToToolsMenu (hsiDockWidget, tr("HSI"), SLOT(showToolWidget()), MENU_HSI, Qt::BottomDockWidgetArea);
    }
381

382 383
    if (!headDown1DockWidget)
    {
384 385
        headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
        headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
386 387
        addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget()), MENU_HDD_1, Qt::RightDockWidgetArea);
    }
388

389 390 391
    if (!headDown2DockWidget)
    {
        headDown2DockWidget = new QDockWidget(tr("Payload Status"), this);
392
        headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Payload Status", this) );
393 394
        addToToolsMenu (headDown2DockWidget, tr("Payload Status"), SLOT(showToolWidget()), MENU_HDD_2, Qt::RightDockWidgetArea);
    }
395

396 397 398 399 400 401
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
402

403 404 405 406 407 408
    if (!headUpDockWidget)
    {
        headUpDockWidget = new QDockWidget(tr("HUD"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
        addToToolsMenu (headUpDockWidget, tr("Control Indicator"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
409

pixhawk's avatar
pixhawk committed
410 411
    // Dialogue widgets
    //FIXME: free memory in destructor
412 413 414 415
    if (!joystick)
    {
        joystick    = new JoystickInput();
    }
416

417 418 419 420
}

void MainWindow::buildSlugsWidgets()
{
421 422 423 424 425
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
    }
426

427 428 429 430 431 432 433
    if (!headUpDockWidget)
    {
        // Dock widgets
        headUpDockWidget = new QDockWidget(tr("Control Indicator"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
        addToToolsMenu (headUpDockWidget, tr("HUD"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
434

435 436 437 438 439 440
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
441

442 443 444 445 446 447 448
    if (!slugsDataWidget)
    {
        // Dialog widgets
        slugsDataWidget = new QDockWidget(tr("Slugs Data"), this);
        slugsDataWidget->setWidget( new SlugsDataSensorView(this));
        addToToolsMenu (slugsDataWidget, tr("Telemetry Data"), SLOT(showToolWidget()), MENU_SLUGS_DATA, Qt::RightDockWidgetArea);
    }
449

450 451 452 453 454 455
    if (!slugsPIDControlWidget)
    {
        slugsPIDControlWidget = new QDockWidget(tr("Slugs PID Control"), this);
        slugsPIDControlWidget->setWidget(new SlugsPIDControl(this));
        addToToolsMenu (slugsPIDControlWidget, tr("PID Configuration"), SLOT(showToolWidget()), MENU_SLUGS_PID, Qt::LeftDockWidgetArea);
    }
456

457 458 459 460 461 462
    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);
    }
463

464 465 466 467 468 469
    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);
    }
470
}
471 472 473 474 475


void MainWindow::addToCentralWidgetsMenu ( QWidget* widget,
                                           const QString title,
                                           const char * slotName,
476 477
                                           TOOLS_WIDGET_NAMES centralWidget)
{
478
    QAction* tempAction;
479

480

481
    // Add the separator that will separate tools from central Widgets
482 483
    if (!toolsMenuActions[CENTRAL_SEPARATOR])
    {
484 485 486 487
        tempAction = ui.menuTools->addSeparator();
        toolsMenuActions[CENTRAL_SEPARATOR] = tempAction;
        tempAction->setData(CENTRAL_SEPARATOR);
    }
488

489
    tempAction = ui.menuTools->addAction(title);
490

491 492
    tempAction->setCheckable(true);
    tempAction->setData(centralWidget);
493

494 495 496
    // populate the Hashes
    toolsMenuActions[centralWidget] = tempAction;
    dockWidgets[centralWidget] = widget;
497

498
    QString chKey = buildMenuKey(SUB_SECTION_CHECKED, centralWidget, currentView);
499

500 501
    if (!settings.contains(chKey))
    {
502 503 504
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
    }
505 506 507 508
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
    }
509

510 511
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
512 513 514
}


lm's avatar
lm committed
515 516
void MainWindow::showCentralWidget()
{
517 518 519
    QAction* senderAction = qobject_cast<QAction *>(sender());
    int tool = senderAction->data().toInt();
    QString chKey;
520

521
    // check the current action
522

523 524
    if (senderAction && dockWidgets[tool])
    {
525

526 527 528 529 530 531 532 533 534 535 536 537 538
        // uncheck all central widget actions
        QHashIterator<int, QAction*> i(toolsMenuActions);
        while (i.hasNext()) {
            i.next();
            qDebug() << "shCW" << i.key() << "read";
            if (i.value() && i.value()->data().toInt() > 255){
                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);
            }
        }
539

540 541 542
        // check the current action
        qDebug() << senderAction->text();
        senderAction->setChecked(true);
543

544 545
        // update the central widget
        centerStack->setCurrentWidget(dockWidgets[tool]);
546

547 548 549 550
        // store the selected central widget
        chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
        settings.setValue(chKey,true);
        settings.sync();
551

552 553
        presentView();
    }
554
}
555

lm's avatar
lm committed
556 557 558 559
/**
 * Adds a widget to the tools menu and sets it visible if it was
 * enabled last time.
 */
560
void MainWindow::addToToolsMenu ( QWidget* widget,
561 562 563 564
                                  const QString title,
                                  const char * slotName,
                                  TOOLS_WIDGET_NAMES tool,
                                  Qt::DockWidgetArea location)
lm's avatar
lm committed
565
{
566 567
    QAction* tempAction;
    QString posKey, chKey;
568

569

570 571
    if (toolsMenuActions[CENTRAL_SEPARATOR])
    {
572 573 574
        tempAction = new QAction(title, this);
        ui.menuTools->insertAction(toolsMenuActions[CENTRAL_SEPARATOR],
                                   tempAction);
575 576 577
    }
    else
    {
578 579
        tempAction = ui.menuTools->addAction(title);
    }
580

581 582
    tempAction->setCheckable(true);
    tempAction->setData(tool);
583

584 585 586 587
    // populate the Hashes
    toolsMenuActions[tool] = tempAction;
    dockWidgets[tool] = widget;
    qDebug() << widget;
588

589
    posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
590

591 592
    if (!settings.contains(posKey))
    {
593 594
        settings.setValue(posKey,location);
        dockWidgetLocations[tool] = location;
595 596 597 598
    }
    else
    {
        dockWidgetLocations[tool] = static_cast <Qt::DockWidgetArea> (settings.value(posKey, Qt::RightDockWidgetArea).toInt());
599
    }
600

601
    chKey = buildMenuKey(SUB_SECTION_CHECKED,tool, currentView);
602

603 604 605 606
    if (!settings.contains(chKey))
    {
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
607
        widget->setVisible(false);
608 609 610 611
    }
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
612
        widget->setVisible(settings.value(chKey, false).toBool());
613
    }
614

615 616
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
617

618 619
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(visibilityChanged(bool)), this, SLOT(updateVisibilitySettings(bool)));
620

621 622
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(updateLocationSettings(Qt::DockWidgetArea)));
623 624 625

}

626 627 628 629
void MainWindow::showToolWidget()
{
    QAction* temp = qobject_cast<QAction *>(sender());
    int tool = temp->data().toInt();
630

631 632 633 634 635 636 637 638 639 640 641
    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]));
        }
642 643 644 645
    }
}


646 647 648 649 650
void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
{
    bool tempVisible;
    Qt::DockWidgetArea tempLocation;
    QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
651

652 653
    tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,widget,view), false).toBool();

654 655 656 657
    if (tempWidget)
    {
        toolsMenuActions[widget]->setChecked(tempVisible);
    }
658 659


660
    //qDebug() <<  buildMenuKey (SUB_SECTION_CHECKED,widget,view) << tempVisible;
661

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

664 665 666 667 668 669 670
    //    if (widget == MainWindow::MENU_UAS_LIST)
    //    {
    //        if (!settings.contains(buildMenuKey (SUB_SECTION_LOCATION,widget, view)))
    //        {
    //            tempLocation = Qt::RightDockWidgetArea;
    //        }
    //    }
671

672
    if ((tempWidget != NULL) && tempVisible)
673 674 675 676
    {
        addDockWidget(tempLocation, tempWidget);
        tempWidget->show();
    }
677

678
}
679

680 681 682 683 684 685 686 687 688 689 690 691 692 693
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) + "/" );
694 695
}

696 697
void MainWindow::closeEvent(QCloseEvent *event)
{
698
    settings.setValue(getWindowGeometryKey(), saveGeometry());
699 700
    //settings.setValue("windowState", saveState());
    aboutToCloseFlag = true;
701 702 703 704 705 706
    // 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);
707 708 709
    settings.sync();
    QMainWindow::closeEvent(event);
}
710

711 712 713 714 715
/**
 * Stores the visibility setting of each widget. This method
 * will only change the settings if the application is not
 * about to close.
 */
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
void MainWindow::updateVisibilitySettings (bool vis)
{
    if (!aboutToCloseFlag)
    {

        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());

        if (temp)
        {
            QHashIterator<int, QWidget*> i(dockWidgets);
            while (i.hasNext())
            {
                i.next();
                if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp)
                {
731 732 733
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,vis);
                    settings.sync();
734 735 736 737 738 739
                    toolsMenuActions[i.key()]->setChecked(vis);
                    break;
                }
            }
        }
    }
740 741
}

742 743 744
void MainWindow::updateLocationSettings (Qt::DockWidgetArea location)
{
    QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
745

746 747 748 749 750 751 752 753 754 755 756
    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;
        }
    }
757 758
}

759 760 761
/**
 * Connect the signals and slots of the common window widgets
 */
762
void MainWindow::connectCommonWidgets()
763
{
pixhawk's avatar
pixhawk committed
764 765 766 767 768
    if (infoDockWidget && infoDockWidget->widget())
    {
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
769

pixhawk's avatar
pixhawk committed
770 771 772
    if (mapWidget && waypointsDockWidget->widget())
    {
        // clear path create on the map
773
        connect(waypointsDockWidget->widget(), SIGNAL(clearPathclicked()), mapWidget, SLOT(clearWaypoints()));
pixhawk's avatar
pixhawk committed
774 775
        // add Waypoint widget in the WaypointList widget when mouse clicked
        connect(mapWidget, SIGNAL(captureMapCoordinateClick(QPointF)), waypointsDockWidget->widget(), SLOT(addWaypointMouse(QPointF)));
776 777 778

        // 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)));
779
    }
780
}
781

782 783 784 785 786 787 788 789
void MainWindow::createCustomWidget()
{
    qDebug() << "ADDING CUSTOM WIDGET";
    QGCToolWidget* tool = new QGCToolWidget(this);
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
    dock->setWidget(tool);
    this->addDockWidget(Qt::LeftDockWidgetArea, dock);
    dock->setVisible(true);
790 791 792 793
}

void MainWindow::connectPxWidgets()
{
794
    // No special connections necessary at this point
795 796 797 798
}

void MainWindow::connectSlugsWidgets()
{
799
    if (slugsHilSimWidget && slugsHilSimWidget->widget()){
800 801
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
802 803 804
    }

    if (slugsDataWidget && slugsDataWidget->widget()){
805 806
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsDataWidget->widget(), SLOT(setActiveUAS(UASInterface*)));
807 808
    }

809

810 811
}

812
void MainWindow::arrangeCommonCenterStack()
813
{
814
    centerStack = new QStackedWidget(this);
815
    centerStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
816

pixhawk's avatar
pixhawk committed
817
    if (!centerStack) return;
818

819
    if (mapWidget && (centerStack->indexOf(mapWidget) == -1)) centerStack->addWidget(mapWidget);
lm's avatar
lm committed
820
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
821
    if (protocolWidget && (centerStack->indexOf(protocolWidget) == -1)) centerStack->addWidget(protocolWidget);
822 823 824 825 826 827 828

    setCentralWidget(centerStack);
}

void MainWindow::arrangePxCenterStack()
{

829 830 831 832
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
833

834 835

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

837
#ifdef QGC_OSG_ENABLED
838
    if (_3DWidget && (centerStack->indexOf(_3DWidget) == -1)) centerStack->addWidget(_3DWidget);
839
#endif
840
#ifdef QGC_OSGEARTH_ENABLED
841
    if (_3DMapWidget && (centerStack->indexOf(_3DMapWidget) == -1)) centerStack->addWidget(_3DMapWidget);
842
#endif
843
#if (defined _MSC_VER) | (defined Q_OS_MAC)
844
    if (gEarthWidget && (centerStack->indexOf(gEarthWidget) == -1)) centerStack->addWidget(gEarthWidget);
845
#endif
846 847
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
848 849 850 851 852
}

void MainWindow::arrangeSlugsCenterStack()
{

853 854 855 856
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
857

858 859
    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
860

861 862
}

863 864
void MainWindow::configureWindowName()
{
pixhawk's avatar
pixhawk committed
865 866 867
    QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
    QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
    bool prevAddr = false;
868

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

pixhawk's avatar
pixhawk committed
871 872 873 874 875 876 877 878 879 880
    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;
        }
    }
881

pixhawk's avatar
pixhawk committed
882
    windowname.append(")");
883

pixhawk's avatar
pixhawk committed
884
    setWindowTitle(windowname);
885 886

#ifndef Q_WS_MAC
pixhawk's avatar
pixhawk committed
887
    //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
888 889 890
#endif
}

pixhawk's avatar
pixhawk committed
891
void MainWindow::startVideoCapture()
pixhawk's avatar
pixhawk committed
892 893 894 895 896 897 898 899 900 901 902
{
    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);
903 904 905
    //videoTimer->setInterval(40);
    //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
    //videoTimer->stop();
pixhawk's avatar
pixhawk committed
906 907
}

pixhawk's avatar
pixhawk committed
908
void MainWindow::stopVideoCapture()
pixhawk's avatar
pixhawk committed
909 910 911 912 913 914
{
    videoTimer->stop();

    // TODO Convert raw images to PNG
}

pixhawk's avatar
pixhawk committed
915
void MainWindow::saveScreen()
pixhawk's avatar
pixhawk committed
916 917 918 919 920 921 922 923 924 925
{
    QPixmap window = QPixmap::grabWindow(this->winId());
    QString format = "bmp";

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

926 927 928 929 930 931
/**
 * 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
932
void MainWindow::reloadStylesheet()
pixhawk's avatar
pixhawk committed
933
{
934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
    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
951
    // Load style sheet
952
    QFile* styleSheet = new QFile(fileName);
953 954 955 956
    if (!styleSheet->exists())
    {
        styleSheet = new QFile(":/images/style-mission.css");
    }
957 958
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
    {
959 960
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
pixhawk's avatar
pixhawk committed
961
        qApp->setStyleSheet(style);
962 963 964
    }
    else
    {
965 966 967 968 969 970 971
        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
972
    }
973
    delete styleSheet;
pixhawk's avatar
pixhawk committed
974 975
}

976 977 978 979 980 981
/**
 * 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
982
void MainWindow::showStatusMessage(const QString& status, int timeout)
pixhawk's avatar
pixhawk committed
983
{
lm's avatar
lm committed
984
    statusBar()->showMessage(status, timeout);
pixhawk's avatar
pixhawk committed
985 986
}

987 988 989 990 991 992
/**
 * 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
 */
993
void MainWindow::showStatusMessage(const QString& status)
pixhawk's avatar
pixhawk committed
994
{
lm's avatar
lm committed
995
    statusBar()->showMessage(status, 20000);
996 997 998 999 1000 1001 1002 1003 1004 1005 1006
}

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
1007 1008
}

lm's avatar
lm committed
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
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
1020 1021 1022 1023
/**
* @brief Create all actions associated to the main window
*
**/
1024
void MainWindow::connectCommonActions()
pixhawk's avatar
pixhawk committed
1025 1026 1027 1028 1029 1030 1031
{
    // 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*)));

1032
    // Unmanned System controls
pixhawk's avatar
pixhawk committed
1033 1034 1035 1036 1037 1038 1039
    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()));

1040
    // Views actions
1041
    connect(ui.actionPilotsView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
1042
    connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
1043
    connect(ui.actionOperatorsView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
1044

1045 1046
    connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
    connect(ui.actionReloadStyle, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
1047

1048
    // Help Actions
1049
    connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
1050
    connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
1051
    connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
1052 1053 1054 1055
}

void MainWindow::connectPxActions()
{
1056
    ui.actionJoystickSettings->setVisible(true);
1057

1058 1059
    // Joystick configuration
    connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
1060 1061 1062 1063 1064

}

void MainWindow::connectSlugsActions()
{
1065

pixhawk's avatar
pixhawk committed
1066 1067
}

1068 1069
void MainWindow::showHelp()
{
1070
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/")))
1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
    {
        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()
{
1084
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits/")))
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097
    {
        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()
{
1098
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/roadmap/")))
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109
    {
        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
1110
void MainWindow::configure()
pixhawk's avatar
pixhawk committed
1111 1112 1113 1114
{
    joystickWidget = new JoystickWidget(joystick, this);
}

pixhawk's avatar
pixhawk committed
1115
void MainWindow::addLink()
pixhawk's avatar
pixhawk committed
1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
{
    SerialLink* link = new SerialLink();
    // TODO This should be only done in the dialog itself

    LinkManager::instance()->addProtocol(link, mavlink);

    CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);

    ui.menuNetwork->addAction(commWidget->getAction());

    commWidget->show();
}

pixhawk's avatar
pixhawk committed
1129 1130
void MainWindow::addLink(LinkInterface *link)
{
1131
    LinkManager::instance()->addProtocol(link, mavlink);
pixhawk's avatar
pixhawk committed
1132 1133 1134 1135 1136 1137 1138
    CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);
    ui.menuNetwork->addAction(commWidget->getAction());

    // Special case for simulationlink
    MAVLinkSimulationLink* sim = dynamic_cast<MAVLinkSimulationLink*>(link);
    if (sim)
    {
1139
        //connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64)));
pixhawk's avatar
pixhawk committed
1140 1141 1142 1143
        connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool)));
    }
}

pixhawk's avatar
pixhawk committed
1144
void MainWindow::UASCreated(UASInterface* uas)
pixhawk's avatar
pixhawk committed
1145
{
1146

pixhawk's avatar
pixhawk committed
1147 1148
    // Connect the UAS to the full user interface

1149 1150
    if (uas != NULL)
    {
1151 1152 1153
        // The pilot view was not available on startup, enable it now
        ui.actionPilotsView->setEnabled(true);

1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
        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
1184 1185
        if (debugConsoleDockWidget)
        {
pixhawk's avatar
pixhawk committed
1186 1187 1188 1189 1190 1191
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
            if (debugConsole)
            {
                connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)),
                        debugConsole, SLOT(receiveTextMessage(int,int,int,QString)));
            }
1192
        }
1193 1194

        // Health / System status indicator
1195 1196
        if (infoDockWidget)
        {
pixhawk's avatar
pixhawk committed
1197 1198 1199 1200 1201
            UASInfoWidget *infoWidget = dynamic_cast<UASInfoWidget*>(infoDockWidget->widget());
            if (infoWidget)
            {
                infoWidget->addUAS(uas);
            }
1202
        }
1203 1204

        // UAS List
1205 1206
        if (listDockWidget)
        {
pixhawk's avatar
pixhawk committed
1207 1208 1209 1210 1211
            UASListWidget *listWidget = dynamic_cast<UASListWidget*>(listDockWidget->widget());
            if (listWidget)
            {
                listWidget->addUAS(uas);
            }
1212
        }
1213

1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
        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;

        }

        // 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)
        {
            qDebug() << "UPDATING THE VIEW SINCE THIS IS THE FIRST CONNECTED SYSTEM";

            // Load last view if setting is present
1275
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
1276
            {
1277
                int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
1278 1279
                currentView = (VIEW_SECTIONS) view;
                presentView();
1280 1281 1282 1283 1284 1285 1286

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

1287 1288 1289 1290 1291
            }
            else
            {
                loadEngineerView();
            }
1292
        }
1293

1294
    }
pixhawk's avatar
pixhawk committed
1295 1296
}

1297 1298 1299
/**
 * Clears the current view completely
 */
pixhawk's avatar
pixhawk committed
1300
void MainWindow::clearView()
1301
{
1302 1303 1304
    // Save current state
    if (UASManager::instance()->getActiveUAS()) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
    settings.setValue(getWindowGeometryKey(), saveGeometry());
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323

    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)
        {
            settings.setValue(chKey,temp->isChecked());
        }
        else
        {
            settings.setValue(chKey,false);
        }
    }

1324 1325
    settings.sync();

1326 1327
    // Remove all dock widgets from main window
    QObjectList childList( this->children() );
pixhawk's avatar
pixhawk committed
1328

1329 1330 1331
    QObjectList::iterator i;
    QDockWidget* dockWidget;
    for (i = childList.begin(); i != childList.end(); ++i)
pixhawk's avatar
pixhawk committed
1332
    {
1333 1334
        dockWidget = dynamic_cast<QDockWidget*>(*i);
        if (dockWidget)
pixhawk's avatar
pixhawk committed
1335
        {
1336
            // Remove dock widget from main window
1337 1338
            //this->removeDockWidget(dockWidget);
            dockWidget->setVisible(false);
1339 1340 1341
            // 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
1342 1343 1344 1345
        }
    }
}

1346
void MainWindow::loadEngineerView()
lm's avatar
lm committed
1347
{
1348 1349 1350
    if (currentView != VIEW_ENGINEER)
    {
        clearView();
lm's avatar
lm committed
1351

1352
        currentView = VIEW_ENGINEER;
lm's avatar
lm committed
1353

1354 1355
        presentView();
    }
lm's avatar
lm committed
1356 1357
}

1358
void MainWindow::loadOperatorView()
lm's avatar
lm committed
1359
{
1360 1361 1362
    if (currentView != VIEW_OPERATOR)
    {
        clearView();
1363

1364
        currentView = VIEW_OPERATOR;
lm's avatar
lm committed
1365

1366 1367
        presentView();
    }
lm's avatar
lm committed
1368 1369
}

1370
void MainWindow::loadPilotView()
1371
{
1372 1373 1374
    if (currentView != VIEW_PILOT)
    {
        clearView();
1375

1376
        currentView = VIEW_PILOT;
1377

1378 1379
        presentView();
    }
1380 1381
}

1382
void MainWindow::loadMAVLinkView()
1383
{
1384 1385 1386
    if (currentView != VIEW_MAVLINK)
    {
        clearView();
pixhawk's avatar
pixhawk committed
1387

1388
        currentView = VIEW_MAVLINK;
1389

1390 1391
        presentView();
    }
1392 1393
}

lm's avatar
lm committed
1394 1395
void MainWindow::presentView()
{
1396
    // LINE CHART
1397
    showTheCentralWidget(CENTRAL_LINECHART, currentView);
1398

1399 1400
    // MAP
    showTheCentralWidget(CENTRAL_MAP, currentView);
pixhawk's avatar
pixhawk committed
1401

1402 1403
    // PROTOCOL
    showTheCentralWidget(CENTRAL_PROTOCOL, currentView);
pixhawk's avatar
pixhawk committed
1404

1405 1406
    // HEAD UP DISPLAY
    showTheCentralWidget(CENTRAL_HUD, currentView);
pixhawk's avatar
pixhawk committed
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416

    // GOOGLE EARTH
    showTheCentralWidget(CENTRAL_GOOGLE_EARTH, currentView);

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

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

1417 1418 1419
    // DATA PLOT
    showTheCentralWidget(CENTRAL_DATA_PLOT, currentView);

pixhawk's avatar
pixhawk committed
1420

pixhawk's avatar
pixhawk committed
1421

1422
    // Show docked widgets based on current view and autopilot type
1423

1424 1425
    // UAS CONTROL
    showTheWidget(MENU_UAS_CONTROL, currentView);
1426

1427 1428
    // UAS LIST
    showTheWidget(MENU_UAS_LIST, currentView);
1429

1430 1431
    // WAYPOINT LIST
    showTheWidget(MENU_WAYPOINTS, currentView);
pixhawk's avatar
pixhawk committed
1432

1433 1434
    // UAS STATUS
    showTheWidget(MENU_STATUS, currentView);
1435

1436 1437
    // DETECTION
    showTheWidget(MENU_DETECTION, currentView);
1438

1439 1440
    // DEBUG CONSOLE
    showTheWidget(MENU_DEBUG_CONSOLE, currentView);
1441

1442 1443
    // ONBOARD PARAMETERS
    showTheWidget(MENU_PARAMETERS, currentView);
1444

1445 1446
    // WATCHDOG
    showTheWidget(MENU_WATCHDOG, currentView);
1447

1448 1449 1450 1451 1452
    // HUD
    showTheWidget(MENU_HUD, currentView);
    if (headUpDockWidget)
    {
        HUD* tmpHud = dynamic_cast<HUD*>( headUpDockWidget->widget() );
1453 1454 1455 1456
        if (tmpHud)
        {
            if (settings.value(buildMenuKey (SUB_SECTION_CHECKED,MENU_HUD,currentView)).toBool())
            {
1457 1458 1459
                addDockWidget(static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,MENU_HUD, currentView)).toInt()),
                              hsiDockWidget);
                headUpDockWidget->show();
1460 1461 1462
            }
            else
            {
1463 1464
                headUpDockWidget->hide();
            }
1465
        }
1466
    }
1467

1468

1469 1470
    // RC View
    showTheWidget(MENU_RC_VIEW, currentView);
1471

1472 1473
    // SLUGS DATA
    showTheWidget(MENU_SLUGS_DATA, currentView);
1474

1475 1476
    // SLUGS PID
    showTheWidget(MENU_SLUGS_PID, currentView);
1477

1478 1479
    // SLUGS HIL
    showTheWidget(MENU_SLUGS_HIL, currentView);
1480

1481 1482
    // SLUGS CAMERA
    showTheWidget(MENU_SLUGS_CAMERA, currentView);
1483

1484 1485
    // HORIZONTAL SITUATION INDICATOR
    showTheWidget(MENU_HSI, currentView);
1486

1487 1488 1489 1490 1491
    // HEAD DOWN 1
    showTheWidget(MENU_HDD_1, currentView);

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

1493
    this->show();
1494

1495
}
1496

1497 1498 1499 1500
void MainWindow::showTheCentralWidget (TOOLS_WIDGET_NAMES centralWidget, VIEW_SECTIONS view)
{
    bool tempVisible;
    QWidget* tempWidget = dockWidgets[centralWidget];
1501

1502
    tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view), false).toBool();
1503 1504
    qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
    if (toolsMenuActions[centralWidget])
1505
    {
1506
        toolsMenuActions[centralWidget]->setChecked(tempVisible);
1507
    }
1508

1509
    if (centerStack && tempWidget && tempVisible)
1510
    {
1511
        centerStack->setCurrentWidget(tempWidget);
1512
    }
1513 1514
}

1515 1516
void MainWindow::loadDataView(QString fileName)
{
1517
    clearView();
1518 1519 1520 1521 1522

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

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

1527
    presentView();
1528

1529 1530
    // Plot is now selected, now load data from file
    if (dataplotWidget)
1531
    {
1532
        dataplotWidget->loadFile(fileName);
1533
    }
1534 1535 1536 1537 1538 1539 1540
//        QStackedWidget *centerStack = dynamic_cast<QStackedWidget*>(centralWidget());
//        if (centerStack)
//        {
//            centerStack->setCurrentWidget(dataplotWidget);
//            dataplotWidget->loadFile(fileName);
//        }
//    }
1541 1542 1543
}