MainWindow.cc 53 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
    settings.sync();
128

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

133 134
    setVisible(false);

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

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

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

152
    buildCommonWidgets();
153

154
    connectCommonWidgets();
155

156
    arrangeCommonCenterStack();
157 158

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

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

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

173
    // Create actions
174
    connectCommonActions();
175

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

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

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

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

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

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

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

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

pixhawk's avatar
pixhawk committed
212 213
}

214 215 216 217 218 219 220 221 222 223
QString MainWindow::getWindowStateKey()
{
    return QString::number(currentView)+"/windowstate";
}

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

lm's avatar
lm committed
224 225 226 227 228 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
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);
            }
        }
    }
}

261 262 263 264
void MainWindow::buildCommonWidgets()
{
    //TODO:  move protocol outside UI
    mavlink     = new MAVLinkProtocol();
265
    connect(mavlink, SIGNAL(protocolStatusMessage(QString,QString)), this, SLOT(showCriticalMessage(QString,QString)), Qt::QueuedConnection);
266 267

    // Dock widgets
268 269 270
    if (!controlDockWidget)
    {
        controlDockWidget = new QDockWidget(tr("Control"), this);
271
        controlDockWidget->setObjectName("UNMANNED_SYSTEM_CONTROL_DOCKWIDGET");
272 273 274
        controlDockWidget->setWidget( new UASControlWidget(this) );
        addToToolsMenu (controlDockWidget, tr("Control"), SLOT(showToolWidget()), MENU_UAS_CONTROL, Qt::LeftDockWidgetArea);
    }
275

276 277 278 279
    if (!listDockWidget)
    {
        listDockWidget = new QDockWidget(tr("Unmanned Systems"), this);
        listDockWidget->setWidget( new UASListWidget(this) );
280
        listDockWidget->setObjectName("UNMANNED_SYSTEMS_LIST_DOCKWIDGET");
281 282
        addToToolsMenu (listDockWidget, tr("Unmanned Systems"), SLOT(showToolWidget()), MENU_UAS_LIST, Qt::RightDockWidgetArea);
    }
283

284 285 286 287
    if (!waypointsDockWidget)
    {
        waypointsDockWidget = new QDockWidget(tr("Waypoint List"), this);
        waypointsDockWidget->setWidget( new WaypointList(this, NULL) );
288
        waypointsDockWidget->setObjectName("WAYPOINT_LIST_DOCKWIDGET");
289 290
        addToToolsMenu (waypointsDockWidget, tr("Waypoints List"), SLOT(showToolWidget()), MENU_WAYPOINTS, Qt::BottomDockWidgetArea);
    }
291

292 293 294 295
    if (!infoDockWidget)
    {
        infoDockWidget = new QDockWidget(tr("Status Details"), this);
        infoDockWidget->setWidget( new UASInfoWidget(this) );
pixhawk's avatar
pixhawk committed
296
        infoDockWidget->setObjectName("UAS_STATUS_DETAILS_DOCKWIDGET");
297 298
        addToToolsMenu (infoDockWidget, tr("Status Details"), SLOT(showToolWidget()), MENU_STATUS, Qt::RightDockWidgetArea);
    }
299

300 301 302 303
    if (!debugConsoleDockWidget)
    {
        debugConsoleDockWidget = new QDockWidget(tr("Communication Console"), this);
        debugConsoleDockWidget->setWidget( new DebugConsole(this) );
304
        debugConsoleDockWidget->setObjectName("COMMUNICATION_DEBUG_CONSOLE_DOCKWIDGET");
305 306
        addToToolsMenu (debugConsoleDockWidget, tr("Communication Console"), SLOT(showToolWidget()), MENU_DEBUG_CONSOLE, Qt::BottomDockWidgetArea);
    }
307

308 309 310 311 312 313
    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);
314
    }
315

316
    // Center widgets
317 318 319 320 321
    if (!mapWidget)
    {
        mapWidget         = new MapWidget(this);
        addToCentralWidgetsMenu (mapWidget, "Maps", SLOT(showCentralWidget()),CENTRAL_MAP);
    }
322

323 324 325 326 327
    if (!protocolWidget)
    {
        protocolWidget    = new XMLCommProtocolWidget(this);
        addToCentralWidgetsMenu (protocolWidget, "Mavlink Generator", SLOT(showCentralWidget()),CENTRAL_PROTOCOL);
    }
lm's avatar
lm committed
328

Alejandro's avatar
Alejandro committed
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
    //TODO temporaly debug
    if (!slugsHilSimWidget)
    {
        slugsHilSimWidget = new QDockWidget(tr("Slugs Hil Sim"), this);
        slugsHilSimWidget->setWidget( new SlugsHilSim(this));
        addToToolsMenu (slugsHilSimWidget, tr("HIL Sim Configuration"), SLOT(showToolWidget()), MENU_SLUGS_HIL, Qt::LeftDockWidgetArea);
    }

    //TODO temporaly debug
    if (!slugsCamControlWidget)
    {
        slugsCamControlWidget = new QDockWidget(tr("Slugs Video Camera Control"), this);
        slugsCamControlWidget->setWidget(new SlugsVideoCamControl(this));
        addToToolsMenu (slugsCamControlWidget, tr("Camera Control"), SLOT(showToolWidget()), MENU_SLUGS_CAMERA, Qt::BottomDockWidgetArea);
    }
lm's avatar
lm committed
344 345 346 347 348
    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu (dataplotWidget, "Data Plot", SLOT(showCentralWidget()),CENTRAL_DATA_PLOT);
    }
349
}
350

351
void MainWindow::buildPxWidgets()
352
{
pixhawk's avatar
pixhawk committed
353 354
    //FIXME: memory of acceptList will never be freed again
    QStringList* acceptList = new QStringList();
lm's avatar
lm committed
355 356 357
    acceptList->append("-105,roll,deg,+105,s");
    acceptList->append("-105,pitch,deg,+105,s");
    acceptList->append("-105,yaw,deg,+105,s");
358

lm's avatar
lm committed
359 360 361
    acceptList->append("-260,rollspeed,deg/s,+260,s");
    acceptList->append("-260,pitchspeed,deg/s,+260,s");
    acceptList->append("-260,yawspeed,deg/s,+260,s");
362

pixhawk's avatar
pixhawk committed
363 364
    //FIXME: memory of acceptList2 will never be freed again
    QStringList* acceptList2 = new QStringList();
lm's avatar
lm committed
365
    acceptList2->append("0,abs pressure,hPa,65500");
366 367
    acceptList2->append("-999,accel. X,raw,999,s");
    acceptList2->append("-999,accel. Y,raw,999,s");
368

369 370 371 372 373 374
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
        addToCentralWidgetsMenu(linechartWidget, "Line Plots", SLOT(showCentralWidget()), CENTRAL_LINECHART);
    }
375 376


377 378 379 380 381
    if (!hudWidget)
    {
        hudWidget         = new HUD(320, 240, this);
        addToCentralWidgetsMenu(hudWidget, "HUD", SLOT(showCentralWidget()), CENTRAL_HUD);
    }
382

383 384 385 386 387
    if (!dataplotWidget)
    {
        dataplotWidget    = new QGCDataPlot2D(this);
        addToCentralWidgetsMenu(dataplotWidget, "Data Plots", SLOT(showCentralWidget()), CENTRAL_DATA_PLOT);
    }
388

389
#ifdef QGC_OSG_ENABLED
390 391 392 393 394
    if (!_3DWidget)
    {
        _3DWidget         = Q3DWidgetFactory::get("PIXHAWK");
        addToCentralWidgetsMenu(_3DWidget, "Local 3D", SLOT(showCentralWidget()), CENTRAL_3D_LOCAL);
    }
395
#endif
396

397
#ifdef QGC_OSGEARTH_ENABLED
398 399 400 401 402
    if (!_3DMapWidget)
    {
        _3DMapWidget = Q3DWidgetFactory::get("MAP3D");
        addToCentralWidgetsMenu(_3DMapWidget, "OSG Earth 3D", SLOT(showCentralWidget()), CENTRAL_OSGEARTH);
    }
403
#endif
lm's avatar
lm committed
404

405
#if (defined _MSC_VER) | (defined Q_OS_MAC)
406 407 408 409 410
    if (!gEarthWidget)
    {
        gEarthWidget = new QGCGoogleEarthView(this);
        addToCentralWidgetsMenu(gEarthWidget, "Google Earth", SLOT(showCentralWidget()), CENTRAL_GOOGLE_EARTH);
    }
411

412
#endif
413

pixhawk's avatar
pixhawk committed
414
    // Dock widgets
415

416 417 418 419
    if (!detectionDockWidget)
    {
        detectionDockWidget = new QDockWidget(tr("Object Recognition"), this);
        detectionDockWidget->setWidget( new ObjectDetectionView("images/patterns", this) );
pixhawk's avatar
pixhawk committed
420
        detectionDockWidget->setObjectName("OBJECT_DETECTION_DOCK_WIDGET");
421 422
        addToToolsMenu (detectionDockWidget, tr("Object Recognition"), SLOT(showToolWidget()), MENU_DETECTION, Qt::RightDockWidgetArea);
    }
423

424 425 426 427
    if (!parametersDockWidget)
    {
        parametersDockWidget = new QDockWidget(tr("Onboard Parameters"), this);
        parametersDockWidget->setWidget( new ParameterInterface(this) );
pixhawk's avatar
pixhawk committed
428
        parametersDockWidget->setObjectName("PARAMETER_INTERFACE_DOCKWIDGET");
429 430
        addToToolsMenu (parametersDockWidget, tr("Onboard Parameters"), SLOT(showToolWidget()), MENU_PARAMETERS, Qt::RightDockWidgetArea);
    }
431

432 433 434 435
    if (!watchdogControlDockWidget)
    {
        watchdogControlDockWidget = new QDockWidget(tr("Process Control"), this);
        watchdogControlDockWidget->setWidget( new WatchdogControl(this) );
pixhawk's avatar
pixhawk committed
436
        watchdogControlDockWidget->setObjectName("WATCHDOG_CONTROL_DOCKWIDGET");
437 438
        addToToolsMenu (watchdogControlDockWidget, tr("Process Control"), SLOT(showToolWidget()), MENU_WATCHDOG, Qt::BottomDockWidgetArea);
    }
439

440 441 442 443
    if (!hsiDockWidget)
    {
        hsiDockWidget = new QDockWidget(tr("Horizontal Situation Indicator"), this);
        hsiDockWidget->setWidget( new HSIDisplay(this) );
444
        hsiDockWidget->setObjectName("HORIZONTAL_SITUATION_INDICATOR_DOCK_WIDGET");
445 446
        addToToolsMenu (hsiDockWidget, tr("HSI"), SLOT(showToolWidget()), MENU_HSI, Qt::BottomDockWidgetArea);
    }
447

448 449
    if (!headDown1DockWidget)
    {
450 451
        headDown1DockWidget = new QDockWidget(tr("Flight Display"), this);
        headDown1DockWidget->setWidget( new HDDisplay(acceptList, "Flight Display", this) );
452
        headDown1DockWidget->setObjectName("HEAD_DOWN_DISPLAY_1_DOCK_WIDGET");
453 454
        addToToolsMenu (headDown1DockWidget, tr("Flight Display"), SLOT(showToolWidget()), MENU_HDD_1, Qt::RightDockWidgetArea);
    }
455

456 457 458
    if (!headDown2DockWidget)
    {
        headDown2DockWidget = new QDockWidget(tr("Payload Status"), this);
459
        headDown2DockWidget->setWidget( new HDDisplay(acceptList2, "Payload Status", this) );
460
        headDown2DockWidget->setObjectName("HEAD_DOWN_DISPLAY_2_DOCK_WIDGET");
461 462
        addToToolsMenu (headDown2DockWidget, tr("Payload Status"), SLOT(showToolWidget()), MENU_HDD_2, Qt::RightDockWidgetArea);
    }
463

464 465 466 467
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
468
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
469 470
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
471

472 473 474 475
    if (!headUpDockWidget)
    {
        headUpDockWidget = new QDockWidget(tr("HUD"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
476
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
477 478
        addToToolsMenu (headUpDockWidget, tr("Control Indicator"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
479

pixhawk's avatar
pixhawk committed
480 481
    // Dialogue widgets
    //FIXME: free memory in destructor
482 483 484 485
    if (!joystick)
    {
        joystick    = new JoystickInput();
    }
486

487 488 489 490
}

void MainWindow::buildSlugsWidgets()
{
491 492 493 494 495
    if (!linechartWidget)
    {
        // Center widgets
        linechartWidget   = new Linecharts(this);
    }
496

497 498 499 500 501
    if (!headUpDockWidget)
    {
        // Dock widgets
        headUpDockWidget = new QDockWidget(tr("Control Indicator"), this);
        headUpDockWidget->setWidget( new HUD(320, 240, this));
pixhawk's avatar
pixhawk committed
502
        headUpDockWidget->setObjectName("HEAD_UP_DISPLAY_DOCK_WIDGET");
503 504
        addToToolsMenu (headUpDockWidget, tr("HUD"), SLOT(showToolWidget()), MENU_HUD, Qt::LeftDockWidgetArea);
    }
505

506 507 508 509
    if (!rcViewDockWidget)
    {
        rcViewDockWidget = new QDockWidget(tr("Radio Control"), this);
        rcViewDockWidget->setWidget( new QGCRemoteControlView(this) );
pixhawk's avatar
pixhawk committed
510
        rcViewDockWidget->setObjectName("RADIO_CONTROL_CHANNELS_DOCK_WIDGET");
511 512
        addToToolsMenu (rcViewDockWidget, tr("Radio Control"), SLOT(showToolWidget()), MENU_RC_VIEW, Qt::BottomDockWidgetArea);
    }
513

514 515 516 517 518
    if (!slugsDataWidget)
    {
        // Dialog widgets
        slugsDataWidget = new QDockWidget(tr("Slugs Data"), this);
        slugsDataWidget->setWidget( new SlugsDataSensorView(this));
pixhawk's avatar
pixhawk committed
519
        slugsDataWidget->setObjectName("SLUGS_DATA_DOCK_WIDGET");
520 521
        addToToolsMenu (slugsDataWidget, tr("Telemetry Data"), SLOT(showToolWidget()), MENU_SLUGS_DATA, Qt::RightDockWidgetArea);
    }
522

523 524 525 526
    if (!slugsPIDControlWidget)
    {
        slugsPIDControlWidget = new QDockWidget(tr("Slugs PID Control"), this);
        slugsPIDControlWidget->setWidget(new SlugsPIDControl(this));
pixhawk's avatar
pixhawk committed
527
        slugsPIDControlWidget->setObjectName("SLUGS_PID_CONTROL_DOCK_WIDGET");
528 529
        addToToolsMenu (slugsPIDControlWidget, tr("PID Configuration"), SLOT(showToolWidget()), MENU_SLUGS_PID, Qt::LeftDockWidgetArea);
    }
530

531 532 533 534
    if (!slugsHilSimWidget)
    {
        slugsHilSimWidget = new QDockWidget(tr("Slugs Hil Sim"), this);
        slugsHilSimWidget->setWidget( new SlugsHilSim(this));
pixhawk's avatar
pixhawk committed
535
        slugsHilSimWidget->setObjectName("SLUGS_HIL_SIM_DOCK_WIDGET");
536 537
        addToToolsMenu (slugsHilSimWidget, tr("HIL Sim Configuration"), SLOT(showToolWidget()), MENU_SLUGS_HIL, Qt::LeftDockWidgetArea);
    }
538

539 540 541 542
    if (!slugsCamControlWidget)
    {
        slugsCamControlWidget = new QDockWidget(tr("Slugs Video Camera Control"), this);
        slugsCamControlWidget->setWidget(new SlugsVideoCamControl(this));
pixhawk's avatar
pixhawk committed
543
        slugsCamControlWidget->setObjectName("SLUGS_CAM_CONTROL_DOCK_WIDGET");
544 545
        addToToolsMenu (slugsCamControlWidget, tr("Camera Control"), SLOT(showToolWidget()), MENU_SLUGS_CAMERA, Qt::BottomDockWidgetArea);
    }
546
}
547 548 549 550 551


void MainWindow::addToCentralWidgetsMenu ( QWidget* widget,
                                           const QString title,
                                           const char * slotName,
552 553
                                           TOOLS_WIDGET_NAMES centralWidget)
{
554
    QAction* tempAction;
555

556

557
    // Add the separator that will separate tools from central Widgets
558 559
    if (!toolsMenuActions[CENTRAL_SEPARATOR])
    {
560 561 562 563
        tempAction = ui.menuTools->addSeparator();
        toolsMenuActions[CENTRAL_SEPARATOR] = tempAction;
        tempAction->setData(CENTRAL_SEPARATOR);
    }
564

565
    tempAction = ui.menuTools->addAction(title);
566

567 568
    tempAction->setCheckable(true);
    tempAction->setData(centralWidget);
569

570 571 572
    // populate the Hashes
    toolsMenuActions[centralWidget] = tempAction;
    dockWidgets[centralWidget] = widget;
573

574
    QString chKey = buildMenuKey(SUB_SECTION_CHECKED, centralWidget, currentView);
575

576 577
    if (!settings.contains(chKey))
    {
578 579 580
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
    }
581 582 583 584
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
    }
585

586 587
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
588 589 590
}


lm's avatar
lm committed
591 592
void MainWindow::showCentralWidget()
{
593 594 595
    QAction* senderAction = qobject_cast<QAction *>(sender());
    int tool = senderAction->data().toInt();
    QString chKey;
596

597
    // check the current action
598

599 600
    if (senderAction && dockWidgets[tool])
    {
601

602 603
        // uncheck all central widget actions
        QHashIterator<int, QAction*> i(toolsMenuActions);
604 605
        while (i.hasNext())
        {
606
            i.next();
607 608 609
            //qDebug() << "shCW" << i.key() << "read";
            if (i.value() && i.value()->data().toInt() > 255)
            {
610
                i.value()->setChecked(false);
611

612 613 614 615 616
                // update the settings
                chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.value()->data().toInt()), currentView);
                settings.setValue(chKey,false);
            }
        }
617

618
        // check the current action
619
        //qDebug() << senderAction->text();
620
        senderAction->setChecked(true);
621

622 623
        // update the central widget
        centerStack->setCurrentWidget(dockWidgets[tool]);
624

625 626 627
        // store the selected central widget
        chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(tool), currentView);
        settings.setValue(chKey,true);
628

629 630
        presentView();
    }
631
}
632

lm's avatar
lm committed
633 634 635 636
/**
 * Adds a widget to the tools menu and sets it visible if it was
 * enabled last time.
 */
637
void MainWindow::addToToolsMenu ( QWidget* widget,
638 639 640 641
                                  const QString title,
                                  const char * slotName,
                                  TOOLS_WIDGET_NAMES tool,
                                  Qt::DockWidgetArea location)
lm's avatar
lm committed
642
{
643 644
    QAction* tempAction;
    QString posKey, chKey;
645

646

647 648
    if (toolsMenuActions[CENTRAL_SEPARATOR])
    {
649 650 651
        tempAction = new QAction(title, this);
        ui.menuTools->insertAction(toolsMenuActions[CENTRAL_SEPARATOR],
                                   tempAction);
652 653 654
    }
    else
    {
655 656
        tempAction = ui.menuTools->addAction(title);
    }
657

658 659
    tempAction->setCheckable(true);
    tempAction->setData(tool);
660

661 662 663
    // populate the Hashes
    toolsMenuActions[tool] = tempAction;
    dockWidgets[tool] = widget;
664
    //qDebug() << widget;
665

666
    posKey = buildMenuKey (SUB_SECTION_LOCATION,tool, currentView);
667

668 669
    if (!settings.contains(posKey))
    {
670 671
        settings.setValue(posKey,location);
        dockWidgetLocations[tool] = location;
672 673 674 675
    }
    else
    {
        dockWidgetLocations[tool] = static_cast <Qt::DockWidgetArea> (settings.value(posKey, Qt::RightDockWidgetArea).toInt());
676
    }
677

678
    chKey = buildMenuKey(SUB_SECTION_CHECKED,tool, currentView);
679

680 681 682 683
    if (!settings.contains(chKey))
    {
        settings.setValue(chKey,false);
        tempAction->setChecked(false);
684
        widget->setVisible(false);
685 686 687 688
    }
    else
    {
        tempAction->setChecked(settings.value(chKey).toBool());
689
        widget->setVisible(settings.value(chKey, false).toBool());
690
    }
691

692 693
    // connect the action
    connect(tempAction,SIGNAL(triggered()),this, slotName);
694

695 696
//  connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
//          SIGNAL(visibilityChanged(bool)), this, SLOT(updateVisibilitySettings(bool)));
697

698 699
    connect(qobject_cast <QDockWidget *>(dockWidgets[tool]),
            SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(updateLocationSettings(Qt::DockWidgetArea)));
700 701 702

}

703 704 705 706
void MainWindow::showToolWidget()
{
    QAction* temp = qobject_cast<QAction *>(sender());
    int tool = temp->data().toInt();
707

708 709 710 711 712 713 714 715 716 717 718
    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]));
        }
719
    }
720

721 722 723
}


724 725 726 727 728
void MainWindow::showTheWidget (TOOLS_WIDGET_NAMES widget, VIEW_SECTIONS view)
{
    bool tempVisible;
    Qt::DockWidgetArea tempLocation;
    QDockWidget* tempWidget = static_cast <QDockWidget *>(dockWidgets[widget]);
729

730
    tempVisible =  settings.value(buildMenuKey(SUB_SECTION_CHECKED,widget,view), false).toBool();
731

732 733 734 735
    if (tempWidget)
    {
        toolsMenuActions[widget]->setChecked(tempVisible);
    }
736 737


738
    //qDebug() <<  buildMenuKey (SUB_SECTION_CHECKED,widget,view) << tempVisible;
739

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

742 743 744 745 746 747 748
    //    if (widget == MainWindow::MENU_UAS_LIST)
    //    {
    //        if (!settings.contains(buildMenuKey (SUB_SECTION_LOCATION,widget, view)))
    //        {
    //            tempLocation = Qt::RightDockWidgetArea;
    //        }
    //    }
749

750
    if ((tempWidget != NULL) && tempVisible)
751 752 753 754
    {
        addDockWidget(tempLocation, tempWidget);
        tempWidget->show();
    }
755 756 757

}

758 759 760 761 762 763 764 765 766 767 768 769 770 771
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) + "/" );
772 773
}

774 775
void MainWindow::closeEvent(QCloseEvent *event)
{
776
    settings.setValue(getWindowGeometryKey(), saveGeometry());
777 778
    //settings.setValue("windowState", saveState());
    aboutToCloseFlag = true;
779 780 781 782 783 784
    // 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);
785 786 787
    settings.sync();
    QMainWindow::closeEvent(event);
}
788

789

790 791
void MainWindow::updateVisibilitySettings (bool vis)
{
792
    if (!aboutToCloseFlag && !changingViewsFlag)
793 794
    {
        QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
795

796 797 798
        if (temp)
        {
            QHashIterator<int, QWidget*> i(dockWidgets);
799
        while (i.hasNext()) {
800
                i.next();
801
          if ((static_cast <QDockWidget *>(dockWidgets[i.key()])) == temp) {
802 803
                    QString chKey = buildMenuKey (SUB_SECTION_CHECKED,static_cast<TOOLS_WIDGET_NAMES>(i.key()), currentView);
                    settings.setValue(chKey,vis);
804 805 806 807 808 809
                    toolsMenuActions[i.key()]->setChecked(vis);
                    break;
                }
            }
        }
    }
810 811
}

812 813 814
void MainWindow::updateLocationSettings (Qt::DockWidgetArea location)
{
    QDockWidget* temp = qobject_cast<QDockWidget *>(sender());
815

816 817 818 819 820 821 822 823 824 825 826
    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;
        }
    }
827 828
}

829 830 831
/**
 * Connect the signals and slots of the common window widgets
 */
832
void MainWindow::connectCommonWidgets()
833
{
pixhawk's avatar
pixhawk committed
834 835 836 837 838
    if (infoDockWidget && infoDockWidget->widget())
    {
        connect(mavlink, SIGNAL(receiveLossChanged(int, float)),
                infoDockWidget->widget(), SLOT(updateSendLoss(int, float)));
    }
839

pixhawk's avatar
pixhawk committed
840 841 842
    if (mapWidget && waypointsDockWidget->widget())
    {
        // clear path create on the map
843
        connect(waypointsDockWidget->widget(), SIGNAL(clearPathclicked()), mapWidget, SLOT(clearWaypoints()));
pixhawk's avatar
pixhawk committed
844 845
        // add Waypoint widget in the WaypointList widget when mouse clicked
        connect(mapWidget, SIGNAL(captureMapCoordinateClick(QPointF)), waypointsDockWidget->widget(), SLOT(addWaypointMouse(QPointF)));
846 847 848

        // 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)));
849
    }
Alejandro's avatar
Alejandro committed
850 851 852 853 854 855

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

858 859
void MainWindow::createCustomWidget()
{
860
    //qDebug() << "ADDING CUSTOM WIDGET";
lm's avatar
lm committed
861 862 863 864 865 866 867 868
    QGCToolWidget* tool = new QGCToolWidget("Unnamed Tool", this);

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

869
    QDockWidget* dock = new QDockWidget("Unnamed Tool", this);
lm's avatar
lm committed
870
    connect(tool, SIGNAL(destroyed()), dock, SLOT(deleteLater()));
871
    dock->setWidget(tool);
lm's avatar
lm committed
872 873 874 875 876 877
    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);
878
    dock->setVisible(true);
879 880 881 882
}

void MainWindow::connectPxWidgets()
{
883
    // No special connections necessary at this point
884 885 886 887
}

void MainWindow::connectSlugsWidgets()
{
888
    if (slugsHilSimWidget && slugsHilSimWidget->widget()){
889 890
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsHilSimWidget->widget(), SLOT(activeUasSet(UASInterface*)));
891 892 893
    }

    if (slugsDataWidget && slugsDataWidget->widget()){
894 895
        connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)),
                slugsDataWidget->widget(), SLOT(setActiveUAS(UASInterface*)));
896 897
    }

898

899 900
}

901
void MainWindow::arrangeCommonCenterStack()
902
{
903
    centerStack = new QStackedWidget(this);
904
    centerStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
905

pixhawk's avatar
pixhawk committed
906
    if (!centerStack) return;
907

908
    if (mapWidget && (centerStack->indexOf(mapWidget) == -1)) centerStack->addWidget(mapWidget);
lm's avatar
lm committed
909
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
910
    if (protocolWidget && (centerStack->indexOf(protocolWidget) == -1)) centerStack->addWidget(protocolWidget);
911 912 913 914 915 916 917

    setCentralWidget(centerStack);
}

void MainWindow::arrangePxCenterStack()
{

918 919 920 921
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
922

923 924

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

926
#ifdef QGC_OSG_ENABLED
927
    if (_3DWidget && (centerStack->indexOf(_3DWidget) == -1)) centerStack->addWidget(_3DWidget);
928
#endif
929
#ifdef QGC_OSGEARTH_ENABLED
930
    if (_3DMapWidget && (centerStack->indexOf(_3DMapWidget) == -1)) centerStack->addWidget(_3DMapWidget);
931
#endif
932
#if (defined _MSC_VER) | (defined Q_OS_MAC)
933
    if (gEarthWidget && (centerStack->indexOf(gEarthWidget) == -1)) centerStack->addWidget(gEarthWidget);
934
#endif
935 936
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
    if (dataplotWidget && (centerStack->indexOf(dataplotWidget) == -1)) centerStack->addWidget(dataplotWidget);
937 938 939 940 941
}

void MainWindow::arrangeSlugsCenterStack()
{

942 943 944 945
    if (!centerStack) {
        qDebug() << "Center Stack not Created!";
        return;
    }
946

947 948
    if (linechartWidget && (centerStack->indexOf(linechartWidget) == -1)) centerStack->addWidget(linechartWidget);
    if (hudWidget && (centerStack->indexOf(hudWidget) == -1)) centerStack->addWidget(hudWidget);
949

950 951
}

952 953
void MainWindow::configureWindowName()
{
pixhawk's avatar
pixhawk committed
954 955 956
    QList<QHostAddress> hostAddresses = QNetworkInterface::allAddresses();
    QString windowname = qApp->applicationName() + " " + qApp->applicationVersion();
    bool prevAddr = false;
957

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

pixhawk's avatar
pixhawk committed
960 961 962 963 964 965 966 967 968 969
    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;
        }
    }
970

pixhawk's avatar
pixhawk committed
971
    windowname.append(")");
972

pixhawk's avatar
pixhawk committed
973
    setWindowTitle(windowname);
974 975

#ifndef Q_WS_MAC
pixhawk's avatar
pixhawk committed
976
    //qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
977 978 979
#endif
}

pixhawk's avatar
pixhawk committed
980
void MainWindow::startVideoCapture()
pixhawk's avatar
pixhawk committed
981 982 983 984 985 986 987 988 989 990 991
{
    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);
992 993 994
    //videoTimer->setInterval(40);
    //connect(videoTimer, SIGNAL(timeout()), this, SLOT(saveScreen()));
    //videoTimer->stop();
pixhawk's avatar
pixhawk committed
995 996
}

pixhawk's avatar
pixhawk committed
997
void MainWindow::stopVideoCapture()
pixhawk's avatar
pixhawk committed
998 999 1000 1001 1002 1003
{
    videoTimer->stop();

    // TODO Convert raw images to PNG
}

pixhawk's avatar
pixhawk committed
1004
void MainWindow::saveScreen()
pixhawk's avatar
pixhawk committed
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
{
    QPixmap window = QPixmap::grabWindow(this->winId());
    QString format = "bmp";

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

1015 1016 1017 1018 1019 1020
/**
 * 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
1021
void MainWindow::reloadStylesheet()
pixhawk's avatar
pixhawk committed
1022
{
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
    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
1040
    // Load style sheet
1041
    QFile* styleSheet = new QFile(fileName);
1042 1043 1044 1045
    if (!styleSheet->exists())
    {
        styleSheet = new QFile(":/images/style-mission.css");
    }
1046 1047
    if (styleSheet->open(QIODevice::ReadOnly | QIODevice::Text))
    {
1048 1049
        QString style = QString(styleSheet->readAll());
        style.replace("ICONDIR", QCoreApplication::applicationDirPath()+ "/images/");
pixhawk's avatar
pixhawk committed
1050
        qApp->setStyleSheet(style);
1051 1052 1053
    }
    else
    {
1054 1055 1056 1057 1058 1059 1060
        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
1061
    }
1062
    delete styleSheet;
pixhawk's avatar
pixhawk committed
1063 1064
}

1065 1066 1067 1068 1069 1070
/**
 * 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
1071
void MainWindow::showStatusMessage(const QString& status, int timeout)
pixhawk's avatar
pixhawk committed
1072
{
lm's avatar
lm committed
1073
    statusBar()->showMessage(status, timeout);
pixhawk's avatar
pixhawk committed
1074 1075
}

1076 1077 1078 1079 1080 1081
/**
 * 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
 */
1082
void MainWindow::showStatusMessage(const QString& status)
pixhawk's avatar
pixhawk committed
1083
{
lm's avatar
lm committed
1084
    statusBar()->showMessage(status, 20000);
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
}

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
1096 1097
}

lm's avatar
lm committed
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
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
1109 1110 1111 1112
/**
* @brief Create all actions associated to the main window
*
**/
1113
void MainWindow::connectCommonActions()
pixhawk's avatar
pixhawk committed
1114 1115 1116 1117 1118 1119
{
    // 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*)));
1120
    connect(UASManager::instance(), SIGNAL(activeUASSet(UASInterface*)), this, SLOT(setActiveUAS(UASInterface*)));
pixhawk's avatar
pixhawk committed
1121

1122
    // Unmanned System controls
pixhawk's avatar
pixhawk committed
1123 1124 1125 1126 1127 1128 1129
    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()));

1130
    // Views actions
1131
    connect(ui.actionPilotsView, SIGNAL(triggered()), this, SLOT(loadPilotView()));
1132
    connect(ui.actionEngineersView, SIGNAL(triggered()), this, SLOT(loadEngineerView()));
1133
    connect(ui.actionOperatorsView, SIGNAL(triggered()), this, SLOT(loadOperatorView()));
1134

1135 1136
    connect(ui.actionMavlinkView, SIGNAL(triggered()), this, SLOT(loadMAVLinkView()));
    connect(ui.actionReloadStyle, SIGNAL(triggered()), this, SLOT(reloadStylesheet()));
1137

1138
    // Help Actions
1139
    connect(ui.actionOnline_Documentation, SIGNAL(triggered()), this, SLOT(showHelp()));
1140
    connect(ui.actionDeveloper_Credits, SIGNAL(triggered()), this, SLOT(showCredits()));
1141
    connect(ui.actionProject_Roadmap_2, SIGNAL(triggered()), this, SLOT(showRoadMap()));
1142 1143 1144 1145
}

void MainWindow::connectPxActions()
{
1146
    ui.actionJoystickSettings->setVisible(true);
1147

1148 1149
    // Joystick configuration
    connect(ui.actionJoystickSettings, SIGNAL(triggered()), this, SLOT(configure()));
1150 1151 1152 1153 1154

}

void MainWindow::connectSlugsActions()
{
1155

pixhawk's avatar
pixhawk committed
1156 1157
}

1158 1159
void MainWindow::showHelp()
{
1160
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/users/")))
1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
    {
        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()
{
1174
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/credits/")))
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187
    {
        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()
{
1188
    if(!QDesktopServices::openUrl(QUrl("http://qgroundcontrol.org/roadmap/")))
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199
    {
        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
1200
void MainWindow::configure()
pixhawk's avatar
pixhawk committed
1201 1202 1203 1204
{
    joystickWidget = new JoystickWidget(joystick, this);
}

pixhawk's avatar
pixhawk committed
1205
void MainWindow::addLink()
pixhawk's avatar
pixhawk committed
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218
{
    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
1219 1220
void MainWindow::addLink(LinkInterface *link)
{
1221
    LinkManager::instance()->addProtocol(link, mavlink);
pixhawk's avatar
pixhawk committed
1222 1223 1224
    CommConfigurationWindow* commWidget = new CommConfigurationWindow(link, mavlink, this);
    ui.menuNetwork->addAction(commWidget->getAction());

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

pixhawk's avatar
pixhawk committed
1227 1228 1229 1230
    // Special case for simulationlink
    MAVLinkSimulationLink* sim = dynamic_cast<MAVLinkSimulationLink*>(link);
    if (sim)
    {
1231
        //connect(sim, SIGNAL(valueChanged(int,QString,double,quint64)), linechart, SLOT(appendData(int,QString,double,quint64)));
pixhawk's avatar
pixhawk committed
1232 1233 1234 1235
        connect(ui.actionSimulate, SIGNAL(triggered(bool)), sim, SLOT(connectLink(bool)));
    }
}

1236 1237 1238 1239 1240 1241 1242
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
1243
void MainWindow::UASCreated(UASInterface* uas)
pixhawk's avatar
pixhawk committed
1244
{
1245

pixhawk's avatar
pixhawk committed
1246 1247
    // Connect the UAS to the full user interface

1248 1249
    if (uas != NULL)
    {
1250 1251 1252
        // The pilot view was not available on startup, enable it now
        ui.actionPilotsView->setEnabled(true);

1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282
        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
1283 1284
        if (debugConsoleDockWidget)
        {
pixhawk's avatar
pixhawk committed
1285 1286 1287 1288 1289 1290
            DebugConsole *debugConsole = dynamic_cast<DebugConsole*>(debugConsoleDockWidget->widget());
            if (debugConsole)
            {
                connect(uas, SIGNAL(textMessageReceived(int,int,int,QString)),
                        debugConsole, SLOT(receiveTextMessage(int,int,int,QString)));
            }
1291
        }
1292 1293

        // Health / System status indicator
1294 1295
        if (infoDockWidget)
        {
pixhawk's avatar
pixhawk committed
1296 1297 1298 1299 1300
            UASInfoWidget *infoWidget = dynamic_cast<UASInfoWidget*>(infoDockWidget->widget());
            if (infoWidget)
            {
                infoWidget->addUAS(uas);
            }
1301
        }
1302 1303

        // UAS List
1304 1305
        if (listDockWidget)
        {
pixhawk's avatar
pixhawk committed
1306 1307 1308 1309 1310
            UASListWidget *listWidget = dynamic_cast<UASListWidget*>(listDockWidget->widget());
            if (listWidget)
            {
                listWidget->addUAS(uas);
            }
1311
        }
1312

1313 1314 1315 1316 1317 1318
        switch (uas->getAutopilotType())
        {
        case (MAV_AUTOPILOT_SLUGS):
            {
                // Build Slugs Widgets
                buildSlugsWidgets();
1319

1320 1321
                // Connect Slugs Widgets
                connectSlugsWidgets();
1322

1323 1324
                // Arrange Slugs Centerstack
                arrangeSlugsCenterStack();
1325

1326 1327
                // Connect Slugs Actions
                connectSlugsActions();
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 1356 1357 1358 1359 1360
                // 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;
1361

1362
        loadOperatorView();
1363
        }
pixhawk's avatar
pixhawk committed
1364

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

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

1373
            // Load last view if setting is present
1374
            if (settings.contains("CURRENT_VIEW_WITH_UAS_CONNECTED"))
1375
            {
1376
                int view = settings.value("CURRENT_VIEW_WITH_UAS_CONNECTED").toInt();
1377 1378
                currentView = (VIEW_SECTIONS) view;
                presentView();
1379 1380 1381 1382 1383

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

1386 1387 1388 1389 1390
            }
            else
            {
                loadEngineerView();
            }
1391
        }
pixhawk's avatar
pixhawk committed
1392

1393
    }
1394 1395

    if (!ui.menuConnected_Systems->isEnabled()) ui.menuConnected_Systems->setEnabled(true);
lm's avatar
lm committed
1396 1397 1398

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

1401 1402 1403
/**
 * Clears the current view completely
 */
pixhawk's avatar
pixhawk committed
1404
void MainWindow::clearView()
1405
{
1406 1407 1408
    // Save current state
    if (UASManager::instance()->getActiveUAS()) settings.setValue(getWindowStateKey(), saveState(QGC::applicationVersion()));
    settings.setValue(getWindowGeometryKey(), saveGeometry());
1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419

    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)
        {
1420
            //qDebug() << "TOOL:" << chKey << "IS:" << temp->isChecked();
1421 1422 1423 1424
            settings.setValue(chKey,temp->isChecked());
        }
        else
        {
1425
            //qDebug() << "TOOL:" << chKey << "IS DEFAULT AND UNCHECKED";
1426 1427 1428 1429
            settings.setValue(chKey,false);
        }
    }

1430
    changingViewsFlag = true;
1431 1432
    // Remove all dock widgets from main window
    QObjectList childList( this->children() );
pixhawk's avatar
pixhawk committed
1433

1434 1435 1436
    QObjectList::iterator i;
    QDockWidget* dockWidget;
    for (i = childList.begin(); i != childList.end(); ++i)
pixhawk's avatar
pixhawk committed
1437
    {
1438 1439
        dockWidget = dynamic_cast<QDockWidget*>(*i);
        if (dockWidget)
pixhawk's avatar
pixhawk committed
1440
        {
1441
            // Remove dock widget from main window
1442 1443
            //this->removeDockWidget(dockWidget);
            dockWidget->setVisible(false);
1444 1445 1446
            // 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
1447 1448
        }
    }
1449
    changingViewsFlag = false;
pixhawk's avatar
pixhawk committed
1450 1451
}

1452
void MainWindow::loadEngineerView()
lm's avatar
lm committed
1453
{
1454 1455
    if (currentView != VIEW_ENGINEER)
    {
1456
    clearView();
lm's avatar
lm committed
1457

1458
    currentView = VIEW_ENGINEER;
lm's avatar
lm committed
1459

1460
    presentView();
1461
    }
lm's avatar
lm committed
1462 1463
}

1464
void MainWindow::loadOperatorView()
lm's avatar
lm committed
1465
{
1466 1467
    if (currentView != VIEW_OPERATOR)
    {
1468 1469 1470
    clearView();

    currentView = VIEW_OPERATOR;
lm's avatar
lm committed
1471

1472
    presentView();
1473
    }
lm's avatar
lm committed
1474 1475
}

1476
void MainWindow::loadPilotView()
1477
{
1478 1479
    if (currentView != VIEW_PILOT)
    {
1480
    clearView();
1481

1482 1483 1484
    currentView = VIEW_PILOT;

    presentView();
1485
    }
1486 1487
}

1488
void MainWindow::loadMAVLinkView()
1489
{
1490 1491
    if (currentView != VIEW_MAVLINK)
    {
1492
    clearView();
pixhawk's avatar
pixhawk committed
1493

1494 1495 1496
    currentView = VIEW_MAVLINK;

    presentView();
1497
    }
1498 1499
}

lm's avatar
lm committed
1500 1501
void MainWindow::presentView()
{
1502
    // LINE CHART
1503
    showTheCentralWidget(CENTRAL_LINECHART, currentView);
1504

1505 1506
    // MAP
    showTheCentralWidget(CENTRAL_MAP, currentView);
pixhawk's avatar
pixhawk committed
1507

1508 1509
    // PROTOCOL
    showTheCentralWidget(CENTRAL_PROTOCOL, currentView);
pixhawk's avatar
pixhawk committed
1510

1511 1512
    // HEAD UP DISPLAY
    showTheCentralWidget(CENTRAL_HUD, currentView);
pixhawk's avatar
pixhawk committed
1513 1514 1515 1516 1517 1518 1519 1520 1521 1522

    // GOOGLE EARTH
    showTheCentralWidget(CENTRAL_GOOGLE_EARTH, currentView);

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

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

1523 1524 1525
    // DATA PLOT
    showTheCentralWidget(CENTRAL_DATA_PLOT, currentView);

pixhawk's avatar
pixhawk committed
1526

pixhawk's avatar
pixhawk committed
1527

1528
    // Show docked widgets based on current view and autopilot type
1529

1530 1531
    // UAS CONTROL
    showTheWidget(MENU_UAS_CONTROL, currentView);
1532

1533 1534
    // UAS LIST
    showTheWidget(MENU_UAS_LIST, currentView);
1535

1536 1537
    // WAYPOINT LIST
    showTheWidget(MENU_WAYPOINTS, currentView);
pixhawk's avatar
pixhawk committed
1538

1539 1540
    // UAS STATUS
    showTheWidget(MENU_STATUS, currentView);
1541

1542 1543
    // DETECTION
    showTheWidget(MENU_DETECTION, currentView);
1544

1545 1546
    // DEBUG CONSOLE
    showTheWidget(MENU_DEBUG_CONSOLE, currentView);
1547

1548 1549
    // ONBOARD PARAMETERS
    showTheWidget(MENU_PARAMETERS, currentView);
1550

1551 1552
    // WATCHDOG
    showTheWidget(MENU_WATCHDOG, currentView);
1553

1554 1555 1556 1557 1558
    // HUD
    showTheWidget(MENU_HUD, currentView);
    if (headUpDockWidget)
    {
        HUD* tmpHud = dynamic_cast<HUD*>( headUpDockWidget->widget() );
1559 1560 1561 1562
        if (tmpHud)
        {
            if (settings.value(buildMenuKey (SUB_SECTION_CHECKED,MENU_HUD,currentView)).toBool())
            {
1563
                addDockWidget(static_cast <Qt::DockWidgetArea>(settings.value(buildMenuKey (SUB_SECTION_LOCATION,MENU_HUD, currentView)).toInt()),
1564
                        headUpDockWidget);
1565
                headUpDockWidget->show();
1566 1567 1568
            }
            else
            {
1569 1570
                headUpDockWidget->hide();
            }
1571
        }
1572
    }
1573

1574

1575 1576
    // RC View
    showTheWidget(MENU_RC_VIEW, currentView);
1577

1578 1579
    // SLUGS DATA
    showTheWidget(MENU_SLUGS_DATA, currentView);
1580

1581 1582
    // SLUGS PID
    showTheWidget(MENU_SLUGS_PID, currentView);
1583

1584 1585
    // SLUGS HIL
    showTheWidget(MENU_SLUGS_HIL, currentView);
1586

1587 1588
    // SLUGS CAMERA
    showTheWidget(MENU_SLUGS_CAMERA, currentView);
1589

1590 1591
    // HORIZONTAL SITUATION INDICATOR
    showTheWidget(MENU_HSI, currentView);
1592

1593 1594
    // HEAD DOWN 1
    showTheWidget(MENU_HDD_1, currentView);
1595

1596 1597
    // HEAD DOWN 2
    showTheWidget(MENU_HDD_2, currentView);
1598

1599 1600 1601
    // MAVLINK LOG PLAYER
    showTheWidget(MENU_MAVLINK_LOG_PLAYER, currentView);

1602
    this->show();
1603

1604 1605
}

1606 1607 1608 1609
void MainWindow::showTheCentralWidget (TOOLS_WIDGET_NAMES centralWidget, VIEW_SECTIONS view)
{
    bool tempVisible;
    QWidget* tempWidget = dockWidgets[centralWidget];
1610

1611
    tempVisible =  settings.value(buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view), false).toBool();
1612
    //qDebug() << buildMenuKey (SUB_SECTION_CHECKED,centralWidget,view) << tempVisible;
1613
    if (toolsMenuActions[centralWidget])
1614
    {
1615
        toolsMenuActions[centralWidget]->setChecked(tempVisible);
1616
    }
1617

1618
    if (centerStack && tempWidget && tempVisible)
1619
    {
1620
        centerStack->setCurrentWidget(tempWidget);
1621 1622 1623 1624 1625
    }
}

void MainWindow::loadDataView(QString fileName)
{
1626
    clearView();
1627

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

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

1636
    presentView();
1637

1638 1639
    // Plot is now selected, now load data from file
    if (dataplotWidget)
1640
    {
1641
        dataplotWidget->loadFile(fileName);
1642
        }
1643 1644 1645 1646 1647 1648 1649
//        QStackedWidget *centerStack = dynamic_cast<QStackedWidget*>(centralWidget());
//        if (centerStack)
//        {
//            centerStack->setCurrentWidget(dataplotWidget);
//            dataplotWidget->loadFile(fileName);
//        }
//    }
1650 1651
}

1652