pxmlw6n2f/Gazebo_Distributed_MPI/gazebo/gui/model/ModelTreeWidget.cc

729 lines
24 KiB
C++

/*
* Copyright (C) 2015 Open Source Robotics Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "gazebo/common/Events.hh"
#include "gazebo/gui/GuiEvents.hh"
#include "gazebo/gui/model/ModelEditorEvents.hh"
#include "gazebo/gui/model/ModelPluginInspector.hh"
#include "gazebo/gui/model/ModelTreeWidget.hh"
using namespace gazebo;
using namespace gui;
/////////////////////////////////////////////////
ModelTreeWidget::ModelTreeWidget(QWidget *_parent)
: QWidget(_parent)
{
this->setObjectName("ModelTreeWidget");
this->modelDefaultName = "Untitled";
QVBoxLayout *mainLayout = new QVBoxLayout;
// Model Settings
QLabel *settingsLabel = new QLabel(tr(
"<font size=4 color='white'>Model Settings</font>"));
QGridLayout *settingsLayout = new QGridLayout;
// Model name
QLabel *modelLabel = new QLabel(tr("Model Name: "));
this->modelNameEdit = new QLineEdit();
this->modelNameEdit->setText(tr(this->modelDefaultName.c_str()));
connect(this->modelNameEdit, SIGNAL(textChanged(QString)), this,
SLOT(OnNameChanged(QString)));
// Static
QLabel *staticLabel = new QLabel(tr("Static:"));
this->staticCheck = new QCheckBox;
this->staticCheck->setChecked(false);
connect(this->staticCheck, SIGNAL(clicked()), this, SLOT(OnStatic()));
// Auto disable
QLabel *autoDisableLabel = new QLabel(tr("Auto-disable:"));
this->autoDisableCheck = new QCheckBox;
this->autoDisableCheck->setChecked(true);
connect(this->autoDisableCheck, SIGNAL(clicked()), this,
SLOT(OnAutoDisable()));
settingsLayout->addWidget(modelLabel, 0, 0);
settingsLayout->addWidget(this->modelNameEdit, 0, 1);
settingsLayout->addWidget(staticLabel, 1, 0);
settingsLayout->addWidget(this->staticCheck, 1, 1);
settingsLayout->addWidget(autoDisableLabel, 2, 0);
settingsLayout->addWidget(this->autoDisableCheck, 2, 1);
// Model tree
this->modelTreeWidget = new QTreeWidget();
this->modelTreeWidget->setObjectName("modelTreeWidget");
this->modelTreeWidget->setColumnCount(1);
this->modelTreeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
this->modelTreeWidget->header()->hide();
this->modelTreeWidget->setFocusPolicy(Qt::NoFocus);
this->modelTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
this->modelTreeWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
this->modelTreeWidget->setVerticalScrollMode(
QAbstractItemView::ScrollPerPixel);
// Model Plugins
this->modelPluginsItem = new QTreeWidgetItem(static_cast<QTreeWidgetItem*>(0),
QStringList(QString("%1").arg(tr("Model Plugins"))));
this->modelPluginsItem->setData(0, Qt::UserRole,
QVariant(tr("Model Plugins")));
QFont headerFont = this->modelPluginsItem->font(0);
headerFont.setBold(true);
headerFont.setPointSize(1.0 * headerFont.pointSize());
this->modelPluginsItem->setFont(0, headerFont);
this->modelTreeWidget->addTopLevelItem(this->modelPluginsItem);
this->modelPluginInspector = new ModelPluginInspector(_parent);
this->modelPluginInspector->SetReadOnly(false);
this->modelPluginInspector->hide();
connect(this->modelPluginInspector,
SIGNAL(Applied()), this, SLOT(OnModelPluginApply()));
// Nested models
this->nestedModelsItem = new QTreeWidgetItem(
static_cast<QTreeWidgetItem *>(0),
QStringList(QString("%1").arg(tr("Models"))));
this->nestedModelsItem->setData(0, Qt::UserRole,
QVariant(tr("Nested Models")));
this->nestedModelsItem->setFont(0, headerFont);
this->modelTreeWidget->addTopLevelItem(this->nestedModelsItem);
// Links
this->linksItem = new QTreeWidgetItem(
static_cast<QTreeWidgetItem *>(0),
QStringList(QString("%1").arg(tr("Links"))));
this->linksItem->setData(0, Qt::UserRole, QVariant(tr("Links")));
this->linksItem->setFont(0, headerFont);
this->modelTreeWidget->addTopLevelItem(this->linksItem);
// Joints
this->jointsItem = new QTreeWidgetItem(
static_cast<QTreeWidgetItem*>(0),
QStringList(QString("%1").arg(tr("Joints"))));
this->jointsItem->setData(0, Qt::UserRole, QVariant(tr("Joints")));
this->jointsItem->setFont(0, headerFont);
this->modelTreeWidget->addTopLevelItem(this->jointsItem);
connect(this->modelTreeWidget,
SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
this, SLOT(OnItemDoubleClicked(QTreeWidgetItem *, int)));
connect(this->modelTreeWidget,
SIGNAL(itemClicked(QTreeWidgetItem *, int)),
this, SLOT(OnItemClicked(QTreeWidgetItem *, int)));
connect(this->modelTreeWidget, SIGNAL(itemSelectionChanged()),
this, SLOT(OnItemSelectionChanged()));
connect(this->modelTreeWidget,
SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(OnCustomContextMenu(const QPoint &)));
// Model layout
QVBoxLayout *modelLayout = new QVBoxLayout();
modelLayout->addWidget(settingsLabel);
modelLayout->addLayout(settingsLayout);
modelLayout->addWidget(this->modelTreeWidget);
modelLayout->setAlignment(Qt::AlignTop | Qt::AlignHCenter);
QWidget *modelWidget = new QWidget();
modelWidget->setLayout(modelLayout);
// Main layout
QFrame *frame = new QFrame;
QVBoxLayout *frameLayout = new QVBoxLayout;
frameLayout->addWidget(modelWidget);
frameLayout->setContentsMargins(0, 0, 0, 0);
frame->setLayout(frameLayout);
mainLayout->addWidget(frame);
this->setLayout(mainLayout);
this->layout()->setContentsMargins(0, 0, 0, 0);
// Connections
this->connections.push_back(
gui::model::Events::ConnectSaveModel(
boost::bind(&ModelTreeWidget::OnSaveModel, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectNewModel(
boost::bind(&ModelTreeWidget::OnNewModel, this)));
this->connections.push_back(
gui::model::Events::ConnectModelPropertiesChanged(
boost::bind(&ModelTreeWidget::OnModelPropertiesChanged, this, _1, _2)));
this->connections.push_back(
gui::model::Events::ConnectModelNameChanged(
boost::bind(&ModelTreeWidget::OnModelNameChanged, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectNestedModelInserted(
std::bind(&ModelTreeWidget::OnNestedModelInserted, this,
std::placeholders::_1)));
this->connections.push_back(
gui::model::Events::ConnectLinkInserted(
boost::bind(&ModelTreeWidget::OnLinkInserted, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectJointInserted(
boost::bind(&ModelTreeWidget::OnJointInserted, this, _1, _2, _3, _4)));
this->connections.push_back(
gui::model::Events::ConnectModelPluginInserted(
boost::bind(&ModelTreeWidget::OnModelPluginInserted, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectNestedModelRemoved(
boost::bind(&ModelTreeWidget::OnNestedModelRemoved, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectLinkRemoved(
boost::bind(&ModelTreeWidget::OnLinkRemoved, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectJointRemoved(
boost::bind(&ModelTreeWidget::OnJointRemoved, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectModelPluginRemoved(
boost::bind(&ModelTreeWidget::OnModelPluginRemoved, this, _1)));
this->connections.push_back(
gui::model::Events::ConnectJointNameChanged(
boost::bind(&ModelTreeWidget::OnJointNameChanged, this, _1, _2)));
this->connections.push_back(
event::Events::ConnectSetSelectedEntity(
boost::bind(&ModelTreeWidget::OnDeselectAll, this, _1, _2)));
this->connections.push_back(
gui::model::Events::ConnectSetSelectedLink(
boost::bind(&ModelTreeWidget::OnSetSelectedEntity, this, _1, _2)));
this->connections.push_back(
gui::model::Events::ConnectSetSelectedJoint(
boost::bind(&ModelTreeWidget::OnSetSelectedJoint, this, _1, _2)));
this->connections.push_back(
gui::model::Events::ConnectSetSelectedModelPlugin(
boost::bind(&ModelTreeWidget::OnSetSelectedModelPlugin, this, _1, _2)));
this->ClearModelTree();
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnAutoDisable()
{
gui::model::Events::modelPropertiesChanged(this->staticCheck->isChecked(),
this->autoDisableCheck->isChecked());
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnStatic()
{
gui::model::Events::modelPropertiesChanged(this->staticCheck->isChecked(),
this->autoDisableCheck->isChecked());
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnModelPropertiesChanged(
bool _static, bool _autoDisable)
{
bool oldState = this->staticCheck->blockSignals(true);
this->staticCheck->setChecked(_static);
this->staticCheck->blockSignals(oldState);
oldState = this->autoDisableCheck->blockSignals(true);
this->autoDisableCheck->setChecked(_autoDisable);
this->autoDisableCheck->blockSignals(oldState);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnModelNameChanged(const std::string &_name)
{
bool oldState = this->modelNameEdit->blockSignals(true);
this->modelNameEdit->setText(tr(_name.c_str()));
this->modelNameEdit->blockSignals(oldState);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnItemSelectionChanged()
{
QList<QTreeWidgetItem *> items = this->modelTreeWidget->selectedItems();
// update and signal new selection
for (auto const item : items)
{
int idx = this->selected.indexOf(item);
if (idx >= 0)
{
this->selected.removeAt(idx);
continue;
}
std::string name = item->data(0, Qt::UserRole).toString().toStdString();
std::string type = item->data(1, Qt::UserRole).toString().toStdString();
if (type == "Link")
gui::model::Events::setSelectedLink(name, true);
if (type == "Nested Model")
gui::model::Events::setSelectedLink(name, true);
else if (type == "Joint")
gui::model::Events::setSelectedJoint(name, true);
else if (type == "Model Plugin")
gui::model::Events::setSelectedModelPlugin(name, true);
}
// deselect
for (auto const item : this->selected)
{
if (item)
{
std::string name = item->data(0, Qt::UserRole).toString().toStdString();
std::string type = item->data(1, Qt::UserRole).toString().toStdString();
if (type == "Link")
gui::model::Events::setSelectedLink(name, false);
if (type == "Nested Model")
gui::model::Events::setSelectedLink(name, false);
else if (type == "Joint")
gui::model::Events::setSelectedJoint(name, false);
else if (type == "Model Plugin")
gui::model::Events::setSelectedModelPlugin(name, false);
}
}
this->selected = items;
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnDeselectAll(const std::string &/*_name*/,
const std::string &/*_mode*/)
{
this->modelTreeWidget->blockSignals(true);
// deselect all
for (auto &item : this->selected)
{
if (item)
item->setSelected(false);
}
this->modelTreeWidget->blockSignals(false);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnNameChanged(const QString &_name)
{
gui::model::Events::modelNameChanged(_name.toStdString());
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnNewModel()
{
this->modelNameEdit->setText(tr(this->modelDefaultName.c_str()));
this->ClearModelTree();
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnSaveModel(const std::string &_saveName)
{
this->modelNameEdit->setText(tr(_saveName.c_str()));
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnItemDoubleClicked(QTreeWidgetItem *_item,
int /*_column*/)
{
if (_item)
{
std::string name = _item->data(0, Qt::UserRole).toString().toStdString();
std::string type = _item->data(1, Qt::UserRole).toString().toStdString();
if (type == "Link")
gui::model::Events::openLinkInspector(name);
else if (type == "Nested Model")
gzwarn << "There's no inspector for nested models yet." << std::endl;
else if (type == "Joint")
gui::model::Events::openJointInspector(name);
else if (type == "Model Plugin")
gui::model::Events::openModelPluginInspector(name);
}
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnItemClicked(QTreeWidgetItem *_item,
int /*_column*/)
{
if (_item)
{
if (this->selected.empty())
return;
QTreeWidgetItem *item = this->selected[0];
std::string selectedType =
item->data(1, Qt::UserRole).toString().toStdString();
std::string type = _item->data(1, Qt::UserRole).toString().toStdString();
// Deselect incompatible types. For example, joints and Links can't be
// selected at the same time, but links and nested models can.
if (type != selectedType &&
!((type == "Link" && selectedType == "Nested Model") ||
(type == "Nested Model" && selectedType == "Link")))
{
this->DeselectType(selectedType);
}
}
}
/////////////////////////////////////////////////
void ModelTreeWidget::DeselectType(const std::string &_type)
{
QObject::disconnect(this->modelTreeWidget, SIGNAL(itemSelectionChanged()),
this, SLOT(OnItemSelectionChanged()));
for (auto it = this->selected.begin(); it != this->selected.end();)
{
std::string name = (*it)->data(0, Qt::UserRole).toString().toStdString();
std::string type = (*it)->data(1, Qt::UserRole).toString().toStdString();
if (type == _type)
{
(*it)->setSelected(false);
it = this->selected.erase(it);
if (type == "Link")
gui::model::Events::setSelectedLink(name, false);
if (type == "Nested Model")
gui::model::Events::setSelectedLink(name, false);
else if (type == "Joint")
gui::model::Events::setSelectedJoint(name, false);
else if (type == "Model Plugin")
gui::model::Events::setSelectedModelPlugin(name, false);
}
else
++it;
}
this->selected = this->modelTreeWidget->selectedItems();
QObject::connect(this->modelTreeWidget, SIGNAL(itemSelectionChanged()),
this, SLOT(OnItemSelectionChanged()));
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnCustomContextMenu(const QPoint &_pt)
{
QTreeWidgetItem *item = this->modelTreeWidget->itemAt(_pt);
if (item)
{
std::string name = item->data(0, Qt::UserRole).toString().toStdString();
std::string type = item->data(1, Qt::UserRole).toString().toStdString();
if (type == "Link")
gui::model::Events::showLinkContextMenu(name);
if (type == "Nested Model")
gui::model::Events::showLinkContextMenu(name);
else if (type == "Joint")
gui::model::Events::showJointContextMenu(name);
else if (type == "Model Plugin")
gui::model::Events::showModelPluginContextMenu(name);
}
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnLinkInserted(const std::string &_linkName)
{
std::string unscopedName = _linkName;
size_t idx = _linkName.find("::");
if (idx != std::string::npos)
unscopedName = _linkName.substr(idx+2);
// TODO support nested model links
// if the name is still scoped then it could be a nested link.
if (unscopedName.find("::") != std::string::npos)
return;
QTreeWidgetItem *newLinkItem = new QTreeWidgetItem(this->linksItem,
QStringList(QString("%1").arg(QString::fromStdString(unscopedName))));
newLinkItem->setData(0, Qt::UserRole, _linkName.c_str());
newLinkItem->setData(1, Qt::UserRole, "Link");
this->linksItem->setExpanded(true);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnJointInserted(const std::string &_jointId,
const std::string &_jointName, const std::string &/*_parentName*/,
const std::string &/*_childName*/)
{
std::string leafName = _jointName;
size_t idx = _jointName.find_last_of("::");
if (idx != std::string::npos)
leafName = _jointName.substr(idx+1);
QTreeWidgetItem *newJointItem = new QTreeWidgetItem(this->jointsItem,
QStringList(QString("%1").arg(QString::fromStdString(leafName))));
newJointItem->setData(0, Qt::UserRole, _jointId.c_str());
newJointItem->setData(1, Qt::UserRole, "Joint");
this->jointsItem->setExpanded(true);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnModelPluginInserted(
const std::string &_modelPluginName)
{
QTreeWidgetItem *newModelPluginItem = new QTreeWidgetItem(
this->modelPluginsItem, QStringList(QString("%1").arg(
QString::fromStdString(_modelPluginName))));
newModelPluginItem->setData(0, Qt::UserRole, _modelPluginName.c_str());
newModelPluginItem->setData(1, Qt::UserRole, "Model Plugin");
this->modelPluginsItem->setExpanded(true);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnLinkRemoved(const std::string &_linkId)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
QTreeWidgetItem *item = this->FindItemByData(_linkId, *this->linksItem);
if (item)
this->linksItem->takeChild(this->linksItem->indexOfChild(item));
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnJointRemoved(const std::string &_jointId)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
QTreeWidgetItem *item = this->FindItemByData(_jointId, *this->jointsItem);
if (item)
this->jointsItem->takeChild(this->jointsItem->indexOfChild(item));
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnModelPluginRemoved(const std::string &_pluginId)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
for (int i = 0; i < this->modelPluginsItem->childCount(); ++i)
{
QTreeWidgetItem *item = this->modelPluginsItem->child(i);
if (!item)
continue;
std::string listData = item->data(0, Qt::UserRole).toString().toStdString();
if (listData == _pluginId)
{
this->modelPluginsItem->takeChild(this->modelPluginsItem->indexOfChild(
item));
break;
}
}
}
/////////////////////////////////////////////////
void ModelTreeWidget::ClearModelTree()
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
// Remove all nested models
this->nestedModelsItem->takeChildren();
// Remove all links
this->linksItem->takeChildren();
// Remove all joints
this->jointsItem->takeChildren();
// Remove all model plugins
this->modelPluginsItem->takeChildren();
// add Model Plugins button
QTreeWidgetItem *addModelPluginItem =
new QTreeWidgetItem(this->modelPluginsItem);
this->modelPluginsItem->setExpanded(true);
QPushButton *addPluginButton = new QPushButton(tr("Add"));
addPluginButton->setMaximumWidth(60);
addPluginButton->setFlat(true);
this->modelTreeWidget->setItemWidget(addModelPluginItem, 0,
addPluginButton);
connect(addPluginButton,
SIGNAL(clicked()), this, SLOT(OnAddModelPlugin()));
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnJointNameChanged(const std::string &_jointId,
const std::string &_newJointName)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
QTreeWidgetItem *item = this->FindItemByData(_jointId, *this->jointsItem);
if (item)
item->setText(0, QString::fromStdString(_newJointName));
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnSetSelectedEntity(const std::string &_entityId,
const bool _selected)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
// Link
auto item = this->FindItemByData(_entityId, *this->linksItem);
if (item)
item->setSelected(_selected);
// Nested model
item = this->FindItemByData(_entityId, *this->nestedModelsItem);
if (item)
item->setSelected(_selected);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnSetSelectedJoint(const std::string &_jointId,
const bool _selected)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
QTreeWidgetItem *item = this->FindItemByData(_jointId, *this->jointsItem);
if (item)
item->setSelected(_selected);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnSetSelectedModelPlugin(const std::string &_name,
const bool _selected)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
for (int i = 0; i < this->modelPluginsItem->childCount(); ++i)
{
QTreeWidgetItem *item = this->modelPluginsItem->child(i);
if (!item)
continue;
std::string listData = item->data(0, Qt::UserRole).toString().toStdString();
if (listData == _name)
{
item->setSelected(_selected);
break;
}
}
}
/////////////////////////////////////////////////
QTreeWidgetItem *ModelTreeWidget::FindItemByData(const std::string &_data,
const QTreeWidgetItem &_parentItem)
{
for (int i = 0; i < _parentItem.childCount(); ++i)
{
QTreeWidgetItem *item = _parentItem.child(i);
std::string itemId =
item->data(0, Qt::UserRole).toString().toStdString();
if (itemId == _data)
{
return item;
}
item = this->FindItemByData(_data, *item);
if (item)
return item;
}
return NULL;
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnNestedModelInserted(const std::string &_nestedModelId)
{
// Divide the name into parent scoped name and leaf name
std::string parentScopedName = _nestedModelId;
std::string leafName = _nestedModelId;
size_t idx = _nestedModelId.rfind("::");
if (idx != std::string::npos)
{
parentScopedName = _nestedModelId.substr(0, idx);
leafName = _nestedModelId.substr(idx+2);
}
// Top level by default
QTreeWidgetItem *parentItem = this->nestedModelsItem;
// If the parent model is a nested model
QTreeWidgetItem *item = this->FindItemByData(parentScopedName,
*this->nestedModelsItem);
if (item)
parentItem = item;
// check if nested model already exists
auto treeItems = this->modelTreeWidget->findItems(tr(leafName.c_str()),
Qt::MatchExactly | Qt::MatchRecursive);
for (auto const &it : treeItems)
{
if (it->data(0, Qt::UserRole).toString().toStdString() == _nestedModelId)
return;
}
QTreeWidgetItem *newNestedModelItem =
new QTreeWidgetItem(parentItem,
QStringList(QString("%1").arg(QString::fromStdString(leafName))));
newNestedModelItem->setData(0, Qt::UserRole, _nestedModelId.c_str());
newNestedModelItem->setData(1, Qt::UserRole, "Nested Model");
this->nestedModelsItem->setExpanded(true);
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnNestedModelRemoved(const std::string &_nestedModelId)
{
std::unique_lock<std::recursive_mutex> lock(this->updateMutex);
for (int i = 0; i < this->nestedModelsItem->childCount(); ++i)
{
QTreeWidgetItem *item = this->nestedModelsItem->child(i);
if (!item)
continue;
std::string listData = item->data(0, Qt::UserRole).toString().toStdString();
if (listData == _nestedModelId)
{
this->nestedModelsItem->takeChild(
this->nestedModelsItem->indexOfChild(item));
break;
}
}
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnAddModelPlugin()
{
this->modelPluginInspector->show();
this->modelPluginInspector->setFocus();
}
/////////////////////////////////////////////////
void ModelTreeWidget::OnModelPluginApply()
{
msgs::Plugin *msg = this->modelPluginInspector->Data();
model::Events::requestModelPluginInsertion(msg->name(), msg->filename(),
msg->innerxml());
}