1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-29 14:52:12 +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) :
QStyledItemDelegate(parent)
{}
{
_sizeHint = QSpinBox().sizeHint();
}
QWidget *BrowserItemDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem & option,
@ -75,5 +77,5 @@ QSize BrowserItemDelegate::sizeHint(const QStyleOptionViewItem & option, const Q
{
Q_UNUSED(option);
Q_UNUSED(index);
return QSpinBox().sizeHint();
return _sizeHint;
}

View File

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

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

View File

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

View File

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

View File

@ -50,11 +50,22 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration *config)
m_widget->setRecentlyUpdatedColor(m->recentlyUpdatedColor());
m_widget->setManuallyChangedColor(m->manuallyChangedColor());
m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout());
m_widget->setOnlyHilightChangedValues(m->onlyHighlightChangedValues());
m_widget->setViewOptions(m->categorizedView(), m->scientificView(), m->showMetaData(), m->showDescription());
m_widget->setOnlyHighlightChangedValues(m->onlyHighlightChangedValues());
m_widget->setViewOptions(m->categorizedView(), m->showMetaData(), m->scientificView(), m->showDescription());
m_widget->setSplitterState(m->splitterState());
}
void UAVObjectBrowser::saveState(QSettings &settings) const
{
m_widget->saveState(settings);
}
void UAVObjectBrowser::restoreState(QSettings &settings)
{
m_widget->restoreState(settings);
}
void UAVObjectBrowser::viewOptionsChangedSlot(bool categorized, bool scientific, bool metadata, bool description)
{
if (m_config) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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