MainWindow.cc 52.5 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
    // 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

208 209
    connect(LinkManager::instance(), SIGNAL(newLink(LinkInterface*)), this, SLOT(addLink(LinkInterface*)));

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

pixhawk's avatar
pixhawk committed
214
MainWindow::~MainWindow()
pixhawk's avatar
pixhawk committed
215
{
lm's avatar
lm committed
216

pixhawk's avatar
pixhawk committed
217 218
}

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

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

lm's avatar
lm committed
229 230 231 232 233 234 235 236 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
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);
            }
        }
    }
}

266 267 268 269
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
270
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
271 272

    // Dock widgets
273 274 275
    if (!controlDockWidget)
    {
        controlDockWidget = new QDockWidget(tr("Control"), this);
276
        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
277 278 279
        controlDockWidget->setWidget( new UASControlWidget(this) );
        addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget()), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
    }
280

281 282 283 284
    if (!listDockWidget)
    {
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
285
        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
286 287
        addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget()), MENU_UAS_LIST, Qt::RightDockWidgetArea);
    }
288

289 290 291 292
    if (!waypointsDockWidget)
    {
        waypointsDockWidget = new QDockWidget(tr("Waypoint List"), this);
        waypointsDockWidget->setWidget( new WaypointList(this, NULL) );
293
        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
294 295
        addToToolsMenu (waypointsDockWidget, tr("Waypoints List"), SLOT(showToolWidget()), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
    }
296

297 298 299 300
    if (!infoDockWidget)
    {
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
pixhawk's avatar
pixhawk committed
301
        infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
302 303
        addToToolsMenu (infoDockWidget, tr("Status Details"), SLOT(showToolWidget()), MENU_STATUS, Qt::RightDockWidgetArea);
    }
304

305 306 307 308
    if (!debugConsoleDockWidget)
    {
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
309
        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
310 311
        addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget()), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
    }
312

313 314 315 316 317 318 319 320
    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);
    }

321
    // Center widgets
322 323 324 325 326
    if (!mapWidget)
    {
        mapWidget         = new MapWidget(this);
        addToCentralWidgetsMenu (mapWidget, "Maps", SLOT(showCentralWidget()),CENTRAL_MAP);
    }
327

328 329 330 331 332
    if (!protocolWidget)
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addToCentralWidgetsMenu (protocolWidget, "Mavlink Generator", SLOT(showCentralWidget()),CENTRAL_PROTOCOL);
    }
lm's avatar
lm committed
333 334 335 336 337 338

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

341
void MainWindow::buildPxWidgets()
342
{
pixhawk's avatar
pixhawk committed
343 344
    //FIXME: memory of acceptList will never be freed again
    QStringList* acceptList = new QStringList();
lm's avatar
lm committed
345 346 347
    acceptList->append("-105,roll,deg,+105,s");
    acceptList->append("-105,pitch,deg,+105,s");
    acceptList->append("-105,yaw,deg,+105,s");
348

lm's avatar
lm committed
349 350 351
    acceptList->append("-260,rollspeed,deg/s,+260,s");
    acceptList->append("-260,pitchspeed,deg/s,+260,s");
    acceptList->append("-260,yawspeed,deg/s,+260,s");
352

pixhawk's avatar
pixhawk committed
353 354
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
lm's avatar
lm committed
355
    acceptList2->append("0,abs pressure,hPa,65500");
356 357
    acceptList2->append("-999,accel. X,raw,999,s");
    acceptList2->append("-999,accel. Y,raw,999,s");
358

359 360 361 362 363 364
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
        addToCentralWidgetsMenu(linechartWidget, "Line Plots", SLOT(showCentralWidget()), CENTRAL_LINECHART);
    }
365 366


367 368 369 370 371
    if (!hudWidget)
    {
        hudWidget         = new HUD(320, 240, this);
        addToCentralWidgetsMenu(hudWidget, "HUD", SLOT(showCentralWidget()), CENTRAL_HUD);
    }
372

373 374 375 376 377
    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu(dataplotWidget, "Data Plots", SLOT(showCentralWidget()), CENTRAL_DATA_PLOT);
    }
378

379
#ifdef QGC_OSG_ENABLED
380 381 382 383 384
    if (!_3DWidget)
    {
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
        addToCentralWidgetsMenu(_3DWidget, "Local 3D", SLOT(showCentralWidget()), CENTRAL_3D_LOCAL);
    }
385
#endif
386

387
#ifdef QGC_OSGEARTH_ENABLED
388 389 390 391 392
    if (!_3DMapWidget)
    {
        _3DMapWidget = Q3DWidgetFactory::get("MAP3D");
        addToCentralWidgetsMenu(_3DMapWidget, "OSG Earth 3D", SLOT(showCentralWidget()), CENTRAL_OSGEARTH);
    }
393
#endif
lm's avatar
lm committed
394

395
#if (defined _MSC_VER) | (defined Q_OS_MAC)
396 397 398 399 400
    if (!gEarthWidget)
    {
        gEarthWidget = new QGCGoogleEarthView(this);
        addToCentralWidgetsMenu(gEarthWidget, "Google Earth", SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
    }
401

402
#endif
403

pixhawk's avatar
pixhawk committed
404
    // Dock widgets
405

406 407 408 409
    if (!detectionDockWidget)
    {
        detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
        detectionDockWidget->setWidget( new ObjectDetectionView("images/patterns", this) );
pixhawk's avatar
pixhawk committed
410
        detectionDockWidget->setObjectName("OBJECT_DETECTION_DOCK_WIDGET");
411 412
        addToToolsMenu (detectionDockWidget, tr("Object Recognition"), SLOT(showToolWidget()), MENU_DETECTION, Qt::RightDockWidgetArea);
    }
413

414 415 416 417
    if (!parametersDockWidget)
    {
        parametersDockWidget = new QDockWidget(tr("Onboard Parameters"), this);
        parametersDockWidget->setWidget( new ParameterInterface(this) );
pixhawk's avatar
pixhawk committed
418
        parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET");
419 420
        addToToolsMenu (parametersDockWidget, tr("Onboard Parameters"), SLOT(showToolWidget()), MENU_PARAMETERS, Qt::RightDockWidgetArea);
    }
421

422 423 424 425
    if (!watchdogControlDockWidget)
    {
        watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
        watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
pixhawk's avatar
pixhawk committed
426
        watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
427 428
        addToToolsMenu (watchdogControlDockWidget, tr("Process Control"), SLOT(showToolWidget()), MENU_WATCHDOG, Qt::BottomDockWidgetArea);
    }
429

430 431 432 433
    if (!hsiDockWidget)
    {
        hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
        hsiDockWidget->setWidget( new HSIDisplay(this) );
434
        hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
435 436
        addToToolsMenu (hsiDockWidget, tr("HSI"), SLOT(showToolWidget()), MENU_HSI, Qt::BottomDockWidgetArea);
    }
437

438 439
    if (!headDown1DockWidget)
    {
440 441
        headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
        headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
442
        headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
443 444
        addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget()), MENU_HDD_1, Qt::RightDockWidgetArea);
    }
445

446 447 448
    if (!headDown2DockWidget)
    {
        headDown2DockWidget = new QDockWidget(tr("Payload Status"), this);
449
        headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Payload Status", this) );
450
        headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
451 452
        addToToolsMenu (headDown2DockWidget, tr("Payload Status"), SLOT(showToolWidget()), MENU_HDD_2, Qt::RightDockWidgetArea);
    }
453

454 455 456 457
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
458
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
459 460
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
461

462 463 464 465
    if (!headUpDockWidget)
    {
        headUpDockWidget = new QDockWidget(tr("HUD"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
466
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
467 468
        addToToolsMenu (headUpDockWidget, tr("Control Indicator"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
469

pixhawk's avatar
pixhawk committed
470 471
    // Dialogue widgets
    //FIXME: free memory in destructor
472 473 474 475
    if (!joystick)
    {
        joystick    = new JoystickInput();
    }
476

477 478 479 480
}

void MainWindow::buildSlugsWidgets()
{
481 482 483 484 485
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
    }
486

487 488 489 490 491
    if (!headUpDockWidget)
    {
        // Dock widgets
        headUpDockWidget = new QDockWidget(tr("Control Indicator"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
pixhawk's avatar
pixhawk committed
492
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
493 494
        addToToolsMenu (headUpDockWidget, tr("HUD"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
495

496 497 498 499
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
pixhawk's avatar
pixhawk committed
500
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
501 502
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
503

504 505 506 507 508
    if (!slugsDataWidget)
    {
        // Dialog widgets
        slugsDataWidget = new QDockWidget(tr("Slugs Data"), this);
        slugsDataWidget->setWidget( new SlugsDataSensorView(this));
pixhawk's avatar
pixhawk committed
509
        slugsDataWidget->setObjectName("SLUGS_DATA_DOCK_WIDGET");
510 511
        addToToolsMenu (slugsDataWidget, tr("Telemetry Data"), SLOT(showToolWidget()), MENU_SLUGS_DATA, Qt::RightDockWidgetArea);
    }
512

513 514 515 516
    if (!slugsPIDControlWidget)
    {
        slugsPIDControlWidget = new QDockWidget(tr("Slugs PID Control"), this);
        slugsPIDControlWidget->setWidget(new SlugsPIDControl(this));
pixhawk's avatar
pixhawk committed
517
        slugsPIDControlWidget->setObjectName("SLUGS_PID_CONTROL_DOCK_WIDGET");
518 519
        addToToolsMenu (slugsPIDControlWidget, tr("PID Configuration"), SLOT(showToolWidget()), MENU_SLUGS_PID, Qt::LeftDockWidgetArea);
    }
520

521 522 523 524
    if (!slugsHilSimWidget)
    {
        slugsHilSimWidget = new QDockWidget(tr("Slugs Hil Sim"), this);
        slugsHilSimWidget->setWidget( new SlugsHilSim(this));
pixhawk's avatar
pixhawk committed
525
        slugsHilSimWidget->setObjectName("SLUGS_HIL_SIM_DOCK_WIDGET");
526 527
        addToToolsMenu (slugsHilSimWidget, tr("HIL Sim Configuration"), SLOT(showToolWidget()), MENU_SLUGS_HIL, Qt::LeftDockWidgetArea);
    }
528

529 530 531 532
    if (!slugsCamControlWidget)
    {
        slugsCamControlWidget = new QDockWidget(tr("Slugs Video Camera Control"), this);
        slugsCamControlWidget->setWidget(new SlugsVideoCamControl(this));
pixhawk's avatar
pixhawk committed
533
        slugsCamControlWidget->setObjectName("SLUGS_CAM_CONTROL_DOCK_WIDGET");
534 535
        addToToolsMenu (slugsCamControlWidget, tr("Camera Control"), SLOT(showToolWidget()), MENU_SLUGS_CAMERA, Qt::BottomDockWidgetArea);
    }
536
}
537 538 539 540 541


void MainWindow::addToCentralWidgetsMenu ( QWidget* widget,
                                           const QString title,
                                           const char * slotName,
542 543
                                           TOOLS_WIDGET_NAMES centralWidget)
{
544
    QAction* tempAction;
545

546

547
    // Add the separator that will separate tools from central Widgets
548 549
    if (!toolsMenuActions[CENTRAL_SEPARATOR])
    {
550 551 552 553
        tempAction = ui.menuTools->addSeparator();
        toolsMenuActions[CENTRAL_SEPARATOR] = tempAction;
        tempAction->setData(CENTRAL_SEPARATOR);
    }
554

555
    tempAction = ui.menuTools->addAction(title);
556

557 558
    tempAction->setCheckable(true);
    tempAction->setData(centralWidget);
559

560 561 562
    // populate the Hashes
    toolsMenuActions[centralWidget] = tempAction;
    dockWidgets[centralWidget] = widget;
563

564
    QString chKey = buildMenuKey(SUB_SECTION_CHECKED, centralWidget, currentView);
565

566 567
    if (!settings.contains(chKey))
    {
568 569 570
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
    }
571 572 573 574
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
    }
575

576 577
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
578 579 580
}


lm's avatar
lm committed
581 582
void MainWindow::showCentralWidget()
{
583 584 585
    QAction* senderAction = qobject_cast<QAction *>(sender());
    int tool = senderAction->data().toInt();
    QString chKey;
586

587
    // check the current action
588

589 590
    if (senderAction && dockWidgets[tool])
    {
591

592 593
        // uncheck all central widget actions
        QHashIterator<int, QAction*> i(toolsMenuActions);
594 595
        while (i.hasNext())
        {
596
            i.next();
597 598 599
            //qDebug() << "shCW" << i.key() << "read";
            if (i.value() && i.value()->data().toInt() > 255)
            {
600 601 602 603 604 605 606
                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);
            }
        }
607

608
        // check the current action
609
        //qDebug() << senderAction->text();
610
        senderAction->setChecked(true);
611

612 613
        // update the central widget
        centerStack->setCurrentWidget(dockWidgets[tool]);
614

615 616 617
        // store the selected central widget
        chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
        settings.setValue(chKey,true);
618

619 620
        presentView();
    }
621
}
622

lm's avatar
lm committed
623 624 625 626
/**
 * Adds a widget to the tools menu and sets it visible if it was
 * enabled last time.
 */
627
void MainWindow::addToToolsMenu ( QWidget* widget,
628 629 630 631
                                  const QString title,
                                  const char * slotName,
                                  TOOLS_WIDGET_NAMES tool,
                                  Qt::DockWidgetArea location)
lm's avatar
lm committed
632
{
633 634
    QAction* tempAction;
    QString posKey, chKey;
635

636

637 638
    if (toolsMenuActions[CENTRAL_SEPARATOR])
    {
639 640 641
        tempAction = new QAction(title, this);
        ui.menuTools->insertAction(toolsMenuActions[CENTRAL_SEPARATOR],
                                   tempAction);
642 643 644
    }
    else
    {
645 646
        tempAction = ui.menuTools->addAction(title);
    }
647

648 649
    tempAction->setCheckable(true);
    tempAction->setData(tool);
650

651 652 653
    // populate the Hashes
    toolsMenuActions[tool] = tempAction;
    dockWidgets[tool] = widget;
654
    //qDebug() << widget;
655

656
    posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
657

658 659
    if (!settings.contains(posKey))
    {
660 661
        settings.setValue(posKey,location);
        dockWidgetLocations[tool] = location;
662 663 664 665
    }
    else
    {
        dockWidgetLocations[tool] = static_cast <Qt::DockWidgetArea> (settings.value(posKey, Qt::RightDockWidgetArea).toInt());
666
    }
667

668
    chKey = buildMenuKey(SUB_SECTION_CHECKED,tool, currentView);
669

670 671 672 673
    if (!settings.contains(chKey))
    {
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
674
        widget->setVisible(false);
675 676 677 678
    }
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
679
        widget->setVisible(settings.value(chKey, false).toBool());
680
    }
681

682 683
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
684

685 686
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(visibilityChanged(bool)), this, SLOT(updateVisibilitySettings(bool)));
687

688 689
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(updateLocationSettings(Qt::DockWidgetArea)));
690 691 692

}

693 694 695 696
void MainWindow::showToolWidget()
{
    QAction* temp = qobject_cast<QAction *>(sender());
    int tool = temp->data().toInt();
697

698 699 700 701 702 703 704 705 706 707 708
    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]));
        }
709 710 711 712
    }
}


713 714 715 716 717
void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
{
    bool tempVisible;
    Qt::DockWidgetArea tempLocation;
    QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
718

719
    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,widget,view), false).toBool();
720

721 722 723 724
    if (tempWidget)
    {
        toolsMenuActions[widget]->setChecked(tempVisible);
    }
725 726


727
    //qDebug() <<  buildMenuKey (SUB_SECTION_CHECKED,widget,view) << tempVisible;
728

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

731 732 733 734 735 736 737
    //    if (widget == MainWindow::MENU_UAS_LIST)
    //    {
    //        if (!settings.contains(buildMenuKey (SUB_SECTION_LOCATION,widget, view)))
    //        {
    //            tempLocation = Qt::RightDockWidgetArea;
    //        }
    //    }
738

739
    if ((tempWidget != NULL) && tempVisible)
740 741 742 743
    {
        addDockWidget(tempLocation, tempWidget);
        tempWidget->show();
    }
744

745
}
746

747 748 749 750 751 752 753 754 755 756 757 758 759 760
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) + "/" );
761 762
}

763 764
void MainWindow::closeEvent(QCloseEvent *event)
{
765
    settings.setValue(getWindowGeometryKey(), saveGeometry());
766 767
    //settings.setValue("windowState", saveState());
    aboutToCloseFlag = true;
768 769 770 771 772 773
    // 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);
774 775 776
    settings.sync();
    QMainWindow::closeEvent(event);
}
777

778

779 780
void MainWindow::updateVisibilitySettings (bool vis)
{
781
    if (!aboutToCloseFlag && !changingViewsFlag)
782 783 784 785 786 787 788 789 790 791 792
    {
        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)
                {
793 794
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,vis);
795 796 797 798 799 800
                    toolsMenuActions[i.key()]->setChecked(vis);
                    break;
                }
            }
        }
    }
801 802
}

803 804 805
void MainWindow::updateLocationSettings (Qt::DockWidgetArea location)
{
    QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
806

807 808 809 810 811 812 813 814 815 816 817
    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;
        }
    }
818 819
}

820 821 822
/**
 * Connect the signals and slots of the common window widgets
 */
823
void MainWindow::connectCommonWidgets()
824
{
pixhawk's avatar
pixhawk committed
825 826 827 828 829
    if (infoDockWidget && infoDockWidget->widget())
    {
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
830

pixhawk's avatar
pixhawk committed
831 832 833
    if (mapWidget && waypointsDockWidget->widget())
    {
        // clear path create on the map
834
        connect(waypointsDockWidget->widget(), SIGNAL(clearPathclicked()), mapWidget, SLOT(clearWaypoints()));
pixhawk's avatar
pixhawk committed
835 836
        // add Waypoint widget in the WaypointList widget when mouse clicked
        connect(mapWidget, SIGNAL(captureMapCoordinateClick(QPointF)), waypointsDockWidget->widget(), SLOT(addWaypointMouse(QPointF)));
837 838 839

        // 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)));
840
    }
841
}
842

843 844
void MainWindow::createCustomWidget()
{
845
    //qDebug() << "ADDING CUSTOM WIDGET";
lm's avatar
lm committed
846 847 848 849 850 851 852 853
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", this);

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

854
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
lm's avatar
lm committed
855
    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
856
    dock->setWidget(tool);
lm's avatar
lm committed
857 858 859 860 861 862
    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);
863
    dock->setVisible(true);
864 865 866 867
}

void MainWindow::connectPxWidgets()
{
868
    // No special connections necessary at this point
869 870 871 872
}

void MainWindow::connectSlugsWidgets()
{
873
    if (slugsHilSimWidget && slugsHilSimWidget->widget()){
874 875
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
876 877 878
    }

    if (slugsDataWidget && slugsDataWidget->widget()){
879 880
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsDataWidget->widget(), SLOT(setActiveUAS(UASInterface*)));
881 882
    }

883

884 885
}

886
void MainWindow::arrangeCommonCenterStack()
887
{
888
    centerStack = new QStackedWidget(this);
889
    centerStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
890

pixhawk's avatar
pixhawk committed
891
    if (!centerStack) return;
892

893
    if (mapWidget && (centerStack->indexOf(mapWidget) == -1)) centerStack->addWidget(mapWidget);
lm's avatar
lm committed
894
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
895
    if (protocolWidget && (centerStack->indexOf(protocolWidget) == -1)) centerStack->addWidget(protocolWidget);
896 897 898 899 900 901 902

    setCentralWidget(centerStack);
}

void MainWindow::arrangePxCenterStack()
{

903 904 905 906
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
907

908 909

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

911
#ifdef QGC_OSG_ENABLED
912
    if (_3DWidget && (centerStack->indexOf(_3DWidget) == -1)) centerStack->addWidget(_3DWidget);
913
#endif
914
#ifdef QGC_OSGEARTH_ENABLED
915
    if (_3DMapWidget && (centerStack->indexOf(_3DMapWidget) == -1)) centerStack->addWidget(_3DMapWidget);
916
#endif
917
#if (defined _MSC_VER) | (defined Q_OS_MAC)
918
    if (gEarthWidget && (centerStack->indexOf(gEarthWidget) == -1)) centerStack->addWidget(gEarthWidget);
919
#endif
920 921
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
922 923 924 925 926
}

void MainWindow::arrangeSlugsCenterStack()
{

927 928 929 930
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
931

932 933
    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
934

935 936
}

937 938
void MainWindow::configureWindowName()
{
pixhawk's avatar
pixhawk committed
939 940 941
    QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
    QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
    bool prevAddr = false;
942

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

pixhawk's avatar
pixhawk committed
945 946 947 948 949 950 951 952 953 954
    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;
        }
    }
955

pixhawk's avatar
pixhawk committed
956
    windowname.append(")");
957

pixhawk's avatar
pixhawk committed
958
    setWindowTitle(windowname);
959 960

#ifndef Q_WS_MAC
pixhawk's avatar
pixhawk committed
961
    //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
962 963 964
#endif
}

pixhawk's avatar
pixhawk committed
965
void MainWindow::startVideoCapture()
pixhawk's avatar
pixhawk committed
966 967 968 969 970 971 972 973 974 975 976
{
    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);
977 978 979
    //videoTimer->setInterval(40);
    //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
    //videoTimer->stop();
pixhawk's avatar
pixhawk committed
980 981
}

pixhawk's avatar
pixhawk committed
982
void MainWindow::stopVideoCapture()
pixhawk's avatar
pixhawk committed
983 984 985 986 987 988
{
    videoTimer->stop();

    // TODO Convert raw images to PNG
}

pixhawk's avatar
pixhawk committed
989
void MainWindow::saveScreen()
pixhawk's avatar
pixhawk committed
990 991 992 993 994 995 996 997 998 999
{
    QPixmap window = QPixmap::grabWindow(this->winId());
    QString format = "bmp";

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

1000 1001 1002 1003 1004 1005
/**
 * 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
1006
void MainWindow::reloadStylesheet()
pixhawk's avatar
pixhawk committed
1007
{
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
    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
1025
    // Load style sheet
1026
    QFile* styleSheet = new QFile(fileName);
1027 1028 1029 1030
    if (!styleSheet->exists())
    {
        styleSheet = new QFile(":/images/style-mission.css");
    }
1031 1032
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
    {
1033 1034
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
pixhawk's avatar
pixhawk committed
1035
        qApp->setStyleSheet(style);
1036 1037 1038
    }
    else
    {
1039 1040 1041 1042 1043 1044 1045
        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
1046
    }
1047
    delete styleSheet;
pixhawk's avatar
pixhawk committed
1048 1049
}

1050 1051 1052 1053 1054 1055
/**
 * 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
1056
void MainWindow::showStatusMessage(const QString& status, int timeout)
pixhawk's avatar
pixhawk committed
1057
{
lm's avatar
lm committed
1058
    statusBar()->showMessage(status, timeout);
pixhawk's avatar
pixhawk committed
1059 1060
}

1061 1062 1063 1064 1065 1066
/**
 * 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
 */
1067
void MainWindow::showStatusMessage(const QString& status)
pixhawk's avatar
pixhawk committed
1068
{
lm's avatar
lm committed
1069
    statusBar()->showMessage(status, 20000);
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
}

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
1081 1082
}

lm's avatar
lm committed
1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
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
1094 1095 1096 1097
/**
* @brief Create all actions associated to the main window
*
**/
1098
void MainWindow::connectCommonActions()
pixhawk's avatar
pixhawk committed
1099 1100 1101 1102 1103 1104
{
    // 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*)));
1105
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
pixhawk's avatar
pixhawk committed
1106

1107
    // Unmanned System controls
pixhawk's avatar
pixhawk committed
1108 1109 1110 1111 1112 1113 1114
    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()));

1115
    // Views actions
1116
    connect(ui.actionPilotsView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
1117
    connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
1118
    connect(ui.actionOperatorsView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
1119

1120 1121
    connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
    connect(ui.actionReloadStyle, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
1122

1123
    // Help Actions
1124
    connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
1125
    connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
1126
    connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
1127 1128 1129 1130
}

void MainWindow::connectPxActions()
{
1131
    ui.actionJoystickSettings->setVisible(true);
1132

1133 1134
    // Joystick configuration
    connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
1135 1136 1137 1138 1139

}

void MainWindow::connectSlugsActions()
{
1140

pixhawk's avatar
pixhawk committed
1141 1142
}

1143 1144
void MainWindow::showHelp()
{
1145
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/")))
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
    {
        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()
{
1159
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits/")))
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
    {
        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()
{
1173
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/roadmap/")))
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184
    {
        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
1185
void MainWindow::configure()
pixhawk's avatar
pixhawk committed
1186 1187 1188 1189
{
    joystickWidget = new JoystickWidget(joystick, this);
}

pixhawk's avatar
pixhawk committed
1190
void MainWindow::addLink()
pixhawk's avatar
pixhawk committed
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203
{
    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
1204 1205
void MainWindow::addLink(LinkInterface *link)
{
1206
    LinkManager::instance()->addProtocol(link, mavlink);
pixhawk's avatar
pixhawk committed
1207 1208 1209
    CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);
    ui.menuNetwork->addAction(commWidget->getAction());

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

pixhawk's avatar
pixhawk committed
1212 1213 1214 1215
    // Special case for simulationlink
    MAVLinkSimulationLink* sim = dynamic_cast<MAVLinkSimulationLink*>(link);
    if (sim)
    {
1216
        //connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64)));
pixhawk's avatar
pixhawk committed
1217 1218 1219 1220
        connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool)));
    }
}

1221 1222 1223 1224 1225 1226 1227
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
1228
void MainWindow::UASCreated(UASInterface* uas)
pixhawk's avatar
pixhawk committed
1229
{
1230

pixhawk's avatar
pixhawk committed
1231 1232
    // Connect the UAS to the full user interface

1233 1234
    if (uas != NULL)
    {
1235 1236 1237
        // The pilot view was not available on startup, enable it now
        ui.actionPilotsView->setEnabled(true);

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
        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
1268 1269
        if (debugConsoleDockWidget)
        {
pixhawk's avatar
pixhawk committed
1270 1271 1272 1273 1274 1275
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
            if (debugConsole)
            {
                connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)),
                        debugConsole, SLOT(receiveTextMessage(int,int,int,QString)));
            }
1276
        }
1277 1278

        // Health / System status indicator
1279 1280
        if (infoDockWidget)
        {
pixhawk's avatar
pixhawk committed
1281 1282 1283 1284 1285
            UASInfoWidget *infoWidget = dynamic_cast<UASInfoWidget*>(infoDockWidget->widget());
            if (infoWidget)
            {
                infoWidget->addUAS(uas);
            }
1286
        }
1287 1288

        // UAS List
1289 1290
        if (listDockWidget)
        {
pixhawk's avatar
pixhawk committed
1291 1292 1293 1294 1295
            UASListWidget *listWidget = dynamic_cast<UASListWidget*>(listDockWidget->widget());
            if (listWidget)
            {
                listWidget->addUAS(uas);
            }
1296
        }
1297

1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355
        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)
        {
1356
            //qDebug() << "UPDATING THE VIEW SINCE THIS IS THE FIRST CONNECTED SYSTEM";
1357 1358

            // Load last view if setting is present
1359
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
1360
            {
1361
                int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
1362 1363
                currentView = (VIEW_SECTIONS) view;
                presentView();
1364 1365 1366 1367 1368 1369 1370

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

1371 1372 1373 1374 1375
            }
            else
            {
                loadEngineerView();
            }
1376
        }
1377

1378
    }
1379 1380

    if (!ui.menuConnected_Systems->isEnabled()) ui.menuConnected_Systems->setEnabled(true);
lm's avatar
lm committed
1381 1382 1383

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

1386 1387 1388
/**
 * Clears the current view completely
 */
pixhawk's avatar
pixhawk committed
1389
void MainWindow::clearView()
1390
{
1391 1392 1393
    // Save current state
    if (UASManager::instance()->getActiveUAS()) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
    settings.setValue(getWindowGeometryKey(), saveGeometry());
1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404

    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)
        {
1405
            //qDebug() << "TOOL:" << chKey << "IS:" << temp->isChecked();
1406 1407 1408 1409
            settings.setValue(chKey,temp->isChecked());
        }
        else
        {
1410
            //qDebug() << "TOOL:" << chKey << "IS DEFAULT AND UNCHECKED";
1411 1412 1413 1414
            settings.setValue(chKey,false);
        }
    }

1415
    changingViewsFlag = true;
1416 1417
    // Remove all dock widgets from main window
    QObjectList childList( this->children() );
pixhawk's avatar
pixhawk committed
1418

1419 1420 1421
    QObjectList::iterator i;
    QDockWidget* dockWidget;
    for (i = childList.begin(); i != childList.end(); ++i)
pixhawk's avatar
pixhawk committed
1422
    {
1423 1424
        dockWidget = dynamic_cast<QDockWidget*>(*i);
        if (dockWidget)
pixhawk's avatar
pixhawk committed
1425
        {
1426
            // Remove dock widget from main window
1427 1428
            //this->removeDockWidget(dockWidget);
            dockWidget->setVisible(false);
1429 1430 1431
            // 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
1432 1433
        }
    }
1434
    changingViewsFlag = false;
pixhawk's avatar
pixhawk committed
1435 1436
}

1437
void MainWindow::loadEngineerView()
lm's avatar
lm committed
1438
{
1439 1440 1441
    if (currentView != VIEW_ENGINEER)
    {
        clearView();
lm's avatar
lm committed
1442

1443
        currentView = VIEW_ENGINEER;
lm's avatar
lm committed
1444

1445 1446
        presentView();
    }
lm's avatar
lm committed
1447 1448
}

1449
void MainWindow::loadOperatorView()
lm's avatar
lm committed
1450
{
1451 1452 1453
    if (currentView != VIEW_OPERATOR)
    {
        clearView();
1454

1455
        currentView = VIEW_OPERATOR;
lm's avatar
lm committed
1456

1457 1458
        presentView();
    }
lm's avatar
lm committed
1459 1460
}

1461
void MainWindow::loadPilotView()
1462
{
1463 1464 1465
    if (currentView != VIEW_PILOT)
    {
        clearView();
1466

1467
        currentView = VIEW_PILOT;
1468

1469 1470
        presentView();
    }
1471 1472
}

1473
void MainWindow::loadMAVLinkView()
1474
{
1475 1476 1477
    if (currentView != VIEW_MAVLINK)
    {
        clearView();
pixhawk's avatar
pixhawk committed
1478

1479
        currentView = VIEW_MAVLINK;
1480

1481 1482
        presentView();
    }
1483 1484
}

lm's avatar
lm committed
1485 1486
void MainWindow::presentView()
{
1487
    // LINE CHART
1488
    showTheCentralWidget(CENTRAL_LINECHART, currentView);
1489

1490 1491
    // MAP
    showTheCentralWidget(CENTRAL_MAP, currentView);
pixhawk's avatar
pixhawk committed
1492

1493 1494
    // PROTOCOL
    showTheCentralWidget(CENTRAL_PROTOCOL, currentView);
pixhawk's avatar
pixhawk committed
1495

1496 1497
    // HEAD UP DISPLAY
    showTheCentralWidget(CENTRAL_HUD, currentView);
pixhawk's avatar
pixhawk committed
1498 1499 1500 1501 1502 1503 1504 1505 1506 1507

    // GOOGLE EARTH
    showTheCentralWidget(CENTRAL_GOOGLE_EARTH, currentView);

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

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

1508 1509 1510
    // DATA PLOT
    showTheCentralWidget(CENTRAL_DATA_PLOT, currentView);

pixhawk's avatar
pixhawk committed
1511

pixhawk's avatar
pixhawk committed
1512

1513
    // Show docked widgets based on current view and autopilot type
1514

1515 1516
    // UAS CONTROL
    showTheWidget(MENU_UAS_CONTROL, currentView);
1517

1518 1519
    // UAS LIST
    showTheWidget(MENU_UAS_LIST, currentView);
1520

1521 1522
    // WAYPOINT LIST
    showTheWidget(MENU_WAYPOINTS, currentView);
pixhawk's avatar
pixhawk committed
1523

1524 1525
    // UAS STATUS
    showTheWidget(MENU_STATUS, currentView);
1526

1527 1528
    // DETECTION
    showTheWidget(MENU_DETECTION, currentView);
1529

1530 1531
    // DEBUG CONSOLE
    showTheWidget(MENU_DEBUG_CONSOLE, currentView);
1532

1533 1534
    // ONBOARD PARAMETERS
    showTheWidget(MENU_PARAMETERS, currentView);
1535

1536 1537
    // WATCHDOG
    showTheWidget(MENU_WATCHDOG, currentView);
1538

1539 1540 1541 1542 1543
    // HUD
    showTheWidget(MENU_HUD, currentView);
    if (headUpDockWidget)
    {
        HUD* tmpHud = dynamic_cast<HUD*>( headUpDockWidget->widget() );
1544 1545 1546 1547
        if (tmpHud)
        {
            if (settings.value(buildMenuKey (SUB_SECTION_CHECKED,MENU_HUD,currentView)).toBool())
            {
1548 1549 1550
                addDockWidget(static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,MENU_HUD, currentView)).toInt()),
                              hsiDockWidget);
                headUpDockWidget->show();
1551 1552 1553
            }
            else
            {
1554 1555
                headUpDockWidget->hide();
            }
1556
        }
1557
    }
1558

1559

1560 1561
    // RC View
    showTheWidget(MENU_RC_VIEW, currentView);
1562

1563 1564
    // SLUGS DATA
    showTheWidget(MENU_SLUGS_DATA, currentView);
1565

1566 1567
    // SLUGS PID
    showTheWidget(MENU_SLUGS_PID, currentView);
1568

1569 1570
    // SLUGS HIL
    showTheWidget(MENU_SLUGS_HIL, currentView);
1571

1572 1573
    // SLUGS CAMERA
    showTheWidget(MENU_SLUGS_CAMERA, currentView);
1574

1575 1576
    // HORIZONTAL SITUATION INDICATOR
    showTheWidget(MENU_HSI, currentView);
1577

1578 1579 1580 1581 1582
    // HEAD DOWN 1
    showTheWidget(MENU_HDD_1, currentView);

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

1584 1585 1586
    // MAVLINK LOG PLAYER
    showTheWidget(MENU_MAVLINK_LOG_PLAYER, currentView);

1587
    this->show();
1588

1589
}
1590

1591 1592 1593 1594
void MainWindow::showTheCentralWidget (TOOLS_WIDGET_NAMES centralWidget, VIEW_SECTIONS view)
{
    bool tempVisible;
    QWidget* tempWidget = dockWidgets[centralWidget];
1595

1596
    tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view), false).toBool();
1597
    //qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
1598
    if (toolsMenuActions[centralWidget])
1599
    {
1600
        toolsMenuActions[centralWidget]->setChecked(tempVisible);
1601
    }
1602

1603
    if (centerStack && tempWidget && tempVisible)
1604
    {
1605
        centerStack->setCurrentWidget(tempWidget);
1606
    }
1607 1608
}

1609 1610
void MainWindow::loadDataView(QString fileName)
{
1611
    clearView();
1612 1613 1614 1615 1616

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

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

1621
    presentView();
1622

1623 1624
    // Plot is now selected, now load data from file
    if (dataplotWidget)
1625
    {
1626
        dataplotWidget->loadFile(fileName);
1627
    }
1628 1629 1630 1631 1632 1633 1634
//        QStackedWidget *centerStack = dynamic_cast<QStackedWidget*>(centralWidget());
//        if (centerStack)
//        {
//            centerStack->setCurrentWidget(dataplotWidget);
//            dataplotWidget->loadFile(fileName);
//        }
//    }
1635 1636 1637
}