Commit ab68042a authored by schultezub's avatar schultezub

Further work on property widgets:

 + added PropertyWidgetFactory
 + added AbstractPropertyWidget and StringPropertyWidget
 * replaced own observer implementation of AbstractPipeline and AbstractProperty with sigslot
 * changed PropertyCollection (aggregation) to HasPropertyCollection (inheritance)

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@207 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent 2d967f2e
......@@ -7,11 +7,13 @@ MESSAGE(STATUS "Configuring TUMVis Application")
FILE(GLOB TUMVIS_APPLICATION_SOURCES
*.cpp
gui/*.cpp
gui/properties/*.cpp
)
FILE(GLOB TUMVIS_APPLICATION_HEADERS
*.h
gui/*.h
gui/properties/*.h
)
#SET(TUMVIS_APPLICATION_SOURCES
......@@ -23,7 +25,10 @@ FILE(GLOB TUMVIS_APPLICATION_HEADERS
SET(TUMVIS_APPLICATION_TO_BE_MOCCED
gui/mainwindow.h
gui/pipelinetreewidget.h
gui/propertycollectionwidget.h
gui/properties/abstractpropertywidget.h
gui/properties/propertycollectionwidget.h
gui/properties/propertywidgetfactory.h
gui/properties/stringpropertywidget.h
)
#
......
......@@ -40,8 +40,8 @@ namespace TUMVis {
_pipelineWidget, SIGNAL(clicked(const QModelIndex&)),
this, SLOT(onPipelineWidgetItemClicked(const QModelIndex&)));
connect(
this, SIGNAL(updatePropCollectionWidget(PropertyCollection*)),
_propCollectionWidget, SLOT(updatePropCollection(PropertyCollection*)));
this, SIGNAL(updatePropCollectionWidget(HasPropertyCollection*)),
_propCollectionWidget, SLOT(updatePropCollection(HasPropertyCollection*)));
_application->s_PipelinesChanged.connect(this, &MainWindow::onPipelinesChanged);
}
......@@ -55,7 +55,7 @@ namespace TUMVis {
QVariant item = index.data(Qt::UserRole);
HasPropertyCollection* ptr = static_cast<HasPropertyCollection*>(item.value<void*>());
if (ptr != 0) {
emit updatePropCollectionWidget(&(ptr->getPropertyCollection()));
emit updatePropCollectionWidget(ptr);
}
else {
emit updatePropCollectionWidget(0);
......
......@@ -4,7 +4,7 @@
#include "sigslot/sigslot.h"
#include "application/tumvisapplication.h"
#include "application/gui/pipelinetreewidget.h"
#include "application/gui/propertycollectionwidget.h"
#include "application/gui/properties/propertycollectionwidget.h"
#include <QMainWindow>
#include <QVBoxLayout>
......@@ -41,7 +41,7 @@ namespace TUMVis {
/// Qt signal for updating the PipelineWidget.
void updatePipelineWidget(const std::vector<AbstractPipeline*>&);
/// Qt signal for updating the PropertyCollectionWidget
void updatePropCollectionWidget(PropertyCollection*);
void updatePropCollectionWidget(HasPropertyCollection*);
private slots:
/**
......
#include "abstractpropertywidget.h"
#include "core/properties/abstractproperty.h"
namespace TUMVis {
AbstractPropertyWidget::AbstractPropertyWidget(AbstractProperty* property, QWidget* parent /*= 0*/)
: QWidget(parent)
, _property(property)
, _ignorePropertyUpdates(false)
, _layout(0)
{
_layout = new QBoxLayout(QBoxLayout::LeftToRight, this);
_property->s_changed.connect(this, &AbstractPropertyWidget::onPropertyChanged);
}
AbstractPropertyWidget::~AbstractPropertyWidget() {
_property->s_changed.disconnect(this);
}
void AbstractPropertyWidget::addWidget(QWidget* widget) {
_layout->addWidget(widget, 1);
}
void AbstractPropertyWidget::onPropertyChanged(const AbstractProperty* property) {
if (!_ignorePropertyUpdates)
updateWidgetFromProperty();
}
}
\ No newline at end of file
#ifndef ABSTRACTPROPERTYWIDGET_H__
#define ABSTRACTPROPERTYWIDGET_H__
#include "sigslot/sigslot.h"
#include <QWidget>
#include <QBoxLayout>
namespace TUMVis {
class AbstractProperty;
/**
* Abstract base class for property widgets.
*/
class AbstractPropertyWidget : public QWidget, public sigslot::has_slots<> {
Q_OBJECT;
public:
/**
* Creates a new PropertyWidget for the property \a property.
* \param property The property the widget shall handle
* \param parent Parent Qt widget
*/
AbstractPropertyWidget(AbstractProperty* property, QWidget* parent = 0);
/**
* Destructor
*/
virtual ~AbstractPropertyWidget();
public slots:
protected:
/**
* Adds a widget to the local Qt layout.
*/
void addWidget(QWidget* widget);
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void updateWidgetFromProperty() = 0;
AbstractProperty* _property; ///< The property this widget handles
bool _ignorePropertyUpdates; ///< Flag whether the widget shall ignore incoming signals from properties being updated.
private:
/// Slot getting called when the property has changed, so that the widget can be updated.
virtual void onPropertyChanged(const AbstractProperty* property);
QBoxLayout* _layout;
};
}
#endif // ABSTRACTPROPERTYWIDGET_H__
#include "propertycollectionwidget.h"
#include "application/gui/properties/abstractpropertywidget.h"
#include "application/gui/properties/propertywidgetfactory.h"
#include "core/properties/abstractproperty.h"
#include "core/properties/propertycollection.h"
......@@ -20,7 +22,7 @@ namespace TUMVis {
qDeleteAll(_widgetList);
}
void PropertyCollectionWidget::updatePropCollection(PropertyCollection* propertyCollection) {
void PropertyCollectionWidget::updatePropCollection(HasPropertyCollection* propertyCollection) {
// just some dummy implementation for property widget listing:
for (QList<QWidget*>::iterator it = _widgetList.begin(); it != _widgetList.end(); ++it) {
_layout->removeWidget(*it);
......@@ -30,7 +32,10 @@ namespace TUMVis {
for (std::vector<AbstractProperty*>::const_iterator it = propertyCollection->getProperties().begin(); it != propertyCollection->getProperties().end(); ++it) {
QPushButton* propWidget = new QPushButton(QString::fromStdString((*it)->getTitle()));
QWidget* propWidget = PropertyWidgetFactory::createWidget(*it);
if (propWidget == 0)
propWidget = new QPushButton(QString::fromStdString((*it)->getTitle()));
_widgetList.push_back(propWidget);
_layout->addWidget(propWidget);
}
......
......@@ -6,7 +6,7 @@
#include <QWidget>
namespace TUMVis {
class PropertyCollection;
class HasPropertyCollection;
/**
* Main Window for the TUMVis application.
......@@ -30,9 +30,9 @@ namespace TUMVis {
public slots:
/**
* Updates the property collection this widget works on.
* \param propertyCollection New PropertyCollection for this widget, may be 0.
* \param propertyCollection New HasPropertyCollection instance for this widget, may be 0.
*/
void updatePropCollection(PropertyCollection* propertyCollection);
void updatePropCollection(HasPropertyCollection* propertyCollection);
private:
......@@ -41,7 +41,7 @@ namespace TUMVis {
*/
void setupWidget();
PropertyCollection* _propCollection; ///< The PropertyCollection this widget is currently working on.
HasPropertyCollection* _propCollection; ///< The HasPropertyCollection instance this widget is currently working on.
QVBoxLayout* _layout;
QList<QWidget*> _widgetList;
};
......
#include "propertywidgetfactory.h"
#include "application/gui/properties/abstractpropertywidget.h"
#include "application/gui/properties/stringpropertywidget.h"
#include "core/properties/abstractproperty.h"
#include "core/properties/genericproperty.h"
#include "core/properties/transferfunctionproperty.h"
namespace TUMVis {
AbstractPropertyWidget* PropertyWidgetFactory::createWidget(AbstractProperty* property) {
tgtAssert(property != 0, "Property must not be 0.");
if (StringProperty* tester = dynamic_cast<StringProperty*>(property)) {
return new StringPropertyWidget(tester);
}
return 0;
}
}
\ No newline at end of file
#ifndef PROPERTYWIDGETFACTORY_H__
#define PROPERTYWIDGETFACTORY_H__
namespace TUMVis {
class AbstractPropertyWidget;
class AbstractProperty;
class PropertyWidgetFactory {
public:
/**
*
* \param property
* \return
*/
static AbstractPropertyWidget* createWidget(AbstractProperty* property);
};
}
#endif // PROPERTYWIDGETFACTORY_H__
#include "stringpropertywidget.h"
namespace TUMVis {
StringPropertyWidget::StringPropertyWidget(StringProperty* property, QWidget* parent /*= 0*/)
: AbstractPropertyWidget(property, parent)
, _lineEdit(0)
{
_lineEdit = new QLineEdit(QString::fromStdString(property->getValue()));
addWidget(_lineEdit);
connect(_lineEdit, SIGNAL(textChanged(const QString&)), this, SIGNAL(onTextChanged(const QString&)));
}
StringPropertyWidget::~StringPropertyWidget() {
}
void StringPropertyWidget::updateWidgetFromProperty() {
StringProperty* prop = static_cast<StringProperty*>(_property);
QString qs = QString::fromStdString(prop->getValue());
if (_lineEdit->text() != qs) {
_lineEdit->blockSignals(true);
_lineEdit->setText(qs);
_lineEdit->blockSignals(false);
}
}
void StringPropertyWidget::onTextChanged(const QString& text) {
StringProperty* prop = static_cast<StringProperty*>(_property);
prop->setValue(text.toStdString());
}
}
\ No newline at end of file
#ifndef STRINGPROPERTYWIDGET_H__
#define STRINGPROPERTYWIDGET_H__
#include "application/gui/properties/abstractpropertywidget.h"
#include "core/properties/genericproperty.h"
#include <QLineEdit>
namespace TUMVis {
/**
* Widget for a StringProperty
*/
class StringPropertyWidget : public AbstractPropertyWidget {
Q_OBJECT;
public:
/**
* Creates a new PropertyWidget for the property \a property.
* \param property The property the widget shall handle
* \param parent Parent Qt widget
*/
StringPropertyWidget(StringProperty* property, QWidget* parent = 0);
/**
* Destructor
*/
virtual ~StringPropertyWidget();
protected:
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void updateWidgetFromProperty();
private slots:
void onTextChanged(const QString& text);
private:
QLineEdit* _lineEdit;
};
}
#endif // STRINGPROPERTYWIDGET_H__
......@@ -38,7 +38,12 @@ namespace TUMVis {
}
}
void AbstractPipeline::onNotify(const ProcessorObserverArgs& poa) {
void AbstractPipeline::onPropertyChanged(const AbstractProperty* prop) {
_invalidationLevel.setLevel(InvalidationLevel::INVALID_RESULT);
s_PipelineInvalidated();
}
void AbstractPipeline::onProcessorInvalidated(const AbstractProcessor* processor) {
_invalidationLevel.setLevel(InvalidationLevel::INVALID_RESULT);
s_PipelineInvalidated();
}
......
......@@ -20,7 +20,7 @@ namespace TUMVis {
* Abstract base class for TUMVis Pipelines.
*
*/
class AbstractPipeline : public HasPropertyCollection, public GenericObserver<ProcessorObserverArgs> {
class AbstractPipeline : public HasPropertyCollection {
friend class PipelineEvaluator;
public:
......@@ -72,19 +72,25 @@ namespace TUMVis {
*/
virtual const std::string getName() const = 0;
/**
* Gets called when one of the observed processors changed and thus notifies its observers.
* The default behaviour is just to set the invalidation level to invalid.
* \sa GenericObserver::onNotify, AbstractProcessor
* \param poa ProcessorObserverArgs ObserverArgument struct containing the emitting processor and its InvalidationLevel
*/
virtual void onNotify(const ProcessorObserverArgs& poa);
InvalidationLevel& getInvalidationLevel();
sigslot::signal0<> s_PipelineInvalidated;
/**
* Slot getting called when one of the observed properties changed and notifies its observers.
* The default behaviour is just to set the invalidation level to invalid.
* \param prop Property that emitted the signal
*/
virtual void onPropertyChanged(const AbstractProperty* prop);
/**
* Slot getting called when one of the observed processors got invalidated.
* The default behaviour is just to set the invalidation level to invalid.
* \param processor The processor that emitted the signal
*/
virtual void onProcessorInvalidated(const AbstractProcessor* processor);
protected:
/**
* Executes the processor \a processor on the pipeline's data and locks its properties meanwhile.
......
......@@ -23,14 +23,10 @@ namespace TUMVis {
// If processor is no longer valid, notify observers
if (! _invalidationLevel.isValid()) {
notifyObservers(ProcessorObserverArgs(this, _invalidationLevel));
s_invalidated(this);
}
}
void AbstractProcessor::onNotify(const PropertyObserverArgs& poa) {
applyInvalidationLevel(poa._invalidationLevel);
}
void AbstractProcessor::init() {
}
......@@ -39,12 +35,15 @@ namespace TUMVis {
void AbstractProcessor::lockProperties() {
_properties.lockAllProperties();
lockAllProperties();
}
void AbstractProcessor::unlockProperties() {
_properties.unlockAllProperties();
unlockAllProperties();
}
void AbstractProcessor::onPropertyChanged(const AbstractProperty* prop) {
applyInvalidationLevel(prop->getInvalidationLevel());
}
}
#ifndef PROCESSOR_H__
#define PROCESSOR_H__
#include "sigslot/sigslot.h"
#include "tgt/logmanager.h"
#include "core/tools/invalidationlevel.h"
#include "core/datastructures/datacontainer.h"
......@@ -11,26 +12,6 @@
#include <vector>
namespace TUMVis {
class AbstractProcessor;
/**
* Observer Arguments for Property observers.
*/
struct ProcessorObserverArgs : public GenericObserverArgs<AbstractProcessor> {
/**
* Creates new PropertyObserverArgs.
* \param subject Subject that emits the notification
* \param invalidationLevel Invalidation level of that property
*/
ProcessorObserverArgs(const AbstractProcessor* subject, InvalidationLevel invalidationLevel)
: GenericObserverArgs<AbstractProcessor>(subject)
, _invalidationLevel(invalidationLevel)
{}
InvalidationLevel _invalidationLevel; ///< Invalidation level of that processor
};
/**
* Abstract base class for TUMVis Processors.
* A processor implements a specific task, which it performs on the DataCollection passed
......@@ -44,7 +25,7 @@ namespace TUMVis {
*
* \sa AbstractPipeline
*/
class AbstractProcessor : public HasPropertyCollection, public GenericObserver<PropertyObserverArgs>, public GenericObservable<ProcessorObserverArgs> {
class AbstractProcessor : public HasPropertyCollection {
/**
* We have to find a trade-off:
......@@ -108,13 +89,6 @@ namespace TUMVis {
*/
void applyInvalidationLevel(InvalidationLevel il);
/**
* Gets called when one of the observed properties changed notifies its observers.
* \sa GenericObserver::onNotify, AbstractProperty
* \param poa PropertyObserverArgs ObserverArgument struct containing the emitting property and its InvalidationLevel
*/
virtual void onNotify(const PropertyObserverArgs& poa);
/**
* Locks all properties in the processor's PropertyCollection and marks them as "in use".
* \sa AbstractProcessor::unlock
......@@ -128,6 +102,16 @@ namespace TUMVis {
void unlockProperties();
/// Signal emitted when the processor has been invalidated.
sigslot::signal1<const AbstractProcessor*> s_invalidated;
/**
* Slot getting called when one of the observed properties changed and notifies its observers.
* \param prop Property that emitted the signal
*/
virtual void onPropertyChanged(const AbstractProperty* prop);
protected:
InvalidationLevel _invalidationLevel; ///< current invalidation level of this processor
......
......@@ -19,7 +19,7 @@ namespace TUMVis {
* Abstract base class for TUMVis Pipelines.
*
*/
class VisualizationPipeline : public AbstractPipeline, public tgt::EventListener, public sigslot::has_slots<> {
class VisualizationPipeline : public AbstractPipeline, public tgt::EventListener {
public:
/**
* Creates a VisualizationPipeline.
......
......@@ -7,7 +7,7 @@ namespace TUMVis {
, _renderTargetSize("canvasSize", "Canvas Size", canvasSize.getValue())
{
canvasSize.addSharedProperty(&_renderTargetSize);
_renderTargetSize.addObserver(this);
_renderTargetSize.s_changed.connect<VisualizationProcessor>(this, &VisualizationProcessor::onPropertyChanged);
}
VisualizationProcessor::~VisualizationProcessor() {
......
#ifndef ABSTRACTPROPERTY_H__
#define ABSTRACTPROPERTY_H__
#include "sigslot/sigslot.h"
#include "tbb/include/tbb/spin_mutex.h"
#include "tgt/logmanager.h"
#include "core/tools/invalidationlevel.h"
#include "core/tools/observer.h"
#include <set>
#include <string>
......@@ -15,31 +15,13 @@ namespace TUMVis {
// But as its only used as pointer within the template, it should be okay.
class AbstractProperty;
/**
* Observer Arguments for Property observers.
*/
struct PropertyObserverArgs : public GenericObserverArgs<AbstractProperty> {
/**
* Creates new PropertyObserverArgs.
* \param subject Subject that emits the notification
* \param invalidationLevel Invalidation level of that property
*/
PropertyObserverArgs(const AbstractProperty* subject, InvalidationLevel invalidationLevel)
: GenericObserverArgs<AbstractProperty>(subject)
, _invalidationLevel(invalidationLevel)
{}
InvalidationLevel _invalidationLevel; ///< Invalidation level of that property
};
/**
* Abstract base class for TUMVis Property.
*
* \todo Add PropertyWidgets, add clone()?
* Think about a reasonable locking mechanism and implement that
*/
class AbstractProperty : public GenericObservable<PropertyObserverArgs> {
class AbstractProperty {
public:
/**
* Creates a new AbstractProperty
......@@ -117,6 +99,9 @@ namespace TUMVis {
virtual void unlock();
/// Signal emitted, when the property changes.
sigslot::signal1<const AbstractProperty*> s_changed;
protected:
// DO NOT REMOVE THE CONSTNESS OF _name. PropertyCollection relies on it!
......
......@@ -103,7 +103,11 @@ namespace TUMVis {
static const std::string loggerCat_;
};
// - template implementation ----------------------------------------------------------------------
// = Typedefs =====================================================================================
typedef GenericProperty<std::string> StringProperty;
// = Template Implementation ======================================================================
template<typename T>
TUMVis::GenericProperty<T>::GenericProperty(const std::string& name, const std::string& title, const T& value, InvalidationLevel il /*= InvalidationLevel::INVALID_RESULT*/)
......@@ -174,7 +178,7 @@ namespace TUMVis {
GenericProperty<T>* child = static_cast< GenericProperty<T>* >(*it);
child->setValue(value);
}
notifyObservers(PropertyObserverArgs(this, _invalidationLevel));
s_changed(this);
}
template<typename T>
......
......@@ -101,8 +101,11 @@ namespace TUMVis {
static const std::string loggerCat_;
};
// = Typedefs =====================================================================================
// - template implementation ----------------------------------------------------------------------