From d03282d9b0177c6b19a6157ed768d7a9a482cffe Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sat, 16 Jun 2012 17:38:05 +0200 Subject: [PATCH 1/2] Changed the way change hilight of three cells works to bring down the number of QTimer instances and the number of redraws to hopefully increase performance. Changed so that when a child gets hilighted it will hilight its parent. --- .../src/plugins/uavobjectbrowser/treeitem.cpp | 70 ++++++++++++++++--- .../src/plugins/uavobjectbrowser/treeitem.h | 31 +++++++- .../uavobjectbrowser/uavobjecttreemodel.cpp | 12 +++- .../uavobjectbrowser/uavobjecttreemodel.h | 1 + 4 files changed, 102 insertions(+), 12 deletions(-) diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp index ced1bfcba..b8cea004f 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -27,6 +27,45 @@ #include "treeitem.h" +HighLightManager::HighLightManager(long checkingInterval) +{ + m_expirationTimer.start(checkingInterval); + connect(&m_expirationTimer, SIGNAL(timeout()), this, SLOT(checkItemsExpired())); +} + +bool HighLightManager::add(TreeItem *itemToAdd) +{ + QMutexLocker locker(&m_listMutex); + if(!m_itemsList.contains(itemToAdd)) + { + m_itemsList.append(itemToAdd); + return true; + } + return false; +} + +bool HighLightManager::remove(TreeItem *itemToRemove) +{ + QMutexLocker locker(&m_listMutex); + return m_itemsList.removeOne(itemToRemove); +} + +void HighLightManager::checkItemsExpired() +{ + QMutexLocker locker(&m_listMutex); + QMutableLinkedListIterator iter(m_itemsList); + QTime now = QTime::currentTime(); + while(iter.hasNext()) + { + TreeItem* item = iter.next(); + if(item->getHiglightExpires() < now) + { + item->removeHighlight(); + iter.remove(); + } + } +} + int TreeItem::m_highlightTimeMs = 500; TreeItem::TreeItem(const QList &data, TreeItem *parent) : @@ -36,7 +75,6 @@ TreeItem::TreeItem(const QList &data, TreeItem *parent) : m_highlight(false), m_changed(false) { - connect(&m_timer, SIGNAL(timeout()), this, SLOT(removeHighlight())); } TreeItem::TreeItem(const QVariant &data, TreeItem *parent) : @@ -46,7 +84,6 @@ TreeItem::TreeItem(const QVariant &data, TreeItem *parent) : m_changed(false) { m_data << data << "" << ""; - connect(&m_timer, SIGNAL(timeout()), this, SLOT(removeHighlight())); } TreeItem::~TreeItem() @@ -112,17 +149,34 @@ void TreeItem::setHighlight(bool highlight) { m_highlight = highlight; m_changed = false; if (highlight) { - if (m_timer.isActive()) { - m_timer.stop(); + m_highlightExpires = QTime::currentTime().addMSecs(m_highlightTimeMs); + if(m_highlightManager->add(this)) + { + emit updateHighlight(this); } - m_timer.setSingleShot(true); - m_timer.start(m_highlightTimeMs); } - emit updateHighlight(this); + else if(m_highlightManager->remove(this)) + { + emit updateHighlight(this); + } + if(m_parent) + { + m_parent->setHighlight(highlight); + } } void TreeItem::removeHighlight() { m_highlight = false; - update(); + //update(); emit updateHighlight(this); } + +void TreeItem::setHighlightManager(HighLightManager *mgr) +{ + m_highlightManager = mgr; +} + +QTime TreeItem::getHiglightExpires() +{ + return m_highlightExpires; +} diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h index 937631b05..494fb9a0b 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h @@ -32,10 +32,31 @@ #include "uavmetaobject.h" #include "uavobjectfield.h" #include +#include #include +#include #include #include +#include +class TreeItem; + +class HighLightManager : public QObject +{ +Q_OBJECT +public: + HighLightManager(long checkingInterval); + bool add(TreeItem* itemToAdd); + bool remove(TreeItem* itemToRemove); + +private slots: + void checkItemsExpired(); + +private: + QTimer m_expirationTimer; + QLinkedList m_itemsList; + QMutex m_listMutex; +}; class TreeItem : public QObject { @@ -77,11 +98,16 @@ public: inline bool changed() { return m_changed; } inline void setChanged(bool changed) { m_changed = changed; } + virtual void setHighlightManager(HighLightManager* mgr); + + QTime getHiglightExpires(); + + virtual void removeHighlight(); + signals: void updateHighlight(TreeItem*); private slots: - void removeHighlight(); private: QList m_children; @@ -91,7 +117,8 @@ private: TreeItem *m_parent; bool m_highlight; bool m_changed; - QTimer m_timer; + QTime m_highlightExpires; + HighLightManager* m_highlightManager; public: static const int dataColumn = 1; private: diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index ac2e4bcee..e2377da9a 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -46,7 +46,7 @@ UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent) : { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); - + m_highlightManager = new HighLightManager(300); connect(objManager, SIGNAL(newObject(UAVObject*)), this, SLOT(newObject(UAVObject*))); connect(objManager, SIGNAL(newInstance(UAVObject*)), this, SLOT(newObject(UAVObject*))); @@ -56,6 +56,7 @@ UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent) : UAVObjectTreeModel::~UAVObjectTreeModel() { + delete m_highlightManager; delete m_rootItem; } @@ -67,9 +68,12 @@ void UAVObjectTreeModel::setupModelData(UAVObjectManager *objManager) m_rootItem = new TreeItem(rootData); m_settingsTree = new TopTreeItem(tr("Settings"), m_rootItem); + m_settingsTree->setHighlightManager(m_highlightManager); m_rootItem->appendChild(m_settingsTree); m_nonSettingsTree = new TopTreeItem(tr("Data Objects"), m_rootItem); + m_nonSettingsTree->setHighlightManager(m_highlightManager); m_rootItem->appendChild(m_nonSettingsTree); + m_rootItem->setHighlightManager(m_highlightManager); connect(m_settingsTree, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); connect(m_nonSettingsTree, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); @@ -96,6 +100,7 @@ void UAVObjectTreeModel::addDataObject(UAVDataObject *obj) addInstance(obj, root->child(index)); } else { DataObjectTreeItem *data = new DataObjectTreeItem(obj->getName() + " (" + QString::number(obj->getNumBytes()) + " bytes)"); + data->setHighlightManager(m_highlightManager); connect(data, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); int index = root->nameIndex(obj->getName()); root->insert(index, data); @@ -110,6 +115,7 @@ void UAVObjectTreeModel::addMetaObject(UAVMetaObject *obj, TreeItem *parent) { connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(highlightUpdatedObject(UAVObject*))); MetaObjectTreeItem *meta = new MetaObjectTreeItem(obj, tr("Meta Data")); + meta->setHighlightManager(m_highlightManager); connect(meta, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); foreach (UAVObjectField *field, obj->getFields()) { if (field->getNumElements() > 1) { @@ -132,6 +138,7 @@ void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent) } else { QString name = tr("Instance") + " " + QString::number(obj->getInstID()); item = new InstanceTreeItem(obj, name); + item->setHighlightManager(m_highlightManager); connect(item, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); parent->appendChild(item); } @@ -148,6 +155,7 @@ void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent) void UAVObjectTreeModel::addArrayField(UAVObjectField *field, TreeItem *parent) { TreeItem *item = new ArrayFieldTreeItem(field->getName()); + item->setHighlightManager(m_highlightManager); connect(item, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); for (uint i = 0; i < field->getNumElements(); ++i) { addSingleField(i, field, item); @@ -192,6 +200,7 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt default: Q_ASSERT(false); } + item->setHighlightManager(m_highlightManager); connect(item, SIGNAL(updateHighlight(TreeItem*)), this, SLOT(updateHighlight(TreeItem*))); parent->appendChild(item); } @@ -352,7 +361,6 @@ void UAVObjectTreeModel::highlightUpdatedObject(UAVObject *obj) Q_ASSERT(obj); ObjectTreeItem *item = findObjectTreeItem(obj); Q_ASSERT(item); - item->setHighlight(true); item->update(); QModelIndex itemIndex = index(item); Q_ASSERT(itemIndex != QModelIndex()); diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index 17399611c..5e67840cd 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -97,6 +97,7 @@ private: int m_recentlyUpdatedTimeout; QColor m_recentlyUpdatedColor; QColor m_manuallyChangedColor; + HighLightManager *m_highlightManager; }; #endif // UAVOBJECTTREEMODEL_H From c8b4abc71fa05ed2c9d8dba0cb898fc40be9588c Mon Sep 17 00:00:00 2001 From: Fredrik Arvidsson Date: Sun, 17 Jun 2012 12:46:45 +0200 Subject: [PATCH 2/2] Added comments to the code. --- .../src/plugins/uavobjectbrowser/treeitem.cpp | 44 +++++++++++++++++++ .../src/plugins/uavobjectbrowser/treeitem.h | 27 ++++++++++++ .../uavobjectbrowser/uavobjecttreemodel.cpp | 2 + .../uavobjectbrowser/uavobjecttreemodel.h | 2 + 4 files changed, 75 insertions(+) diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp index b8cea004f..a6924e71d 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.cpp @@ -27,15 +27,24 @@ #include "treeitem.h" +/* Constructor */ HighLightManager::HighLightManager(long checkingInterval) { + // Start the timer and connect it to the callback m_expirationTimer.start(checkingInterval); connect(&m_expirationTimer, SIGNAL(timeout()), this, SLOT(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) { + // Lock to ensure thread safety QMutexLocker locker(&m_listMutex); + + // Check so that the item isn't already in the list if(!m_itemsList.contains(itemToAdd)) { m_itemsList.append(itemToAdd); @@ -44,23 +53,46 @@ bool HighLightManager::add(TreeItem *itemToAdd) return false; } +/* + * 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_listMutex); + + // Remove item and return result return m_itemsList.removeOne(itemToRemove); } +/* + * Callback called periodically by the timer. + * This method checks for expired highlights and + * removes them if they are expired. + * Expired highlights are restored. + */ void HighLightManager::checkItemsExpired() { + // Lock to ensure thread safety QMutexLocker locker(&m_listMutex); + + // Get a mutable iterator for the list QMutableLinkedListIterator iter(m_itemsList); + + // This is the timestamp to compare with QTime now = QTime::currentTime(); + + // Loop over all items, check if they expired. while(iter.hasNext()) { TreeItem* item = iter.next(); if(item->getHiglightExpires() < now) { + // If expired, call removeHighlight item->removeHighlight(); + + // Remove from list since it is restored. iter.remove(); } } @@ -145,20 +177,32 @@ void TreeItem::apply() { child->apply(); } +/* + * Called after a value has changed to trigger highlightning 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 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. + // 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); diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h index 494fb9a0b..c4f8e0355 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/treeitem.h @@ -41,20 +41,47 @@ class TreeItem; +/* +* Small utility class that handles the higlighting of +* tree grid items. +* Basicly it maintains all items due to be restored to +* 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. +* 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. +* Items that are updated during the expiration time are +* left untouched in the list. This reduces unwanted emits +* of signals to the repaint/update function. +*/ class HighLightManager : public QObject { Q_OBJECT public: + // Constructor taking the checking interval in ms. HighLightManager(long checkingInterval); + + // 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 = false; bool remove(TreeItem* itemToRemove); private slots: + // Timer callback method. void checkItemsExpired(); private: + // The timer checking highlight expiration. QTimer m_expirationTimer; + + // The list holding all items due to be updated. QLinkedList m_itemsList; + + //Mutex to lock when accessing list. QMutex m_listMutex; }; diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index e2377da9a..9bd8b20b4 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -46,6 +46,8 @@ UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent) : { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectManager *objManager = pm->getObject(); + + // Create highlight manager, let it run every 300 ms. m_highlightManager = new HighLightManager(300); connect(objManager, SIGNAL(newObject(UAVObject*)), this, SLOT(newObject(UAVObject*))); connect(objManager, SIGNAL(newInstance(UAVObject*)), this, SLOT(newObject(UAVObject*))); diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h index 5e67840cd..d9787e3a7 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.h @@ -97,6 +97,8 @@ private: int m_recentlyUpdatedTimeout; QColor m_recentlyUpdatedColor; QColor m_manuallyChangedColor; + + // Highlight manager to handle highlighting of tree items. HighLightManager *m_highlightManager; };