1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-06 21:54:15 +01:00

Merged in filnet/librepilot/LP-567_uavobjectbrowser_highlight_handling (pull request #486)

LP-567 uavobjectbrowser highlight handling

Approved-by: Philippe Renon <philippe_renon@yahoo.fr>
Approved-by: Lalanne Laurent <f5soh@free.fr>
This commit is contained in:
Philippe Renon 2018-04-29 17:34:08 +00:00 committed by Lalanne Laurent
commit 53bd0da106
18 changed files with 1169 additions and 843 deletions

View File

@ -31,7 +31,9 @@
BrowserItemDelegate::BrowserItemDelegate(QObject *parent) : BrowserItemDelegate::BrowserItemDelegate(QObject *parent) :
QStyledItemDelegate(parent) QStyledItemDelegate(parent)
{} {
_sizeHint = QSpinBox().sizeHint();
}
QWidget *BrowserItemDelegate::createEditor(QWidget *parent, QWidget *BrowserItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem & option, const QStyleOptionViewItem & option,
@ -75,5 +77,5 @@ QSize BrowserItemDelegate::sizeHint(const QStyleOptionViewItem & option, const Q
{ {
Q_UNUSED(option); Q_UNUSED(option);
Q_UNUSED(index); Q_UNUSED(index);
return QSpinBox().sizeHint(); return _sizeHint;
} }

View File

@ -47,6 +47,9 @@ public:
const QStyleOptionViewItem &option, const QModelIndex &index) const; const QStyleOptionViewItem &option, const QModelIndex &index) const;
QSize sizeHint(const QStyleOptionViewItem & option, QSize sizeHint(const QStyleOptionViewItem & option,
const QModelIndex &index) const; const QModelIndex &index) const;
private:
QSize _sizeHint;
}; };
#endif // BROWSERITEMDELEGATE_H #endif // BROWSERITEMDELEGATE_H

View File

@ -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"

View File

@ -29,12 +29,15 @@
#define FIELDTREEITEM_H #define FIELDTREEITEM_H
#include "treeitem.h" #include "treeitem.h"
#include <QtCore/QStringList>
#include <QStringList>
#include <QSettings>
#include <QWidget> #include <QWidget>
#include <QSpinBox> #include <QSpinBox>
#include <QDoubleSpinBox> #include <QDoubleSpinBox>
#include <qscispinbox/QScienceSpinBox.h> #include <qscispinbox/QScienceSpinBox.h>
#include <QComboBox> #include <QComboBox>
#include <limits> #include <limits>
#define QINT8MIN std::numeric_limits<qint8>::min() #define QINT8MIN std::numeric_limits<qint8>::min()
@ -49,58 +52,72 @@
#define QUINT32MAX std::numeric_limits<qint32>::max() #define QUINT32MAX std::numeric_limits<qint32>::max()
class FieldTreeItem : public TreeItem { class FieldTreeItem : public TreeItem {
Q_OBJECT
public: public:
FieldTreeItem(int index, const QList<QVariant> &data, UAVObjectField *field, TreeItem *parent = 0) : FieldTreeItem(int index, const QList<QVariant> &data, UAVObjectField *field) :
TreeItem(data, parent), m_index(index), m_field(field) TreeItem(data), m_index(index), m_field(field)
{}
FieldTreeItem(int index, const QVariant &data, UAVObjectField *field) :
TreeItem(data), m_index(index), m_field(field)
{} {}
FieldTreeItem(int index, const QVariant &data, UAVObjectField *field, TreeItem *parent = 0) : bool isEditable() const
TreeItem(data, parent), m_index(index), m_field(field)
{}
bool isEditable()
{ {
return true; return true;
} }
virtual QWidget *createEditor(QWidget *parent) = 0; virtual QWidget *createEditor(QWidget *parent) const = 0;
virtual QVariant getEditorValue(QWidget *editor) = 0; virtual QVariant getEditorValue(QWidget *editor) const = 0;
virtual void setEditorValue(QWidget *editor, QVariant value) = 0; virtual void setEditorValue(QWidget *editor, QVariant value) const = 0;
virtual void apply() {}
virtual bool isKnown() void setData(QVariant value, int column)
{ {
return parent()->isKnown(); QVariant currentValue = fieldToData();
setChanged(currentValue != value);
TreeItem::setData(value, column);
} }
void update(const QTime &ts)
{
bool updated = false;
if (!changed()) {
QVariant currentValue = fieldToData();
if (data() != currentValue) {
updated = true;
TreeItem::setData(currentValue);
}
}
if (changed() || updated) {
setHighlighted(true, ts);
}
}
void apply()
{
m_field->setValue(dataToField(), m_index);
setChanged(false);
}
protected: protected:
virtual QVariant fieldToData() const = 0;
virtual QVariant dataToField() const = 0;
int m_index; int m_index;
UAVObjectField *m_field; UAVObjectField *m_field;
}; };
class EnumFieldTreeItem : public FieldTreeItem { class EnumFieldTreeItem : public FieldTreeItem {
Q_OBJECT
public: public:
EnumFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data, TreeItem *parent = 0) : EnumFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data) :
FieldTreeItem(index, data, field, parent), m_enumOptions(field->getOptions()) FieldTreeItem(index, data, field), m_enumOptions(field->getOptions())
{} {}
EnumFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : EnumFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) :
FieldTreeItem(index, data, field, parent), m_enumOptions(field->getOptions()) FieldTreeItem(index, data, field), 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) QString enumOptions(int index)
{ {
if ((index < 0) || (index >= m_enumOptions.length())) { if ((index < 0) || (index >= m_enumOptions.length())) {
@ -109,28 +126,24 @@ public:
return m_enumOptions.at(index); return m_enumOptions.at(index);
} }
void apply() QVariant fieldToData() const
{
int value = data().toInt();
QStringList options = m_field->getOptions();
m_field->setValue(options[value], m_index);
setChanged(false);
}
void update()
{ {
QStringList options = m_field->getOptions(); QStringList options = m_field->getOptions();
QVariant value = m_field->getValue(m_index); QVariant value = m_field->getValue(m_index);
int valIndex = options.indexOf(value.toString()); int valIndex = options.indexOf(value.toString());
if (data() != valIndex || changed()) { return valIndex;
TreeItem::setData(valIndex);
setHighlight(true);
}
} }
QWidget *createEditor(QWidget *parent) QVariant dataToField() const
{
int value = data().toInt();
QStringList options = m_field->getOptions();
return options[value];
}
QWidget *createEditor(QWidget *parent) const
{ {
QComboBox *editor = new QComboBox(parent); QComboBox *editor = new QComboBox(parent);
@ -142,14 +155,14 @@ public:
return editor; return editor;
} }
QVariant getEditorValue(QWidget *editor) QVariant getEditorValue(QWidget *editor) const
{ {
QComboBox *comboBox = static_cast<QComboBox *>(editor); QComboBox *comboBox = static_cast<QComboBox *>(editor);
return comboBox->currentIndex(); return comboBox->currentIndex();
} }
void setEditorValue(QWidget *editor, QVariant value) void setEditorValue(QWidget *editor, QVariant value) const
{ {
QComboBox *comboBox = static_cast<QComboBox *>(editor); QComboBox *comboBox = static_cast<QComboBox *>(editor);
@ -161,16 +174,14 @@ private:
}; };
class IntFieldTreeItem : public FieldTreeItem { class IntFieldTreeItem : public FieldTreeItem {
Q_OBJECT
public: public:
IntFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data, TreeItem *parent = 0) : IntFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data) :
FieldTreeItem(index, data, field, parent) FieldTreeItem(index, data, field)
{ {
setMinMaxValues(); setMinMaxValues();
} }
IntFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) :
IntFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : FieldTreeItem(index, data, field)
FieldTreeItem(index, data, field, parent)
{ {
setMinMaxValues(); setMinMaxValues();
} }
@ -208,7 +219,17 @@ public:
} }
} }
QWidget *createEditor(QWidget *parent) 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); QSpinBox *editor = new QSpinBox(parent);
@ -217,7 +238,7 @@ public:
return editor; return editor;
} }
QVariant getEditorValue(QWidget *editor) QVariant getEditorValue(QWidget *editor) const
{ {
QSpinBox *spinBox = static_cast<QSpinBox *>(editor); QSpinBox *spinBox = static_cast<QSpinBox *>(editor);
@ -225,74 +246,41 @@ public:
return spinBox->value(); return spinBox->value();
} }
void setEditorValue(QWidget *editor, QVariant value) void setEditorValue(QWidget *editor, QVariant value) const
{ {
QSpinBox *spinBox = static_cast<QSpinBox *>(editor); QSpinBox *spinBox = static_cast<QSpinBox *>(editor);
spinBox->setValue(value.toInt()); 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: private:
int m_minValue; int m_minValue;
int m_maxValue; int m_maxValue;
}; };
class FloatFieldTreeItem : public FieldTreeItem { class FloatFieldTreeItem : public FieldTreeItem {
Q_OBJECT
public: public:
FloatFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data, bool scientific = false, TreeItem *parent = 0) : FloatFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data, const QSettings &settings) :
FieldTreeItem(index, data, field, parent), m_useScientificNotation(scientific) {} FieldTreeItem(index, data, field), m_settings(settings) {}
FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, bool scientific = false, TreeItem *parent = 0) : FloatFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, const QSettings &settings) :
FieldTreeItem(index, data, field, parent), m_useScientificNotation(scientific) {} FieldTreeItem(index, data, field), m_settings(settings) {}
void setData(QVariant value, int column) QVariant fieldToData() const
{ {
setChanged(m_field->getValue(m_index) != value); return m_field->getValue(m_index).toDouble();
TreeItem::setData(value, column);
} }
void apply() QVariant dataToField() const
{ {
m_field->setValue(data().toDouble(), m_index); return data().toDouble();
setChanged(false);
} }
void update() QWidget *createEditor(QWidget *parent) const
{ {
double value = m_field->getValue(m_index).toDouble(); bool useScientificNotation = m_settings.value("useScientificNotation", false).toBool();
if (data() != value || changed()) { if (useScientificNotation) {
TreeItem::setData(value);
setHighlight(true);
}
}
QWidget *createEditor(QWidget *parent)
{
if (m_useScientificNotation) {
QScienceSpinBox *editor = new QScienceSpinBox(parent); QScienceSpinBox *editor = new QScienceSpinBox(parent);
editor->setDecimals(6); editor->setDecimals(6);
editor->setMinimum(-std::numeric_limits<float>::max()); editor->setMinimum(-std::numeric_limits<float>::max());
@ -307,9 +295,11 @@ public:
} }
} }
QVariant getEditorValue(QWidget *editor) QVariant getEditorValue(QWidget *editor) const
{ {
if (m_useScientificNotation) { bool useScientificNotation = m_settings.value("useScientificNotation", false).toBool();
if (useScientificNotation) {
QScienceSpinBox *spinBox = static_cast<QScienceSpinBox *>(editor); QScienceSpinBox *spinBox = static_cast<QScienceSpinBox *>(editor);
spinBox->interpretText(); spinBox->interpretText();
return spinBox->value(); return spinBox->value();
@ -320,9 +310,11 @@ public:
} }
} }
void setEditorValue(QWidget *editor, QVariant value) void setEditorValue(QWidget *editor, QVariant value) const
{ {
if (m_useScientificNotation) { bool useScientificNotation = m_settings.value("useScientificNotation", false).toBool();
if (useScientificNotation) {
QScienceSpinBox *spinBox = static_cast<QScienceSpinBox *>(editor); QScienceSpinBox *spinBox = static_cast<QScienceSpinBox *>(editor);
spinBox->setValue(value.toDouble()); spinBox->setValue(value.toDouble());
} else { } else {
@ -332,21 +324,30 @@ public:
} }
private: private:
bool m_useScientificNotation; const QSettings &m_settings;
}; };
class HexFieldTreeItem : public FieldTreeItem { class HexFieldTreeItem : public FieldTreeItem {
Q_OBJECT
public: public:
HexFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data, TreeItem *parent = 0) : HexFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data) :
FieldTreeItem(index, data, field, parent) FieldTreeItem(index, data, field)
{} {}
HexFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : HexFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) :
FieldTreeItem(index, data, field, parent) FieldTreeItem(index, data, field)
{} {}
QWidget *createEditor(QWidget *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); QLineEdit *lineEdit = new QLineEdit(parent);
@ -355,44 +356,22 @@ public:
return lineEdit; return lineEdit;
} }
QVariant getEditorValue(QWidget *editor) QVariant getEditorValue(QWidget *editor) const
{ {
QLineEdit *lineEdit = static_cast<QLineEdit *>(editor); QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
return lineEdit->text(); return lineEdit->text();
} }
void setEditorValue(QWidget *editor, QVariant value) void setEditorValue(QWidget *editor, QVariant value) const
{ {
QLineEdit *lineEdit = static_cast<QLineEdit *>(editor); QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
lineEdit->setText(value.toString()); 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: private:
QVariant toHexString(QVariant value) QVariant toHexString(QVariant value) const
{ {
QString str; QString str;
bool ok; bool ok;
@ -400,7 +379,7 @@ private:
return str.setNum(value.toUInt(&ok), 16).toUpper(); return str.setNum(value.toUInt(&ok), 16).toUpper();
} }
QVariant toUInt(QVariant str) QVariant toUInt(QVariant str) const
{ {
bool ok; bool ok;
@ -409,17 +388,26 @@ private:
}; };
class CharFieldTreeItem : public FieldTreeItem { class CharFieldTreeItem : public FieldTreeItem {
Q_OBJECT
public: public:
CharFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data, TreeItem *parent = 0) : CharFieldTreeItem(UAVObjectField *field, int index, const QList<QVariant> &data) :
FieldTreeItem(index, data, field, parent) FieldTreeItem(index, data, field)
{} {}
CharFieldTreeItem(UAVObjectField *field, int index, const QVariant &data, TreeItem *parent = 0) : CharFieldTreeItem(UAVObjectField *field, int index, const QVariant &data) :
FieldTreeItem(index, data, field, parent) FieldTreeItem(index, data, field)
{} {}
QWidget *createEditor(QWidget *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); QLineEdit *lineEdit = new QLineEdit(parent);
@ -428,49 +416,27 @@ public:
return lineEdit; return lineEdit;
} }
QVariant getEditorValue(QWidget *editor) QVariant getEditorValue(QWidget *editor) const
{ {
QLineEdit *lineEdit = static_cast<QLineEdit *>(editor); QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
return lineEdit->text(); return lineEdit->text();
} }
void setEditorValue(QWidget *editor, QVariant value) void setEditorValue(QWidget *editor, QVariant value) const
{ {
QLineEdit *lineEdit = static_cast<QLineEdit *>(editor); QLineEdit *lineEdit = static_cast<QLineEdit *>(editor);
lineEdit->setText(value.toString()); 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: private:
QVariant toChar(QVariant value) QVariant toChar(QVariant value) const
{ {
return value.toChar(); return value.toChar();
} }
QVariant toUInt(QVariant str) QVariant toUInt(QVariant str) const
{ {
return QVariant(str.toString().at(0).toLatin1()); return QVariant(str.toString().at(0).toLatin1());
} }

View File

@ -27,26 +27,30 @@
#include "treeitem.h" #include "treeitem.h"
#include <QDebug>
/* Constructor */ /* Constructor */
HighLightManager::HighLightManager(long checkingInterval) HighlightManager::HighlightManager()
{ {
// Start the timer and connect it to the callback // Initialize the timer and connect it to the callback
m_expirationTimer.start(checkingInterval); m_expirationTimer.setTimerType(Qt::PreciseTimer);
connect(&m_expirationTimer, SIGNAL(timeout()), this, SLOT(checkItemsExpired())); m_expirationTimer.setSingleShot(true);
connect(&m_expirationTimer, &QTimer::timeout, this, &HighlightManager::checkItemsExpired);
} }
/* /*
* Called to add item to list. Item is only added if absent. * Called to add item to list. Item is only added if absent.
* Returns true if item was added, otherwise false. * Returns true if item was added, otherwise false.
*/ */
bool HighLightManager::add(TreeItem *itemToAdd) bool HighlightManager::add(TreeItem *item)
{ {
// Lock to ensure thread safety // Lock to ensure thread safety
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
// Check so that the item isn't already in the list // Check so that the item isn't already in the list
if (!m_items.contains(itemToAdd)) { if (!m_items.contains(item)) {
m_items.insert(itemToAdd); m_items.insert(item);
emit updateHighlight(item);
return true; return true;
} }
return false; return false;
@ -56,13 +60,57 @@ bool HighLightManager::add(TreeItem *itemToAdd)
* Called to remove item from list. * Called to remove item from list.
* Returns true if item was removed, otherwise false. * Returns true if item was removed, otherwise false.
*/ */
bool HighLightManager::remove(TreeItem *itemToRemove) bool HighlightManager::remove(TreeItem *item)
{ {
// Lock to ensure thread safety // Lock to ensure thread safety
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
// Remove item and return result // Remove item and return result
return m_items.remove(itemToRemove); const bool removed = m_items.remove(item);
if (removed) {
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
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;
}
void HighlightManager::reset()
{
// Lock to ensure thread safety
QMutexLocker locker(&m_mutex);
m_expirationTimer.stop();
m_items.clear();
} }
/* /*
@ -71,7 +119,7 @@ bool HighLightManager::remove(TreeItem *itemToRemove)
* removes them if they are expired. * removes them if they are expired.
* Expired highlights are restored. * Expired highlights are restored.
*/ */
void HighLightManager::checkItemsExpired() void HighlightManager::checkItemsExpired()
{ {
// Lock to ensure thread safety // Lock to ensure thread safety
QMutexLocker locker(&m_mutex); QMutexLocker locker(&m_mutex);
@ -81,72 +129,102 @@ void HighLightManager::checkItemsExpired()
// This is the timestamp to compare with // This is the timestamp to compare with
QTime now = QTime::currentTime(); QTime now = QTime::currentTime();
QTime next;
// Loop over all items, check if they expired. // Loop over all items, check if they expired.
while (iter.hasNext()) { while (iter.hasNext()) {
TreeItem *item = iter.next(); TreeItem *item = iter.next();
if (item->getHiglightExpires() < now) { if (item->getHighlightExpires() <= now) {
// If expired, call removeHighlight // expired, call removeHighlight
item->removeHighlight(); item->resetHighlight();
// Remove from list since it is restored. // Remove from list since it is restored.
iter.remove(); iter.remove();
emit updateHighlight(item);
} else {
// not expired, check if next to expire
if (!next.isValid() || (next > item->getHighlightExpires())) {
next = item->getHighlightExpires();
} }
} }
}
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<QVariant> &data, TreeItem *parent) : TreeItem::TreeItem(const QList<QVariant> &data) :
QObject(0), m_itemData(data),
m_data(data), m_parentItem(0),
m_parent(parent), m_changed(false),
m_highlight(false), m_highlighted(false),
m_changed(false) m_highlightManager(0)
{} {}
TreeItem::TreeItem(const QVariant &data, TreeItem *parent) : TreeItem::TreeItem(const QVariant &data) :
QObject(0), m_parentItem(0),
m_parent(parent), m_changed(false),
m_highlight(false), m_highlighted(false),
m_changed(false) m_highlightManager(0)
{ {
m_data << data << "" << ""; m_itemData << data << "" << "";
} }
TreeItem::~TreeItem() TreeItem::~TreeItem()
{ {
qDeleteAll(m_children); if (m_highlightManager) {
m_highlightManager->reset(this);
}
qDeleteAll(m_childItems);
} }
void TreeItem::appendChild(TreeItem *child) void TreeItem::setParentItem(TreeItem *parentItem)
{ {
m_children.append(child); if (m_parentItem) {
child->setParentTree(this); 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_children.insert(index, child);
child->setParentTree(this);
} }
TreeItem *TreeItem::getChild(int index) void TreeItem::insertChild(TreeItem *childItem, int index)
{ {
return m_children.value(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
{
return m_childItems.value(index);
} }
int TreeItem::childCount() const int TreeItem::childCount() const
{ {
return m_children.count(); return m_childItems.count();
} }
int TreeItem::row() const int TreeItem::row() const
{ {
if (m_parent) { if (m_parentItem) {
return m_parent->m_children.indexOf(const_cast<TreeItem *>(this)); return m_parentItem->m_childItems.indexOf(const_cast<TreeItem *>(this));
} }
return 0; return 0;
@ -154,79 +232,140 @@ int TreeItem::row() const
int TreeItem::columnCount() const int TreeItem::columnCount() const
{ {
return m_data.count(); return m_itemData.count();
}
void TreeItem::setDescription(QString desc)
{
// Split around 40 characters
int idx = desc.indexOf(" ", 40);
desc.insert(idx, QString("<br>"));
desc.remove("@Ref", Qt::CaseInsensitive);
m_description = desc;
} }
QVariant TreeItem::data(int column) const QVariant TreeItem::data(int column) const
{ {
return m_data.value(column); return m_itemData.value(column);
} }
void TreeItem::setData(QVariant value, int column) void TreeItem::setData(QVariant value, int column)
{ {
m_data.replace(column, value); m_itemData.replace(column, value);
} }
void TreeItem::update() void TreeItem::update(const QTime &ts)
{ {
foreach(TreeItem * child, treeChildren()) foreach(TreeItem * child, children()) {
child->update(); child->update(ts);
}
} }
void TreeItem::apply() void TreeItem::apply()
{ {
foreach(TreeItem * child, treeChildren()) foreach(TreeItem * child, children()) {
child->apply(); child->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) void TreeItem::setHighlighted(bool highlighted, const QTime &ts)
{ {
m_highlight = highlight;
m_changed = false; m_changed = false;
if (highlight) { if (m_highlighted != highlighted) {
// Update the expires timestamp m_highlighted = highlighted;
m_highlightExpires = QTime::currentTime().addMSecs(m_highlightTimeMs); if (highlighted) {
// Add to highlight manager
// Add to highlightmanager m_highlightManager->add(this);
if (m_highlightManager->add(this)) { // Update expiration timeout
// Only emit signal if it was added m_highlightExpires = ts.addMSecs(m_highlightTimeMs);
emit updateHighlight(this); // start expiration timer if necessary
m_highlightManager->startTimer(m_highlightExpires);
} else {
m_highlightManager->remove(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. // 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. // Only updates that really changes values will trigger highlight of parents.
if (m_parent) { if (m_parentItem) {
m_parent->setHighlight(highlight); m_parentItem->setHighlighted(highlighted, ts);
} }
} }
void TreeItem::removeHighlight() void TreeItem::resetHighlight()
{ {
m_highlight = false; m_highlighted = false;
emit updateHighlight(this);
} }
void TreeItem::setHighlightManager(HighLightManager *mgr) void TreeItem::setHighlightManager(HighlightManager *mgr)
{ {
m_highlightManager = mgr; m_highlightManager = mgr;
} }
QTime TreeItem::getHiglightExpires() QTime TreeItem::getHighlightExpires() const
{ {
return m_highlightExpires; return m_highlightExpires;
} }
QList<MetaObjectTreeItem *> TopTreeItem::getMetaObjectItems() int TreeItem::childIndex(QString name) const
{ {
return m_metaObjectTreeItemsPerObjectIds.values(); 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 QVariant ArrayFieldTreeItem::data(int column) const
@ -234,28 +373,32 @@ QVariant ArrayFieldTreeItem::data(int column) const
if (column == 1) { if (column == 1) {
if (m_field->getType() == UAVObjectField::UINT8 && m_field->getUnits().toLower() == "char") { if (m_field->getType() == UAVObjectField::UINT8 && m_field->getUnits().toLower() == "char") {
QString dataString; QString dataString;
dataString.reserve(2 + m_field->getNumElements());
dataString.append("'");
for (uint i = 0; i < m_field->getNumElements(); ++i) { for (uint i = 0; i < m_field->getNumElements(); ++i) {
dataString.append(m_field->getValue(i).toChar()); dataString.append(m_field->getValue(i).toChar());
} }
QString data = QString("'%1'").arg(dataString); dataString.append("'");
return data; return dataString;
} else if (m_field->getUnits().toLower() == "hex") { } else if (m_field->getUnits().toLower() == "hex") {
QString dataString; 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) { for (uint i = 0; i < m_field->getNumElements(); ++i) {
if (i > 0) { if (i > 0) {
dataString.append(' '); dataString.append(' ');
} }
bool ok; bool ok;
dataString.append(QString("%1") uint value = m_field->getValue(i).toUInt(&ok);
.arg(m_field->getValue(i).toUInt(&ok), TreeItem::maxHexStringLength(m_field->getType()), QString str = QString("%1").arg(value, len, 16, fillChar);
16, QChar('0')).toUpper()); str = str.toUpper();
dataString.append(str);
}
dataString.append("}");
return dataString;
} }
QString data = QString("{%1}").arg(dataString);
return data;
} else {
return QVariant();
} }
} else {
return TreeItem::data(column); return TreeItem::data(column);
}
} }

View File

@ -29,16 +29,16 @@
#define TREEITEM_H #define TREEITEM_H
#include "uavobject.h" #include "uavobject.h"
#include "uavdataobject.h"
#include "uavmetaobject.h" #include "uavmetaobject.h"
#include "uavobjectfield.h" #include "uavobjectfield.h"
#include <QtCore/QList>
#include <QtCore/QLinkedList> #include <QList>
#include <QtCore/QMap> #include <QMap>
#include <QtCore/QVariant> #include <QVariant>
#include <QtCore/QTime> #include <QTime>
#include <QtCore/QTimer> #include <QTimer>
#include <QtCore/QObject> #include <QObject>
#include <QtCore/QDebug>
class TreeItem; class TreeItem;
@ -49,7 +49,7 @@ class TreeItem;
* non highlighted state in a linked list. * non highlighted state in a linked list.
* A timer traverses this list periodically to find out * A timer traverses this list periodically to find out
* if any of the items should be restored. All items are * 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 * An item that is beeing restored is removed from the
* list and its removeHighlight() method is called. Items * list and its removeHighlight() method is called. Items
* that are not expired are left in the list til next time. * that are not expired are left in the list til next time.
@ -57,18 +57,26 @@ class TreeItem;
* left untouched in the list. This reduces unwanted emits * left untouched in the list. This reduces unwanted emits
* of signals to the repaint/update function. * of signals to the repaint/update function.
*/ */
class HighLightManager : public QObject { class HighlightManager : public QObject {
Q_OBJECT Q_OBJECT
public: public:
// Constructor taking the checking interval in ms. HighlightManager();
HighLightManager(long checkingInterval);
// This is called when an item has been set to // This is called when an item is set to highlighted = true.
// highlighted = true. bool add(TreeItem *item);
bool add(TreeItem *itemToAdd);
// This is called when an item is set to highlighted = false; // 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);
void reset();
signals:
void updateHighlight(TreeItem *item);
private slots: private slots:
// Timer callback method. // Timer callback method.
@ -85,252 +93,182 @@ private:
QMutex m_mutex; QMutex m_mutex;
}; };
class TreeItem : public QObject { class TreeItem {
Q_OBJECT
public: public:
static const int TITLE_COLUMN = 0; static const int TITLE_COLUMN = 0;
static const int DATA_COLUMN = 1; static const int DATA_COLUMN = 1;
TreeItem(const QList<QVariant> &data, TreeItem *parent = 0); TreeItem(const QList<QVariant> &data);
TreeItem(const QVariant &data, TreeItem *parent = 0); TreeItem(const QVariant &data);
virtual ~TreeItem(); virtual ~TreeItem();
void appendChild(TreeItem *child); TreeItem *parentItem() const
void insertChild(TreeItem *child);
TreeItem *getChild(int index);
inline QList<TreeItem *> treeChildren() const
{ {
return m_children; 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<TreeItem *> children() const
{
return m_childItems;
}
int childCount() const; int childCount() const;
int columnCount() const; int columnCount() const;
virtual QVariant data(int column = 1) const;
QString description() QString description() const
{ {
return m_description; return m_description;
} }
void setDescription(QString d) // Split around 40 characters
{
int idx = d.indexOf(" ", 40);
d.insert(idx, QString("<br>")); void setDescription(QString desc);
d.remove("@Ref", Qt::CaseInsensitive);
m_description = d; virtual QVariant data(int column = 1) const;
}
// only column 1 (TreeItem::dataColumn) is changed with setData currently
// other columns are initialized in constructor
virtual void setData(QVariant value, int column = 1); virtual void setData(QVariant value, int column = 1);
int row() const; int row() const;
TreeItem *parent()
{ virtual bool isEditable() const
return m_parent;
}
void setParentTree(TreeItem *parent)
{
m_parent = parent;
}
inline virtual bool isEditable()
{ {
return false; return false;
} }
virtual void update();
virtual void update(const QTime &ts);
virtual void apply(); virtual void apply();
inline bool highlighted() 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, const QTime &ts);
static void setHighlightTime(int time) static void setHighlightTime(int time)
{ {
m_highlightTimeMs = time; m_highlightTimeMs = time;
} }
inline bool changed() QTime getHighlightExpires() const;
void resetHighlight();
void setHighlightManager(HighlightManager *mgr);
virtual bool isKnown() const
{ {
return m_changed; if (m_parentItem) {
return m_parentItem->isKnown();
} }
inline void setChanged(bool changed)
{
m_changed = changed;
}
virtual void setHighlightManager(HighLightManager *mgr);
QTime getHiglightExpires();
virtual void removeHighlight();
int nameIndex(QString name)
{
for (int i = 0; i < childCount(); ++i) {
if (name < getChild(i)->data(0).toString()) {
return i;
}
}
return childCount();
}
TreeItem *findChildByName(QString name)
{
foreach(TreeItem * child, m_children) {
if (name == child->data(0).toString()) {
return child;
}
}
return 0;
}
static int 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;
}
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()
{
return true; return true;
} }
signals: int childIndex(QString name) const;
void updateHighlight(TreeItem *item);
void updateIsKnown(TreeItem *item);
private slots: TreeItem *childByName(QString name) const;
int insertionIndex(TreeItem *item) const;
static int maxHexStringLength(UAVObjectField::FieldType type);
private: private:
static int m_highlightTimeMs; static int m_highlightTimeMs;
QList<TreeItem *> m_children;
QList<TreeItem *> m_childItems;
// m_data contains: [0] property name, [1] value, [2] unit // m_data contains: [0] property name, [1] value, [2] unit
QList<QVariant> m_data; QList<QVariant> m_itemData;
TreeItem *m_parentItem;
QString m_description; QString m_description;
TreeItem *m_parent;
bool m_highlight;
bool m_changed; bool m_changed;
bool m_highlighted;
QTime m_highlightExpires; QTime m_highlightExpires;
HighLightManager *m_highlightManager; HighlightManager *m_highlightManager;
}; };
class DataObjectTreeItem;
class MetaObjectTreeItem;
class TopTreeItem : public TreeItem { class TopTreeItem : public TreeItem {
Q_OBJECT
public: public:
TopTreeItem(const QList<QVariant> &data, TreeItem *parent = 0) : TreeItem(data, parent) {} TopTreeItem(const QList<QVariant> &data) :
TopTreeItem(const QVariant &data, TreeItem *parent = 0) : TreeItem(data, parent) {} TreeItem(data)
{}
void addObjectTreeItem(quint32 objectId, DataObjectTreeItem *oti) TopTreeItem(const QVariant &data) :
{ TreeItem(data)
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);
}
QList<MetaObjectTreeItem *> getMetaObjectItems();
private:
QHash<quint32, DataObjectTreeItem *> m_objectTreeItemsPerObjectIds;
QHash<quint32, MetaObjectTreeItem *> m_metaObjectTreeItemsPerObjectIds;
}; };
class ObjectTreeItem : public TreeItem { class ObjectTreeItem : public TreeItem {
Q_OBJECT
public: public:
ObjectTreeItem(const QList<QVariant> &data, UAVObject *object, TreeItem *parent = 0) : ObjectTreeItem(UAVObject *object, const QList<QVariant> &data) :
TreeItem(data, parent), m_obj(object) TreeItem(data), m_obj(object)
{ {
setDescription(m_obj->getDescription()); setDescription(m_obj->getDescription());
} }
ObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parent = 0) : ObjectTreeItem(UAVObject *object, const QVariant &data) :
TreeItem(data, parent), m_obj(object) TreeItem(data), m_obj(object)
{ {
setDescription(m_obj->getDescription()); setDescription(m_obj->getDescription());
} }
inline UAVObject *object()
UAVObject *object() const
{ {
return m_obj; return m_obj;
} }
bool isKnown()
{
return !m_obj->isSettingsObject() || m_obj->isKnown();
}
private: private:
UAVObject *m_obj; UAVObject *m_obj;
}; };
class MetaObjectTreeItem : public ObjectTreeItem { class MetaObjectTreeItem : public ObjectTreeItem {
Q_OBJECT
public: public:
MetaObjectTreeItem(UAVObject *object, const QList<QVariant> &data, TreeItem *parent = 0) : MetaObjectTreeItem(UAVMetaObject *object, const QList<QVariant> &data) :
ObjectTreeItem(data, object, parent) ObjectTreeItem(object, data)
{} {}
MetaObjectTreeItem(UAVObject *object, const QVariant &data, TreeItem *parent = 0) : MetaObjectTreeItem(UAVMetaObject *object, const QVariant &data) :
ObjectTreeItem(data, object, parent) ObjectTreeItem(object, data)
{} {}
bool isKnown() UAVMetaObject *metaObject() const
{ {
return parent()->isKnown(); return static_cast<UAVMetaObject *>(object());
} }
}; };
class DataObjectTreeItem : public ObjectTreeItem { class DataObjectTreeItem : public ObjectTreeItem {
Q_OBJECT
public: public:
DataObjectTreeItem(const QList<QVariant> &data, UAVObject *object, TreeItem *parent = 0) : DataObjectTreeItem(UAVDataObject *object, const QList<QVariant> &data) :
ObjectTreeItem(data, object, parent) {} ObjectTreeItem(object, data)
DataObjectTreeItem(const QVariant &data, UAVObject *object, TreeItem *parent = 0) : {}
ObjectTreeItem(data, object, parent) {} DataObjectTreeItem(UAVDataObject *object, const QVariant &data) :
ObjectTreeItem(object, data)
{}
UAVDataObject *dataObject() const
{
return static_cast<UAVDataObject *>(object());
}
virtual void apply() virtual void apply()
{ {
foreach(TreeItem * child, treeChildren()) { foreach(TreeItem * child, children()) {
MetaObjectTreeItem *metaChild = dynamic_cast<MetaObjectTreeItem *>(child); MetaObjectTreeItem *metaChild = dynamic_cast<MetaObjectTreeItem *>(child);
if (!metaChild) { if (!metaChild) {
@ -338,49 +276,54 @@ public:
} }
} }
} }
virtual void update()
virtual void update(const QTime &ts)
{ {
foreach(TreeItem * child, treeChildren()) { foreach(TreeItem * child, children()) {
MetaObjectTreeItem *metaChild = dynamic_cast<MetaObjectTreeItem *>(child); MetaObjectTreeItem *metaChild = dynamic_cast<MetaObjectTreeItem *>(child);
if (!metaChild) { if (!metaChild) {
child->update(); child->update(ts);
} }
} }
} }
virtual bool isKnown() const
{
return !object()->isSettingsObject() || object()->isKnown();
}
}; };
class InstanceTreeItem : public DataObjectTreeItem { class InstanceTreeItem : public DataObjectTreeItem {
Q_OBJECT
public: public:
InstanceTreeItem(UAVObject *object, const QList<QVariant> &data, TreeItem *parent = 0) : InstanceTreeItem(UAVDataObject *object, const QList<QVariant> &data) :
DataObjectTreeItem(data, object, parent) DataObjectTreeItem(object, data)
{} {}
InstanceTreeItem(UAVObject *object, const QVariant &data, TreeItem *parent = 0) : InstanceTreeItem(UAVDataObject *object, const QVariant &data) :
DataObjectTreeItem(data, object, parent) DataObjectTreeItem(object, data)
{} {}
virtual void update(const QTime &ts)
{
TreeItem::update(ts);
}
virtual void apply() virtual void apply()
{ {
TreeItem::apply(); TreeItem::apply();
} }
virtual void update()
{
TreeItem::update();
}
}; };
class ArrayFieldTreeItem : public TreeItem { class ArrayFieldTreeItem : public TreeItem {
Q_OBJECT
public: public:
ArrayFieldTreeItem(UAVObjectField *field, const QList<QVariant> &data, TreeItem *parent = 0) : TreeItem(data, parent), m_field(field) ArrayFieldTreeItem(UAVObjectField *field, const QList<QVariant> &data) :
TreeItem(data), 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(data), m_field(field)
{} {}
QVariant data(int column) const; QVariant data(int column) const;
bool isKnown()
{
return parent()->isKnown();
}
private: private:
UAVObjectField *m_field; UAVObjectField *m_field;

View File

@ -50,11 +50,22 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration *config)
m_widget->setRecentlyUpdatedColor(m->recentlyUpdatedColor()); m_widget->setRecentlyUpdatedColor(m->recentlyUpdatedColor());
m_widget->setManuallyChangedColor(m->manuallyChangedColor()); m_widget->setManuallyChangedColor(m->manuallyChangedColor());
m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout()); 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->setViewOptions(m->categorizedView(), m->showMetaData(), m->scientificView(), m->showDescription());
m_widget->setSplitterState(m->splitterState()); 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) void UAVObjectBrowser::viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description)
{ {
if (m_config) { if (m_config) {

View File

@ -51,6 +51,9 @@ public:
} }
void loadConfiguration(IUAVGadgetConfiguration *config); void loadConfiguration(IUAVGadgetConfiguration *config);
void saveState(QSettings &settings) const;
void restoreState(QSettings &settings);
private slots: private slots:
void viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description); void viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description);
void splitterChanged(QByteArray state); void splitterChanged(QByteArray state);

View File

@ -7,28 +7,27 @@ include(../../plugin.pri)
include(uavobjectbrowser_dependencies.pri) include(uavobjectbrowser_dependencies.pri)
HEADERS += \ HEADERS += \
browserplugin.h \ treeitem.h \
fieldtreeitem.h \
browseritemdelegate.h \
uavobjecttreemodel.h \
uavobjectbrowserconfiguration.h \ uavobjectbrowserconfiguration.h \
uavobjectbrowseroptionspage.h \
uavobjectbrowser.h \ uavobjectbrowser.h \
uavobjectbrowserwidget.h \ uavobjectbrowserwidget.h \
uavobjectbrowserfactory.h \ uavobjectbrowserfactory.h \
uavobjectbrowseroptionspage.h \ browserplugin.h
uavobjecttreemodel.h \
treeitem.h \
browseritemdelegate.h \
fieldtreeitem.h
SOURCES += \ SOURCES += \
browserplugin.cpp \ treeitem.cpp \
browseritemdelegate.cpp \
uavobjecttreemodel.cpp \
uavobjectbrowserconfiguration.cpp \ uavobjectbrowserconfiguration.cpp \
uavobjectbrowseroptionspage.cpp \
uavobjectbrowser.cpp \ uavobjectbrowser.cpp \
uavobjectbrowserfactory.cpp \ uavobjectbrowserfactory.cpp \
uavobjectbrowserwidget.cpp \ uavobjectbrowserwidget.cpp \
uavobjectbrowseroptionspage.cpp \ browserplugin.cpp
uavobjecttreemodel.cpp \
treeitem.cpp \
browseritemdelegate.cpp \
fieldtreeitem.cpp
OTHER_FILES += UAVObjectBrowser.pluginspec OTHER_FILES += UAVObjectBrowser.pluginspec

View File

@ -38,6 +38,7 @@
#include "extensionsystem/pluginmanager.h" #include "extensionsystem/pluginmanager.h"
#include "utils/mustache.h" #include "utils/mustache.h"
#include <QTextStream>
#include <QDebug> #include <QDebug>
UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent) UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent)
@ -47,10 +48,7 @@ UAVObjectBrowserWidget::UAVObjectBrowserWidget(QWidget *parent) : QWidget(parent
m_viewoptions = new Ui_viewoptions(); m_viewoptions = new Ui_viewoptions();
m_viewoptions->setupUi(m_viewoptionsDialog); m_viewoptions->setupUi(m_viewoptionsDialog);
m_model = new UAVObjectTreeModel(this, m_model = createTreeModel();
m_viewoptions->cbCategorized->isChecked(),
m_viewoptions->cbMetaData->isChecked(),
m_viewoptions->cbScientific->isChecked());
m_modelProxy = new TreeSortFilterProxyModel(this); m_modelProxy = new TreeSortFilterProxyModel(this);
m_modelProxy->setSourceModel(m_model); m_modelProxy->setSourceModel(m_model);
@ -97,12 +95,12 @@ UAVObjectBrowserWidget::~UAVObjectBrowserWidget()
delete m_browser; 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->cbCategorized->setChecked(showCategories);
m_viewoptions->cbMetaData->setChecked(metadata); m_viewoptions->cbMetaData->setChecked(showMetadata);
m_viewoptions->cbScientific->setChecked(scientific); m_viewoptions->cbScientific->setChecked(useScientificNotation);
m_viewoptions->cbDescription->setChecked(description); m_viewoptions->cbDescription->setChecked(showDescription);
} }
void UAVObjectBrowserWidget::setSplitterState(QByteArray state) void UAVObjectBrowserWidget::setSplitterState(QByteArray state)
@ -156,7 +154,7 @@ ObjectTreeItem *UAVObjectBrowserWidget::findCurrentObjectTreeItem()
if (objItem) { if (objItem) {
break; break;
} }
item = item->parent(); item = item->parentItem();
} }
return objItem; return objItem;
} }
@ -186,7 +184,7 @@ void UAVObjectBrowserWidget::saveObject()
if (objItem != NULL) { if (objItem != NULL) {
UAVObject *obj = objItem->object(); UAVObject *obj = objItem->object();
Q_ASSERT(obj); Q_ASSERT(obj);
updateObjectPersistance(ObjectPersistence::OPERATION_SAVE, obj); updateObjectPersistence(ObjectPersistence::OPERATION_SAVE, obj);
} }
} }
@ -198,7 +196,7 @@ void UAVObjectBrowserWidget::loadObject()
if (objItem != NULL) { if (objItem != NULL) {
UAVObject *obj = objItem->object(); UAVObject *obj = objItem->object();
Q_ASSERT(obj); Q_ASSERT(obj);
updateObjectPersistance(ObjectPersistence::OPERATION_LOAD, obj); updateObjectPersistence(ObjectPersistence::OPERATION_LOAD, obj);
// Retrieve object so that latest value is displayed // Retrieve object so that latest value is displayed
requestUpdate(); requestUpdate();
} }
@ -211,13 +209,13 @@ void UAVObjectBrowserWidget::eraseObject()
if (objItem != NULL) { if (objItem != NULL) {
UAVObject *obj = objItem->object(); UAVObject *obj = objItem->object();
Q_ASSERT(obj); Q_ASSERT(obj);
updateObjectPersistance(ObjectPersistence::OPERATION_DELETE, obj); updateObjectPersistence(ObjectPersistence::OPERATION_DELETE, obj);
// Retrieve object so that correct default value is displayed // Retrieve object so that correct default value is displayed
requestUpdate(); requestUpdate();
} }
} }
void UAVObjectBrowserWidget::updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj) void UAVObjectBrowserWidget::updateObjectPersistence(ObjectPersistence::OperationOptions op, UAVObject *obj)
{ {
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
@ -238,11 +236,11 @@ void UAVObjectBrowserWidget::currentChanged(const QModelIndex &current, const QM
{ {
Q_UNUSED(previous); Q_UNUSED(previous);
TreeItem *item = static_cast<TreeItem *>(current.data(Qt::UserRole).value<void *>());
bool enable = true; bool enable = true;
if (!current.isValid()) { if (!current.isValid()) {
enable = false; enable = false;
} }
TreeItem *item = static_cast<TreeItem *>(current.data(Qt::UserRole).value<void *>());
TopTreeItem *top = dynamic_cast<TopTreeItem *>(item); TopTreeItem *top = dynamic_cast<TopTreeItem *>(item);
ObjectTreeItem *data = dynamic_cast<ObjectTreeItem *>(item); ObjectTreeItem *data = dynamic_cast<ObjectTreeItem *>(item);
if (top || (data && !data->object())) { 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 UAVObjectTreeModel *model = new UAVObjectTreeModel(this);
// a side effect of rebuilding is that some state is lost (expand state, ...)
UAVObjectTreeModel *model = new UAVObjectTreeModel(this, model->setShowCategories(m_viewoptions->cbCategorized->isChecked());
m_viewoptions->cbCategorized->isChecked(), model->setShowMetadata(m_viewoptions->cbMetaData->isChecked());
m_viewoptions->cbMetaData->isChecked(), model->setUseScientificNotation(m_viewoptions->cbScientific->isChecked());
m_viewoptions->cbScientific->isChecked());
model->setUnknowObjectColor(m_unknownObjectColor);
model->setRecentlyUpdatedColor(m_recentlyUpdatedColor); model->setRecentlyUpdatedColor(m_recentlyUpdatedColor);
model->setManuallyChangedColor(m_manuallyChangedColor); model->setManuallyChangedColor(m_manuallyChangedColor);
model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout); model->setRecentlyUpdatedTimeout(m_recentlyUpdatedTimeout);
model->setOnlyHilightChangedValues(m_onlyHilightChangedValues); model->setUnknownObjectColor(m_unknownObjectColor);
model->setOnlyHighlightChangedValues(m_onlyHighlightChangedValues);
UAVObjectTreeModel *tmpModel = m_model; return model;
m_model = model; }
m_modelProxy->setSourceModel(m_model);
delete tmpModel; void UAVObjectBrowserWidget::updateViewOptions()
{
bool showCategories = 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(showCategories);
m_model->setShowMetadata(showMetadata);
m_model->setUseScientificNotation(useScientificNotation);
// force an expand all if search text is not empty // force an expand all if search text is not empty
if (!m_browser->searchLine->text().isEmpty()) { if (!m_browser->searchLine->text().isEmpty()) {
@ -290,8 +296,7 @@ void UAVObjectBrowserWidget::updateViewOptions()
} }
// persist options // persist options
emit viewOptionsChanged(m_viewoptions->cbCategorized->isChecked(), m_viewoptions->cbScientific->isChecked(), emit viewOptionsChanged(showCategories, useScientificNotation, showMetadata, showDesc);
m_viewoptions->cbMetaData->isChecked(), m_viewoptions->cbDescription->isChecked());
} }
void UAVObjectBrowserWidget::splitterMoved() void UAVObjectBrowserWidget::splitterMoved()
@ -417,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() void UAVObjectBrowserWidget::searchTextCleared()
{ {
m_browser->searchLine->clear(); m_browser->searchLine->clear();

View File

@ -46,6 +46,12 @@ class TreeSortFilterProxyModel : public QSortFilterProxyModel {
public: public:
TreeSortFilterProxyModel(QObject *parent); TreeSortFilterProxyModel(QObject *parent);
public:
QModelIndexList getPersistentIndexList() const
{
return persistentIndexList();
}
protected: protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const; bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
bool filterAcceptsRowItself(int source_row, const QModelIndex &source_parent) const; bool filterAcceptsRowItself(int source_row, const QModelIndex &source_parent) const;
@ -62,7 +68,7 @@ public:
void setUnknownObjectColor(QColor color) void setUnknownObjectColor(QColor color)
{ {
m_unknownObjectColor = color; m_unknownObjectColor = color;
m_model->setUnknowObjectColor(color); m_model->setUnknownObjectColor(color);
} }
void setRecentlyUpdatedColor(QColor color) void setRecentlyUpdatedColor(QColor color)
{ {
@ -79,14 +85,20 @@ public:
m_recentlyUpdatedTimeout = timeout; m_recentlyUpdatedTimeout = timeout;
m_model->setRecentlyUpdatedTimeout(timeout); m_model->setRecentlyUpdatedTimeout(timeout);
} }
void setOnlyHilightChangedValues(bool hilight) void setOnlyHighlightChangedValues(bool highlight)
{ {
m_onlyHilightChangedValues = hilight; m_onlyHighlightChangedValues = highlight;
m_model->setOnlyHilightChangedValues(hilight); m_model->setOnlyHighlightChangedValues(highlight);
} }
void setViewOptions(bool categorized, bool scientific, bool metadata, bool description); void setViewOptions(bool showCategories, bool showMetadata, bool useScientificNotation, bool showDescription);
void setSplitterState(QByteArray state); 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: public slots:
void showDescription(bool show); void showDescription(bool show);
@ -119,10 +131,12 @@ private:
QColor m_unknownObjectColor; QColor m_unknownObjectColor;
QColor m_recentlyUpdatedColor; QColor m_recentlyUpdatedColor;
QColor m_manuallyChangedColor; QColor m_manuallyChangedColor;
bool m_onlyHilightChangedValues; bool m_onlyHighlightChangedValues;
QString m_mustacheTemplate; QString m_mustacheTemplate;
void updateObjectPersistance(ObjectPersistence::OperationOptions op, UAVObject *obj); UAVObjectTreeModel *createTreeModel();
void updateObjectPersistence(ObjectPersistence::OperationOptions op, UAVObject *obj);
void enableSendRequest(bool enable); void enableSendRequest(bool enable);
void updateDescription(); void updateDescription();
ObjectTreeItem *findCurrentObjectTreeItem(); ObjectTreeItem *findCurrentObjectTreeItem();

View File

@ -26,169 +26,226 @@
*/ */
#include "uavobjecttreemodel.h" #include "uavobjecttreemodel.h"
#include "fieldtreeitem.h" #include "fieldtreeitem.h"
#include "uavobjectmanager.h" #include "uavobjectmanager.h"
#include "uavdataobject.h" #include "uavdataobject.h"
#include "uavmetaobject.h" #include "uavmetaobject.h"
#include "uavobjectfield.h" #include "uavobjectfield.h"
#include "extensionsystem/pluginmanager.h" #include "extensionsystem/pluginmanager.h"
#include <QColor> #include <QColor>
#include <QtCore/QTimer>
#include <QtCore/QSignalMapper>
#include <QtCore/QDebug>
UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent, bool categorize, bool showMetadata, bool useScientificNotation) : UAVObjectTreeModel::UAVObjectTreeModel(QObject *parent) : QAbstractItemModel(parent)
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))
{ {
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); m_highlightManager = new HighlightManager();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>(); connect(m_highlightManager, &HighlightManager::updateHighlight, this, &UAVObjectTreeModel::refreshHighlight);
Q_ASSERT(objManager); TreeItem::setHighlightTime(recentlyUpdatedTimeout());
// Create highlight manager, let it run every 300 ms. setupModelData();
m_highlightManager = new HighLightManager(300);
connect(objManager, SIGNAL(newObject(UAVObject *)), this, SLOT(newObject(UAVObject *)));
connect(objManager, SIGNAL(newInstance(UAVObject *)), this, SLOT(newObject(UAVObject *)));
TreeItem::setHighlightTime(m_recentlyUpdatedTimeout);
setupModelData(objManager);
} }
UAVObjectTreeModel::~UAVObjectTreeModel() UAVObjectTreeModel::~UAVObjectTreeModel()
{ {
delete m_highlightManager;
delete m_rootItem; delete m_rootItem;
delete m_highlightManager;
} }
void UAVObjectTreeModel::setupModelData(UAVObjectManager *objManager) bool UAVObjectTreeModel::showCategories() const
{ {
m_settingsTree = new TopTreeItem(tr("Settings")); return m_settings.value("showCategories", false).toBool();
m_settingsTree->setHighlightManager(m_highlightManager); }
connect(m_settingsTree, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *)));
m_nonSettingsTree = new TopTreeItem(tr("Data Objects")); void UAVObjectTreeModel::setShowCategories(bool show)
m_nonSettingsTree->setHighlightManager(m_highlightManager); {
connect(m_nonSettingsTree, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); if (show == showCategories()) {
return;
}
m_settings.setValue("showCategories", show);
toggleCategoryItems();
}
// root bool UAVObjectTreeModel::showMetadata() const
{
return m_settings.value("showMetadata", false).toBool();
}
void UAVObjectTreeModel::setShowMetadata(bool show)
{
if (show == showMetadata()) {
return;
}
m_settings.setValue("showMetadata", show);
toggleMetaItems();
}
bool UAVObjectTreeModel::useScientificNotation()
{
return m_settings.value("useScientificNotation", false).toBool();
}
void UAVObjectTreeModel::setUseScientificNotation(bool useScientificNotation)
{
m_settings.setValue("useScientificNotation", useScientificNotation);
}
QColor UAVObjectTreeModel::unknownObjectColor() const
{
return m_settings.value("unknownObjectColor", QColor(Qt::gray)).value<QColor>();
}
void UAVObjectTreeModel::setUnknownObjectColor(QColor color)
{
m_settings.setValue("unknownObjectColor", color);
}
QColor UAVObjectTreeModel::recentlyUpdatedColor() const
{
return m_settings.value("recentlyUpdatedColor", QColor(255, 230, 230)).value<QColor>();
}
void UAVObjectTreeModel::setRecentlyUpdatedColor(QColor color)
{
m_settings.setValue("recentlyUpdatedColor", color);
}
QColor UAVObjectTreeModel::manuallyChangedColor() const
{
return m_settings.value("manuallyChangedColor", QColor(230, 230, 255)).value<QColor>();
}
void UAVObjectTreeModel::setManuallyChangedColor(QColor color)
{
m_settings.setValue("manuallyChangedColor", color);
}
int UAVObjectTreeModel::recentlyUpdatedTimeout() const
{
return m_settings.value("recentlyUpdatedTimeout", 300).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);
}
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<QVariant> rootData; QList<QVariant> rootData;
rootData << tr("Property") << tr("Value") << tr("Unit"); rootData << tr("Property") << tr("Value") << tr("Unit");
m_rootItem = new TreeItem(rootData); m_rootItem = new TreeItem(rootData);
m_rootItem->setHighlightManager(m_highlightManager); m_rootItem->setHighlightManager(m_highlightManager);
// tree item takes ownership of its children m_settingsTree = new TopTreeItem(tr("Settings"));
m_rootItem->appendChild(m_settingsTree); m_settingsTree->setHighlightManager(m_highlightManager);
m_rootItem->appendChild(m_nonSettingsTree);
m_nonSettingsTree = new TopTreeItem(tr("Data Objects"));
m_nonSettingsTree->setHighlightManager(m_highlightManager);
// 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<UAVObjectManager>();
Q_ASSERT(objManager);
connect(objManager, &UAVObjectManager::newObject, this, &UAVObjectTreeModel::newObject, Qt::UniqueConnection);
connect(objManager, &UAVObjectManager::newInstance, this, &UAVObjectTreeModel::newObject, Qt::UniqueConnection);
QList< QList<UAVDataObject *> > objList = objManager->getDataObjects(); QList< QList<UAVDataObject *> > objList = objManager->getDataObjects();
foreach(QList<UAVDataObject *> list, objList) { foreach(QList<UAVDataObject *> list, objList) {
foreach(UAVDataObject * obj, list) { foreach(UAVDataObject * obj, list) {
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) void UAVObjectTreeModel::newObject(UAVObject *obj)
{ {
UAVDataObject *dobj = qobject_cast<UAVDataObject *>(obj); UAVDataObject *dataObj = qobject_cast<UAVDataObject *>(obj);
if (dobj) { if (dataObj) {
addDataObject(dobj); addObject(dataObj);
} }
} }
void UAVObjectTreeModel::addDataObject(UAVDataObject *obj) void UAVObjectTreeModel::addObject(UAVDataObject *obj)
{ {
TopTreeItem *root = obj->isSettingsObject() ? m_settingsTree : m_nonSettingsTree; connect(obj, &UAVDataObject::objectUpdated, this, &UAVObjectTreeModel::updateObject, Qt::UniqueConnection);
connect(obj, &UAVDataObject::isKnownChanged, this, &UAVObjectTreeModel::updateIsKnown, Qt::UniqueConnection);
TreeItem *parent = root; if (obj->getInstID() == 0) {
UAVMetaObject *metaObj = obj->getMetaObject();
if (m_categorize && obj->getCategory() != 0 && !obj->getCategory().isEmpty()) { connect(metaObj, &UAVDataObject::objectUpdated, this, &UAVObjectTreeModel::updateObject, Qt::UniqueConnection);
QStringList categoryPath = obj->getCategory().split('/');
parent = createCategoryItems(categoryPath, root);
} }
ObjectTreeItem *existing = root->findDataObjectTreeItemByObjectId(obj->getObjID());
if (existing) {
addInstance(obj, existing);
} else {
DataObjectTreeItem *dataTreeItem = new DataObjectTreeItem(obj->getName(), obj);
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) {
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);
connect(categoryItem, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *)));
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(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) {
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(highlightUpdatedObject(UAVObject *)));
connect(obj, SIGNAL(isKnownChanged(UAVObject *, bool)), this, SLOT(isKnownChanged(UAVObject *, bool)));
TreeItem *item;
if (obj->isSingleInstance()) { if (obj->isSingleInstance()) {
item = parent; DataObjectTreeItem *dataObjectItem = createDataObject(obj);
DataObjectTreeItem *objectItem = static_cast<DataObjectTreeItem *>(parent); TreeItem *parentItem = getParentItem(obj, showCategories());
connect(objectItem, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); insertItem(parentItem, dataObjectItem);
} else { } else {
QString name = tr("Instance") + " " + QString::number(obj->getInstID()); TreeItem *dataObjectItem;
item = new InstanceTreeItem(obj, name); if (obj->getInstID() == 0) {
item->setHighlightManager(m_highlightManager); dataObjectItem = createDataObject(obj);
connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); TreeItem *parentItem = getParentItem(obj, showCategories());
connect(item, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); insertItem(parentItem, dataObjectItem);
parent->appendChild(item); } 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);
// metadata items are created up front and are added/removed as needed
// see toggleMetaItems()
MetaObjectTreeItem *metaItem = createMetaObject(obj->getMetaObject());
if (showMetadata()) {
appendItem(item, metaItem);
}
if (obj->isSingleInstance()) {
foreach(UAVObjectField * field, obj->getFields()) { foreach(UAVObjectField * field, obj->getFields()) {
if (field->getNumElements() > 1) { if (field->getNumElements() > 1) {
addArrayField(field, item); addArrayField(field, item);
@ -196,6 +253,71 @@ void UAVObjectTreeModel::addInstance(UAVObject *obj, TreeItem *parent)
addSingleField(0, field, item); addSingleField(0, field, item);
} }
} }
}
return item;
}
InstanceTreeItem *UAVObjectTreeModel::createDataObjectInstance(UAVDataObject *obj)
{
QString name = obj->getName() + " " + 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);
} else {
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) {
// metadata items are created and destroyed as needed
// see toggleCategoryItems()
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) void UAVObjectTreeModel::addArrayField(UAVObjectField *field, TreeItem *parent)
@ -203,21 +325,21 @@ void UAVObjectTreeModel::addArrayField(UAVObjectField *field, TreeItem *parent)
TreeItem *item = new ArrayFieldTreeItem(field, field->getName()); TreeItem *item = new ArrayFieldTreeItem(field, field->getName());
item->setHighlightManager(m_highlightManager); item->setHighlightManager(m_highlightManager);
connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *)));
connect(item, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); appendItem(parent, item);
for (uint i = 0; i < field->getNumElements(); ++i) {
for (int i = 0; i < (int)field->getNumElements(); ++i) {
addSingleField(i, field, item); addSingleField(i, field, item);
} }
parent->appendChild(item);
} }
void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeItem *parent) void UAVObjectTreeModel::addSingleField(int i, UAVObjectField *field, TreeItem *parent)
{ {
QList<QVariant> data; QList<QVariant> data;
if (field->getNumElements() == 1) { if (field->getNumElements() == 1) {
data.append(field->getName()); data.append(field->getName());
} else { } else {
data.append(QString("[%1]").arg((field->getElementNames())[index])); data.append(QString("[%1]").arg((field->getElementNames())[i]));
} }
FieldTreeItem *item = NULL; FieldTreeItem *item = NULL;
@ -227,10 +349,10 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt
case UAVObjectField::ENUM: case UAVObjectField::ENUM:
{ {
QStringList options = field->getOptions(); QStringList options = field->getOptions();
QVariant value = field->getValue(index); QVariant value = field->getValue(i);
data.append(options.indexOf(value.toString())); data.append(options.indexOf(value.toString()));
data.append(field->getUnits()); data.append(field->getUnits());
item = new EnumFieldTreeItem(field, index, data); item = new EnumFieldTreeItem(field, i, data);
break; break;
} }
case UAVObjectField::INT8: case UAVObjectField::INT8:
@ -239,29 +361,113 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt
case UAVObjectField::UINT8: case UAVObjectField::UINT8:
case UAVObjectField::UINT16: case UAVObjectField::UINT16:
case UAVObjectField::UINT32: case UAVObjectField::UINT32:
data.append(field->getValue(index)); data.append(field->getValue(i));
data.append(field->getUnits()); data.append(field->getUnits());
if (field->getUnits().toLower() == "hex") { if (field->getUnits().toLower() == "hex") {
item = new HexFieldTreeItem(field, index, data); item = new HexFieldTreeItem(field, i, data);
} else if (field->getUnits().toLower() == "char") { } else if (field->getUnits().toLower() == "char") {
item = new CharFieldTreeItem(field, index, data); item = new CharFieldTreeItem(field, i, data);
} else { } else {
item = new IntFieldTreeItem(field, index, data); item = new IntFieldTreeItem(field, i, data);
} }
break; break;
case UAVObjectField::FLOAT32: case UAVObjectField::FLOAT32:
data.append(field->getValue(index)); data.append(field->getValue(i));
data.append(field->getUnits()); data.append(field->getUnits());
item = new FloatFieldTreeItem(field, index, data, m_useScientificFloatNotation); item = new FloatFieldTreeItem(field, i, data, m_settings);
break; break;
default: default:
Q_ASSERT(false); Q_ASSERT(false);
} }
item->setHighlightManager(m_highlightManager); item->setHighlightManager(m_highlightManager);
item->setDescription(field->getDescription()); item->setDescription(field->getDescription());
connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *)));
connect(item, SIGNAL(updateIsKnown(TreeItem *)), this, SLOT(updateIsKnown(TreeItem *))); appendItem(parent, item);
parent->appendChild(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<DataObjectTreeItem *>(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<MetaObjectTreeItem *>(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 QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &parent) const
@ -271,38 +477,26 @@ QModelIndex UAVObjectTreeModel::index(int row, int column, const QModelIndex &pa
} }
TreeItem *parentItem; TreeItem *parentItem;
if (!parent.isValid()) { if (!parent.isValid()) {
parentItem = m_rootItem; parentItem = m_rootItem;
} else { } else {
parentItem = static_cast<TreeItem *>(parent.internalPointer()); parentItem = static_cast<TreeItem *>(parent.internalPointer());
} }
TreeItem *childItem = parentItem->getChild(row); TreeItem *childItem = parentItem->child(row);
if (childItem) { if (childItem) {
return createIndex(row, column, childItem); return createIndex(row, column, childItem);
} else {
return QModelIndex();
} }
return QModelIndex();
} }
QModelIndex UAVObjectTreeModel::index(TreeItem *item) QModelIndex UAVObjectTreeModel::index(TreeItem *item, int column) const
{ {
if (item->parent() == 0) { if (item == m_rootItem) {
return QModelIndex(); return QModelIndex();
} }
QModelIndex root = index(item->parent()); return createIndex(item->row(), column, item);
for (int i = 0; i < rowCount(root); ++i) {
QModelIndex childIndex = index(i, 0, root);
TreeItem *child = static_cast<TreeItem *>(childIndex.internalPointer());
if (child == item) {
return childIndex;
}
}
Q_ASSERT(false);
return QModelIndex();
} }
QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const
@ -311,11 +505,14 @@ QModelIndex UAVObjectTreeModel::parent(const QModelIndex &index) const
return QModelIndex(); return QModelIndex();
} }
TreeItem *item = static_cast<TreeItem *>(index.internalPointer()); TreeItem *childItem = static_cast<TreeItem *>(index.internalPointer());
TreeItem *parentItem = childItem->parentItem();
TreeItem *parentItem = item->parent();
if (!parentItem) { if (!parentItem) {
// item is root has no parent... return QModelIndex();
}
if (parentItem == m_rootItem) {
return QModelIndex(); return QModelIndex();
} }
@ -341,24 +538,15 @@ int UAVObjectTreeModel::rowCount(const QModelIndex &parent) const
int UAVObjectTreeModel::columnCount(const QModelIndex &parent) const int UAVObjectTreeModel::columnCount(const QModelIndex &parent) const
{ {
TreeItem *parentItem;
if (parent.isValid()) { if (parent.isValid()) {
return static_cast<TreeItem *>(parent.internalPointer())->columnCount(); parentItem = static_cast<TreeItem *>(parent.internalPointer());
} else { } else {
return m_rootItem->columnCount(); parentItem = m_rootItem;
}
}
QList<QModelIndex> UAVObjectTreeModel::getMetaDataIndexes()
{
QList<QModelIndex> metaIndexes;
foreach(MetaObjectTreeItem * metaItem, m_settingsTree->getMetaObjectItems()) {
metaIndexes.append(index(metaItem));
} }
foreach(MetaObjectTreeItem * metaItem, m_nonSettingsTree->getMetaObjectItems()) { return parentItem->columnCount();
metaIndexes.append(index(metaItem));
}
return metaIndexes;
} }
QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const
@ -391,22 +579,26 @@ QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const
case Qt::ForegroundRole: case Qt::ForegroundRole:
if (!dynamic_cast<TopTreeItem *>(item) && !item->isKnown()) { if (!dynamic_cast<TopTreeItem *>(item) && !item->isKnown()) {
return m_unknownObjectColor; return unknownObjectColor();
} }
return QVariant(); return QVariant();
case Qt::BackgroundRole: case Qt::BackgroundRole:
if (index.column() == TreeItem::TITLE_COLUMN) { if (index.column() == TreeItem::TITLE_COLUMN) {
if (!dynamic_cast<TopTreeItem *>(item) && item->highlighted()) { // TODO filtering here on highlightTopTreeItems() should not be necessary
return m_recentlyUpdatedColor; // top tree items should not be highlighted at all in the first place
// when highlightTopTreeItems() is false
bool highlight = (highlightTopTreeItems() || !dynamic_cast<TopTreeItem *>(item));
if (highlight && item->isHighlighted()) {
return recentlyUpdatedColor();
} }
} else if (index.column() == TreeItem::DATA_COLUMN) { } else if (index.column() == TreeItem::DATA_COLUMN) {
FieldTreeItem *fieldItem = dynamic_cast<FieldTreeItem *>(item); FieldTreeItem *fieldItem = dynamic_cast<FieldTreeItem *>(item);
if (fieldItem && fieldItem->highlighted()) { if (fieldItem && fieldItem->isHighlighted()) {
return m_recentlyUpdatedColor; return recentlyUpdatedColor();
} }
if (fieldItem && fieldItem->changed()) { if (fieldItem && fieldItem->changed()) {
return m_manuallyChangedColor; return manuallyChangedColor();
} }
} }
return QVariant(); return QVariant();
@ -423,13 +615,12 @@ QVariant UAVObjectTreeModel::data(const QModelIndex &index, int role) const
bool UAVObjectTreeModel::setData(const QModelIndex &index, const QVariant & value, int role) bool UAVObjectTreeModel::setData(const QModelIndex &index, const QVariant & value, int role)
{ {
Q_UNUSED(role) Q_UNUSED(role);
TreeItem * item = static_cast<TreeItem *>(index.internalPointer()); TreeItem *item = static_cast<TreeItem *>(index.internalPointer());
item->setData(value, index.column()); item->setData(value, index.column());
return true; return true;
} }
Qt::ItemFlags UAVObjectTreeModel::flags(const QModelIndex &index) const Qt::ItemFlags UAVObjectTreeModel::flags(const QModelIndex &index) const
{ {
if (!index.isValid()) { if (!index.isValid()) {
@ -452,77 +643,83 @@ QVariant UAVObjectTreeModel::headerData(int section, Qt::Orientation orientation
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
return m_rootItem->data(section); return m_rootItem->data(section);
} }
return QVariant(); return QVariant();
} }
void UAVObjectTreeModel::highlightUpdatedObject(UAVObject *obj) void UAVObjectTreeModel::updateObject(UAVObject *obj)
{ {
Q_ASSERT(obj); Q_ASSERT(obj);
ObjectTreeItem *item = findObjectTreeItem(obj); ObjectTreeItem *item = findObjectTreeItem(obj->getObjID());
Q_ASSERT(item); Q_ASSERT(item);
if (!m_onlyHilightChangedValues) { // TODO don't update meta object if they are not shown
item->setHighlight(true); QTime ts = QTime::currentTime();
item->update(ts);
if (!onlyHighlightChangedValues()) {
item->setHighlighted(true, ts);
} }
item->update(); }
if (!m_onlyHilightChangedValues) {
QModelIndex itemIndex = index(item); void UAVObjectTreeModel::updateIsKnown(UAVObject *object)
{
DataObjectTreeItem *item = findDataObjectTreeItem(object);
if (item) {
refreshIsKnown(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 caused by the sort/filter proxy...
QModelIndex itemIndex;
itemIndex = index(item, TreeItem::TITLE_COLUMN);
Q_ASSERT(itemIndex != QModelIndex()); Q_ASSERT(itemIndex != QModelIndex());
emit dataChanged(itemIndex, itemIndex); emit dataChanged(itemIndex, itemIndex);
itemIndex = index(item, TreeItem::DATA_COLUMN);
Q_ASSERT(itemIndex != QModelIndex());
emit dataChanged(itemIndex, itemIndex);
}
void UAVObjectTreeModel::refreshIsKnown(TreeItem *item)
{
QModelIndex itemIndex;
itemIndex = index(item, TreeItem::TITLE_COLUMN);
Q_ASSERT(itemIndex != QModelIndex());
emit dataChanged(itemIndex, itemIndex);
foreach(TreeItem * child, item->children()) {
refreshIsKnown(child);
} }
} }
ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(UAVObject *object) void UAVObjectTreeModel::addObjectTreeItem(quint32 objectId, ObjectTreeItem *oti)
{ {
UAVDataObject *dataObject = qobject_cast<UAVDataObject *>(object); 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<UAVMetaObject *>(object); UAVMetaObject *metaObject = qobject_cast<UAVMetaObject *>(object);
Q_ASSERT(dataObject || metaObject); if (metaObject) {
if (dataObject) { dataObject = qobject_cast<UAVDataObject *>(metaObject->getParentObject());
return findDataObjectTreeItem(dataObject);
} else { } else {
return findMetaObjectTreeItem(metaObject); dataObject = qobject_cast<UAVDataObject *>(object);
} }
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<UAVDataObject *>(obj->getParentObject());
Q_ASSERT(dataObject); Q_ASSERT(dataObject);
TopTreeItem *root = dataObject->isSettingsObject() ? m_settingsTree : m_nonSettingsTree; return static_cast<DataObjectTreeItem *>(findObjectTreeItem(dataObject->getObjID()));
return root->findMetaObjectTreeItemByObjectId(obj->getObjID());
}
void UAVObjectTreeModel::updateHighlight(TreeItem *item)
{
QModelIndex itemIndex = index(item);
Q_ASSERT(itemIndex != QModelIndex());
emit dataChanged(itemIndex, itemIndex.sibling(itemIndex.row(), TreeItem::DATA_COLUMN));
}
void UAVObjectTreeModel::updateIsKnown(TreeItem *item)
{
QModelIndex itemIndex = index(item);
Q_ASSERT(itemIndex != QModelIndex());
emit dataChanged(itemIndex, itemIndex.sibling(itemIndex.row(), TreeItem::TITLE_COLUMN));
}
void UAVObjectTreeModel::isKnownChanged(UAVObject *object, bool isKnown)
{
Q_UNUSED(isKnown);
ObjectTreeItem *item = findObjectTreeItem(object);
if (item) {
item->updateIsKnown(isKnown);
}
} }

View File

@ -29,10 +29,12 @@
#define UAVOBJECTTREEMODEL_H #define UAVOBJECTTREEMODEL_H
#include "treeitem.h" #include "treeitem.h"
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QtCore/QMap> #include <QMap>
#include <QtCore/QList> #include <QList>
#include <QColor> #include <QColor>
#include <QSettings>
class TopTreeItem; class TopTreeItem;
class ObjectTreeItem; class ObjectTreeItem;
@ -48,8 +50,7 @@ class QTimer;
class UAVObjectTreeModel : public QAbstractItemModel { class UAVObjectTreeModel : public QAbstractItemModel {
Q_OBJECT Q_OBJECT
public: public:
explicit UAVObjectTreeModel(QObject *parent, bool categorize, bool showMetadata, bool useScientificNotation); explicit UAVObjectTreeModel(QObject *parent);
explicit UAVObjectTreeModel(bool categorize, bool showMetadata, bool useScientificNotation);
~UAVObjectTreeModel(); ~UAVObjectTreeModel();
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role) const;
@ -63,71 +64,77 @@ public:
int rowCount(const QModelIndex &parent = QModelIndex()) const; int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const; int columnCount(const QModelIndex &parent = QModelIndex()) const;
void setUnknowObjectColor(QColor color) bool showCategories() const;
{ void setShowCategories(bool show);
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 setOnlyHilightChangedValues(bool hilight)
{
m_onlyHilightChangedValues = hilight;
}
QList<QModelIndex> getMetaDataIndexes(); bool showMetadata() const;
void setShowMetadata(bool show);
signals: bool useScientificNotation();
void setUseScientificNotation(bool useScientificNotation);
public slots: QColor unknownObjectColor() const;
void newObject(UAVObject *obj); void setUnknownObjectColor(QColor color);
QColor recentlyUpdatedColor() const;
void setRecentlyUpdatedColor(QColor color);
QColor manuallyChangedColor() const;
void setManuallyChangedColor(QColor color);
int recentlyUpdatedTimeout() const;
void setRecentlyUpdatedTimeout(int timeout);
bool onlyHighlightChangedValues() const;
void setOnlyHighlightChangedValues(bool highlight);
bool highlightTopTreeItems() const;
void setHighlightTopTreeItems(bool highlight);
private slots: private slots:
void updateHighlight(TreeItem *item); void newObject(UAVObject *obj);
void updateIsKnown(TreeItem *item); void updateObject(UAVObject *obj);
void highlightUpdatedObject(UAVObject *obj); void updateIsKnown(UAVObject *obj);
void isKnownChanged(UAVObject *object, bool isKnown); void refreshHighlight(TreeItem *item);
void refreshIsKnown(TreeItem *item);
private: private:
void setupModelData(UAVObjectManager *objManager); QSettings m_settings;
QModelIndex index(TreeItem *item);
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);
TreeItem *createCategoryItems(QStringList categoryPath, TreeItem *root); HighlightManager *m_highlightManager;
QString updateMode(quint8 updateMode);
ObjectTreeItem *findObjectTreeItem(UAVObject *obj);
DataObjectTreeItem *findDataObjectTreeItem(UAVDataObject *obj);
MetaObjectTreeItem *findMetaObjectTreeItem(UAVMetaObject *obj);
TreeItem *m_rootItem; TreeItem *m_rootItem;
TopTreeItem *m_settingsTree; TopTreeItem *m_settingsTree;
TopTreeItem *m_nonSettingsTree; 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_onlyHilightChangedValues;
// Highlight manager to handle highlighting of tree items. QHash<quint32, ObjectTreeItem *> m_objectTreeItems;
HighLightManager *m_highlightManager;
QModelIndex index(TreeItem *item, int column = 0) const;
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 #endif // UAVOBJECTTREEMODEL_H

View File

@ -622,7 +622,7 @@ void UAVObject::setIsKnown(bool isKnown)
unlock(); unlock();
if (changed) { if (changed) {
emit isKnownChanged(this, isKnown); emit isKnownChanged(this);
} }
} }

View File

@ -181,7 +181,7 @@ signals:
void updateRequested(UAVObject *obj, bool all = false); void updateRequested(UAVObject *obj, bool all = false);
void transactionCompleted(UAVObject *obj, bool success); void transactionCompleted(UAVObject *obj, bool success);
void newInstance(UAVObject *obj); void newInstance(UAVObject *obj);
void isKnownChanged(UAVObject *obj, bool isKnown); void isKnownChanged(UAVObject *obj);
protected: protected:
quint32 objID; quint32 objID;

View File

@ -79,7 +79,7 @@ Telemetry::~Telemetry()
closeAllTransactions(); closeAllTransactions();
foreach(QList<UAVObject *> instances, objMngr->getObjects()) { foreach(QList<UAVObject *> instances, objMngr->getObjects()) {
foreach(UAVObject * object, instances) { foreach(UAVObject * object, instances) {
// make sure we 'forget' all objects before we request it from the flight side // 'forget' all objects
object->setIsKnown(false); object->setIsKnown(false);
} }
} }
@ -244,9 +244,8 @@ void Telemetry::transactionCompleted(UAVObject *obj, bool success)
if (transInfo) { if (transInfo) {
if (success) { 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); obj->setIsKnown(true);
#ifdef VERBOSE_TELEMETRY #ifdef VERBOSE_TELEMETRY
qDebug() << "Telemetry - transaction successful for object" << obj->toStringBrief(); qDebug() << "Telemetry - transaction successful for object" << obj->toStringBrief();
#endif #endif

View File

@ -365,7 +365,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
{ {
UAVObject *rxObj = objMngr->getObject(rxObjId); UAVObject *rxObj = objMngr->getObject(rxObjId);
if (rxObj == NULL && rxType != TYPE_OBJ_REQ) { 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++; stats.rxErrors++;
rxState = STATE_ERROR; rxState = STATE_ERROR;
break; break;
@ -385,7 +385,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
// Check length and determine next state // Check length and determine next state
if (rxLength >= MAX_PAYLOAD_LENGTH) { if (rxLength >= MAX_PAYLOAD_LENGTH) {
// packet error - exceeded payload max 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++; stats.rxErrors++;
rxState = STATE_ERROR; rxState = STATE_ERROR;
break; break;
@ -394,7 +394,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
// Check the lengths match // Check the lengths match
if ((rxPacketLength + rxLength) != packetSize) { if ((rxPacketLength + rxLength) != packetSize) {
// packet error - mismatched packet size // 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++; stats.rxErrors++;
rxState = STATE_ERROR; rxState = STATE_ERROR;
break; break;
@ -430,7 +430,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
if (rxCS != rxCSPacket) { if (rxCS != rxCSPacket) {
// packet error - faulty CRC // 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++; stats.rxCrcErrors++;
rxState = STATE_ERROR; rxState = STATE_ERROR;
break; break;
@ -438,7 +438,7 @@ bool UAVTalk::processInputByte(quint8 rxbyte)
if (rxPacketLength != packetSize + CHECKSUM_LENGTH) { if (rxPacketLength != packetSize + CHECKSUM_LENGTH) {
// packet error - mismatched packet size // 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++; stats.rxErrors++;
rxState = STATE_ERROR; rxState = STATE_ERROR;
break; break;

View File

@ -2780,7 +2780,7 @@
<manuallyChangedColor>#5baa56</manuallyChangedColor> <manuallyChangedColor>#5baa56</manuallyChangedColor>
<onlyHilightChangedValues>false</onlyHilightChangedValues> <onlyHilightChangedValues>false</onlyHilightChangedValues>
<recentlyUpdatedColor>#ff7957</recentlyUpdatedColor> <recentlyUpdatedColor>#ff7957</recentlyUpdatedColor>
<recentlyUpdatedTimeout>500</recentlyUpdatedTimeout> <recentlyUpdatedTimeout>300</recentlyUpdatedTimeout>
<showMetaData>false</showMetaData> <showMetaData>false</showMetaData>
</data> </data>
</default> </default>