/** ****************************************************************************** * * @file pathactioneditortreemodel.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 "pathactioneditortreemodel.h" #include "pathactioneditorgadget.h" #include "fieldtreeitem.h" #include "uavobjectmanager.h" #include "uavdataobject.h" #include "uavmetaobject.h" #include "uavobjectfield.h" #include "extensionsystem/pluginmanager.h" #include // #include #include #include #include #include "waypoint.h" #include "waypointactive.h" #include "pathaction.h" PathActionEditorTreeModel::PathActionEditorTreeModel(QObject *parent) : QAbstractItemModel(parent), m_recentlyUpdatedColor(QColor(255, 230, 230)), m_manuallyChangedColor(QColor(230, 230, 255)) { ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); m_objManager = pm->getObject(); connect(m_objManager, SIGNAL(newInstance(UAVObject *)), this, SLOT(newInstance(UAVObject *))); connect(m_objManager->getObject("WaypointActive"), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(objUpdated(UAVObject *))); connect(m_objManager->getObject("PathAction"), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(objUpdated(UAVObject *))); connect(m_objManager->getObject("Waypoint"), SIGNAL(objectUpdated(UAVObject *)), this, SLOT(objUpdated(UAVObject *))); setupModelData(); } PathActionEditorTreeModel::~PathActionEditorTreeModel() { delete m_rootItem; } void PathActionEditorTreeModel::setupModelData() { m_actions = new QStringList(); updateActions(); // root QList rootData; rootData << tr("Property") << tr("Value") << tr("Unit"); m_rootItem = new TreeItem(rootData); m_pathactionsTree = new TopTreeItem(tr("PathActions"), m_rootItem); m_rootItem->appendChild(m_pathactionsTree); m_waypointsTree = new TopTreeItem(tr("Waypoints"), m_rootItem); m_rootItem->appendChild(m_waypointsTree); connect(m_rootItem, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); connect(m_pathactionsTree, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); connect(m_waypointsTree, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); { QList list = m_objManager->getObjectInstances("PathAction"); foreach(UAVObject * obj, list) { addInstance(obj, m_pathactionsTree); } } { QList list = m_objManager->getObjectInstances("Waypoint"); foreach(UAVObject * obj, list) { addInstance(obj, m_waypointsTree); } } } void PathActionEditorTreeModel::updateActions() { m_actions->clear(); QList list = m_objManager->getObjectInstances("PathAction"); foreach(UAVObject * obj, list) { QString title; title.append((QVariant(obj->getInstID()).toString())); title.append(" "); title.append((obj->getField("Mode")->getValue().toString())); title.append(" "); title.append((obj->getField("Command")->getValue().toString())); title.append(":"); title.append((obj->getField("EndCondition")->getValue().toString())); title.append(" "); m_actions->append(title); } } void PathActionEditorTreeModel::addInstance(UAVObject *obj, TreeItem *parent) { connect(obj, SIGNAL(objectUpdated(UAVObject *)), this, SLOT(highlightUpdatedObject(UAVObject *))); TreeItem *item; QString name = QString::number(obj->getInstID()); item = new InstanceTreeItem(obj, name); connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); parent->appendChild(item); foreach(UAVObjectField * field, obj->getFields()) { if (field->getNumElements() > 1) { addArrayField(field, item); } else { addSingleField(0, field, item); } } } void PathActionEditorTreeModel::addArrayField(UAVObjectField *field, TreeItem *parent) { TreeItem *item = new ArrayFieldTreeItem(field->getName()); connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); for (uint i = 0; i < field->getNumElements(); ++i) { addSingleField(i, field, item); } parent->appendChild(item); } void PathActionEditorTreeModel::addSingleField(int index, UAVObjectField *field, TreeItem *parent) { QList data; if (field->getNumElements() == 1) { data.append(field->getName()); } else { data.append(QString("[%1]").arg((field->getElementNames())[index])); } FieldTreeItem *item = NULL; UAVObjectField::FieldType type = field->getType(); // hack: list available actions in an enum if (field->getName().compare("Action") == 0 && type == UAVObjectField::UINT8) { data.append(field->getValue(index).toInt()); data.append(field->getUnits()); item = new ActionFieldTreeItem(field, index, data, m_actions); } else { switch (type) { case UAVObjectField::ENUM: { QStringList options = field->getOptions(); QVariant value = field->getValue(); data.append(options.indexOf(value.toString())); data.append(field->getUnits()); item = new EnumFieldTreeItem(field, index, data); break; } case UAVObjectField::INT8: case UAVObjectField::INT16: case UAVObjectField::INT32: case UAVObjectField::UINT8: case UAVObjectField::UINT16: case UAVObjectField::UINT32: data.append(field->getValue(index)); data.append(field->getUnits()); item = new IntFieldTreeItem(field, index, data); break; case UAVObjectField::FLOAT32: data.append(field->getValue(index)); data.append(field->getUnits()); item = new FloatFieldTreeItem(field, index, data); break; default: Q_ASSERT(false); } } connect(item, SIGNAL(updateHighlight(TreeItem *)), this, SLOT(updateHighlight(TreeItem *))); parent->appendChild(item); } QModelIndex PathActionEditorTreeModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } TreeItem *parentItem; if (!parent.isValid()) { parentItem = m_rootItem; } else { parentItem = static_cast(parent.internalPointer()); } TreeItem *childItem = parentItem->child(row); if (childItem) { return createIndex(row, column, childItem); } else { return QModelIndex(); } } QModelIndex PathActionEditorTreeModel::index(TreeItem *item) { if (item->parent() == 0) { return QModelIndex(); } QModelIndex root = index(item->parent()); for (int i = 0; i < rowCount(root); ++i) { QModelIndex childIndex = index(i, 0, root); TreeItem *child = static_cast(childIndex.internalPointer()); if (child == item) { return childIndex; } } Q_ASSERT(false); return QModelIndex(); } QModelIndex PathActionEditorTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } TreeItem *childItem = static_cast(index.internalPointer()); TreeItem *parentItem = childItem->parent(); if (parentItem == m_rootItem) { return QModelIndex(); } return createIndex(parentItem->row(), 0, parentItem); } int PathActionEditorTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentItem; if (parent.column() > 0) { return 0; } if (!parent.isValid()) { parentItem = m_rootItem; } else { parentItem = static_cast(parent.internalPointer()); } return parentItem->childCount(); } int PathActionEditorTreeModel::columnCount(const QModelIndex &parent) const { if (parent.isValid()) { return static_cast(parent.internalPointer())->columnCount(); } else { return m_rootItem->columnCount(); } } QVariant PathActionEditorTreeModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.column() == TreeItem::dataColumn && role == Qt::EditRole) { TreeItem *item = static_cast(index.internalPointer()); return item->data(index.column()); } // if (role == Qt::DecorationRole) // return QIcon(":/core/images/openpilot_logo_128.png"); if (role == Qt::ToolTipRole) { TreeItem *item = static_cast(index.internalPointer()); return item->description(); } TreeItem *item = static_cast(index.internalPointer()); if (index.column() == 0 && role == Qt::BackgroundRole) { ObjectTreeItem *objItem = dynamic_cast(item); if (objItem && objItem->highlighted()) { return QVariant(m_recentlyUpdatedColor); } } if (index.column() == TreeItem::dataColumn && role == Qt::BackgroundRole) { FieldTreeItem *fieldItem = dynamic_cast(item); if (fieldItem && fieldItem->highlighted()) { return QVariant(m_recentlyUpdatedColor); } if (fieldItem && fieldItem->changed()) { return QVariant(m_manuallyChangedColor); } } if (role != Qt::DisplayRole) { return QVariant(); } if (index.column() == TreeItem::dataColumn) { EnumFieldTreeItem *fieldItem = dynamic_cast(item); if (fieldItem) { int enumIndex = fieldItem->data(index.column()).toInt(); return fieldItem->enumOptions(enumIndex); } else { ActionFieldTreeItem *afieldItem = dynamic_cast(item); if (afieldItem) { int enumIndex = afieldItem->data(index.column()).toInt(); return afieldItem->enumOptions(enumIndex); } } } return item->data(index.column()); } bool PathActionEditorTreeModel::setData(const QModelIndex &index, const QVariant & value, int role) { Q_UNUSED(role) TreeItem * item = static_cast(index.internalPointer()); item->setData(value, index.column()); return true; } Qt::ItemFlags PathActionEditorTreeModel::flags(const QModelIndex &index) const { if (!index.isValid()) { return 0; } if (index.column() == TreeItem::dataColumn) { TreeItem *item = static_cast(index.internalPointer()); if (item->isEditable()) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; } } return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QVariant PathActionEditorTreeModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { return m_rootItem->data(section); } return QVariant(); } void PathActionEditorTreeModel::updateHighlight(TreeItem *item) { QModelIndex itemIndex = index(item); Q_ASSERT(itemIndex != QModelIndex()); emit dataChanged(itemIndex, itemIndex.sibling(itemIndex.row(), TreeItem::dataColumn)); // update uavobject if any - go up the tree until there is ObjectTreeItem *objItem = 0; TreeItem *searchItem = item; while (searchItem) { objItem = dynamic_cast(searchItem); if (objItem) { break; } searchItem = searchItem->parent(); } if (objItem) { item->apply(); objItem->apply(); UAVObject *obj = objItem->object(); Q_ASSERT(obj); obj->updated(); } } void PathActionEditorTreeModel::highlightUpdatedObject(UAVObject *obj) { Q_ASSERT(obj); if (obj->getName().compare("Waypoint") == 0) { m_waypointsTree->update(); // emit dataChanged(index(m_waypointsTree), index(m_waypointsTree)); } else if (obj->getName().compare("PathAction") == 0) { m_pathactionsTree->update(); // emit dataChanged(index(m_pathactionsTree), index(m_pathactionsTree)); } } void PathActionEditorTreeModel::newInstance(UAVObject *obj) { if (obj->getName().compare("Waypoint") == 0) { addInstance(obj, m_waypointsTree); m_waypointsTree->update(); } else if (obj->getName().compare("PathAction") == 0) { addInstance(obj, m_pathactionsTree); m_pathactionsTree->update(); } updateActions(); emit layoutChanged(); } void PathActionEditorTreeModel::objUpdated(UAVObject *obj) { Q_UNUSED(obj); quint16 index = m_objManager->getObject("WaypointActive")->getField("Index")->getValue().toInt(); quint16 action = 0; foreach(TreeItem * child, m_waypointsTree->treeChildren()) { ObjectTreeItem *objItem = dynamic_cast(child); if (index == objItem->object()->getInstID()) { child->setActive(true); action = objItem->object()->getField("Action")->getValue().toInt(); } else { child->setActive(false); } } foreach(TreeItem * child, m_pathactionsTree->treeChildren()) { ObjectTreeItem *objItem = dynamic_cast(child); if (action == objItem->object()->getInstID()) { child->setActive(true); } else { child->setActive(false); } } updateActions(); emit layoutChanged(); }