diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.cpp b/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.cpp
index 82656b39a2..aeb91124d6 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.cpp
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.cpp
@@ -1,845 +1,900 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "QmitkSegmentationTaskListWidget.h"
#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
#include
-#include
+#include
#include
#include
+#include
+
#include
#include
#include
#include
#include
namespace
{
mitk::IPreferences* GetSegmentationPreferences()
{
return mitk::CoreServices::GetPreferencesService()->GetSystemPreferences()->Node("/org.mitk.views.segmentation");
}
std::filesystem::path GetInputLocation(const mitk::BaseData* data)
{
std::string result;
if (data != nullptr)
data->GetPropertyList()->GetStringProperty("MITK.IO.reader.inputlocation", result);
return result;
}
QString ColorString(const QString& string, const QColor& color, const QColor& backgroundColor = QColor::Invalid)
{
if (!color.isValid() && !backgroundColor.isValid())
return string;
auto result = QStringLiteral("%1 ").arg(string);
return result;
}
}
/* This constructor has three objectives:
* 1. Do widget initialization that cannot be done in the .ui file
* 2. Connect signals and slots
* 3. Explicitly trigger a reset to a valid initial widget state
*/
QmitkSegmentationTaskListWidget::QmitkSegmentationTaskListWidget(QWidget* parent)
: QWidget(parent),
m_Ui(new Ui::QmitkSegmentationTaskListWidget),
m_FileSystemWatcher(new QFileSystemWatcher(this)),
m_UnsavedChanges(false)
{
m_Ui->setupUi(this);
m_Ui->selectionWidget->SetSelectionIsOptional(true);
m_Ui->selectionWidget->SetEmptyInfo(QStringLiteral("Select a segmentation task list"));
m_Ui->selectionWidget->SetAutoSelectNewNodes(true);
m_Ui->selectionWidget->SetNodePredicate(mitk::TNodePredicateDataType::New());
m_Ui->progressBar->setStyleSheet(QString("QProgressBar::chunk { background-color: %1; }").arg(QmitkStyleManager::GetIconAccentColor()));
+ m_Ui->storeButton->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg")));
+
using Self = QmitkSegmentationTaskListWidget;
connect(m_Ui->selectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &Self::OnSelectionChanged);
connect(m_Ui->previousButton, &QToolButton::clicked, this, &Self::OnPreviousButtonClicked);
connect(m_Ui->nextButton, &QToolButton::clicked, this, &Self::OnNextButtonClicked);
connect(m_Ui->loadButton, &QPushButton::clicked, this, &Self::OnLoadButtonClicked);
+ connect(m_Ui->storeButton, &QPushButton::clicked, this, &Self::OnStoreButtonClicked);
+ connect(m_Ui->acceptButton, &QPushButton::clicked, this, &Self::OnAcceptButtonClicked);
connect(m_FileSystemWatcher, &QFileSystemWatcher::directoryChanged, this, &Self::OnResultDirectoryChanged);
auto* prevShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_P), this);
connect(prevShortcut, &QShortcut::activated, this, &Self::OnPreviousTaskShortcutActivated);
auto* prevUndoneShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key::Key_P), this);
connect(prevUndoneShortcut, &QShortcut::activated, this, &Self::OnPreviousTaskShortcutActivated);
auto* nextShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_N), this);
connect(nextShortcut, &QShortcut::activated, this, &Self::OnNextTaskShortcutActivated);
auto* nextUndoneShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key::Key_N), this);
connect(nextUndoneShortcut, &QShortcut::activated, this, &Self::OnNextTaskShortcutActivated);
auto* loadShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_L), this);
connect(loadShortcut, &QShortcut::activated, this, &Self::OnLoadTaskShortcutActivated);
+
+ auto* storeShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_S), parent);
+ connect(storeShortcut, &QShortcut::activated, this, &Self::OnStoreInterimResultShortcutActivated);
+
+ auto* acceptShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_A), parent);
+ connect(acceptShortcut, &QShortcut::activated, this, &Self::OnAcceptSegmentationShortcutActivated);
+
+ this->ResetControls();
}
QmitkSegmentationTaskListWidget::~QmitkSegmentationTaskListWidget()
{
}
void QmitkSegmentationTaskListWidget::SetDataStorage(mitk::DataStorage* dataStorage)
{
m_DataStorage = dataStorage;
m_Ui->selectionWidget->SetDataStorage(dataStorage); // Triggers OnSelectionChanged()
}
void QmitkSegmentationTaskListWidget::OnUnsavedChangesSaved()
{
if (m_UnsavedChanges)
{
m_UnsavedChanges = false;
if (this->ActiveTaskIsShown())
this->UpdateDetailsLabel();
}
}
/* Make sure that the widget transitions into a valid state whenever the
* selection changes.
*/
void QmitkSegmentationTaskListWidget::OnSelectionChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes)
{
this->UnloadTasks();
this->ResetControls();
if (!nodes.empty())
{
m_TaskListNode = nodes.front();
auto taskList = dynamic_cast(m_TaskListNode->GetData());
if (taskList != nullptr)
{
this->OnTaskListChanged(taskList);
return;
}
}
this->SetTaskList(nullptr);
m_TaskListNode = nullptr;
}
/* Reset all controls to a default state as a common basis for further
* adjustments.
*/
void QmitkSegmentationTaskListWidget::ResetControls()
{
m_Ui->progressBar->setEnabled(false);
m_Ui->progressBar->setFormat("");
m_Ui->progressBar->setValue(0);
m_Ui->progressBar->setMaximum(1);
m_Ui->previousButton->setEnabled(false);
m_Ui->nextButton->setEnabled(false);
this->UpdateLoadButton();
this->UpdateDetailsLabel();
+ this->UpdateStoreAndAcceptButtons();
}
/* If the segmentation task changed, reset all member variables to expected
* default values and reset the file system watcher.
*/
void QmitkSegmentationTaskListWidget::SetTaskList(mitk::SegmentationTaskList* taskList)
{
if (m_TaskList != taskList)
{
m_TaskList = taskList;
if (taskList != nullptr)
{
this->SetCurrentTaskIndex(0);
}
else
{
this->SetCurrentTaskIndex(std::nullopt);
}
this->ResetFileSystemWatcher();
}
}
void QmitkSegmentationTaskListWidget::ResetFileSystemWatcher()
{
auto paths = m_FileSystemWatcher->directories();
if (!paths.empty())
m_FileSystemWatcher->removePaths(paths);
if (m_TaskList.IsNotNull())
{
for (const auto& task : *m_TaskList)
{
auto resultPath = m_TaskList->GetAbsolutePath(task.GetResult()).remove_filename();
if (!std::filesystem::exists(resultPath))
{
try
{
std::filesystem::create_directories(resultPath);
}
catch (const std::filesystem::filesystem_error& e)
{
MITK_ERROR << e.what();
}
}
if (std::filesystem::exists(resultPath))
m_FileSystemWatcher->addPath(QString::fromStdString(resultPath.string()));
}
}
}
void QmitkSegmentationTaskListWidget::OnResultDirectoryChanged(const QString&)
{
// TODO: If a segmentation was modified ("Unsaved changes"), saved ("Done"), and then the file is deleted, the status should be "Unsaved changes" instead of "Not done".
this->UpdateProgressBar();
this->UpdateDetailsLabel();
}
void QmitkSegmentationTaskListWidget::UpdateProgressBar()
{
int progress = 0;
for (size_t i = 0; i < m_TaskList->GetNumberOfTasks(); ++i)
{
if (m_TaskList->IsDone(i))
++progress;
}
m_Ui->progressBar->setValue(progress);
}
/* Provided that a valid segmentation task list is currently selected and the
* widget is in its default state, update all controls accordingly.
* TODO: Then, load the first unfinished task, if any.
*/
void QmitkSegmentationTaskListWidget::OnTaskListChanged(mitk::SegmentationTaskList* taskList)
{
this->SetTaskList(taskList);
const auto numTasks = taskList->GetNumberOfTasks();
m_Ui->progressBar->setMaximum(numTasks);
m_Ui->progressBar->setFormat(QStringLiteral("%v/%m Task(s) done"));
m_Ui->progressBar->setEnabled(true);
this->UpdateProgressBar();
m_Ui->loadButton->setEnabled(true);
if (numTasks > 1)
m_Ui->nextButton->setEnabled(true);
// TODO: This line should be enough but it is happening too early even before
// the RenderingManager has any registered render windows, resulting in mismatching
// renderer and data geometries.
// this->LoadNextUnfinishedTask();
}
/* If possible, change the currently displayed task to the previous task.
* Enable/disable navigation buttons according to the task's position.
*/
void QmitkSegmentationTaskListWidget::OnPreviousButtonClicked()
{
auto current = m_CurrentTaskIndex.value();
// If the shift modifier key is pressed, look for the previous undone task.
if (QApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier))
{
if (current > 0)
{
for (decltype(current) i = current; i > 0; --i)
{
if (!m_TaskList->IsDone(i - 1))
{
this->SetCurrentTaskIndex(i - 1);
break;
}
}
}
}
else
{
if (current != 0)
this->SetCurrentTaskIndex(current - 1);
}
this->UpdateNavigationButtons();
}
/* If possible, change the currently displayed task to the next task.
* Enable/disable navigation buttons according to the task's position.
*/
void QmitkSegmentationTaskListWidget::OnNextButtonClicked()
{
const auto numTasks = m_TaskList->GetNumberOfTasks();
auto current = m_CurrentTaskIndex.value();
// If the shift modifier key is pressed, look for the next undone task.
if (QApplication::queryKeyboardModifiers().testFlag(Qt::ShiftModifier))
{
for (std::remove_const_t i = current + 1; i < numTasks; ++i)
{
if (!m_TaskList->IsDone(i))
{
this->SetCurrentTaskIndex(i);
break;
}
}
}
else
{
if (current < numTasks - 1)
this->SetCurrentTaskIndex(current + 1);
}
this->UpdateNavigationButtons();
}
void QmitkSegmentationTaskListWidget::UpdateNavigationButtons()
{
if (m_TaskList.IsNull() || m_TaskList->GetNumberOfTasks() == 0)
{
m_Ui->previousButton->setEnabled(false);
m_Ui->nextButton->setEnabled(false);
return;
}
const auto maxIndex = m_TaskList->GetNumberOfTasks() - 1;
const auto current = m_CurrentTaskIndex.value();
m_Ui->previousButton->setEnabled(current != 0);
m_Ui->nextButton->setEnabled(current != maxIndex);
}
/* Update affected controls when the currently displayed task changed.
*/
void QmitkSegmentationTaskListWidget::OnCurrentTaskChanged()
{
this->UpdateLoadButton();
this->UpdateNavigationButtons();
this->UpdateDetailsLabel();
+ this->UpdateStoreAndAcceptButtons();
}
/* Update the load button according to the currently displayed task.
*/
void QmitkSegmentationTaskListWidget::UpdateLoadButton()
{
auto text = !this->ActiveTaskIsShown()
? QStringLiteral("Load task")
: QStringLiteral("Task");
if (m_CurrentTaskIndex.has_value())
{
const auto current = m_CurrentTaskIndex.value();
if (m_TaskList.IsNotNull())
{
text += QString(" %1/%2").arg(current + 1).arg(m_TaskList->GetNumberOfTasks());
if (m_TaskList->HasName(current))
text += QStringLiteral(":\n") + QString::fromStdString(m_TaskList->GetName(current));
}
m_Ui->loadButton->setDisabled(this->ActiveTaskIsShown());
}
else
{
m_Ui->loadButton->setEnabled(false);
}
m_Ui->loadButton->setText(text);
}
/* Update the details label according to the currently display task.
* The text is composed of the status of the task and a variable number
* of text blocks according to the optional values provided by the task.
*/
void QmitkSegmentationTaskListWidget::UpdateDetailsLabel()
{
if (!m_CurrentTaskIndex.has_value())
{
m_Ui->detailsLabel->clear();
return;
}
const auto current = m_CurrentTaskIndex.value();
bool isDone = m_TaskList->IsDone(current);
auto details = QString("Status: %1 / ").arg(this->ActiveTaskIsShown()
? ColorString("Active", Qt::white, QColor(Qt::green).darker())
: ColorString("Inactive", Qt::white, QColor(Qt::red).darker()));
if (m_UnsavedChanges && this->ActiveTaskIsShown())
{
details += QString("%1
").arg(ColorString("Unsaved changes", Qt::white, QColor(Qt::red).darker()));
}
else
{
details += QString("%1
").arg(isDone
? ColorString("Done", Qt::white, QColor(Qt::green).darker())
: ColorString("Not done", Qt::white, QColor(Qt::red).darker()));
}
if (m_TaskList->HasDescription(current))
details += QString("Description: %1
").arg(QString::fromStdString(m_TaskList->GetDescription(current)));
QStringList stringList;
if (m_TaskList->HasImage(current))
stringList << QString::fromStdString("Image: " + m_TaskList->GetImage(current).string());
if (m_TaskList->HasSegmentation(current))
stringList << QString::fromStdString("Segmentation: " + m_TaskList->GetSegmentation(current).string());
if (m_TaskList->HasLabelName(current))
stringList << QString::fromStdString("Label name: " + m_TaskList->GetLabelName(current));
if (m_TaskList->HasLabelNameSuggestions(current))
stringList << QString::fromStdString("Label name suggestions: " + m_TaskList->GetLabelNameSuggestions(current).string());
if (m_TaskList->HasPreset(current))
stringList << QString::fromStdString("Label set preset: " + m_TaskList->GetPreset(current).string());
if (m_TaskList->HasDynamic(current))
stringList << QString("Segmentation type: %1").arg(m_TaskList->GetDynamic(current) ? "Dynamic" : "Static");
if (!stringList.empty())
details += QString("%1
").arg(stringList.join(QStringLiteral(" ")));
m_Ui->detailsLabel->setText(details);
}
+void QmitkSegmentationTaskListWidget::UpdateStoreAndAcceptButtons()
+{
+ auto activeTaskIsShown = this->ActiveTaskIsShown();
+
+ m_Ui->storeButton->setVisible(activeTaskIsShown);
+ m_Ui->acceptButton->setEnabled(activeTaskIsShown);
+}
+
/* Load/activate the currently displayed task. Unload all data nodes from
* previously active tasks first, but spare and reuse the image if possible.
*/
void QmitkSegmentationTaskListWidget::OnLoadButtonClicked()
{
if (!this->HandleUnsavedChanges() || m_UnsavedChanges)
return;
m_Ui->loadButton->setEnabled(false);
QApplication::setOverrideCursor(Qt::BusyCursor);
this->LoadTask(this->GetImageDataNode(m_CurrentTaskIndex.value()));
QApplication::restoreOverrideCursor();
}
/* If present, return the image data node for the task with the specified
* index. Otherwise, return nullptr.
*/
mitk::DataNode* QmitkSegmentationTaskListWidget::GetImageDataNode(size_t index) const
{
const auto imagePath = m_TaskList->GetAbsolutePath(m_TaskList->GetImage(index));
auto imageNodes = m_DataStorage->GetDerivations(m_TaskListNode, mitk::NodePredicateFunction::New([imagePath](const mitk::DataNode* node) {
return imagePath == GetInputLocation(node->GetData());
}));
return !imageNodes->empty()
? imageNodes->front()
: nullptr;
}
/* If present, return the segmentation data node for the task with the
* specified index. Otherwise, return nullptr.
*/
mitk::DataNode* QmitkSegmentationTaskListWidget::GetSegmentationDataNode(size_t index) const
{
const auto* imageNode = this->GetImageDataNode(index);
if (imageNode != nullptr)
{
auto segmentations = m_DataStorage->GetDerivations(imageNode, mitk::TNodePredicateDataType::New());
if (!segmentations->empty())
return segmentations->front();
}
return nullptr;
}
/* Unload all task data nodes but spare the passed image data node.
*/
void QmitkSegmentationTaskListWidget::UnloadTasks(const mitk::DataNode* skip)
{
this->UnsubscribeFromActiveSegmentation();
if (m_TaskListNode.IsNotNull())
{
auto imageNodes = m_DataStorage->GetDerivations(m_TaskListNode, mitk::TNodePredicateDataType::New());
for (auto imageNode : *imageNodes)
{
m_DataStorage->Remove(m_DataStorage->GetDerivations(imageNode, nullptr, false));
if (imageNode != skip)
m_DataStorage->Remove(imageNode);
}
}
this->SetActiveTaskIndex(std::nullopt);
}
void QmitkSegmentationTaskListWidget::LoadNextUnfinishedTask()
{
const auto current = m_CurrentTaskIndex.value();
const auto numTasks = m_TaskList->GetNumberOfTasks();
for (size_t unboundNext = current; unboundNext < current + numTasks; ++unboundNext)
{
auto next = unboundNext % numTasks;
if (!m_TaskList->IsDone(next))
{
this->SetCurrentTaskIndex(next);
this->OnLoadButtonClicked();
break;
}
}
}
/* Load/activate the currently displayed task. The task must specify
* an image. The segmentation is either created from scratch with an optional
* name for the first label, possibly based on a label set preset specified by
* the task, or loaded as specified by the task. If a result file does
* exist, it is chosen as segmentation instead.
*/
void QmitkSegmentationTaskListWidget::LoadTask(mitk::DataNode::Pointer imageNode)
{
this->UnloadTasks(imageNode);
const auto current = m_CurrentTaskIndex.value();
mitk::Image::Pointer image;
mitk::LabelSetImage::Pointer segmentation;
try
{
if (imageNode.IsNull())
{
const auto path = m_TaskList->GetAbsolutePath(m_TaskList->GetImage(current));
image = mitk::IOUtil::Load(path.string());
}
const auto path = m_TaskList->GetAbsolutePath(m_TaskList->GetResult(current));
const auto interimPath = m_TaskList->GetInterimPath(path);
if (std::filesystem::exists(path))
{
segmentation = mitk::IOUtil::Load(path.string());
}
else if (std::filesystem::exists(interimPath))
{
segmentation = mitk::IOUtil::Load(interimPath.string());
}
else if (m_TaskList->HasSegmentation(current))
{
const auto path = m_TaskList->GetAbsolutePath(m_TaskList->GetSegmentation(current));
segmentation = mitk::IOUtil::Load(path.string());
}
}
catch (const mitk::Exception&)
{
return;
}
if (imageNode.IsNull())
{
imageNode = mitk::DataNode::New();
imageNode->SetData(image);
m_DataStorage->Add(imageNode, m_TaskListNode);
mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry());
}
else
{
image = static_cast(imageNode->GetData());
}
auto name = "Task " + std::to_string(current + 1);
imageNode->SetName(name);
if (segmentation.IsNull())
{
mitk::Image::ConstPointer templateImage = image;
if (templateImage->GetDimension() > 3)
{
if (m_TaskList->HasDynamic(current))
{
if (!m_TaskList->GetDynamic(current))
templateImage = mitk::SegmentationHelper::GetStaticSegmentationTemplate(image);
}
else
{
QmitkStaticDynamicSegmentationDialog dialog(this);
dialog.SetReferenceImage(templateImage);
dialog.exec();
templateImage = dialog.GetSegmentationTemplate();
}
}
auto segmentationNode = mitk::LabelSetImageHelper::CreateNewSegmentationNode(imageNode, templateImage, name);
segmentation = static_cast(segmentationNode->GetData());
if (m_TaskList->HasPreset(current))
{
const auto path = m_TaskList->GetAbsolutePath(m_TaskList->GetPreset(current));
mitk::LabelSetIOHelper::LoadLabelSetImagePreset(path.string(), segmentation);
}
else
{
auto label = mitk::LabelSetImageHelper::CreateNewLabel(segmentation);
if (m_TaskList->HasLabelName(current))
label->SetName(m_TaskList->GetLabelName(current));
segmentation->GetActiveLabelSet()->AddLabel(label);
}
m_DataStorage->Add(segmentationNode, imageNode);
}
else
{
auto segmentationNode = mitk::DataNode::New();
segmentationNode->SetName(name);
segmentationNode->SetData(segmentation);
m_DataStorage->Add(segmentationNode, imageNode);
}
// Workaround for T29431. Remove when T26953 is fixed.
mitk::DICOMQIPropertyHelper::DeriveDICOMSourceProperties(image, segmentation);
auto prefs = GetSegmentationPreferences();
if (prefs != nullptr)
{
if (m_TaskList->HasLabelNameSuggestions(current))
{
auto path = m_TaskList->GetAbsolutePath(m_TaskList->GetLabelNameSuggestions(current));
prefs->PutBool("default label naming", false);
prefs->Put("label suggestions", path.string());
prefs->PutBool("replace standard suggestions", true);
prefs->PutBool("suggest once", true);
}
else
{
prefs->PutBool("default label naming", true);
prefs->Put("label suggestions", "");
}
}
m_UnsavedChanges = false;
this->SetActiveTaskIndex(current);
this->SubscribeToActiveSegmentation();
this->OnCurrentTaskChanged();
}
void QmitkSegmentationTaskListWidget::SubscribeToActiveSegmentation()
{
if (m_ActiveTaskIndex.has_value())
{
auto segmentationNode = this->GetSegmentationDataNode(m_ActiveTaskIndex.value());
if (segmentationNode != nullptr)
{
auto segmentation = static_cast(segmentationNode->GetData());
auto command = itk::SimpleMemberCommand::New();
command->SetCallbackFunction(this, &QmitkSegmentationTaskListWidget::OnSegmentationModified);
m_SegmentationModifiedObserverTag = segmentation->AddObserver(itk::ModifiedEvent(), command);
}
}
}
void QmitkSegmentationTaskListWidget::UnsubscribeFromActiveSegmentation()
{
if (m_ActiveTaskIndex.has_value() && m_SegmentationModifiedObserverTag.has_value())
{
auto segmentationNode = this->GetSegmentationDataNode(m_ActiveTaskIndex.value());
if (segmentationNode != nullptr)
{
auto segmentation = static_cast(segmentationNode->GetData());
segmentation->RemoveObserver(m_SegmentationModifiedObserverTag.value());
}
m_SegmentationModifiedObserverTag.reset();
}
}
void QmitkSegmentationTaskListWidget::OnSegmentationModified()
{
if (!m_UnsavedChanges)
{
m_UnsavedChanges = true;
if (m_ActiveTaskIndex.value() == m_CurrentTaskIndex)
this->UpdateDetailsLabel();
}
}
void QmitkSegmentationTaskListWidget::SetActiveTaskIndex(const std::optional& index)
{
if (m_ActiveTaskIndex != index)
{
m_ActiveTaskIndex = index;
- emit ActiveTaskChanged(m_ActiveTaskIndex);
+ this->UpdateStoreAndAcceptButtons();
}
}
void QmitkSegmentationTaskListWidget::SetCurrentTaskIndex(const std::optional& index)
{
if (m_CurrentTaskIndex != index)
{
m_CurrentTaskIndex = index;
this->OnCurrentTaskChanged();
- emit CurrentTaskChanged(m_CurrentTaskIndex);
+
}
}
bool QmitkSegmentationTaskListWidget::ActiveTaskIsShown() const
{
return m_ActiveTaskIndex.has_value() && m_CurrentTaskIndex.has_value() && m_ActiveTaskIndex == m_CurrentTaskIndex;
}
bool QmitkSegmentationTaskListWidget::HandleUnsavedChanges(const QString& alternativeTitle)
{
if (m_UnsavedChanges)
{
const auto active = m_ActiveTaskIndex.value();
const auto current = m_CurrentTaskIndex.value();
QString title;
if (alternativeTitle.isEmpty())
{
title = QString("Load task %1").arg(current + 1);
if (m_TaskList->HasName(current))
title += ": " + QString::fromStdString(m_TaskList->GetName(current));
}
else
{
title = alternativeTitle;
}
auto text = QString("The currently active task %1 ").arg(active + 1);
if (m_TaskList->HasName(active))
text += "(" + QString::fromStdString(m_TaskList->GetName(active)) + ") ";
text += "has unsaved changes.";
auto reply = QMessageBox::question(this, title, text, QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel, QMessageBox::Cancel);
switch (reply)
{
case QMessageBox::Save:
this->SaveActiveTask(!std::filesystem::exists(m_TaskList->GetResult(active)));
break;
case QMessageBox::Discard:
m_UnsavedChanges = false;
break;
default:
return false;
}
}
return true;
}
void QmitkSegmentationTaskListWidget::SaveActiveTask(bool saveAsIntermediateResult)
{
if (!m_ActiveTaskIndex.has_value())
return;
QApplication::setOverrideCursor(Qt::BusyCursor);
try
{
const auto active = m_ActiveTaskIndex.value();
m_TaskList->SaveTask(active, this->GetSegmentationDataNode(active)->GetData(), saveAsIntermediateResult);
this->OnUnsavedChangesSaved();
}
catch (const mitk::Exception& e)
{
MITK_ERROR << e;
}
QApplication::restoreOverrideCursor();
}
bool QmitkSegmentationTaskListWidget::OnPreShutdown()
{
return this->HandleUnsavedChanges(QStringLiteral("Application shutdown"));
}
void QmitkSegmentationTaskListWidget::OnPreviousTaskShortcutActivated()
{
m_Ui->previousButton->click();
}
void QmitkSegmentationTaskListWidget::OnNextTaskShortcutActivated()
{
m_Ui->nextButton->click();
}
void QmitkSegmentationTaskListWidget::OnLoadTaskShortcutActivated()
{
m_Ui->loadButton->click();
}
+
+void QmitkSegmentationTaskListWidget::OnStoreInterimResultShortcutActivated()
+{
+ m_Ui->storeButton->click();
+}
+
+void QmitkSegmentationTaskListWidget::OnAcceptSegmentationShortcutActivated()
+{
+ m_Ui->acceptButton->click();
+}
+
+void QmitkSegmentationTaskListWidget::OnStoreButtonClicked()
+{
+ this->SaveActiveTask(true);
+}
+
+void QmitkSegmentationTaskListWidget::OnAcceptButtonClicked()
+{
+ auto* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager();
+ int activeToolId = -1;
+
+ if (toolManager != nullptr)
+ activeToolId = toolManager->GetActiveToolID();
+
+ this->SaveActiveTask();
+ this->LoadNextUnfinishedTask();
+
+ if (toolManager != nullptr)
+ toolManager->ActivateTool(activeToolId);
+}
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.h b/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.h
index d8aebca780..bea9c4f9b8 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.h
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.h
@@ -1,93 +1,98 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef QmitkSegmentationTaskListWidget_h
#define QmitkSegmentationTaskListWidget_h
#include
#include
#include
#include
#include
class QFileSystemWatcher;
namespace Ui
{
class QmitkSegmentationTaskListWidget;
}
class MITKSEGMENTATIONUI_EXPORT QmitkSegmentationTaskListWidget : public QWidget
{
Q_OBJECT
public:
explicit QmitkSegmentationTaskListWidget(QWidget* parent = nullptr);
~QmitkSegmentationTaskListWidget() override;
void SetDataStorage(mitk::DataStorage* dataStorage);
bool ActiveTaskIsShown() const;
void LoadNextUnfinishedTask();
void SaveActiveTask(bool saveAsIntermediateResult = false);
bool OnPreShutdown();
signals:
void ActiveTaskChanged(const std::optional& index);
void CurrentTaskChanged(const std::optional& index);
private:
void OnSelectionChanged(const QmitkSingleNodeSelectionWidget::NodeList& nodes);
void ResetControls();
void SetTaskList(mitk::SegmentationTaskList* task);
void ResetFileSystemWatcher();
void OnResultDirectoryChanged(const QString&);
void UpdateProgressBar();
void OnTaskListChanged(mitk::SegmentationTaskList* task);
void OnPreviousButtonClicked();
void OnNextButtonClicked();
void OnCurrentTaskChanged();
void UpdateLoadButton();
void UpdateNavigationButtons();
void UpdateDetailsLabel();
+ void UpdateStoreAndAcceptButtons();
void OnLoadButtonClicked();
mitk::DataNode* GetImageDataNode(size_t index) const;
void UnloadTasks(const mitk::DataNode* skip = nullptr);
void LoadTask(mitk::DataNode::Pointer imageNode = nullptr);
void SubscribeToActiveSegmentation();
void UnsubscribeFromActiveSegmentation();
void OnSegmentationModified();
void SetActiveTaskIndex(const std::optional& index);
void SetCurrentTaskIndex(const std::optional& index);
bool HandleUnsavedChanges(const QString& alternativeTitle = QString());
mitk::DataNode* GetSegmentationDataNode(size_t index) const;
void OnUnsavedChangesSaved();
void OnPreviousTaskShortcutActivated();
void OnNextTaskShortcutActivated();
void OnLoadTaskShortcutActivated();
+ void OnStoreInterimResultShortcutActivated();
+ void OnAcceptSegmentationShortcutActivated();
+ void OnStoreButtonClicked();
+ void OnAcceptButtonClicked();
Ui::QmitkSegmentationTaskListWidget* m_Ui;
QFileSystemWatcher* m_FileSystemWatcher;
mitk::DataStorage* m_DataStorage;
mitk::SegmentationTaskList::Pointer m_TaskList;
mitk::DataNode::Pointer m_TaskListNode;
std::optional m_CurrentTaskIndex;
std::optional m_ActiveTaskIndex;
std::optional m_SegmentationModifiedObserverTag;
bool m_UnsavedChanges;
};
#endif
diff --git a/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.ui b/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.ui
index db3f206306..8913da293a 100644
--- a/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.ui
+++ b/Modules/SegmentationUI/Qmitk/QmitkSegmentationTaskListWidget.ui
@@ -1,150 +1,199 @@
QmitkSegmentationTaskListWidget
0
0
- 299
- 329
+ 313
+ 217
Segmentation Task List
-
+
0
0
0
0
-
-
-
- Segmentation Task List
+
+
+
+ 0
+ 40
+
-
- -
-
-
-
- 0
- 40
-
-
-
-
- -
-
-
-
- 0
- 40
-
-
-
- 0
-
-
- Qt::AlignCenter
-
-
-
-
-
-
- -
-
- -
-
-
-
- 40
- 40
-
-
-
- Previous subtask
-
-
- Qt::LeftArrow
-
-
-
- -
-
-
-
- 0
- 40
-
-
-
- Load subtask
-
-
-
- -
-
-
-
- 40
- 40
-
-
-
- Next subtask
-
-
- Qt::RightArrow
-
-
-
-
-
- -
-
-
-
- 0
- 0
-
-
-
-
-
-
- Qt::RichText
-
-
- Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
-
-
- true
-
-
-
-
+ -
+
+
+
+ 0
+ 40
+
+
+
+ 0
+
+
+ Qt::AlignCenter
+
+
+
+
+
+
+ -
+
+ -
+
+
+
+ 40
+ 40
+
+
+
+ Previous subtask
+
+
+ Qt::LeftArrow
+
+
+
+ -
+
+
+
+ 0
+ 40
+
+
+
+ Load subtask
+
+
+
+ -
+
+
+
+ 40
+ 40
+
+
+
+ Next subtask
+
+
+ Qt::RightArrow
+
+
+
+
+
+ -
+
+
+
+
+
+ Qt::RichText
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
+
+
+ true
+
+
+
+ -
+
+ -
+
+
+
+ 50
+ 50
+
+
+
+
+ 50
+ 50
+
+
+
+ Save interim segmentation
+
+
+
+ 32
+ 32
+
+
+
+
+ -
+
+
+
+ 0
+ 50
+
+
+
+ Save and accept segmentation
+
+
+ Accept segmentation
+
+
+
+ 32
+ 32
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
QmitkSingleNodeSelectionWidget
QWidget
QmitkSingleNodeSelectionWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp
index 71e81f6602..9e232f1abf 100644
--- a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp
+++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.cpp
@@ -1,209 +1,114 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "org_mitk_gui_qt_flow_segmentation_Activator.h"
-// Blueberry
-#include
-#include
-#include
-#include
-
#include
//MITK
#include
#include
#include
#include
#include
#include
#include
-#include
// Qmitk
#include "QmitkSegmentationFlowControlView.h"
#include
// Qt
-#include
#include
-#include
const std::string QmitkSegmentationFlowControlView::VIEW_ID = "org.mitk.views.flow.control";
QmitkSegmentationFlowControlView::QmitkSegmentationFlowControlView()
: m_Controls(new Ui::SegmentationFlowControlView),
m_Parent(nullptr)
{
auto notHelperObject = mitk::NodePredicateNot::New(
mitk::NodePredicateProperty::New("helper object"));
m_SegmentationPredicate = mitk::NodePredicateAnd::New(
mitk::TNodePredicateDataType::New(),
notHelperObject);
-
- m_SegmentationTaskListPredicate = mitk::NodePredicateAnd::New(
- mitk::TNodePredicateDataType::New(),
- notHelperObject);
-
- berry::PlatformUI::GetWorkbench()->AddWorkbenchListener(this);
}
QmitkSegmentationFlowControlView::~QmitkSegmentationFlowControlView()
{
- berry::PlatformUI::GetWorkbench()->RemoveWorkbenchListener(this);
-}
-
-bool QmitkSegmentationFlowControlView::PreShutdown(berry::IWorkbench*, bool)
-{
- return m_Controls->segmentationTaskListWidget != nullptr
- ? m_Controls->segmentationTaskListWidget->OnPreShutdown()
- : true;
}
void QmitkSegmentationFlowControlView::SetFocus()
{
- m_Controls->btnStoreAndAccept->setFocus();
+ m_Controls->btnStoreAndAccept->setFocus();
}
void QmitkSegmentationFlowControlView::CreateQtPartControl(QWidget* parent)
{
m_Controls->setupUi(parent);
m_Parent = parent;
using Self = QmitkSegmentationFlowControlView;
- connect(m_Controls->btnStore, &QPushButton::clicked, this, &Self::OnStoreButtonClicked);
connect(m_Controls->btnStoreAndAccept, &QPushButton::clicked, this, &Self::OnAcceptButtonClicked);
- connect(m_Controls->segmentationTaskListWidget, &QmitkSegmentationTaskListWidget::ActiveTaskChanged, this, &Self::OnActiveTaskChanged);
- connect(m_Controls->segmentationTaskListWidget, &QmitkSegmentationTaskListWidget::CurrentTaskChanged, this, &Self::OnCurrentTaskChanged);
-
- auto* prevShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_S), parent);
- connect(prevShortcut, &QShortcut::activated, this, &Self::OnStoreInterimResultShortcutActivated);
-
- auto* nextShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key::Key_A), parent);
- connect(nextShortcut, &QShortcut::activated, this, &Self::OnAcceptSegmentationShortcutActivated);
-
- m_Controls->btnStore->setIcon(berry::QtStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/document-save.svg")));
- m_Controls->btnStore->setVisible(false);
-
- m_Controls->segmentationTaskListWidget->SetDataStorage(this->GetDataStorage());
- m_Controls->segmentationTaskListWidget->setVisible(false);
m_Controls->labelStored->setVisible(false);
this->UpdateControls();
m_OutputDir = QString::fromStdString(mitk::BaseApplication::instance().config().getString("flow.outputdir", itksys::SystemTools::GetCurrentWorkingDirectory()));
m_OutputDir = QDir::fromNativeSeparators(m_OutputDir);
m_FileExtension = QString::fromStdString(mitk::BaseApplication::instance().config().getString("flow.outputextension", "nrrd"));
}
-void QmitkSegmentationFlowControlView::OnStoreButtonClicked()
-{
- m_Controls->segmentationTaskListWidget->SaveActiveTask(true);
-}
-
void QmitkSegmentationFlowControlView::OnAcceptButtonClicked()
{
- if (m_Controls->segmentationTaskListWidget->isVisible())
- {
- auto* toolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager();
- int activeToolId = -1;
+ auto nodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate);
- if (toolManager != nullptr)
- activeToolId = toolManager->GetActiveToolID();
-
- m_Controls->segmentationTaskListWidget->SaveActiveTask();
- m_Controls->segmentationTaskListWidget->LoadNextUnfinishedTask();
-
- if (toolManager != nullptr)
- toolManager->ActivateTool(activeToolId);
- }
- else
+ for (auto node : *nodes)
{
- auto nodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate);
-
- for (auto node : *nodes)
- {
- QString outputpath = m_OutputDir + "/" + QString::fromStdString(node->GetName()) + "." + m_FileExtension;
- outputpath = QDir::toNativeSeparators(QDir::cleanPath(outputpath));
- mitk::IOUtil::Save(node->GetData(), outputpath.toStdString());
- }
-
- m_Controls->labelStored->setVisible(true);
+ QString outputpath = m_OutputDir + "/" + QString::fromStdString(node->GetName()) + "." + m_FileExtension;
+ outputpath = QDir::toNativeSeparators(QDir::cleanPath(outputpath));
+ mitk::IOUtil::Save(node->GetData(), outputpath.toStdString());
}
-}
-
-void QmitkSegmentationFlowControlView::OnActiveTaskChanged(const std::optional&)
-{
- this->UpdateControls();
-}
-void QmitkSegmentationFlowControlView::OnCurrentTaskChanged(const std::optional&)
-{
- this->UpdateControls();
+ m_Controls->labelStored->setVisible(true);
}
void QmitkSegmentationFlowControlView::UpdateControls()
{
auto dataStorage = this->GetDataStorage();
- auto hasTaskList = !dataStorage->GetSubset(m_SegmentationTaskListPredicate)->empty();
-
- m_Controls->segmentationTaskListWidget->setVisible(hasTaskList);
-
- if (hasTaskList)
- {
- auto activeTaskIsShown = m_Controls->segmentationTaskListWidget->ActiveTaskIsShown();
+ auto hasSegmentation = !dataStorage->GetSubset(m_SegmentationPredicate)->empty();
- m_Controls->btnStore->setVisible(activeTaskIsShown);
- m_Controls->btnStoreAndAccept->setEnabled(activeTaskIsShown);
- }
- else
- {
- auto hasSegmentation = !dataStorage->GetSubset(m_SegmentationPredicate)->empty();
-
- m_Controls->btnStore->setVisible(false);
- m_Controls->btnStoreAndAccept->setEnabled(hasSegmentation);
- }
+ m_Controls->btnStoreAndAccept->setEnabled(hasSegmentation);
}
void QmitkSegmentationFlowControlView::NodeAdded(const mitk::DataNode* node)
{
if (dynamic_cast(node->GetData()) != nullptr)
this->UpdateControls();
}
void QmitkSegmentationFlowControlView::NodeChanged(const mitk::DataNode* node)
{
if (dynamic_cast(node->GetData()) != nullptr)
this->UpdateControls();
}
void QmitkSegmentationFlowControlView::NodeRemoved(const mitk::DataNode* node)
{
if (dynamic_cast(node->GetData()) != nullptr)
this->UpdateControls();
}
-
-void QmitkSegmentationFlowControlView::OnStoreInterimResultShortcutActivated()
-{
- m_Controls->btnStore->click();
-}
-
-void QmitkSegmentationFlowControlView::OnAcceptSegmentationShortcutActivated()
-{
- m_Controls->btnStoreAndAccept->click();
-}
diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h
index 26e4316e21..54e8fa2f8e 100644
--- a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h
+++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.h
@@ -1,88 +1,78 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#ifndef QmitkSegmentationFlowControlView_h
#define QmitkSegmentationFlowControlView_h
#include
-#include
#include
#include "mitkNodePredicateBase.h"
-#include
-
namespace Ui
{
class SegmentationFlowControlView;
}
/*!
\brief QmitkSegmentationFlowControlView
Class that "controls" the segmentation view. It offers the possibility to accept a segmentation.
Accepting the segmentation stores the segmentation to the given working directory.
The working directory is specified by command line arguments. If no commandline flag is set the current working directory will be used.
*/
-class QmitkSegmentationFlowControlView : public QmitkAbstractView, public berry::IWorkbenchListener
+class QmitkSegmentationFlowControlView : public QmitkAbstractView
{
// this is needed for all Qt objects that should have a Qt meta-object
// (everything that derives from QObject and wants to have signal/slots)
Q_OBJECT
public:
static const std::string VIEW_ID;
/**
* Creates smartpointer typedefs
*/
berryObjectMacro(QmitkSegmentationFlowControlView)
QmitkSegmentationFlowControlView();
~QmitkSegmentationFlowControlView() override;
void CreateQtPartControl(QWidget *parent) override;
protected slots:
- void OnStoreButtonClicked();
void OnAcceptButtonClicked();
- void OnActiveTaskChanged(const std::optional& index);
- void OnCurrentTaskChanged(const std::optional& index);
- void OnStoreInterimResultShortcutActivated();
- void OnAcceptSegmentationShortcutActivated();
+
protected:
void SetFocus() override;
void NodeAdded(const mitk::DataNode* node) override;
void NodeChanged(const mitk::DataNode* node) override;
void NodeRemoved(const mitk::DataNode* node) override;
- bool PreShutdown(berry::IWorkbench*, bool) override;
-
void UpdateControls();
Ui::SegmentationFlowControlView* m_Controls;
private:
QWidget *m_Parent;
mitk::NodePredicateBase::Pointer m_SegmentationPredicate;
- mitk::NodePredicateBase::Pointer m_SegmentationTaskListPredicate;
QString m_OutputDir;
QString m_FileExtension;
};
#endif
diff --git a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui
index e2a96650c9..964a36323e 100644
--- a/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui
+++ b/Plugins/org.mitk.gui.qt.flow.segmentation/src/internal/QmitkSegmentationFlowControlView.ui
@@ -1,133 +1,97 @@
SegmentationFlowControlView
0
0
268
324
-
Qt::Vertical
20
40
- -
-
-
-
- -
-
-
-
- 50
- 50
-
-
-
-
- 50
- 50
-
-
-
- Save interim segmentation
-
-
-
- 32
- 32
-
-
-
-
-
0
50
Save and accept segmentation
Accept segmentation
32
32
-
<html><head/><body><p><span style=" font-size:12pt;">Segmentation accepted! Flow on...</span></p></body></html>
Qt::AlignCenter
-
Qt::Vertical
20
40
-
-
- QmitkSegmentationTaskListWidget
- QWidget
- QmitkSegmentationTaskListWidget.h
- 1
-
-
5
5
true
true
true
diff --git a/Plugins/org.mitk.gui.qt.segmentation/files.cmake b/Plugins/org.mitk.gui.qt.segmentation/files.cmake
index 49b6f35827..c92f6fd02d 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/files.cmake
+++ b/Plugins/org.mitk.gui.qt.segmentation/files.cmake
@@ -1,73 +1,78 @@
set(SRC_CPP_FILES
QmitkSegmentationPreferencePage.cpp
QmitkNewSegmentationDialog.cpp
QmitkLabelSetWidget.cpp
)
set(INTERNAL_CPP_FILES
mitkPluginActivator.cpp
QmitkSegmentationView.cpp
QmitkSegmentationUtilitiesView.cpp
+ QmitkSegmentationTaskListView.cpp
QmitkAutocropAction.cpp
QmitkAutocropLabelSetImageAction.cpp
QmitkCreatePolygonModelAction.cpp
QmitkLoadMultiLabelPresetAction.cpp
QmitkSaveMultiLabelPresetAction.cpp
QmitkConvertSurfaceToLabelAction.cpp
QmitkConvertMaskToLabelAction.cpp
QmitkConvertToMultiLabelSegmentationAction.cpp
QmitkCreateMultiLabelSegmentationAction.cpp
Common/QmitkLabelsWidget.cpp
Common/QmitkLayersWidget.cpp
)
set(UI_FILES
src/QmitkSegmentationPreferencePageControls.ui
src/QmitkNewSegmentationDialog.ui
src/QmitkLabelSetWidgetControls.ui
src/internal/QmitkSegmentationViewControls.ui
src/internal/QmitkSegmentationUtilitiesViewControls.ui
+ src/internal/QmitkSegmentationTaskListView.ui
src/internal/Common/QmitkLabelsWidgetControls.ui
src/internal/Common/QmitkLayersWidgetControls.ui
)
set(MOC_H_FILES
src/QmitkSegmentationPreferencePage.h
src/QmitkNewSegmentationDialog.h
src/QmitkLabelSetWidget.h
src/internal/mitkPluginActivator.h
src/internal/QmitkSegmentationView.h
src/internal/QmitkSegmentationUtilitiesView.h
+ src/internal/QmitkSegmentationTaskListView.h
src/internal/QmitkAutocropAction.h
src/internal/QmitkAutocropLabelSetImageAction.h
src/internal/QmitkCreatePolygonModelAction.h
src/internal/QmitkLoadMultiLabelPresetAction.h
src/internal/QmitkSaveMultiLabelPresetAction.h
src/internal/QmitkConvertSurfaceToLabelAction.h
src/internal/QmitkConvertMaskToLabelAction.h
src/internal/QmitkConvertToMultiLabelSegmentationAction.h
src/internal/QmitkCreateMultiLabelSegmentationAction.h
src/internal/Common/QmitkLabelsWidget.h
src/internal/Common/QmitkLayersWidget.h
)
set(CACHED_RESOURCE_FILES
resources/segmentation.svg
resources/segmentation_utilities.svg
+ resources/SegmentationTaskListIcon.svg
plugin.xml
)
set(QRC_FILES
resources/segmentation.qrc
resources/SegmentationUtilities.qrc
+ resources/SegmentationTaskList.qrc
)
set(CPP_FILES)
foreach(file ${SRC_CPP_FILES})
set(CPP_FILES ${CPP_FILES} src/${file})
endforeach(file ${SRC_CPP_FILES})
foreach(file ${INTERNAL_CPP_FILES})
set(CPP_FILES ${CPP_FILES} src/internal/${file})
endforeach(file ${INTERNAL_CPP_FILES})
diff --git a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml
index d761442833..70faf41d0e 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml
+++ b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml
@@ -1,84 +1,102 @@
Allows the segmentation of images using different tools.
Edit segmentations using standard operations.
+
+ Create or edit a batch of segmentations according to a task list in a streamlined workflow.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/org.mitk.gui.qt.segmentation/resources/SegmentationTaskList.qrc b/Plugins/org.mitk.gui.qt.segmentation/resources/SegmentationTaskList.qrc
new file mode 100644
index 0000000000..9a581864a6
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.segmentation/resources/SegmentationTaskList.qrc
@@ -0,0 +1,5 @@
+
+
+ SegmentationTaskListIcon.svg
+
+
diff --git a/Plugins/org.mitk.gui.qt.segmentation/resources/SegmentationTaskListIcon.svg b/Plugins/org.mitk.gui.qt.segmentation/resources/SegmentationTaskListIcon.svg
new file mode 100644
index 0000000000..1beb5d6b9e
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.segmentation/resources/SegmentationTaskListIcon.svg
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+ image/svg+xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.cpp
new file mode 100644
index 0000000000..d1a47b525a
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.cpp
@@ -0,0 +1,44 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#include "QmitkSegmentationTaskListView.h"
+#include
+
+#include
+
+const std::string QmitkSegmentationTaskListView::VIEW_ID = "org.mitk.views.segmentationtasklist";
+
+QmitkSegmentationTaskListView::QmitkSegmentationTaskListView()
+ : m_Ui(new Ui::QmitkSegmentationTaskListView)
+{
+ berry::PlatformUI::GetWorkbench()->AddWorkbenchListener(this);
+}
+
+QmitkSegmentationTaskListView::~QmitkSegmentationTaskListView()
+{
+ berry::PlatformUI::GetWorkbench()->RemoveWorkbenchListener(this);
+}
+
+void QmitkSegmentationTaskListView::CreateQtPartControl(QWidget* parent)
+{
+ m_Ui->setupUi(parent);
+ m_Ui->segmentationTaskListWidget->SetDataStorage(this->GetDataStorage());
+}
+
+void QmitkSegmentationTaskListView::SetFocus()
+{
+}
+
+bool QmitkSegmentationTaskListView::PreShutdown(berry::IWorkbench*, bool)
+{
+ return m_Ui->segmentationTaskListWidget->OnPreShutdown();
+}
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.h
new file mode 100644
index 0000000000..56ecd2df5e
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.h
@@ -0,0 +1,43 @@
+/*============================================================================
+
+The Medical Imaging Interaction Toolkit (MITK)
+
+Copyright (c) German Cancer Research Center (DKFZ)
+All rights reserved.
+
+Use of this source code is governed by a 3-clause BSD license that can be
+found in the LICENSE file.
+
+============================================================================*/
+
+#ifndef QmitkSegmentationTaskListView_h
+#define QmitkSegmentationTaskListView_h
+
+#include
+#include
+
+namespace Ui
+{
+ class QmitkSegmentationTaskListView;
+}
+
+class QmitkSegmentationTaskListView : public QmitkAbstractView, public berry::IWorkbenchListener
+{
+ Q_OBJECT
+
+public:
+ static const std::string VIEW_ID;
+
+ QmitkSegmentationTaskListView();
+ ~QmitkSegmentationTaskListView() override;
+
+private:
+ void CreateQtPartControl(QWidget* parent) override;
+ void SetFocus() override;
+
+ bool PreShutdown(berry::IWorkbench*, bool) override;
+
+ Ui::QmitkSegmentationTaskListView* m_Ui;
+};
+
+#endif
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.ui b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.ui
new file mode 100644
index 0000000000..76821f3e6b
--- /dev/null
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/QmitkSegmentationTaskListView.ui
@@ -0,0 +1,32 @@
+
+
+ QmitkSegmentationTaskListView
+
+
+
+ 0
+ 0
+ 400
+ 300
+
+
+
+ Form
+
+
+ -
+
+
+
+
+
+
+ QmitkSegmentationTaskListWidget
+ QWidget
+ QmitkSegmentationTaskListWidget.h
+ 1
+
+
+
+
+
diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp
index ea361b7226..70ab9cfbb3 100644
--- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp
+++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/mitkPluginActivator.cpp
@@ -1,78 +1,80 @@
/*============================================================================
The Medical Imaging Interaction Toolkit (MITK)
Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.
Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.
============================================================================*/
#include "mitkPluginActivator.h"
#include "QmitkSegmentationView.h"
#include "QmitkSegmentationPreferencePage.h"
#include "QmitkSegmentationUtilitiesView.h"
+#include "QmitkSegmentationTaskListView.h"
#include "QmitkAutocropAction.h"
#include "QmitkAutocropLabelSetImageAction.h"
#include "QmitkCreatePolygonModelAction.h"
#include "QmitkLoadMultiLabelPresetAction.h"
#include "QmitkSaveMultiLabelPresetAction.h"
#include "QmitkConvertSurfaceToLabelAction.h"
#include "QmitkConvertMaskToLabelAction.h"
#include "QmitkConvertToMultiLabelSegmentationAction.h"
#include "QmitkCreateMultiLabelSegmentationAction.h"
#include
US_INITIALIZE_MODULE
using namespace mitk;
ctkPluginContext* PluginActivator::m_context = nullptr;
PluginActivator* PluginActivator::m_Instance = nullptr;
PluginActivator::PluginActivator()
{
m_Instance = this;
}
PluginActivator::~PluginActivator()
{
m_Instance = nullptr;
}
void PluginActivator::start(ctkPluginContext *context)
{
BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationView, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationPreferencePage, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationUtilitiesView, context)
+ BERRY_REGISTER_EXTENSION_CLASS(QmitkSegmentationTaskListView, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropLabelSetImageAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkCreatePolygonModelAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkLoadMultiLabelPresetAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkSaveMultiLabelPresetAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertSurfaceToLabelAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertMaskToLabelAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertToMultiLabelSegmentationAction, context)
BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelSegmentationAction, context)
this->m_context = context;
}
void PluginActivator::stop(ctkPluginContext *)
{
this->m_context = nullptr;
}
PluginActivator* PluginActivator::getDefault()
{
return m_Instance;
}
ctkPluginContext*PluginActivator::getContext()
{
return m_context;
}