Currently job artifacts in CI/CD pipelines on LRZ GitLab never expire. Starting from Wed 26.1.2022 the default expiration time will be 30 days (GitLab default). Currently existing artifacts in already completed jobs will not be affected by the change. The latest artifacts for all jobs in the latest successful pipelines will be kept. More information: https://gitlab.lrz.de/help/user/admin_area/settings/continuous_integration.html#default-artifacts-expiration

Commit 1c50f447 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge remote-tracking branch 'remotes/origin/refactor-pipeline-concept' into development

parents 37886930 73cd3ed8
......@@ -28,24 +28,6 @@
// ================================================================================================
#include "application/campvisapplication.h"
#include "modules/advancedusvis/pipelines/advancedusvis.h"
#include "modules/advancedusvis/pipelines/cmbatchgeneration.h"
#include "modules/vis/pipelines/ixpvdemo.h"
#include "modules/vis/pipelines/dvrvis.h"
#include "modules/vis/pipelines/volumerendererdemo.h"
#include "modules/vis/pipelines/volumeexplorerdemo.h"
#include "modules/vis/pipelines/slicevis.h"
#ifdef HAS_KISSCL
#include "modules/opencl/pipelines/openclpipeline.h"
#endif
#ifdef CAMPVIS_HAS_MODULE_SCR_MSK
#include "modules/scr_msk/pipelines/uscompounding.h"
#endif
#ifdef CAMPVIS_HAS_MODULE_COLUMBIA
#include "modules/columbia/pipelines/columbia1.h"
#endif
#ifdef Q_WS_X11
#include <X11/Xlib.h>
......@@ -66,27 +48,6 @@ int main(int argc, char** argv) {
#endif
CampVisApplication app(argc, argv);
// app.addVisualizationPipeline("Advanced Ultrasound Visualization", new AdvancedUsVis());
// app.addVisualizationPipeline("Confidence Map Generation", new CmBatchGeneration());
// app.addVisualizationPipeline("IXPV", new IxpvDemo());
app.addVisualizationPipeline("SliceVis", new SliceVis());
// app.addVisualizationPipeline("DVRVis", new DVRVis());
// app.addVisualizationPipeline("VolumeRendererDemo", new VolumeRendererDemo());
app.addVisualizationPipeline("VolumeExplorerDemo", new VolumeExplorerDemo());
#ifdef HAS_KISSCL
// app.addVisualizationPipeline("DVR with OpenCL", new OpenCLPipeline());
#endif
#ifdef CAMPVIS_HAS_MODULE_SCR_MSK
app.addVisualizationPipeline("US Compounding", new UsCompounding());
#endif
#ifdef CAMPVIS_HAS_MODULE_COLUMBIA
app.addVisualizationPipeline("Columbia", new Columbia1());
#endif
app.init();
int toReturn = app.run();
app.deinit();
......
......@@ -47,9 +47,10 @@
#include "application/gui/mainwindow.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/simplejobprocessor.h"
#include "core/tools/stringutils.h"
#include "core/tools/quadrenderer.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/pipeline/visualizationpipeline.h"
#include "modules/pipelinefactory.h"
namespace campvis {
......@@ -78,17 +79,29 @@ namespace campvis {
tgtAssert(_initialized == false, "Destructing initialized CampVisApplication, deinitialize first!");
// delete everything in the right order:
for (std::vector< std::pair<VisualizationPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
for (std::vector< std::pair<AbstractPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
delete it->second;
}
for (std::vector<AbstractPipeline*>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
delete *it;
}
for (std::vector<DataContainer*>::iterator it = _dataContainers.begin(); it != _dataContainers.end(); ++it) {
delete *it;
}
}
void CampVisApplication::init() {
tgtAssert(_initialized == false, "Tried to initialize CampVisApplication twice.");
// parse argument list and create pipelines
QStringList pipelinesToAdd = this->arguments();
for (int i = 1; i < pipelinesToAdd.size(); ++i) {
DataContainer* dc = createAndAddDataContainer("DataContainer #" + StringUtils::toString(_dataContainers.size() + 1));
AbstractPipeline* p = PipelineFactory::getRef().createPipeline(pipelinesToAdd[i].toStdString(), dc);
if (p != 0)
addPipeline(pipelinesToAdd[i].toStdString(), p);
}
// Init TGT
tgt::InitFeature::Features featureset = tgt::InitFeature::ALL;
tgt::init(featureset);
......@@ -167,7 +180,7 @@ namespace campvis {
}
// Now init painters:
for (std::vector< std::pair<VisualizationPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
for (std::vector< std::pair<AbstractPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
it->second->init();
}
......@@ -190,7 +203,7 @@ namespace campvis {
}
// Now deinit painters:
for (std::vector< std::pair<VisualizationPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
for (std::vector< std::pair<AbstractPipeline*, CampVisPainter*> >::iterator it = _visualizations.begin(); it != _visualizations.end(); ++it) {
it->second->deinit();
}
......@@ -235,33 +248,57 @@ namespace campvis {
return toReturn;
}
void CampVisApplication::addPipeline(AbstractPipeline* pipeline) {
tgtAssert(_initialized == false, "Adding pipelines after initialization is currently not supported.");
void CampVisApplication::addPipeline(const std::string& name, AbstractPipeline* pipeline) {
tgtAssert(pipeline != 0, "Pipeline must not be 0.");
_pipelines.push_back(pipeline);
// if CAMPVis is already fully initialized, we need to temporarily shut down its
// OpenGL job processor, since we need to create a new context.
if (_initialized) {
GLJobProc.pause();
{
tgt::QtThreadedCanvas* canvas = CtxtMgr.createContext(name, "CAMPVis", tgt::ivec2(512, 512));
tgt::GLContextScopedLock lock(canvas->getContext());
addPipelineImpl(canvas, name, pipeline);
}
GLJobProc.resume();
}
else {
tgt::QtThreadedCanvas* canvas = CtxtMgr.createContext(name, "CAMPVis", tgt::ivec2(512, 512));
addPipelineImpl(canvas, name, pipeline);
}
s_PipelinesChanged();
}
void CampVisApplication::addVisualizationPipeline(const std::string& name, VisualizationPipeline* vp) {
tgtAssert(_initialized == false, "Adding pipelines after initialization is currently not supported.");
tgtAssert(vp != 0, "Pipeline must not be 0.");
// create canvas and painter for the VisPipeline and connect all together
tgt::QtThreadedCanvas* canvas = CtxtMgr.createContext(name, "CAMPVis", tgt::ivec2(512, 512));
void CampVisApplication::addPipelineImpl(tgt::QtThreadedCanvas* canvas, const std::string& name, AbstractPipeline* pipeline) {
// create canvas and painter for the pipeline and connect all together
GLJobProc.registerContext(canvas);
_mainWindow->addVisualizationPipelineWidget(name, canvas);
canvas->init();
CampVisPainter* painter = new CampVisPainter(canvas, vp);
CampVisPainter* painter = new CampVisPainter(canvas, pipeline);
canvas->setPainter(painter, false);
pipeline->setCanvas(canvas);
_visualizations.push_back(std::make_pair(vp, painter));
_visualizations.push_back(std::make_pair(pipeline, painter));
_pipelines.push_back(pipeline);
vp->setCanvas(canvas);
addPipeline(vp);
if (_initialized) {
LGL_ERROR;
pipeline->init();
LGL_ERROR;
painter->init();
LGL_ERROR;
}
CtxtMgr.releaseCurrentContext();
_mainWindow->addVisualizationPipelineWidget(name, canvas);
// enable pipeline and invalidate all processors
pipeline->setEnabled(true);
for (std::vector<AbstractProcessor*>::const_iterator it = pipeline->getProcessors().begin(); it != pipeline->getProcessors().end(); ++it) {
(*it)->invalidate(AbstractProcessor::INVALID_RESULT);
}
}
void CampVisApplication::registerDockWidget(Qt::DockWidgetArea area, QDockWidget* dock) {
......@@ -270,4 +307,12 @@ namespace campvis {
_mainWindow->addDockWidget(area, dock);
}
DataContainer* CampVisApplication::createAndAddDataContainer(const std::string& name) {
DataContainer* dc = new DataContainer(name);
_dataContainers.push_back(dc);
s_DataContainersChanged();
return dc;
}
}
......@@ -38,6 +38,8 @@
#include <utility>
#include <vector>
#include "core/datastructures/datacontainer.h"
namespace tgt {
class QtThreadedCanvas;
}
......@@ -46,7 +48,6 @@ namespace campvis {
class AbstractPipeline;
class MainWindow;
class CampVisPainter;
class VisualizationPipeline;
/**
* The CampVisApplication class wraps Pipelines, Evaluators and Painters all together and takes
......@@ -89,25 +90,14 @@ namespace campvis {
void deinit();
/**
* Adds a pipeline which doesn't need visualization (OpenGL) support.
* Each pipeline will automatically get its own evaluator.
*
* \note If you want to add a pipeline that needs a valid OpenGL context, use
* addVisualizationPipeline() instead.
* \param pipeline Pipeline to add, must not need OpenGL support.
*/
void addPipeline(AbstractPipeline* pipeline);
/**
* Adds a visualization pipeline (i.e. a pipeline that needs a OpenGL context).
* For each added pipeline, an OpenGL context will be created (for the evaluation
* and rendering).
* Adds a pipeline to this CAMPVis application.
* Each pipeline will automatically get its own OpenGL context, the corresponding CampvisPainter
* and all necessary connections will be created.
*
* \note You do \b not need to call addPipeline.
* \param name Name of the OpenGL context to create for the pipeline.
* \param vp VisualizationPipeline to add.
* \param vp AbstractPipeline to add.
*/
void addVisualizationPipeline(const std::string& name, VisualizationPipeline* vp);
void addPipeline(const std::string& name, AbstractPipeline* pipeline);
/**
* Adds a dock widget to the main window.
......@@ -125,14 +115,30 @@ namespace campvis {
*/
int run();
/**
* Creates a new DataContainer with the given name.
* \param name Name of the new DataContainer
* \return The newly created DataContainer
*/
DataContainer* createAndAddDataContainer(const std::string& name);
/// Signal emitted when the collection of pipelines has changed.
sigslot::signal0<> s_PipelinesChanged;
/// Signal emitted when the collection of DataContainers has changed.
sigslot::signal0<> s_DataContainersChanged;
private:
/// All pipelines (incuding VisualizationPipelines)
void addPipelineImpl(tgt::QtThreadedCanvas* canvas, const std::string& name, AbstractPipeline* pipeline);
/// All pipelines
std::vector<AbstractPipeline*> _pipelines;
/// All visualisations (i.e. VisualizationPipelines with their corresponding painters/canvases)
std::vector< std::pair<VisualizationPipeline*, CampVisPainter*> > _visualizations;
/// All visualisations (i.e. Pipelines with their corresponding painters/canvases)
std::vector< std::pair<AbstractPipeline*, CampVisPainter*> > _visualizations;
/// All DataContainers
std::vector<DataContainer*> _dataContainers;
/// A local OpenGL context used for initialization
tgt::QtThreadedCanvas* _localContext;
......
......@@ -41,7 +41,7 @@
#include "core/datastructures/imagedata.h"
#include "core/datastructures/renderdata.h"
#include "core/pipeline/visualizationpipeline.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
#include "core/tools/quadrenderer.h"
......@@ -49,7 +49,7 @@
namespace campvis {
const std::string CampVisPainter::loggerCat_ = "CAMPVis.core.CampVisPainter";
CampVisPainter::CampVisPainter(tgt::GLCanvas* canvas, VisualizationPipeline* pipeline)
CampVisPainter::CampVisPainter(tgt::GLCanvas* canvas, AbstractPipeline* pipeline)
: Runnable()
, tgt::Painter(canvas)
, _pipeline(0)
......@@ -97,7 +97,7 @@ namespace campvis {
glViewport(0, 0, size.x, size.y);
// try get Data
DataContainer::ScopedTypedData<RenderData> rd(_pipeline->getDataContainer(), _pipeline->getRenderTargetID());
ScopedTypedData<RenderData> rd(_pipeline->getDataContainer(), _pipeline->getRenderTargetID());
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (rd != 0) {
// activate shader
......@@ -175,7 +175,7 @@ namespace campvis {
}
}
void CampVisPainter::setPipeline(VisualizationPipeline* pipeline) {
void CampVisPainter::setPipeline(AbstractPipeline* pipeline) {
tgtAssert(pipeline != 0, "The given pipeline must not be 0.");
if (_pipeline != 0) {
_pipeline->s_renderTargetChanged.disconnect(this);
......
......@@ -44,16 +44,16 @@ namespace tgt {
}
namespace campvis {
class VisualizationPipeline;
class AbstractPipeline;
/**
* Painter class for CAMPVis, rendering the render target of a VisualizationPipeline.
* Painter class for CAMPVis, rendering the render target of an AbstractPipeline.
* This painter implements Runnable, hence, it runs in its own thread and the associated canvas
* must be of type QtThreadedCanvas.
* Rendering is implemented using condidional wait - hence the canvas is only updated when
* \a pipeline emits the s_RenderTargetChanged signal.
*
* \sa Runnable, VisualizationPipeline
* \sa Runnable, AbstractPipeline
*/
class CampVisPainter : public Runnable, public tgt::Painter, public sigslot::has_slots<> {
public:
......@@ -62,7 +62,7 @@ namespace campvis {
* \param canvas Canvas to render on
* \param pipeline Pipeline to render
*/
CampVisPainter(tgt::GLCanvas* canvas, VisualizationPipeline* pipeline);
CampVisPainter(tgt::GLCanvas* canvas, AbstractPipeline* pipeline);
/**
* Destructor, stops and waits for the rendering thread if it's still running.
......@@ -106,7 +106,7 @@ namespace campvis {
* Pipeline with the render target to render.
* \param pipeline Pipeline to render
*/
void setPipeline(VisualizationPipeline* pipeline);
void setPipeline(AbstractPipeline* pipeline);
/**
* Slot being notified when the pipeline's render target changed.
......@@ -121,7 +121,7 @@ namespace campvis {
static const std::string loggerCat_;
VisualizationPipeline* _pipeline; ///< Pipeline to render
AbstractPipeline* _pipeline; ///< Pipeline to render
tgt::Shader* _copyShader; ///< Shader for copying the render target to the framebuffer.
tbb::atomic<bool> _dirty; ///< Flag whether render result is dirty and needs to be rerendered.
std::condition_variable _renderCondition; ///< conditional wait condition for rendering
......
......@@ -35,18 +35,25 @@
#include "application/gui/datacontainerinspectorcanvas.h"
#include "application/gui/qtdatahandle.h"
#include "application/gui/visualizationpipelinewrapper.h"
#include "core/datastructures/datacontainer.h"
#include "core/pipeline/abstractpipeline.h"
#include "core/pipeline/abstractprocessor.h"
#include "core/tools/stringutils.h"
#include "modules/pipelinefactory.h"
#include <QMdiSubWindow>
#include <QScrollBar>
namespace campvis {
MainWindow::MainWindow(CampVisApplication* application)
: QMainWindow()
, _application(application)
, _mdiArea(0)
, _containerWidget(0)
, _cbPipelineFactory(0)
, _btnPipelineFactory(0)
, _pipelineWidget(0)
, _propCollectionWidget(0)
, _dcInspectorWidget(0)
......@@ -55,6 +62,7 @@ namespace campvis {
, _btnShowDataContainerInspector(0)
, _selectedPipeline(0)
, _selectedProcessor(0)
, _selectedDataContainer(0)
, _logViewer(0)
{
tgtAssert(_application != 0, "Application must not be 0.");
......@@ -64,6 +72,7 @@ namespace campvis {
MainWindow::~MainWindow() {
_application->s_PipelinesChanged.disconnect(this);
_application->s_DataContainersChanged.disconnect(this);
delete _dcInspectorWidget;
}
......@@ -81,9 +90,24 @@ namespace campvis {
_mdiArea->tileSubWindows();
setCentralWidget(_mdiArea);
_containerWidget = new QWidget(this);
QGridLayout* _cwLayout = new QGridLayout(_containerWidget);
_cbPipelineFactory = new QComboBox(_containerWidget);
std::vector<std::string> registeredPipelines = PipelineFactory::getRef().getRegisteredPipelines();
for (std::vector<std::string>::const_iterator it = registeredPipelines.begin(); it != registeredPipelines.end(); ++it)
_cbPipelineFactory->addItem(QString::fromStdString(*it));
_cwLayout->addWidget(_cbPipelineFactory, 0, 0);
_btnPipelineFactory = new QPushButton("Add Pipeline", _containerWidget);
_cwLayout->addWidget(_btnPipelineFactory, 0, 1);
_pipelineWidget = new PipelineTreeWidget();
_pipelineWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
ui.pipelineTreeDock->setWidget(_pipelineWidget);
_containerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
_cwLayout->addWidget(_pipelineWidget, 1, 0, 1, 2);
_containerWidget->setLayout(_cwLayout);
ui.pipelineTreeDock->setWidget(_containerWidget);
_pipelinePropertiesScrollArea = new QScrollArea();
_pipelinePropertiesScrollArea->setWidgetResizable(true);
......@@ -115,8 +139,8 @@ namespace campvis {
_dcInspectorWidget = new DataContainerInspectorWidget();
connect(
this, SIGNAL(updatePipelineWidget(const std::vector<AbstractPipeline*>&)),
_pipelineWidget, SLOT(update(const std::vector<AbstractPipeline*>&)));
this, SIGNAL(updatePipelineWidget(const std::vector<DataContainer*>&, const std::vector<AbstractPipeline*>&)),
_pipelineWidget, SLOT(update(const std::vector<DataContainer*>&, const std::vector<AbstractPipeline*>&)));
connect(
_pipelineWidget, SIGNAL(clicked(const QModelIndex&)),
this, SLOT(onPipelineWidgetItemClicked(const QModelIndex&)));
......@@ -129,7 +153,12 @@ namespace campvis {
connect(
_btnShowDataContainerInspector, SIGNAL(clicked()),
this, SLOT(onBtnShowDataContainerInspectorClicked()));
connect(
_btnPipelineFactory, SIGNAL(clicked()),
this, SLOT(onBtnPipelineFactoryClicked()));
_application->s_PipelinesChanged.connect(this, &MainWindow::onPipelinesChanged);
_application->s_DataContainersChanged.connect(this, &MainWindow::onDataContainersChanged);
}
bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
......@@ -142,38 +171,51 @@ namespace campvis {
}
void MainWindow::onPipelinesChanged() {
emit updatePipelineWidget(_application->_pipelines);
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
}
void MainWindow::onDataContainersChanged() {
emit updatePipelineWidget(_application->_dataContainers, _application->_pipelines);
}
void MainWindow::onPipelineWidgetItemClicked(const QModelIndex& index) {
if (index.isValid()) {
// Yak, this is so ugly - another reason why GUI programming sucks...
QVariant item = index.data(Qt::UserRole);
HasPropertyCollection* ptr = static_cast<HasPropertyCollection*>(item.value<void*>());
if (item.isValid()) {
HasPropertyCollection* ptr = static_cast<HasPropertyCollection*>(item.value<void*>());
if (AbstractPipeline* pipeline = dynamic_cast<AbstractPipeline*>(ptr)) {
_selectedPipeline = pipeline;
_selectedProcessor = 0;
}
else if (AbstractProcessor* processor = dynamic_cast<AbstractProcessor*>(ptr)) {
_selectedProcessor = processor;
QVariant parentItem = index.parent().data(Qt::UserRole);
HasPropertyCollection* pptr = static_cast<HasPropertyCollection*>(parentItem.value<void*>());
if (AbstractPipeline* pipeline = dynamic_cast<AbstractPipeline*>(pptr)) {
if (AbstractPipeline* pipeline = dynamic_cast<AbstractPipeline*>(ptr)) {
_selectedPipeline = pipeline;
_selectedProcessor = 0;
_selectedDataContainer = &pipeline->getDataContainer();
}
else if (AbstractProcessor* processor = dynamic_cast<AbstractProcessor*>(ptr)) {
_selectedProcessor = processor;
QVariant parentItem = index.parent().data(Qt::UserRole);
HasPropertyCollection* pptr = static_cast<HasPropertyCollection*>(parentItem.value<void*>());
if (AbstractPipeline* pipeline = dynamic_cast<AbstractPipeline*>(pptr)) {
_selectedPipeline = pipeline;
_selectedDataContainer = &pipeline->getDataContainer();
}
}
}
emit updatePropCollectionWidget(ptr, &_selectedPipeline->getDataContainer());
emit updatePropCollectionWidget(ptr, &_selectedPipeline->getDataContainer());
}
else {
emit updatePropCollectionWidget(0, 0);
_selectedDataContainer = 0;
}
}
else {
emit updatePropCollectionWidget(0, 0);
_selectedDataContainer = 0;
}
}
QSize MainWindow::sizeHint() const {
return QSize(800, 450);
return QSize(1000, 600);
}
void MainWindow::onBtnExecuteClicked() {
......@@ -239,4 +281,14 @@ namespace campvis {
return dockWidget;
}
void MainWindow::onBtnPipelineFactoryClicked() {
std::string name = this->_cbPipelineFactory->currentText().toStdString();
DataContainer* dc = _selectedDataContainer;
if (dc == 0) {
dc = _application->createAndAddDataContainer("DataContainer #" + StringUtils::toString(_application->_dataContainers.size() + 1));
}
AbstractPipeline* p = PipelineFactory::getRef().createPipeline(name, dc);
_application->addPipeline(name, p);
}
}
......@@ -42,6 +42,7 @@
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QComboBox>
#include <QMdiArea>
#include <QScrollArea>
#include <vector>
......@@ -80,11 +81,6 @@ namespace campvis {
*/
void deinit();
/**
* Slot to be called by the application when its collection of pipelines has changed.
*/
void onPipelinesChanged();
/**
* Size hint for the default window size
* \return QSize(800, 450)
......@@ -108,7 +104,8 @@ namespace campvis {
signals:
/// Qt signal for updating the PipelineWidget.
void updatePipelineWidget(const std::vector<AbstractPipeline*>&);
void updatePipelineWidget(const std::vector<DataContainer*>&, const std::vector<AbstractPipeline*>&);
/// Qt signal for updating the PropertyCollectionWidget
void updatePropCollectionWidget(HasPropertyCollection*, DataContainer*);
......@@ -129,7 +126,22 @@ namespace campvis {
*/
void onBtnShowDataContainerInspectorClicked();
/// Slot to be called when _btnPipelineFactory was clicked;
void onBtnPipelineFactoryClicked();
private:
/**
* Slot to be called by the application when its collection of pipelines has changed.
*/
void onPipelinesChanged();
/**
* Slot to be called by the application when its collection of DataContainers has changed.
*/
void onDataContainersChanged();
/**
* Setup Qt GUI stuff
*/
......@@ -152,6 +164,9 @@ namespace campvis {
CampVisApplication* _application; ///< Pointer to the application hosting the whole stuff
QMdiArea* _mdiArea; ///< MDI area (the window's central widget)
QWidget* _containerWidget; ///< Widget to manage the app's DataContainers and pipelines
QComboBox* _cbPipelineFactory; ///< Combobox for selecting the Pipelines from the PipelineFactory
QPushButton* _btnPipelineFactory; ///< Button to add a Pipeline from the factory
PipelineTreeWidget* _pipelineWidget; ///< Widget for browsing the active pipelines
QWidget* _pipelinePropertiesWidget; ///< Widget showing the selected pipeline's properties
QScrollArea* _pipelinePropertiesScrollArea; ///< Scroll area for _pipelinePropertiesWidget
......@@ -164,6 +179,8 @@ namespace campvis {
AbstractPipeline* _selectedPipeline; ///< currently selected pipeline
AbstractProcessor* _selectedProcessor; ///< currently selected processor
DataContainer* _selectedDataContainer; ///< currently selected DataContainer
LogViewerWidget* _logViewer; ///< Widget displaying log messages
std::vector<QDockWidget*> _primaryDocks; ///< Docks located in top docking area of the main window
};
......
<
......@@ -45,6 +45,38 @@ namespace campvis {
// = TreeModel items ==============================================================================
DataContainerTreeItem::DataContainerTreeItem(DataContainer* dc, TreeItem* parent)
: TreeItem(parent)
, _dataContainer(dc)
{
tgtAssert(_dataContainer != 0, "Pipeline must not be 0.");
}