From ca1ebc7cba4c66e9798c295283fd9d280d551c72 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 15 Dec 2017 21:15:17 +0100 Subject: [PATCH 01/20] LP-567 uavobjectbrowser: improve highlight handling keep track of when to check highlight and schedule timer accordingly old way would do that at a fixed periodicity leading to aliasing --- .../src/plugins/uavobjectbrowser/treeitem.cpp | 73 +++++++++++++------ .../src/plugins/uavobjectbrowser/treeitem.h | 7 +- .../uavobjectbrowser/uavobjecttreemodel.cpp | 3 +- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index 71b9cf690..5b4d17702 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -28,11 +28,12 @@ #include "treeitem.h" /* Constructor */ -HighLightManager::HighLightManager(long checkingInterval) +HighLightManager::HighLightManager() { - // Start the timer and connect it to the callback - m_expirationTimer.start(checkingInterval); - connect(&m_expirationTimer, SIGNAL(timeout()), this, SLOT(checkItemsExpired())); + // Initialize the timer and connect it to the callback + m_expirationTimer.setTimerType(Qt::PreciseTimer); + m_expirationTimer.setSingleShot(true); + connect(&m_expirationTimer, &QTimer::timeout, this, &HighLightManager::checkItemsExpired); } /* @@ -52,6 +53,20 @@ bool HighLightManager::add(TreeItem *itemToAdd) return false; } +bool HighLightManager::startTimer(QTime expirationTime) +{ + // Lock to ensure thread safety + QMutexLocker locker(&m_mutex); + + if (!m_expirationTimer.isActive()) { + int msec = QTime::currentTime().msecsTo(expirationTime); + // qDebug() << "start" << msec; + m_expirationTimer.start((msec < 10) ? 10 : msec); + return true; + } + return false; +} + /* * Called to remove item from list. * Returns true if item was removed, otherwise false. @@ -81,35 +96,48 @@ void HighLightManager::checkItemsExpired() // This is the timestamp to compare with QTime now = QTime::currentTime(); + QTime next; // Loop over all items, check if they expired. while (iter.hasNext()) { TreeItem *item = iter.next(); - if (item->getHiglightExpires() < now) { - // If expired, call removeHighlight + if (item->getHiglightExpires() <= now) { + // expired, call removeHighlight item->removeHighlight(); // Remove from list since it is restored. iter.remove(); + } else { + // not expired, check if next to expire + if (!next.isValid() || (next > item->getHiglightExpires())) { + next = item->getHiglightExpires(); + } } } + if (next.isValid()) { + int msec = QTime::currentTime().msecsTo(next); + // qDebug() << "restart" << msec; + m_expirationTimer.start((msec < 10) ? 10 : msec); + } } -int TreeItem::m_highlightTimeMs = 500; +int TreeItem::m_highlightTimeMs = 300; TreeItem::TreeItem(const QList &data, TreeItem *parent) : QObject(0), m_data(data), m_parent(parent), m_highlight(false), - m_changed(false) + m_changed(false), + m_highlightManager(0) {} TreeItem::TreeItem(const QVariant &data, TreeItem *parent) : QObject(0), m_parent(parent), m_highlight(false), - m_changed(false) + m_changed(false), + m_highlightManager(0) { m_data << data << "" << ""; } @@ -180,24 +208,27 @@ void TreeItem::apply() } /* - * Called after a value has changed to trigger highlightning of tree item. + * Called after a value has changed to trigger highlighting of tree item. */ void TreeItem::setHighlight(bool highlight) { - m_highlight = highlight; m_changed = false; - if (highlight) { - // Update the expires timestamp - m_highlightExpires = QTime::currentTime().addMSecs(m_highlightTimeMs); - - // Add to highlightmanager - if (m_highlightManager->add(this)) { - // Only emit signal if it was added + if (m_highlight != highlight) { + m_highlight = highlight; + if (highlight) { + // Add to highlight manager + if (m_highlightManager->add(this)) { + // Only emit signal if it was added + emit updateHighlight(this); + } + // Update expiration timeout + m_highlightExpires = QTime::currentTime().addMSecs(m_highlightTimeMs); + // start expiration timer if necessary + m_highlightManager->startTimer(m_highlightExpires); + } else if (m_highlightManager->remove(this)) { + // Only emit signal if it was removed emit updateHighlight(this); } - } else if (m_highlightManager->remove(this)) { - // Only emit signal if it was removed - emit updateHighlight(this); } // If we have a parent, call recursively to update highlight status of parents. diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h index 253ec041c..ba7d4564f 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h @@ -49,7 +49,7 @@ class TreeItem; * non highlighted state in a linked list. * A timer traverses this list periodically to find out * if any of the items should be restored. All items are - * updated withan expiration timestamp when they expires. + * updated with an expiration timestamp when they expires. * An item that is beeing restored is removed from the * list and its removeHighlight() method is called. Items * that are not expired are left in the list til next time. @@ -60,8 +60,7 @@ class TreeItem; class HighLightManager : public QObject { Q_OBJECT public: - // Constructor taking the checking interval in ms. - HighLightManager(long checkingInterval); + HighLightManager(); // This is called when an item has been set to // highlighted = true. @@ -70,6 +69,8 @@ public: // This is called when an item is set to highlighted = false; bool remove(TreeItem *itemToRemove); + bool startTimer(QTime time); + private slots: // Timer callback method. void checkItemsExpired(); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 8f5941a48..77dbcabae 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -52,8 +52,7 @@ UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent, bool categorize, bool sh Q_ASSERT(objManager); - // Create highlight manager, let it run every 300 ms. - m_highlightManager = new HighLightManager(300); + m_highlightManager = new HighLightManager(); connect(objManager, SIGNAL(newObject(UAVObject *)), this, SLOT(newObject(UAVObject *))); connect(objManager, SIGNAL(newInstance(UAVObject *)), this, SLOT(newObject(UAVObject *))); From 4c40d7f6203381534d021c252ae3c8227dd112a1 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Fri, 15 Dec 2017 22:03:48 +0100 Subject: [PATCH 02/20] LP-567 uavobjectbrowser: change updated timeout to 300ms --- ground/gcs/src/share/configurations/default.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/share/configurations/default.xml b/ground/gcs/src/share/configurations/default.xml index 65dc90947..8a5b4766d 100644 --- a/ground/gcs/src/share/configurations/default.xml +++ b/ground/gcs/src/share/configurations/default.xml @@ -2780,7 +2780,7 @@ #5baa56 false #ff7957 - 500 + 300 false From 849f7845a11a7b35f843ca34170faf7785359279 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 12 Mar 2018 22:03:49 +0100 Subject: [PATCH 03/20] LP-567 fix performance issue (high CPU) when highlighting items we now emit data changes column by column emitting a dataChanged that spans multiple columns kills performance (CPU shoots up) this is probably because we configure the sort/filter proxy to be dynamic this happens when calling setDynamicSortFilter(true) on it which we do --- .../uavobjectbrowser/uavobjecttreemodel.cpp | 45 ++++++++----------- .../uavobjectbrowser/uavobjecttreemodel.h | 2 +- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 77dbcabae..a4a41b377 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -280,28 +280,13 @@ QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &pa TreeItem *childItem = parentItem->getChild(row); if (childItem) { return createIndex(row, column, childItem); - } else { - return QModelIndex(); } + return QModelIndex(); } -QModelIndex UAVObjectTreeModel::index(TreeItem *item) +QModelIndex UAVObjectTreeModel::index(TreeItem *item, int column) { - if (item->parent() == 0) { - return QModelIndex(); - } - - QModelIndex root = index(item->parent()); - - for (int i = 0; i < rowCount(root); ++i) { - QModelIndex childIndex = index(i, 0, root); - TreeItem *child = static_cast(childIndex.internalPointer()); - if (child == item) { - return childIndex; - } - } - Q_ASSERT(false); - return QModelIndex(); + return createIndex(item->row(), column, item); } QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const @@ -464,11 +449,6 @@ void UAVObjectTreeModel::highlightUpdatedObject(UAVObject *obj) item->setHighlight(true); } item->update(); - if (!m_onlyHilightChangedValues) { - QModelIndex itemIndex = index(item); - Q_ASSERT(itemIndex != QModelIndex()); - emit dataChanged(itemIndex, itemIndex); - } } ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(UAVObject *object) @@ -503,18 +483,29 @@ MetaObjectTreeItem *UAVObjectTreeModel::findMetaObjectTreeItem(UAVMetaObject *ob void UAVObjectTreeModel::updateHighlight(TreeItem *item) { - QModelIndex itemIndex = index(item); + // performance note: here we emit data changes column by column + // emitting a dataChanged that spans multiple columns kills performance (CPU shoots up) + // this is probably because we configure the sort/filter proxy to be dynamic + // this happens when calling setDynamicSortFilter(true) on it which we do + QModelIndex itemIndex; + + itemIndex = index(item, TreeItem::TITLE_COLUMN); Q_ASSERT(itemIndex != QModelIndex()); - emit dataChanged(itemIndex, itemIndex.sibling(itemIndex.row(), TreeItem::DATA_COLUMN)); + emit dataChanged(itemIndex, itemIndex); + + itemIndex = index(item, TreeItem::DATA_COLUMN); + Q_ASSERT(itemIndex != QModelIndex()); + emit dataChanged(itemIndex, itemIndex); } void UAVObjectTreeModel::updateIsKnown(TreeItem *item) { - QModelIndex itemIndex = index(item); + QModelIndex itemIndex; + itemIndex = index(item, TreeItem::TITLE_COLUMN); Q_ASSERT(itemIndex != QModelIndex()); - emit dataChanged(itemIndex, itemIndex.sibling(itemIndex.row(), TreeItem::TITLE_COLUMN)); + emit dataChanged(itemIndex, itemIndex); } void UAVObjectTreeModel::isKnownChanged(UAVObject *object, bool isKnown) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index b7c1d2e8a..65882e9fe 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -100,7 +100,7 @@ private slots: private: void setupModelData(UAVObjectManager *objManager); - QModelIndex index(TreeItem *item); + QModelIndex index(TreeItem *item, int column = 0); void addDataObject(UAVDataObject *obj); MetaObjectTreeItem *addMetaObject(UAVMetaObject *obj, TreeItem *parent); void addArrayField(UAVObjectField *field, TreeItem *parent); From 6ded0d0b7a95c1d093fd64e1dff99b198e490379 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 12 Mar 2018 22:29:33 +0100 Subject: [PATCH 04/20] LP-567 improve treeitem const correcteness --- .../plugins/uavobjectbrowser/fieldtreeitem.h | 50 +++++++++---------- .../src/plugins/uavobjectbrowser/treeitem.cpp | 4 +- .../src/plugins/uavobjectbrowser/treeitem.h | 23 +++++---- 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h index df1247cf7..5a7ebe902 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h @@ -60,16 +60,15 @@ public: TreeItem(data, parent), m_index(index), m_field(field) {} - bool isEditable() + bool isEditable() const { return true; } - virtual QWidget *createEditor(QWidget *parent) = 0; - virtual QVariant getEditorValue(QWidget *editor) = 0; - virtual void setEditorValue(QWidget *editor, QVariant value) = 0; - virtual void apply() {} - virtual bool isKnown() + virtual QWidget *createEditor(QWidget *parent) const = 0; + virtual QVariant getEditorValue(QWidget *editor) const = 0; + virtual void setEditorValue(QWidget *editor, QVariant value) const = 0; + virtual bool isKnown() const { return parent()->isKnown(); } @@ -130,7 +129,7 @@ public: } } - QWidget *createEditor(QWidget *parent) + QWidget *createEditor(QWidget *parent) const { QComboBox *editor = new QComboBox(parent); @@ -142,14 +141,14 @@ public: return editor; } - QVariant getEditorValue(QWidget *editor) + QVariant getEditorValue(QWidget *editor) const { QComboBox *comboBox = static_cast(editor); return comboBox->currentIndex(); } - void setEditorValue(QWidget *editor, QVariant value) + void setEditorValue(QWidget *editor, QVariant value) const { QComboBox *comboBox = static_cast(editor); @@ -208,7 +207,7 @@ public: } } - QWidget *createEditor(QWidget *parent) + QWidget *createEditor(QWidget *parent) const { QSpinBox *editor = new QSpinBox(parent); @@ -217,7 +216,7 @@ public: return editor; } - QVariant getEditorValue(QWidget *editor) + QVariant getEditorValue(QWidget *editor) const { QSpinBox *spinBox = static_cast(editor); @@ -225,7 +224,7 @@ public: return spinBox->value(); } - void setEditorValue(QWidget *editor, QVariant value) + void setEditorValue(QWidget *editor, QVariant value) const { QSpinBox *spinBox = static_cast(editor); @@ -290,7 +289,7 @@ public: } } - QWidget *createEditor(QWidget *parent) + QWidget *createEditor(QWidget *parent) const { if (m_useScientificNotation) { QScienceSpinBox *editor = new QScienceSpinBox(parent); @@ -307,7 +306,7 @@ public: } } - QVariant getEditorValue(QWidget *editor) + QVariant getEditorValue(QWidget *editor) const { if (m_useScientificNotation) { QScienceSpinBox *spinBox = static_cast(editor); @@ -320,7 +319,7 @@ public: } } - void setEditorValue(QWidget *editor, QVariant value) + void setEditorValue(QWidget *editor, QVariant value) const { if (m_useScientificNotation) { QScienceSpinBox *spinBox = static_cast(editor); @@ -346,7 +345,7 @@ public: FieldTreeItem(index, data, field, parent) {} - QWidget *createEditor(QWidget *parent) + QWidget *createEditor(QWidget *parent) const { QLineEdit *lineEdit = new QLineEdit(parent); @@ -355,14 +354,14 @@ public: return lineEdit; } - QVariant getEditorValue(QWidget *editor) + QVariant getEditorValue(QWidget *editor) const { QLineEdit *lineEdit = static_cast(editor); return lineEdit->text(); } - void setEditorValue(QWidget *editor, QVariant value) + void setEditorValue(QWidget *editor, QVariant value) const { QLineEdit *lineEdit = static_cast(editor); @@ -392,7 +391,7 @@ public: } private: - QVariant toHexString(QVariant value) + QVariant toHexString(QVariant value) const { QString str; bool ok; @@ -400,7 +399,7 @@ private: return str.setNum(value.toUInt(&ok), 16).toUpper(); } - QVariant toUInt(QVariant str) + QVariant toUInt(QVariant str) const { bool ok; @@ -419,7 +418,7 @@ public: FieldTreeItem(index, data, field, parent) {} - QWidget *createEditor(QWidget *parent) + QWidget *createEditor(QWidget *parent) const { QLineEdit *lineEdit = new QLineEdit(parent); @@ -428,14 +427,14 @@ public: return lineEdit; } - QVariant getEditorValue(QWidget *editor) + QVariant getEditorValue(QWidget *editor) const { QLineEdit *lineEdit = static_cast(editor); return lineEdit->text(); } - void setEditorValue(QWidget *editor, QVariant value) + void setEditorValue(QWidget *editor, QVariant value) const { QLineEdit *lineEdit = static_cast(editor); @@ -463,14 +462,13 @@ public: setHighlight(true); } } - private: - QVariant toChar(QVariant value) + QVariant toChar(QVariant value) const { return value.toChar(); } - QVariant toUInt(QVariant str) + QVariant toUInt(QVariant str) const { return QVariant(str.toString().at(0).toLatin1()); } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index 5b4d17702..627c427c1 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -161,7 +161,7 @@ void TreeItem::insertChild(TreeItem *child) child->setParentTree(this); } -TreeItem *TreeItem::getChild(int index) +TreeItem *TreeItem::getChild(int index) const { return m_children.value(index); } @@ -250,7 +250,7 @@ void TreeItem::setHighlightManager(HighLightManager *mgr) m_highlightManager = mgr; } -QTime TreeItem::getHiglightExpires() +QTime TreeItem::getHiglightExpires() const { return m_highlightExpires; } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h index ba7d4564f..481031d09 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h @@ -99,7 +99,7 @@ public: void appendChild(TreeItem *child); void insertChild(TreeItem *child); - TreeItem *getChild(int index); + TreeItem *getChild(int index) const; inline QList treeChildren() const { return m_children; @@ -107,12 +107,13 @@ public: int childCount() const; int columnCount() const; virtual QVariant data(int column = 1) const; - QString description() + QString description() const { return m_description; } - void setDescription(QString d) // Split around 40 characters + void setDescription(QString d) { + // Split around 40 characters int idx = d.indexOf(" ", 40); d.insert(idx, QString("
")); @@ -123,7 +124,7 @@ public: // other columns are initialized in constructor virtual void setData(QVariant value, int column = 1); int row() const; - TreeItem *parent() + TreeItem *parent() const { return m_parent; } @@ -131,14 +132,14 @@ public: { m_parent = parent; } - inline virtual bool isEditable() + inline virtual bool isEditable() const { return false; } virtual void update(); virtual void apply(); - inline bool highlighted() + inline bool highlighted() const { return m_highlight; } @@ -148,7 +149,7 @@ public: m_highlightTimeMs = time; } - inline bool changed() + inline bool changed() const { return m_changed; } @@ -159,11 +160,11 @@ public: virtual void setHighlightManager(HighLightManager *mgr); - QTime getHiglightExpires(); + QTime getHiglightExpires() const; virtual void removeHighlight(); - int nameIndex(QString name) + int nameIndex(QString name) const { for (int i = 0; i < childCount(); ++i) { if (name < getChild(i)->data(0).toString()) { @@ -173,7 +174,7 @@ public: return childCount(); } - TreeItem *findChildByName(QString name) + TreeItem *findChildByName(QString name) const { foreach(TreeItem * child, m_children) { if (name == child->data(0).toString()) { @@ -219,7 +220,7 @@ public: emit updateIsKnown(this); } } - virtual bool isKnown() + virtual bool isKnown() const { return true; } From 9f71b941edc5bca58589b6a153fd4b11034ba325 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 12 Mar 2018 22:31:25 +0100 Subject: [PATCH 05/20] LP-567 factorize common code up into FieldTreeItem derived classes are simpler --- .../plugins/uavobjectbrowser/fieldtreeitem.h | 181 ++++++++---------- 1 file changed, 76 insertions(+), 105 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h index 5a7ebe902..7b752f11b 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h @@ -73,8 +73,40 @@ public: return parent()->isKnown(); } + void setData(QVariant value, int column) + { + QVariant currentValue = fieldToData(); + + setChanged(currentValue != value); + TreeItem::setData(value, column); + } + + void update() + { + bool updated = false; + + if (!changed()) { + QVariant currentValue = fieldToData(); + if (data() != currentValue) { + updated = true; + TreeItem::setData(currentValue); + } + } + if (changed() || updated) { + setHighlight(true); + } + } + + void apply() + { + m_field->setValue(dataToField(), m_index); + setChanged(false); + } protected: + virtual QVariant fieldToData() const = 0; + virtual QVariant dataToField() const = 0; + int m_index; UAVObjectField *m_field; }; @@ -90,16 +122,6 @@ public: FieldTreeItem(index, data, field, parent), m_enumOptions(field->getOptions()) {} - void setData(QVariant value, int column) - { - QStringList options = m_field->getOptions(); - QVariant tmpValue = m_field->getValue(m_index); - int tmpValIndex = options.indexOf(tmpValue.toString()); - - setChanged(tmpValIndex != value); - TreeItem::setData(value, column); - } - QString enumOptions(int index) { if ((index < 0) || (index >= m_enumOptions.length())) { @@ -108,25 +130,21 @@ public: return m_enumOptions.at(index); } - void apply() - { - int value = data().toInt(); - QStringList options = m_field->getOptions(); - - m_field->setValue(options[value], m_index); - setChanged(false); - } - - void update() + QVariant fieldToData() const { QStringList options = m_field->getOptions(); QVariant value = m_field->getValue(m_index); int valIndex = options.indexOf(value.toString()); - if (data() != valIndex || changed()) { - TreeItem::setData(valIndex); - setHighlight(true); - } + return valIndex; + } + + QVariant dataToField() const + { + int value = data().toInt(); + QStringList options = m_field->getOptions(); + + return options[value]; } QWidget *createEditor(QWidget *parent) const @@ -207,6 +225,16 @@ public: } } + QVariant fieldToData() const + { + return m_field->getValue(m_index).toInt(); + } + + QVariant dataToField() const + { + return data().toInt(); + } + QWidget *createEditor(QWidget *parent) const { QSpinBox *editor = new QSpinBox(parent); @@ -231,28 +259,6 @@ public: spinBox->setValue(value.toInt()); } - void setData(QVariant value, int column) - { - setChanged(m_field->getValue(m_index) != value); - TreeItem::setData(value, column); - } - - void apply() - { - m_field->setValue(data().toInt(), m_index); - setChanged(false); - } - - void update() - { - int value = m_field->getValue(m_index).toInt(); - - if (data() != value || changed()) { - TreeItem::setData(value); - setHighlight(true); - } - } - private: int m_minValue; int m_maxValue; @@ -267,26 +273,14 @@ public: FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, bool scientific = false, TreeItem *parent = 0) : FieldTreeItem(index, data, field, parent), m_useScientificNotation(scientific) {} - void setData(QVariant value, int column) + QVariant fieldToData() const { - setChanged(m_field->getValue(m_index) != value); - TreeItem::setData(value, column); + return m_field->getValue(m_index).toDouble(); } - void apply() + QVariant dataToField() const { - m_field->setValue(data().toDouble(), m_index); - setChanged(false); - } - - void update() - { - double value = m_field->getValue(m_index).toDouble(); - - if (data() != value || changed()) { - TreeItem::setData(value); - setHighlight(true); - } + return data().toDouble(); } QWidget *createEditor(QWidget *parent) const @@ -345,6 +339,16 @@ public: FieldTreeItem(index, data, field, parent) {} + QVariant fieldToData() const + { + return toHexString(m_field->getValue(m_index)); + } + + QVariant dataToField() const + { + return toUInt(data()); + } + QWidget *createEditor(QWidget *parent) const { QLineEdit *lineEdit = new QLineEdit(parent); @@ -368,28 +372,6 @@ public: lineEdit->setText(value.toString()); } - void setData(QVariant value, int column) - { - setChanged(m_field->getValue(m_index) != toUInt(value)); - TreeItem::setData(value, column); - } - - void apply() - { - m_field->setValue(toUInt(data()), m_index); - setChanged(false); - } - - void update() - { - QVariant value = toHexString(m_field->getValue(m_index)); - - if (data() != value || changed()) { - TreeItem::setData(value); - setHighlight(true); - } - } - private: QVariant toHexString(QVariant value) const { @@ -418,6 +400,16 @@ public: FieldTreeItem(index, data, field, parent) {} + QVariant fieldToData() const + { + return toChar(m_field->getValue(m_index)); + } + + QVariant dataToField() const + { + return toUInt(data()); + } + QWidget *createEditor(QWidget *parent) const { QLineEdit *lineEdit = new QLineEdit(parent); @@ -441,27 +433,6 @@ public: lineEdit->setText(value.toString()); } - void setData(QVariant value, int column) - { - setChanged(m_field->getValue(m_index) != toUInt(value)); - TreeItem::setData(value, column); - } - - void apply() - { - m_field->setValue(toUInt(data()), m_index); - setChanged(false); - } - - void update() - { - QVariant value = toChar(m_field->getValue(m_index)); - - if (data() != value || changed()) { - TreeItem::setData(value); - setHighlight(true); - } - } private: QVariant toChar(QVariant value) const { From 32ce9bfea918c26b8cda79fac3f5ccba2c140be4 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 12 Mar 2018 22:32:56 +0100 Subject: [PATCH 06/20] LP-567 don't create a QSpinBox each time BrowserItemDelegate::sizeHint() is called --- .../src/plugins/uavobjectbrowser/browseritemdelegate.cpp | 6 ++++-- .../gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp index 017dd8b40..7af9b2f46 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.cpp @@ -31,7 +31,9 @@ BrowserItemDelegate::BrowserItemDelegate(QObject *parent) : QStyledItemDelegate(parent) -{} +{ + _sizeHint = QSpinBox().sizeHint(); +} QWidget *BrowserItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option, @@ -75,5 +77,5 @@ QSize BrowserItemDelegate::sizeHint(const QStyleOptionViewItem & option, const Q { Q_UNUSED(option); Q_UNUSED(index); - return QSpinBox().sizeHint(); + return _sizeHint; } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h index b9d12af04..3a9a1c3d7 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/browseritemdelegate.h @@ -47,6 +47,9 @@ public: const QStyleOptionViewItem &option, const QModelIndex &index) const; QSize sizeHint(const QStyleOptionViewItem & option, const QModelIndex &index) const; + +private: + QSize _sizeHint; }; #endif // BROWSERITEMDELEGATE_H From 0a40850574c824dca42d0a32d4877cc8e620ea43 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 12 Mar 2018 22:34:40 +0100 Subject: [PATCH 07/20] LP-567 avoid too many QString creations when generating string/hex for array fields --- .../src/plugins/uavobjectbrowser/treeitem.cpp | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index 627c427c1..729608d90 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -212,7 +212,7 @@ void TreeItem::apply() */ void TreeItem::setHighlight(bool highlight) { - m_changed = false; + m_changed = false; if (m_highlight != highlight) { m_highlight = highlight; if (highlight) { @@ -265,28 +265,32 @@ QVariant ArrayFieldTreeItem::data(int column) const if (column == 1) { if (m_field->getType() == UAVObjectField::UINT8 && m_field->getUnits().toLower() == "char") { QString dataString; + dataString.reserve(2 + m_field->getNumElements()); + dataString.append("'"); for (uint i = 0; i < m_field->getNumElements(); ++i) { dataString.append(m_field->getValue(i).toChar()); } - QString data = QString("'%1'").arg(dataString); - return data; + dataString.append("'"); + return dataString; } else if (m_field->getUnits().toLower() == "hex") { QString dataString; + int len = TreeItem::maxHexStringLength(m_field->getType()); + QChar fillChar('0'); + dataString.reserve(2 + (len + 1) * m_field->getNumElements()); + dataString.append("{"); for (uint i = 0; i < m_field->getNumElements(); ++i) { if (i > 0) { dataString.append(' '); } bool ok; - dataString.append(QString("%1") - .arg(m_field->getValue(i).toUInt(&ok), TreeItem::maxHexStringLength(m_field->getType()), - 16, QChar('0')).toUpper()); + uint value = m_field->getValue(i).toUInt(&ok); + QString str = QString("%1").arg(value, len, 16, fillChar); + str = str.toUpper(); + dataString.append(str); } - QString data = QString("{%1}").arg(dataString); - return data; - } else { - return QVariant(); + dataString.append("}"); + return dataString; } - } else { - return TreeItem::data(column); } + return TreeItem::data(column); } From d28cf2a070bd7bc44149b54821bebce48e53bba2 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 15 Mar 2018 21:16:57 +0100 Subject: [PATCH 08/20] LP-567 fix spurious Settings node expand when selecting a Data item was due a regression in the parent() method --- .../src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index a4a41b377..8613650bd 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -295,11 +295,10 @@ QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const return QModelIndex(); } - TreeItem *item = static_cast(index.internalPointer()); + TreeItem *childItem = static_cast(index.internalPointer()); + TreeItem *parentItem = childItem->parent(); - TreeItem *parentItem = item->parent(); - if (!parentItem) { - // item is root has no parent... + if (parentItem == m_rootItem) { return QModelIndex(); } From 5c746fb28a3824d3032212cab202dc24fc1cc466 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 17 Mar 2018 14:53:07 +0100 Subject: [PATCH 09/20] LP-567 uavtalk: show object id has hex in log message --- ground/gcs/src/plugins/uavtalk/uavtalk.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ground/gcs/src/plugins/uavtalk/uavtalk.cpp b/ground/gcs/src/plugins/uavtalk/uavtalk.cpp index 8bb246d90..dc4b4d18a 100644 --- a/ground/gcs/src/plugins/uavtalk/uavtalk.cpp +++ b/ground/gcs/src/plugins/uavtalk/uavtalk.cpp @@ -365,7 +365,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) { UAVObject *rxObj = objMngr->getObject(rxObjId); if (rxObj == NULL && rxType != TYPE_OBJ_REQ) { - qWarning() << "UAVTalk - error : unknown object" << rxObjId; + qWarning().noquote() << "UAVTalk - error : unknown object" << QString::number(rxObjId, 16).toUpper(); stats.rxErrors++; rxState = STATE_ERROR; break; @@ -385,7 +385,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) // Check length and determine next state if (rxLength >= MAX_PAYLOAD_LENGTH) { // packet error - exceeded payload max length - qWarning() << "UAVTalk - error : exceeded payload max length" << rxObjId; + qWarning().noquote() << "UAVTalk - error : exceeded payload max length" << QString::number(rxObjId, 16).toUpper(); stats.rxErrors++; rxState = STATE_ERROR; break; @@ -394,7 +394,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) // Check the lengths match if ((rxPacketLength + rxLength) != packetSize) { // packet error - mismatched packet size - qWarning() << "UAVTalk - error : mismatched packet size" << rxObjId; + qWarning().noquote() << "UAVTalk - error : mismatched packet size" << QString::number(rxObjId, 16).toUpper(); stats.rxErrors++; rxState = STATE_ERROR; break; @@ -430,7 +430,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) if (rxCS != rxCSPacket) { // packet error - faulty CRC - qWarning() << "UAVTalk - error : failed CRC check" << rxObjId; + qWarning().noquote() << "UAVTalk - error : failed CRC check" << QString::number(rxObjId, 16).toUpper(); stats.rxCrcErrors++; rxState = STATE_ERROR; break; @@ -438,7 +438,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte) if (rxPacketLength != packetSize + CHECKSUM_LENGTH) { // packet error - mismatched packet size - qWarning() << "UAVTalk - error : mismatched packet size" << rxObjId; + qWarning().noquote() << "UAVTalk - error : mismatched packet size" << QString::number(rxObjId, 16).toUpper(); stats.rxErrors++; rxState = STATE_ERROR; break; From 3f7dcab185e25e7dd6c6a7965546533a50a207fa Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 17 Mar 2018 14:53:32 +0100 Subject: [PATCH 10/20] LP-567 telemetry: fix typo in comments --- ground/gcs/src/plugins/uavtalk/telemetry.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ground/gcs/src/plugins/uavtalk/telemetry.cpp b/ground/gcs/src/plugins/uavtalk/telemetry.cpp index 78602919f..e118b3291 100644 --- a/ground/gcs/src/plugins/uavtalk/telemetry.cpp +++ b/ground/gcs/src/plugins/uavtalk/telemetry.cpp @@ -79,7 +79,7 @@ Telemetry::~Telemetry() closeAllTransactions(); foreach(QList instances, objMngr->getObjects()) { foreach(UAVObject * object, instances) { - // make sure we 'forget' all objects before we request it from the flight side + // 'forget' all objects object->setIsKnown(false); } } @@ -244,9 +244,8 @@ void Telemetry::transactionCompleted(UAVObject *obj, bool success) if (transInfo) { if (success) { - // We now know tat the flight side knows of this object. + // We now know that the flight side knows of this object. obj->setIsKnown(true); - #ifdef VERBOSE_TELEMETRY qDebug() << "Telemetry - transaction successful for object" << obj->toStringBrief(); #endif From a02bea9aed1a0e44f4a9e799e9c8fbc6c9506f60 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Thu, 22 Mar 2018 09:03:14 +0100 Subject: [PATCH 11/20] LP-567 simplify highlight management it is now the HighlightManager that will emit the highlight related signals TreeItem don't need to be QObjects anymore also fix crashes after changing display options and rebuilding the tree model --- .../plugins/uavobjectbrowser/fieldtreeitem.h | 66 +++--- .../src/plugins/uavobjectbrowser/treeitem.cpp | 142 ++++++------ .../src/plugins/uavobjectbrowser/treeitem.h | 213 +++++++++--------- .../uavobjectbrowser/uavobjectbrowser.cpp | 2 +- .../uavobjectbrowserwidget.cpp | 49 ++-- .../uavobjectbrowser/uavobjectbrowserwidget.h | 12 +- .../uavobjectbrowser/uavobjecttreemodel.cpp | 178 +++++++++------ .../uavobjectbrowser/uavobjecttreemodel.h | 47 ++-- .../gcs/src/plugins/uavobjects/uavobject.cpp | 2 +- ground/gcs/src/plugins/uavobjects/uavobject.h | 2 +- 10 files changed, 382 insertions(+), 331 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h index 7b752f11b..88cd6632d 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h @@ -29,12 +29,14 @@ #define FIELDTREEITEM_H #include "treeitem.h" -#include + +#include #include #include #include #include #include + #include #define QINT8MIN std::numeric_limits::min() @@ -49,15 +51,13 @@ #define QUINT32MAX std::numeric_limits::max() class FieldTreeItem : public TreeItem { - Q_OBJECT public: - FieldTreeItem(int index, const QList &data, UAVObjectField *field, TreeItem *parent = 0) : - TreeItem(data, parent), m_index(index), m_field(field) + FieldTreeItem(int index, const QList &data, UAVObjectField *field, TreeItem *parentItem) : + TreeItem(data, parentItem), m_index(index), m_field(field) {} - - FieldTreeItem(int index, const QVariant &data, UAVObjectField *field, TreeItem *parent = 0) : - TreeItem(data, parent), m_index(index), m_field(field) + FieldTreeItem(int index, const QVariant &data, UAVObjectField *field, TreeItem *parentItem) : + TreeItem(data, parentItem), m_index(index), m_field(field) {} bool isEditable() const @@ -68,10 +68,6 @@ public: virtual QWidget *createEditor(QWidget *parent) const = 0; virtual QVariant getEditorValue(QWidget *editor) const = 0; virtual void setEditorValue(QWidget *editor, QVariant value) const = 0; - virtual bool isKnown() const - { - return parent()->isKnown(); - } void setData(QVariant value, int column) { @@ -93,7 +89,7 @@ public: } } if (changed() || updated) { - setHighlight(true); + setHighlighted(true); } } @@ -112,14 +108,13 @@ protected: }; class EnumFieldTreeItem : public FieldTreeItem { - Q_OBJECT public: - EnumFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent), m_enumOptions(field->getOptions()) + EnumFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem), m_enumOptions(field->getOptions()) {} - EnumFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent), m_enumOptions(field->getOptions()) + EnumFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem), m_enumOptions(field->getOptions()) {} QString enumOptions(int index) @@ -178,16 +173,14 @@ private: }; class IntFieldTreeItem : public FieldTreeItem { - Q_OBJECT public: - IntFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent) + IntFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem) { setMinMaxValues(); } - - IntFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent) + IntFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem) { setMinMaxValues(); } @@ -265,13 +258,12 @@ private: }; class FloatFieldTreeItem : public FieldTreeItem { - Q_OBJECT public: - FloatFieldTreeItem(UAVObjectField *field, int index, const QList &data, bool scientific = false, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent), m_useScientificNotation(scientific) {} + FloatFieldTreeItem(UAVObjectField *field, int index, const QList &data, bool scientific, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem), m_useScientificNotation(scientific) {} - FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, bool scientific = false, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent), m_useScientificNotation(scientific) {} + FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, bool scientific, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem), m_useScientificNotation(scientific) {} QVariant fieldToData() const { @@ -329,14 +321,13 @@ private: }; class HexFieldTreeItem : public FieldTreeItem { - Q_OBJECT public: - HexFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent) + HexFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem) {} - HexFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent) + HexFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem) {} QVariant fieldToData() const @@ -390,14 +381,13 @@ private: }; class CharFieldTreeItem : public FieldTreeItem { - Q_OBJECT public: - CharFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent) + CharFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem) {} - CharFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : - FieldTreeItem(index, data, field, parent) + CharFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : + FieldTreeItem(index, data, field, parentItem) {} QVariant fieldToData() const diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index 729608d90..08bff3ebf 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -27,20 +27,22 @@ #include "treeitem.h" +#include + /* Constructor */ -HighLightManager::HighLightManager() +HighlightManager::HighlightManager() { // Initialize the timer and connect it to the callback m_expirationTimer.setTimerType(Qt::PreciseTimer); m_expirationTimer.setSingleShot(true); - connect(&m_expirationTimer, &QTimer::timeout, this, &HighLightManager::checkItemsExpired); + connect(&m_expirationTimer, &QTimer::timeout, this, &HighlightManager::checkItemsExpired); } /* * Called to add item to list. Item is only added if absent. * Returns true if item was added, otherwise false. */ -bool HighLightManager::add(TreeItem *itemToAdd) +bool HighlightManager::add(TreeItem *itemToAdd) { // Lock to ensure thread safety QMutexLocker locker(&m_mutex); @@ -48,12 +50,31 @@ bool HighLightManager::add(TreeItem *itemToAdd) // Check so that the item isn't already in the list if (!m_items.contains(itemToAdd)) { m_items.insert(itemToAdd); + emit updateHighlight(itemToAdd); return true; } return false; } -bool HighLightManager::startTimer(QTime expirationTime) +/* + * Called to remove item from list. + * Returns true if item was removed, otherwise false. + */ +bool HighlightManager::remove(TreeItem *itemToRemove) +{ + // Lock to ensure thread safety + QMutexLocker locker(&m_mutex); + + // Remove item and return result + const bool removed = m_items.remove(itemToRemove); + + if (removed) { + emit updateHighlight(itemToRemove); + } + return removed; +} + +bool HighlightManager::startTimer(QTime expirationTime) { // Lock to ensure thread safety QMutexLocker locker(&m_mutex); @@ -67,17 +88,15 @@ bool HighLightManager::startTimer(QTime expirationTime) return false; } -/* - * Called to remove item from list. - * Returns true if item was removed, otherwise false. - */ -bool HighLightManager::remove(TreeItem *itemToRemove) + +void HighlightManager::reset() { // Lock to ensure thread safety QMutexLocker locker(&m_mutex); - // Remove item and return result - return m_items.remove(itemToRemove); + m_expirationTimer.stop(); + + m_items.clear(); } /* @@ -86,7 +105,7 @@ bool HighLightManager::remove(TreeItem *itemToRemove) * removes them if they are expired. * Expired highlights are restored. */ -void HighLightManager::checkItemsExpired() +void HighlightManager::checkItemsExpired() { // Lock to ensure thread safety QMutexLocker locker(&m_mutex); @@ -101,16 +120,18 @@ void HighLightManager::checkItemsExpired() // Loop over all items, check if they expired. while (iter.hasNext()) { TreeItem *item = iter.next(); - if (item->getHiglightExpires() <= now) { + if (item->getHighlightExpires() <= now) { // expired, call removeHighlight - item->removeHighlight(); + item->resetHighlight(); // Remove from list since it is restored. iter.remove(); + + emit updateHighlight(item); } else { // not expired, check if next to expire - if (!next.isValid() || (next > item->getHiglightExpires())) { - next = item->getHiglightExpires(); + if (!next.isValid() || (next > item->getHighlightExpires())) { + next = item->getHighlightExpires(); } } } @@ -123,58 +144,54 @@ void HighLightManager::checkItemsExpired() int TreeItem::m_highlightTimeMs = 300; -TreeItem::TreeItem(const QList &data, TreeItem *parent) : - QObject(0), - m_data(data), - m_parent(parent), - m_highlight(false), +TreeItem::TreeItem(const QList &data, TreeItem *parentItem) : + m_itemData(data), + m_parentItem(parentItem), m_changed(false), + m_highlighted(false), m_highlightManager(0) {} -TreeItem::TreeItem(const QVariant &data, TreeItem *parent) : - QObject(0), - m_parent(parent), - m_highlight(false), +TreeItem::TreeItem(const QVariant &data, TreeItem *parentItem) : + m_parentItem(parentItem), m_changed(false), + m_highlighted(false), m_highlightManager(0) { - m_data << data << "" << ""; + m_itemData << data << "" << ""; } TreeItem::~TreeItem() { - qDeleteAll(m_children); + qDeleteAll(m_childItems); } void TreeItem::appendChild(TreeItem *child) { - m_children.append(child); - child->setParentTree(this); + m_childItems.append(child); } void TreeItem::insertChild(TreeItem *child) { int index = nameIndex(child->data(0).toString()); - m_children.insert(index, child); - child->setParentTree(this); + m_childItems.insert(index, child); } -TreeItem *TreeItem::getChild(int index) const +TreeItem *TreeItem::child(int index) const { - return m_children.value(index); + return m_childItems.value(index); } int TreeItem::childCount() const { - return m_children.count(); + return m_childItems.count(); } int TreeItem::row() const { - if (m_parent) { - return m_parent->m_children.indexOf(const_cast(this)); + if (m_parentItem) { + return m_parentItem->m_childItems.indexOf(const_cast(this)); } return 0; @@ -182,84 +199,77 @@ int TreeItem::row() const int TreeItem::columnCount() const { - return m_data.count(); + return m_itemData.count(); } QVariant TreeItem::data(int column) const { - return m_data.value(column); + return m_itemData.value(column); } void TreeItem::setData(QVariant value, int column) { - m_data.replace(column, value); + m_itemData.replace(column, value); } void TreeItem::update() { - foreach(TreeItem * child, treeChildren()) - child->update(); + foreach(TreeItem * child, children()) { + child->update(); + } } void TreeItem::apply() { - foreach(TreeItem * child, treeChildren()) - child->apply(); + foreach(TreeItem * child, children()) { + child->apply(); + } } /* * Called after a value has changed to trigger highlighting of tree item. */ -void TreeItem::setHighlight(bool highlight) +void TreeItem::setHighlighted(bool highlighted) { m_changed = false; - if (m_highlight != highlight) { - m_highlight = highlight; - if (highlight) { + if (m_highlighted != highlighted) { + m_highlighted = highlighted; + if (highlighted) { // Add to highlight manager - if (m_highlightManager->add(this)) { - // Only emit signal if it was added - emit updateHighlight(this); - } + m_highlightManager->add(this); // Update expiration timeout m_highlightExpires = QTime::currentTime().addMSecs(m_highlightTimeMs); // start expiration timer if necessary m_highlightManager->startTimer(m_highlightExpires); - } else if (m_highlightManager->remove(this)) { - // Only emit signal if it was removed - emit updateHighlight(this); + } else { + m_highlightManager->remove(this); } } // If we have a parent, call recursively to update highlight status of parents. // This will ensure that the root of a leaf that is changed also is highlighted. // Only updates that really changes values will trigger highlight of parents. - if (m_parent) { - m_parent->setHighlight(highlight); + if (m_parentItem) { + // FIXME: need to pass m_highlightExpires + m_parentItem->setHighlighted(highlighted); } } -void TreeItem::removeHighlight() +void TreeItem::resetHighlight() { - m_highlight = false; - emit updateHighlight(this); + m_highlighted = false; } -void TreeItem::setHighlightManager(HighLightManager *mgr) +void TreeItem::setHighlightManager(HighlightManager *mgr) { m_highlightManager = mgr; } -QTime TreeItem::getHiglightExpires() const +QTime TreeItem::getHighlightExpires() const { return m_highlightExpires; } -QList TopTreeItem::getMetaObjectItems() -{ - return m_metaObjectTreeItemsPerObjectIds.values(); -} - QVariant ArrayFieldTreeItem::data(int column) const { if (column == 1) { diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h index 481031d09..061a9aeef 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h @@ -31,14 +31,13 @@ #include "uavobject.h" #include "uavmetaobject.h" #include "uavobjectfield.h" -#include -#include -#include -#include -#include -#include -#include -#include + +#include +#include +#include +#include +#include +#include class TreeItem; @@ -57,10 +56,10 @@ class TreeItem; * left untouched in the list. This reduces unwanted emits * of signals to the repaint/update function. */ -class HighLightManager : public QObject { +class HighlightManager : public QObject { Q_OBJECT public: - HighLightManager(); + HighlightManager(); // This is called when an item has been set to // highlighted = true. @@ -71,6 +70,11 @@ public: bool startTimer(QTime time); + void reset(); + +signals: + void updateHighlight(TreeItem *item); + private slots: // Timer callback method. void checkItemsExpired(); @@ -86,23 +90,22 @@ private: QMutex m_mutex; }; -class TreeItem : public QObject { - Q_OBJECT +class TreeItem { public: static const int TITLE_COLUMN = 0; - static const int DATA_COLUMN = 1; + static const int DATA_COLUMN = 1; - TreeItem(const QList &data, TreeItem *parent = 0); - TreeItem(const QVariant &data, TreeItem *parent = 0); + TreeItem(const QList &data, TreeItem *parentItem = 0); + TreeItem(const QVariant &data, TreeItem *parentItem = 0); virtual ~TreeItem(); void appendChild(TreeItem *child); void insertChild(TreeItem *child); - TreeItem *getChild(int index) const; - inline QList treeChildren() const + TreeItem *child(int index) const; + QList children() const { - return m_children; + return m_childItems; } int childCount() const; int columnCount() const; @@ -124,50 +127,57 @@ public: // other columns are initialized in constructor virtual void setData(QVariant value, int column = 1); int row() const; - TreeItem *parent() const + TreeItem *parentItem() const { - return m_parent; + return m_parentItem; } - void setParentTree(TreeItem *parent) - { - m_parent = parent; - } - inline virtual bool isEditable() const + virtual bool isEditable() const { return false; } virtual void update(); virtual void apply(); - inline bool highlighted() const + bool changed() const { - return m_highlight; + return m_changed; } - void setHighlight(bool highlight); + + void setChanged(bool changed) + { + m_changed = changed; + } + + bool isHighlighted() const + { + return m_highlighted; + } + + void setHighlighted(bool highlighted); + static void setHighlightTime(int time) { m_highlightTimeMs = time; } - inline bool changed() const + QTime getHighlightExpires() const; + + void resetHighlight(); + + void setHighlightManager(HighlightManager *mgr); + + virtual bool isKnown() const { - return m_changed; + if (m_parentItem) { + return m_parentItem->isKnown(); + } + return true; } - inline void setChanged(bool changed) - { - m_changed = changed; - } - - virtual void setHighlightManager(HighLightManager *mgr); - - QTime getHiglightExpires() const; - - virtual void removeHighlight(); int nameIndex(QString name) const { for (int i = 0; i < childCount(); ++i) { - if (name < getChild(i)->data(0).toString()) { + if (name < child(i)->data(0).toString()) { return i; } } @@ -176,7 +186,7 @@ public: TreeItem *findChildByName(QString name) const { - foreach(TreeItem * child, m_children) { + foreach(TreeItem * child, m_childItems) { if (name == child->data(0).toString()) { return child; } @@ -210,49 +220,35 @@ public: } return 0; } - void updateIsKnown(bool isKnown) - { - if (isKnown != this->isKnown()) { - m_changed = false; - foreach(TreeItem * child, m_children) { - child->updateIsKnown(isKnown); - } - emit updateIsKnown(this); - } - } - virtual bool isKnown() const - { - return true; - } - -signals: - void updateHighlight(TreeItem *item); - void updateIsKnown(TreeItem *item); - -private slots: private: static int m_highlightTimeMs; - QList m_children; + QList m_childItems; // m_data contains: [0] property name, [1] value, [2] unit - QList m_data; + QList m_itemData; + TreeItem *m_parentItem; + QString m_description; - TreeItem *m_parent; - bool m_highlight; + bool m_changed; + + bool m_highlighted; QTime m_highlightExpires; - HighLightManager *m_highlightManager; + HighlightManager *m_highlightManager; }; class DataObjectTreeItem; class MetaObjectTreeItem; class TopTreeItem : public TreeItem { - Q_OBJECT public: - TopTreeItem(const QList &data, TreeItem *parent = 0) : TreeItem(data, parent) {} - TopTreeItem(const QVariant &data, TreeItem *parent = 0) : TreeItem(data, parent) {} + TopTreeItem(const QList &data, TreeItem *parentItem) : + TreeItem(data, parentItem) + {} + TopTreeItem(const QVariant &data, TreeItem *parentItem) : + TreeItem(data, parentItem) + {} void addObjectTreeItem(quint32 objectId, DataObjectTreeItem *oti) { @@ -274,65 +270,55 @@ public: return m_metaObjectTreeItemsPerObjectIds.value(objectId, 0); } - QList getMetaObjectItems(); - private: QHash m_objectTreeItemsPerObjectIds; QHash m_metaObjectTreeItemsPerObjectIds; }; class ObjectTreeItem : public TreeItem { - Q_OBJECT public: - ObjectTreeItem(const QList &data, UAVObject *object, TreeItem *parent = 0) : - TreeItem(data, parent), m_obj(object) + ObjectTreeItem(const QList &data, UAVObject *object, TreeItem *parentItem) : + TreeItem(data, parentItem), m_obj(object) { setDescription(m_obj->getDescription()); } - ObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parent = 0) : - TreeItem(data, parent), m_obj(object) + ObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parentItem) : + TreeItem(data, parentItem), m_obj(object) { setDescription(m_obj->getDescription()); } - inline UAVObject *object() + + UAVObject *object() const { return m_obj; } - bool isKnown() - { - return !m_obj->isSettingsObject() || m_obj->isKnown(); - } private: UAVObject *m_obj; }; class MetaObjectTreeItem : public ObjectTreeItem { - Q_OBJECT public: - MetaObjectTreeItem(UAVObject *object, const QList &data, TreeItem *parent = 0) : - ObjectTreeItem(data, object, parent) + MetaObjectTreeItem(UAVObject *object, const QList &data, TreeItem *parentItem) : + ObjectTreeItem(data, object, parentItem) {} - MetaObjectTreeItem(UAVObject *object, const QVariant &data, TreeItem *parent = 0) : - ObjectTreeItem(data, object, parent) + MetaObjectTreeItem(UAVObject *object, const QVariant &data, TreeItem *parentItem) : + ObjectTreeItem(data, object, parentItem) {} - - bool isKnown() - { - return parent()->isKnown(); - } }; class DataObjectTreeItem : public ObjectTreeItem { - Q_OBJECT public: - DataObjectTreeItem(const QList &data, UAVObject *object, TreeItem *parent = 0) : - ObjectTreeItem(data, object, parent) {} - DataObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parent = 0) : - ObjectTreeItem(data, object, parent) {} + DataObjectTreeItem(const QList &data, UAVObject *object, TreeItem *parentItem) : + ObjectTreeItem(data, object, parentItem) + {} + DataObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parentItem) : + ObjectTreeItem(data, object, parentItem) + {} + virtual void apply() { - foreach(TreeItem * child, treeChildren()) { + foreach(TreeItem * child, children()) { MetaObjectTreeItem *metaChild = dynamic_cast(child); if (!metaChild) { @@ -340,9 +326,10 @@ public: } } } + virtual void update() { - foreach(TreeItem * child, treeChildren()) { + foreach(TreeItem * child, children()) { MetaObjectTreeItem *metaChild = dynamic_cast(child); if (!metaChild) { @@ -350,21 +337,27 @@ public: } } } + + virtual bool isKnown() const + { + return !object()->isSettingsObject() || object()->isKnown(); + } }; class InstanceTreeItem : public DataObjectTreeItem { - Q_OBJECT public: - InstanceTreeItem(UAVObject *object, const QList &data, TreeItem *parent = 0) : - DataObjectTreeItem(data, object, parent) + InstanceTreeItem(UAVObject *object, const QList &data, TreeItem *parentItem) : + DataObjectTreeItem(data, object, parentItem) {} - InstanceTreeItem(UAVObject *object, const QVariant &data, TreeItem *parent = 0) : - DataObjectTreeItem(data, object, parent) + InstanceTreeItem(UAVObject *object, const QVariant &data, TreeItem *parentItem) : + DataObjectTreeItem(data, object, parentItem) {} + virtual void apply() { TreeItem::apply(); } + virtual void update() { TreeItem::update(); @@ -372,17 +365,15 @@ public: }; class ArrayFieldTreeItem : public TreeItem { - Q_OBJECT public: - ArrayFieldTreeItem(UAVObjectField *field, const QList &data, TreeItem *parent = 0) : TreeItem(data, parent), m_field(field) + ArrayFieldTreeItem(UAVObjectField *field, const QList &data, TreeItem *parentItem) : + TreeItem(data, parentItem), m_field(field) {} - ArrayFieldTreeItem(UAVObjectField *field, const QVariant &data, TreeItem *parent = 0) : TreeItem(data, parent), m_field(field) + ArrayFieldTreeItem(UAVObjectField *field, const QVariant &data, TreeItem *parentItem) : + TreeItem(data, parentItem), m_field(field) {} + QVariant data(int column) const; - bool isKnown() - { - return parent()->isKnown(); - } private: UAVObjectField *m_field; diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp index 0eb9011fd..4c4caa715 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp @@ -50,7 +50,7 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration *config) m_widget->setRecentlyUpdatedColor(m->recentlyUpdatedColor()); m_widget->setManuallyChangedColor(m->manuallyChangedColor()); m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout()); - m_widget->setOnlyHilightChangedValues(m->onlyHighlightChangedValues()); + m_widget->setOnlyHighlightChangedValues(m->onlyHighlightChangedValues()); m_widget->setViewOptions(m->categorizedView(), m->scientificView(), m->showMetaData(), m->showDescription()); m_widget->setSplitterState(m->splitterState()); } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index b7ab69aef..07b0f325f 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -38,6 +38,7 @@ #include "extensionsystem/pluginmanager.h" #include "utils/mustache.h" +#include #include UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent) @@ -47,10 +48,7 @@ UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent m_viewoptions = new Ui_viewoptions(); m_viewoptions->setupUi(m_viewoptionsDialog); - m_model = new UAVObjectTreeModel(this, - m_viewoptions->cbCategorized->isChecked(), - m_viewoptions->cbMetaData->isChecked(), - m_viewoptions->cbScientific->isChecked()); + m_model = createTreeModel(); m_modelProxy = new TreeSortFilterProxyModel(this); m_modelProxy->setSourceModel(m_model); @@ -156,7 +154,7 @@ ObjectTreeItem *UAVObjectBrowserWidget::findCurrentObjectTreeItem() if (objItem) { break; } - item = item->parent(); + item = item->parentItem(); } return objItem; } @@ -186,7 +184,7 @@ void UAVObjectBrowserWidget::saveObject() if (objItem != NULL) { UAVObject *obj = objItem->object(); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); + updateObjectPersistence(ObjectPersistence::OPERATION_SAVE, obj); } } @@ -198,7 +196,7 @@ void UAVObjectBrowserWidget::loadObject() if (objItem != NULL) { UAVObject *obj = objItem->object(); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_LOAD, obj); + updateObjectPersistence(ObjectPersistence::OPERATION_LOAD, obj); // Retrieve object so that latest value is displayed requestUpdate(); } @@ -211,13 +209,13 @@ void UAVObjectBrowserWidget::eraseObject() if (objItem != NULL) { UAVObject *obj = objItem->object(); Q_ASSERT(obj); - updateObjectPersistance(ObjectPersistence::OPERATION_DELETE, obj); + updateObjectPersistence(ObjectPersistence::OPERATION_DELETE, obj); // Retrieve object so that correct default value is displayed requestUpdate(); } } -void UAVObjectBrowserWidget::updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj) +void UAVObjectBrowserWidget::updateObjectPersistence(ObjectPersistence::OperationOptions op, UAVObject *obj) { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); @@ -238,11 +236,11 @@ void UAVObjectBrowserWidget::currentChanged(const QModelIndex ¤t, const QM { Q_UNUSED(previous); - TreeItem *item = static_cast(current.data(Qt::UserRole).value()); - bool enable = true; + bool enable = true; if (!current.isValid()) { enable = false; } + TreeItem *item = static_cast(current.data(Qt::UserRole).value()); TopTreeItem *top = dynamic_cast(item); ObjectTreeItem *data = dynamic_cast(item); if (top || (data && !data->object())) { @@ -264,25 +262,33 @@ void UAVObjectBrowserWidget::viewSlot() } } -void UAVObjectBrowserWidget::updateViewOptions() +UAVObjectTreeModel *UAVObjectBrowserWidget::createTreeModel() { - // TODO we should update the model instead of rebuilding it - // a side effect of rebuilding is that some state is lost (expand state, ...) UAVObjectTreeModel *model = new UAVObjectTreeModel(this, m_viewoptions->cbCategorized->isChecked(), m_viewoptions->cbMetaData->isChecked(), m_viewoptions->cbScientific->isChecked()); - model->setUnknowObjectColor(m_unknownObjectColor); model->setRecentlyUpdatedColor(m_recentlyUpdatedColor); model->setManuallyChangedColor(m_manuallyChangedColor); model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout); - model->setOnlyHilightChangedValues(m_onlyHilightChangedValues); + model->setUnknowObjectColor(m_unknownObjectColor); + model->setOnlyHighlightChangedValues(m_onlyHighlightChangedValues); - UAVObjectTreeModel *tmpModel = m_model; - m_model = model; - m_modelProxy->setSourceModel(m_model); - delete tmpModel; + return model; +} + +void UAVObjectBrowserWidget::updateViewOptions() +{ + bool categorize = m_viewoptions->cbCategorized->isChecked(); + bool useScientificNotation = m_viewoptions->cbScientific->isChecked(); + bool showMetadata = m_viewoptions->cbMetaData->isChecked(); + bool showDesc = m_viewoptions->cbDescription->isChecked(); + + m_model->setShowCategories(categorize); + m_model->setShowMetadata(showMetadata); + m_model->setShowScientificNotation(useScientificNotation); + m_model->resetModelData(); // force an expand all if search text is not empty if (!m_browser->searchLine->text().isEmpty()) { @@ -290,8 +296,7 @@ void UAVObjectBrowserWidget::updateViewOptions() } // persist options - emit viewOptionsChanged(m_viewoptions->cbCategorized->isChecked(), m_viewoptions->cbScientific->isChecked(), - m_viewoptions->cbMetaData->isChecked(), m_viewoptions->cbDescription->isChecked()); + emit viewOptionsChanged(categorize, useScientificNotation, showMetadata, showDesc); } void UAVObjectBrowserWidget::splitterMoved() diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h index d5d536dd7..437edb2ba 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h @@ -79,10 +79,10 @@ public: m_recentlyUpdatedTimeout = timeout; m_model->setRecentlyUpdatedTimeout(timeout); } - void setOnlyHilightChangedValues(bool hilight) + void setOnlyHighlightChangedValues(bool hilight) { - m_onlyHilightChangedValues = hilight; - m_model->setOnlyHilightChangedValues(hilight); + m_onlyHighlightChangedValues = hilight; + m_model->setOnlyHighlightChangedValues(hilight); } void setViewOptions(bool categorized, bool scientific, bool metadata, bool description); void setSplitterState(QByteArray state); @@ -119,10 +119,12 @@ private: QColor m_unknownObjectColor; QColor m_recentlyUpdatedColor; QColor m_manuallyChangedColor; - bool m_onlyHilightChangedValues; + bool m_onlyHighlightChangedValues; QString m_mustacheTemplate; - void updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj); + UAVObjectTreeModel *createTreeModel(); + + void updateObjectPersistence(ObjectPersistence::OperationOptions op, UAVObject *obj); void enableSendRequest(bool enable); void updateDescription(); ObjectTreeItem *findCurrentObjectTreeItem(); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 8613650bd..749fe9a11 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -26,16 +26,15 @@ */ #include "uavobjecttreemodel.h" + #include "fieldtreeitem.h" #include "uavobjectmanager.h" #include "uavdataobject.h" #include "uavmetaobject.h" #include "uavobjectfield.h" #include "extensionsystem/pluginmanager.h" + #include -#include -#include -#include UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent, bool categorize, bool showMetadata, bool useScientificNotation) : QAbstractItemModel(parent), @@ -52,36 +51,78 @@ UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent, bool categorize, bool sh Q_ASSERT(objManager); - m_highlightManager = new HighLightManager(); connect(objManager, SIGNAL(newObject(UAVObject *)), this, SLOT(newObject(UAVObject *))); connect(objManager, SIGNAL(newInstance(UAVObject *)), this, SLOT(newObject(UAVObject *))); + m_highlightManager = new HighlightManager(); + connect(m_highlightManager, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); + TreeItem::setHighlightTime(m_recentlyUpdatedTimeout); setupModelData(objManager); } UAVObjectTreeModel::~UAVObjectTreeModel() { - delete m_highlightManager; delete m_rootItem; + delete m_highlightManager; } +void UAVObjectTreeModel::resetModelData() +{ + m_highlightManager->reset(); + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + Q_ASSERT(objManager); + + emit beginResetModel(); + + delete m_rootItem; + m_rootItem = NULL; + setupModelData(objManager); + + emit endResetModel(); +} + +void UAVObjectTreeModel::setShowCategories(bool showCategories) +{ + if (showCategories == m_categorize) { + return; + } + m_categorize = showCategories; +} + +void UAVObjectTreeModel::setShowMetadata(bool showMetadata) +{ + if (showMetadata == m_showMetadata) { + return; + } + m_showMetadata = showMetadata; +} + +void UAVObjectTreeModel::setShowScientificNotation(bool showScientificNotation) +{ + if (showScientificNotation == m_useScientificFloatNotation) { + return; + } + m_useScientificFloatNotation = showScientificNotation; +} + + void UAVObjectTreeModel::setupModelData(UAVObjectManager *objManager) { - m_settingsTree = new TopTreeItem(tr("Settings")); - m_settingsTree->setHighlightManager(m_highlightManager); - connect(m_settingsTree, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); - - m_nonSettingsTree = new TopTreeItem(tr("Data Objects")); - m_nonSettingsTree->setHighlightManager(m_highlightManager); - connect(m_nonSettingsTree, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); - // root QList rootData; rootData << tr("Property") << tr("Value") << tr("Unit"); - m_rootItem = new TreeItem(rootData); + m_rootItem = new TreeItem(rootData); m_rootItem->setHighlightManager(m_highlightManager); + m_settingsTree = new TopTreeItem(tr("Settings"), m_rootItem); + m_settingsTree->setHighlightManager(m_highlightManager); + + m_nonSettingsTree = new TopTreeItem(tr("Data Objects"), m_rootItem); + m_nonSettingsTree->setHighlightManager(m_highlightManager); + // tree item takes ownership of its children m_rootItem->appendChild(m_settingsTree); m_rootItem->appendChild(m_nonSettingsTree); @@ -89,6 +130,7 @@ void UAVObjectTreeModel::setupModelData(UAVObjectManager *objManager) QList< QList > objList = objManager->getDataObjects(); foreach(QList list, objList) { foreach(UAVDataObject * obj, list) { + disconnect(obj, 0, this, 0); addDataObject(obj); } } @@ -118,10 +160,9 @@ void UAVObjectTreeModel::addDataObject(UAVDataObject *obj) if (existing) { addInstance(obj, existing); } else { - DataObjectTreeItem *dataTreeItem = new DataObjectTreeItem(obj->getName(), obj); + DataObjectTreeItem *dataTreeItem = new DataObjectTreeItem(obj->getName(), obj, parent); dataTreeItem->setHighlightManager(m_highlightManager); - connect(dataTreeItem, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); - connect(dataTreeItem, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); + parent->insertChild(dataTreeItem); root->addObjectTreeItem(obj->getObjID(), dataTreeItem); if (m_showMetadata) { @@ -141,9 +182,9 @@ TreeItem *UAVObjectTreeModel::createCategoryItems(QStringList categoryPath, Tree TreeItem *existing = parent->findChildByName(category); if (!existing) { - TreeItem *categoryItem = new TopTreeItem(category); - connect(categoryItem, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); + TreeItem *categoryItem = new TopTreeItem(category, parent); categoryItem->setHighlightManager(m_highlightManager); + parent->insertChild(categoryItem); parent = categoryItem; } else { @@ -155,11 +196,11 @@ TreeItem *UAVObjectTreeModel::createCategoryItems(QStringList categoryPath, Tree MetaObjectTreeItem *UAVObjectTreeModel::addMetaObject(UAVMetaObject *obj, TreeItem *parent) { - connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(highlightUpdatedObject(UAVObject *))); - MetaObjectTreeItem *meta = new MetaObjectTreeItem(obj, tr("Meta Data")); + connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateObject(UAVObject *))); + MetaObjectTreeItem *meta = new MetaObjectTreeItem(obj, tr("Meta Data"), parent); meta->setHighlightManager(m_highlightManager); - connect(meta, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); + foreach(UAVObjectField * field, obj->getFields()) { if (field->getNumElements() > 1) { addArrayField(field, meta); @@ -173,19 +214,16 @@ MetaObjectTreeItem *UAVObjectTreeModel::addMetaObject(UAVMetaObject *obj, TreeIt void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent) { - connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(highlightUpdatedObject(UAVObject *))); - connect(obj, SIGNAL(isKnownChanged(UAVObject *, bool)), this, SLOT(isKnownChanged(UAVObject *, bool))); + connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateObject(UAVObject *))); + connect(obj, SIGNAL(isKnownChanged(UAVObject *)), this, SLOT(updateIsKnown(UAVObject *))); + TreeItem *item; if (obj->isSingleInstance()) { item = parent; - DataObjectTreeItem *objectItem = static_cast(parent); - connect(objectItem, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); } else { QString name = tr("Instance") + " " + QString::number(obj->getInstID()); - item = new InstanceTreeItem(obj, name); + item = new InstanceTreeItem(obj, name, parent); item->setHighlightManager(m_highlightManager); - connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); - connect(item, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); parent->appendChild(item); } foreach(UAVObjectField * field, obj->getFields()) { @@ -199,15 +237,14 @@ void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent) void UAVObjectTreeModel::addArrayField(UAVObjectField *field, TreeItem *parent) { - TreeItem *item = new ArrayFieldTreeItem(field, field->getName()); + TreeItem *item = new ArrayFieldTreeItem(field, field->getName(), parent); item->setHighlightManager(m_highlightManager); - connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); - connect(item, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); - for (uint i = 0; i < field->getNumElements(); ++i) { + parent->appendChild(item); + + for (int i = 0; i < (int)field->getNumElements(); ++i) { addSingleField(i, field, item); } - parent->appendChild(item); } void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeItem *parent) @@ -229,7 +266,7 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt QVariant value = field->getValue(index); data.append(options.indexOf(value.toString())); data.append(field->getUnits()); - item = new EnumFieldTreeItem(field, index, data); + item = new EnumFieldTreeItem(field, index, data, parent); break; } case UAVObjectField::INT8: @@ -241,25 +278,25 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt data.append(field->getValue(index)); data.append(field->getUnits()); if (field->getUnits().toLower() == "hex") { - item = new HexFieldTreeItem(field, index, data); + item = new HexFieldTreeItem(field, index, data, parent); } else if (field->getUnits().toLower() == "char") { - item = new CharFieldTreeItem(field, index, data); + item = new CharFieldTreeItem(field, index, data, parent); } else { - item = new IntFieldTreeItem(field, index, data); + item = new IntFieldTreeItem(field, index, data, parent); } break; case UAVObjectField::FLOAT32: data.append(field->getValue(index)); data.append(field->getUnits()); - item = new FloatFieldTreeItem(field, index, data, m_useScientificFloatNotation); + item = new FloatFieldTreeItem(field, index, data, m_useScientificFloatNotation, parent); break; default: Q_ASSERT(false); } + item->setHighlightManager(m_highlightManager); item->setDescription(field->getDescription()); - connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); - connect(item, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); + parent->appendChild(item); } @@ -270,14 +307,13 @@ QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &pa } TreeItem *parentItem; - if (!parent.isValid()) { parentItem = m_rootItem; } else { parentItem = static_cast(parent.internalPointer()); } - TreeItem *childItem = parentItem->getChild(row); + TreeItem *childItem = parentItem->child(row); if (childItem) { return createIndex(row, column, childItem); } @@ -286,6 +322,10 @@ QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &pa QModelIndex UAVObjectTreeModel::index(TreeItem *item, int column) { + if (item == m_rootItem) { + return QModelIndex(); + } + return createIndex(item->row(), column, item); } @@ -296,7 +336,7 @@ QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const } TreeItem *childItem = static_cast(index.internalPointer()); - TreeItem *parentItem = childItem->parent(); + TreeItem *parentItem = childItem->parentItem(); if (parentItem == m_rootItem) { return QModelIndex(); @@ -324,24 +364,15 @@ int UAVObjectTreeModel::rowCount(const QModelIndex &parent) const int UAVObjectTreeModel::columnCount(const QModelIndex &parent) const { + TreeItem *parentItem; + if (parent.isValid()) { - return static_cast(parent.internalPointer())->columnCount(); + parentItem = static_cast(parent.internalPointer()); } else { - return m_rootItem->columnCount(); - } -} - -QList UAVObjectTreeModel::getMetaDataIndexes() -{ - QList metaIndexes; - foreach(MetaObjectTreeItem * metaItem, m_settingsTree->getMetaObjectItems()) { - metaIndexes.append(index(metaItem)); + parentItem = m_rootItem; } - foreach(MetaObjectTreeItem * metaItem, m_nonSettingsTree->getMetaObjectItems()) { - metaIndexes.append(index(metaItem)); - } - return metaIndexes; + return parentItem->columnCount(); } QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const @@ -380,12 +411,12 @@ QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const case Qt::BackgroundRole: if (index.column() == TreeItem::TITLE_COLUMN) { - if (!dynamic_cast(item) && item->highlighted()) { + if (!dynamic_cast(item) && item->isHighlighted()) { return m_recentlyUpdatedColor; } } else if (index.column() == TreeItem::DATA_COLUMN) { FieldTreeItem *fieldItem = dynamic_cast(item); - if (fieldItem && fieldItem->highlighted()) { + if (fieldItem && fieldItem->isHighlighted()) { return m_recentlyUpdatedColor; } if (fieldItem && fieldItem->changed()) { @@ -435,19 +466,18 @@ QVariant UAVObjectTreeModel::headerData(int section, Qt::Orientation orientation if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { return m_rootItem->data(section); } - return QVariant(); } -void UAVObjectTreeModel::highlightUpdatedObject(UAVObject *obj) +void UAVObjectTreeModel::updateObject(UAVObject *obj) { Q_ASSERT(obj); ObjectTreeItem *item = findObjectTreeItem(obj); Q_ASSERT(item); - if (!m_onlyHilightChangedValues) { - item->setHighlight(true); - } item->update(); + if (!m_onlyHighlightChangedValues) { + item->setHighlighted(true); + } } ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(UAVObject *object) @@ -498,6 +528,15 @@ void UAVObjectTreeModel::updateHighlight(TreeItem *item) emit dataChanged(itemIndex, itemIndex); } +void UAVObjectTreeModel::updateIsKnown(UAVObject *object) +{ + ObjectTreeItem *item = findObjectTreeItem(object); + + if (item) { + updateIsKnown(item); + } +} + void UAVObjectTreeModel::updateIsKnown(TreeItem *item) { QModelIndex itemIndex; @@ -505,13 +544,8 @@ void UAVObjectTreeModel::updateIsKnown(TreeItem *item) itemIndex = index(item, TreeItem::TITLE_COLUMN); Q_ASSERT(itemIndex != QModelIndex()); emit dataChanged(itemIndex, itemIndex); -} -void UAVObjectTreeModel::isKnownChanged(UAVObject *object, bool isKnown) -{ - Q_UNUSED(isKnown); - ObjectTreeItem *item = findObjectTreeItem(object); - if (item) { - item->updateIsKnown(isKnown); + foreach(TreeItem * child, item->children()) { + updateIsKnown(child); } } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index 65882e9fe..c037f4d5f 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -29,9 +29,10 @@ #define UAVOBJECTTREEMODEL_H #include "treeitem.h" + #include -#include -#include +#include +#include #include class TopTreeItem; @@ -49,7 +50,6 @@ class UAVObjectTreeModel : public QAbstractItemModel { Q_OBJECT public: explicit UAVObjectTreeModel(QObject *parent, bool categorize, bool showMetadata, bool useScientificNotation); - explicit UAVObjectTreeModel(bool categorize, bool showMetadata, bool useScientificNotation); ~UAVObjectTreeModel(); QVariant data(const QModelIndex &index, int role) const; @@ -63,6 +63,29 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; + void resetModelData(); + + bool showCategories() + { + return m_categorize; + } + + void setShowCategories(bool showCategories); + + bool showMetadata() + { + return m_showMetadata; + } + + void setShowMetadata(bool showMetadata); + + bool showScientificNotation() + { + return m_useScientificFloatNotation; + } + + void setShowScientificNotation(bool showScientificNotation); + void setUnknowObjectColor(QColor color) { m_unknownObjectColor = color; @@ -80,27 +103,23 @@ public: m_recentlyUpdatedTimeout = timeout; TreeItem::setHighlightTime(timeout); } - void setOnlyHilightChangedValues(bool hilight) + void setOnlyHighlightChangedValues(bool hilight) { - m_onlyHilightChangedValues = hilight; + m_onlyHighlightChangedValues = hilight; } - QList getMetaDataIndexes(); - -signals: - public slots: void newObject(UAVObject *obj); private slots: + void updateObject(UAVObject *obj); + void updateIsKnown(UAVObject *obj); void updateHighlight(TreeItem *item); void updateIsKnown(TreeItem *item); - void highlightUpdatedObject(UAVObject *obj); - void isKnownChanged(UAVObject *object, bool isKnown); private: - void setupModelData(UAVObjectManager *objManager); QModelIndex index(TreeItem *item, int column = 0); + void setupModelData(UAVObjectManager *objManager); void addDataObject(UAVDataObject *obj); MetaObjectTreeItem *addMetaObject(UAVMetaObject *obj, TreeItem *parent); void addArrayField(UAVObjectField *field, TreeItem *parent); @@ -124,10 +143,10 @@ private: QColor m_recentlyUpdatedColor; QColor m_manuallyChangedColor; QColor m_unknownObjectColor; - bool m_onlyHilightChangedValues; + bool m_onlyHighlightChangedValues; // Highlight manager to handle highlighting of tree items. - HighLightManager *m_highlightManager; + HighlightManager *m_highlightManager; }; #endif // UAVOBJECTTREEMODEL_H diff --git a/ground/gcs/src/plugins/uavobjects/uavobject.cpp b/ground/gcs/src/plugins/uavobjects/uavobject.cpp index 63b07b8fc..8a95d873b 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobject.cpp +++ b/ground/gcs/src/plugins/uavobjects/uavobject.cpp @@ -622,7 +622,7 @@ void UAVObject::setIsKnown(bool isKnown) unlock(); if (changed) { - emit isKnownChanged(this, isKnown); + emit isKnownChanged(this); } } diff --git a/ground/gcs/src/plugins/uavobjects/uavobject.h b/ground/gcs/src/plugins/uavobjects/uavobject.h index 26c24f037..a1e332b16 100644 --- a/ground/gcs/src/plugins/uavobjects/uavobject.h +++ b/ground/gcs/src/plugins/uavobjects/uavobject.h @@ -181,7 +181,7 @@ signals: void updateRequested(UAVObject *obj, bool all = false); void transactionCompleted(UAVObject *obj, bool success); void newInstance(UAVObject *obj); - void isKnownChanged(UAVObject *obj, bool isKnown); + void isKnownChanged(UAVObject *obj); protected: quint32 objID; From f27258a5988d66918442d094a44e22b635c5a4de Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 25 Mar 2018 19:03:15 +0200 Subject: [PATCH 12/20] LP-567 rewrite uavobjecttreemodel to better handle dynamic changes don't rebuild the model when toggling options (categories, meta, scientific notation) fixes a number of issues when adding/removing/removing items dynamically for example, new object instances would not appear if added dynamically selection and expansion states are not lost when toogling options note that toggling categories is not really well behaved concerning expansion state... --- .../uavobjectbrowser/fieldtreeitem.cpp | 28 - .../plugins/uavobjectbrowser/fieldtreeitem.h | 63 +- .../src/plugins/uavobjectbrowser/treeitem.cpp | 100 +++- .../src/plugins/uavobjectbrowser/treeitem.h | 196 +++---- .../uavobjectbrowser/uavobjectbrowser.cpp | 2 +- .../uavobjectbrowser/uavobjectbrowser.pro | 23 +- .../uavobjectbrowserwidget.cpp | 34 +- .../uavobjectbrowser/uavobjectbrowserwidget.h | 4 +- .../uavobjectbrowser/uavobjecttreemodel.cpp | 545 +++++++++++------- .../uavobjectbrowser/uavobjecttreemodel.h | 117 ++-- 10 files changed, 630 insertions(+), 482 deletions(-) delete mode 100644 ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.cpp diff --git a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.cpp deleted file mode 100644 index 2c1407d06..000000000 --- a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/** - ****************************************************************************** - * - * @file fieldtreeitem.cpp - * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010. - * @addtogroup GCSPlugins GCS Plugins - * @{ - * @addtogroup UAVObjectBrowserPlugin UAVObject Browser Plugin - * @{ - * @brief The UAVObject Browser gadget plugin - *****************************************************************************/ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "fieldtreeitem.h" diff --git a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h index 88cd6632d..271198c78 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h @@ -31,6 +31,7 @@ #include "treeitem.h" #include +#include #include #include #include @@ -53,11 +54,11 @@ class FieldTreeItem : public TreeItem { public: - FieldTreeItem(int index, const QList &data, UAVObjectField *field, TreeItem *parentItem) : - TreeItem(data, parentItem), m_index(index), m_field(field) + FieldTreeItem(int index, const QList &data, UAVObjectField *field) : + TreeItem(data), m_index(index), m_field(field) {} - FieldTreeItem(int index, const QVariant &data, UAVObjectField *field, TreeItem *parentItem) : - TreeItem(data, parentItem), m_index(index), m_field(field) + FieldTreeItem(int index, const QVariant &data, UAVObjectField *field) : + TreeItem(data), m_index(index), m_field(field) {} bool isEditable() const @@ -109,12 +110,12 @@ protected: class EnumFieldTreeItem : public FieldTreeItem { public: - EnumFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem), m_enumOptions(field->getOptions()) + EnumFieldTreeItem(UAVObjectField *field, int index, const QList &data) : + FieldTreeItem(index, data, field), m_enumOptions(field->getOptions()) {} - EnumFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem), m_enumOptions(field->getOptions()) + EnumFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) : + FieldTreeItem(index, data, field), m_enumOptions(field->getOptions()) {} QString enumOptions(int index) @@ -174,13 +175,13 @@ private: class IntFieldTreeItem : public FieldTreeItem { public: - IntFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem) + IntFieldTreeItem(UAVObjectField *field, int index, const QList &data) : + FieldTreeItem(index, data, field) { setMinMaxValues(); } - IntFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem) + IntFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) : + FieldTreeItem(index, data, field) { setMinMaxValues(); } @@ -259,11 +260,11 @@ private: class FloatFieldTreeItem : public FieldTreeItem { public: - FloatFieldTreeItem(UAVObjectField *field, int index, const QList &data, bool scientific, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem), m_useScientificNotation(scientific) {} + FloatFieldTreeItem(UAVObjectField *field, int index, const QList &data, const QSettings &settings) : + FieldTreeItem(index, data, field), m_settings(settings) {} - FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, bool scientific, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem), m_useScientificNotation(scientific) {} + FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, const QSettings &settings) : + FieldTreeItem(index, data, field), m_settings(settings) {} QVariant fieldToData() const { @@ -277,7 +278,9 @@ public: QWidget *createEditor(QWidget *parent) const { - if (m_useScientificNotation) { + bool useScientificNotation = m_settings.value("useScientificNotation", false).toBool(); + + if (useScientificNotation) { QScienceSpinBox *editor = new QScienceSpinBox(parent); editor->setDecimals(6); editor->setMinimum(-std::numeric_limits::max()); @@ -294,7 +297,9 @@ public: QVariant getEditorValue(QWidget *editor) const { - if (m_useScientificNotation) { + bool useScientificNotation = m_settings.value("useScientificNotation", false).toBool(); + + if (useScientificNotation) { QScienceSpinBox *spinBox = static_cast(editor); spinBox->interpretText(); return spinBox->value(); @@ -307,7 +312,9 @@ public: void setEditorValue(QWidget *editor, QVariant value) const { - if (m_useScientificNotation) { + bool useScientificNotation = m_settings.value("useScientificNotation", false).toBool(); + + if (useScientificNotation) { QScienceSpinBox *spinBox = static_cast(editor); spinBox->setValue(value.toDouble()); } else { @@ -317,17 +324,17 @@ public: } private: - bool m_useScientificNotation; + const QSettings &m_settings; }; class HexFieldTreeItem : public FieldTreeItem { public: - HexFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem) + HexFieldTreeItem(UAVObjectField *field, int index, const QList &data) : + FieldTreeItem(index, data, field) {} - HexFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem) + HexFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) : + FieldTreeItem(index, data, field) {} QVariant fieldToData() const @@ -382,12 +389,12 @@ private: class CharFieldTreeItem : public FieldTreeItem { public: - CharFieldTreeItem(UAVObjectField *field, int index, const QList &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem) + CharFieldTreeItem(UAVObjectField *field, int index, const QList &data) : + FieldTreeItem(index, data, field) {} - CharFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parentItem) : - FieldTreeItem(index, data, field, parentItem) + CharFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) : + FieldTreeItem(index, data, field) {} QVariant fieldToData() const diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index 08bff3ebf..108867f43 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -144,16 +144,16 @@ void HighlightManager::checkItemsExpired() int TreeItem::m_highlightTimeMs = 300; -TreeItem::TreeItem(const QList &data, TreeItem *parentItem) : +TreeItem::TreeItem(const QList &data) : m_itemData(data), - m_parentItem(parentItem), + m_parentItem(0), m_changed(false), m_highlighted(false), m_highlightManager(0) {} -TreeItem::TreeItem(const QVariant &data, TreeItem *parentItem) : - m_parentItem(parentItem), +TreeItem::TreeItem(const QVariant &data) : + m_parentItem(0), m_changed(false), m_highlighted(false), m_highlightManager(0) @@ -166,16 +166,32 @@ TreeItem::~TreeItem() qDeleteAll(m_childItems); } -void TreeItem::appendChild(TreeItem *child) +void TreeItem::setParentItem(TreeItem *parentItem) { - m_childItems.append(child); + if (m_parentItem) { + m_parentItem->removeChild(this, false); + } + m_parentItem = parentItem; } -void TreeItem::insertChild(TreeItem *child) +void TreeItem::appendChild(TreeItem *childItem) { - int index = nameIndex(child->data(0).toString()); + m_childItems.append(childItem); + childItem->setParentItem(this); +} - m_childItems.insert(index, child); +void TreeItem::insertChild(TreeItem *childItem, int index) +{ + m_childItems.insert(index, childItem); + childItem->setParentItem(this); +} + +void TreeItem::removeChild(TreeItem *childItem, bool reparent) +{ + m_childItems.removeOne(childItem); + if (reparent) { + childItem->setParentItem(0); + } } TreeItem *TreeItem::child(int index) const @@ -202,6 +218,16 @@ int TreeItem::columnCount() const return m_itemData.count(); } +void TreeItem::setDescription(QString desc) +{ + // Split around 40 characters + int idx = desc.indexOf(" ", 40); + + desc.insert(idx, QString("
")); + desc.remove("@Ref", Qt::CaseInsensitive); + m_description = desc; +} + QVariant TreeItem::data(int column) const { return m_itemData.value(column); @@ -270,6 +296,62 @@ QTime TreeItem::getHighlightExpires() const return m_highlightExpires; } +int TreeItem::childIndex(QString name) const +{ + for (int i = 0; i < childCount(); ++i) { + if (name == child(i)->data(0).toString()) { + return i; + } + } + return -1; +} + +TreeItem *TreeItem::childByName(QString name) const +{ + int index = childIndex(name); + + return (index >= 0) ? m_childItems[index] : 0; +} + +int TreeItem::insertionIndex(TreeItem *item) const +{ + QString name = item->data(0).toString(); + + for (int i = 0; i < childCount(); ++i) { + if (name < child(i)->data(0).toString()) { + return i; + } + } + return childCount(); +} + +int TreeItem::maxHexStringLength(UAVObjectField::FieldType type) +{ + switch (type) { + case UAVObjectField::INT8: + return 2; + + case UAVObjectField::INT16: + return 4; + + case UAVObjectField::INT32: + return 8; + + case UAVObjectField::UINT8: + return 2; + + case UAVObjectField::UINT16: + return 4; + + case UAVObjectField::UINT32: + return 8; + + default: + Q_ASSERT(false); + } + return 0; +} + QVariant ArrayFieldTreeItem::data(int column) const { if (column == 1) { diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h index 061a9aeef..d7c0d2ad7 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h @@ -29,6 +29,7 @@ #define TREEITEM_H #include "uavobject.h" +#include "uavdataobject.h" #include "uavmetaobject.h" #include "uavobjectfield.h" @@ -95,46 +96,49 @@ public: static const int TITLE_COLUMN = 0; static const int DATA_COLUMN = 1; - TreeItem(const QList &data, TreeItem *parentItem = 0); - TreeItem(const QVariant &data, TreeItem *parentItem = 0); + TreeItem(const QList &data); + TreeItem(const QVariant &data); virtual ~TreeItem(); - void appendChild(TreeItem *child); - void insertChild(TreeItem *child); - - TreeItem *child(int index) const; - QList children() const - { - return m_childItems; - } - int childCount() const; - int columnCount() const; - virtual QVariant data(int column = 1) const; - QString description() const - { - return m_description; - } - void setDescription(QString d) - { - // Split around 40 characters - int idx = d.indexOf(" ", 40); - - d.insert(idx, QString("
")); - d.remove("@Ref", Qt::CaseInsensitive); - m_description = d; - } - // only column 1 (TreeItem::dataColumn) is changed with setData currently - // other columns are initialized in constructor - virtual void setData(QVariant value, int column = 1); - int row() const; TreeItem *parentItem() const { return m_parentItem; } + void setParentItem(TreeItem *parentItem); + + void appendChild(TreeItem *childItem); + void insertChild(TreeItem *childItem, int index); + void removeChild(TreeItem *childItem, bool reparent = true); + + TreeItem *child(int index) const; + + QList children() const + { + return m_childItems; + } + + int childCount() const; + + int columnCount() const; + + QString description() const + { + return m_description; + } + + void setDescription(QString desc); + + virtual QVariant data(int column = 1) const; + + virtual void setData(QVariant value, int column = 1); + + int row() const; + virtual bool isEditable() const { return false; } + virtual void update(); virtual void apply(); @@ -174,52 +178,13 @@ public: return true; } - int nameIndex(QString name) const - { - for (int i = 0; i < childCount(); ++i) { - if (name < child(i)->data(0).toString()) { - return i; - } - } - return childCount(); - } + int childIndex(QString name) const; - TreeItem *findChildByName(QString name) const - { - foreach(TreeItem * child, m_childItems) { - if (name == child->data(0).toString()) { - return child; - } - } - return 0; - } + TreeItem *childByName(QString name) const; - static int maxHexStringLength(UAVObjectField::FieldType type) - { - switch (type) { - case UAVObjectField::INT8: - return 2; + int insertionIndex(TreeItem *item) const; - case UAVObjectField::INT16: - return 4; - - case UAVObjectField::INT32: - return 8; - - case UAVObjectField::UINT8: - return 2; - - case UAVObjectField::UINT16: - return 4; - - case UAVObjectField::UINT32: - return 8; - - default: - Q_ASSERT(false); - } - return 0; - } + static int maxHexStringLength(UAVObjectField::FieldType type); private: static int m_highlightTimeMs; @@ -238,52 +203,25 @@ private: HighlightManager *m_highlightManager; }; -class DataObjectTreeItem; -class MetaObjectTreeItem; - class TopTreeItem : public TreeItem { public: - TopTreeItem(const QList &data, TreeItem *parentItem) : - TreeItem(data, parentItem) + TopTreeItem(const QList &data) : + TreeItem(data) {} - TopTreeItem(const QVariant &data, TreeItem *parentItem) : - TreeItem(data, parentItem) + TopTreeItem(const QVariant &data) : + TreeItem(data) {} - - void addObjectTreeItem(quint32 objectId, DataObjectTreeItem *oti) - { - m_objectTreeItemsPerObjectIds[objectId] = oti; - } - - DataObjectTreeItem *findDataObjectTreeItemByObjectId(quint32 objectId) - { - return m_objectTreeItemsPerObjectIds.value(objectId, 0); - } - - void addMetaObjectTreeItem(quint32 objectId, MetaObjectTreeItem *oti) - { - m_metaObjectTreeItemsPerObjectIds[objectId] = oti; - } - - MetaObjectTreeItem *findMetaObjectTreeItemByObjectId(quint32 objectId) - { - return m_metaObjectTreeItemsPerObjectIds.value(objectId, 0); - } - -private: - QHash m_objectTreeItemsPerObjectIds; - QHash m_metaObjectTreeItemsPerObjectIds; }; class ObjectTreeItem : public TreeItem { public: - ObjectTreeItem(const QList &data, UAVObject *object, TreeItem *parentItem) : - TreeItem(data, parentItem), m_obj(object) + ObjectTreeItem(UAVObject *object, const QList &data) : + TreeItem(data), m_obj(object) { setDescription(m_obj->getDescription()); } - ObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parentItem) : - TreeItem(data, parentItem), m_obj(object) + ObjectTreeItem(UAVObject *object, const QVariant &data) : + TreeItem(data), m_obj(object) { setDescription(m_obj->getDescription()); } @@ -299,23 +237,33 @@ private: class MetaObjectTreeItem : public ObjectTreeItem { public: - MetaObjectTreeItem(UAVObject *object, const QList &data, TreeItem *parentItem) : - ObjectTreeItem(data, object, parentItem) + MetaObjectTreeItem(UAVMetaObject *object, const QList &data) : + ObjectTreeItem(object, data) {} - MetaObjectTreeItem(UAVObject *object, const QVariant &data, TreeItem *parentItem) : - ObjectTreeItem(data, object, parentItem) + MetaObjectTreeItem(UAVMetaObject *object, const QVariant &data) : + ObjectTreeItem(object, data) {} + + UAVMetaObject *metaObject() const + { + return static_cast(object()); + } }; class DataObjectTreeItem : public ObjectTreeItem { public: - DataObjectTreeItem(const QList &data, UAVObject *object, TreeItem *parentItem) : - ObjectTreeItem(data, object, parentItem) + DataObjectTreeItem(UAVDataObject *object, const QList &data) : + ObjectTreeItem(object, data) {} - DataObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parentItem) : - ObjectTreeItem(data, object, parentItem) + DataObjectTreeItem(UAVDataObject *object, const QVariant &data) : + ObjectTreeItem(object, data) {} + UAVDataObject *dataObject() const + { + return static_cast(object()); + } + virtual void apply() { foreach(TreeItem * child, children()) { @@ -346,11 +294,11 @@ public: class InstanceTreeItem : public DataObjectTreeItem { public: - InstanceTreeItem(UAVObject *object, const QList &data, TreeItem *parentItem) : - DataObjectTreeItem(data, object, parentItem) + InstanceTreeItem(UAVDataObject *object, const QList &data) : + DataObjectTreeItem(object, data) {} - InstanceTreeItem(UAVObject *object, const QVariant &data, TreeItem *parentItem) : - DataObjectTreeItem(data, object, parentItem) + InstanceTreeItem(UAVDataObject *object, const QVariant &data) : + DataObjectTreeItem(object, data) {} virtual void apply() @@ -366,11 +314,11 @@ public: class ArrayFieldTreeItem : public TreeItem { public: - ArrayFieldTreeItem(UAVObjectField *field, const QList &data, TreeItem *parentItem) : - TreeItem(data, parentItem), m_field(field) + ArrayFieldTreeItem(UAVObjectField *field, const QList &data) : + TreeItem(data), m_field(field) {} - ArrayFieldTreeItem(UAVObjectField *field, const QVariant &data, TreeItem *parentItem) : - TreeItem(data, parentItem), m_field(field) + ArrayFieldTreeItem(UAVObjectField *field, const QVariant &data) : + TreeItem(data), m_field(field) {} QVariant data(int column) const; diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp index 4c4caa715..cd2f87587 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp @@ -51,7 +51,7 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration *config) m_widget->setManuallyChangedColor(m->manuallyChangedColor()); m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout()); m_widget->setOnlyHighlightChangedValues(m->onlyHighlightChangedValues()); - m_widget->setViewOptions(m->categorizedView(), m->scientificView(), m->showMetaData(), m->showDescription()); + m_widget->setViewOptions(m->categorizedView(), m->showMetaData(), m->scientificView(), m->showDescription()); m_widget->setSplitterState(m->splitterState()); } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.pro b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.pro index 03fafd067..6ce72896d 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.pro +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.pro @@ -7,28 +7,27 @@ include(../../plugin.pri) include(uavobjectbrowser_dependencies.pri) HEADERS += \ - browserplugin.h \ + treeitem.h \ + fieldtreeitem.h \ + browseritemdelegate.h \ + uavobjecttreemodel.h \ uavobjectbrowserconfiguration.h \ + uavobjectbrowseroptionspage.h \ uavobjectbrowser.h \ uavobjectbrowserwidget.h \ uavobjectbrowserfactory.h \ - uavobjectbrowseroptionspage.h \ - uavobjecttreemodel.h \ - treeitem.h \ - browseritemdelegate.h \ - fieldtreeitem.h + browserplugin.h SOURCES += \ - browserplugin.cpp \ + treeitem.cpp \ + browseritemdelegate.cpp \ + uavobjecttreemodel.cpp \ uavobjectbrowserconfiguration.cpp \ + uavobjectbrowseroptionspage.cpp \ uavobjectbrowser.cpp \ uavobjectbrowserfactory.cpp \ uavobjectbrowserwidget.cpp \ - uavobjectbrowseroptionspage.cpp \ - uavobjecttreemodel.cpp \ - treeitem.cpp \ - browseritemdelegate.cpp \ - fieldtreeitem.cpp + browserplugin.cpp OTHER_FILES += UAVObjectBrowser.pluginspec diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index 07b0f325f..2b6f24c0e 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -95,12 +95,12 @@ UAVObjectBrowserWidget::~UAVObjectBrowserWidget() delete m_browser; } -void UAVObjectBrowserWidget::setViewOptions(bool categorized, bool scientific, bool metadata, bool description) +void UAVObjectBrowserWidget::setViewOptions(bool showCategories, bool showMetadata, bool useScientificNotation, bool showDescription) { - m_viewoptions->cbCategorized->setChecked(categorized); - m_viewoptions->cbMetaData->setChecked(metadata); - m_viewoptions->cbScientific->setChecked(scientific); - m_viewoptions->cbDescription->setChecked(description); + m_viewoptions->cbCategorized->setChecked(showCategories); + m_viewoptions->cbMetaData->setChecked(showMetadata); + m_viewoptions->cbScientific->setChecked(useScientificNotation); + m_viewoptions->cbDescription->setChecked(showDescription); } void UAVObjectBrowserWidget::setSplitterState(QByteArray state) @@ -264,15 +264,16 @@ void UAVObjectBrowserWidget::viewSlot() UAVObjectTreeModel *UAVObjectBrowserWidget::createTreeModel() { - UAVObjectTreeModel *model = new UAVObjectTreeModel(this, - m_viewoptions->cbCategorized->isChecked(), - m_viewoptions->cbMetaData->isChecked(), - m_viewoptions->cbScientific->isChecked()); + UAVObjectTreeModel *model = new UAVObjectTreeModel(this); + + model->setShowCategories(m_viewoptions->cbCategorized->isChecked()); + model->setShowMetadata(m_viewoptions->cbMetaData->isChecked()); + model->setUseScientificNotation(m_viewoptions->cbScientific->isChecked()); model->setRecentlyUpdatedColor(m_recentlyUpdatedColor); model->setManuallyChangedColor(m_manuallyChangedColor); model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout); - model->setUnknowObjectColor(m_unknownObjectColor); + model->setUnknownObjectColor(m_unknownObjectColor); model->setOnlyHighlightChangedValues(m_onlyHighlightChangedValues); return model; @@ -280,15 +281,14 @@ UAVObjectTreeModel *UAVObjectBrowserWidget::createTreeModel() void UAVObjectBrowserWidget::updateViewOptions() { - bool categorize = m_viewoptions->cbCategorized->isChecked(); + bool showCategories = m_viewoptions->cbCategorized->isChecked(); bool useScientificNotation = m_viewoptions->cbScientific->isChecked(); - bool showMetadata = m_viewoptions->cbMetaData->isChecked(); - bool showDesc = m_viewoptions->cbDescription->isChecked(); + bool showMetadata = m_viewoptions->cbMetaData->isChecked(); + bool showDesc = m_viewoptions->cbDescription->isChecked(); - m_model->setShowCategories(categorize); + m_model->setShowCategories(showCategories); m_model->setShowMetadata(showMetadata); - m_model->setShowScientificNotation(useScientificNotation); - m_model->resetModelData(); + m_model->setUseScientificNotation(useScientificNotation); // force an expand all if search text is not empty if (!m_browser->searchLine->text().isEmpty()) { @@ -296,7 +296,7 @@ void UAVObjectBrowserWidget::updateViewOptions() } // persist options - emit viewOptionsChanged(categorize, useScientificNotation, showMetadata, showDesc); + emit viewOptionsChanged(showCategories, useScientificNotation, showMetadata, showDesc); } void UAVObjectBrowserWidget::splitterMoved() diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h index 437edb2ba..22530992b 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h @@ -62,7 +62,7 @@ public: void setUnknownObjectColor(QColor color) { m_unknownObjectColor = color; - m_model->setUnknowObjectColor(color); + m_model->setUnknownObjectColor(color); } void setRecentlyUpdatedColor(QColor color) { @@ -84,7 +84,7 @@ public: m_onlyHighlightChangedValues = hilight; m_model->setOnlyHighlightChangedValues(hilight); } - void setViewOptions(bool categorized, bool scientific, bool metadata, bool description); + void setViewOptions(bool showCategories, bool showMetadata, bool useScientificNotation, bool showDescription); void setSplitterState(QByteArray state); public slots: diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 749fe9a11..b12235de0 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -36,29 +36,14 @@ #include -UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent, bool categorize, bool showMetadata, bool useScientificNotation) : - QAbstractItemModel(parent), - m_categorize(categorize), - m_showMetadata(showMetadata), - m_useScientificFloatNotation(useScientificNotation), - m_recentlyUpdatedTimeout(500), // ms - m_recentlyUpdatedColor(QColor(255, 230, 230)), - m_manuallyChangedColor(QColor(230, 230, 255)), - m_unknownObjectColor(QColor(Qt::gray)) +UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent) : QAbstractItemModel(parent) { - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - - Q_ASSERT(objManager); - - connect(objManager, SIGNAL(newObject(UAVObject *)), this, SLOT(newObject(UAVObject *))); - connect(objManager, SIGNAL(newInstance(UAVObject *)), this, SLOT(newObject(UAVObject *))); - m_highlightManager = new HighlightManager(); - connect(m_highlightManager, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); + connect(m_highlightManager, &HighlightManager::updateHighlight, this, &refreshHighlight); - TreeItem::setHighlightTime(m_recentlyUpdatedTimeout); - setupModelData(objManager); + TreeItem::setHighlightTime(recentlyUpdatedTimeout()); + + setupModelData(); } UAVObjectTreeModel::~UAVObjectTreeModel() @@ -67,165 +52,207 @@ UAVObjectTreeModel::~UAVObjectTreeModel() delete m_highlightManager; } -void UAVObjectTreeModel::resetModelData() +bool UAVObjectTreeModel::showCategories() const { - m_highlightManager->reset(); - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager *objManager = pm->getObject(); - Q_ASSERT(objManager); - - emit beginResetModel(); - - delete m_rootItem; - m_rootItem = NULL; - setupModelData(objManager); - - emit endResetModel(); + return m_settings.value("showCategories", false).toBool(); } -void UAVObjectTreeModel::setShowCategories(bool showCategories) +void UAVObjectTreeModel::setShowCategories(bool show) { - if (showCategories == m_categorize) { + if (show == showCategories()) { return; } - m_categorize = showCategories; + m_settings.setValue("showCategories", show); + toggleCategoryItems(); } -void UAVObjectTreeModel::setShowMetadata(bool showMetadata) +bool UAVObjectTreeModel::showMetadata() const { - if (showMetadata == m_showMetadata) { + return m_settings.value("showMetadata", false).toBool(); +} + +void UAVObjectTreeModel::setShowMetadata(bool show) +{ + if (show == showMetadata()) { return; } - m_showMetadata = showMetadata; + m_settings.setValue("showMetadata", show); + toggleMetaItems(); } -void UAVObjectTreeModel::setShowScientificNotation(bool showScientificNotation) +bool UAVObjectTreeModel::useScientificNotation() { - if (showScientificNotation == m_useScientificFloatNotation) { - return; - } - m_useScientificFloatNotation = showScientificNotation; + return m_settings.value("useScientificNotation", false).toBool(); } - -void UAVObjectTreeModel::setupModelData(UAVObjectManager *objManager) +void UAVObjectTreeModel::setUseScientificNotation(bool useScientificNotation) +{ + m_settings.setValue("useScientificNotation", useScientificNotation); +} + +QColor UAVObjectTreeModel::unknownObjectColor() const +{ + return m_settings.value("unknownObjectColor", QColor(Qt::gray)).value(); +} + +void UAVObjectTreeModel::setUnknownObjectColor(QColor color) +{ + m_settings.setValue("unknownObjectColor", color); +} + +QColor UAVObjectTreeModel::recentlyUpdatedColor() const +{ + return m_settings.value("recentlyUpdatedColor", QColor(255, 230, 230)).value(); +} + +void UAVObjectTreeModel::setRecentlyUpdatedColor(QColor color) +{ + m_settings.setValue("recentlyUpdatedColor", color); +} + +QColor UAVObjectTreeModel::manuallyChangedColor() const +{ + return m_settings.value("manuallyChangedColor", QColor(230, 230, 255)).value(); +} + +void UAVObjectTreeModel::setManuallyChangedColor(QColor color) +{ + m_settings.setValue("manuallyChangedColor", color); +} + +int UAVObjectTreeModel::recentlyUpdatedTimeout() const +{ + return m_settings.value("recentlyUpdatedTimeout", 500).toInt(); +} + +void UAVObjectTreeModel::setRecentlyUpdatedTimeout(int timeout) +{ + m_settings.setValue("recentlyUpdatedTimeout", timeout); + TreeItem::setHighlightTime(timeout); +} + +bool UAVObjectTreeModel::onlyHighlightChangedValues() const +{ + return m_settings.value("onlyHighlightChangedValues", false).toBool(); +} + +void UAVObjectTreeModel::setOnlyHighlightChangedValues(bool highlight) +{ + m_settings.setValue("onlyHighlightChangedValues", highlight); +} + +void UAVObjectTreeModel::setupModelData() { - // root QList rootData; rootData << tr("Property") << tr("Value") << tr("Unit"); m_rootItem = new TreeItem(rootData); m_rootItem->setHighlightManager(m_highlightManager); - m_settingsTree = new TopTreeItem(tr("Settings"), m_rootItem); + m_settingsTree = new TopTreeItem(tr("Settings")); m_settingsTree->setHighlightManager(m_highlightManager); - m_nonSettingsTree = new TopTreeItem(tr("Data Objects"), m_rootItem); + m_nonSettingsTree = new TopTreeItem(tr("Data Objects")); m_nonSettingsTree->setHighlightManager(m_highlightManager); - // tree item takes ownership of its children - m_rootItem->appendChild(m_settingsTree); - m_rootItem->appendChild(m_nonSettingsTree); + // tree item takes ownership of their children + appendItem(m_rootItem, m_settingsTree); + appendItem(m_rootItem, m_nonSettingsTree); + + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + UAVObjectManager *objManager = pm->getObject(); + Q_ASSERT(objManager); + + connect(objManager, &UAVObjectManager::newObject, this, &newObject, Qt::UniqueConnection); + connect(objManager, &UAVObjectManager::newInstance, this, &newObject, Qt::UniqueConnection); QList< QList > objList = objManager->getDataObjects(); foreach(QList list, objList) { foreach(UAVDataObject * obj, list) { - disconnect(obj, 0, this, 0); - addDataObject(obj); + addObject(obj); } } } +void UAVObjectTreeModel::resetModelData() +{ + m_highlightManager->reset(); + + emit beginResetModel(); + + delete m_rootItem; + m_rootItem = NULL; + setupModelData(); + + emit endResetModel(); +} + void UAVObjectTreeModel::newObject(UAVObject *obj) { - UAVDataObject *dobj = qobject_cast(obj); + UAVDataObject *dataObj = qobject_cast(obj); - if (dobj) { - addDataObject(dobj); + if (dataObj) { + addObject(dataObj); } } -void UAVObjectTreeModel::addDataObject(UAVDataObject *obj) +void UAVObjectTreeModel::addObject(UAVDataObject *obj) { - TopTreeItem *root = obj->isSettingsObject() ? m_settingsTree : m_nonSettingsTree; - - TreeItem *parent = root; - - if (m_categorize && obj->getCategory() != 0 && !obj->getCategory().isEmpty()) { - QStringList categoryPath = obj->getCategory().split('/'); - parent = createCategoryItems(categoryPath, root); + connect(obj, &UAVDataObject::objectUpdated, this, &updateObject, Qt::UniqueConnection); + connect(obj, &UAVDataObject::isKnownChanged, this, &updateIsKnown, Qt::UniqueConnection); + if (obj->getInstID() == 0) { + UAVMetaObject *metaObj = obj->getMetaObject(); + connect(metaObj, &UAVDataObject::objectUpdated, this, &updateObject, Qt::UniqueConnection); } - - ObjectTreeItem *existing = root->findDataObjectTreeItemByObjectId(obj->getObjID()); - if (existing) { - addInstance(obj, existing); - } else { - DataObjectTreeItem *dataTreeItem = new DataObjectTreeItem(obj->getName(), obj, parent); - dataTreeItem->setHighlightManager(m_highlightManager); - - parent->insertChild(dataTreeItem); - root->addObjectTreeItem(obj->getObjID(), dataTreeItem); - if (m_showMetadata) { - UAVMetaObject *meta = obj->getMetaObject(); - MetaObjectTreeItem *metaTreeItem = addMetaObject(meta, dataTreeItem); - root->addMetaObjectTreeItem(meta->getObjID(), metaTreeItem); - } - addInstance(obj, dataTreeItem); - } -} - -TreeItem *UAVObjectTreeModel::createCategoryItems(QStringList categoryPath, TreeItem *root) -{ - TreeItem *parent = root; - - foreach(QString category, categoryPath) { - TreeItem *existing = parent->findChildByName(category); - - if (!existing) { - TreeItem *categoryItem = new TopTreeItem(category, parent); - categoryItem->setHighlightManager(m_highlightManager); - - parent->insertChild(categoryItem); - parent = categoryItem; - } else { - parent = existing; - } - } - return parent; -} - -MetaObjectTreeItem *UAVObjectTreeModel::addMetaObject(UAVMetaObject *obj, TreeItem *parent) -{ - connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateObject(UAVObject *))); - - MetaObjectTreeItem *meta = new MetaObjectTreeItem(obj, tr("Meta Data"), parent); - meta->setHighlightManager(m_highlightManager); - - foreach(UAVObjectField * field, obj->getFields()) { - if (field->getNumElements() > 1) { - addArrayField(field, meta); - } else { - addSingleField(0, field, meta); - } - } - parent->appendChild(meta); - return meta; -} - -void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent) -{ - connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(updateObject(UAVObject *))); - connect(obj, SIGNAL(isKnownChanged(UAVObject *)), this, SLOT(updateIsKnown(UAVObject *))); - - TreeItem *item; if (obj->isSingleInstance()) { - item = parent; + DataObjectTreeItem *dataObjectItem = createDataObject(obj); + TreeItem *parentItem = getParentItem(obj, showCategories()); + insertItem(parentItem, dataObjectItem); } else { - QString name = tr("Instance") + " " + QString::number(obj->getInstID()); - item = new InstanceTreeItem(obj, name, parent); - item->setHighlightManager(m_highlightManager); - parent->appendChild(item); + TreeItem *dataObjectItem; + if (obj->getInstID() == 0) { + dataObjectItem = createDataObject(obj); + TreeItem *parentItem = getParentItem(obj, showCategories()); + insertItem(parentItem, dataObjectItem); + } else { + dataObjectItem = findObjectTreeItem(obj->getObjID()); + } + InstanceTreeItem *instanceItem = createDataObjectInstance(obj); + appendItem(dataObjectItem, instanceItem); } +} + +DataObjectTreeItem *UAVObjectTreeModel::createDataObject(UAVDataObject *obj) +{ + DataObjectTreeItem *item = new DataObjectTreeItem(obj, obj->getName()); + + addObjectTreeItem(obj->getObjID(), item); + item->setHighlightManager(m_highlightManager); + + MetaObjectTreeItem *metaItem = createMetaObject(obj->getMetaObject()); + if (showMetadata()) { + appendItem(item, metaItem); + } + + if (obj->isSingleInstance()) { + foreach(UAVObjectField * field, obj->getFields()) { + if (field->getNumElements() > 1) { + addArrayField(field, item); + } else { + addSingleField(0, field, item); + } + } + } + + return item; +} + +InstanceTreeItem *UAVObjectTreeModel::createDataObjectInstance(UAVDataObject *obj) +{ + QString name = tr("Instance") + " " + QString::number((int)obj->getInstID()); + InstanceTreeItem *item = new InstanceTreeItem(obj, name); + + item->setHighlightManager(m_highlightManager); + foreach(UAVObjectField * field, obj->getFields()) { if (field->getNumElements() > 1) { addArrayField(field, item); @@ -233,27 +260,72 @@ void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent) addSingleField(0, field, item); } } + + return item; +} + +MetaObjectTreeItem *UAVObjectTreeModel::createMetaObject(UAVMetaObject *obj) +{ + MetaObjectTreeItem *item = new MetaObjectTreeItem(obj, tr("Meta Data")); + + addObjectTreeItem(obj->getObjID(), item); + item->setHighlightManager(m_highlightManager); + + foreach(UAVObjectField * field, obj->getFields()) { + if (field->getNumElements() > 1) { + addArrayField(field, item); + } else { + addSingleField(0, field, item); + } + } + return item; +} + +TreeItem *UAVObjectTreeModel::getParentItem(UAVDataObject *obj, bool categorize) +{ + TreeItem *parentItem = obj->isSettingsObject() ? m_settingsTree : m_nonSettingsTree; + + if (categorize) { + QString category = obj->getCategory(); + if (obj->getCategory().isEmpty()) { + category = tr("Uncategorized"); + } + QStringList categoryPath = category.split('/'); + + foreach(QString category, categoryPath) { + TreeItem *categoryItem = parentItem->childByName(category); + + if (!categoryItem) { + categoryItem = new TopTreeItem(category); + categoryItem->setHighlightManager(m_highlightManager); + insertItem(parentItem, categoryItem); + } + parentItem = categoryItem; + } + } + return parentItem; } void UAVObjectTreeModel::addArrayField(UAVObjectField *field, TreeItem *parent) { - TreeItem *item = new ArrayFieldTreeItem(field, field->getName(), parent); + TreeItem *item = new ArrayFieldTreeItem(field, field->getName()); item->setHighlightManager(m_highlightManager); - parent->appendChild(item); + + appendItem(parent, item); for (int i = 0; i < (int)field->getNumElements(); ++i) { addSingleField(i, field, item); } } -void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeItem *parent) +void UAVObjectTreeModel::addSingleField(int i, UAVObjectField *field, TreeItem *parent) { QList data; if (field->getNumElements() == 1) { data.append(field->getName()); } else { - data.append(QString("[%1]").arg((field->getElementNames())[index])); + data.append(QString("[%1]").arg((field->getElementNames())[i])); } FieldTreeItem *item = NULL; @@ -263,10 +335,10 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt case UAVObjectField::ENUM: { QStringList options = field->getOptions(); - QVariant value = field->getValue(index); + QVariant value = field->getValue(i); data.append(options.indexOf(value.toString())); data.append(field->getUnits()); - item = new EnumFieldTreeItem(field, index, data, parent); + item = new EnumFieldTreeItem(field, i, data); break; } case UAVObjectField::INT8: @@ -275,20 +347,20 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt case UAVObjectField::UINT8: case UAVObjectField::UINT16: case UAVObjectField::UINT32: - data.append(field->getValue(index)); + data.append(field->getValue(i)); data.append(field->getUnits()); if (field->getUnits().toLower() == "hex") { - item = new HexFieldTreeItem(field, index, data, parent); + item = new HexFieldTreeItem(field, i, data); } else if (field->getUnits().toLower() == "char") { - item = new CharFieldTreeItem(field, index, data, parent); + item = new CharFieldTreeItem(field, i, data); } else { - item = new IntFieldTreeItem(field, index, data, parent); + item = new IntFieldTreeItem(field, i, data); } break; case UAVObjectField::FLOAT32: - data.append(field->getValue(index)); + data.append(field->getValue(i)); data.append(field->getUnits()); - item = new FloatFieldTreeItem(field, index, data, m_useScientificFloatNotation, parent); + item = new FloatFieldTreeItem(field, i, data, m_settings); break; default: Q_ASSERT(false); @@ -297,7 +369,91 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt item->setHighlightManager(m_highlightManager); item->setDescription(field->getDescription()); - parent->appendChild(item); + appendItem(parent, item); +} + +void UAVObjectTreeModel::appendItem(TreeItem *parentItem, TreeItem *childItem) +{ + int row = parentItem->childCount(); + + beginInsertRows(index(parentItem), row, row); + parentItem->appendChild(childItem); + endInsertRows(); +} + +void UAVObjectTreeModel::insertItem(TreeItem *parentItem, TreeItem *childItem, int row) +{ + if (row < 0) { + row = parentItem->insertionIndex(childItem); + } + beginInsertRows(index(parentItem), row, row); + parentItem->insertChild(childItem, row); + endInsertRows(); +} + +void UAVObjectTreeModel::removeItem(TreeItem *parentItem, TreeItem *childItem) +{ + int row = childItem->row(); + + beginRemoveRows(index(parentItem), row, row); + parentItem->removeChild(childItem); + endRemoveRows(); +} + +void UAVObjectTreeModel::moveItem(TreeItem *newParentItem, TreeItem *oldParentItem, TreeItem *childItem) +{ + int destinationRow = newParentItem->insertionIndex(childItem); + int sourceRow = childItem->row(); + + beginMoveRows(index(oldParentItem), sourceRow, sourceRow, index(newParentItem), destinationRow); + oldParentItem->removeChild(childItem); + newParentItem->insertChild(childItem, destinationRow); + endMoveRows(); +} + +void UAVObjectTreeModel::toggleCategoryItems() +{ + foreach(ObjectTreeItem * item, m_objectTreeItems.values()) { + DataObjectTreeItem *dataItem = dynamic_cast(item); + + if (dataItem) { + TreeItem *oldParentItem = dataItem->parentItem(); + TreeItem *newParentItem = getParentItem(dataItem->dataObject(), showCategories()); + if (oldParentItem == newParentItem) { + // should not happen + continue; + } + + moveItem(newParentItem, oldParentItem, dataItem); + + if (!showCategories()) { + // remove empty category items + TreeItem *item = oldParentItem; + while (item->childCount() == 0 && item != newParentItem) { + TreeItem *tmp = item; + item = item->parentItem(); + removeItem(tmp->parentItem(), tmp); + delete tmp; + } + } + } + } +} + +void UAVObjectTreeModel::toggleMetaItems() +{ + foreach(ObjectTreeItem * item, m_objectTreeItems.values()) { + MetaObjectTreeItem *metaItem = dynamic_cast(item); + + if (metaItem) { + DataObjectTreeItem *dataItem = findDataObjectTreeItem(metaItem->object()); + if (showMetadata()) { + insertItem(dataItem, metaItem, 0); + } else { + removeItem(dataItem, metaItem); + } + } + } } QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &parent) const @@ -338,6 +494,10 @@ QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const TreeItem *childItem = static_cast(index.internalPointer()); TreeItem *parentItem = childItem->parentItem(); + if (!parentItem) { + return QModelIndex(); + } + if (parentItem == m_rootItem) { return QModelIndex(); } @@ -405,22 +565,22 @@ QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const case Qt::ForegroundRole: if (!dynamic_cast(item) && !item->isKnown()) { - return m_unknownObjectColor; + return unknownObjectColor(); } return QVariant(); case Qt::BackgroundRole: if (index.column() == TreeItem::TITLE_COLUMN) { if (!dynamic_cast(item) && item->isHighlighted()) { - return m_recentlyUpdatedColor; + return recentlyUpdatedColor(); } } else if (index.column() == TreeItem::DATA_COLUMN) { FieldTreeItem *fieldItem = dynamic_cast(item); if (fieldItem && fieldItem->isHighlighted()) { - return m_recentlyUpdatedColor; + return recentlyUpdatedColor(); } if (fieldItem && fieldItem->changed()) { - return m_manuallyChangedColor; + return manuallyChangedColor(); } } return QVariant(); @@ -437,13 +597,12 @@ QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const bool UAVObjectTreeModel::setData(const QModelIndex &index, const QVariant & value, int role) { - Q_UNUSED(role) - TreeItem * item = static_cast(index.internalPointer()); + Q_UNUSED(role); + TreeItem *item = static_cast(index.internalPointer()); item->setData(value, index.column()); return true; } - Qt::ItemFlags UAVObjectTreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) { @@ -472,50 +631,29 @@ QVariant UAVObjectTreeModel::headerData(int section, Qt::Orientation orientation void UAVObjectTreeModel::updateObject(UAVObject *obj) { Q_ASSERT(obj); - ObjectTreeItem *item = findObjectTreeItem(obj); + ObjectTreeItem *item = findObjectTreeItem(obj->getObjID()); Q_ASSERT(item); + // TODO don't update meta object if they are not shown item->update(); - if (!m_onlyHighlightChangedValues) { + if (!onlyHighlightChangedValues()) { item->setHighlighted(true); } } -ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(UAVObject *object) +void UAVObjectTreeModel::updateIsKnown(UAVObject *object) { - UAVDataObject *dataObject = qobject_cast(object); - UAVMetaObject *metaObject = qobject_cast(object); + DataObjectTreeItem *item = findDataObjectTreeItem(object); - Q_ASSERT(dataObject || metaObject); - if (dataObject) { - return findDataObjectTreeItem(dataObject); - } else { - return findMetaObjectTreeItem(metaObject); + if (item) { + refreshIsKnown(item); } - return 0; } -DataObjectTreeItem *UAVObjectTreeModel::findDataObjectTreeItem(UAVDataObject *obj) -{ - TopTreeItem *root = obj->isSettingsObject() ? m_settingsTree : m_nonSettingsTree; - - return root->findDataObjectTreeItemByObjectId(obj->getObjID()); -} - -MetaObjectTreeItem *UAVObjectTreeModel::findMetaObjectTreeItem(UAVMetaObject *obj) -{ - UAVDataObject *dataObject = qobject_cast(obj->getParentObject()); - - Q_ASSERT(dataObject); - TopTreeItem *root = dataObject->isSettingsObject() ? m_settingsTree : m_nonSettingsTree; - return root->findMetaObjectTreeItemByObjectId(obj->getObjID()); -} - -void UAVObjectTreeModel::updateHighlight(TreeItem *item) +void UAVObjectTreeModel::refreshHighlight(TreeItem *item) { // performance note: here we emit data changes column by column // emitting a dataChanged that spans multiple columns kills performance (CPU shoots up) - // this is probably because we configure the sort/filter proxy to be dynamic - // this happens when calling setDynamicSortFilter(true) on it which we do + // this is probably caused by the sort/filter proxy... QModelIndex itemIndex; @@ -528,16 +666,7 @@ void UAVObjectTreeModel::updateHighlight(TreeItem *item) emit dataChanged(itemIndex, itemIndex); } -void UAVObjectTreeModel::updateIsKnown(UAVObject *object) -{ - ObjectTreeItem *item = findObjectTreeItem(object); - - if (item) { - updateIsKnown(item); - } -} - -void UAVObjectTreeModel::updateIsKnown(TreeItem *item) +void UAVObjectTreeModel::refreshIsKnown(TreeItem *item) { QModelIndex itemIndex; @@ -546,6 +675,32 @@ void UAVObjectTreeModel::updateIsKnown(TreeItem *item) emit dataChanged(itemIndex, itemIndex); foreach(TreeItem * child, item->children()) { - updateIsKnown(child); + refreshIsKnown(child); } } + +void UAVObjectTreeModel::addObjectTreeItem(quint32 objectId, ObjectTreeItem *oti) +{ + m_objectTreeItems[objectId] = oti; +} + +ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(quint32 objectId) +{ + return m_objectTreeItems.value(objectId, 0); +} + +DataObjectTreeItem *UAVObjectTreeModel::findDataObjectTreeItem(UAVObject *object) +{ + UAVDataObject *dataObject; + + UAVMetaObject *metaObject = qobject_cast(object); + + if (metaObject) { + dataObject = qobject_cast(metaObject->getParentObject()); + } else { + dataObject = qobject_cast(object); + } + + Q_ASSERT(dataObject); + return static_cast(findObjectTreeItem(dataObject->getObjID())); +} diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index c037f4d5f..87b2f16cf 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -34,6 +34,7 @@ #include #include #include +#include class TopTreeItem; class ObjectTreeItem; @@ -49,7 +50,7 @@ class QTimer; class UAVObjectTreeModel : public QAbstractItemModel { Q_OBJECT public: - explicit UAVObjectTreeModel(QObject *parent, bool categorize, bool showMetadata, bool useScientificNotation); + explicit UAVObjectTreeModel(QObject *parent); ~UAVObjectTreeModel(); QVariant data(const QModelIndex &index, int role) const; @@ -63,90 +64,74 @@ public: int rowCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const; - void resetModelData(); + bool showCategories() const; + void setShowCategories(bool show); - bool showCategories() - { - return m_categorize; - } + bool showMetadata() const; + void setShowMetadata(bool show); - void setShowCategories(bool showCategories); + bool useScientificNotation(); + void setUseScientificNotation(bool useScientificNotation); - bool showMetadata() - { - return m_showMetadata; - } + QColor unknownObjectColor() const; + void setUnknownObjectColor(QColor color); - void setShowMetadata(bool showMetadata); + QColor recentlyUpdatedColor() const; + void setRecentlyUpdatedColor(QColor color); - bool showScientificNotation() - { - return m_useScientificFloatNotation; - } + QColor manuallyChangedColor() const; + void setManuallyChangedColor(QColor color); - void setShowScientificNotation(bool showScientificNotation); + int recentlyUpdatedTimeout() const; + void setRecentlyUpdatedTimeout(int timeout); - void setUnknowObjectColor(QColor color) - { - m_unknownObjectColor = color; - } - void setRecentlyUpdatedColor(QColor color) - { - m_recentlyUpdatedColor = color; - } - void setManuallyChangedColor(QColor color) - { - m_manuallyChangedColor = color; - } - void setRecentlyUpdatedTimeout(int timeout) - { - m_recentlyUpdatedTimeout = timeout; - TreeItem::setHighlightTime(timeout); - } - void setOnlyHighlightChangedValues(bool hilight) - { - m_onlyHighlightChangedValues = hilight; - } - -public slots: - void newObject(UAVObject *obj); + bool onlyHighlightChangedValues() const; + void setOnlyHighlightChangedValues(bool highlight); private slots: + void newObject(UAVObject *obj); void updateObject(UAVObject *obj); void updateIsKnown(UAVObject *obj); - void updateHighlight(TreeItem *item); - void updateIsKnown(TreeItem *item); + void refreshHighlight(TreeItem *item); + void refreshIsKnown(TreeItem *item); private: - QModelIndex index(TreeItem *item, int column = 0); - void setupModelData(UAVObjectManager *objManager); - void addDataObject(UAVDataObject *obj); - MetaObjectTreeItem *addMetaObject(UAVMetaObject *obj, TreeItem *parent); - void addArrayField(UAVObjectField *field, TreeItem *parent); - void addSingleField(int index, UAVObjectField *field, TreeItem *parent); - void addInstance(UAVObject *obj, TreeItem *parent); + QSettings m_settings; - TreeItem *createCategoryItems(QStringList categoryPath, TreeItem *root); - - QString updateMode(quint8 updateMode); - ObjectTreeItem *findObjectTreeItem(UAVObject *obj); - DataObjectTreeItem *findDataObjectTreeItem(UAVDataObject *obj); - MetaObjectTreeItem *findMetaObjectTreeItem(UAVMetaObject *obj); + HighlightManager *m_highlightManager; TreeItem *m_rootItem; TopTreeItem *m_settingsTree; TopTreeItem *m_nonSettingsTree; - bool m_categorize; - bool m_showMetadata; - bool m_useScientificFloatNotation; - int m_recentlyUpdatedTimeout; - QColor m_recentlyUpdatedColor; - QColor m_manuallyChangedColor; - QColor m_unknownObjectColor; - bool m_onlyHighlightChangedValues; - // Highlight manager to handle highlighting of tree items. - HighlightManager *m_highlightManager; + QHash m_objectTreeItems; + + QModelIndex index(TreeItem *item, int column = 0); + + void setupModelData(); + void resetModelData(); + + void addObject(UAVDataObject *obj); + void addArrayField(UAVObjectField *field, TreeItem *parent); + void addSingleField(int index, UAVObjectField *field, TreeItem *parent); + + DataObjectTreeItem *createDataObject(UAVDataObject *obj); + InstanceTreeItem *createDataObjectInstance(UAVDataObject *obj); + MetaObjectTreeItem *createMetaObject(UAVMetaObject *obj); + TreeItem *getParentItem(UAVDataObject *obj, bool categorize); + + void appendItem(TreeItem *parentItem, TreeItem *childItem); + void insertItem(TreeItem *parentItem, TreeItem *childItem, int row = -1); + void removeItem(TreeItem *parentItem, TreeItem *childItem); + void moveItem(TreeItem *newParentItem, TreeItem *oldParentItem, TreeItem *childItem); + + void toggleCategoryItems(); + void toggleMetaItems(); + + void addObjectTreeItem(quint32 objectId, ObjectTreeItem *oti); + ObjectTreeItem *findObjectTreeItem(quint32 objectId); + + DataObjectTreeItem *findDataObjectTreeItem(UAVObject *obj); }; #endif // UAVOBJECTTREEMODEL_H From e215e6fd2e111020cce938877a1819f7cad0bec5 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 25 Mar 2018 19:32:18 +0200 Subject: [PATCH 13/20] LP-567 use common timestamp when updating an object and its field this ensures that highlihhting will be synchronized --- .../plugins/uavobjectbrowser/fieldtreeitem.h | 4 ++-- .../src/plugins/uavobjectbrowser/treeitem.cpp | 11 +++++------ .../src/plugins/uavobjectbrowser/treeitem.h | 18 +++++++++--------- .../uavobjectbrowser/uavobjectbrowserwidget.h | 6 +++--- .../uavobjectbrowser/uavobjecttreemodel.cpp | 5 +++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h index 271198c78..c21b76807 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/fieldtreeitem.h @@ -78,7 +78,7 @@ public: TreeItem::setData(value, column); } - void update() + void update(const QTime &ts) { bool updated = false; @@ -90,7 +90,7 @@ public: } } if (changed() || updated) { - setHighlighted(true); + setHighlighted(true, ts); } } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index 108867f43..ffcbc56c2 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -238,10 +238,10 @@ void TreeItem::setData(QVariant value, int column) m_itemData.replace(column, value); } -void TreeItem::update() +void TreeItem::update(const QTime &ts) { foreach(TreeItem * child, children()) { - child->update(); + child->update(ts); } } @@ -255,7 +255,7 @@ void TreeItem::apply() /* * Called after a value has changed to trigger highlighting of tree item. */ -void TreeItem::setHighlighted(bool highlighted) +void TreeItem::setHighlighted(bool highlighted, const QTime &ts) { m_changed = false; if (m_highlighted != highlighted) { @@ -264,7 +264,7 @@ void TreeItem::setHighlighted(bool highlighted) // Add to highlight manager m_highlightManager->add(this); // Update expiration timeout - m_highlightExpires = QTime::currentTime().addMSecs(m_highlightTimeMs); + m_highlightExpires = ts.addMSecs(m_highlightTimeMs); // start expiration timer if necessary m_highlightManager->startTimer(m_highlightExpires); } else { @@ -276,8 +276,7 @@ void TreeItem::setHighlighted(bool highlighted) // This will ensure that the root of a leaf that is changed also is highlighted. // Only updates that really changes values will trigger highlight of parents. if (m_parentItem) { - // FIXME: need to pass m_highlightExpires - m_parentItem->setHighlighted(highlighted); + m_parentItem->setHighlighted(highlighted, ts); } } diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h index d7c0d2ad7..14c22cefa 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h @@ -139,7 +139,7 @@ public: return false; } - virtual void update(); + virtual void update(const QTime &ts); virtual void apply(); bool changed() const @@ -157,7 +157,7 @@ public: return m_highlighted; } - void setHighlighted(bool highlighted); + void setHighlighted(bool highlighted, const QTime &ts); static void setHighlightTime(int time) { @@ -275,13 +275,13 @@ public: } } - virtual void update() + virtual void update(const QTime &ts) { foreach(TreeItem * child, children()) { MetaObjectTreeItem *metaChild = dynamic_cast(child); if (!metaChild) { - child->update(); + child->update(ts); } } } @@ -301,15 +301,15 @@ public: DataObjectTreeItem(object, data) {} + virtual void update(const QTime &ts) + { + TreeItem::update(ts); + } + virtual void apply() { TreeItem::apply(); } - - virtual void update() - { - TreeItem::update(); - } }; class ArrayFieldTreeItem : public TreeItem { diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h index 22530992b..73b010afc 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h @@ -79,10 +79,10 @@ public: m_recentlyUpdatedTimeout = timeout; m_model->setRecentlyUpdatedTimeout(timeout); } - void setOnlyHighlightChangedValues(bool hilight) + void setOnlyHighlightChangedValues(bool highlight) { - m_onlyHighlightChangedValues = hilight; - m_model->setOnlyHighlightChangedValues(hilight); + m_onlyHighlightChangedValues = highlight; + m_model->setOnlyHighlightChangedValues(highlight); } void setViewOptions(bool showCategories, bool showMetadata, bool useScientificNotation, bool showDescription); void setSplitterState(QByteArray state); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index b12235de0..7cd57cae5 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -634,9 +634,10 @@ void UAVObjectTreeModel::updateObject(UAVObject *obj) ObjectTreeItem *item = findObjectTreeItem(obj->getObjID()); Q_ASSERT(item); // TODO don't update meta object if they are not shown - item->update(); + QTime ts = QTime::currentTime(); + item->update(ts); if (!onlyHighlightChangedValues()) { - item->setHighlighted(true); + item->setHighlighted(true, ts); } } From 738171e4a6657bef36db654c05db57f5a16787c2 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sun, 25 Mar 2018 21:38:47 +0200 Subject: [PATCH 14/20] LP-567 fix compilation errors with older compilers --- .../plugins/uavobjectbrowser/uavobjecttreemodel.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 7cd57cae5..ae07096d0 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -39,7 +39,7 @@ UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent) : QAbstractItemModel(parent) { m_highlightManager = new HighlightManager(); - connect(m_highlightManager, &HighlightManager::updateHighlight, this, &refreshHighlight); + connect(m_highlightManager, &HighlightManager::updateHighlight, this, &UAVObjectTreeModel::refreshHighlight); TreeItem::setHighlightTime(recentlyUpdatedTimeout()); @@ -162,8 +162,8 @@ void UAVObjectTreeModel::setupModelData() UAVObjectManager *objManager = pm->getObject(); Q_ASSERT(objManager); - connect(objManager, &UAVObjectManager::newObject, this, &newObject, Qt::UniqueConnection); - connect(objManager, &UAVObjectManager::newInstance, this, &newObject, Qt::UniqueConnection); + connect(objManager, &UAVObjectManager::newObject, this, &UAVObjectTreeModel::newObject, Qt::UniqueConnection); + connect(objManager, &UAVObjectManager::newInstance, this, &UAVObjectTreeModel::newObject, Qt::UniqueConnection); QList< QList > objList = objManager->getDataObjects(); foreach(QList list, objList) { @@ -197,11 +197,11 @@ void UAVObjectTreeModel::newObject(UAVObject *obj) void UAVObjectTreeModel::addObject(UAVDataObject *obj) { - connect(obj, &UAVDataObject::objectUpdated, this, &updateObject, Qt::UniqueConnection); - connect(obj, &UAVDataObject::isKnownChanged, this, &updateIsKnown, Qt::UniqueConnection); + connect(obj, &UAVDataObject::objectUpdated, this, &UAVObjectTreeModel::updateObject, Qt::UniqueConnection); + connect(obj, &UAVDataObject::isKnownChanged, this, &UAVObjectTreeModel::updateIsKnown, Qt::UniqueConnection); if (obj->getInstID() == 0) { UAVMetaObject *metaObj = obj->getMetaObject(); - connect(metaObj, &UAVDataObject::objectUpdated, this, &updateObject, Qt::UniqueConnection); + connect(metaObj, &UAVDataObject::objectUpdated, this, &UAVObjectTreeModel::updateObject, Qt::UniqueConnection); } if (obj->isSingleInstance()) { DataObjectTreeItem *dataObjectItem = createDataObject(obj); From bf3ce97e32d8262eb7902d5c26126f7a8946226c Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 26 Mar 2018 22:22:42 +0200 Subject: [PATCH 15/20] LP-567 fix crash when connected and switching back from categorized mode crash was due to highlight manager still referencing destroyed category tree items --- .../src/plugins/uavobjectbrowser/treeitem.cpp | 33 ++++++++++++++----- .../src/plugins/uavobjectbrowser/treeitem.h | 10 +++--- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp index ffcbc56c2..584c25881 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -42,15 +42,15 @@ HighlightManager::HighlightManager() * Called to add item to list. Item is only added if absent. * Returns true if item was added, otherwise false. */ -bool HighlightManager::add(TreeItem *itemToAdd) +bool HighlightManager::add(TreeItem *item) { // Lock to ensure thread safety QMutexLocker locker(&m_mutex); // Check so that the item isn't already in the list - if (!m_items.contains(itemToAdd)) { - m_items.insert(itemToAdd); - emit updateHighlight(itemToAdd); + if (!m_items.contains(item)) { + m_items.insert(item); + emit updateHighlight(item); return true; } return false; @@ -60,20 +60,34 @@ bool HighlightManager::add(TreeItem *itemToAdd) * Called to remove item from list. * Returns true if item was removed, otherwise false. */ -bool HighlightManager::remove(TreeItem *itemToRemove) +bool HighlightManager::remove(TreeItem *item) { // Lock to ensure thread safety QMutexLocker locker(&m_mutex); // Remove item and return result - const bool removed = m_items.remove(itemToRemove); + const bool removed = m_items.remove(item); if (removed) { - emit updateHighlight(itemToRemove); + emit updateHighlight(item); } return removed; } +/* + * Called to remove item from list. + * Will not emit a signal. Called when destroying an item + * Returns true if item was removed, otherwise false. + */ +bool HighlightManager::reset(TreeItem *item) +{ + // Lock to ensure thread safety + QMutexLocker locker(&m_mutex); + + // Remove item and return result + return m_items.remove(item); +} + bool HighlightManager::startTimer(QTime expirationTime) { // Lock to ensure thread safety @@ -163,6 +177,9 @@ TreeItem::TreeItem(const QVariant &data) : TreeItem::~TreeItem() { + if (m_highlightManager) { + m_highlightManager->reset(this); + } qDeleteAll(m_childItems); } @@ -273,7 +290,7 @@ void TreeItem::setHighlighted(bool highlighted, const QTime &ts) } // If we have a parent, call recursively to update highlight status of parents. - // This will ensure that the root of a leaf that is changed also is highlighted. + // This will ensure that the root of a leaf that is changed is also highlighted. // Only updates that really changes values will trigger highlight of parents. if (m_parentItem) { m_parentItem->setHighlighted(highlighted, ts); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h index 14c22cefa..a67a45aff 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/treeitem.h @@ -62,12 +62,14 @@ class HighlightManager : public QObject { public: HighlightManager(); - // This is called when an item has been set to - // highlighted = true. - bool add(TreeItem *itemToAdd); + // This is called when an item is set to highlighted = true. + bool add(TreeItem *item); // This is called when an item is set to highlighted = false; - bool remove(TreeItem *itemToRemove); + bool remove(TreeItem *item); + + // This is called when an item is destroyed + bool reset(TreeItem *item); bool startTimer(QTime time); From 79966757081608f1019c025c55a8ed74132d36c0 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 26 Mar 2018 22:26:06 +0200 Subject: [PATCH 16/20] LP-571 change generic instance tree node name to actual object name the other LP-571 issue is addressed by LP-567 --- ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index ae07096d0..aa13b6ea9 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -248,7 +248,7 @@ DataObjectTreeItem *UAVObjectTreeModel::createDataObject(UAVDataObject *obj) InstanceTreeItem *UAVObjectTreeModel::createDataObjectInstance(UAVDataObject *obj) { - QString name = tr("Instance") + " " + QString::number((int)obj->getInstID()); + QString name = obj->getName() + " " + QString::number((int)obj->getInstID()); InstanceTreeItem *item = new InstanceTreeItem(obj, name); item->setHighlightManager(m_highlightManager); From 64dfc358f8538a6b6376ba1e8fc67548c4ca7b0e Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 26 Mar 2018 22:27:49 +0200 Subject: [PATCH 17/20] LP-567 add new highlightTopTreeItems property false by default and not accessible through the UI... --- .../uavobjectbrowser/uavobjecttreemodel.cpp | 16 +++++++++++++++- .../uavobjectbrowser/uavobjecttreemodel.h | 3 +++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index aa13b6ea9..c91db8559 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -141,6 +141,16 @@ void UAVObjectTreeModel::setOnlyHighlightChangedValues(bool highlight) m_settings.setValue("onlyHighlightChangedValues", highlight); } +bool UAVObjectTreeModel::highlightTopTreeItems() const +{ + return m_settings.value("highlightTopTreeItems", false).toBool(); +} + +void UAVObjectTreeModel::setHighlightTopTreeItems(bool highlight) +{ + m_settings.setValue("highlightTopTreeItems", highlight); +} + void UAVObjectTreeModel::setupModelData() { QList rootData; @@ -571,7 +581,11 @@ QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const case Qt::BackgroundRole: if (index.column() == TreeItem::TITLE_COLUMN) { - if (!dynamic_cast(item) && item->isHighlighted()) { + // TODO filtering here on highlightTopTreeItems() should not be necessary + // top tree items should not be highlighted at all in the first place + // when highlightTopTreeItems() is false + bool highlight = (highlightTopTreeItems() || !dynamic_cast(item)); + if (highlight && item->isHighlighted()) { return recentlyUpdatedColor(); } } else if (index.column() == TreeItem::DATA_COLUMN) { diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index 87b2f16cf..80f2abc62 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -88,6 +88,9 @@ public: bool onlyHighlightChangedValues() const; void setOnlyHighlightChangedValues(bool highlight); + bool highlightTopTreeItems() const; + void setHighlightTopTreeItems(bool highlight); + private slots: void newObject(UAVObject *obj); void updateObject(UAVObject *obj); From 96cf07e77d594ffb0f9d6ff0211a18777127b7c8 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 26 Mar 2018 22:28:43 +0200 Subject: [PATCH 18/20] LP-567 added comments and const correctness --- .../gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp | 6 +++++- .../gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index c91db8559..42374410e 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -238,6 +238,8 @@ DataObjectTreeItem *UAVObjectTreeModel::createDataObject(UAVDataObject *obj) addObjectTreeItem(obj->getObjID(), item); item->setHighlightManager(m_highlightManager); + // metadata items are created up front and are added/removed as needed + // see toggleMetaItems() MetaObjectTreeItem *metaItem = createMetaObject(obj->getMetaObject()); if (showMetadata()) { appendItem(item, metaItem); @@ -303,6 +305,8 @@ TreeItem *UAVObjectTreeModel::getParentItem(UAVDataObject *obj, bool categorize) QStringList categoryPath = category.split('/'); foreach(QString category, categoryPath) { + // metadata items are created and destroyed as needed + // see toggleCategoryItems() TreeItem *categoryItem = parentItem->childByName(category); if (!categoryItem) { @@ -486,7 +490,7 @@ QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &pa return QModelIndex(); } -QModelIndex UAVObjectTreeModel::index(TreeItem *item, int column) +QModelIndex UAVObjectTreeModel::index(TreeItem *item, int column) const { if (item == m_rootItem) { return QModelIndex(); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index 80f2abc62..e6f641ae5 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -109,7 +109,7 @@ private: QHash m_objectTreeItems; - QModelIndex index(TreeItem *item, int column = 0); + QModelIndex index(TreeItem *item, int column = 0) const; void setupModelData(); void resetModelData(); From 077d1e89d108a1e11620d8675961b4dbbfa30341 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Mon, 26 Mar 2018 22:29:46 +0200 Subject: [PATCH 19/20] LP-567 reduce default highlight timeout from 500ms to 300ms --- ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 42374410e..cb7b6d335 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -122,7 +122,7 @@ void UAVObjectTreeModel::setManuallyChangedColor(QColor color) int UAVObjectTreeModel::recentlyUpdatedTimeout() const { - return m_settings.value("recentlyUpdatedTimeout", 500).toInt(); + return m_settings.value("recentlyUpdatedTimeout", 300).toInt(); } void UAVObjectTreeModel::setRecentlyUpdatedTimeout(int timeout) From 6e8f33803414510727f5f08fb9d12e9350407273 Mon Sep 17 00:00:00 2001 From: Philippe Renon Date: Sat, 7 Apr 2018 14:55:30 +0200 Subject: [PATCH 20/20] LP-567 store/restore tree expansion state --- .../uavobjectbrowser/uavobjectbrowser.cpp | 11 ++++ .../uavobjectbrowser/uavobjectbrowser.h | 3 + .../uavobjectbrowserwidget.cpp | 62 +++++++++++++++++++ .../uavobjectbrowser/uavobjectbrowserwidget.h | 12 ++++ 4 files changed, 88 insertions(+) diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp index cd2f87587..40f710c26 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.cpp @@ -55,6 +55,17 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration *config) m_widget->setSplitterState(m->splitterState()); } +void UAVObjectBrowser::saveState(QSettings &settings) const +{ + m_widget->saveState(settings); +} + + +void UAVObjectBrowser::restoreState(QSettings &settings) +{ + m_widget->restoreState(settings); +} + void UAVObjectBrowser::viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description) { if (m_config) { diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.h index d84891a95..d8e0c7adf 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowser.h @@ -51,6 +51,9 @@ public: } void loadConfiguration(IUAVGadgetConfiguration *config); + void saveState(QSettings &settings) const; + void restoreState(QSettings &settings); + private slots: void viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description); void splitterChanged(QByteArray state); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp index 2b6f24c0e..a18c2ce0d 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.cpp @@ -422,6 +422,68 @@ void UAVObjectBrowserWidget::searchLineChanged(QString searchText) } } +QString UAVObjectBrowserWidget::indexToPath(const QModelIndex &index) const +{ + QString path = index.data(Qt::DisplayRole).toString(); + + QModelIndex parent = index.parent(); + + while (parent.isValid()) { + path = parent.data(Qt::DisplayRole).toString() + "/" + path; + parent = parent.parent(); + } + return path; +} + +QModelIndex UAVObjectBrowserWidget::indexFromPath(const QString &path) const +{ + QStringList list = path.split("/"); + + QModelIndex index = m_modelProxy->index(0, 0); + + foreach(QString name, list) { + QModelIndexList items = m_modelProxy->match(index, Qt::DisplayRole, name, 1, Qt::MatchFlags(Qt::MatchExactly | Qt::MatchRecursive)); + + if (!items.isEmpty()) { + index = items.first(); + } else { + // bail out + return QModelIndex(); + } + } + return index; +} + +void UAVObjectBrowserWidget::saveState(QSettings &settings) const +{ + QStringList list; + + // prepare list + foreach(QModelIndex index, m_modelProxy->getPersistentIndexList()) { + if (m_browser->treeView->isExpanded(index)) { + QString path = indexToPath(index); + list << path; + } + } + + // save list + settings.setValue("expandedItems", QVariant::fromValue(list)); +} + +void UAVObjectBrowserWidget::restoreState(QSettings &settings) +{ + // get list + QStringList list = settings.value("expandedItems").toStringList(); + + foreach(QString path, list) { + QModelIndex index = indexFromPath(path); + + if (index.isValid()) { + m_browser->treeView->setExpanded(index, true); + } + } +} + void UAVObjectBrowserWidget::searchTextCleared() { m_browser->searchLine->clear(); diff --git a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h index 73b010afc..bcf8a7ac5 100644 --- a/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h +++ b/ground/gcs/src/plugins/uavobjectbrowser/uavobjectbrowserwidget.h @@ -46,6 +46,12 @@ class TreeSortFilterProxyModel : public QSortFilterProxyModel { public: TreeSortFilterProxyModel(QObject *parent); +public: + QModelIndexList getPersistentIndexList() const + { + return persistentIndexList(); + } + protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; bool filterAcceptsRowItself(int source_row, const QModelIndex &source_parent) const; @@ -87,6 +93,12 @@ public: void setViewOptions(bool showCategories, bool showMetadata, bool useScientificNotation, bool showDescription); void setSplitterState(QByteArray state); + void saveState(QSettings &settings) const; + void restoreState(QSettings &settings); + + QString indexToPath(const QModelIndex &index) const; + QModelIndex indexFromPath(const QString &path) const; + public slots: void showDescription(bool show);