diff --git a/Modules/QtWidgets/include/QmitkIOUtil.h b/Modules/QtWidgets/include/QmitkIOUtil.h
index 2baa1cc464..47ca03ac63 100644
--- a/Modules/QtWidgets/include/QmitkIOUtil.h
+++ b/Modules/QtWidgets/include/QmitkIOUtil.h
@@ -1,238 +1,237 @@
/*============================================================================
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 QmitkIOUtil_h
#define QmitkIOUtil_h
#include "MitkQtWidgetsExports.h"
// std
#include
// mitk includes
#include
#include
#include
#include
#include
#include
#include
#include
// Qt
#include
#include
#include
#include
class QWidget;
class QString;
-class QStringList;
namespace mitk
{
class DataStorage;
class MimeType;
struct IFileReader;
}
/**
* @brief QmitkIOUtil Provides static helper methods to open and save files with Qt dialogs.
*/
class MITKQTWIDGETS_EXPORT QmitkIOUtil : public mitk::IOUtil
{
public:
class MITKQTWIDGETS_EXPORT SaveFilter
{
public:
static mitk::MimeType ALL_MIMETYPE();
SaveFilter(const SaveFilter &other);
SaveFilter(const SaveInfo &saveInfo);
SaveFilter &operator=(const SaveFilter &other);
std::vector GetMimeTypes() const;
QString GetFilterForMimeType(const std::string &mimeType) const;
mitk::MimeType GetMimeTypeForFilter(const QString &filter) const;
QString GetDefaultFilter() const;
QString GetDefaultExtension() const;
mitk::MimeType GetDefaultMimeType() const;
QString ToString() const;
int Size() const;
bool IsEmpty() const;
bool ContainsMimeType(const std::string &mimeType);
private:
struct Impl;
QScopedPointer d;
};
/**
* @brief GetFilterString
* @return
*/
static QString GetFileOpenFilterString();
/**
* @brief Loads the specified files
*
* This methods tries to load all specified files and pop-ups dialog boxes if further
* user input is required (e.g. ambiguous mime-types or reader options).
*
* If the provided DataStorage is not nullptr, some files will be added to it automatically,
* dependeing on the IFileReader used.
*
* @param paths
* @param parent
* @return A list of BaseData instances which have not already been added to the data storage.
*/
static QList Load(const QStringList &paths, QWidget *parent = nullptr);
static mitk::DataStorage::SetOfObjects::Pointer Load(const QStringList &paths,
mitk::DataStorage &storage,
QWidget *parent = nullptr);
static QList Load(const QString &path, QWidget *parent = nullptr);
static mitk::DataStorage::SetOfObjects::Pointer Load(const QString &path,
mitk::DataStorage &storage,
QWidget *parent = nullptr);
using mitk::IOUtil::Load;
static QString Save(const mitk::BaseData *data,
const QString &defaultBaseName,
const QString &defaultPath = QString(),
QWidget *parent = nullptr,
bool setPathProperty = false);
/**
* @brief Save a list of BaseData objects using a "File Save Dialog".
*
* For each element in the \c data vector, the following algorithm is
* used to find a IFileWriter instance for writing the BaseData object.
*
* First, the user is prompted to select file names for each BaseData object. This
* is equivalent to choosing a specific mime-type, either by selecting a filter
* in the save dialog or by explicitly providing a file name extension:
*
* - Get a list of registered IFileWriter objects for the current BaseData object.
* If no writers are found, a message box displays a warning and
* the process starts from the beginning for the next BaseData object.
* - A QFileDialog for prompting the user to select a file name is opened.
* The mime-type associated with each IFileWriter object is used to create
* a filter for file name extensions.
* The best IFileWriter (see FileWriterSelector) for the current BaseData object
* defines the default file name suffix via its associated mime-type. If the
* file name is empty (the user cancelled the dialog), the remaining
* BaseData objects are skipped.
*
- The file name is matched against valid mime-types. The first mime-type
* which accepts the file name is associated with the current BaseData object.
* If no mime-type accepts the supplied file name and the file already
* exists, the process starts from the beginning with the next BaseData object.
* Otherwise, if the selected filter is the special "all" filter and the
* file name does not contain periods (which may or may not mark the start of
* a file extension), the current BaseData object is associated with the
* default mime-type. If the selected filter is not the special "all" filter,
* the mime-type for this filter is associated with the current BaseData object.
* The default extension of the associated mime-type is then appended to the
* supplied file name.
*
- The selected/derived file name and associated mime-type is stored in a list
* and the process starts from the beginning for the next BaseData object.
*
*
* In the second phase, each BaseData object is saved to disk using the specified
* file name and mime-type, according to the following procedure:
*
* - If multiple IFileWriter objects are compatible with the current base data
* object or if the single compatible IFileWriter provides configuration
* options, a dialog window containing a list of IFileWriter objects and
* configurable options is displayed. If the dialog is cancelled by the user,
* neither the current nor the remaining base data objects are saved to disk.
* If the user previously in this phase enabled the "remember options" checkbox
* of the dialog, then the dialog is not shown for base data objects with the
* same data type and associated mime-type if the file writer instance reports
* a higher or equal confidence level for the current base data object.
* - The selected writer (either the only available one or the user selected one)
* is used to write the base data object to disk. On failure, an error is
* reported and the second phase continues with the next base data object.
*
*
* @param data
* @param defaultBaseNames
* @param defaultPath
* @param parent
* @param setPathProperty
* @return
*/
static QStringList Save(const std::vector &data,
const QStringList &defaultBaseNames,
const QString &defaultPath = QString(),
QWidget *parent = nullptr,
bool setPathProperty = false);
using mitk::IOUtil::Save;
/**
* @brief SaveBaseDataWithDialog Convenience method to save any data with a Qt dialog.
* @param data BaseData holding the data you wish to save.
* @param fileName The file name where to save the data (including path and extension).
* @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the
* screen.
* @deprecatedSince{2014_10} Use Save() instead.
*/
DEPRECATED(static void SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget *parent = nullptr));
/**
* @brief SaveSurfaceWithDialog Convenience method to save a surface with a Qt dialog.
* @param surface The surface to save.
* @param fileName The file name where to save the data (including path and extension).
* @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the
* screen.
* @deprecatedSince{2014_10} Use Save() instead.
*/
DEPRECATED(static void SaveSurfaceWithDialog(mitk::Surface::Pointer surface,
std::string fileName = "",
QWidget *parent = nullptr));
/**
* @brief SaveImageWithDialog Convenience method to save an image with a Qt dialog.
* @param image The image to save.
* @param fileName The file name where to save the data (including path and extension).
* @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the
* screen.
* @deprecatedSince{2014_10} Use Save() instead.
*/
DEPRECATED(static void SaveImageWithDialog(mitk::Image::Pointer image,
std::string fileName = "",
QWidget *parent = nullptr));
/**
* @brief SavePointSetWithDialog Convenience method to save a pointset with a Qt dialog.
* @param pointset The pointset to save.
* @param fileName The file name where to save the data (including path and extension).
* @param parent An optional QWidget as parent. If no parent is supplied, the QFileDialog can occur anywhere on the
* screen.
* @deprecatedSince{2014_10} Use Save() instead.
*/
DEPRECATED(static void SavePointSetWithDialog(mitk::PointSet::Pointer pointset,
std::string fileName = "",
QWidget *parent = nullptr));
private:
struct Impl;
};
#endif
diff --git a/Modules/QtWidgets/src/QmitkIOUtil.cpp b/Modules/QtWidgets/src/QmitkIOUtil.cpp
index 8dbde985ca..9ab8678e53 100644
--- a/Modules/QtWidgets/src/QmitkIOUtil.cpp
+++ b/Modules/QtWidgets/src/QmitkIOUtil.cpp
@@ -1,586 +1,587 @@
/*============================================================================
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 "QmitkIOUtil.h"
#include "mitkCoreServices.h"
#include "mitkCustomMimeType.h"
#include "mitkFileReaderRegistry.h"
#include "mitkFileWriterRegistry.h"
#include "mitkIMimeTypeProvider.h"
#include "mitkMimeType.h"
#include
#include
#include "QmitkFileReaderOptionsDialog.h"
#include "QmitkFileWriterOptionsDialog.h"
// QT
#include
#include
#include
#include
#include
+#include
// ITK
#include
#include
struct QmitkIOUtil::Impl
{
struct ReaderOptionsDialogFunctor : public ReaderOptionsFunctorBase
{
bool operator()(LoadInfo &loadInfo) const override
{
QmitkFileReaderOptionsDialog dialog(loadInfo);
if (dialog.exec() == QDialog::Accepted)
{
return !dialog.ReuseOptions();
}
else
{
loadInfo.m_Cancel = true;
return true;
}
}
};
struct WriterOptionsDialogFunctor : public WriterOptionsFunctorBase
{
bool operator()(SaveInfo &saveInfo) const override
{
QmitkFileWriterOptionsDialog dialog(saveInfo);
if (dialog.exec() == QDialog::Accepted)
{
return !dialog.ReuseOptions();
}
else
{
saveInfo.m_Cancel = true;
return true;
}
}
};
//! Filename characters that are not valid - depending on the platform (Windows, Posix)
static QString s_InvalidFilenameCharacters;
//! Return 'true' when:
//! - the specified filename contains characters not accepted by the file system (see s_InvalidFilenameCharacters)
//! - filename starts or ends in space characters
//!
//! This test is not exhaustive but just excluding the most common problems.
static bool IsIllegalFilename(const QString &fullFilename)
{
QFileInfo fi(fullFilename);
auto filename = fi.fileName();
for (const auto &ch : qAsConst(s_InvalidFilenameCharacters))
{
if (filename.contains(ch))
{
return true;
}
}
if (filename.startsWith(' ') || filename.endsWith(' '))
{
return true;
}
return false;
}
}; // Impl
#if defined(_WIN32) || defined(_WIN64)
QString QmitkIOUtil::Impl::s_InvalidFilenameCharacters = "<>:\"/\\|?*";
#else
QString QmitkIOUtil::Impl::s_InvalidFilenameCharacters = "/";
#endif
struct MimeTypeComparison
{
MimeTypeComparison(const std::string &mimeTypeName) : m_Name(mimeTypeName) {}
bool operator()(const mitk::MimeType &mimeType) const { return mimeType.GetName() == m_Name; }
const std::string m_Name;
};
QString QmitkIOUtil::GetFileOpenFilterString()
{
QString filters;
mitk::CoreServicePointer mimeTypeProvider(mitk::CoreServices::GetMimeTypeProvider());
std::vector categories = mimeTypeProvider->GetCategories();
for (std::vector::iterator cat = categories.begin(); cat != categories.end(); ++cat)
{
QSet filterExtensions;
std::vector mimeTypes = mimeTypeProvider->GetMimeTypesForCategory(*cat);
for (std::vector::iterator mt = mimeTypes.begin(); mt != mimeTypes.end(); ++mt)
{
std::vector extensions = mt->GetExtensions();
for (std::vector::iterator ext = extensions.begin(); ext != extensions.end(); ++ext)
{
filterExtensions << QString::fromStdString(*ext);
}
}
QString filter = QString::fromStdString(*cat) + " (";
foreach (const QString &extension, filterExtensions)
{
filter += "*." + extension + " ";
}
filter = filter.replace(filter.size() - 1, 1, ')');
filters += ";;" + filter;
}
filters.prepend("All (*)");
return filters;
}
QList QmitkIOUtil::Load(const QStringList &paths, QWidget *parent)
{
std::vector loadInfos;
foreach (const QString &file, paths)
{
loadInfos.push_back(LoadInfo(file.toLocal8Bit().constData()));
}
Impl::ReaderOptionsDialogFunctor optionsCallback;
std::string errMsg = Load(loadInfos, nullptr, nullptr, &optionsCallback);
if (!errMsg.empty())
{
QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg));
mitkThrow() << errMsg;
}
QList qResult;
for (std::vector::const_iterator iter = loadInfos.begin(), iterEnd = loadInfos.end(); iter != iterEnd;
++iter)
{
for (const auto &elem : iter->m_Output)
{
qResult << elem;
}
}
return qResult;
}
mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QStringList &paths,
mitk::DataStorage &storage,
QWidget *parent)
{
std::vector loadInfos;
foreach (const QString &file, paths)
{
loadInfos.push_back(LoadInfo(file.toLocal8Bit().constData()));
}
mitk::DataStorage::SetOfObjects::Pointer nodeResult = mitk::DataStorage::SetOfObjects::New();
Impl::ReaderOptionsDialogFunctor optionsCallback;
std::string errMsg = Load(loadInfos, nodeResult, &storage, &optionsCallback);
if (!errMsg.empty())
{
QMessageBox::warning(parent, "Error reading files", QString::fromStdString(errMsg));
}
return nodeResult;
}
QList QmitkIOUtil::Load(const QString &path, QWidget *parent)
{
QStringList paths;
paths << path;
return Load(paths, parent);
}
mitk::DataStorage::SetOfObjects::Pointer QmitkIOUtil::Load(const QString &path,
mitk::DataStorage &storage,
QWidget *parent)
{
QStringList paths;
paths << path;
return Load(paths, storage, parent);
}
QString QmitkIOUtil::Save(const mitk::BaseData *data,
const QString &defaultBaseName,
const QString &defaultPath,
QWidget *parent,
bool setPathProperty)
{
std::vector dataVector;
dataVector.push_back(data);
QStringList defaultBaseNames;
defaultBaseNames.push_back(defaultBaseName);
return Save(dataVector, defaultBaseNames, defaultPath, parent, setPathProperty).back();
}
QStringList QmitkIOUtil::Save(const std::vector &data,
const QStringList &defaultBaseNames,
const QString &defaultPath,
QWidget *parent,
bool setPathProperty)
{
QStringList fileNames;
QString currentPath = defaultPath;
std::vector saveInfos;
int counter = 0;
for (std::vector::const_iterator dataIter = data.begin(), dataIterEnd = data.end();
dataIter != dataIterEnd;
++dataIter, ++counter)
{
SaveInfo saveInfo(*dataIter, mitk::MimeType(), std::string());
SaveFilter filters(saveInfo);
// If there is only the "__all__" filter string, it means there is no writer for this base data
if (filters.Size() < 2)
{
QMessageBox::warning(
parent,
"Saving not possible",
QString("No writer available for type \"%1\"").arg(QString::fromStdString((*dataIter)->GetNameOfClass())));
continue;
}
// Construct a default path and file name
QString filterString = filters.ToString();
QString selectedFilter = filters.GetDefaultFilter();
QString fileName = currentPath;
QString dialogTitle = "Save " + QString::fromStdString((*dataIter)->GetNameOfClass());
if (counter < defaultBaseNames.size())
{
dialogTitle += " \"" + defaultBaseNames[counter] + "\"";
fileName += QDir::separator() + defaultBaseNames[counter];
// We do not append an extension to the file name by default. The extension
// is chosen by the user by either selecting a filter or writing the
// extension in the file name himself (in the file save dialog).
/*
QString defaultExt = filters.GetDefaultExtension();
if (!defaultExt.isEmpty())
{
fileName += "." + defaultExt;
}
*/
}
// Ask the user for a file name
QString nextName = QFileDialog::getSaveFileName(parent, dialogTitle, fileName, filterString, &selectedFilter);
if (Impl::IsIllegalFilename(nextName))
{
QMessageBox::warning(
parent,
"Saving not possible",
QString("File \"%2\" contains invalid characters.\n\nPlease avoid any of \"%1\"")
.arg(Impl::s_InvalidFilenameCharacters.split("", Qt::SkipEmptyParts).join(" "))
.arg(nextName));
continue;
}
if (nextName.isEmpty())
{
// We stop asking for further file names, but we still save the
// data where the user already confirmed the save dialog.
break;
}
fileName = nextName;
std::string stdFileName = fileName.toLocal8Bit().constData();
QFileInfo fileInfo(fileName);
currentPath = fileInfo.absolutePath();
QString suffix = fileInfo.completeSuffix();
mitk::MimeType filterMimeType = filters.GetMimeTypeForFilter(selectedFilter);
mitk::MimeType selectedMimeType;
if (fileInfo.exists() && !fileInfo.isFile())
{
QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName));
continue;
}
// Theoretically, the user could have entered an extension that does not match the selected filter
// The extension then has prioritry over the filter
// Check if one of the available mime-types match the filename
std::vector filterMimeTypes = filters.GetMimeTypes();
for (std::vector::const_iterator mimeTypeIter = filterMimeTypes.begin(),
mimeTypeIterEnd = filterMimeTypes.end();
mimeTypeIter != mimeTypeIterEnd;
++mimeTypeIter)
{
if (mimeTypeIter->MatchesExtension(stdFileName))
{
selectedMimeType = *mimeTypeIter;
break;
}
}
if (!selectedMimeType.IsValid())
{
// The file name either does not contain an extension or the
// extension is unknown.
// If the file already exists, we stop here because we are unable
// to (over)write the file without adding a custom suffix. If the file
// does not exist, we add the default extension from the currently
// selected filter. If the "All" filter was selected, we only add the
// default extensions if the file name itself does not already contain
// an extension.
if (!fileInfo.exists())
{
if (filterMimeType == SaveFilter::ALL_MIMETYPE())
{
if (suffix.isEmpty())
{
// Use the highest ranked mime-type from the list
selectedMimeType = filters.GetDefaultMimeType();
}
}
else
{
selectedMimeType = filterMimeType;
}
if (selectedMimeType.IsValid())
{
suffix = QString::fromStdString(selectedMimeType.GetExtensions().front());
fileName += "." + suffix;
stdFileName = fileName.toLocal8Bit().constData();
// We changed the file name (added a suffix) so ask in case
// the file aready exists.
fileInfo = QFileInfo(fileName);
if (fileInfo.exists())
{
if (!fileInfo.isFile())
{
QMessageBox::warning(
parent, "Saving not possible", QString("The path \"%1\" is not a file").arg(fileName));
continue;
}
if (QMessageBox::question(
parent,
"Replace File",
QString("A file named \"%1\" already exists. Do you want to replace it?").arg(fileName)) ==
QMessageBox::No)
{
continue;
}
}
}
}
}
if (!selectedMimeType.IsValid())
{
// The extension/filename is not valid (no mime-type found), bail out
QMessageBox::warning(
parent, "Saving not possible", QString("No mime-type available which can handle \"%1\".").arg(fileName));
continue;
}
if (!QFileInfo(fileInfo.absolutePath()).isWritable())
{
QMessageBox::warning(parent, "Saving not possible", QString("The path \"%1\" is not writable").arg(fileName));
continue;
}
fileNames.push_back(fileName);
saveInfo.m_Path = stdFileName;
saveInfo.m_MimeType = selectedMimeType;
// pre-select the best writer for the chosen mime-type
saveInfo.m_WriterSelector.Select(selectedMimeType.GetName());
saveInfos.push_back(saveInfo);
}
if (!saveInfos.empty())
{
Impl::WriterOptionsDialogFunctor optionsCallback;
std::string errMsg = Save(saveInfos, &optionsCallback, setPathProperty);
if (!errMsg.empty())
{
QMessageBox::warning(parent, "Error writing files", QString::fromStdString(errMsg));
mitkThrow() << errMsg;
}
}
return fileNames;
}
void QmitkIOUtil::SaveBaseDataWithDialog(mitk::BaseData *data, std::string fileName, QWidget * /*parent*/)
{
Save(data, fileName);
}
void QmitkIOUtil::SaveSurfaceWithDialog(mitk::Surface::Pointer surface, std::string fileName, QWidget * /*parent*/)
{
Save(surface, fileName);
}
void QmitkIOUtil::SaveImageWithDialog(mitk::Image::Pointer image, std::string fileName, QWidget * /*parent*/)
{
Save(image, fileName);
}
void QmitkIOUtil::SavePointSetWithDialog(mitk::PointSet::Pointer pointset, std::string fileName, QWidget * /*parent*/)
{
Save(pointset, fileName);
}
struct QmitkIOUtil::SaveFilter::Impl
{
Impl(const mitk::IOUtil::SaveInfo &saveInfo) : m_SaveInfo(saveInfo)
{
// Add an artifical filter for "All"
m_MimeTypes.push_back(ALL_MIMETYPE());
m_FilterStrings.push_back("All (*.*)");
// Get all writers and their mime types for the given base data type
// (this is sorted already)
std::vector mimeTypes = saveInfo.m_WriterSelector.GetMimeTypes();
for (std::vector::const_reverse_iterator iter = mimeTypes.rbegin(), iterEnd = mimeTypes.rend();
iter != iterEnd;
++iter)
{
QList filterExtensions;
mitk::MimeType mimeType = *iter;
std::vector extensions = mimeType.GetExtensions();
for (auto &extension : extensions)
{
filterExtensions << QString::fromStdString(extension);
}
if (m_DefaultExtension.isEmpty())
{
m_DefaultExtension = QString::fromStdString(extensions.front());
}
QString filter = QString::fromStdString(mimeType.GetComment()) + " (";
foreach (const QString &extension, filterExtensions)
{
filter += "*." + extension + " ";
}
filter = filter.replace(filter.size() - 1, 1, ')');
m_MimeTypes.push_back(mimeType);
m_FilterStrings.push_back(filter);
}
}
const mitk::IOUtil::SaveInfo m_SaveInfo;
std::vector m_MimeTypes;
QStringList m_FilterStrings;
QString m_DefaultExtension;
};
mitk::MimeType QmitkIOUtil::SaveFilter::ALL_MIMETYPE()
{
static mitk::CustomMimeType allMimeType(std::string("__all__"));
return mitk::MimeType(allMimeType, -1, -1);
}
QmitkIOUtil::SaveFilter::SaveFilter(const QmitkIOUtil::SaveFilter &other) : d(new Impl(*other.d))
{
}
QmitkIOUtil::SaveFilter::SaveFilter(const SaveInfo &saveInfo) : d(new Impl(saveInfo))
{
}
QmitkIOUtil::SaveFilter &QmitkIOUtil::SaveFilter::operator=(const QmitkIOUtil::SaveFilter &other)
{
d.reset(new Impl(*other.d));
return *this;
}
std::vector QmitkIOUtil::SaveFilter::GetMimeTypes() const
{
return d->m_MimeTypes;
}
QString QmitkIOUtil::SaveFilter::GetFilterForMimeType(const std::string &mimeType) const
{
std::vector::const_iterator iter =
std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType));
if (iter == d->m_MimeTypes.end())
{
return QString();
}
int index = static_cast(iter - d->m_MimeTypes.begin());
if (index < 0 || index >= d->m_FilterStrings.size())
{
return QString();
}
return d->m_FilterStrings[index];
}
mitk::MimeType QmitkIOUtil::SaveFilter::GetMimeTypeForFilter(const QString &filter) const
{
int index = d->m_FilterStrings.indexOf(filter);
if (index < 0)
{
return mitk::MimeType();
}
return d->m_MimeTypes[index];
}
QString QmitkIOUtil::SaveFilter::GetDefaultFilter() const
{
if (d->m_FilterStrings.size() > 1)
{
return d->m_FilterStrings.at(1);
}
else if (d->m_FilterStrings.size() > 0)
{
return d->m_FilterStrings.front();
}
return QString();
}
QString QmitkIOUtil::SaveFilter::GetDefaultExtension() const
{
return d->m_DefaultExtension;
}
mitk::MimeType QmitkIOUtil::SaveFilter::GetDefaultMimeType() const
{
if (d->m_MimeTypes.size() > 1)
{
return d->m_MimeTypes.at(1);
}
else if (d->m_MimeTypes.size() > 0)
{
return d->m_MimeTypes.front();
}
return mitk::MimeType();
}
QString QmitkIOUtil::SaveFilter::ToString() const
{
return d->m_FilterStrings.join(";;");
}
int QmitkIOUtil::SaveFilter::Size() const
{
return d->m_FilterStrings.size();
}
bool QmitkIOUtil::SaveFilter::IsEmpty() const
{
return d->m_FilterStrings.isEmpty();
}
bool QmitkIOUtil::SaveFilter::ContainsMimeType(const std::string &mimeType)
{
return std::find_if(d->m_MimeTypes.begin(), d->m_MimeTypes.end(), MimeTypeComparison(mimeType)) !=
d->m_MimeTypes.end();
}
diff --git a/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp b/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp
index a4c6cb67ae..b1666aa931 100644
--- a/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp
+++ b/Modules/QtWidgets/src/QmitkRenderWindowDataNodeTableModel.cpp
@@ -1,370 +1,372 @@
/*============================================================================
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 "QmitkRenderWindowDataNodeTableModel.h"
// mitk core
#include
// qt widgets module
#include
#include
#include
#include
#include
#include
+#include
+
#include
QmitkRenderWindowDataNodeTableModel::QmitkRenderWindowDataNodeTableModel(QObject* parent /*= nullptr*/)
: QAbstractItemModel(parent)
{
m_RenderWindowLayerController = std::make_unique();
m_VisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/visible.svg"));
m_InvisibleIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/invisible.svg"));
m_ArrowIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/reset.svg"));
m_TimesIcon = QmitkStyleManager::ThemeIcon(QLatin1String(":/Qmitk/times.svg"));
}
void QmitkRenderWindowDataNodeTableModel::UpdateModelData()
{
auto baseRenderer = m_BaseRenderer.Lock();
auto greaterThan = [&baseRenderer](const mitk::DataNode* dataNodeLeft, const mitk::DataNode* dataNodeRight)
{
int layerLeft = -1;
int layerRight = -1;
bool layerLeftFound = dataNodeLeft->GetIntProperty("layer", layerLeft, baseRenderer);
bool layerRightFound = dataNodeRight->GetIntProperty("layer", layerRight, baseRenderer);
if (layerLeftFound && layerRightFound)
{
return layerLeft > layerRight;
}
return true;
};
// sort node selection
beginResetModel();
std::sort(m_CurrentSelection.begin(), m_CurrentSelection.end(), greaterThan);
endResetModel();
emit ModelUpdated();
}
void QmitkRenderWindowDataNodeTableModel::SetDataStorage(mitk::DataStorage* dataStorage)
{
m_RenderWindowLayerController->SetDataStorage(dataStorage);
}
void QmitkRenderWindowDataNodeTableModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer)
{
if (m_BaseRenderer == baseRenderer)
{
// resetting the same base renderer does nothing
return;
}
m_BaseRenderer = baseRenderer;
// update the model, since a new base renderer could have set the relevant node-properties differently
this->UpdateModelData();
}
mitk::BaseRenderer::Pointer QmitkRenderWindowDataNodeTableModel::GetCurrentRenderer() const
{
return m_BaseRenderer.Lock();
}
void QmitkRenderWindowDataNodeTableModel::SetCurrentSelection(NodeList selectedNodes)
{
m_CurrentSelection = selectedNodes;
// update the model: sort the current internal selection
this->UpdateModelData();
}
QmitkRenderWindowDataNodeTableModel::NodeList QmitkRenderWindowDataNodeTableModel::GetCurrentSelection() const
{
return m_CurrentSelection;
}
QModelIndex QmitkRenderWindowDataNodeTableModel::index(int row, int column, const QModelIndex& parent /*= QModelIndex()*/) const
{
bool hasIndex = this->hasIndex(row, column, parent);
if (hasIndex)
{
return this->createIndex(row, column);
}
return QModelIndex();
}
QModelIndex QmitkRenderWindowDataNodeTableModel::parent(const QModelIndex& /*child*/) const
{
return QModelIndex();
}
int QmitkRenderWindowDataNodeTableModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{
if (parent.isValid())
{
return 0;
}
return static_cast(m_CurrentSelection.size());
}
int QmitkRenderWindowDataNodeTableModel::columnCount(const QModelIndex& parent /*= QModelIndex()*/) const
{
if (parent.isValid())
{
return 0;
}
return 4;
}
Qt::ItemFlags QmitkRenderWindowDataNodeTableModel::flags(const QModelIndex &index) const
{
if (this != index.model())
{
return Qt::NoItemFlags;
}
if (index.isValid())
{
if (index.column() == 0)
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable |
Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
else
{
return Qt::ItemIsDropEnabled;
}
}
QVariant QmitkRenderWindowDataNodeTableModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid() || this != index.model())
{
return QVariant();
}
if (index.row() < 0 || index.row() >= static_cast(m_CurrentSelection.size()))
{
return QVariant();
}
mitk::DataNode* dataNode = m_CurrentSelection.at(index.row());
if (role == QmitkDataNodeRole)
{
return QVariant::fromValue(mitk::DataNode::Pointer(dataNode));
}
if (role == QmitkDataNodeRawPointerRole)
{
return QVariant::fromValue(dataNode);
}
if (index.column() == 0) // data node information column
{
QString nodeName = QString::fromStdString(dataNode->GetName());
if (nodeName.isEmpty())
{
nodeName = "unnamed";
}
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
return nodeName;
}
if (role == Qt::ToolTipRole)
{
return QVariant("Name of the data node.");
}
if (role == Qt::DecorationRole)
{
QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode);
return QVariant(nodeDescriptor->GetIcon(dataNode));
}
}
if (index.column() == 1) // node visibility column
{
if (role == Qt::DecorationRole)
{
auto baseRenderer = m_BaseRenderer.Lock();
bool visibility = false;
dataNode->GetVisibility(visibility, baseRenderer);
return visibility ? QVariant(m_VisibleIcon) : QVariant(m_InvisibleIcon);
}
if (role == Qt::EditRole)
{
auto baseRenderer = m_BaseRenderer.Lock();
bool visibility = false;
dataNode->GetVisibility(visibility, baseRenderer);
return QVariant(visibility);
}
}
if (index.column() == 2) // reset geometry column
{
if (role == Qt::DecorationRole)
{
return QVariant(m_ArrowIcon);
}
}
if (index.column() == 3) // remove node column
{
if (role == Qt::DecorationRole)
{
return QVariant(m_TimesIcon);
}
}
return QVariant();
}
bool QmitkRenderWindowDataNodeTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (!index.isValid() || this != index.model())
{
return false;
}
if (index.row() < 0 || index.row() >= static_cast(m_CurrentSelection.size()))
{
return false;
}
mitk::DataNode* dataNode = m_CurrentSelection.at(index.row());
if (index.column() == 0) // data node information column
{
if (role == Qt::EditRole && !value.toString().isEmpty())
{
dataNode->SetName(value.toString().toStdString());
emit dataChanged(index, index);
return true;
}
}
if (index.column() == 1) // data node visibility column
{
if (role == Qt::EditRole)
{
auto baseRenderer = m_BaseRenderer.Lock();
bool visibility = value.toBool();
dataNode->SetVisibility(visibility, baseRenderer);
if (baseRenderer.IsNotNull())
{
// Explicitly request an update since a renderer-specific property change does not mark the node as modified.
// see https://phabricator.mitk.org/T22322
mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow());
}
emit dataChanged(index, index);
return true;
}
}
return false;
}
Qt::DropActions QmitkRenderWindowDataNodeTableModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
Qt::DropActions QmitkRenderWindowDataNodeTableModel::supportedDragActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
QStringList QmitkRenderWindowDataNodeTableModel::mimeTypes() const
{
QStringList types = QAbstractItemModel::mimeTypes();
types << QmitkMimeTypes::DataNodePtrs;
return types;
}
QMimeData* QmitkRenderWindowDataNodeTableModel::mimeData(const QModelIndexList& indexes) const
{
QMimeData* mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const auto& index : indexes)
{
if (index.isValid())
{
auto dataNode = data(index, QmitkDataNodeRawPointerRole).value();
stream << reinterpret_cast(dataNode);
}
}
mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData);
return mimeData;
}
bool QmitkRenderWindowDataNodeTableModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent)
{
if (action == Qt::IgnoreAction)
{
return true;
}
if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs))
{
return false;
}
if (parent.isValid())
{
auto baseRenderer = m_BaseRenderer.Lock();
int layer = -1;
auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value();
if (nullptr != dataNode)
{
dataNode->GetIntProperty("layer", layer, baseRenderer);
}
auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data);
for (const auto& dataNode : qAsConst(dataNodeList))
{
m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer);
}
this->UpdateModelData();
return true;
}
return false;
}
diff --git a/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp
index cebc96e009..c1543e3f54 100644
--- a/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp
+++ b/Modules/QtWidgets/src/QmitkRenderWindowDataStorageTreeModel.cpp
@@ -1,606 +1,608 @@
/*============================================================================
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.
============================================================================*/
// render window manager UI module
#include "QmitkRenderWindowDataStorageTreeModel.h"
#include
// qt widgets module
#include "QmitkCustomVariants.h"
#include "QmitkEnums.h"
#include "QmitkMimeTypes.h"
#include "QmitkNodeDescriptorManager.h"
+#include
+
QmitkRenderWindowDataStorageTreeModel::QmitkRenderWindowDataStorageTreeModel(QObject* parent /*= nullptr*/)
: QmitkAbstractDataStorageModel(parent)
, m_Root(nullptr)
{
m_RenderWindowLayerController = std::make_unique();
ResetTree();
}
void QmitkRenderWindowDataStorageTreeModel::DataStorageChanged()
{
m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock());
ResetTree();
UpdateModelData();
}
void QmitkRenderWindowDataStorageTreeModel::NodePredicateChanged()
{
ResetTree();
UpdateModelData();
}
void QmitkRenderWindowDataStorageTreeModel::NodeAdded(const mitk::DataNode* node)
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return;
}
if (m_NodePredicate.IsNotNull())
{
if (m_NodePredicate->CheckNode(node))
{
AddNodeInternal(node, baseRenderer);
}
}
}
void QmitkRenderWindowDataStorageTreeModel::NodeChanged(const mitk::DataNode* node)
{
auto item = m_Root->Find(node);
if (nullptr != item)
{
auto parentItem = item->GetParent();
// as the root node should not be removed one should always have a parent item
if (nullptr == parentItem)
{
return;
}
auto index = createIndex(item->GetIndex(), 0, item);
emit dataChanged(index, index);
}
}
void QmitkRenderWindowDataStorageTreeModel::NodeRemoved(const mitk::DataNode* node)
{
RemoveNodeInternal(node);
}
QModelIndex QmitkRenderWindowDataStorageTreeModel::index(int row, int column, const QModelIndex& parent) const
{
auto item = GetItemByIndex(parent);
if (nullptr != item)
{
item = item->GetChild(row);
}
if (nullptr == item)
{
return QModelIndex();
}
return createIndex(row, column, item);
}
QModelIndex QmitkRenderWindowDataStorageTreeModel::parent(const QModelIndex& parent) const
{
auto item = GetItemByIndex(parent);
if (nullptr != item)
{
item = item->GetParent();
}
if(nullptr == item)
{
return QModelIndex();
}
if (item == m_Root)
{
return QModelIndex();
}
return createIndex(item->GetIndex(), 0, item);
}
int QmitkRenderWindowDataStorageTreeModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{
auto item = GetItemByIndex(parent);
if (nullptr == item)
{
return 0;
}
return item->GetChildCount();
}
int QmitkRenderWindowDataStorageTreeModel::columnCount(const QModelIndex&/* parent = QModelIndex()*/) const
{
if (0 == m_Root->GetChildCount())
{
// no items stored, no need to display columns
return 0;
}
return 1;
}
QVariant QmitkRenderWindowDataStorageTreeModel::data(const QModelIndex& index, int role) const
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return QVariant();
}
if (!index.isValid() || this != index.model())
{
return QVariant();
}
auto item = GetItemByIndex(index);
if (nullptr == item)
{
return QVariant();
}
auto dataNode = item->GetDataNode();
if (nullptr == dataNode)
{
return QVariant();
}
if (Qt::CheckStateRole == role)
{
bool visibility = false;
dataNode->GetVisibility(visibility, baseRenderer);
if (visibility)
{
return Qt::Checked;
}
else
{
return Qt::Unchecked;
}
}
else if (Qt::DisplayRole == role)
{
return QVariant(QString::fromStdString(dataNode->GetName()));
}
else if (Qt::ToolTipRole == role)
{
return QVariant("Name of the data node.");
}
else if (Qt::DecorationRole == role)
{
QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode);
return nodeDescriptor->GetIcon(dataNode);
}
else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role)
{
// user role always returns a reference to the data node,
// which can be used to modify the data node in the data storage
return QVariant::fromValue(dataNode);
}
else if (QmitkDataNodeRole == role)
{
return QVariant::fromValue(mitk::DataNode::Pointer(dataNode));
}
return QVariant();
}
bool QmitkRenderWindowDataStorageTreeModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/)
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return false;
}
if (!index.isValid() || this != index.model())
{
return false;
}
auto item = GetItemByIndex(index);
if (nullptr == item)
{
return false;
}
auto dataNode = item->GetDataNode();
if (nullptr == dataNode)
{
return false;
}
if (Qt::EditRole == role && !value.toString().isEmpty())
{
dataNode->SetName(value.toString().toStdString().c_str());
emit dataChanged(index, index);
return true;
}
if (Qt::CheckStateRole == role)
{
Qt::CheckState newCheckState = static_cast(value.toInt());
bool isVisible = newCheckState;
dataNode->SetVisibility(isVisible, baseRenderer);
emit dataChanged(index, index);
mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow());
return true;
}
return false;
}
Qt::ItemFlags QmitkRenderWindowDataStorageTreeModel::flags(const QModelIndex& index) const
{
if (this != index.model())
{
return Qt::NoItemFlags;
}
if (!index.isValid())
{
return Qt::ItemIsDropEnabled;
}
auto item = GetItemByIndex(index);
if (nullptr == item)
{
return Qt::NoItemFlags;
}
const auto dataNode = item->GetDataNode();
if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode))
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
return Qt::NoItemFlags;
}
Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
Qt::DropActions QmitkRenderWindowDataStorageTreeModel::supportedDragActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
QStringList QmitkRenderWindowDataStorageTreeModel::mimeTypes() const
{
QStringList types = QAbstractItemModel::mimeTypes();
types << QmitkMimeTypes::DataNodePtrs;
return types;
}
QMimeData* QmitkRenderWindowDataStorageTreeModel::mimeData(const QModelIndexList& indexes) const
{
QMimeData* mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const auto& index : indexes)
{
if (index.isValid())
{
auto dataNode = data(index, QmitkDataNodeRawPointerRole).value();
stream << reinterpret_cast(dataNode);
}
}
mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData);
return mimeData;
}
bool QmitkRenderWindowDataStorageTreeModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex& parent)
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return false;
}
if (action == Qt::IgnoreAction)
{
return true;
}
if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs))
{
return false;
}
if (!parent.isValid())
{
return false;
}
int layer = -1;
auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value();
if (nullptr != dataNode)
{
dataNode->GetIntProperty("layer", layer, baseRenderer);
}
auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data);
for (const auto& dataNode : qAsConst(dataNodeList))
{
m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer);
}
ResetTree();
UpdateModelData();
AdjustLayerProperty();
return true;
}
void QmitkRenderWindowDataStorageTreeModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector controlledRenderer)
{
ResetTree();
auto dataStorage = m_DataStorage.Lock();
if (dataStorage.IsNull())
{
return;
}
for (const auto& renderer : controlledRenderer)
{
if (nullptr == renderer)
{
continue;
}
auto allDataNodes = dataStorage->GetAll();
for (const auto& dataNode : *allDataNodes)
{
// add the node to each render window
mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, renderer);
}
}
}
void QmitkRenderWindowDataStorageTreeModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer)
{
if (m_BaseRenderer == baseRenderer)
{
return;
}
// base renderer changed
// reset tree to build a new renderer-specific item hierarchy
m_BaseRenderer = baseRenderer;
ResetTree();
UpdateModelData();
}
mitk::BaseRenderer::Pointer QmitkRenderWindowDataStorageTreeModel::GetCurrentRenderer() const
{
return m_BaseRenderer.Lock();
}
void QmitkRenderWindowDataStorageTreeModel::ResetTree()
{
beginResetModel();
if (nullptr != m_Root)
{
m_Root->Delete();
}
mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New();
rootDataNode->SetName("Data Storage");
m_Root = new QmitkDataStorageTreeModelInternalItem(rootDataNode);
endResetModel();
}
void QmitkRenderWindowDataStorageTreeModel::UpdateModelData()
{
auto dataStorage = m_DataStorage.Lock();
if (dataStorage.IsNotNull())
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNotNull())
{
auto allDataNodes = dataStorage->GetAll();
for (const auto& dataNode : *allDataNodes)
{
// add the node to each render window
mitk::RenderWindowLayerUtilities::SetRenderWindowProperties(dataNode, baseRenderer);
}
if (m_NodePredicate.IsNotNull())
{
auto filteredDataNodes = dataStorage->GetSubset(m_NodePredicate);
for (const auto& dataNode : *filteredDataNodes)
{
AddNodeInternal(dataNode, baseRenderer);
}
}
}
}
}
void QmitkRenderWindowDataStorageTreeModel::AdjustLayerProperty()
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return;
}
std::vector treeAsVector;
TreeToVector(m_Root, treeAsVector);
int i = treeAsVector.size() - 1;
for (auto it = treeAsVector.begin(); it != treeAsVector.end(); ++it)
{
auto dataNode = (*it)->GetDataNode();
dataNode->SetIntProperty("layer", i, baseRenderer);
--i;
}
}
void QmitkRenderWindowDataStorageTreeModel::TreeToVector(QmitkDataStorageTreeModelInternalItem* parent, std::vector& treeAsVector) const
{
QmitkDataStorageTreeModelInternalItem* item;
for (int i = 0; i < parent->GetChildCount(); ++i)
{
item = parent->GetChild(i);
TreeToVector(item, treeAsVector);
treeAsVector.push_back(item);
}
}
void QmitkRenderWindowDataStorageTreeModel::AddNodeInternal(const mitk::DataNode* dataNode, const mitk::BaseRenderer* renderer)
{
if (nullptr == dataNode
|| m_DataStorage.IsExpired()
|| nullptr != m_Root->Find(dataNode))
{
return;
}
// find out if we have a root node
auto parentItem = m_Root;
QModelIndex index;
auto parentDataNode = GetParentNode(dataNode);
if (nullptr != parentDataNode) // no top level data node
{
parentItem = m_Root->Find(parentDataNode);
if (nullptr == parentItem)
{
// parent node not contained in the tree; add it
NodeAdded(parentDataNode);
parentItem = m_Root->Find(parentDataNode);
if (nullptr == parentItem)
{
// could not find and add the parent tree; abort
return;
}
}
// get the index of this parent with the help of the grand parent
index = createIndex(parentItem->GetIndex(), 0, parentItem);
}
int firstRowWithASiblingBelow = 0;
int nodeLayer = -1;
dataNode->GetIntProperty("layer", nodeLayer, renderer);
for (const auto& siblingItem : parentItem->GetChildren())
{
int siblingLayer = -1;
auto siblingNode = siblingItem->GetDataNode();
if (nullptr != siblingNode)
{
siblingNode->GetIntProperty("layer", siblingLayer, renderer);
}
if (nodeLayer > siblingLayer)
{
break;
}
++firstRowWithASiblingBelow;
}
beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow);
auto newNode = new QmitkDataStorageTreeModelInternalItem(const_cast(dataNode));
parentItem->InsertChild(newNode, firstRowWithASiblingBelow);
endInsertRows();
}
void QmitkRenderWindowDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode* dataNode)
{
if (nullptr == dataNode
|| nullptr == m_Root)
{
return;
}
auto item = m_Root->Find(dataNode);
if (nullptr == item)
{
return;
}
auto parentItem = item->GetParent();
auto parentIndex = GetIndexByItem(parentItem);
auto children = item->GetChildren();
beginRemoveRows(parentIndex, item->GetIndex(), item->GetIndex());
parentItem->RemoveChild(item);
delete item;
endRemoveRows();
if (!children.empty())
{
// rebuild tree because children could not be at the top level
ResetTree();
UpdateModelData();
}
}
mitk::DataNode* QmitkRenderWindowDataStorageTreeModel::GetParentNode(const mitk::DataNode* node) const
{
mitk::DataNode* dataNode = nullptr;
auto dataStorage = m_DataStorage.Lock();
if (dataStorage.IsNull())
{
return dataNode;
}
auto sources = dataStorage->GetSources(node);
if (sources->empty())
{
return dataNode;
}
return sources->front();
}
QmitkDataStorageTreeModelInternalItem* QmitkRenderWindowDataStorageTreeModel::GetItemByIndex(const QModelIndex& index) const
{
if (index.isValid())
{
return static_cast(index.internalPointer());
}
return m_Root;
}
QModelIndex QmitkRenderWindowDataStorageTreeModel::GetIndexByItem(QmitkDataStorageTreeModelInternalItem* item) const
{
if (item == m_Root)
{
return QModelIndex();
}
return createIndex(item->GetIndex(), 0, item);
}
diff --git a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp
index 0ea68a3046..7582a388a3 100644
--- a/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp
+++ b/Modules/QtWidgets/src/QmitkRenderWindowMenu.cpp
@@ -1,578 +1,579 @@
/*============================================================================
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 "QmitkRenderWindowMenu.h"
// mitk core
#include "mitkProperties.h"
#include "mitkResliceMethodProperty.h"
// qt
+#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include"iconClose.xpm"
#include "iconCrosshairMode.xpm"
#include "iconFullScreen.xpm"
//#include"iconHoriSplit.xpm"
#include "iconSettings.xpm"
//#include"iconVertiSplit.xpm"
#include "iconLeaveFullScreen.xpm"
// c++
#include
unsigned int QmitkRenderWindowMenu::m_DefaultThickMode(1);
QmitkRenderWindowMenu::QmitkRenderWindowMenu(QWidget* parent,
Qt::WindowFlags flags,
mitk::BaseRenderer* baseRenderer)
: QWidget(parent, flags)
, m_LayoutActionsMenu(nullptr)
, m_CrosshairMenu(nullptr)
, m_FullScreenMode(false)
, m_Renderer(baseRenderer)
, m_Parent(parent)
, m_CrosshairRotationMode(0)
, m_CrosshairVisibility(true)
, m_Layout(LayoutIndex::Axial)
, m_LayoutDesign(LayoutDesign::DEFAULT)
, m_OldLayoutDesign(LayoutDesign::DEFAULT)
{
CreateMenuWidget();
setMinimumWidth(61); // DIRTY.. If you add or remove a button, you need to change the size.
setMaximumWidth(61);
setAutoFillBackground(true);
this->hide();
m_AutoRotationTimer = new QTimer(this);
m_AutoRotationTimer->setInterval(75);
connect(m_AutoRotationTimer, &QTimer::timeout, this, &QmitkRenderWindowMenu::AutoRotateNextStep);
connect(m_Parent, &QObject::destroyed, this, &QmitkRenderWindowMenu::deleteLater);
}
QmitkRenderWindowMenu::~QmitkRenderWindowMenu()
{
if (m_AutoRotationTimer->isActive())
{
m_AutoRotationTimer->stop();
}
}
void QmitkRenderWindowMenu::SetLayoutIndex(LayoutIndex layoutIndex)
{
m_Layout = layoutIndex;
}
void QmitkRenderWindowMenu::UpdateLayoutDesignList(LayoutDesign layoutDesign)
{
m_LayoutDesign = layoutDesign;
if (nullptr == m_LayoutActionsMenu)
{
CreateSettingsWidget();
}
m_DefaultLayoutAction->setEnabled(true);
m_All2DTop3DBottomLayoutAction->setEnabled(true);
m_All2DLeft3DRightLayoutAction->setEnabled(true);
m_OneBigLayoutAction->setEnabled(true);
m_Only2DHorizontalLayoutAction->setEnabled(true);
m_Only2DVerticalLayoutAction->setEnabled(true);
m_OneTop3DBottomLayoutAction->setEnabled(true);
m_OneLeft3DRightLayoutAction->setEnabled(true);
m_AllHorizontalLayoutAction->setEnabled(true);
m_AllVerticalLayoutAction->setEnabled(true);
m_RemoveOneLayoutAction->setEnabled(true);
switch (m_LayoutDesign)
{
case LayoutDesign::DEFAULT:
{
m_DefaultLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ALL_2D_TOP_3D_BOTTOM:
{
m_All2DTop3DBottomLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ALL_2D_LEFT_3D_RIGHT:
{
m_All2DLeft3DRightLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ONE_BIG:
{
m_OneBigLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ONLY_2D_HORIZONTAL:
{
m_Only2DHorizontalLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ONLY_2D_VERTICAL:
{
m_Only2DVerticalLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ONE_TOP_3D_BOTTOM:
{
m_OneTop3DBottomLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ONE_LEFT_3D_RIGHT:
{
m_OneLeft3DRightLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ALL_HORIZONTAL:
{
m_AllHorizontalLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::ALL_VERTICAL:
{
m_AllVerticalLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::REMOVE_ONE:
{
m_RemoveOneLayoutAction->setEnabled(false);
break;
}
case LayoutDesign::NONE:
{
break;
}
}
}
void QmitkRenderWindowMenu::UpdateCrosshairVisibility(bool visible)
{
m_CrosshairVisibility = visible;
}
void QmitkRenderWindowMenu::UpdateCrosshairRotationMode(int mode)
{
m_CrosshairRotationMode = mode;
}
void QmitkRenderWindowMenu::MoveWidgetToCorrectPos()
{
int moveX = floor(static_cast(this->m_Parent->width()) - static_cast(this->width()) - 4.0);
this->move(moveX, 3);
auto cursorPos = this->mapFromGlobal(QCursor::pos());
if (cursorPos.x() < 0 || cursorPos.x() >= this->width() ||
cursorPos.y() < 0 || cursorPos.y() >= this->height())
{
this->HideMenu();
}
else
{
this->ShowMenu();
}
}
void QmitkRenderWindowMenu::ShowMenu()
{
MITK_DEBUG << "menu showMenu";
this->show();
this->raise();
}
void QmitkRenderWindowMenu::HideMenu()
{
MITK_DEBUG << "menu hideEvent";
this->hide();
}
void QmitkRenderWindowMenu::paintEvent(QPaintEvent * /*e*/)
{
QPainter painter(this);
QColor semiTransparentColor = Qt::black;
semiTransparentColor.setAlpha(255);
painter.fillRect(rect(), semiTransparentColor);
}
void QmitkRenderWindowMenu::CreateMenuWidget()
{
QHBoxLayout *layout = new QHBoxLayout(this);
layout->setAlignment(Qt::AlignRight);
layout->setContentsMargins(1, 1, 1, 1);
QSize size(13, 13);
m_CrosshairMenu = new QMenu(this);
connect(m_CrosshairMenu, &QMenu::aboutToShow, this, &QmitkRenderWindowMenu::OnCrosshairMenuAboutToShow);
m_CrosshairModeButton = new QToolButton(this);
m_CrosshairModeButton->setMaximumSize(15, 15);
m_CrosshairModeButton->setIconSize(size);
m_CrosshairModeButton->setMenu(m_CrosshairMenu);
m_CrosshairModeButton->setIcon(QIcon(QPixmap(iconCrosshairMode_xpm)));
m_CrosshairModeButton->setPopupMode(QToolButton::InstantPopup);
m_CrosshairModeButton->setStyleSheet("QToolButton::menu-indicator { image: none; }");
m_CrosshairModeButton->setAutoRaise(true);
layout->addWidget(m_CrosshairModeButton);
m_FullScreenButton = new QToolButton(this);
m_FullScreenButton->setMaximumSize(15, 15);
m_FullScreenButton->setIconSize(size);
m_FullScreenButton->setIcon(QIcon(QPixmap(iconFullScreen_xpm)));
m_FullScreenButton->setAutoRaise(true);
layout->addWidget(m_FullScreenButton);
m_LayoutDesignButton = new QToolButton(this);
m_LayoutDesignButton->setMaximumSize(15, 15);
m_LayoutDesignButton->setIconSize(size);
m_LayoutDesignButton->setIcon(QIcon(QPixmap(iconSettings_xpm)));
m_LayoutDesignButton->setAutoRaise(true);
layout->addWidget(m_LayoutDesignButton);
connect(m_FullScreenButton, &QToolButton::clicked, this, &QmitkRenderWindowMenu::OnFullScreenButton);
connect(m_LayoutDesignButton, &QToolButton::clicked, this, &QmitkRenderWindowMenu::OnLayoutDesignButton);
}
void QmitkRenderWindowMenu::CreateSettingsWidget()
{
m_LayoutActionsMenu = new QMenu(this);
m_DefaultLayoutAction = new QAction("Standard layout", m_LayoutActionsMenu);
m_DefaultLayoutAction->setDisabled(true);
m_All2DTop3DBottomLayoutAction = new QAction("All 2D top, 3D bottom", m_LayoutActionsMenu);
m_All2DTop3DBottomLayoutAction->setDisabled(false);
m_All2DLeft3DRightLayoutAction = new QAction("All 2D left, 3D right", m_LayoutActionsMenu);
m_All2DLeft3DRightLayoutAction->setDisabled(false);
m_OneBigLayoutAction = new QAction("This big", m_LayoutActionsMenu);
m_OneBigLayoutAction->setDisabled(false);
m_Only2DHorizontalLayoutAction = new QAction("Only 2D horizontal", m_LayoutActionsMenu);
m_Only2DHorizontalLayoutAction->setDisabled(false);
m_Only2DVerticalLayoutAction = new QAction("Only 2D vertical", m_LayoutActionsMenu);
m_Only2DVerticalLayoutAction->setDisabled(false);
m_OneTop3DBottomLayoutAction = new QAction("This top, 3D bottom", m_LayoutActionsMenu);
m_OneTop3DBottomLayoutAction->setDisabled(false);
m_OneLeft3DRightLayoutAction = new QAction("This left, 3D right", m_LayoutActionsMenu);
m_OneLeft3DRightLayoutAction->setDisabled(false);
m_AllHorizontalLayoutAction = new QAction("All horizontal", m_LayoutActionsMenu);
m_AllHorizontalLayoutAction->setDisabled(false);
m_AllVerticalLayoutAction = new QAction("All vertical", m_LayoutActionsMenu);
m_AllVerticalLayoutAction->setDisabled(false);
m_RemoveOneLayoutAction = new QAction("Remove this", m_LayoutActionsMenu);
m_RemoveOneLayoutAction->setDisabled(false);
m_LayoutActionsMenu->addAction(m_DefaultLayoutAction);
m_LayoutActionsMenu->addAction(m_All2DTop3DBottomLayoutAction);
m_LayoutActionsMenu->addAction(m_All2DLeft3DRightLayoutAction);
m_LayoutActionsMenu->addAction(m_OneBigLayoutAction);
m_LayoutActionsMenu->addAction(m_Only2DHorizontalLayoutAction);
m_LayoutActionsMenu->addAction(m_Only2DVerticalLayoutAction);
m_LayoutActionsMenu->addAction(m_OneTop3DBottomLayoutAction);
m_LayoutActionsMenu->addAction(m_OneLeft3DRightLayoutAction);
m_LayoutActionsMenu->addAction(m_AllHorizontalLayoutAction);
m_LayoutActionsMenu->addAction(m_AllVerticalLayoutAction);
m_LayoutActionsMenu->addAction(m_RemoveOneLayoutAction);
m_LayoutActionsMenu->setVisible(false);
connect(m_DefaultLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::DEFAULT); });
connect(m_All2DTop3DBottomLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_2D_TOP_3D_BOTTOM); });
connect(m_All2DLeft3DRightLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_2D_LEFT_3D_RIGHT); });
connect(m_OneBigLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_BIG); });
connect(m_Only2DHorizontalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONLY_2D_HORIZONTAL); });
connect(m_Only2DVerticalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONLY_2D_VERTICAL); });
connect(m_OneTop3DBottomLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_TOP_3D_BOTTOM); });
connect(m_OneLeft3DRightLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ONE_LEFT_3D_RIGHT); });
connect(m_AllHorizontalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_HORIZONTAL); });
connect(m_AllVerticalLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::ALL_VERTICAL); });
connect(m_RemoveOneLayoutAction, &QAction::triggered, [this]() { this->OnSetLayout(LayoutDesign::REMOVE_ONE); });
}
void QmitkRenderWindowMenu::ChangeFullScreenIcon()
{
m_FullScreenButton->setIcon(m_FullScreenMode ? QPixmap(iconLeaveFullScreen_xpm) : QPixmap(iconFullScreen_xpm));
}
void QmitkRenderWindowMenu::AutoRotateNextStep()
{
if (m_Renderer->GetCameraRotationController())
{
m_Renderer->GetCameraRotationController()->GetStepper()->Next();
}
}
void QmitkRenderWindowMenu::OnAutoRotationActionTriggered()
{
if (m_AutoRotationTimer->isActive())
{
m_AutoRotationTimer->stop();
m_Renderer->GetCameraRotationController()->GetStepper()->PingPongOff();
}
else
{
m_Renderer->GetCameraRotationController()->GetStepper()->PingPongOn();
m_AutoRotationTimer->start();
}
}
void QmitkRenderWindowMenu::OnTSNumChanged(int num)
{
MITK_DEBUG << "Thickslices num: " << num << " on renderer " << m_Renderer.GetPointer();
if (m_Renderer.IsNotNull())
{
unsigned int thickSlicesMode = 0;
// determine the state of the thick-slice mode
mitk::ResliceMethodProperty *resliceMethodEnumProperty = nullptr;
if(m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty(resliceMethodEnumProperty, "reslice.thickslices") && resliceMethodEnumProperty)
{
thickSlicesMode = resliceMethodEnumProperty->GetValueAsId();
if(thickSlicesMode!=0)
m_DefaultThickMode = thickSlicesMode;
}
if(thickSlicesMode==0 && num>0) //default mode only for single slices
{
thickSlicesMode = m_DefaultThickMode; //mip default
m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea",
mitk::BoolProperty::New(true));
}
if(num<1)
{
thickSlicesMode = 0;
m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.showarea",
mitk::BoolProperty::New(false));
}
m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices",
mitk::ResliceMethodProperty::New(thickSlicesMode));
m_Renderer->GetCurrentWorldPlaneGeometryNode()->SetProperty("reslice.thickslices.num",
mitk::IntProperty::New(num));
m_TSLabel->setText(QString::number(num * 2 + 1));
m_Renderer->SendUpdateSlice();
mitk::RenderingManager::GetInstance()->RequestUpdateAll();
}
}
void QmitkRenderWindowMenu::OnCrosshairMenuAboutToShow()
{
QMenu *crosshairModesMenu = m_CrosshairMenu;
crosshairModesMenu->clear();
QAction *resetViewAction = new QAction(crosshairModesMenu);
resetViewAction->setText("Reset view");
crosshairModesMenu->addAction(resetViewAction);
connect(resetViewAction, &QAction::triggered, this, &QmitkRenderWindowMenu::ResetView);
// Show hide crosshairs
{
QAction *showHideCrosshairVisibilityAction = new QAction(crosshairModesMenu);
showHideCrosshairVisibilityAction->setText("Show crosshair");
showHideCrosshairVisibilityAction->setCheckable(true);
showHideCrosshairVisibilityAction->setChecked(m_CrosshairVisibility);
crosshairModesMenu->addAction(showHideCrosshairVisibilityAction);
connect(showHideCrosshairVisibilityAction, &QAction::toggled, this, &QmitkRenderWindowMenu::OnCrosshairVisibilityChanged);
}
// Rotation mode
{
QAction *rotationGroupSeparator = new QAction(crosshairModesMenu);
rotationGroupSeparator->setSeparator(true);
rotationGroupSeparator->setText("Rotation mode");
crosshairModesMenu->addAction(rotationGroupSeparator);
QActionGroup *rotationModeActionGroup = new QActionGroup(crosshairModesMenu);
rotationModeActionGroup->setExclusive(true);
QAction *noCrosshairRotation = new QAction(crosshairModesMenu);
noCrosshairRotation->setActionGroup(rotationModeActionGroup);
noCrosshairRotation->setText("No crosshair rotation");
noCrosshairRotation->setCheckable(true);
noCrosshairRotation->setChecked(m_CrosshairRotationMode == 0);
noCrosshairRotation->setData(0);
crosshairModesMenu->addAction(noCrosshairRotation);
QAction *singleCrosshairRotation = new QAction(crosshairModesMenu);
singleCrosshairRotation->setActionGroup(rotationModeActionGroup);
singleCrosshairRotation->setText("Crosshair rotation");
singleCrosshairRotation->setCheckable(true);
singleCrosshairRotation->setChecked(m_CrosshairRotationMode == 1);
singleCrosshairRotation->setData(1);
crosshairModesMenu->addAction(singleCrosshairRotation);
QAction *coupledCrosshairRotation = new QAction(crosshairModesMenu);
coupledCrosshairRotation->setActionGroup(rotationModeActionGroup);
coupledCrosshairRotation->setText("Coupled crosshair rotation");
coupledCrosshairRotation->setCheckable(true);
coupledCrosshairRotation->setChecked(m_CrosshairRotationMode == 2);
coupledCrosshairRotation->setData(2);
crosshairModesMenu->addAction(coupledCrosshairRotation);
QAction *swivelMode = new QAction(crosshairModesMenu);
swivelMode->setActionGroup(rotationModeActionGroup);
swivelMode->setText("Swivel mode");
swivelMode->setCheckable(true);
swivelMode->setChecked(m_CrosshairRotationMode == 3);
swivelMode->setData(3);
crosshairModesMenu->addAction(swivelMode);
connect(rotationModeActionGroup, &QActionGroup::triggered, this, &QmitkRenderWindowMenu::OnCrosshairRotationModeSelected);
}
// auto rotation support
if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard3D)
{
QAction *autoRotationGroupSeparator = new QAction(crosshairModesMenu);
autoRotationGroupSeparator->setSeparator(true);
crosshairModesMenu->addAction(autoRotationGroupSeparator);
QAction *autoRotationAction = crosshairModesMenu->addAction("Auto Rotation");
autoRotationAction->setCheckable(true);
autoRotationAction->setChecked(m_AutoRotationTimer->isActive());
connect(autoRotationAction, &QAction::triggered, this, &QmitkRenderWindowMenu::OnAutoRotationActionTriggered);
}
// Thickslices support
if (m_Renderer.IsNotNull() && m_Renderer->GetMapperID() == mitk::BaseRenderer::Standard2D)
{
QAction *thickSlicesGroupSeparator = new QAction(crosshairModesMenu);
thickSlicesGroupSeparator->setSeparator(true);
thickSlicesGroupSeparator->setText("ThickSlices mode");
crosshairModesMenu->addAction(thickSlicesGroupSeparator);
QActionGroup *thickSlicesActionGroup = new QActionGroup(crosshairModesMenu);
thickSlicesActionGroup->setExclusive(true);
int currentMode = 0;
{
mitk::ResliceMethodProperty::Pointer m = dynamic_cast(
m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices"));
if (m.IsNotNull())
currentMode = m->GetValueAsId();
}
int currentNum = 1;
{
mitk::IntProperty::Pointer m = dynamic_cast(
m_Renderer->GetCurrentWorldPlaneGeometryNode()->GetProperty("reslice.thickslices.num"));
if (m.IsNotNull())
{
currentNum = m->GetValue();
}
}
if (currentMode == 0)
currentNum = 0;
QSlider *m_TSSlider = new QSlider(crosshairModesMenu);
m_TSSlider->setMinimum(0);
m_TSSlider->setMaximum(50);
m_TSSlider->setValue(currentNum);
m_TSSlider->setOrientation(Qt::Horizontal);
connect(m_TSSlider, &QSlider::valueChanged, this, &QmitkRenderWindowMenu::OnTSNumChanged);
QHBoxLayout *tsLayout = new QHBoxLayout;
tsLayout->setContentsMargins(4, 4, 4, 4);
tsLayout->addWidget(new QLabel("TS: "));
tsLayout->addWidget(m_TSSlider);
tsLayout->addWidget(m_TSLabel = new QLabel(QString::number(currentNum * 2 + 1), this));
QWidget *tsWidget = new QWidget;
tsWidget->setLayout(tsLayout);
QWidgetAction *m_TSSliderAction = new QWidgetAction(crosshairModesMenu);
m_TSSliderAction->setDefaultWidget(tsWidget);
crosshairModesMenu->addAction(m_TSSliderAction);
}
}
void QmitkRenderWindowMenu::OnCrosshairVisibilityChanged(bool visible)
{
UpdateCrosshairVisibility(visible);
emit CrosshairVisibilityChanged(m_CrosshairVisibility);
}
void QmitkRenderWindowMenu::OnCrosshairRotationModeSelected(QAction *action)
{
UpdateCrosshairRotationMode(action->data().toInt());
emit CrosshairRotationModeChanged(m_CrosshairRotationMode);
}
void QmitkRenderWindowMenu::OnFullScreenButton(bool /*checked*/)
{
if (!m_FullScreenMode)
{
m_FullScreenMode = true;
m_OldLayoutDesign = m_LayoutDesign;
emit LayoutDesignChanged(LayoutDesign::ONE_BIG);
}
else
{
m_FullScreenMode = false;
emit LayoutDesignChanged(m_OldLayoutDesign);
}
MoveWidgetToCorrectPos();
ChangeFullScreenIcon();
ShowMenu();
}
void QmitkRenderWindowMenu::OnLayoutDesignButton(bool /*checked*/)
{
if (nullptr == m_LayoutActionsMenu)
{
CreateSettingsWidget();
}
QPoint point = mapToGlobal(m_LayoutDesignButton->geometry().topLeft());
m_LayoutActionsMenu->setVisible(true);
m_LayoutActionsMenu->exec(point);
}
void QmitkRenderWindowMenu::OnSetLayout(LayoutDesign layoutDesign)
{
m_FullScreenMode = false;
ChangeFullScreenIcon();
m_LayoutDesign = layoutDesign;
emit LayoutDesignChanged(m_LayoutDesign);
ShowMenu();
}
diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp
index efba98a992..5177ec6657 100644
--- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp
+++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowDataStorageListModel.cpp
@@ -1,350 +1,352 @@
/*============================================================================
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.
============================================================================*/
// render window manager UI module
#include "QmitkRenderWindowDataStorageListModel.h"
// qt widgets module
#include "QmitkCustomVariants.h"
#include "QmitkEnums.h"
#include "QmitkMimeTypes.h"
#include "QmitkNodeDescriptorManager.h"
+#include
+
QmitkRenderWindowDataStorageListModel::QmitkRenderWindowDataStorageListModel(QObject* parent /*= nullptr*/)
: QmitkAbstractDataStorageModel(parent)
{
m_RenderWindowLayerController = std::make_unique();
}
void QmitkRenderWindowDataStorageListModel::DataStorageChanged()
{
m_RenderWindowLayerController->SetDataStorage(m_DataStorage.Lock());
UpdateModelData();
}
void QmitkRenderWindowDataStorageListModel::NodePredicateChanged()
{
UpdateModelData();
}
void QmitkRenderWindowDataStorageListModel::NodeAdded(const mitk::DataNode* node)
{
// add a node to each render window specific list (or to a global list initially)
AddDataNodeToAllRenderer(const_cast(node));
UpdateModelData();
}
void QmitkRenderWindowDataStorageListModel::NodeChanged(const mitk::DataNode* /*node*/)
{
// nothing here, since the "'NodeChanged'-event is currently sent far too often
}
void QmitkRenderWindowDataStorageListModel::NodeRemoved(const mitk::DataNode* /*node*/)
{
// update model data to create a new list without the removed data node
UpdateModelData();
}
QModelIndex QmitkRenderWindowDataStorageListModel::index(int row, int column, const QModelIndex& parent) const
{
bool hasIndex = this->hasIndex(row, column, parent);
if (hasIndex)
{
return this->createIndex(row, column);
}
return QModelIndex();
}
QModelIndex QmitkRenderWindowDataStorageListModel::parent(const QModelIndex& /*child*/) const
{
return QModelIndex();
}
int QmitkRenderWindowDataStorageListModel::rowCount(const QModelIndex& parent /*= QModelIndex()*/) const
{
if (parent.isValid())
{
return 0;
}
return static_cast(m_LayerStack.size());
}
int QmitkRenderWindowDataStorageListModel::columnCount(const QModelIndex& parent /*= QModelIndex()*/) const
{
if (parent.isValid())
{
return 0;
}
return 1;
}
QVariant QmitkRenderWindowDataStorageListModel::data(const QModelIndex& index, int role) const
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return QVariant();
}
if (!index.isValid() || this != index.model())
{
return QVariant();
}
if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size()))
{
return QVariant();
}
mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin();
std::advance(layerStackIt, index.row());
mitk::DataNode* dataNode = layerStackIt->second;
if (Qt::CheckStateRole == role)
{
bool visibility = false;
dataNode->GetVisibility(visibility, baseRenderer);
if (visibility)
{
return Qt::Checked;
}
else
{
return Qt::Unchecked;
}
}
else if (Qt::DisplayRole == role)
{
return QVariant(QString::fromStdString(dataNode->GetName()));
}
else if (Qt::ToolTipRole == role)
{
return QVariant("Name of the data node.");
}
else if (Qt::DecorationRole == role)
{
QmitkNodeDescriptor* nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode);
return nodeDescriptor->GetIcon(dataNode);
}
else if (Qt::UserRole == role || QmitkDataNodeRawPointerRole == role)
{
// user role always returns a reference to the data node,
// which can be used to modify the data node in the data storage
return QVariant::fromValue(dataNode);
}
else if (QmitkDataNodeRole == role)
{
return QVariant::fromValue(mitk::DataNode::Pointer(dataNode));
}
return QVariant();
}
bool QmitkRenderWindowDataStorageListModel::setData(const QModelIndex& index, const QVariant& value, int role /*= Qt::EditRole*/)
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return false;
}
if (!index.isValid() || this != index.model())
{
return false;
}
if (index.row() < 0 || index.row() >= static_cast(m_LayerStack.size()))
{
return false;
}
mitk::RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_LayerStack.begin();
std::advance(layerStackIt, index.row());
mitk::DataNode* dataNode = layerStackIt->second;
if (Qt::CheckStateRole == role)
{
Qt::CheckState newCheckState = static_cast(value.toInt());
bool isVisible = newCheckState;
dataNode->SetVisibility(isVisible, baseRenderer);
emit dataChanged(index, index);
mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow());
return true;
}
return false;
}
Qt::ItemFlags QmitkRenderWindowDataStorageListModel::flags(const QModelIndex &index) const
{
if (this != index.model())
{
return Qt::NoItemFlags;
}
if (!index.isValid())
{
return Qt::ItemIsDropEnabled;
}
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled;
}
Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
Qt::DropActions QmitkRenderWindowDataStorageListModel::supportedDragActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
QStringList QmitkRenderWindowDataStorageListModel::mimeTypes() const
{
QStringList types = QAbstractItemModel::mimeTypes();
types << QmitkMimeTypes::DataNodePtrs;
return types;
}
QMimeData* QmitkRenderWindowDataStorageListModel::mimeData(const QModelIndexList& indexes) const
{
QMimeData* mimeData = new QMimeData();
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
for (const auto& index : indexes)
{
if (index.isValid())
{
auto dataNode = data(index, QmitkDataNodeRawPointerRole).value();
stream << reinterpret_cast(dataNode);
}
}
mimeData->setData(QmitkMimeTypes::DataNodePtrs, encodedData);
return mimeData;
}
bool QmitkRenderWindowDataStorageListModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int /*row*/, int column, const QModelIndex& parent)
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNull())
{
return false;
}
if (action == Qt::IgnoreAction)
{
return true;
}
if (!data->hasFormat(QmitkMimeTypes::DataNodePtrs))
{
return false;
}
if (column > 0)
{
return false;
}
if (parent.isValid())
{
int layer = -1;
auto dataNode = this->data(parent, QmitkDataNodeRawPointerRole).value();
if (nullptr != dataNode)
{
dataNode->GetIntProperty("layer", layer, baseRenderer);
}
auto dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data);
for (const auto& dataNode : qAsConst(dataNodeList))
{
m_RenderWindowLayerController->MoveNodeToPosition(dataNode, layer, baseRenderer);
}
UpdateModelData();
return true;
}
return false;
}
void QmitkRenderWindowDataStorageListModel::SetControlledRenderer(mitk::RenderWindowLayerUtilities::RendererVector /*controlledRenderer*/)
{
auto dataStorage = m_DataStorage.Lock();
if (dataStorage.IsNotNull())
{
mitk::DataStorage::SetOfObjects::ConstPointer allDataNodes = dataStorage->GetAll();
for (mitk::DataStorage::SetOfObjects::ConstIterator it = allDataNodes->Begin(); it != allDataNodes->End(); ++it)
{
mitk::DataNode::Pointer dataNode = it->Value();
if (dataNode.IsNull())
{
continue;
}
AddDataNodeToAllRenderer(dataNode);
}
}
}
void QmitkRenderWindowDataStorageListModel::SetCurrentRenderer(mitk::BaseRenderer* baseRenderer)
{
if (m_BaseRenderer == baseRenderer)
{
return;
}
m_BaseRenderer = baseRenderer;
if (!m_BaseRenderer.IsExpired())
{
UpdateModelData();
}
}
mitk::BaseRenderer::Pointer QmitkRenderWindowDataStorageListModel::GetCurrentRenderer() const
{
return m_BaseRenderer.Lock();
}
void QmitkRenderWindowDataStorageListModel::AddDataNodeToAllRenderer(mitk::DataNode* dataNode)
{
m_RenderWindowLayerController->InsertLayerNode(dataNode);
}
void QmitkRenderWindowDataStorageListModel::UpdateModelData()
{
auto dataStorage = m_DataStorage.Lock();
if (dataStorage.IsNotNull())
{
auto baseRenderer = m_BaseRenderer.Lock();
if (baseRenderer.IsNotNull())
{
// update the model, so that it will be filled with the nodes of the new data storage
beginResetModel();
// get the current layer stack of the given base renderer
m_LayerStack = mitk::RenderWindowLayerUtilities::GetLayerStack(dataStorage, baseRenderer);
endResetModel();
}
}
}
diff --git a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp
index 8f294d0934..262b7a99cf 100755
--- a/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp
+++ b/Modules/SegmentationUI/Qmitk/QmitkToolSelectionBox.cpp
@@ -1,622 +1,623 @@
/*============================================================================
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.
============================================================================*/
//#define MBILOG_ENABLE_DEBUG 1
#include
#include "QmitkToolSelectionBox.h"
#include "QmitkToolGUI.h"
#include "mitkBaseRenderer.h"
#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include "usModuleResource.h"
#include "usModuleResourceStream.h"
#include "mitkToolManagerProvider.h"
QmitkToolSelectionBox::QmitkToolSelectionBox(QWidget *parent, mitk::DataStorage *)
: QWidget(parent),
m_SelfCall(false),
m_DisplayedGroups("default"),
m_LayoutColumns(2),
m_ShowNames(true),
m_GenerateAccelerators(false),
m_ToolGUIWidget(nullptr),
m_LastToolGUI(nullptr),
m_ToolButtonGroup(nullptr),
m_ButtonLayout(nullptr)
{
QFont currentFont = QWidget::font();
currentFont.setBold(true);
QWidget::setFont(currentFont);
m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager();
// QButtonGroup
m_ToolButtonGroup = new QButtonGroup(this);
// some features of QButtonGroup
m_ToolButtonGroup->setExclusive(false); // mutually exclusive toggle buttons
RecreateButtons();
QWidget::setContentsMargins(0, 0, 0, 0);
if (layout() != nullptr)
{
layout()->setContentsMargins(0, 0, 0, 0);
}
// reactions to signals
connect(m_ToolButtonGroup, &QButtonGroup::idClicked, this, &QmitkToolSelectionBox::toolButtonClicked);
// reactions to ToolManager events
m_ToolManager->ActiveToolChanged +=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified);
m_ToolManager->ReferenceDataChanged +=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified);
m_ToolManager->WorkingDataChanged +=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified);
// show active tool
SetOrUnsetButtonForActiveTool();
QWidget::setEnabled(false);
}
QmitkToolSelectionBox::~QmitkToolSelectionBox()
{
m_ToolManager->ActiveToolChanged -=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified);
m_ToolManager->ReferenceDataChanged -=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified);
m_ToolManager->WorkingDataChanged -=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified);
}
mitk::ToolManager *QmitkToolSelectionBox::GetToolManager()
{
return m_ToolManager;
}
void QmitkToolSelectionBox::SetToolManager(
mitk::ToolManager &newManager) // no nullptr pointer allowed here, a manager is required
{
// say bye to the old manager
m_ToolManager->ActiveToolChanged -=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified);
m_ToolManager->ReferenceDataChanged -=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified);
m_ToolManager->WorkingDataChanged -=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified);
if (QWidget::isEnabled())
{
m_ToolManager->UnregisterClient();
}
m_ToolManager = &newManager;
RecreateButtons();
// greet the new one
m_ToolManager->ActiveToolChanged +=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerToolModified);
m_ToolManager->ReferenceDataChanged +=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerReferenceDataModified);
m_ToolManager->WorkingDataChanged +=
mitk::MessageDelegate(this, &QmitkToolSelectionBox::OnToolManagerWorkingDataModified);
if (QWidget::isEnabled())
{
m_ToolManager->RegisterClient();
}
// ask the new one what the situation is like
SetOrUnsetButtonForActiveTool();
}
void QmitkToolSelectionBox::toolButtonClicked(int id)
{
if (!QWidget::isEnabled())
return; // this method could be triggered from the constructor, when we are still disabled
MITK_DEBUG << "toolButtonClicked(" << id << "): id translates to tool ID " << m_ToolIDForButtonID[id];
QToolButton *toolButton = dynamic_cast(m_ToolButtonGroup->buttons().at(id));
if (toolButton)
{
if ((m_ButtonIDForToolID.find(m_ToolManager->GetActiveToolID()) !=
m_ButtonIDForToolID.end()) // if we have this tool in our box
&&
(m_ButtonIDForToolID[m_ToolManager->GetActiveToolID()] ==
id)) // the tool corresponding to this button is already active
{
// disable this button, disable all tools
toolButton->setChecked(false);
m_ToolManager->ActivateTool(-1); // disable everything
}
else
{
// enable the corresponding tool
m_SelfCall = true;
m_ToolManager->ActivateTool(m_ToolIDForButtonID[id]);
m_SelfCall = false;
}
}
}
void QmitkToolSelectionBox::OnToolManagerToolModified()
{
SetOrUnsetButtonForActiveTool();
}
void QmitkToolSelectionBox::SetOrUnsetButtonForActiveTool()
{
// we want to emit a signal in any case, whether we selected ourselves or somebody else changes "our" tool manager.
// --> emit before check on m_SelfCall
int id = m_ToolManager->GetActiveToolID();
// don't emit signal for shape model tools
bool emitSignal = true;
mitk::Tool *tool = m_ToolManager->GetActiveTool();
if (tool && std::string(tool->GetGroup()) == "organ_segmentation")
emitSignal = false;
if (emitSignal)
emit ToolSelected(id);
// delete old GUI (if any)
if (m_LastToolGUI && m_ToolGUIWidget)
{
if (m_ToolGUIWidget->layout())
{
m_ToolGUIWidget->layout()->removeWidget(m_LastToolGUI);
}
m_LastToolGUI->setParent(nullptr);
delete m_LastToolGUI; // will hopefully notify parent and layouts
m_LastToolGUI = nullptr;
QLayout *layout = m_ToolGUIWidget->layout();
if (layout)
{
layout->activate();
}
}
QToolButton *toolButton(nullptr);
if (m_ButtonIDForToolID.find(id) != m_ButtonIDForToolID.end()) // if this tool is in our box
{
toolButton = dynamic_cast(m_ToolButtonGroup->buttons().at(m_ButtonIDForToolID[id]));
}
if (toolButton)
{
// mmueller
// uncheck all other buttons
QAbstractButton *tmpBtn = nullptr;
for (int i = 0; i < m_ToolButtonGroup->buttons().size(); ++i)
{
tmpBtn = m_ToolButtonGroup->buttons().at(i);
if (tmpBtn != toolButton)
dynamic_cast(tmpBtn)->setChecked(false);
}
toolButton->setChecked(true);
if (m_ToolGUIWidget && tool)
{
// create and reparent new GUI (if any)
itk::Object::Pointer possibleGUI = tool->GetGUI("Qmitk", "GUI").GetPointer(); // prefix and postfix
if (possibleGUI.IsNull())
possibleGUI = tool->GetGUI("", "GUI").GetPointer();
QmitkToolGUI *gui = dynamic_cast(possibleGUI.GetPointer());
//!
m_LastToolGUI = gui;
if (gui)
{
gui->SetTool(tool);
gui->setParent(m_ToolGUIWidget);
gui->move(gui->geometry().topLeft());
gui->show();
QLayout *layout = m_ToolGUIWidget->layout();
if (!layout)
{
layout = new QVBoxLayout(m_ToolGUIWidget);
}
if (layout)
{
layout->addWidget(gui);
layout->activate();
}
}
}
}
else
{
// disable all buttons
QToolButton *selectedToolButton = dynamic_cast(m_ToolButtonGroup->checkedButton());
if (selectedToolButton)
{
selectedToolButton->setChecked(false);
}
}
}
void QmitkToolSelectionBox::OnToolManagerReferenceDataModified()
{
if (m_SelfCall)
return;
MITK_DEBUG << "OnToolManagerReferenceDataModified()";
this->UpdateButtonsEnabledState();
}
void QmitkToolSelectionBox::OnToolManagerWorkingDataModified()
{
if (m_SelfCall)
return;
MITK_DEBUG << "OnToolManagerWorkingDataModified()";
this->UpdateButtonsEnabledState();
}
void QmitkToolSelectionBox::setEnabled(bool enable)
{
if (QWidget::isEnabled() == enable)
return;
QWidget::setEnabled(enable);
if (enable)
{
m_ToolManager->RegisterClient();
auto id = m_ToolManager->GetActiveToolID();
emit ToolSelected(id);
}
else
{
m_ToolManager->ActivateTool(-1);
m_ToolManager->UnregisterClient();
emit ToolSelected(-1);
}
}
void QmitkToolSelectionBox::UpdateButtonsEnabledState()
{
auto buttons = m_ToolButtonGroup->buttons();
const auto refDataNode = m_ToolManager->GetReferenceData(0);
const mitk::BaseData* refData = nullptr;
if (nullptr != refDataNode)
{
refData = refDataNode->GetData();
}
const auto workingDataNode = m_ToolManager->GetWorkingData(0);
const mitk::BaseData* workingData = nullptr;
if (nullptr != workingDataNode)
{
workingData = workingDataNode->GetData();
}
for (const auto& button : qAsConst(buttons))
{
const auto buttonID = m_ToolButtonGroup->id(button);
const auto toolID = m_ToolIDForButtonID[buttonID];
const auto tool = m_ToolManager->GetToolById(toolID);
button->setEnabled(tool->CanHandle(refData, workingData));
}
}
void QmitkToolSelectionBox::RecreateButtons()
{
if (m_ToolManager.IsNull())
return;
QList l = m_ToolButtonGroup->buttons();
// remove all buttons that are there
QList::iterator it;
QAbstractButton *btn;
for (it = l.begin(); it != l.end(); ++it)
{
btn = *it;
m_ToolButtonGroup->removeButton(btn);
delete btn;
}
mitk::ToolManager::ToolVectorTypeConst allPossibleTools = m_ToolManager->GetTools();
mitk::ToolManager::ToolVectorTypeConst allTools;
typedef std::pair SortPairType;
typedef std::priority_queue SortedToolQueueType;
SortedToolQueueType toolPositions;
// clear and sort all tools
// step one: find name/group of all tools in m_DisplayedGroups string. remember these positions for all tools.
for (mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allPossibleTools.begin();
iter != allPossibleTools.end();
++iter)
{
const mitk::Tool *tool = *iter;
std::string::size_type namePos = m_DisplayedGroups.find(std::string("'") + tool->GetName() + "'");
std::string::size_type groupPos = m_DisplayedGroups.find(std::string("'") + tool->GetGroup() + "'");
if (!m_DisplayedGroups.empty() && namePos == std::string::npos && groupPos == std::string::npos)
continue; // skip
if (m_DisplayedGroups.empty() && std::string(tool->GetName()).length() > 0)
{
namePos = static_cast(tool->GetName()[0]);
}
SortPairType thisPair = std::make_pair(namePos < groupPos ? namePos : groupPos, *iter);
toolPositions.push(thisPair);
}
// step two: sort tools according to previously found positions in m_DisplayedGroups
MITK_DEBUG << "Sorting order of tools (lower number --> earlier in button group)";
while (!toolPositions.empty())
{
SortPairType thisPair = toolPositions.top();
MITK_DEBUG << "Position " << thisPair.first << " : " << thisPair.second->GetName();
allTools.push_back(thisPair.second);
toolPositions.pop();
}
std::reverse(allTools.begin(), allTools.end());
MITK_DEBUG << "Sorted tools:";
for (mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter)
{
MITK_DEBUG << (*iter)->GetName();
}
if (m_ButtonLayout == nullptr)
m_ButtonLayout = new QGridLayout;
int row(0);
int column(-1);
int currentButtonID(0);
m_ButtonIDForToolID.clear();
m_ToolIDForButtonID.clear();
QToolButton *button = nullptr;
MITK_DEBUG << "Creating buttons for tools";
// fill group box with buttons
for (mitk::ToolManager::ToolVectorTypeConst::const_iterator iter = allTools.begin(); iter != allTools.end(); ++iter)
{
const mitk::Tool *tool = *iter;
int currentToolID(m_ToolManager->GetToolID(tool));
++column;
// new line if we are at the maximum columns
if (column == m_LayoutColumns)
{
++row;
column = 0;
}
button = new QToolButton;
button->setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum));
// add new button to the group
MITK_DEBUG << "Adding button with ID " << currentToolID;
m_ToolButtonGroup->addButton(button, currentButtonID);
// ... and to the layout
MITK_DEBUG << "Adding button in row/column " << row << "/" << column;
m_ButtonLayout->addWidget(button, row, column);
if (m_LayoutColumns == 1)
{
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
}
else
{
button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
}
button->setCheckable(true);
if (currentToolID == m_ToolManager->GetActiveToolID())
button->setChecked(true);
QString label;
if (m_GenerateAccelerators)
{
label += "&";
}
label += tool->GetName();
QString tooltip = tool->GetName();
MITK_DEBUG << tool->GetName() << ", " << label.toLocal8Bit().constData() << ", '"
<< tooltip.toLocal8Bit().constData();
if (m_ShowNames)
{
button->setText(label); // a label
button->setToolTip(tooltip);
QFont currentFont = button->font();
currentFont.setBold(false);
button->setFont(currentFont);
}
us::ModuleResource iconResource = tool->GetIconResource();
if (!iconResource.IsValid())
{
button->setIcon(QIcon(QPixmap(tool->GetXPM())));
}
else
{
auto isSVG = "svg" == iconResource.GetSuffix();
auto openmode = isSVG ? std::ios_base::in : std::ios_base::binary;
us::ModuleResourceStream resourceStream(iconResource, openmode);
resourceStream.seekg(0, std::ios::end);
std::ios::pos_type length = resourceStream.tellg();
resourceStream.seekg(0, std::ios::beg);
char *data = new char[length];
resourceStream.read(data, length);
if (isSVG)
{
button->setIcon(QmitkStyleManager::ThemeIcon(QByteArray::fromRawData(data, length)));
}
else
{
QPixmap pixmap;
pixmap.loadFromData(QByteArray::fromRawData(data, length));
button->setIcon(QIcon(pixmap));
}
delete[] data;
if (m_ShowNames)
{
if (m_LayoutColumns == 1)
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
else
button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
button->setIconSize(QSize(24, 24));
}
else
{
button->setToolButtonStyle(Qt::ToolButtonIconOnly);
button->setIconSize(QSize(32, 32));
button->setToolTip(tooltip);
}
}
if (m_GenerateAccelerators)
{
QString firstLetter = QString(tool->GetName());
firstLetter.truncate(1);
button->setShortcut(
firstLetter); // a keyboard shortcut (just the first letter of the given name w/o any CTRL or something)
}
m_ButtonIDForToolID[currentToolID] = currentButtonID;
m_ToolIDForButtonID[currentButtonID] = currentToolID;
MITK_DEBUG << "m_ButtonIDForToolID[" << currentToolID << "] == " << currentButtonID;
MITK_DEBUG << "m_ToolIDForButtonID[" << currentButtonID << "] == " << currentToolID;
tool->GUIProcessEventsMessage += mitk::MessageDelegate(
this, &QmitkToolSelectionBox::OnToolGUIProcessEventsMessage); // will never add a listener twice, so we don't have
// to check here
tool->ErrorMessage += mitk::MessageDelegate1(
this,
&QmitkToolSelectionBox::OnToolErrorMessage); // will never add a listener twice, so we don't have to check here
tool->GeneralMessage +=
mitk::MessageDelegate1(this, &QmitkToolSelectionBox::OnGeneralToolMessage);
++currentButtonID;
}
// setting grid layout for this groupbox
this->setLayout(m_ButtonLayout);
this->UpdateButtonsEnabledState();
// this->update();
}
void QmitkToolSelectionBox::OnToolGUIProcessEventsMessage()
{
qApp->processEvents();
}
void QmitkToolSelectionBox::OnToolErrorMessage(std::string s)
{
QMessageBox::critical(
this, "MITK", QString(s.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
}
void QmitkToolSelectionBox::OnGeneralToolMessage(std::string s)
{
QMessageBox::information(
this, "MITK", QString(s.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton);
}
void QmitkToolSelectionBox::SetDisplayedToolGroups(const std::string &toolGroups)
{
if (m_DisplayedGroups != toolGroups)
{
QString q_DisplayedGroups = toolGroups.c_str();
// quote all unquoted single words
q_DisplayedGroups = q_DisplayedGroups.replace(QRegExp("\\b(\\w+)\\b|'([^']+)'"), "'\\1\\2'");
MITK_DEBUG << "m_DisplayedGroups was \"" << toolGroups << "\"";
m_DisplayedGroups = q_DisplayedGroups.toLocal8Bit().constData();
MITK_DEBUG << "m_DisplayedGroups is \"" << m_DisplayedGroups << "\"";
RecreateButtons();
SetOrUnsetButtonForActiveTool();
}
}
void QmitkToolSelectionBox::SetLayoutColumns(int columns)
{
if (columns > 0 && columns != m_LayoutColumns)
{
m_LayoutColumns = columns;
RecreateButtons();
}
}
void QmitkToolSelectionBox::SetShowNames(bool show)
{
if (show != m_ShowNames)
{
m_ShowNames = show;
RecreateButtons();
}
}
void QmitkToolSelectionBox::SetGenerateAccelerators(bool accel)
{
if (accel != m_GenerateAccelerators)
{
m_GenerateAccelerators = accel;
RecreateButtons();
}
}
void QmitkToolSelectionBox::SetToolGUIArea(QWidget *parentWidget)
{
m_ToolGUIWidget = parentWidget;
}
diff --git a/Plugins/org.blueberry.core.runtime/src/berryMacros.h b/Plugins/org.blueberry.core.runtime/src/berryMacros.h
index 31387c7544..d7defa8091 100644
--- a/Plugins/org.blueberry.core.runtime/src/berryMacros.h
+++ b/Plugins/org.blueberry.core.runtime/src/berryMacros.h
@@ -1,87 +1,85 @@
/*============================================================================
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 __BERRY_MACROS_H__
#define __BERRY_MACROS_H__
#include "berryWeakPointer.h"
#include "berryReflection.h"
#include "berryExtensionType.h"
-class QStringList;
-
#define berryArgGlue(x, y) x y
#define berryArgCount(_1,_2,_3,_4,_5,_6,_7,_8,count,...) count
#define berryExpandArgs(args) berryArgCount args
#define berryCountArgsMax8(...) berryExpandArgs((__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1, 0))
#define berryOverloadMacro2(name, count) name##count
#define berryOverloadMacro1(name, count) berryOverloadMacro2(name, count)
#define berryOverloadMacro(name, count) berryOverloadMacro1(name, count)
#define berryCallOverload(name, ...) berryArgGlue(berryOverloadMacro(name, berryCountArgsMax8(__VA_ARGS__)), (__VA_ARGS__))
#define berryObjectMacro(...) berryCallOverload(berryObjectMacro, __VA_ARGS__)
#define berryObjectTypeInfo(...) \
static ::berry::Reflection::TypeInfo GetStaticTypeInfo() \
{ return ::berry::Reflection::TypeInfo::New(); } \
::berry::Reflection::TypeInfo GetTypeInfo() const override \
{ return Self::GetStaticTypeInfo(); } \
/*typedef ::berry::Reflection::TypeList<__VA_ARGS__> SuperclassTypes;*/\
static QList< ::berry::Reflection::TypeInfo> GetStaticSuperclasses() \
{ return ::berry::Reflection::GetSuperclasses(); } \
QList< ::berry::Reflection::TypeInfo> GetSuperclasses() const override \
{ return Self::GetStaticSuperclasses(); }
#define berryObjectMacro1(className) \
typedef className Self; \
typedef berry::SmartPointer Pointer; \
typedef berry::SmartPointer ConstPointer; \
typedef berry::WeakPointer WeakPtr; \
typedef berry::WeakPointer ConstWeakPtr; \
static const char* GetStaticClassName() \
{ return #className; }
#define berryObjectMacro2(className, super1) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1)
#define berryObjectMacro3(className, super1, super2) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2)
#define berryObjectMacro4(className, super1, super2, super3) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2, super3)
#define berryObjectMacro5(className, super1, super2, super3, super4) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2, super3, super4)
#define berryObjectMacro6(className, super1, super2, super3, super4, super5) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2, super3, super4, super5)
#define berryObjectMacro7(className, super1, super2, super3, super4, super5, super6) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2, super3, super4, super5, super6)
#define berryObjectMacro8(className, super1, super2, super3, super4, super5, super6, super7) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2, super3, super4, super5, super6, super7)
#define berryObjectMacro9(className, super1, super2, super3, super4, super5, super6, super7, super8) \
berryObjectMacro1(className) \
berryObjectTypeInfo(super1, super2, super3, super4, super5, super6, super7, super8)
#define BERRY_REGISTER_EXTENSION_CLASS(_ClassType, _PluginContext) \
{ \
Q_UNUSED(_PluginContext) \
QString typeName = _ClassType::staticMetaObject.className(); \
::berry::registerExtensionType<_ClassType>(typeName.toLatin1().data()); \
}
#endif /*__BERRY_MACROS_H__*/
diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.h b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.h
index 80b96759fc..5a833556dd 100644
--- a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.h
+++ b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.h
@@ -1,448 +1,449 @@
/*============================================================================
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 BERRYEXTENSIONREGISTRY_H
#define BERRYEXTENSIONREGISTRY_H
#include
#include
#include "berryRegistryTimestamp.h"
#include "berryCombinedEventDelta.h"
#include "berryListenerList.h"
+#include
#include
#include
class QTranslator;
namespace berry {
struct IContributor;
struct IStatus;
class ConfigurationElementDescription;
class RegistryContribution;
class RegistryContributor;
class RegistryObject;
class RegistryObjectFactory;
class RegistryObjectManager;
class RegistryStrategy;
/**
* An implementation for the extension registry API.
*/
class ExtensionRegistry : public QObject, public IExtensionRegistry
{
Q_OBJECT
Q_INTERFACES(berry::IExtensionRegistry)
private:
struct ListenerInfo;
class RegistryEventThread;
// used to enforce concurrent access policy for readers/writers
mutable QReadWriteLock access;
// all registry event listeners
ListenerList listeners;
QScopedPointer debugRegistryListener;
SmartPointer registryObjects;
QObject* masterToken; // use to get full control of the registry; objects created as "static"
QObject* userToken; // use to modify non-persisted registry elements
RegistryTimestamp aggregatedTimestamp; // tracks current contents of the registry
// encapsulates processing of new registry deltas
CombinedEventDelta eventDelta;
// marks a new extended delta. The namespace that normally would not exists is used for this purpose
const static QString notNamespace;
// does this instance of the extension registry has multiple language support enabled?
bool isMultiLanguage;
// have we already logged a error on usage of an unsupported multi-language method?
mutable bool mlErrorLogged;
QScopedPointer eventThread; // registry event loop
// The pair of values we store in the event queue
struct QueueElement;
class Queue : public QList
{
QMutex mutex;
QWaitCondition waitCond;
public:
class Locker {
private: Queue* q;
public:
Locker(Queue* q) : q(q) { q->mutex.lock(); }
~Locker() { q->mutex.unlock(); }
};
void wait() { waitCond.wait(&mutex); }
void notify() { waitCond.wakeOne(); }
};
Queue queue; // stores registry events info
/**
* Adds and resolves all extensions and extension points provided by the
* plug-in.
*
* A corresponding IRegistryChangeEvent will be broadcast to all listeners
* interested on changes in the given plug-in.
*
*/
void Add(const SmartPointer& element);
QString AddExtension(int extension);
/**
* Looks for existing orphan extensions to connect to the given extension
* point. If none is found, there is nothing to do. Otherwise, link them.
*/
QString AddExtensionPoint(int extPoint);
QSet AddExtensionsAndExtensionPoints(const SmartPointer& element);
void AddListenerInternal(IRegistryEventListener* listener, const IExtensionPointFilter& filter);
void BasicAdd(const SmartPointer& element, bool link);
void SetObjectManagers(const SmartPointer &manager);
void BasicRemove(const QString& contributorId);
/**
* Broadcasts (asynchronously) the event to all interested parties.
*/
void FireRegistryChangeEvent();
//RegistryDelta GetDelta(const QString& namespaze) const;
void Link(const SmartPointer& extPoint, const QList& extensions);
/*
* Records an extension addition/removal.
*/
//QString RecordChange(const SmartPointer& extPoint, int extension, int kind);
/*
* Records a set of extension additions/removals.
*/
//QString RecordChange(const SmartPointer& extPoint, const QList& extensions, int kind);
//Return the affected namespace
QString RemoveExtension(int extensionId);
QString RemoveExtensionPoint(int extPoint);
QSet RemoveExtensionsAndExtensionPoints(const QString& contributorId);
/**
* Access check for add/remove operations:
* - Master key allows all operations
* - User key allows modifications of non-persisted elements
*
* @param key key to the registry supplied by the user
* @param persist true if operation affects persisted elements
* @return true is the key grants read/write access to the registry
*/
bool CheckReadWriteAccess(QObject* key, bool persist) const;
void LogError(const QString& owner, const QString& contributionName, const ctkException& e);
void LogError(const QString& owner, const QString& contributionName);
// Fill in the actual content of this extension
void CreateExtensionData(const QString& contributorId,
const ConfigurationElementDescription& description,
const SmartPointer& parent, bool persist);
bool RemoveObject(const SmartPointer& registryObject,
bool isExtensionPoint, QObject* token);
protected:
//storage manager associated with the registry cache
//StorageManager cacheStorageManager;
// Table reader associated with this extension registry
//TableReader theTableReader = new TableReader(this);
QScopedPointer strategy; // overridable portions of the registry functionality
/**
* Sets new cache file manager. If existing file manager was owned by the registry,
* closes it.
*
* @param cacheBase the base location for the registry cache
* @param isCacheReadOnly whether the file cache is read only
*/
void SetFileManager(const QString& cacheBase, bool isCacheReadOnly);
// allow other objects in the registry to use the same lock
void EnterRead();
// allow other objects in the registry to use the same lock
void ExitRead();
/////////////////////////////////////////////////////////////////////////////////////////////////
// Registry Object Factory
// The factory produces contributions, extension points, extensions, and configuration elements
// to be stored in the extension registry.
QScopedPointer theRegistryObjectFactory;
// Override to provide domain-specific elements to be stored in the extension registry
void SetElementFactory();
//TableReader getTableReader() const;
// Find the first location that contains a cache table file and set file manager to it.
bool CheckCache();
void StopChangeEventScheduler();
public:
SmartPointer GetObjectManager() const;
void AddListener(IRegistryEventListener* listener, const QString& extensionPointId = QString()) override;
void AddListener(IRegistryEventListener *listener, const IExtensionPointFilter& filter) override;
/*
* @see IExtensionRegistry#getConfigurationElementsFor(java.lang. QString)
*/
QList > GetConfigurationElementsFor(const QString& extensionPointId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getConfigurationElementsFor(java.lang. QString, java.lang. QString)
*/
QList > GetConfigurationElementsFor(const QString& pluginId,
const QString& extensionPointSimpleId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getConfigurationElementsFor(java.lang. QString, java.lang. QString, java.lang. QString)
*/
QList > GetConfigurationElementsFor(const QString& pluginId,
const QString& extensionPointName,
const QString& extensionId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtension(java.lang. QString)
*/
SmartPointer GetExtension(const QString& extensionId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtension(java.lang. QString, java.lang. QString)
*/
SmartPointer GetExtension(const QString& extensionPointId, const QString& extensionId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtension(java.lang. QString, java.lang. QString, java.lang. QString)
*/
SmartPointer GetExtension(const QString& pluginId,
const QString& extensionPointName,
const QString& extensionId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoint(java.lang. QString)
*/
SmartPointer GetExtensionPoint(const QString& xptUniqueId) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoint(java.lang. QString, java.lang. QString)
*/
SmartPointer GetExtensionPoint(const QString& elementName, const QString& xpt) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoints()
*/
QList > GetExtensionPoints() const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtensionPoints(java.lang. QString)
*/
QList > GetExtensionPoints(const QString& namespaceName) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getExtensions(java.lang. QString)
*/
QList > GetExtensions(const QString& namespaceName) const override;
QList > GetExtensions(const SmartPointer& contributor) const override;
QList > GetExtensionPoints(const SmartPointer& contributor) const override;
/*
* @see org.eclipse.core.runtime.IExtensionRegistry#getNamespaces()
*/
QList GetNamespaces() const override;
bool HasContributor(const SmartPointer& contributor) const;
bool HasContributor(const QString& contributorId) const;
void Remove(const QString& removedContributorId, long timestamp);
void RemoveContributor(const SmartPointer& contributor, QObject* key);
/**
* Unresolves and removes all extensions and extension points provided by
* the plug-in.
*
* A corresponding IRegistryChangeEvent will be broadcast to all listeners
* interested on changes in the given plug-in.
*
*/
void Remove(const QString& removedContributorId);
void RemoveListener(IRegistryEventListener* listener) override;
ExtensionRegistry(RegistryStrategy* registryStrategy, QObject* masterToken, QObject* userToken);
~ExtensionRegistry() override;
/**
* Stops the registry. Registry has to be stopped to properly
* close cache and dispose of listeners.
* @param key - key token for this registry
*/
void Stop(QObject* key) override;
/*
* Clear the registry cache files from the file manager so on next start-up we recompute it.
*/
void ClearRegistryCache();
// Lazy initialization.
RegistryObjectFactory* GetElementFactory();
void Log(const SmartPointer& status) const;
/**
* With multi-locale support enabled this method returns the non-translated
* key so that they can be cached and translated later into desired languages.
* In the absence of the multi-locale support the key gets translated immediately
* and only translated values is cached.
*/
QString Translate(const QString& key, QTranslator* resources) const;
bool Debug() const;
bool DebugEvents() const;
bool UseLazyCacheLoading() const;
long ComputeState() const;
QObject* CreateExecutableExtension(const SmartPointer& defaultContributor,
const QString& className, const QString& requestedContributorName);
//////////////////////////////////////////////////////////////////////////////////////////
// Registry change events processing
void ProcessChangeEvent(const QList& listenerInfos,
const CombinedEventDelta &scheduledDelta);
// Registry events notifications are done on a separate thread in a sequential manner
// (first in - first processed)
void ScheduleChangeEvent(const QList& listenerInfos,
const CombinedEventDelta& scheduledDeltas);
bool AddContribution(QIODevice* is, const SmartPointer& contributor,
bool persist, const QString& contributionName,
QTranslator* translationBundle, QObject* key, long timestamp);
bool AddContribution(QIODevice* is, const SmartPointer& contributor, bool persist,
const QString& contributionName, QTranslator* translationBundle, QObject* key) override;
/**
* Adds an extension point to the extension registry.
*
* If the registry is not modifiable, this method is an access controlled method.
* Proper token should be passed as an argument for non-modifiable registries.
*
* @param identifier Id of the extension point. If non-qualified names is supplied,
* it will be converted internally into a fully qualified name
* @param contributor the contributor of this extension point
* @param persist indicates if contribution should be stored in the registry cache. If false,
* contribution is not persisted in the registry cache and is lost on Eclipse restart
* @param label display string for the extension point
* @param schemaReference reference to the extension point schema. The schema reference
* is a URL path relative to the plug-in installation URL. May be null
* @param token the key used to check permissions. Two registry keys are set in the registry
* constructor {@link RegistryFactory#createRegistry(org.eclipse.core.runtime.spi.RegistryStrategy, Object, Object)}:
* master token and a user token. Master token allows all operations; user token
* allows non-persisted registry elements to be modified.
* @return true
if successful, false
if a problem was encountered
* @throws IllegalArgumentException if incorrect token is passed in
*/
bool AddExtensionPoint(const QString& identifier, const SmartPointer& contributor,
bool persist, const QString& label, const QString& schemaReference, QObject* token);
/**
* Adds an extension to the extension registry.
*
* If the registry is not modifiable, this method is an access controlled method.
* Proper token should be passed as an argument for non-modifiable registries.
*
* @see org.eclipse.core.internal.registry.spi.ConfigurationElementDescription
*
* @param identifier Id of the extension. If non-qualified name is supplied,
* it will be converted internally into a fully qualified name
* @param contributor the contributor of this extension
* @param persist indicates if contribution should be stored in the registry cache. If false,
* contribution is not persisted in the registry cache and is lost on Eclipse restart
* @param label display string for this extension
* @param extensionPointId Id of the point being extended. If non-qualified
* name is supplied, it is assumed to have the same contributorId as this extension
* @param configurationElements contents of the extension
* @param token the key used to check permissions. Two registry keys are set in the registry
* constructor {@link RegistryFactory#createRegistry(org.eclipse.core.runtime.spi.RegistryStrategy, Object, Object)}:
* master token and a user token. Master token allows all operations; user token
* allows non-persisted registry elements to be modified.
* @return true
if successful, false
if a problem was encountered
* @throws IllegalArgumentException if incorrect token is passed in
*/
bool AddExtension(const QString& identifier, const SmartPointer& contributor,
bool persist, const QString& label, const QString& extensionPointId,
const ConfigurationElementDescription& configurationElements, QObject* token);
bool RemoveExtension(const SmartPointer& extension, QObject* token) override;
bool RemoveExtensionPoint(const SmartPointer& extensionPoint, QObject* token) override;
QList > GetAllContributors() const;
bool IsMultiLanguage() const override;
QList Translate(const QList& nonTranslated, const SmartPointer& contributor,
const QLocale& locale) const;
QLocale GetLocale() const;
void LogMultiLangError() const;
};
}
#endif // BERRYEXTENSIONREGISTRY_H
diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp
index 402bf7a6ed..e90e666400 100644
--- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp
+++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryObject.cpp
@@ -1,119 +1,121 @@
/*============================================================================
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 "berryRegistryObject.h"
#include "berryExtensionRegistry.h"
#include "berryRegistryObjectManager.h"
+#include
+
namespace berry {
// it is assumed that int has 32 bits (bits #0 to #31);
// bits #0 - #29 are the offset (limited to about 1Gb)
// bit #30 - persistence flag
// bit #31 - registry object has no extra data offset
// the bit#31 is a sign bit; bit#30 is the highest mantissa bit
const int RegistryObject::EMPTY_MASK = 0x80000000; // only taking bit #31
const int RegistryObject::PERSIST_MASK = 0x40000000; // only taking bit #30
const int RegistryObject::OFFSET_MASK = 0x3FFFFFFF; // all bits but #30, #31
RegistryObject::RegistryObject()
: registry(nullptr), objectId(RegistryObjectManager::UNKNOWN), extraDataOffset(EMPTY_MASK)
{
objectKey = QString::number(objectId);
}
QString RegistryObject::GetKey() const
{
return objectKey;
}
bool RegistryObject::IsEqual(const KeyedElement& other) const
{
return objectId == static_cast(other).objectId;
}
RegistryObject::RegistryObject(ExtensionRegistry* registry, bool persist)
: registry(registry), objectId(RegistryObjectManager::UNKNOWN), extraDataOffset(EMPTY_MASK)
{
objectKey = QString::number(objectId);
SetPersist(persist);
}
void RegistryObject::SetRawChildren(const QList& values)
{
children = values;
}
QList RegistryObject::GetRawChildren() const
{
return children;
}
void RegistryObject::SetObjectId(int value)
{
objectId = value;
objectKey = QString::number(value);
}
int RegistryObject::GetObjectId() const
{
return objectId;
}
bool RegistryObject::ShouldPersist() const
{
return (extraDataOffset & PERSIST_MASK) == PERSIST_MASK;
}
bool RegistryObject::NoExtraData() const
{
return (extraDataOffset & EMPTY_MASK) == EMPTY_MASK;
}
int RegistryObject::GetExtraDataOffset() const
{
if (NoExtraData())
return -1;
return extraDataOffset & OFFSET_MASK;
}
void RegistryObject::SetExtraDataOffset(int offset)
{
if (offset == -1)
{
extraDataOffset &= ~OFFSET_MASK; // clear all offset bits
extraDataOffset |= EMPTY_MASK;
return;
}
if ((offset & OFFSET_MASK) != offset)
throw ctkInvalidArgumentException("Registry object: extra data offset is out of range");
extraDataOffset &= ~(OFFSET_MASK | EMPTY_MASK); // clear all offset bits; mark as non-empty
extraDataOffset |= (offset & OFFSET_MASK); // set all offset bits
}
QLocale RegistryObject::GetLocale() const
{
return registry->GetLocale();
}
void RegistryObject::SetPersist(bool persist)
{
if (persist)
extraDataOffset |= PERSIST_MASK;
else
extraDataOffset &= ~PERSIST_MASK;
}
}
diff --git a/Plugins/org.blueberry.core.runtime/src/registry/berryIExtensionRegistry.h b/Plugins/org.blueberry.core.runtime/src/registry/berryIExtensionRegistry.h
index a42b906847..d216827edd 100644
--- a/Plugins/org.blueberry.core.runtime/src/registry/berryIExtensionRegistry.h
+++ b/Plugins/org.blueberry.core.runtime/src/registry/berryIExtensionRegistry.h
@@ -1,396 +1,397 @@
/*============================================================================
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 BERRYIEXTENSIONREGISTRY_H
#define BERRYIEXTENSIONREGISTRY_H
#include "org_blueberry_core_runtime_Export.h"
#include
#include
+#include
class QTranslator;
namespace berry {
struct IConfigurationElement;
struct IContributor;
struct IExtension;
struct IExtensionPoint;
struct IExtensionPointFilter;
struct IRegistryEventListener;
/**
* The extension registry holds the master list of all
* discovered namespaces, extension points and extensions.
*
* The extension registry can be queried, by name, for
* extension points and extensions.
*
*
* The various objects that describe the contents of the extension registry
* ({@link IExtensionPoint}, {@link IExtension}, and {@link IConfigurationElement})
* are intended for relatively short-term use. Clients that deal with these objects
* must be aware that they may become invalid if the declaring plug-in is updated
* or uninstalled. If this happens, all methods on these object except
* isValid()
will throw {@link InvalidRegistryObjectException}.
* Code in a plug-in that has declared that it is not dynamic aware (or not declared
* anything) can safely ignore this issue, since the registry would not be
* modified while it is active. However, code in a plug-in that declares that it
* is dynamic aware must be careful if it accesses extension registry objects,
* because it's at risk if plug-in are removed. Similarly, tools that analyze
* or display the extension registry are vulnerable. Client code can pre-test for
* invalid objects by calling isValid()
, which never throws this exception.
* However, pre-tests are usually not sufficient because of the possibility of the
* extension registry object becoming invalid as a result of a concurrent activity.
* At-risk clients must treat InvalidRegistryObjectException
as if it
* were a checked exception. Also, such clients should probably register a listener
* with the extension registry so that they receive notification of any changes to
* the registry.
*
*
* Extensions and extension points are declared by generic entities called
* \c namespaces . The only fact known about namespaces is that they
* have unique string-based identifiers. One example of a namespace
* is a plug-in, for which the namespace id is the plug-in id.
*
* This interface is not intended to be implemented by clients.
*
*/
struct org_blueberry_core_runtime_EXPORT IExtensionRegistry
{
virtual ~IExtensionRegistry();
/**
* Returns all configuration elements from all extensions configured
* into the identified extension point. Returns an empty list if the extension
* point does not exist, has no extensions configured, or none of the extensions
* contain configuration elements.
*
* @param extensionPointId the unique identifier of the extension point
* (e.g. "org.blueberry.core.applications"
)
* @return the configuration elements
*/
virtual QList > GetConfigurationElementsFor(
const QString& extensionPointId) const = 0;
/**
* Returns all configuration elements from all extensions configured
* into the identified extension point. Returns an empty list if the extension
* point does not exist, has no extensions configured, or none of the extensions
* contain configuration elements.
*
* @param namespaze the namespace for the extension point
* (e.g. "org.eclipse.core.resources"
)
* @param extensionPointName the simple identifier of the
* extension point (e.g. "builders"
)
* @return the configuration elements
*/
virtual QList > GetConfigurationElementsFor(
const QString& namespaze, const QString& extensionPointName) const = 0;
/**
* Returns all configuration elements from the identified extension.
* Returns an empty array if the extension does not exist or
* contains no configuration elements.
*
* @param namespaze the namespace for the extension point
* (e.g. "org.eclipse.core.resources"
)
* @param extensionPointName the simple identifier of the
* extension point (e.g. "builders"
)
* @param extensionId the unique identifier of the extension
* (e.g. "com.example.acme.coolbuilder"
)
* @return the configuration elements
*/
virtual QList > GetConfigurationElementsFor(
const QString& namespaze, const QString& extensionPointName, const QString& extensionId) const = 0;
/**
* Returns the specified extension in this extension registry,
* or null
if there is no such extension.
*
* @param extensionId the unique identifier of the extension
* (e.g. "com.example.acme.coolbuilder"
)
* @return the extension, or null
*/
virtual SmartPointer GetExtension(const QString& extensionId) const = 0;
/**
* Returns the specified extension in this extension registry,
* or null
if there is no such extension.
* The first parameter identifies the extension point, and the second
* parameter identifies an extension plugged in to that extension point.
*
* @param extensionPointId the unique identifier of the extension point
* (e.g. "org.eclipse.core.resources.builders"
)
* @param extensionId the unique identifier of the extension
* (e.g. "com.example.acme.coolbuilder"
)
* @return the extension, or null
*/
virtual SmartPointer GetExtension(const QString& extensionPointId,
const QString& extensionId) const = 0;
/**
* Returns the specified extension in this extension registry,
* or null
if there is no such extension.
* The first two parameters identify the extension point, and the third
* parameter identifies an extension plugged in to that extension point.
*
* @param namespaze the namespace for the extension point
* (e.g. "org.eclipse.core.resources"
)
* @param extensionPointName the simple identifier of the
* extension point (e.g. "builders"
)
* @param extensionId the unique identifier of the extension
* (e.g. "com.example.acme.coolbuilder"
)
* @return the extension, or null
*/
virtual SmartPointer GetExtension(const QString& namespaze,
const QString& extensionPointName,
const QString& extensionId) const = 0;
/**
* Returns the extension point with the given extension point identifier
* in this extension registry, or null
if there is no such
* extension point.
*
* @param extensionPointId the unique identifier of the extension point
* (e.g., "org.blueberry.core.applications"
)
* @return the extension point, or null
*/
virtual SmartPointer GetExtensionPoint(const QString& extensionPointId) const = 0;
/**
* Returns the extension point in this extension registry
* with the given namespace and extension point simple identifier,
* or null
if there is no such extension point.
*
* @param namespaze the namespace for the given extension point
* (e.g. "org.eclipse.core.resources"
)
* @param extensionPointName the simple identifier of the
* extension point (e.g. "builders"
)
* @return the extension point, or null
*/
virtual SmartPointer GetExtensionPoint(const QString& namespaze,
const QString& extensionPointName) const = 0;
/**
* Returns all extension points known to this extension registry.
* Returns an empty array if there are no extension points.
*
* @return the extension points known to this extension registry
*/
virtual QList > GetExtensionPoints() const = 0;
/**
* Returns all extension points declared in the given namespace. Returns an empty array if
* there are no extension points declared in the namespace.
*
* @param namespaze the namespace for the extension points
* (e.g. "org.eclipse.core.resources"
)
* @return the extension points in this registry declared in the given namespace
*/
virtual QList > GetExtensionPoints(const QString& namespaze) const = 0;
/**
* Returns all extension points supplied by the contributor, or null
* if there are no such extension points.
*
* @param contributor the contributor for the extensions (for OSGi registry, bundles and
* fragments are different contributors)
* @return the extension points, or null
* @since 3.4
*/
virtual QList > GetExtensionPoints(
const SmartPointer& contributor) const = 0;
/**
* Returns all extensions declared in the given namespace. Returns an empty array if
* no extensions are declared in the namespace.
*
* @param namespaze the namespace for the extensions
* (e.g. "org.eclipse.core.resources"
)
* @return the extensions in this registry declared in the given namespace
*/
virtual QList > GetExtensions(const QString& namespaze) const = 0;
/**
* Returns all extensions supplied by the contributor, or null
if there
* are no such extensions.
* @param contributor the contributor for the extensions (for OSGi registry, bundles and
* fragments are different contributors)
* @return the extensions, or null
*/
virtual QList > GetExtensions(const SmartPointer& contributor) const = 0;
/**
* Returns all namespaces currently used by extensions and extension points in this
* registry. Returns an empty array if there are no known extensions/extension points
* in this registry.
*
* The fully-qualified name of an extension point or an extension consist of
* a namespace and a simple name (much like a qualified Java class name consist
* of a package name and a class name). The simple names are presumed to be unique
* in the namespace.
*
* @return all namespaces known to this registry
*/
virtual QList GetNamespaces() const = 0;
/**
* Adds to this extension registry an extension point(s), extension(s), or
* a combination of those described by the XML file. The information in
* the XML file should be supplied in the same format as the plugin.xml; in fact,
* Plug-in Manifest editor can be used to prepare the XML file. The top token
* of the contribution (normally, "plugin" or "fragment" in the Plug-in Manifest
* editor) is ignored by this method.
*
* This method is an access controlled method. Proper token (master token or user token) should
* be passed as an argument. Two registry keys are set in the registry constructor:
* master token and a user token. Master token allows all operations; user token allows
* non-persisted registry elements to be modified.
*
*
* @param is stream open on the XML file. The XML file can contain an extension
* point(s) or/and extension(s) described in the format similar to plugin.xml. The method
* closes the device before returning.
* @param contributor the contributor making this contribution.
* @param persist indicates if the contribution(s) should be stored in the registry cache. If false
,
* contribution is not persisted in the registry cache and is lost on BlueBerry restart
* @param name optional name of the contribution. Used for error reporting; might be QString()
* @param translationBundle optional translator used for translations; might be nullptr
* @param token the key used to check permissions
* @return true
if the contribution was successfully processed and false
otherwise
* @throws ctkInvalidArgumentException if an incorrect token is passed
*
* @see IContributor
*/
virtual bool AddContribution(QIODevice* is, const SmartPointer& contributor,
bool persist, const QString& name, QTranslator* translationBundle, QObject* token) = 0;
/**
* Removes the given extension from this registry.
*
* This method is an access controlled method. Proper token (master token or user token) should
* be passed as an argument. Two registry keys are set in the registry constructor:
* master token and a user token. Master token allows all operations; user token only
* allows non-persisted registry elements to be modified.
*
*
* @param extension extension to be removed
* @param token the key used to check permissions
* @return true
if the extension was successfully removed, and false
otherwise
* @throws ctkInvalidArgumentException if an incorrect token is passed
*/
virtual bool RemoveExtension(const SmartPointer& extension, QObject* token) = 0;
/**
* Removes the specified extension point from this registry.
*
* This method is an access controlled method. Proper token (master token or user token) should
* be passed as an argument. Two registry keys are set in the registry constructor:
* master token and a user token. Master token allows all operations; user token only
* allows non-persisted registry elements to be modified.
*
*
* @param extensionPoint extension point to be removed
* @param token the key used to check permissions
* @return true
if the extension point was successfully removed, and
* false
otherwise
* @throws ctkInvalidArgumentException if incorrect token is passed
*/
virtual bool RemoveExtensionPoint(const SmartPointer& extensionPoint, QObject* token) = 0;
/**
* Call this method to properly stop the registry. The method stops registry event processing
* and writes out cache information to be used in the next run. This is an access controlled
* method; master token is required.
*
* This method is an access controlled method. Master token should be passed as an argument.
*
* @param token master token for the registry
* @throws IllegalArgumentException if incorrect token is passed
*/
virtual void Stop(QObject* token) = 0;
/**
* Adds the given listener for registry change events related to the specified
* extension point or for changes to all extension points and underlying
* extensions if the \c extensionPointId argument is empty.
*
* Depending on activity, listeners of this type might receive a large number
* of modifications and negatively impact overall system performance. Whenever
* possible, consider registering listener specific to an extension point rather
* than a "global" listener.
*
* Once registered, a listener starts receiving notification of changes to
* the registry. Registry change notifications are sent asynchronously.
* The listener continues to receive notifications until it is removed.
*
* This method has no effect if the listener is already registered.
*
* @param listener the listener
* @param extensionPointId the unique identifier of extension point
* @see IExtensionPoint#GetUniqueIdentifier()
*/
virtual void AddListener(IRegistryEventListener* listener, const QString& extensionPointId = QString()) = 0;
/**
* Adds the given listener for registry change events for extension points
* matching the provided filter.
*
* Depending on activity, listeners of this type might receive a large number
* of modifications and negatively impact overall system performance. Whenever
* possible, consider registering listener specific to an extension point rather
* than a "global" listener.
*
* Once registered, a listener starts receiving notification of changes to
* the registry. Registry change notifications are sent asynchronously.
* The listener continues to receive notifications until it is removed.
*
* This method has no effect if the listener is already registered.
*
* @param listener the listener
* @param filter An extension point filter
* @see ExtensionTracker
*/
virtual void AddListener(IRegistryEventListener *listener, const IExtensionPointFilter& filter) = 0;
/**
* Removes the given registry change listener from this registry.
*
* This method has no effect if the listener is not registered.
*
* @param listener the listener
* @see #AddListener(IRegistryEventListener*, const QString&)
*/
virtual void RemoveListener(IRegistryEventListener* listener) = 0;
/**
* Call this method to determine if this extension registry supports multiple languages.
*
* See the runtime option "-registryMultiLanguage" for enabling multi-language
* support.
*
* @return true
if multiple languages are supported by this
* instance of the extension registry; false
otherwise.
*/
virtual bool IsMultiLanguage() const = 0;
};
}
Q_DECLARE_INTERFACE(berry::IExtensionRegistry, "org.blueberry.service.IExtensionRegistry")
#endif // BERRYIEXTENSIONREGISTRY_H
diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h
index cb4c05330b..c005928b2b 100644
--- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h
+++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.h
@@ -1,118 +1,119 @@
/*============================================================================
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 BERRYHELPINDEXVIEW_H_
#define BERRYHELPINDEXVIEW_H_
#include
#include
#include
+#include
class ctkSearchBox;
class QHelpIndexWidget;
namespace berry {
class HelpIndexWidget : public QListView
{
Q_OBJECT
Q_SIGNALS:
/**
* This signal is emitted when an item is activated and its
* associated \a link should be shown. To know where the link
* belongs to, the \a keyword is given as a second parameter.
*/
void linkActivated(const QUrl &link, const QString &keyword);
/**
* This signal is emitted when the item representing the \a keyword
* is activated and the item has more than one link associated.
* The \a links consist of the document title and their URL.
*/
void linksActivated(const QMap &links,
const QString &keyword);
public:
HelpIndexWidget();
public Q_SLOTS:
/**
* Filters the indices according to \a filter or \a wildcard.
* The item with the best match is set as current item.
*/
void filterIndices(const QString &filter,
const QString &wildcard = QString());
/**
* Activates the current item which will result eventually in
* the emitting of a linkActivated() or linksActivated()
* signal.
*/
void activateCurrentItem();
private Q_SLOTS:
void showLink(const QModelIndex &index);
};
class HelpIndexView : public QtViewPart
{
Q_OBJECT
public:
HelpIndexView();
~HelpIndexView() override;
void SetFocus() override;
protected:
void CreateQtPartControl(QWidget* parent) override;
void setSearchLineEditText(const QString &text);
QString searchLineEditText() const;
protected Q_SLOTS:
void linkActivated(const QUrl& link);
void linksActivated(const QMap &links, const QString &keyword);
private Q_SLOTS:
void filterIndices(const QString &filter);
void enableSearchLineEdit();
void disableSearchLineEdit();
void setIndexWidgetBusy();
void unsetIndexWidgetBusy();
private:
bool eventFilter(QObject *obj, QEvent *e) override;
void focusInEvent(QFocusEvent *e);
void open(HelpIndexWidget *indexWidget, const QModelIndex &index);
Q_DISABLE_COPY(HelpIndexView)
ctkSearchBox* m_SearchLineEdit;
HelpIndexWidget* m_IndexWidget;
};
} // namespace berry
#endif /*BERRYHELPINDEXVIEW_H_*/
diff --git a/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h b/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h
index 7135b29cf2..5e65da9603 100644
--- a/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h
+++ b/Plugins/org.blueberry.ui.qt/src/application/berryWorkbenchWindowAdvisor.h
@@ -1,262 +1,264 @@
/*============================================================================
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 BERRYWORKBENCHWINDOWADVISOR_H_
#define BERRYWORKBENCHWINDOWADVISOR_H_
#include
#include
+class QWidget;
+
namespace berry
{
struct IActionBarConfigurer;
struct IMemento;
struct IWorkbenchWindowConfigurer;
class ActionBarAdvisor;
class Shell;
/**
* Public base class for configuring a workbench window.
*
* The workbench window advisor object is created in response to a workbench
* window being created (one per window), and is used to configure the window.
*
*
* An application should declare a subclass of