13 : QAbstractTableModel(parent)
25 return _tableData.count();
30 return _tableViewColCount;
35 if (!index.isValid()) {
39 if (index.row() < 0 || index.row() >= _tableData.count()) {
42 if (index.column() < 0 || index.column() >= _tableViewColCount) {
48 return QVariant::fromValue(_tableData[index.row()][index.column()]);
50 return QVariant::fromValue(_tableData[index.row()][
ValueColumn]);
58 if (orientation != Qt::Horizontal || role != Qt::DisplayRole) {
67 default:
return QVariant();
74 {Qt::DisplayRole,
"display"},
94 qWarning() <<
"Invalid row row:rowCount" << row <<
rowCount() << Q_FUNC_INFO;
95 row = qMax(qMin(row,
rowCount()), 0);
98 ColumnData colData(_tableViewColCount, QString());
104 if (!_isResetting()) {
105 beginInsertRows(QModelIndex(), row, row);
107 _tableData.insert(row, colData);
108 if (!_isResetting()) {
116 _resetNestingCount++;
118 if (_resetNestingCount == 1) {
125 if (_resetNestingCount == 0) {
126 qWarning() <<
"ParameterTableModel::endReset called without prior beginReset";
129 _resetNestingCount--;
130 if (_resetNestingCount == 0) {
138 if (row < 0 || row >= _tableData.count()) {
139 qWarning() <<
"Invalid row row:rowCount" << row << _tableData.count() << Q_FUNC_INFO;
155 , _parameterMgr(_vehicle->parameterManager())
161 _searchTimer.setSingleShot(
true);
162 _searchTimer.setInterval(300);
170 connect(&_searchTimer, &QTimer::timeout,
this, &ParameterEditorController::_performSearch);
184void ParameterEditorController::_buildListsForComponent(
int compId)
186 for (
const QString& factName: _parameterMgr->parameterNames(compId)) {
189 if (_hideReadOnly && fact->
readOnly()) {
194 if (_mapCategoryName2Category.contains(fact->
category())) {
195 category = _mapCategoryName2Category[fact->
category()];
199 _mapCategoryName2Category[fact->
category()] = category;
200 _categories.
append(category);
218void ParameterEditorController::_buildLists(
void)
220 _currentCategory =
nullptr;
221 _currentGroup =
nullptr;
222 _parameters =
nullptr;
223 _mapCategoryName2Category.clear();
228 _buildListsForComponent(MAV_COMP_ID_AUTOPILOT1);
231 for (
int i=0; i<_categories.
count(); i++) {
233 if (category->
name ==
"Standard" && i != 0) {
235 _categories.
insert(0, category);
241 for (
int i=0; i<_categories.
count(); i++) {
244 if (i != _categories.
count() - 1) {
246 _categories.
append(category);
253 for (
int compId: _parameterMgr->componentIds()) {
254 if (compId != MAV_COMP_ID_AUTOPILOT1) {
255 _buildListsForComponent(compId);
260 for (
int i=0; i<_categories.
count(); i++) {
265 if (j != _categories.
count() - 1) {
275void ParameterEditorController::_factAdded(
int compId,
Fact* fact)
277 if (_hideReadOnly && fact->
readOnly()) {
281 bool inserted =
false;
284 if (_mapCategoryName2Category.contains(fact->
category())) {
285 category = _mapCategoryName2Category[fact->
category()];
289 _mapCategoryName2Category[fact->
category()] = category;
293 for (
int i=0; i<_categories.
count(); i++) {
295 _categories.
insert(i, category);
301 _categories.
append(category);
317 for (
int i=0; i<groups.
count(); i++) {
330 auto& facts = group->
facts;
331 for (
int i=0; i<facts.rowCount(); i++) {
332 if (facts.factAt(i)->name() > fact->
name()) {
342 if (!filename.isEmpty()) {
343 QString parameterFilename = filename;
344 if (!QFileInfo(filename).fileName().contains(
".")) {
348 QFile file(parameterFilename);
350 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
351 qCWarning(ParameterEditorControllerLog) <<
"saveToFile: unable to create file" << parameterFilename;
356 qCDebug(ParameterEditorControllerLog) <<
"saveToFile:" << parameterFilename;
357 QTextStream stream(&file);
363template <
typename T,
typename SignalFn>
364void ParameterEditorController::_setDiffProperty(T& member,
const T& value, SignalFn changedSignal)
366 if (member == value) {
370 emit (this->*changedSignal)(member);
388void ParameterEditorController::_updateDiffSelectedCount()
390 int selectedCount = 0;
391 for (
int i=0; i<_diffList.
count(); i++) {
403 int uncheckedCount = 0;
405 for (
int i=0; i<_diffList.
count(); i++) {
409 qCDebug(ParameterEditorControllerLog) <<
"sendDiff: skipped (cannot send, not on vehicle) -" << paramDiff->
name;
413 if (paramDiff->
load) {
416 qCDebug(ParameterEditorControllerLog) <<
"sendDiff: PARAM_SET new param -" << paramDiff->
name
420 qCDebug(ParameterEditorControllerLog) <<
"sendDiff: fact write -" << paramDiff->
name
427 qCDebug(ParameterEditorControllerLog) <<
"sendDiff: skipped (unchecked) -" << paramDiff->
name;
431 qCDebug(ParameterEditorControllerLog) <<
"sendDiff summary - sent:" << sentCount <<
"unchecked:" << uncheckedCount;
436 QFile file(filename);
438 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
439 qCWarning(ParameterEditorControllerLog) <<
"buildDiffFromFile: unable to open file" << filename;
446 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile:" << filename;
448 QTextStream stream(&file);
460 int firstComponentId = -1;
461 while (!stream.atEnd()) {
462 QString line = stream.readLine();
463 if (!line.startsWith(
"#") && !line.trimmed().isEmpty()) {
464 QStringList wpParams = line.trimmed().split(QRegularExpression(
"[\\t ,]+"));
466 int componentId = -1;
468 QString fileValueStr;
469 int mavParamType = -1;
470 bool isMPFormat =
false;
472 if (wpParams.size() == 5) {
474 int vehicleId = wpParams.at(0).toInt();
475 componentId = wpParams.at(1).toInt();
476 paramName = wpParams.at(2);
477 fileValueStr = wpParams.at(3);
478 mavParamType = wpParams.at(4).toInt();
482 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: file is from other vehicle - file vehicleId:" << vehicleId <<
"connected vehicleId:" <<
_vehicle->
id();
486 if (firstComponentId == -1) {
487 firstComponentId = componentId;
488 }
else if (firstComponentId != componentId) {
490 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: file contains multiple componentIds:" << firstComponentId << componentId;
494 }
else if (wpParams.size() == 2) {
496 paramName = wpParams.at(0);
497 fileValueStr = wpParams.at(1);
501 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: skipping unparseable line:" << line.trimmed().left(80);
507 QString vehicleValueStr;
509 QVariant fileValueVar = fileValueStr;
510 bool noVehicleValue =
false;
511 bool readOnly =
false;
518 if (mavParamType == -1) {
534 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: changed -" << paramName
540 }
else if (isMPFormat) {
543 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: not on vehicle, cannot send (MP format) -" << paramName;
549 paramDiff->
name = paramName;
554 paramDiff->
load =
false;
556 _diffList.
append(paramDiff);
559 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: not on vehicle, will send as new (QGC format) -" << paramName <<
"value:" << fileValueStr;
560 noVehicleValue =
true;
569 fileValueVar = typedValue;
571 qCWarning(ParameterEditorControllerLog) <<
"buildDiffFromFile: value conversion failed, skipping -" << paramName
572 <<
"value:" << fileValueStr <<
"error:" <<
errorString;
582 paramDiff->
name = paramName;
588 paramDiff->
units = units;
592 _diffList.
append(paramDiff);
595 if (noVehicleValue) {
599 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile: skipping read-only param -" << paramName;
608 QGC::showAppMessage(tr(
"No valid parameters found in file. Check that the file is in QGC or Mission Planner format."));
612 qCDebug(ParameterEditorControllerLog) <<
"buildDiffFromFile summary -"
651bool ParameterEditorController::_shouldShow(
Fact* fact)
const
653 if (_hideReadOnly && fact->
readOnly()) {
656 if (_showModifiedOnly) {
661 if (_showFavoritesOnly) {
662 if (!_favoriteNames.contains(fact->
name())) {
669void ParameterEditorController::_searchTextChanged(
void)
671 _searchTimer.start();
674void ParameterEditorController::_hideReadOnlyChanged(
void)
682 if (!_searchText.isEmpty() || _showModifiedOnly) {
687void ParameterEditorController::_performSearch(
void)
689 QObjectList newParameterList;
691 QStringList rgSearchStrings = _searchText.split(
' ', Qt::SkipEmptyParts);
693 if (rgSearchStrings.isEmpty() && !_showModifiedOnly && !_showFavoritesOnly) {
696 _searchParameters.
clear();
698 QVector<QRegularExpression> regexList;
699 regexList.reserve(rgSearchStrings.size());
700 for (
const QString &searchItem : rgSearchStrings) {
701 QRegularExpression re(searchItem, QRegularExpression::CaseInsensitiveOption);
702 regexList.append(re.isValid() ? re : QRegularExpression());
706 _searchParameters.
clear();
708 for (
int compId : _parameterMgr->componentIds()) {
709 for (
const QString ¶Name: _parameterMgr->parameterNames(compId)) {
711 bool matched = _shouldShow(fact);
714 for (
int i = 0; i < rgSearchStrings.size(); ++i) {
715 const QRegularExpression &re = regexList.at(i);
717 if (!fact->
name().contains(re) &&
723 const QString &searchItem = rgSearchStrings.at(i);
724 if (!fact->
name().contains(searchItem, Qt::CaseInsensitive) &&
733 _searchParameters.
append(fact);
740 if (_parameters != &_searchParameters) {
741 _parameters = &_searchParameters;
744 _currentCategory =
nullptr;
745 _currentGroup =
nullptr;
750void ParameterEditorController::_currentCategoryChanged(
void)
753 if (_currentCategory) {
762void ParameterEditorController::_currentGroupChanged(
void)
764 _parameters = _currentGroup ? &_currentGroup->
facts :
nullptr;
771 if (category != _currentCategory) {
772 _currentCategory = category;
780 if (group != _currentGroup) {
781 _currentGroup = group;
788 QStringList list(_favoriteNames.begin(), _favoriteNames.end());
795 if (_favoriteNames.contains(paramName)) {
796 _favoriteNames.remove(paramName);
798 _favoriteNames.insert(paramName);
803 if (_showFavoritesOnly) {
810 return _favoriteNames.contains(paramName);
815 _favoriteNames.clear();
819 if (_showFavoritesOnly) {
824void ParameterEditorController::_loadFavorites()
827 const QStringList list = fact->
rawValue().toString().split(
",", Qt::SkipEmptyParts);
828 _favoriteNames = QSet<QString>(list.begin(), list.end());
831void ParameterEditorController::_saveFavorites()
833 QStringList list(_favoriteNames.begin(), _favoriteNames.end());
#define QGC_LOGGING_CATEGORY(name, categoryStr)
static constexpr const char * parameterFileExtension
Used for handling missing Facts from C++ code.
A Fact is used to hold a single value within the system.
QString enumOrValueString()
void setMetaData(FactMetaData *metaData, bool setDefaultFromMetaData=false)
QString cookedUnits() const
QString longDescription() const
QString shortDescription() const
FactMetaData * metaData()
bool valueEqualsDefault() const
FactMetaData::ValueType_t type() const
void setRawValue(const QVariant &value)
bool defaultValueAvailable() const
QVariant rawValue() const
QMap< QString, ParameterEditorGroup * > mapGroupName2Group
QmlObjectListModel groups
void diffMissingParamsChanged(const QStringList &diffMissingParams)
QStringList diffMissingParams(void) const
Q_INVOKABLE void resetAllToVehicleConfiguration(void)
void showFavoritesOnlyChanged(void)
Q_INVOKABLE bool buildDiffFromFile(const QString &filename)
void parametersChanged(void)
int diffParsedCount(void) const
Q_INVOKABLE void refresh(void)
void currentGroupChanged(void)
int diffSendableCount(void) const
void diffSelectedCountChanged(int diffSelectedCount)
void diffMultipleComponentsChanged(bool diffMultipleComponents)
Q_INVOKABLE void toggleFavorite(const QString ¶mName)
QObject * currentCategory(void)
void diffParsedCountChanged(int diffParsedCount)
void diffReadOnlyCountChanged(int diffReadOnlyCount)
int diffReadOnlyCount(void) const
Q_INVOKABLE void clearAllFavorites(void)
~ParameterEditorController()
void diffNoVehicleCountChanged(int diffNoVehicleCount)
QStringList favoriteParameterNames(void) const
void setCurrentGroup(QObject *currentGroup)
Q_INVOKABLE void saveToFile(const QString &filename)
void diffUnchangedCountChanged(int diffUnchangedCount)
ParameterEditorController(QObject *parent=nullptr)
void searchTextChanged(QString searchText)
Q_INVOKABLE void sendDiff(void)
void currentCategoryChanged(void)
void diffOtherVehicleChanged(bool diffOtherVehicle)
void setCurrentCategory(QObject *currentCategory)
void diffSendableCountChanged(int diffSendableCount)
void favoritesChanged(void)
int diffNoVehicleCount(void) const
bool diffMultipleComponents(void) const
Q_INVOKABLE bool isFavorite(const QString ¶mName) const
bool diffOtherVehicle(void) const
Q_INVOKABLE void clearDiff(void)
void showModifiedOnlyChanged(void)
int diffUnchangedCount(void) const
QObject * currentGroup(void)
Q_INVOKABLE void resetAllToDefaults(void)
void hideReadOnlyChanged(void)
bool cannotSend
Param not on vehicle and file has no type info (MP format) - shown but never sent.
void loadChanged(bool load)
FactMetaData::ValueType_t valueType
ParameterEditorGroup(QObject *parent)
ParameterTableModel facts
bool parameterExists(int componentId, const QString ¶mName) const
Fact * getParameter(int componentId, const QString ¶mName)
void factAdded(int componentId, Fact *fact)
static FactMetaData::ValueType_t mavTypeToFactType(MAV_PARAM_TYPE mavType)
static constexpr int defaultComponentId
void resetAllParametersToDefaults()
void refreshAllParameters(uint8_t componentID)
Re-request the full set of parameters from the autopilot.
static MAV_PARAM_TYPE factTypeToMavType(FactMetaData::ValueType_t factType)
void resetAllToVehicleConfiguration()
void writeParametersToStream(QTextStream &stream) const
QVector< QVariant > ColumnData
void insert(int row, Fact *fact)
int rowCount(const QModelIndex &parent=QModelIndex()) const override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QHash< int, QByteArray > roleNames(void) const override
~ParameterTableModel() override
void rowCountChanged(int count)
void endReset()
Supports nesting - only outermost call has effect.
void beginReset()
Supports nesting - only outermost call has effect.
Fact * factAt(int row) const
void append(QObject *object)
Caller maintains responsibility for object ownership and deletion.
QObject * removeAt(int index)
int count() const override final
void clearAndDeleteContents() override final
Clears the list and calls deleteLater on each entry.
void insert(int index, QObject *object)
static SettingsManager * instance()
AppSettings * appSettings() const
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.