Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

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