Commit cadb8aed authored by Pierre Kraemer's avatar Pierre Kraemer

SCHNApps: plugin de rendu avec choix dynamique des VBO a utiliser

parent bde7578e
...@@ -37,8 +37,9 @@ void ImportPlugin::cb_import() ...@@ -37,8 +37,9 @@ void ImportPlugin::cb_import()
VertexAttribute<VEC3> position = m->getAttribute<VEC3, CGoGN::VERTEX>(attrNames[0]); VertexAttribute<VEC3> position = m->getAttribute<VEC3, CGoGN::VERTEX>(attrNames[0]);
// create VBO for vertex position attribute // create VBO for vertex position attribute
Utils::VBO* positionVBO = h->getVBO(position.name()); h->createVBO(position);
positionVBO->updateData(position); // Utils::VBO* positionVBO = h->getVBO(position.name());
// positionVBO->updateData(position);
// compute vertex normal attribute // compute vertex normal attribute
VertexAttribute<VEC3> normal = m->getAttribute<VEC3, CGoGN::VERTEX>("normal"); VertexAttribute<VEC3> normal = m->getAttribute<VEC3, CGoGN::VERTEX>("normal");
...@@ -47,8 +48,9 @@ void ImportPlugin::cb_import() ...@@ -47,8 +48,9 @@ void ImportPlugin::cb_import()
Algo::Geometry::computeNormalVertices<PFP>(*m, position, normal); Algo::Geometry::computeNormalVertices<PFP>(*m, position, normal);
// create VBO for vertex normal attribute // create VBO for vertex normal attribute
CGoGN::Utils::VBO* normalVBO = h->getVBO("normal"); h->createVBO(normal);
normalVBO->updateData(normal); // CGoGN::Utils::VBO* normalVBO = h->getVBO(normal);
// normalVBO->updateData(normal);
// compute map bounding box // compute map bounding box
h->updateBB(position); h->updateBB(position);
......
...@@ -51,6 +51,9 @@ public: ...@@ -51,6 +51,9 @@ public:
virtual void viewUnlinked(View* view) {} virtual void viewUnlinked(View* view) {}
virtual void currentViewChanged(View* view) {} virtual void currentViewChanged(View* view) {}
virtual void mapLinked(View* view, MapHandlerGen* m) {}
virtual void mapUnlinked(View* view, MapHandlerGen* m) {}
public slots: public slots:
void cb_import(); void cb_import();
......
...@@ -79,6 +79,9 @@ public: ...@@ -79,6 +79,9 @@ public:
virtual void viewUnlinked(View* view); virtual void viewUnlinked(View* view);
virtual void currentViewChanged(View* view); virtual void currentViewChanged(View* view);
virtual void mapLinked(View* view, MapHandlerGen* m) {}
virtual void mapUnlinked(View* view, MapHandlerGen* m) {}
protected: protected:
RenderDockTab* m_dockTab; RenderDockTab* m_dockTab;
QHash<View*, TabParams*> h_viewParams; QHash<View*, TabParams*> h_viewParams;
......
...@@ -14,6 +14,10 @@ bool RenderVectorPlugin::enable() ...@@ -14,6 +14,10 @@ bool RenderVectorPlugin::enable()
registerShader(m_vectorShader); registerShader(m_vectorShader);
connect(m_dockTab->mapList, SIGNAL(itemSelectionChanged()), this, SLOT(cb_selectedMapChanged()));
connect(m_dockTab->combo_positionVBO, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_positionVBOChanged(int)));
connect(m_dockTab->combo_vectorVBO, SIGNAL(currentIndexChanged(int)), this, SLOT(cb_vectorVBOChanged(int)));
connect(m_dockTab->button_refreshVBOs, SIGNAL(clicked()), this, SLOT(cb_refreshVBOs()));
connect(m_dockTab->slider_vectorsScaleFactor, SIGNAL(valueChanged(int)), this, SLOT(cb_vectorsScaleFactorChanged(int))); connect(m_dockTab->slider_vectorsScaleFactor, SIGNAL(valueChanged(int)), this, SLOT(cb_vectorsScaleFactorChanged(int)));
return true; return true;
...@@ -31,19 +35,58 @@ void RenderVectorPlugin::redraw(View* view) ...@@ -31,19 +35,58 @@ void RenderVectorPlugin::redraw(View* view)
const QList<MapHandlerGen*>& maps = view->getLinkedMaps(); const QList<MapHandlerGen*>& maps = view->getLinkedMaps();
foreach(MapHandlerGen* m, maps) foreach(MapHandlerGen* m, maps)
{ {
CGoGN::Utils::VBO* positionVBO = m->getVBO("position"); std::cout << "draw map " << m->getName().toUtf8().constData() << std::endl;
CGoGN::Utils::VBO* normalVBO = m->getVBO("normal"); const PerMapTabParams& p = params->perMap[m->getName()];
m_vectorShader->setScale(m->getBBdiagSize() / 100.0f * params->vectorsScaleFactor) ; if(p.positionVBO != NULL && p.vectorVBO != NULL)
m_vectorShader->setAttributePosition(positionVBO) ; {
m_vectorShader->setAttributeVector(normalVBO) ; m_vectorShader->setScale(m->getBBdiagSize() / 100.0f * p.vectorsScaleFactor) ;
glLineWidth(1.0f) ; m_vectorShader->setAttributePosition(p.positionVBO) ;
m->draw(m_vectorShader, Algo::Render::GL2::POINTS) ; m_vectorShader->setAttributeVector(p.vectorVBO) ;
glLineWidth(1.0f) ;
m->draw(m_vectorShader, Algo::Render::GL2::POINTS) ;
}
} }
} }
void RenderVectorPlugin::viewLinked(View* view) void RenderVectorPlugin::viewLinked(View* view)
{ {
h_viewParams.insert(view, new TabParams(1.0)); TabParams* params = new TabParams();
h_viewParams.insert(view, params);
m_dockTab->mapList->clear();
const QList<MapHandlerGen*>& maps = view->getLinkedMaps();
if(maps.empty())
params->selectedMap = NULL;
else
{
params->selectedMap = maps[0];
for(int i = 0; i < maps.count(); ++i)
{
PerMapTabParams p(NULL, NULL, 1.0f);
params->perMap.insert(maps[i]->getName(), p);
m_dockTab->mapList->addItem(maps[i]->getName());
if(maps[i] == params->selectedMap)
{
m_dockTab->mapList->item(i)->setSelected(true);
m_dockTab->combo_positionVBO->clear();
m_dockTab->combo_vectorVBO->clear();
QList<Utils::VBO*> vbos = maps[i]->getVBOList();
for(int j = 0; j < vbos.count(); ++j)
{
m_dockTab->combo_positionVBO->addItem(QString::fromStdString(vbos[j]->name()));
m_dockTab->combo_vectorVBO->addItem(QString::fromStdString(vbos[j]->name()));
}
if(vbos.count() > 0)
{
p.positionVBO = vbos[0];
m_dockTab->combo_positionVBO->setCurrentIndex(0);
p.vectorVBO = vbos[0];
m_dockTab->combo_vectorVBO->setCurrentIndex(0);
}
}
}
}
} }
void RenderVectorPlugin::viewUnlinked(View* view) void RenderVectorPlugin::viewUnlinked(View* view)
...@@ -51,10 +94,195 @@ void RenderVectorPlugin::viewUnlinked(View* view) ...@@ -51,10 +94,195 @@ void RenderVectorPlugin::viewUnlinked(View* view)
h_viewParams.remove(view); h_viewParams.remove(view);
} }
void RenderVectorPlugin::mapLinked(View* view, MapHandlerGen* m)
{
assert(isLinkedToView(view));
TabParams* params = h_viewParams[view];
PerMapTabParams p(NULL, NULL, 1.0f);
params->perMap.insert(m->getName(), p);
m_dockTab->mapList->addItem(m->getName());
}
void RenderVectorPlugin::mapUnlinked(View* view, MapHandlerGen* m)
{
assert(isLinkedToView(view));
TabParams* params = h_viewParams[view];
params->perMap.remove(m->getName());
// for(int i = 0; i < m_dockTab->mapList->count(); ++i)
// {
// if(m_dockTab->mapList->item(i)->text() == m->getName())
// {
// delete m_dockTab->mapList->item(i);
// return;
// }
// }
}
void RenderVectorPlugin::currentViewChanged(View* view) void RenderVectorPlugin::currentViewChanged(View* view)
{ {
TabParams* params = h_viewParams[view]; TabParams* params = h_viewParams[view];
m_dockTab->slider_vectorsScaleFactor->setSliderPosition(params->vectorsScaleFactor * 50.0);
m_dockTab->mapList->clear();
const QList<MapHandlerGen*>& maps = view->getLinkedMaps();
for(int i = 0; i < maps.count(); ++i)
{
m_dockTab->mapList->addItem(maps[i]->getName());
if(maps[i] == params->selectedMap)
{
m_dockTab->mapList->item(i)->setSelected(true);
PerMapTabParams p = params->perMap[maps[i]->getName()];
m_dockTab->slider_vectorsScaleFactor->setSliderPosition(p.vectorsScaleFactor * 50.0);
m_dockTab->combo_positionVBO->clear();
m_dockTab->combo_vectorVBO->clear();
QList<Utils::VBO*> vbos = maps[i]->getVBOList();
for(int j = 0; j < vbos.count(); ++j)
{
m_dockTab->combo_positionVBO->addItem(QString::fromStdString(vbos[j]->name()));
if(vbos[j] == p.positionVBO)
m_dockTab->combo_positionVBO->setCurrentIndex(j);
m_dockTab->combo_vectorVBO->addItem(QString::fromStdString(vbos[j]->name()));
if(vbos[j] == p.vectorVBO)
m_dockTab->combo_vectorVBO->setCurrentIndex(j);
}
if(p.positionVBO == NULL && vbos.count() > 0)
m_dockTab->combo_positionVBO->setCurrentIndex(0);
if(p.vectorVBO == NULL && vbos.count() > 0)
m_dockTab->combo_vectorVBO->setCurrentIndex(0);
}
}
}
void RenderVectorPlugin::refreshTabInfo()
{
m_dockTab->mapList->clear();
m_dockTab->combo_positionVBO->clear();
m_dockTab->combo_vectorVBO->clear();
View* view = m_window->getCurrentView();
assert(isLinkedToView(view));
TabParams* params = h_viewParams[view];
MapHandlerGen* map = params->selectedMap;
const QList<MapHandlerGen*>& maps = view->getLinkedMaps();
for(int i = 0; i < maps.count(); ++i)
{
m_dockTab->mapList->addItem(maps[i]->getName());
if(maps[i] == map)
m_dockTab->mapList->item(i)->setSelected(true);
}
if(map != NULL)
{
PerMapTabParams p = params->perMap[map->getName()];
m_dockTab->slider_vectorsScaleFactor->setSliderPosition(p.vectorsScaleFactor * 50.0);
QList<Utils::VBO*> vbos = map->getVBOList();
for(int i = 0; i < vbos.count(); ++i)
{
m_dockTab->combo_positionVBO->addItem(QString::fromStdString(vbos[i]->name()));
if(vbos[i] == p.positionVBO)
m_dockTab->combo_positionVBO->setCurrentIndex(i);
m_dockTab->combo_vectorVBO->addItem(QString::fromStdString(vbos[i]->name()));
if(vbos[i] == p.vectorVBO)
m_dockTab->combo_vectorVBO->setCurrentIndex(i);
}
if(p.positionVBO == NULL && vbos.count() > 0)
{
p.positionVBO = vbos[0];
m_dockTab->combo_positionVBO->setCurrentIndex(0);
}
if(p.vectorVBO == NULL && vbos.count() > 0)
{
p.vectorVBO = vbos[0];
m_dockTab->combo_vectorVBO->setCurrentIndex(0);
}
}
}
void RenderVectorPlugin::cb_selectedMapChanged()
{
View* current = m_window->getCurrentView();
assert(isLinkedToView(current));
TabParams* params = h_viewParams[current];
QList<QListWidgetItem*> currentItems = m_dockTab->mapList->selectedItems();
if(!currentItems.empty())
{
const QString& mapname = currentItems[0]->text();
MapHandlerGen* m = m_window->getMap(mapname);
params->selectedMap = m;
PerMapTabParams p = params->perMap[m->getName()];
m_dockTab->combo_positionVBO->clear();
m_dockTab->combo_vectorVBO->clear();
QList<Utils::VBO*> vbos = m->getVBOList();
for(int j = 0; j < vbos.count(); ++j)
{
m_dockTab->combo_positionVBO->addItem(QString::fromStdString(vbos[j]->name()));
if(vbos[j] == p.positionVBO)
m_dockTab->combo_positionVBO->setCurrentIndex(j);
m_dockTab->combo_vectorVBO->addItem(QString::fromStdString(vbos[j]->name()));
if(vbos[j] == p.vectorVBO)
m_dockTab->combo_vectorVBO->setCurrentIndex(j);
}
if(p.positionVBO == NULL && vbos.count() > 0)
m_dockTab->combo_positionVBO->setCurrentIndex(0);
if(p.vectorVBO == NULL && vbos.count() > 0)
m_dockTab->combo_vectorVBO->setCurrentIndex(0);
}
}
void RenderVectorPlugin::cb_positionVBOChanged(int index)
{
View* current = m_window->getCurrentView();
assert(isLinkedToView(current));
TabParams* params = h_viewParams[current];
MapHandlerGen* m = params->selectedMap;
params->perMap[m->getName()].positionVBO = m->getVBO(m_dockTab->combo_positionVBO->currentText());
current->updateGL();
}
void RenderVectorPlugin::cb_vectorVBOChanged(int index)
{
View* current = m_window->getCurrentView();
assert(isLinkedToView(current));
TabParams* params = h_viewParams[current];
MapHandlerGen* m = params->selectedMap;
params->perMap[m->getName()].vectorVBO = m->getVBO(m_dockTab->combo_vectorVBO->currentText());
current->updateGL();
}
void RenderVectorPlugin::cb_refreshVBOs()
{
View* current = m_window->getCurrentView();
assert(isLinkedToView(current));
TabParams* params = h_viewParams[current];
MapHandlerGen* m = params->selectedMap;
if(m != NULL)
{
PerMapTabParams p = params->perMap[m->getName()];
p.positionVBO = NULL;
p.vectorVBO = NULL;
m_dockTab->combo_positionVBO->clear();
m_dockTab->combo_vectorVBO->clear();
QList<Utils::VBO*> vbos = m->getVBOList();
for(int j = 0; j < vbos.count(); ++j)
{
m_dockTab->combo_positionVBO->addItem(QString::fromStdString(vbos[j]->name()));
m_dockTab->combo_vectorVBO->addItem(QString::fromStdString(vbos[j]->name()));
}
if(vbos.count() > 0)
{
p.positionVBO = vbos[0];
m_dockTab->combo_positionVBO->setCurrentIndex(0);
p.vectorVBO = vbos[0];
m_dockTab->combo_vectorVBO->setCurrentIndex(0);
}
}
} }
void RenderVectorPlugin::cb_vectorsScaleFactorChanged(int i) void RenderVectorPlugin::cb_vectorsScaleFactorChanged(int i)
...@@ -63,7 +291,8 @@ void RenderVectorPlugin::cb_vectorsScaleFactorChanged(int i) ...@@ -63,7 +291,8 @@ void RenderVectorPlugin::cb_vectorsScaleFactorChanged(int i)
assert(isLinkedToView(current)); assert(isLinkedToView(current));
TabParams* params = h_viewParams[current]; TabParams* params = h_viewParams[current];
params->vectorsScaleFactor = i / 50.0; MapHandlerGen* m = params->selectedMap;
params->perMap[m->getName()].vectorsScaleFactor = i / 50.0;
current->updateGL(); current->updateGL();
} }
......
...@@ -21,15 +21,27 @@ public: ...@@ -21,15 +21,27 @@ public:
RenderVectorDockTab() { setupUi(this); } RenderVectorDockTab() { setupUi(this); }
}; };
struct TabParams struct PerMapTabParams
{ {
TabParams(float vsf) : PerMapTabParams() {}
vectorsScaleFactor(vsf)
PerMapTabParams(Utils::VBO* pos, Utils::VBO* vec, float s) :
positionVBO(pos),
vectorVBO(vec),
vectorsScaleFactor(s)
{} {}
Utils::VBO* positionVBO;
Utils::VBO* vectorVBO;
float vectorsScaleFactor; float vectorsScaleFactor;
}; };
struct TabParams
{
QHash<QString, PerMapTabParams> perMap;
MapHandlerGen* selectedMap;
};
class RenderVectorPlugin : public Plugin class RenderVectorPlugin : public Plugin
{ {
...@@ -61,6 +73,11 @@ public: ...@@ -61,6 +73,11 @@ public:
virtual void viewUnlinked(View* view); virtual void viewUnlinked(View* view);
virtual void currentViewChanged(View* view); virtual void currentViewChanged(View* view);
virtual void mapLinked(View* view, MapHandlerGen* m);
virtual void mapUnlinked(View* view, MapHandlerGen* m);
void refreshTabInfo();
protected: protected:
RenderVectorDockTab* m_dockTab; RenderVectorDockTab* m_dockTab;
QHash<View*, TabParams*> h_viewParams; QHash<View*, TabParams*> h_viewParams;
...@@ -68,6 +85,10 @@ protected: ...@@ -68,6 +85,10 @@ protected:
CGoGN::Utils::ShaderVectorPerVertex* m_vectorShader; CGoGN::Utils::ShaderVectorPerVertex* m_vectorShader;
public slots: public slots:
void cb_selectedMapChanged();
void cb_positionVBOChanged(int index);
void cb_vectorVBOChanged(int index);
void cb_refreshVBOs();
void cb_vectorsScaleFactorChanged(int i); void cb_vectorsScaleFactorChanged(int i);
}; };
......
...@@ -6,14 +6,74 @@ ...@@ -6,14 +6,74 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>174</width> <width>184</width>
<height>397</height> <height>487</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QPushButton" name="button_refreshVBOs">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="mapList"/>
</item>
<item>
<layout class="QGridLayout" name="gridLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Vector :</string>
</property>
</widget>
</item>
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Position :</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QComboBox" name="combo_positionVBO">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QComboBox" name="combo_vectorVBO">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
......
...@@ -44,8 +44,17 @@ public: ...@@ -44,8 +44,17 @@ public:
* MANAGE VBOs * MANAGE VBOs
*********************************************************/ *********************************************************/
Utils::VBO* getVBO(const std::string& name); template <typename ATTR_HANDLER>
void deleteVBO(const std::string& name); Utils::VBO* createVBO(const ATTR_HANDLER& attr)
{
Utils::VBO* vbo = getVBO(QString::fromStdString(attr.name()));
vbo->updateData(attr);
return vbo;
}
Utils::VBO* getVBO(const QString& name);
QList<Utils::VBO*> getVBOList() const { return h_vbo.values(); }
void deleteVBO(const QString& name);
/********************************************************* /*********************************************************
* MANAGE LINKED VIEWS * MANAGE LINKED VIEWS
......
...@@ -50,6 +50,9 @@ public: ...@@ -50,6 +50,9 @@ public:
virtual void viewUnlinked(View* view) = 0; virtual void viewUnlinked(View* view) = 0;
virtual void currentViewChanged(View* view) = 0; virtual void currentViewChanged(View* view) = 0;
virtual void mapLinked(View* view, MapHandlerGen* m) = 0;
virtual void mapUnlinked(View* view, MapHandlerGen* m) = 0;
/********************************************************* /*********************************************************
* MANAGE LINKED VIEWS * MANAGE LINKED VIEWS
*********************************************************/ *********************************************************/
......
...@@ -28,7 +28,7 @@ typedef QHash<QString, View*> ViewHash; ...@@ -28,7 +28,7 @@ typedef QHash<QString, View*> ViewHash;
typedef QHash<QString, Camera*> CameraHash; typedef QHash<QString, Camera*> CameraHash;
typedef QHash<QString, MapHandlerGen*> MapHash; typedef QHash<QString, MapHandlerGen*> MapHash;
typedef QMap<std::string, Utils::VBO*> VBOHash; typedef QMap<QString, Utils::VBO*> VBOHash;
typedef QHash<QString, Utils::GLSLShader*> ShaderHash; typedef QHash<QString, Utils::GLSLShader*> ShaderHash;
typedef QHash<QString, Texture*> TextureHash; typedef QHash<QString, Texture*> TextureHash;
......
...@@ -133,7 +133,6 @@ void MapsDialog::cb_selectedMapChanged() ...@@ -133,7 +133,6 @@ void MapsDialog::cb_selectedMapChanged()
case VOLUME : volumeAttributes->addItem(name + " (" + type + ")"); break; case VOLUME : volumeAttributes->addItem(name + " (" + type + ")"); break;
} }
} }
} }
} }
} }
......
...@@ -41,15 +41,15 @@ void MapsViewDialog::cb_selectedMapsChanged() ...@@ -41,15 +41,15 @@ void MapsViewDialog::cb_selectedMapsChanged()
{ {
QString mapName = mapList->item(i)->text(); QString mapName = mapList->item(i)->text();
MapHandlerGen* map = m_window->getMap(mapName); MapHandlerGen* map = m_window->getMap(mapName);
if(mapList->item(i)->isSelected()) if(mapList->item(i)->isSelected() && !m_view->isLinkedToMap(map))
{ {
assert(!m_view->isLinkedToMap(map) && !map->isLinkedToView(m_view)); assert(!map->isLinkedToView(m_view));
m_view->linkMap(map); m_view->linkMap(map);
map->linkView(m_view); map->linkView(m_view);
} }
else if(!mapList->item(i)->isSelected()) else if(!mapList->item(i)->isSelected() && m_view->isLinkedToMap(map))
{ {
assert(m_view->isLinkedToMap(map) && map->isLinkedToView(m_view)); assert(map->isLinkedToView(m_view));
m_view->unlinkMap(map); m_view->unlinkMap(map);
map->unlinkView(m_view); map->unlinkView(m_view);
} }
......
...@@ -43,15 +43,15 @@ void PluginsViewDialog::cb_selectedPluginsChanged() ...@@ -43,15 +43,15 @@ void PluginsViewDialog::cb_selectedPluginsChanged()
{ {
QString pluginName = pluginList->item(i)->text(); QString pluginName = pluginList->item(i)->text();
Plugin* plugin = m_window->getPlugin(pluginName); Plugin* plugin = m_window->getPlugin(pluginName);
if(pluginList->item(i)->isSelected()) if(pluginList->item(i)->isSelected() && !m_view->isLinkedToPlugin(plugin))
{ {
assert(!m_view->isLinkedToPlugin(plugin) && !plugin->isLinkedToView(m_view)); assert(!plugin->isLinkedToView(m_view));
m_view->linkPlugin(plugin); m_view->linkPlugin(plugin);
plugin->linkView(m_view); plugin->linkView(m_view);
} }
else if(!pluginList->item(i)->isSelected()) else if(!pluginList->item(i)->isSelected() && m_view->isLinkedToPlugin(plugin))
{ {
assert(m_view->isLinkedToPlugin(plugin) && plugin->isLinkedToView(m_view)); assert(plugin->isLinkedToView(m_view));
m_view->unlinkPlugin(plugin); m_view->unlinkPlugin(plugin);
plugin->unlinkView(m_view); plugin->unlinkView(m_view);