Commit fedbc913 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge

Merge branch 'core-updates' into 'development'

Core updates

Various updates to the base library, cherry-picked from the biopsy-workflow-gui branch. Most notably:

* new AbstractJob instance taking C++11 functionals in the constructor
* new QtJobProcessor singleton for executing jobs in the Qt GUI thread
* new StatusProperty and StatusPropertyWidget to display status information as color+text
* ButtonProperty forwards clicks to its shared properties
* s_changed signal of properties is only fired if the value actually has changed
* MatrixProcessor fix for endless loops occuring when a formula uses a matrix that is computed by that same formula and that is put into the data container
* various accessors to internals of MainWindow and AbstractPipeline

See merge request !93
parents 1be35662 11f1805e
......@@ -28,6 +28,7 @@ FILE(GLOB CampvisApplicationForms
)
SET(CampvisApplicationToBeMocced
qtjobprocessor.h
gui/mainwindow.h
gui/datacontainerinspectorcanvas.h
gui/datacontainerinspectorwidget.h
......@@ -61,6 +62,7 @@ SET(CampvisApplicationToBeMocced
gui/properties/propertycollectionwidget.h
gui/properties/simpletransferfunctioneditor.h
gui/properties/stringpropertywidget.h
gui/properties/statuspropertywidget.h
gui/properties/transferfunctionpropertywidget.h
tools/qtexteditlog.h
tools/bufferinglog.h
......
......@@ -37,6 +37,7 @@
#include "application/campvispainter.h"
#include "application/gui/properties/propertywidgetfactory.h"
#include "application/gui/mainwindow.h"
#include "application/gui/mdi/mdidockablewindow.h"
#include "core/tools/job.h"
#include "core/tools/opengljobprocessor.h"
......@@ -48,6 +49,7 @@
#include "core/pipeline/visualizationprocessor.h"
#include "modules/pipelinefactory.h"
#include "qtjobprocessor.h"
#ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/gen_pipelineregistration.h"
......@@ -77,6 +79,7 @@ namespace campvis {
OpenGLJobProcessor::init();
SimpleJobProcessor::init();
QtJobProcessor::init();
}
CampVisApplication::~CampVisApplication() {
......@@ -259,7 +262,7 @@ namespace campvis {
PipelineRecord pr = { pipeline, painter };
_pipelines.push_back(pr);
_mainWindow->addVisualizationPipelineWidget(name, canvas);
_pipelineWindows[pipeline] = _mainWindow->addVisualizationPipelineWidget(name, canvas);
// initialize context (GLEW) and pipeline in OpenGL thread)
GLJobProc.enqueueJob(
......
......@@ -35,6 +35,7 @@
#include "core/datastructures/datacontainer.h"
#ifdef CAMPVIS_HAS_SCRIPTING
#include "scripting/glue/luavmstate.h"
#endif
......@@ -49,6 +50,7 @@ namespace campvis {
class AbstractPipeline;
class MainWindow;
class CampVisPainter;
class MdiDockableWindow;
class LuaVmState;
/**
......@@ -157,6 +159,8 @@ namespace campvis {
/// All pipelines
std::vector<PipelineRecord> _pipelines;
std::map<AbstractPipeline *, MdiDockableWindow *> _pipelineWindows;
/// All DataContainers
std::vector<DataContainer*> _dataContainers;
......
......@@ -295,11 +295,12 @@ namespace campvis {
_scriptingConsoleWidget->deinit();
}
void MainWindow::addVisualizationPipelineWidget(const std::string& name, QWidget* canvas) {
MdiDockableWindow * MainWindow::addVisualizationPipelineWidget(const std::string& name, QWidget* canvas) {
MdiDockableWindow* dockableWindow = _mdiArea->addWidget(canvas);
QString windowTitle = QString::fromStdString(name);
dockableWindow->setWindowTitle(windowTitle);
dockableWindow->show();
return dockableWindow;
}
QDockWidget* MainWindow::dockPrimaryWidget(const std::string& name, QWidget* widget) {
......
......@@ -89,7 +89,7 @@ namespace campvis {
* \param name the name of the visualization pipeline
* \param canvas the pipeline's canvas
*/
void addVisualizationPipelineWidget(const std::string& name, QWidget* canvas);
MdiDockableWindow * addVisualizationPipelineWidget(const std::string& name, QWidget* canvas);
protected:
/**
......
......@@ -67,8 +67,8 @@ namespace campvis {
_property->s_changed.disconnect(this);
}
void AbstractPropertyWidget::addWidget(QWidget* widget) {
_layout->addWidget(widget, 1);
void AbstractPropertyWidget::addWidget(QWidget* widget, int stretch) {
_layout->addWidget(widget, stretch);
}
void AbstractPropertyWidget::onPropertyChanged(const AbstractProperty* property) {
......
......@@ -63,7 +63,7 @@ namespace campvis {
/**
* Adds a widget to the local Qt layout.
*/
void addWidget(QWidget* widget);
void addWidget(QWidget* widget, int stretch = 1);
AbstractProperty* _property; ///< The property this widget handles
DataContainer* _dataContainer; ///< DataContainer to use (e.g. to populate GUI), may be 0!
......
......@@ -64,6 +64,7 @@ namespace campvis {
propertyCollection->s_propertyAdded.connect(this, &PropertyCollectionWidget::onPropCollectionPropAdded);
propertyCollection->s_propertyRemoved.connect(this, &PropertyCollectionWidget::onPropCollectionPropRemoved);
}
_layout->addStretch(1);
}
void PropertyCollectionWidget::setupWidget() {
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// 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 "statuspropertywidget.h"
#include <QLabel>
namespace campvis {
const char * StatusPropertyWidget::baseStyle = "text-align: center; padding: 1px; font-weight: bold;";
StatusPropertyWidget::StatusPropertyWidget(StatusProperty * property, DataContainer* dataContainer /*= nullptr*/, QWidget* parent /*= 0*/)
: AbstractPropertyWidget(property, false, dataContainer, parent)
{
_statusLabel = new QLabel(this);
_statusLabel->setText(QString::fromStdString(property->getValue().string));
_statusLabel->setStyleSheet(getStyleFromStatusType(property->getValue().status));
_statusLabel->setMinimumWidth(100);
_statusLabel->setMaximumWidth(100);
_statusLabel->setAlignment(Qt::AlignCenter);
addWidget(new QWidget(this), 1); //spacer item to force right-alignment
addWidget(_statusLabel, 0);
//_statusLabel->setStyleSheet();
}
StatusPropertyWidget::~StatusPropertyWidget() {
}
void StatusPropertyWidget::updateWidgetFromProperty() {
StatusProperty * prop = static_cast<StatusProperty*>(_property);
QString qs = QString::fromStdString(prop->getValue().string);
_statusLabel->setText(qs);
_statusLabel->setStyleSheet(getStyleFromStatusType(prop->getValue().status));
}
QString StatusPropertyWidget::getStyleFromStatusType(Status::StatusType type) const {
switch (type) {
case Status::UNKNOWN:
return QString("color: black; background-color: grey; border: 1px solid black;") + baseStyle;
case Status::OK:
return QString("color: black; background-color: green; border: 1px solid darkgreen;") + baseStyle;
case Status::WARNING:
return QString("color: black; background-color: orange; border: 1px solid darkorange;") + baseStyle;
case Status::CRITICAL:
return QString("color: black; background-color: red; border: 1px solid darkred; text-align: center; padding: 2px;") + baseStyle;
default:
return QString("color: black; background-color: white; border: 1px solid grey;") + baseStyle;
}
};
}
\ No newline at end of file
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// 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.
//
// ================================================================================================
#ifndef STATUSPROPERTYWIDGET_H__
#define STATUSPROPERTYWIDGET_H__
#include "application/gui/properties/abstractpropertywidget.h"
#include "application/gui/properties/propertywidgetfactory.h"
#include "core/properties/statusproperty.h"
namespace campvis {
/**
* Widget for a StringProperty
*/
class StatusPropertyWidget : public AbstractPropertyWidget {
Q_OBJECT;
public:
/**
* Creates a new PropertyWidget for the property \a property.
* \param property The property the widget shall handle
* \param dataContainer DataContainer to use (optional), defaults to nullptr.
* \param parent Parent Qt widget
*/
StatusPropertyWidget(StatusProperty * property, DataContainer* dataContainer = nullptr, QWidget* parent = 0);
/**
* Destructor
*/
virtual ~StatusPropertyWidget();
protected:
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void updateWidgetFromProperty();
private:
static const char* baseStyle;
QString getStyleFromStatusType(Status::StatusType type) const;
QLabel * _statusLabel;
};
// explicitly instantiate template, so that it gets registered also over DLL boundaries.
template class PropertyWidgetRegistrar<StatusPropertyWidget, StatusProperty>;
}
#endif // STATUSPROPERTYWIDGET_H__
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// 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 "qtjobprocessor.h"
namespace campvis {
QtJobProcessor::QtJobProcessor()
: QWidget()
{
connect(this, SIGNAL(newJobSignal(AbstractJob *)), this, SLOT(onJobArrived(AbstractJob *)));
}
QtJobProcessor::~QtJobProcessor()
{
}
void QtJobProcessor::enqueueJob(AbstractJob * job) {
emit newJobSignal(job);
}
void QtJobProcessor::enqueueJob(std::function<void(void)> fn)
{
emit newJobSignal(makeJobOnHeap(fn));
}
void QtJobProcessor::onJobArrived(AbstractJob * job)
{
tgtAssert(job, "Job must not be null!");
(*job)();
delete job;
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// 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.
//
// ================================================================================================
#ifndef QTJOBPROCESSOR_H__
#define QTJOBPROCESSOR_H__
#include "core/tools/job.h"
#include "tgt/singleton.h"
#include <QWidget>
#include <functional>
namespace campvis {
/**
* This job processor singleton can be used to execute jobs (asynchronously) from inside the Qt GUI thread.
* This can result in simpler and better understandable code when only a few lines of code need
* to be executed in the context, as it removes the need to introduce a new signal and slot just
* to transition into the Qt GUI thread.
*
* Example:
* \code
* QtJobProc.enqueueJob([=](){
* _application->_mainWindow->statusBar()->showMessage(QString::fromStdString(status), timeout);
* });
* \endcode
*/
class QtJobProcessor : public QWidget, public tgt::Singleton<QtJobProcessor> {
Q_OBJECT;
public:
QtJobProcessor();
virtual ~QtJobProcessor();
/**
Enqueues a new job to be processed by the job processor
*/
void enqueueJob(AbstractJob * job);
/**
Convenience function to simplify the code, removing the necessity for a makeJobOnHeap() call
*/
void enqueueJob(std::function<void(void)> fn);
signals:
void newJobSignal(AbstractJob * job);
private slots:
void onJobArrived(AbstractJob * job);
};
}
#define QtJobProc tgt::Singleton<campvis::QtJobProcessor>::getRef()
#endif // QTJOBPROCESSOR_H__
......@@ -169,6 +169,12 @@ namespace campvis {
*/
const std::string& getRenderTargetID() const;
/**
* returns the currently set canvas for the pipeline
*/
tgt::GLCanvas * getCanvas() {
return _canvas;
}
/// Signal emitted when the pipeline's render target has changed
sigslot::signal0 s_renderTargetChanged;
......
......@@ -34,5 +34,6 @@
#include "core/properties/optionproperty.h"
#include "core/properties/stringproperty.h"
#include "core/properties/transferfunctionproperty.h"
#include "core/properties/statusproperty.h"
#endif // ALLPROPERTIES_H__
\ No newline at end of file
......@@ -37,6 +37,13 @@ namespace campvis {
}
void ButtonProperty::click() {
//pass the click on to all shared button that are connected
for (auto it = _sharedProperties.begin(), end = _sharedProperties.end(); it != end; ++it) {
ButtonProperty * btn = dynamic_cast<ButtonProperty*>(*it);
if (btn)
btn->click();
}
s_clicked.emitSignal();
s_changed.emitSignal(this);
}
......
......@@ -177,6 +177,7 @@ namespace campvis {
template<typename T>
void campvis::GenericProperty<T>::setFrontValue(const T& value) {
bool valueChanged = !(_value == value);
_value = value;
for (std::set<AbstractProperty*>::iterator it = _sharedProperties.begin(); it != _sharedProperties.end(); ++it) {
// We ensure all shared properties to be of type GenericProperty<T> in the addSharedProperty overload.
......@@ -184,7 +185,8 @@ namespace campvis {
GenericProperty<T>* child = static_cast< GenericProperty<T>* >(*it);
child->setValue(value);
}
s_changed.emitSignal(this);
if (valueChanged) //dont't signal a change if it has not really changed
s_changed.emitSignal(this);
}
template<typename T>
......
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// 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 "statusproperty.h"
namespace campvis {
const std::string StatusProperty::loggerCat_ = "CAMPVis.core.datastructures.StatusProperty";
StatusProperty::StatusProperty(const std::string& name, const std::string& title, const Status & value)
: GenericProperty<Status>(name, title, value)
{
}
StatusProperty::~StatusProperty() {
}
}
// ================================================================================================
//
// This file is part of the CAMPVis Software Framework.
//
// If not explicitly stated otherwise: Copyright (C) 2012-2014, all rights reserved,
// Christian Schulte zu Berge <christian.szb@in.tum.de>
// Chair for Computer Aided Medical Procedures
// Technische Universitaet Muenchen
// Boltzmannstr. 3, 85748 Garching b. Muenchen, Germany
//
// For a full list of authors and contributors, please refer to the file "AUTHORS.txt".
//
// 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.
//
// ================================================================================================
#ifndef STATUSPROPERTY_H__
#define STATUSPROPERTY_H__
#include "core/properties/genericproperty.h"
#include <string>
#include <tuple>
namespace campvis {
// simple class to store status as a combination of string and type
struct Status {
public:
/// Enumeration of the possible status types
enum StatusType {
UNKNOWN,
OK,
WARNING,
CRITICAL
};
Status(std::string string_arg, StatusType status_arg)
: string(string_arg)
, status(status_arg)
{};
bool operator==(const Status & rhs) {
return status == rhs.status && string == rhs.string;
};
bool operator!=(const Status &rhs) {
return status != rhs.status || string != rhs.string;
};
std::string string;
StatusType status;
};
class CAMPVIS_CORE_API StatusProperty : public GenericProperty<Status> {
public:
/**
* Creates a new StatusProperty
* \param name Property name (unchangable!)
* \param title Property title (e.g. used for GUI)
* \param value Initial value
*/
StatusProperty(const std::string& name, const std::string& title, const Status & value = Status(std::string(""), Status::UNKNOWN));
/**
* Virtual Destructor
**/
virtual ~StatusProperty();
// convenience setter
void setStatus(std::string str, Status::StatusType status)
{
setValue(Status(str, status));
};
protected:
static const std::string loggerCat_;
};
}
#endif // STATUSPROPERTY_H__
......@@ -29,6 +29,8 @@
#include "core/coreapi.h"
#include <functional>
namespace campvis {
/**
......@@ -258,6 +260,27 @@ namespace campvis {
A2 _arg2; ///< Second Argument to pass to \a callee
};