Commit 94f27ca9 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Introducing WorkflowControllerWidget draft.

The WorkflowControllerWidget resides as new tab on the right-hand dock area of the main window and allows to interact with an AbstractWorkflow instance.

refs #13
parent 3bbbdc6b
......@@ -40,6 +40,7 @@ SET(CampvisApplicationToBeMocced
gui/logviewerwidget.h
gui/loghighlighter.h
gui/scriptingwidget.h
gui/workflowcontrollerwidget.h
gui/mdi/mdidockarea.h
gui/mdi/mdidockablewindow.h
gui/mdi/mdidockedwindow.h
......
......@@ -61,6 +61,7 @@ namespace campvis {
, _selectedDataContainer(0)
, _logViewer(0)
, _scriptingConsoleWidget(nullptr)
, _workflowWidget(nullptr)
{
cgtAssert(_application != 0, "Application must not be 0.");
ui.setupUi(this);
......@@ -141,6 +142,9 @@ namespace campvis {
ui.scriptingConsoleDock->setVisible(false);
#endif
_workflowWidget = new WorkflowControllerWidget(this);
ui.workflowDock->setWidget(_workflowWidget);
_dcInspectorWidget = new DataContainerInspectorWidget();
this->populateMainMenu();
......@@ -187,6 +191,7 @@ namespace campvis {
toolsMenu->addAction(ui.pipelineTreeDock->toggleViewAction());
toolsMenu->addAction(ui.pipelinePropertiesDock->toggleViewAction());
toolsMenu->addAction(ui.logViewerDock->toggleViewAction());
toolsMenu->addAction(ui.workflowDock->toggleViewAction());
}
bool MainWindow::eventFilter(QObject* watched, QEvent* event) {
......
......@@ -32,6 +32,7 @@
#include "application/gui/properties/propertycollectionwidget.h"
#include "application/gui/logviewerwidget.h"
#include "application/gui/scriptingwidget.h"
#include "application/gui/workflowcontrollerwidget.h"
#include "application/tools/qtexteditlog.h"
#include "application/ui_mainwindow.h"
......@@ -190,6 +191,7 @@ namespace campvis {
LogViewerWidget* _logViewer; ///< Widget displaying log messages
ScriptingWidget* _scriptingConsoleWidget; ///< Widget showing the scripting console (if available)
WorkflowControllerWidget* _workflowWidget; ///< Widget showing the workflow controller
std::vector<QDockWidget*> _primaryDocks; ///< Docks located in top docking area of the main window
};
......
// ================================================================================================
//
// 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 "workflowcontrollerwidget.h"
#include "cgt/assert.h"
#include "application/qtjobprocessor.h"
#include <QLabel>
#include <QGridLayout>
#include <QPushButton>
#include <QScrollArea>
#include <QSignalMapper>
#include <QVBoxLayout>
namespace campvis {
const std::string WorkflowControllerWidget::loggerCat_ = "CAMPVis.application.WorkflowControllerWidget";
WorkflowControllerWidget::WorkflowControllerWidget(QWidget* parent /*= nullptr*/)
: QWidget(parent)
, _workflow(nullptr)
, _isBackWardsStep(false)
, _signalMapper(nullptr)
, _lblWorkflowStage(nullptr)
, _propertyCollectionWidget(nullptr)
, _btnPrevStage(nullptr)
, _layoutNextStages(nullptr)
{
setupGUI();
}
WorkflowControllerWidget::~WorkflowControllerWidget() {
clearNextStagesLayout();
}
void WorkflowControllerWidget::init() {
if (_workflow != nullptr)
_workflow->init();
}
void WorkflowControllerWidget::deinit() {
if (_workflow != nullptr)
_workflow->deinit();
}
void WorkflowControllerWidget::setWorkflow(AbstractWorkflow* workflow) {
if (_workflow != nullptr) {
_workflow->s_stageChanged.disconnect(this);
_workflow->s_stageAvailabilityChanged.disconnect(this);
}
_workflow = workflow;
_stageHistory.clear();
QtJobProc.enqueueJob([&]() {
if (_workflow != nullptr) {
// FIXME: Taking the first of the DataContainers here is not really beautiful!
_propertyCollectionWidget->updatePropCollection(_workflow, _workflow->getDataContainers().front());
_workflow->s_stageChanged.connect(this, &WorkflowControllerWidget::onStageChanged);
_workflow->s_stageAvailabilityChanged.connect(this, &WorkflowControllerWidget::onStageAvailabilityChanged);
}
else {
_propertyCollectionWidget->updatePropCollection(nullptr, nullptr);
_lblWorkflowStage->setText(tr("No Workflow Loaded."));
}
});
}
void WorkflowControllerWidget::onPrevButtonClicked() {
if (!_stageHistory.empty()) {
int previousStage = _stageHistory.back();
_stageHistory.pop_back();
_isBackWardsStep = true;
_workflow->setCurrentStage(previousStage);
}
}
void WorkflowControllerWidget::onStageSelectionButtonClicked(int id) {
_workflow->setCurrentStage(id);
}
void WorkflowControllerWidget::setupGUI() {
QGridLayout* layout = new QGridLayout(this);
_lblWorkflowStage = new QLabel(tr("Current Stage: n/a"), this);
layout->addWidget(_lblWorkflowStage, 0, 0, 1, 2);
QScrollArea* sa = new QScrollArea(this);
sa->setWidgetResizable(true);
sa->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
sa->setFrameStyle(QScrollArea::NoFrame);
_propertyCollectionWidget = new PropertyCollectionWidget(this);
sa->setWidget(_propertyCollectionWidget);
layout->addWidget(sa, 1, 0, 1, 2);
_btnPrevStage = new QPushButton("<< n/a");
_btnPrevStage->setEnabled(false);
layout->addWidget(_btnPrevStage, 2, 0, 1, 1);
_layoutNextStages = new QVBoxLayout();
layout->addLayout(_layoutNextStages, 2, 1, 1, 1);
_signalMapper = new QSignalMapper(this);
populateNextStagesLayout();
connect(_btnPrevStage, SIGNAL(clicked()), this, SLOT(onPrevButtonClicked()));
connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(onStageSelectionButtonClicked(int)));
}
void WorkflowControllerWidget::clearNextStagesLayout() {
for (auto it = _nextButtons.begin(); it != _nextButtons.end(); ++it) {
_layoutNextStages->removeWidget(it->first);
delete it->first;
}
_nextButtons.clear();
}
void WorkflowControllerWidget::populateNextStagesLayout() {
// first, remove all buttons from the layout
clearNextStagesLayout();
// now, populate with buttons for the current stage
if (_workflow != nullptr) {
const AbstractWorkflow::Stage& s = _workflow->getCurrentStage();
for (auto it = s._possibleTransitions.begin(); it != s._possibleTransitions.end(); ++it) {
QPushButton* theButton = new QPushButton(QString::fromStdString((*it)->_title + " >>"));
_layoutNextStages->addWidget(theButton);
_nextButtons.push_back(std::make_pair(theButton, (*it)->_id));
_signalMapper->setMapping(theButton, (*it)->_id);
connect(theButton, SIGNAL(clicked()), _signalMapper, SLOT(map()));
}
onStageAvailabilityChanged();
}
}
void WorkflowControllerWidget::onStageChanged(int previousStage, int currentStage) {
if (!_isBackWardsStep)
_stageHistory.push_back(previousStage);
_isBackWardsStep = false;
QtJobProc.enqueueJob([=]() {
populateNextStagesLayout();
const AbstractWorkflow::Stage& s = _workflow->getCurrentStage();
_lblWorkflowStage->setText(QString::fromStdString(s._title));
});
}
void WorkflowControllerWidget::onStageAvailabilityChanged() {
for (auto it = _nextButtons.begin(); it != _nextButtons.end(); ++it) {
int theStage = it->second;
it->first->setEnabled(_workflow->isStageAvailable(theStage));
}
}
}
// ================================================================================================
//
// 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 WORKFLOWCONTROLLERWIDGET_H__
#define WORKFLOWCONTROLLERWIDGET_H__
#include "core/pipeline/abstractworkflow.h"
#include "application/gui/properties/propertycollectionwidget.h"
#include <QLabel>
#include <QWidget>
#include <list>
#include <utility>
#include <vector>
class QPushButton;
class QSignalMapper;
class QVBoxLayout;
namespace campvis {
/**
* This widget is used to offer a user interface to an \a AbstractWorkflow instance.
*
* It has two buttons to navigate through the workflow and displays the properties
* of the \a AbstractWorkflow using a \a PropertyCollectionWidget.
*/
class WorkflowControllerWidget : public QWidget, public sigslot::has_slots {
Q_OBJECT;
public:
/**
* Creates a new WorkflowControllerWidget.
* \param parent Parent Qt widget, may be 0 (default)
*/
explicit WorkflowControllerWidget(QWidget* parent = nullptr);
/**
* Destructor.
*/
~WorkflowControllerWidget();
/// dummy. may be useful at some point
void init();
/// dummy. may be useful at some point
void deinit();
/**
* Sets the AbstractWorkflow that should be handled by this widget.
* Sets up the signal/slot connections.
*/
void setWorkflow(AbstractWorkflow* workflow);
public slots:
void onPrevButtonClicked();
void onStageSelectionButtonClicked(int id);
private:
/// Setup the the workflow controller's GUI.
void setupGUI();
void clearNextStagesLayout();
void populateNextStagesLayout();
/// connects to \a AbstractWorkflow::s_stageChanged signal
void onStageChanged(int previousStage, int currentStage);
/// connects to \a AbstractWorkflow::s_stageAvailabilityChanged signal
void onStageAvailabilityChanged();
AbstractWorkflow* _workflow; ///< the currently associated \a WorkflowController
std::list<int> _stageHistory; ///< History of the visited stages, used to provide "go back" functionality
bool _isBackWardsStep; ///< Flag whether current stage selection is a backwards step (then don't add previous stage to history)
/// All existing buttons to move to next stage paired with the stage they advance to.
std::vector< std::pair<QPushButton*, int> > _nextButtons;
QSignalMapper* _signalMapper;
QLabel* _lblWorkflowStage;
PropertyCollectionWidget* _propertyCollectionWidget;
QPushButton* _btnPrevStage;
QVBoxLayout* _layoutNextStages;
static const std::string loggerCat_;
};
}
#endif // WORKFLOWCONTROLLERWIDGET_H__
......@@ -13,6 +13,9 @@
<property name="windowTitle">
<string>MainWindow</string>
</property>
<property name="dockNestingEnabled">
<bool>true</bool>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
......@@ -58,15 +61,24 @@
</attribute>
<widget class="QWidget" name="logViewerDockContents"/>
</widget>
<widget class="QDockWidget" name="scriptingConsoleDock">
<property name="windowTitle">
<string>Scripting Console</string>
</property>
<attribute name="dockWidgetArea">
<number>8</number>
</attribute>
<widget class="QWidget" name="scriptingConsoleDockContents"/>
</widget>
<widget class="QDockWidget" name="scriptingConsoleDock">
<property name="windowTitle">
<string>Scripting Console</string>
</property>
<attribute name="dockWidgetArea">
<number>8</number>
</attribute>
<widget class="QWidget" name="scriptingConsoleDockContents"/>
</widget>
<widget class="QDockWidget" name="workflowDock">
<property name="windowTitle">
<string>Workflow</string>
</property>
<attribute name="dockWidgetArea">
<number>2</number>
</attribute>
<widget class="QWidget" name="workflowDockContents"/>
</widget>
</widget>
<resources/>
<connections/>
......
......@@ -28,7 +28,7 @@
#include "cgt/assert.h"
namespace campvis {
const std::string AbstractPipeline::loggerCat_ = "CAMPVis.core.pipeline.AbstractWorkflow";
const std::string AbstractWorkflow::loggerCat_ = "CAMPVis.core.pipeline.AbstractWorkflow";
AbstractWorkflow::AbstractWorkflow()
: _currentStage(0)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment