ParameterEditorController.cc 15.7 KB
Newer Older
1 2
/****************************************************************************
 *
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

Don Gagne's avatar
Don Gagne committed
10
#include "ParameterEditorController.h"
11
#include "QGCApplication.h"
12
#include "ParameterManager.h"
13 14
#include "SettingsManager.h"
#include "AppSettings.h"
Don Gagne's avatar
Don Gagne committed
15

Don Gagne's avatar
Don Gagne committed
16 17
#include <QStandardPaths>

Don Gagne's avatar
Don Gagne committed
18
ParameterEditorController::ParameterEditorController(void)
19
    : _parameterMgr(_vehicle->parameterManager())
Don Gagne's avatar
Don Gagne committed
20
{
21
    _buildLists();
22

23 24 25 26
    connect(this, &ParameterEditorController::currentCategoryChanged,   this, &ParameterEditorController::_currentCategoryChanged);
    connect(this, &ParameterEditorController::currentGroupChanged,      this, &ParameterEditorController::_currentGroupChanged);
    connect(this, &ParameterEditorController::searchTextChanged,        this, &ParameterEditorController::_searchTextChanged);
    connect(this, &ParameterEditorController::showModifiedOnlyChanged,  this, &ParameterEditorController::_searchTextChanged);
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
    connect(_parameterMgr, &ParameterManager::factAdded, this, &ParameterEditorController::_factAdded);

    ParameterEditorCategory* category = _categories.count() ? _categories.value<ParameterEditorCategory*>(0) : nullptr;
    setCurrentCategory(category);
}

ParameterEditorController::~ParameterEditorController()
{

}

void ParameterEditorController::_buildListsForComponent(int compId)
{
    for (const QString& factName: _parameterMgr->parameterNames(compId)) {
        Fact* fact = _parameterMgr->getParameter(compId, factName);

        ParameterEditorCategory* category = nullptr;
        if (_mapCategoryName2Category.contains(fact->category())) {
            category = _mapCategoryName2Category[fact->category()];
        } else {
            category        = new ParameterEditorCategory(this);
            category->name  = fact->category();
            _mapCategoryName2Category[fact->category()] = category;
            _categories.append(category);
52 53
        }

54 55 56 57 58 59 60 61 62 63
        ParameterEditorGroup* group = nullptr;
        if (category->mapGroupName2Group.contains(fact->group())) {
            group = category->mapGroupName2Group[fact->group()];
        } else {
            group               = new ParameterEditorGroup(this);
            group->componentId  = compId;
            group->name         = fact->group();
            category->mapGroupName2Group[fact->group()] = group;
            category->groups.append(group);
        }
64

65 66
        group->facts.append(fact);
    }
Don Gagne's avatar
Don Gagne committed
67 68
}

69
void ParameterEditorController::_buildLists(void)
70
{
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    // Autopilot component should always be first list
    _buildListsForComponent(MAV_COMP_ID_AUTOPILOT1);

    // "Standard" category should always be first
    for (int i=0; i<_categories.count(); i++) {
        ParameterEditorCategory* category = _categories.value<ParameterEditorCategory*>(i);
        if (category->name == "Standard" && i != 0) {
            _categories.removeAt(i);
            _categories.insert(0, category);
            break;
        }
    }

    // Default category should always be last
    for (int i=0; i<_categories.count(); i++) {
        ParameterEditorCategory* category = _categories.value<ParameterEditorCategory*>(i);
        if (category->name == FactMetaData::kDefaultCategory) {
            if (i != _categories.count() - 1) {
                _categories.removeAt(i);
                _categories.append(category);
            }
            break;
        }
    }

    // Now add other random components
    for (int compId: _parameterMgr->componentIds()) {
        if (compId != MAV_COMP_ID_AUTOPILOT1) {
            _buildListsForComponent(compId);
        }
    }

    // Default group should always be last
    for (int i=0; i<_categories.count(); i++) {
        ParameterEditorCategory* category = _categories.value<ParameterEditorCategory*>(i);
        for (int j=0; j<category->groups.count(); j++) {
            ParameterEditorGroup* group = category->groups.value<ParameterEditorGroup*>(j);
            if (group->name == FactMetaData::kDefaultGroup) {
                if (j != _categories.count() - 1) {
                    category->groups.removeAt(j);
                    category->groups.append(category);
                }
                break;
            }
        }
    }
117 118
}

119
void ParameterEditorController::_factAdded(int compId, Fact* fact)
Don Gagne's avatar
Don Gagne committed
120
{
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
    bool                        inserted = false;
    ParameterEditorCategory*    category = nullptr;

    if (_mapCategoryName2Category.contains(fact->category())) {
        category = _mapCategoryName2Category[fact->category()];
    } else {
        category        = new ParameterEditorCategory(this);
        category->name  = fact->category();
        _mapCategoryName2Category[fact->category()] = category;

        // Insert in sorted order
        inserted = false;
        for (int i=0; i<_categories.count(); i++) {
            if (_categories.value<ParameterEditorCategory*>(i)->name > category->name) {
                _categories.insert(i, category);
                inserted = true;
                break;
            }
        }
        if (!inserted) {
            _categories.append(category);
        }
    }

    ParameterEditorGroup* group = nullptr;
    if (category->mapGroupName2Group.contains(fact->group())) {
        group = category->mapGroupName2Group[fact->group()];
148
    } else {
149 150 151 152
        group               = new ParameterEditorGroup(this);
        group->componentId  = compId;
        group->name         = fact->group();
        category->mapGroupName2Group[fact->group()] = group;
153

154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
        // Insert in sorted order
        QmlObjectListModel& groups = category->groups;
        inserted = false;
        for (int i=0; i<groups.count(); i++) {
            if (groups.value<ParameterEditorCategory*>(i)->name > group->name) {
                groups.insert(i, group);
                inserted = true;
                break;
            }
        }
        if (!inserted) {
            groups.append(group);
        }
    }

    // Insert in sorted order
    QmlObjectListModel& facts = group->facts;
    inserted = false;
    for (int i=0; i<facts.count(); i++) {
        if (facts.value<Fact*>(i)->name() > fact->name()) {
            facts.insert(i, fact);
            inserted = true;
            break;
        }
    }
    if (!inserted) {
        facts.append(fact);
181
    }
Don Gagne's avatar
Don Gagne committed
182 183
}

184
QStringList ParameterEditorController::searchParameters(const QString& searchText, bool searchInName, bool searchInDescriptions)
Don Gagne's avatar
Don Gagne committed
185 186
{
    QStringList list;
187

188
    for(const QString &paramName: _parameterMgr->parameterNames(_vehicle->defaultComponentId())) {
Don Gagne's avatar
Don Gagne committed
189 190 191
        if (searchText.isEmpty()) {
            list += paramName;
        } else {
192
            Fact* fact = _parameterMgr->getParameter(_vehicle->defaultComponentId(), paramName);
193

Don Gagne's avatar
Don Gagne committed
194 195 196 197 198 199 200 201 202
            if (searchInName && fact->name().contains(searchText, Qt::CaseInsensitive)) {
                list += paramName;
            } else if (searchInDescriptions && (fact->shortDescription().contains(searchText, Qt::CaseInsensitive) || fact->longDescription().contains(searchText, Qt::CaseInsensitive))) {
                list += paramName;
            }
        }
    }
    list.sort();

203
    return list;
Don Gagne's avatar
Don Gagne committed
204 205
}

Don Gagne's avatar
Don Gagne committed
206
void ParameterEditorController::saveToFile(const QString& filename)
Don Gagne's avatar
Don Gagne committed
207
{
Don Gagne's avatar
Don Gagne committed
208
    if (!filename.isEmpty()) {
Don Gagne's avatar
Don Gagne committed
209 210 211 212 213 214
        QString parameterFilename = filename;
        if (!QFileInfo(filename).fileName().contains(".")) {
            parameterFilename += QString(".%1").arg(AppSettings::parameterFileExtension);
        }

        QFile file(parameterFilename);
215

216
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
217
            qgcApp()->showAppMessage(tr("Unable to create file: %1").arg(parameterFilename));
218 219
            return;
        }
220

221
        QTextStream stream(&file);
222
        _parameterMgr->writeParametersToStream(stream);
223 224
        file.close();
    }
Don Gagne's avatar
Don Gagne committed
225 226
}

227
void ParameterEditorController::clearDiff(void)
Don Gagne's avatar
Don Gagne committed
228
{
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
    _diffList.clearAndDeleteContents();
    _diffOtherVehicle = false;
    _diffMultipleComponents = false;

    emit diffOtherVehicleChanged(_diffOtherVehicle);
    emit diffMultipleComponentsChanged(_diffMultipleComponents);
}

void ParameterEditorController::sendDiff(void)
{
    for (int i=0; i<_diffList.count(); i++) {
        ParameterEditorDiff* paramDiff = _diffList.value<ParameterEditorDiff*>(i);

        if (paramDiff->load) {
            if (paramDiff->noVehicleValue) {
                _parameterMgr->_factRawValueUpdateWorker(paramDiff->componentId, paramDiff->name, paramDiff->valueType, paramDiff->fileValueVar);
            } else {
                Fact* fact = _parameterMgr->getParameter(paramDiff->componentId, paramDiff->name);
                fact->setRawValue(paramDiff->fileValueVar);
            }
Don Gagne's avatar
Don Gagne committed
249
        }
250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    }
}

bool ParameterEditorController::buildDiffFromFile(const QString& filename)
{
    QFile file(filename);

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qgcApp()->showAppMessage(tr("Unable to open file: %1").arg(filename));
        return false;
    }

    clearDiff();

    QTextStream stream(&file);

    int firstComponentId = -1;
    while (!stream.atEnd()) {
        QString line = stream.readLine();
        if (!line.startsWith("#")) {
            QStringList wpParams = line.split("\t");
            if (wpParams.size() == 5) {
                int         vehicleId       = wpParams.at(0).toInt();
                int         componentId     = wpParams.at(1).toInt();
                QString     paramName       = wpParams.at(2);
                QString     fileValueStr    = wpParams.at(3);
                int         mavParamType    = wpParams.at(4).toInt();
                QString     vehicleValueStr;
                QString     units;
                QVariant    fileValueVar    = fileValueStr;
                bool        noVehicleValue   = false;

                if (_vehicle->id() != vehicleId) {
                    _diffOtherVehicle = true;
                }
                if (firstComponentId == -1) {
                    firstComponentId = componentId;
                } else if (firstComponentId != componentId) {
                    _diffMultipleComponents = true;
                }

                if (_parameterMgr->parameterExists(componentId, paramName)) {
                    Fact*           vehicleFact         = _parameterMgr->getParameter(componentId, paramName);
                    FactMetaData*   vehicleFactMetaData = vehicleFact->metaData();
                    Fact*           fileFact            = new Fact(vehicleFact->componentId(), vehicleFact->name(), vehicleFact->type(), this);

                    // Turn off reboot messaging before setting value in fileFact
                    bool vehicleRebootRequired = vehicleFactMetaData->vehicleRebootRequired();
                    vehicleFactMetaData->setVehicleRebootRequired(false);
                    fileFact->setMetaData(vehicleFact->metaData());
                    fileFact->setRawValue(fileValueStr);
                    vehicleFactMetaData->setVehicleRebootRequired(vehicleRebootRequired);

                    if (vehicleFact->rawValue() == fileFact->rawValue()) {
                        continue;
                    }
                    fileValueStr    = fileFact->enumOrValueString();
                    fileValueVar    = fileFact->rawValue();
                    vehicleValueStr = vehicleFact->enumOrValueString();
                    units           = vehicleFact->cookedUnits();
                } else {
                    noVehicleValue = true;
                }

                ParameterEditorDiff* paramDiff = new ParameterEditorDiff(this);

                paramDiff->componentId      = componentId;
                paramDiff->name             = paramName;
                paramDiff->valueType        = ParameterManager::mavTypeToFactType(static_cast<MAV_PARAM_TYPE>(mavParamType));
                paramDiff->fileValue        = fileValueStr;
                paramDiff->fileValueVar     = fileValueVar;
                paramDiff->vehicleValue     = vehicleValueStr;
                paramDiff->noVehicleValue   = noVehicleValue;
                paramDiff->units            = units;

                _diffList.append(paramDiff);
            }
327
        }
Don Gagne's avatar
Don Gagne committed
328
    }
329 330 331 332 333 334 335

    file.close();

    emit diffOtherVehicleChanged(_diffOtherVehicle);
    emit diffMultipleComponentsChanged(_diffMultipleComponents);

    return true;
Don Gagne's avatar
Don Gagne committed
336 337
}

Don Gagne's avatar
Don Gagne committed
338 339
void ParameterEditorController::refresh(void)
{
340
    _parameterMgr->refreshAllParameters();
Don Gagne's avatar
Don Gagne committed
341 342
}

343 344
void ParameterEditorController::resetAllToDefaults(void)
{
345
    _parameterMgr->resetAllParametersToDefaults();
346 347 348
    refresh();
}

349
void ParameterEditorController::resetAllToVehicleConfiguration(void)
Don Gagne's avatar
Don Gagne committed
350
{
351 352
    _parameterMgr->resetAllToVehicleConfiguration();
    refresh();
Don Gagne's avatar
Don Gagne committed
353
}
354

355 356 357 358 359 360
bool ParameterEditorController::_shouldShow(Fact* fact)
{
    bool show = _showModifiedOnly ? (fact->defaultValueAvailable() ? (fact->valueEqualsDefault() ? false : true) : false) : true;
    return show;
}

361
void ParameterEditorController::_searchTextChanged(void)
362 363 364
{
    QObjectList newParameterList;

365 366 367 368 369
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
    QStringList rgSearchStrings = _searchText.split(' ', QString::SkipEmptyParts);
#else
    QStringList rgSearchStrings = _searchText.split(' ', Qt::SkipEmptyParts);
#endif
370

371 372 373 374 375

    if (rgSearchStrings.isEmpty() && !_showModifiedOnly) {
        ParameterEditorCategory* category = _categories.count() ? _categories.value<ParameterEditorCategory*>(0) : nullptr;
        setCurrentCategory(category);
        _searchParameters.clear();
376
    } else {
377 378 379 380 381
        _searchParameters.beginReset();
        _searchParameters.clear();

        for (const QString &paraName: _parameterMgr->parameterNames(_vehicle->defaultComponentId())) {
            Fact* fact = _parameterMgr->getParameter(_vehicle->defaultComponentId(), paraName);
382 383
            bool matched = _shouldShow(fact);
            // All of the search items must match in order for the parameter to be added to the list
384 385
            if (matched) {
                for (const auto& searchItem : rgSearchStrings) {
386
                    if (!fact->name().contains(searchItem, Qt::CaseInsensitive) &&
387 388
                            !fact->shortDescription().contains(searchItem, Qt::CaseInsensitive) &&
                            !fact->longDescription().contains(searchItem, Qt::CaseInsensitive)) {
389 390
                        matched = false;
                    }
391 392 393
                }
            }
            if (matched) {
394
                _searchParameters.append(fact);
395 396
            }
        }
397 398 399 400 401 402 403 404 405 406

        _searchParameters.endReset();

        if (_parameters != &_searchParameters) {
            _parameters = &_searchParameters;
            emit parametersChanged();

            _currentCategory    = nullptr;
            _currentGroup       = nullptr;
        }
407
    }
408 409 410 411 412 413 414 415 416 417 418 419 420
}

void ParameterEditorController::_currentCategoryChanged(void)
{
    ParameterEditorGroup* group = nullptr;
    if (_currentCategory) {
        // Select first group when category changes
        group = _currentCategory->groups.value<ParameterEditorGroup*>(0);
    } else {
        group = nullptr;
    }
    setCurrentGroup(group);
}
421

422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443
void ParameterEditorController::_currentGroupChanged(void)
{
    _parameters = _currentGroup ? &_currentGroup->facts : nullptr;
    emit parametersChanged();
}

void ParameterEditorController::setCurrentCategory(QObject* currentCategory)
{
    ParameterEditorCategory* category = qobject_cast<ParameterEditorCategory*>(currentCategory);
    if (category != _currentCategory) {
        _currentCategory = category;
        emit currentCategoryChanged();
    }
}

void ParameterEditorController::setCurrentGroup(QObject* currentGroup)
{
    ParameterEditorGroup* group = qobject_cast<ParameterEditorGroup*>(currentGroup);
    if (group != _currentGroup) {
        _currentGroup = group;
        emit currentGroupChanged();
    }
444
}