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: *
    *
  1. 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.
  2. *
  3. 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. *
  4. 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. *
  5. 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.
  6. *
* * In the second phase, each BaseData object is saved to disk using the specified * file name and mime-type, according to the following procedure: *
    *
  1. 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.
  2. *
  3. 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.
  4. *
* * @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 WorkbenchWindowAdvisor * and override methods to configure workbench windows to suit the needs of the * particular application. *

*

* The following advisor methods are called at strategic points in the * workbench window's lifecycle (as with the workbench advisor, all occur * within the dynamic scope of the call to * PlatformUI#CreateAndRunWorkbench()): *

    *
  • PreWindowOpen() - called as the window is being opened; * use to configure aspects of the window other than actions bars
  • *
  • PostWindowRestore() - called after the window has been * recreated from a previously saved state; use to adjust the restored * window
  • *
  • PostWindowCreate() - called after the window has been created, * either from an initial state or from a restored state; used to adjust the * window
  • *
  • OpenIntro() - called immediately before the window is opened in * order to create the introduction component, if any.
  • *
  • PostWindowOpen() - called after the window has been * opened; use to hook window listeners, etc.
  • *
  • PreWindowShellClose() - called when the window's shell * is closed by the user; use to pre-screen window closings
  • *
*

* */ class BERRY_UI_QT WorkbenchWindowAdvisor { private: SmartPointer windowConfigurer; protected: /** * Returns the workbench window configurer. * * @return the workbench window configurer */ SmartPointer GetWindowConfigurer(); public: /** * Creates a new workbench window advisor for configuring a workbench * window via the given workbench window configurer. * * @param configurer an object for configuring the workbench window */ WorkbenchWindowAdvisor(const SmartPointer& configurer); virtual ~WorkbenchWindowAdvisor(); /** * Performs arbitrary actions before the window is opened. *

* This method is called before the window's controls have been created. * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. * Typical clients will use the window configurer to tweak the * workbench window in an application-specific way; however, filling the * window's menu bar, tool bar, and status line must be done in * ActionBarAdvisor#FillActionBars(), which is called immediately * after this method is called. *

*/ virtual void PreWindowOpen(); /** * Creates a new action bar advisor to configure the action bars of the window * via the given action bar configurer. * The default implementation returns a new instance of ActionBarAdvisor. * * @param configurer the action bar configurer for the window * @return the action bar advisor for the window */ virtual SmartPointer CreateActionBarAdvisor( SmartPointer configurer); /** * Performs arbitrary actions after the window has been restored, * but before it is opened. *

* This method is called after a previously-saved window has been * recreated. This method is not called when a new window is created from * scratch. This method is never called when a workbench is started for the * very first time, or when workbench state is not saved or restored. * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. * It is okay to call IWorkbench#Close() from this method. *

* * @exception WorkbenchException thrown if there are any errors to report * from post-restoration of the window */ virtual void PostWindowRestore(); /** * Opens the introduction component. *

* Clients must not call this method directly (although super calls are okay). * The default implementation opens the intro in the first window provided * if the preference WorkbenchPreferenceConstants#SHOW_INTRO is true. If * an intro is shown then this preference will be set to false. * Subsequently, and intro will be shown only if * WorkbenchConfigurer#GetSaveAndRestore() returns * true and the introduction was visible on last shutdown. * Subclasses may override. *

*/ virtual void OpenIntro(); /** * Performs arbitrary actions after the window has been created (possibly * after being restored), but has not yet been opened. *

* This method is called after the window has been created from scratch, * or when it has been restored from a previously-saved window. In the latter case, * this method is called after PostWindowRestore(). * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. *

*/ virtual void PostWindowCreate(); /** * Performs arbitrary actions after the window has been opened (possibly * after being restored). *

* This method is called after the window has been opened. This method is * called after the window has been created from scratch, or when * it has been restored from a previously-saved window. * Clients must not call this method directly (although super calls are okay). * The default implementation does nothing. Subclasses may override. *

*/ virtual void PostWindowOpen(); /** * Performs arbitrary actions as the window's shell is being closed * directly, and possibly veto the close. *

* This method is called from a IShellListener associated with the window, * for example when the user clicks the window's close button. It is not * called when the window is being closed for other reasons, such as if the * user exits the workbench via the ActionFactory#QUIT action. * Clients must not call this method directly (although super calls are * okay). If this method returns false, then the user's * request to close the shell is ignored. This gives the workbench advisor * an opportunity to query the user and/or veto the closing of a window * under some circumstances. *

* * @return true to allow the window to close, and * false to prevent the window from closing * @see IWorkbenchWindow#Close() * @see WorkbenchAdvisor#PreShutdown() */ virtual bool PreWindowShellClose(); /** * Performs arbitrary actions after the window is closed. *

* This method is called after the window's controls have been disposed. * Clients must not call this method directly (although super calls are * okay). The default implementation does nothing. Subclasses may override. *

*/ virtual void PostWindowClose(); /** * Creates the contents of the window. *

* The default implementation adds a menu bar, a cool bar, a status line, * a perspective bar, and a fast view bar. The visibility of these controls * can be configured using the SetShow* methods on * IWorkbenchWindowConfigurer. *

*

* Subclasses may override to define custom window contents and layout, * but must call IWorkbenchWindowConfigurer#CreatePageComposite(). *

* * @param shell the window's shell * @see IWorkbenchWindowConfigurer#CreateMenuBar() * @see IWorkbenchWindowConfigurer#CreateCoolBarControl() * @see IWorkbenchWindowConfigurer#CreateStatusLineControl() * @see IWorkbenchWindowConfigurer#CreatePageComposite() */ virtual void CreateWindowContents(SmartPointer shell); /** * Creates and returns the control to be shown when the window has no open pages. * If null is returned, the default window background is shown. *

* The default implementation returns null. * Subclasses may override. *

* * @param parent the parent composite * @return the control or null */ virtual QWidget* CreateEmptyWindowContents(QWidget* parent); /** * Saves arbitrary application specific state information. * * @param memento the storage area for object's state * @return a status object indicating whether the save was successful */ virtual bool SaveState(SmartPointer memento); /** * Restores arbitrary application specific state information. * * @param memento the storage area for object's state * @return a status object indicating whether the restore was successful */ virtual bool RestoreState(SmartPointer memento); }; } #endif /*BERRYWORKBENCHWINDOWADVISOR_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h b/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h index 4105bba7fd..4435cee61e 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h @@ -1,71 +1,72 @@ /*============================================================================ 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 BERRYIELEMENTFACTORY_H #define BERRYIELEMENTFACTORY_H #include #include +#include namespace berry { struct IAdaptable; struct IMemento; /** * A factory for re-creating objects from a previously saved memento. *

* Clients should implement this interface and include the name of their class * in an extension to the platform extension point named * "org.blueberry.ui.elementFactories". * For example, the plug-in's XML markup might contain: * \code{.unparsed} * * * * \endcode *

* * @see IPersistableElement * @see IMemento * @see IWorkbench#GetElementFactory */ struct BERRY_UI_QT IElementFactory { virtual ~IElementFactory(); /** * Re-creates and returns an object from the state captured within the given * memento. *

* If the result is not null, it should be persistable; that is, *

    * result.getAdapter(org.eclipse.ui.IPersistableElement.class)
    * 
* should not return null. The caller takes ownership of the * result and must delete it when it is not needed any more. *

* * @param memento * a memento containing the state for the object * @return an object, or nullptr if the element could not be * created */ virtual IAdaptable* CreateElement(const SmartPointer& memento) = 0; }; } Q_DECLARE_INTERFACE(berry::IElementFactory, "org.blueberry.ui.IElementFactory") #endif // BERRYIELEMENTFACTORY_H diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.cpp index 8678fa9104..538cbf4bfa 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.cpp @@ -1,55 +1,57 @@ /*============================================================================ 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 "berryQtShowViewAction.h" #include #include +#include + namespace berry { QtShowViewAction::QtShowViewAction(IWorkbenchWindow::Pointer window, IViewDescriptor::Pointer desc) : QAction(nullptr) { - this->setParent(static_cast(window->GetShell()->GetControl())); + this->setParent(window->GetShell()->GetControl()); this->setText(desc->GetLabel()); this->setToolTip(desc->GetLabel()); this->setIconVisibleInMenu(true); QIcon icon = desc->GetImageDescriptor(); this->setIcon(icon); m_Window = window.GetPointer(); m_Desc = desc; this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); } void QtShowViewAction::Run() { IWorkbenchPage::Pointer page = m_Window->GetActivePage(); if (page.IsNotNull()) { try { page->ShowView(m_Desc->GetId()); } catch (const PartInitException& e) { BERRY_ERROR << "Error: " << e.what(); } } } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp index 7529cc5fbc..5a06815e16 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeGlobalReinitAction.cpp @@ -1,81 +1,83 @@ /*============================================================================ 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 // mitk core #include // mitk gui common plugin #include +#include + const QString QmitkDataNodeGlobalReinitAction::ACTION_ID = "org.mitk.gui.qt.application.globalreinitaction"; // namespace that contains the concrete action namespace GlobalReinitAction { void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage) { auto renderWindow = mitk::WorkbenchUtil::GetRenderWindowPart(workbenchPartSite->GetPage(), mitk::WorkbenchUtil::NONE); if (nullptr == renderWindow) { renderWindow = mitk::WorkbenchUtil::OpenRenderWindowPart(workbenchPartSite->GetPage(), false); if (nullptr == renderWindow) { // no render window available return; } } mitk::RenderingManager::GetInstance()->InitializeViewsByBoundingObjects(dataStorage); } } QmitkDataNodeGlobalReinitAction::QmitkDataNodeGlobalReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchPartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchPartSite) { setText(tr("Global Reinit")); InitializeAction(); } QmitkDataNodeGlobalReinitAction::QmitkDataNodeGlobalReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchPartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchPartSite)) { setText(tr("Global Reinit")); InitializeAction(); } void QmitkDataNodeGlobalReinitAction::InitializeAction() { connect(this, &QmitkDataNodeGlobalReinitAction::triggered, this, &QmitkDataNodeGlobalReinitAction::OnActionTriggered); } void QmitkDataNodeGlobalReinitAction::OnActionTriggered(bool /*checked*/) { auto workbenchPartSite = m_WorkbenchPartSite.Lock(); if (workbenchPartSite.IsNull()) { return; } auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } GlobalReinitAction::Run(workbenchPartSite, dataStorage); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp index 128961634a..7ff07a1526 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeHideAllAction.cpp @@ -1,73 +1,75 @@ /*============================================================================ 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 // mitk core #include +#include + namespace HideAllAction { void Run(const QList& selectedNodes, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { if (selectedNodes.empty()) { return; } for (auto& node : selectedNodes) { if (node.IsNotNull()) { node->SetVisibility(false, baseRenderer); } } if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); } } } QmitkDataNodeHideAllAction::QmitkDataNodeHideAllAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Hide all nodes")); InitializeAction(); } QmitkDataNodeHideAllAction::QmitkDataNodeHideAllAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Hide all nodes")); InitializeAction(); } void QmitkDataNodeHideAllAction::InitializeAction() { connect(this, &QmitkDataNodeHideAllAction::triggered, this, &QmitkDataNodeHideAllAction::OnActionTriggered); } void QmitkDataNodeHideAllAction::OnActionTriggered(bool /*checked*/) { mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); auto selectedNodes = GetSelectedNodes(); HideAllAction::Run(selectedNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp index 622d38362f..b492c2d399 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeReinitAction.cpp @@ -1,137 +1,139 @@ /*============================================================================ 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 // mitk core #include #include #include #include #include // mitk gui common plugin #include +#include + // namespace that contains the concrete action namespace ReinitAction { void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, const QList& selectedNodes /*= QList()*/, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { if (selectedNodes.empty()) { return; } if (workbenchPartSite.IsNotNull()) { auto renderWindow = mitk::WorkbenchUtil::GetRenderWindowPart(workbenchPartSite->GetPage(), mitk::WorkbenchUtil::NONE); if (nullptr == renderWindow) { renderWindow = mitk::WorkbenchUtil::OpenRenderWindowPart(workbenchPartSite->GetPage(), false); if (nullptr == renderWindow) { // no render window available return; } } } auto boundingBoxPredicate = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false), baseRenderer)); mitk::DataStorage::SetOfObjects::Pointer nodes = mitk::DataStorage::SetOfObjects::New(); for (const auto& dataNode : selectedNodes) { if (boundingBoxPredicate->CheckNode(dataNode)) { nodes->InsertElement(nodes->Size(), dataNode); } } if (nodes->empty()) { return; } if (1 == nodes->Size()) // Special case: If exactly one ... { auto image = dynamic_cast(nodes->ElementAt(0)->GetData()); if (nullptr != image) // ... image is selected, reinit is expected to rectify askew images. { if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->InitializeViews(image->GetTimeGeometry()); } else { mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), image->GetTimeGeometry()); } return; } } auto boundingGeometry = dataStorage->ComputeBoundingGeometry3D(nodes, "visible", baseRenderer); if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->InitializeViews(boundingGeometry); } else { mitk::RenderingManager::GetInstance()->InitializeView(baseRenderer->GetRenderWindow(), boundingGeometry); } } } QmitkDataNodeReinitAction::QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Reinit")); InitializeAction(); } QmitkDataNodeReinitAction::QmitkDataNodeReinitAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Reinit")); InitializeAction(); } void QmitkDataNodeReinitAction::InitializeAction() { connect(this, &QmitkDataNodeReinitAction::triggered, this, &QmitkDataNodeReinitAction::OnActionTriggered); } void QmitkDataNodeReinitAction::OnActionTriggered(bool /*checked*/) { auto workbenchPartSite = m_WorkbenchPartSite.Lock(); if (workbenchPartSite.IsNull()) { return; } auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); auto selectedNodes = GetSelectedNodes(); ReinitAction::Run(workbenchPartSite, dataStorage, selectedNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeResetGeometryAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeResetGeometryAction.cpp index 49aabdb6f1..34aec1209d 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeResetGeometryAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeResetGeometryAction.cpp @@ -1,113 +1,115 @@ /*============================================================================ 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 // mitk core #include #include // mitk gui common plugin #include +#include + // namespace that contains the concrete action namespace ResetGeometryAction { void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, const mitk::TimeGeometry* referenceGeometry, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { if (workbenchPartSite.IsNull()) { return; } auto* renderWindowPart = mitk::WorkbenchUtil::GetRenderWindowPart(workbenchPartSite->GetPage(), mitk::WorkbenchUtil::NONE); if (nullptr == renderWindowPart) { renderWindowPart = mitk::WorkbenchUtil::OpenRenderWindowPart(workbenchPartSite->GetPage(), false); if (nullptr == renderWindowPart) { // no render window available return; } } if (nullptr == referenceGeometry) { return; } mitk::TimeStepType imageTimeStep = 0; // store the current position to set it again later, if the camera should not be reset mitk::Point3D currentPosition = renderWindowPart->GetSelectedPosition(); // store the current time step to set it again later, if the camera should not be reset auto* renderingManager = mitk::RenderingManager::GetInstance(); const mitk::TimePointType currentTimePoint = renderingManager->GetTimeNavigationController()->GetSelectedTimePoint(); if (referenceGeometry->IsValidTimePoint(currentTimePoint)) { imageTimeStep = referenceGeometry->TimePointToTimeStep(currentTimePoint); } if (nullptr == baseRenderer) { renderingManager->InitializeViews(referenceGeometry, mitk::RenderingManager::REQUEST_UPDATE_ALL, false); } else { renderingManager->InitializeView(baseRenderer->GetRenderWindow(), referenceGeometry, false); } renderWindowPart->SetSelectedPosition(currentPosition); renderingManager->GetTimeNavigationController()->GetStepper()->SetPos(imageTimeStep); } } // namespace ResetGeometryAction QmitkDataNodeResetGeometryAction::QmitkDataNodeResetGeometryAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { this->setText(tr("Reset geometry")); this->InitializeAction(); } QmitkDataNodeResetGeometryAction::QmitkDataNodeResetGeometryAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QmitkDataNodeResetGeometryAction(parent, berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { } void QmitkDataNodeResetGeometryAction::InitializeAction() { connect(this, &QmitkDataNodeResetGeometryAction::triggered, this, &QmitkDataNodeResetGeometryAction::OnActionTriggered); } void QmitkDataNodeResetGeometryAction::OnActionTriggered(bool /*checked*/) { auto workbenchPartSite = m_WorkbenchPartSite.Lock(); if (workbenchPartSite.IsNull()) { return; } auto baseRenderer = this->GetBaseRenderer(); auto selectedNode = this->GetSelectedNode(); mitk::Image::ConstPointer selectedImage = dynamic_cast(selectedNode->GetData()); if (selectedImage.IsNull()) { return; } ResetGeometryAction::Run(workbenchPartSite, selectedImage->GetTimeGeometry(), baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp index e42ec1aa42..8c5857c707 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeShowSelectedNodesAction.cpp @@ -1,70 +1,72 @@ /*============================================================================ 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 // mitk core #include +#include + QmitkDataNodeShowSelectedNodesAction::QmitkDataNodeShowSelectedNodesAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Show only selected nodes")); InitializeAction(); } QmitkDataNodeShowSelectedNodesAction::QmitkDataNodeShowSelectedNodesAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Show only selected nodes")); InitializeAction(); } void QmitkDataNodeShowSelectedNodesAction::InitializeAction() { connect(this, &QmitkDataNodeShowSelectedNodesAction::triggered, this, &QmitkDataNodeShowSelectedNodesAction::OnActionTriggered); } void QmitkDataNodeShowSelectedNodesAction::OnActionTriggered(bool /*checked*/) { auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); auto selectedNodes = GetSelectedNodes(); auto allNodes = dataStorage->GetAll(); for (auto& node : *allNodes) { if (node.IsNotNull() && node->GetData() != nullptr && strcmp(node->GetData()->GetNameOfClass(), "PlaneGeometryData")) { node->SetVisibility(selectedNodes.contains(node), baseRenderer); } } if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); } } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp index fea8a8598c..b041e59329 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeTextureInterpolationAction.cpp @@ -1,87 +1,89 @@ /*============================================================================ 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 // mitk core #include +#include + QmitkDataNodeTextureInterpolationAction::QmitkDataNodeTextureInterpolationAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Texture Interpolation")); InitializeAction(); } QmitkDataNodeTextureInterpolationAction::QmitkDataNodeTextureInterpolationAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Texture Interpolation")); InitializeAction(); } void QmitkDataNodeTextureInterpolationAction::InitializeAction() { setCheckable(true); connect(this, &QmitkDataNodeTextureInterpolationAction::toggled, this, &QmitkDataNodeTextureInterpolationAction::OnActionToggled); connect(this, &QmitkDataNodeTextureInterpolationAction::changed, this, &QmitkDataNodeTextureInterpolationAction::OnActionChanged); } void QmitkDataNodeTextureInterpolationAction::InitializeWithDataNode(const mitk::DataNode* dataNode) { if (nullptr == dataNode) { setChecked(false); return; } mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); bool textureInterpolation = false; dataNode->GetBoolProperty("texture interpolation", textureInterpolation, baseRenderer); setChecked(textureInterpolation); } void QmitkDataNodeTextureInterpolationAction::OnActionToggled(bool checked) { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); dataNode->SetBoolProperty("texture interpolation", checked, baseRenderer); if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); } } void QmitkDataNodeTextureInterpolationAction::OnActionChanged() { auto dataNode = GetSelectedNode(); if (dataNode.IsNull()) { return; } InitializeWithDataNode(dataNode); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp index d5aa7de5b4..51c9684afe 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkDataNodeToggleVisibilityAction.cpp @@ -1,102 +1,104 @@ /*============================================================================ 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 #include // mitk core #include #include #include #include +#include + // namespace that contains the concrete action namespace ToggleVisibilityAction { void Run(berry::IWorkbenchPartSite::Pointer workbenchPartSite, mitk::DataStorage::Pointer dataStorage, const QList& selectedNodes /*= QList()*/, mitk::BaseRenderer* baseRenderer /*= nullptr*/) { bool isVisible; for (auto& node : selectedNodes) { if (node.IsNotNull()) { isVisible = false; node->GetBoolProperty("visible", isVisible, baseRenderer); node->SetVisibility(!isVisible, baseRenderer); } } auto* prefService = mitk::CoreServices::GetPreferencesService(); auto* preferences = prefService->GetSystemPreferences()->Node(QmitkDataNodeGlobalReinitAction::ACTION_ID.toStdString()); bool globalReinit = preferences->GetBool("Call global reinit if node visibility is changed", false); if (globalReinit) { GlobalReinitAction::Run(workbenchPartSite, dataStorage); } else { if (nullptr == baseRenderer) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); } } } } QmitkDataNodeToggleVisibilityAction::QmitkDataNodeToggleVisibilityAction(QWidget* parent, berry::IWorkbenchPartSite::Pointer workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(workbenchpartSite) { setText(tr("Toggle visibility")); InitializeAction(); } QmitkDataNodeToggleVisibilityAction::QmitkDataNodeToggleVisibilityAction(QWidget* parent, berry::IWorkbenchPartSite* workbenchpartSite) : QAction(parent) , QmitkAbstractDataNodeAction(berry::IWorkbenchPartSite::Pointer(workbenchpartSite)) { setText(tr("Toggle visibility")); InitializeAction(); } void QmitkDataNodeToggleVisibilityAction::InitializeAction() { connect(this, &QmitkDataNodeToggleVisibilityAction::triggered, this, &QmitkDataNodeToggleVisibilityAction::OnActionTriggered); } void QmitkDataNodeToggleVisibilityAction::OnActionTriggered(bool /*checked*/) { auto workbenchPartSite = m_WorkbenchPartSite.Lock(); if (workbenchPartSite.IsNull()) { return; } auto dataStorage = m_DataStorage.Lock(); if (dataStorage.IsNull()) { return; } mitk::BaseRenderer::Pointer baseRenderer = GetBaseRenderer(); auto dataNodes = GetSelectedNodes(); ToggleVisibilityAction::Run(workbenchPartSite, dataStorage, dataNodes, baseRenderer); } diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkStatusBar.cpp b/Plugins/org.mitk.gui.qt.application/src/QmitkStatusBar.cpp index 9329824efc..02584a0aa9 100755 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkStatusBar.cpp +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkStatusBar.cpp @@ -1,89 +1,89 @@ /*============================================================================ 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 "QmitkStatusBar.h" -#include -#include -#include -#include +#include +#include +#include +#include #include #include /** * Display the text in the statusbar of the application */ void QmitkStatusBar::DisplayText(const char* t) { m_StatusBar->showMessage(t); // TODO bug #1357 //qApp->processEvents(); // produces crashes! } /** * Display the text in the statusbar of the application for ms seconds */ void QmitkStatusBar::DisplayText(const char* t, int ms) { m_StatusBar->showMessage(t, ms); // TODO bug #1357 //qApp->processEvents(); // produces crashes! } /** * Show the grey value text in the statusbar */ void QmitkStatusBar::DisplayGreyValueText(const char* t) { QString text(t); m_GreyValueLabel->setText(text); } /** * Clear the text in the StatusBar */ void QmitkStatusBar::Clear() { if (m_StatusBar != nullptr) m_StatusBar->clearMessage(); // TODO bug #1357 //qApp->processEvents(); // produces crashes! } /** * enable or disable the QSizeGrip */ void QmitkStatusBar::SetSizeGripEnabled(bool enable) { if (m_StatusBar != nullptr) m_StatusBar->setSizeGripEnabled(enable); } QmitkStatusBar::QmitkStatusBar(QStatusBar* instance) :StatusBarImplementation() { m_StatusBar = instance; m_GreyValueLabel = new QLabel(m_StatusBar,nullptr); int xResolution = QApplication::desktop()->screenGeometry(0).width()-100; m_GreyValueLabel->setMaximumSize(QSize(xResolution,50)); m_GreyValueLabel->setSizePolicy(QSizePolicy::Maximum,QSizePolicy::Fixed); m_StatusBar->addPermanentWidget(m_GreyValueLabel); mitk::StatusBar::SetImplementation(this); } QmitkStatusBar::~QmitkStatusBar() { } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp index e9b6b0b708..a7829fa0d2 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenMxNMultiWidgetEditorAction.cpp @@ -1,72 +1,74 @@ /*============================================================================ 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 "QmitkOpenMxNMultiWidgetEditorAction.h" #include "mitkCoreObjectFactory.h" #include #include #include #include #include "internal/QmitkCommonExtPlugin.h" #include +#include + class ctkPluginContext; QmitkOpenMxNMultiWidgetEditorAction::QmitkOpenMxNMultiWidgetEditorAction(berry::IWorkbenchWindow::Pointer window) : QAction(nullptr) { this->init(window); } QmitkOpenMxNMultiWidgetEditorAction::QmitkOpenMxNMultiWidgetEditorAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window) : QAction(nullptr) { this->setIcon(icon); this->init(window); } void QmitkOpenMxNMultiWidgetEditorAction::init(berry::IWorkbenchWindow::Pointer window) { m_Window = window; this->setParent(static_cast(m_Window->GetShell()->GetControl())); this->setText("MxN Display"); this->setToolTip("Open the mxn multi widget editor"); this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); } void QmitkOpenMxNMultiWidgetEditorAction::Run() { // check if there is an open perspective, if not open the default perspective if (m_Window->GetActivePage().IsNull()) { QString defaultPerspId = m_Window->GetWorkbench()->GetPerspectiveRegistry()->GetDefaultPerspective(); m_Window->GetWorkbench()->ShowPerspective(defaultPerspId, m_Window); } ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); ctkServiceReference serviceRef = context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService* dsService = context->getService(serviceRef); if (dsService) { mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); berry::IEditorInput::Pointer editorInput(new mitk::DataStorageEditorInput(dsRef)); m_Window->GetActivePage()->OpenEditor(editorInput, "org.mitk.editors.mxnmultiwidget", true, berry::IWorkbenchPage::MATCH_ID); } } } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp index a6aad97a05..bc530ca86d 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenStdMultiWidgetEditorAction.cpp @@ -1,72 +1,74 @@ /*============================================================================ 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 "QmitkOpenStdMultiWidgetEditorAction.h" #include "mitkCoreObjectFactory.h" #include #include #include #include #include "internal/QmitkCommonExtPlugin.h" #include +#include + class ctkPluginContext; QmitkOpenStdMultiWidgetEditorAction::QmitkOpenStdMultiWidgetEditorAction(berry::IWorkbenchWindow::Pointer window) : QAction(nullptr) { this->init(window); } QmitkOpenStdMultiWidgetEditorAction::QmitkOpenStdMultiWidgetEditorAction(const QIcon& icon, berry::IWorkbenchWindow::Pointer window) : QAction(nullptr) { this->setIcon(icon); this->init(window); } void QmitkOpenStdMultiWidgetEditorAction::init(berry::IWorkbenchWindow::Pointer window) { m_Window = window; this->setParent(static_cast(m_Window->GetShell()->GetControl())); this->setText("Standard Display"); this->setToolTip("Open the standard multi widget editor"); this->connect(this, SIGNAL(triggered(bool)), this, SLOT(Run())); } void QmitkOpenStdMultiWidgetEditorAction::Run() { // check if there is an open perspective, if not open the default perspective if (m_Window->GetActivePage().IsNull()) { QString defaultPerspId = m_Window->GetWorkbench()->GetPerspectiveRegistry()->GetDefaultPerspective(); m_Window->GetWorkbench()->ShowPerspective(defaultPerspId, m_Window); } ctkPluginContext* context = QmitkCommonExtPlugin::getContext(); ctkServiceReference serviceRef = context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService* dsService = context->getService(serviceRef); if (dsService) { mitk::IDataStorageReference::Pointer dsRef = dsService->GetDataStorage(); berry::IEditorInput::Pointer editorInput(new mitk::DataStorageEditorInput(dsRef)); m_Window->GetActivePage()->OpenEditor(editorInput, "org.mitk.editors.stdmultiwidget", true, berry::IWorkbenchPage::MATCH_ID); } } } diff --git a/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkCommonExtPlugin.cpp b/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkCommonExtPlugin.cpp index 7e85faa6f1..99394e3e56 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkCommonExtPlugin.cpp +++ b/Plugins/org.mitk.gui.qt.ext/src/internal/QmitkCommonExtPlugin.cpp @@ -1,237 +1,238 @@ /*============================================================================ 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 "QmitkCommonExtPlugin.h" #include #include "QmitkAboutHandler.h" #include "QmitkAppInstancesPreferencePage.h" #include "QmitkExternalProgramsPreferencePage.h" #include "QmitkModuleView.h" #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include #include US_INITIALIZE_MODULE ctkPluginContext* QmitkCommonExtPlugin::_context = nullptr; void QmitkCommonExtPlugin::start(ctkPluginContext* context) { this->_context = context; QtWidgetsExtRegisterClasses(); BERRY_REGISTER_EXTENSION_CLASS(QmitkAboutHandler, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkAppInstancesPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkExternalProgramsPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkModuleView, context) if (qApp->metaObject()->indexOfSignal("messageReceived(QByteArray)") > -1) { connect(qApp, SIGNAL(messageReceived(QByteArray)), this, SLOT(handleIPCMessage(QByteArray))); } // This is a potentially long running operation. loadDataFromDisk(berry::Platform::GetApplicationArgs(), true); } void QmitkCommonExtPlugin::stop(ctkPluginContext* context) { Q_UNUSED(context) this->_context = nullptr; } ctkPluginContext* QmitkCommonExtPlugin::getContext() { return _context; } void QmitkCommonExtPlugin::loadDataFromDisk(const QStringList &arguments, bool globalReinit) { if (!arguments.empty()) { ctkServiceReference serviceRef = _context->getServiceReference(); if (serviceRef) { mitk::IDataStorageService* dataStorageService = _context->getService(serviceRef); mitk::DataStorage::Pointer dataStorage = dataStorageService->GetDefaultDataStorage()->GetDataStorage(); int argumentsAdded = 0; for (int i = 0; i < arguments.size(); ++i) { if (arguments[i].right(5) == ".mitk") { mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); bool clearDataStorageFirst(false); mitk::ProgressBar::GetInstance()->AddStepsToDo(2); dataStorage = sceneIO->LoadScene( arguments[i].toLocal8Bit().constData(), dataStorage, clearDataStorageFirst ); mitk::ProgressBar::GetInstance()->Progress(2); argumentsAdded++; } else if (arguments[i].right(15) == ".mitksceneindex") { mitk::SceneIO::Pointer sceneIO = mitk::SceneIO::New(); bool clearDataStorageFirst(false); mitk::ProgressBar::GetInstance()->AddStepsToDo(2); dataStorage = sceneIO->LoadSceneUnzipped(arguments[i].toLocal8Bit().constData(), dataStorage, clearDataStorageFirst); mitk::ProgressBar::GetInstance()->Progress(2); argumentsAdded++; } else { try { const std::string path(arguments[i].toStdString()); auto addedNodes = mitk::IOUtil::Load(path, *dataStorage); for (const auto& node : *addedNodes ) { node->SetIntProperty("layer", argumentsAdded); } argumentsAdded++; } catch(...) { MITK_WARN << "Failed to load command line argument: " << arguments[i].toStdString(); } } } // end for each command line argument if (argumentsAdded > 0 && globalReinit) { // calculate bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(dataStorage->ComputeBoundingGeometry3D()); } } else { MITK_ERROR << "A service reference for mitk::IDataStorageService does not exist"; } } } void QmitkCommonExtPlugin::startNewInstance(const QStringList &args, const QStringList& files) { QStringList newArgs(args); #ifdef Q_OS_UNIX newArgs << QString("--") + mitk::BaseApplication::ARG_NEWINSTANCE; #else newArgs << QString("/") + mitk::BaseApplication::ARG_NEWINSTANCE; #endif newArgs << files; QProcess::startDetached(qApp->applicationFilePath(), newArgs); } void QmitkCommonExtPlugin::handleIPCMessage(const QByteArray& msg) { QDataStream ds(msg); QString msgType; ds >> msgType; // we only handle messages containing command line arguments if (msgType != "$cmdLineArgs") return; // activate the current workbench window berry::IWorkbenchWindow::Pointer window = berry::PlatformUI::GetWorkbench()->GetActiveWorkbenchWindow(); QMainWindow* mainWindow = static_cast (window->GetShell()->GetControl()); mainWindow->setWindowState(mainWindow->windowState() & ~Qt::WindowMinimized); mainWindow->raise(); mainWindow->activateWindow(); // Get the preferences for the instantiation behavior auto* prefService = mitk::CoreServices::GetPreferencesService(); auto* prefs = prefService->GetSystemPreferences()->Node("/General"); bool newInstanceAlways = prefs->GetBool("newInstance.always", false); bool newInstanceScene = prefs->GetBool("newInstance.scene", true); QStringList args; ds >> args; QStringList fileArgs; QStringList sceneArgs; foreach (QString arg, args) { if (arg.endsWith(".mitk")) { sceneArgs << arg; } else { fileArgs << arg; } } if (newInstanceAlways) { if (newInstanceScene) { startNewInstance(args, fileArgs); foreach(QString sceneFile, sceneArgs) { startNewInstance(args, QStringList(sceneFile)); } } else { fileArgs.append(sceneArgs); startNewInstance(args, fileArgs); } } else { loadDataFromDisk(fileArgs, false); if (newInstanceScene) { foreach(QString sceneFile, sceneArgs) { startNewInstance(args, QStringList(sceneFile)); } } else { loadDataFromDisk(sceneArgs, false); } } } diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp index 9a32cb1f47..f0df3dcc23 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/src/internal/QmitkMeasurementView.cpp @@ -1,820 +1,821 @@ /*============================================================================ 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 "QmitkMeasurementView.h" #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ctkDoubleSpinBox.h" #include "mitkPluginActivator.h" #include "usModuleRegistry.h" #include "usGetModuleContext.h" #include "usModuleContext.h" #include US_INITIALIZE_MODULE struct QmitkPlanarFigureData { QmitkPlanarFigureData() : m_EndPlacementObserverTag(0), m_SelectObserverTag(0), m_StartInteractionObserverTag(0), m_EndInteractionObserverTag(0), m_DuringInteractionObserverTag(0) { } mitk::PlanarFigure::Pointer m_Figure; unsigned int m_EndPlacementObserverTag; unsigned int m_SelectObserverTag; unsigned int m_StartInteractionObserverTag; unsigned int m_EndInteractionObserverTag; unsigned int m_DuringInteractionObserverTag; }; struct QmitkMeasurementViewData { QmitkMeasurementViewData() : m_LineCounter(0), m_PathCounter(0), m_AngleCounter(0), m_FourPointAngleCounter(0), m_CircleCounter(0), m_EllipseCounter(0), m_DoubleEllipseCounter(0), m_RectangleCounter(0), m_PolygonCounter(0), m_BezierCurveCounter(0), m_SubdivisionPolygonCounter(0), m_UnintializedPlanarFigure(false), m_Parent(nullptr), m_SingleNodeSelectionWidget(nullptr), m_DrawLine(nullptr), m_DrawPath(nullptr), m_DrawAngle(nullptr), m_DrawFourPointAngle(nullptr), m_DrawRectangle(nullptr), m_DrawPolygon(nullptr), m_DrawCircle(nullptr), m_DrawEllipse(nullptr), m_DrawDoubleEllipse(nullptr), m_DrawBezierCurve(nullptr), m_DrawSubdivisionPolygon(nullptr), m_DrawActionsToolBar(nullptr), m_DrawActionsGroup(nullptr), m_SelectedPlanarFiguresText(nullptr), m_CopyToClipboard(nullptr), m_Layout(nullptr), m_Radius(nullptr), m_Thickness(nullptr), m_FixedParameterBox(nullptr) { } unsigned int m_LineCounter; unsigned int m_PathCounter; unsigned int m_AngleCounter; unsigned int m_FourPointAngleCounter; unsigned int m_CircleCounter; unsigned int m_EllipseCounter; unsigned int m_DoubleEllipseCounter; unsigned int m_RectangleCounter; unsigned int m_PolygonCounter; unsigned int m_BezierCurveCounter; unsigned int m_SubdivisionPolygonCounter; QList m_CurrentSelection; std::map m_DataNodeToPlanarFigureData; mitk::DataNode::Pointer m_SelectedImageNode; bool m_UnintializedPlanarFigure; QWidget* m_Parent; QLabel* m_SelectedImageLabel; QmitkSingleNodeSelectionWidget* m_SingleNodeSelectionWidget; QAction* m_DrawLine; QAction* m_DrawPath; QAction* m_DrawAngle; QAction* m_DrawFourPointAngle; QAction* m_DrawRectangle; QAction* m_DrawPolygon; QAction* m_DrawCircle; QAction* m_DrawEllipse; QAction* m_DrawDoubleEllipse; QAction* m_DrawBezierCurve; QAction* m_DrawSubdivisionPolygon; QToolBar* m_DrawActionsToolBar; QActionGroup* m_DrawActionsGroup; QTextBrowser* m_SelectedPlanarFiguresText; QPushButton* m_CopyToClipboard; QGridLayout* m_Layout; ctkDoubleSpinBox* m_Radius; ctkDoubleSpinBox* m_Thickness; QGroupBox* m_FixedParameterBox; }; const std::string QmitkMeasurementView::VIEW_ID = "org.mitk.views.measurement"; QmitkMeasurementView::QmitkMeasurementView() : d(new QmitkMeasurementViewData) { } QmitkMeasurementView::~QmitkMeasurementView() { auto planarFigures = this->GetAllPlanarFigures(); for (auto it = planarFigures->Begin(); it != planarFigures->End(); ++it) this->NodeRemoved(it.Value()); delete d; } void QmitkMeasurementView::CreateQtPartControl(QWidget* parent) { d->m_Parent = parent; d->m_SingleNodeSelectionWidget = new QmitkSingleNodeSelectionWidget(); d->m_SingleNodeSelectionWidget->SetDataStorage(GetDataStorage()); d->m_SingleNodeSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); d->m_SingleNodeSelectionWidget->SetSelectionIsOptional(true); d->m_SingleNodeSelectionWidget->SetEmptyInfo(QStringLiteral("Please select a reference image")); d->m_SingleNodeSelectionWidget->SetPopUpTitel(QStringLiteral("Select a reference image")); d->m_DrawActionsToolBar = new QToolBar; d->m_DrawActionsGroup = new QActionGroup(this); d->m_DrawActionsGroup->setExclusive(true); auto* currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/line.png"), tr("Draw Line")); currentAction->setCheckable(true); d->m_DrawLine = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/path.png"), tr("Draw Path")); currentAction->setCheckable(true); d->m_DrawPath = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/angle.png"), tr("Draw Angle")); currentAction->setCheckable(true); d->m_DrawAngle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/four-point-angle.png"), tr("Draw Four Point Angle")); currentAction->setCheckable(true); d->m_DrawFourPointAngle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/circle.png"), tr("Draw Circle")); currentAction->setCheckable(true); d->m_DrawCircle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/ellipse.png"), tr("Draw Ellipse")); currentAction->setCheckable(true); d->m_DrawEllipse = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/doubleellipse.png"), tr("Draw Double Ellipse")); currentAction->setCheckable(true); d->m_DrawDoubleEllipse = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/rectangle.png"), tr("Draw Rectangle")); currentAction->setCheckable(true); d->m_DrawRectangle = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/polygon.png"), tr("Draw Polygon")); currentAction->setCheckable(true); d->m_DrawPolygon = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/beziercurve.png"), tr("Draw Bezier Curve")); currentAction->setCheckable(true); d->m_DrawBezierCurve = currentAction; currentAction = d->m_DrawActionsToolBar->addAction(QIcon(":/measurement/subdivisionpolygon.png"), tr("Draw Subdivision Polygon")); currentAction->setCheckable(true); d->m_DrawSubdivisionPolygon = currentAction; d->m_DrawActionsToolBar->setEnabled(false); // fixed parameter section auto fixedLayout = new QGridLayout(); d->m_FixedParameterBox = new QGroupBox(); d->m_FixedParameterBox->setCheckable(true); d->m_FixedParameterBox->setChecked(false); d->m_FixedParameterBox->setEnabled(false); d->m_FixedParameterBox->setTitle("Fixed sized circle/double ellipse"); d->m_FixedParameterBox->setToolTip("If activated, circles and double ellipses (as rings) figures will always be created with the set parameters as fixed size."); d->m_FixedParameterBox->setAlignment(Qt::AlignLeft); auto labelRadius1 = new QLabel(QString("Radius")); d->m_Radius = new ctkDoubleSpinBox(); d->m_Radius->setMinimum(0); d->m_Radius->setValue(10); d->m_Radius->setSuffix(" mm"); d->m_Radius->setAlignment(Qt::AlignLeft); d->m_Radius->setToolTip("Sets the radius for following planar figures: circle, double ellipse (as ring)."); auto labelThickness = new QLabel(QString("Thickness")); d->m_Thickness = new ctkDoubleSpinBox(); d->m_Thickness->setMinimum(0); d->m_Thickness->setMaximum(10); d->m_Thickness->setValue(5); d->m_Thickness->setSuffix(" mm"); d->m_Thickness->setAlignment(Qt::AlignLeft); d->m_Thickness->setToolTip("Sets the thickness for following planar figures: double ellipse (as ring)."); fixedLayout->addWidget(labelRadius1,0,0); fixedLayout->addWidget(d->m_Radius,0,1); fixedLayout->addWidget(labelThickness,1,0); fixedLayout->addWidget(d->m_Thickness,1,1); d->m_FixedParameterBox->setLayout(fixedLayout); // planar figure details text d->m_SelectedPlanarFiguresText = new QTextBrowser; // copy to clipboard button d->m_CopyToClipboard = new QPushButton(tr("Copy to Clipboard")); d->m_SelectedImageLabel = new QLabel("Selected Image"); d->m_Layout = new QGridLayout; d->m_Layout->addWidget(d->m_SelectedImageLabel, 0, 0); d->m_Layout->addWidget(d->m_SingleNodeSelectionWidget, 0, 1, 1, 1); d->m_Layout->addWidget(d->m_DrawActionsToolBar, 1, 0, 1, 2); d->m_Layout->addWidget(d->m_FixedParameterBox, 2, 0, 1, 2); d->m_Layout->addWidget(d->m_SelectedPlanarFiguresText, 3, 0, 1, 2); d->m_Layout->addWidget(d->m_CopyToClipboard, 4, 0, 1, 2); d->m_Parent->setLayout(d->m_Layout); this->CreateConnections(); this->AddAllInteractors(); // placed after CreateConnections to trigger update of the current selection d->m_SingleNodeSelectionWidget->SetAutoSelectNewNodes(true); } void QmitkMeasurementView::CreateConnections() { connect(d->m_SingleNodeSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, this, &QmitkMeasurementView::OnCurrentSelectionChanged); connect(d->m_DrawLine, SIGNAL(triggered(bool)), this, SLOT(OnDrawLineTriggered(bool))); connect(d->m_DrawPath, SIGNAL(triggered(bool)), this, SLOT(OnDrawPathTriggered(bool))); connect(d->m_DrawAngle, SIGNAL(triggered(bool)), this, SLOT(OnDrawAngleTriggered(bool))); connect(d->m_DrawFourPointAngle, SIGNAL(triggered(bool)), this, SLOT(OnDrawFourPointAngleTriggered(bool))); connect(d->m_DrawCircle, SIGNAL(triggered(bool)), this, SLOT(OnDrawCircleTriggered(bool))); connect(d->m_DrawEllipse, SIGNAL(triggered(bool)), this, SLOT(OnDrawEllipseTriggered(bool))); connect(d->m_DrawDoubleEllipse, SIGNAL(triggered(bool)), this, SLOT(OnDrawDoubleEllipseTriggered(bool))); connect(d->m_DrawRectangle, SIGNAL(triggered(bool)), this, SLOT(OnDrawRectangleTriggered(bool))); connect(d->m_DrawPolygon, SIGNAL(triggered(bool)), this, SLOT(OnDrawPolygonTriggered(bool))); connect(d->m_DrawBezierCurve, SIGNAL(triggered(bool)), this, SLOT(OnDrawBezierCurveTriggered(bool))); connect(d->m_DrawSubdivisionPolygon, SIGNAL(triggered(bool)), this, SLOT(OnDrawSubdivisionPolygonTriggered(bool))); connect(d->m_CopyToClipboard, SIGNAL(clicked(bool)), this, SLOT(OnCopyToClipboard(bool))); connect(d->m_Radius, QOverload::of(&ctkDoubleSpinBox::valueChanged), d->m_Thickness, &ctkDoubleSpinBox::setMaximum); } void QmitkMeasurementView::OnCurrentSelectionChanged(QList nodes) { if (nodes.empty() || nodes.front().IsNull()) { d->m_SelectedImageNode = nullptr; d->m_DrawActionsToolBar->setEnabled(false); d->m_FixedParameterBox->setEnabled(false); } else { d->m_SelectedImageNode = nodes.front(); d->m_DrawActionsToolBar->setEnabled(true); d->m_FixedParameterBox->setEnabled(true); } } void QmitkMeasurementView::NodeAdded(const mitk::DataNode* node) { // add observer for selection in renderwindow mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(node->GetData()); auto isPositionMarker = false; node->GetBoolProperty("isContourMarker", isPositionMarker); if (planarFigure.IsNotNull() && !isPositionMarker) { auto nonConstNode = const_cast(node); mitk::PlanarFigureInteractor::Pointer interactor = dynamic_cast(node->GetDataInteractor().GetPointer()); if (interactor.IsNull()) { interactor = mitk::PlanarFigureInteractor::New(); auto planarFigureModule = us::ModuleRegistry::GetModule("MitkPlanarFigure"); interactor->LoadStateMachine("PlanarFigureInteraction.xml", planarFigureModule); interactor->SetEventConfig("PlanarFigureConfig.xml", planarFigureModule); } interactor->SetDataNode(nonConstNode); QmitkPlanarFigureData data; data.m_Figure = planarFigure; typedef itk::SimpleMemberCommand SimpleCommandType; typedef itk::MemberCommand MemberCommandType; // add observer for event when figure has been placed auto initializationCommand = SimpleCommandType::New(); initializationCommand->SetCallbackFunction(this, &QmitkMeasurementView::PlanarFigureInitialized); data.m_EndPlacementObserverTag = planarFigure->AddObserver(mitk::EndPlacementPlanarFigureEvent(), initializationCommand); // add observer for event when figure is picked (selected) auto selectCommand = MemberCommandType::New(); selectCommand->SetCallbackFunction(this, &QmitkMeasurementView::PlanarFigureSelected); data.m_SelectObserverTag = planarFigure->AddObserver(mitk::SelectPlanarFigureEvent(), selectCommand); // add observer for event during interaction when a point is moved auto duringInteractionCommand = SimpleCommandType::New(); duringInteractionCommand->SetCallbackFunction(this, &QmitkMeasurementView::UpdateMeasurementText); data.m_DuringInteractionObserverTag = planarFigure->AddObserver(mitk::PointMovedPlanarFigureEvent(), duringInteractionCommand); // adding to the map of tracked planarfigures d->m_DataNodeToPlanarFigureData[nonConstNode] = data; } } void QmitkMeasurementView::NodeChanged(const mitk::DataNode* node) { auto it = std::find(d->m_CurrentSelection.begin(), d->m_CurrentSelection.end(), node); if (it != d->m_CurrentSelection.end()) { this->UpdateMeasurementText(); } } void QmitkMeasurementView::NodeRemoved(const mitk::DataNode* node) { auto nonConstNode = const_cast(node); auto it = d->m_DataNodeToPlanarFigureData.find(nonConstNode); auto isFigureFinished = false; auto isPlaced = false; if (it != d->m_DataNodeToPlanarFigureData.end()) { QmitkPlanarFigureData& data = it->second; data.m_Figure->RemoveObserver(data.m_EndPlacementObserverTag); data.m_Figure->RemoveObserver(data.m_SelectObserverTag); data.m_Figure->RemoveObserver(data.m_StartInteractionObserverTag); data.m_Figure->RemoveObserver(data.m_EndInteractionObserverTag); data.m_Figure->RemoveObserver(data.m_DuringInteractionObserverTag); isFigureFinished = data.m_Figure->GetPropertyList()->GetBoolProperty("initiallyplaced", isPlaced); if (!isFigureFinished) // if the property does not yet exist or is false, drop the datanode this->PlanarFigureInitialized(); // normally called when a figure is finished, to reset all buttons d->m_DataNodeToPlanarFigureData.erase( it ); } if (nonConstNode != nullptr) nonConstNode->SetDataInteractor(nullptr); auto isPlanarFigure = mitk::TNodePredicateDataType::New(); auto nodes = this->GetDataStorage()->GetDerivations(node, isPlanarFigure); for (unsigned int x = 0; x < nodes->size(); ++x) { mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(nodes->at(x)->GetData()); if (planarFigure.IsNotNull()) { isFigureFinished = planarFigure->GetPropertyList()->GetBoolProperty("initiallyplaced",isPlaced); if (!isFigureFinished) // if the property does not yet exist or is false, drop the datanode { this->GetDataStorage()->Remove(nodes->at(x)); if (!d->m_DataNodeToPlanarFigureData.empty()) { it = d->m_DataNodeToPlanarFigureData.find(nodes->at(x)); if (it != d->m_DataNodeToPlanarFigureData.end()) { d->m_DataNodeToPlanarFigureData.erase(it); this->PlanarFigureInitialized(); // normally called when a figure is finished, to reset all buttons } } } } } } void QmitkMeasurementView::PlanarFigureSelected(itk::Object* object, const itk::EventObject&) { d->m_CurrentSelection.clear(); auto lambda = [&object](const std::pair& element) { return element.second.m_Figure == object; }; auto it = std::find_if(d->m_DataNodeToPlanarFigureData.begin(), d->m_DataNodeToPlanarFigureData.end(), lambda); if (it != d->m_DataNodeToPlanarFigureData.end()) { d->m_CurrentSelection.push_back(it->first); } this->UpdateMeasurementText(); this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::PlanarFigureInitialized() { d->m_UnintializedPlanarFigure = false; d->m_DrawActionsToolBar->setEnabled(true); d->m_DrawLine->setChecked(false); d->m_DrawPath->setChecked(false); d->m_DrawAngle->setChecked(false); d->m_DrawFourPointAngle->setChecked(false); d->m_DrawCircle->setChecked(false); d->m_DrawEllipse->setChecked(false); d->m_DrawDoubleEllipse->setChecked(false); d->m_DrawRectangle->setChecked(false); d->m_DrawPolygon->setChecked(false); d->m_DrawBezierCurve->setChecked(false); d->m_DrawSubdivisionPolygon->setChecked(false); } void QmitkMeasurementView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& nodes) { d->m_CurrentSelection = nodes; this->UpdateMeasurementText(); // bug 16600: deselecting all planarfigures by clicking on datamanager when no node is selected if (d->m_CurrentSelection.size() == 0) { auto isPlanarFigure = mitk::TNodePredicateDataType::New(); auto planarFigures = this->GetDataStorage()->GetSubset(isPlanarFigure); // setting all planar figures which are not helper objects not selected for (mitk::DataStorage::SetOfObjects::ConstIterator it = planarFigures->Begin(); it != planarFigures->End(); ++it) { auto node = it.Value(); auto isHelperObject = false; node->GetBoolProperty("helper object", isHelperObject); if (!isHelperObject) node->SetSelected(false); } } for (int i = d->m_CurrentSelection.size() - 1; i >= 0; --i) { auto node = d->m_CurrentSelection[i]; mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(node->GetData()); // the last selected planar figure if (planarFigure.IsNotNull() && planarFigure->GetPlaneGeometry()) { auto planarFigureInitializedWindow = false; auto linkedRenderWindow = dynamic_cast(this->GetRenderWindowPart()); QmitkRenderWindow* selectedRenderWindow; if (!linkedRenderWindow) return; auto axialRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("axial"); auto sagittalRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("sagittal"); auto coronalRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("coronal"); auto threeDimRenderWindow = linkedRenderWindow->GetQmitkRenderWindow("3d"); if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, axialRenderWindow->GetRenderer())) { selectedRenderWindow = axialRenderWindow; } else if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, sagittalRenderWindow->GetRenderer())) { selectedRenderWindow = sagittalRenderWindow; } else if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, coronalRenderWindow->GetRenderer())) { selectedRenderWindow = coronalRenderWindow; } else if (node->GetBoolProperty("planarFigureInitializedWindow", planarFigureInitializedWindow, threeDimRenderWindow->GetRenderer())) { selectedRenderWindow = threeDimRenderWindow; } else { selectedRenderWindow = nullptr; } auto planeGeometry = dynamic_cast(planarFigure->GetPlaneGeometry()); auto normal = planeGeometry->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer axialPlane = axialRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); auto axialNormal = axialPlane->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer sagittalPlane = sagittalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); auto sagittalNormal = sagittalPlane->GetNormalVnl(); mitk::PlaneGeometry::ConstPointer coronalPlane = coronalRenderWindow->GetRenderer()->GetCurrentWorldPlaneGeometry(); auto coronalNormal = coronalPlane->GetNormalVnl(); normal[0] = fabs(normal[0]); normal[1] = fabs(normal[1]); normal[2] = fabs(normal[2]); axialNormal[0] = fabs(axialNormal[0]); axialNormal[1] = fabs(axialNormal[1]); axialNormal[2] = fabs(axialNormal[2]); sagittalNormal[0] = fabs(sagittalNormal[0]); sagittalNormal[1] = fabs(sagittalNormal[1]); sagittalNormal[2] = fabs(sagittalNormal[2]); coronalNormal[0] = fabs(coronalNormal[0]); coronalNormal[1] = fabs(coronalNormal[1]); coronalNormal[2] = fabs(coronalNormal[2]); auto ang1 = angle(normal, axialNormal); auto ang2 = angle(normal, sagittalNormal); auto ang3 = angle(normal, coronalNormal); if (ang1 < ang2 && ang1 < ang3) { selectedRenderWindow = axialRenderWindow; } else { if (ang2 < ang3) { selectedRenderWindow = sagittalRenderWindow; } else { selectedRenderWindow = coronalRenderWindow; } } // re-orient view if (selectedRenderWindow) selectedRenderWindow->GetSliceNavigationController()->ReorientSlices(planeGeometry->GetOrigin(), planeGeometry->GetNormal()); } break; } this->RequestRenderWindowUpdate(); } void QmitkMeasurementView::OnDrawLineTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarLine::New(), QString("Line%1").arg(++d->m_LineCounter)); } void QmitkMeasurementView::OnDrawPathTriggered(bool) { mitk::CoreServicePointer propertyFilters(mitk::CoreServices::GetPropertyFilters()); mitk::PropertyFilter filter; filter.AddEntry("ClosedPlanarPolygon", mitk::PropertyFilter::Blacklist); propertyFilters->AddFilter(filter, "PlanarPolygon"); mitk::PlanarPolygon::Pointer planarFigure = mitk::PlanarPolygon::New(); planarFigure->ClosedOff(); auto node = this->AddFigureToDataStorage( planarFigure, QString("Path%1").arg(++d->m_PathCounter)); node->SetProperty("ClosedPlanarPolygon", mitk::BoolProperty::New(false)); node->SetProperty("planarfigure.isextendable", mitk::BoolProperty::New(true)); } void QmitkMeasurementView::OnDrawAngleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarAngle::New(), QString("Angle%1").arg(++d->m_AngleCounter)); } void QmitkMeasurementView::OnDrawFourPointAngleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarFourPointAngle::New(), QString("Four Point Angle%1").arg(++d->m_FourPointAngleCounter)); } void QmitkMeasurementView::OnDrawCircleTriggered(bool) { auto circle = (d->m_FixedParameterBox->isChecked()) ? mitk::PlanarCircle::New(d->m_Radius->value()) : mitk::PlanarCircle::New(); this->AddFigureToDataStorage(circle, QString("Circle%1").arg(++d->m_CircleCounter)); } void QmitkMeasurementView::OnDrawEllipseTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarEllipse::New(), QString("Ellipse%1").arg(++d->m_EllipseCounter)); } void QmitkMeasurementView::OnDrawDoubleEllipseTriggered(bool) { auto ellipse = (d->m_FixedParameterBox->isChecked()) ? mitk::PlanarDoubleEllipse::New(d->m_Radius->value(),d->m_Thickness->value()) : mitk::PlanarDoubleEllipse::New(); this->AddFigureToDataStorage(ellipse, QString("DoubleEllipse%1").arg(++d->m_DoubleEllipseCounter)); } void QmitkMeasurementView::OnDrawBezierCurveTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarBezierCurve::New(), QString("BezierCurve%1").arg(++d->m_BezierCurveCounter)); } void QmitkMeasurementView::OnDrawSubdivisionPolygonTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarSubdivisionPolygon::New(), QString("SubdivisionPolygon%1").arg(++d->m_SubdivisionPolygonCounter)); } void QmitkMeasurementView::OnDrawRectangleTriggered(bool) { this->AddFigureToDataStorage( mitk::PlanarRectangle::New(), QString("Rectangle%1").arg(++d->m_RectangleCounter)); } void QmitkMeasurementView::OnDrawPolygonTriggered(bool) { auto planarFigure = mitk::PlanarPolygon::New(); planarFigure->ClosedOn(); auto node = this->AddFigureToDataStorage( planarFigure, QString("Polygon%1").arg(++d->m_PolygonCounter)); node->SetProperty("planarfigure.isextendable", mitk::BoolProperty::New(true)); } void QmitkMeasurementView::OnCopyToClipboard(bool) { QApplication::clipboard()->setText(d->m_SelectedPlanarFiguresText->toPlainText(), QClipboard::Clipboard); } mitk::DataNode::Pointer QmitkMeasurementView::AddFigureToDataStorage(mitk::PlanarFigure* figure, const QString& name) { auto newNode = mitk::DataNode::New(); newNode->SetName(name.toStdString()); newNode->SetData(figure); newNode->SetSelected(true); if (d->m_SelectedImageNode.IsNotNull()) { this->GetDataStorage()->Add(newNode, d->m_SelectedImageNode); } else { this->GetDataStorage()->Add(newNode); } for (auto &node : d->m_CurrentSelection) node->SetSelected(false); d->m_CurrentSelection.clear(); d->m_CurrentSelection.push_back(newNode); this->UpdateMeasurementText(); d->m_DrawActionsToolBar->setEnabled(false); d->m_UnintializedPlanarFigure = true; return newNode; } void QmitkMeasurementView::UpdateMeasurementText() { d->m_SelectedPlanarFiguresText->clear(); QString infoText; QString plainInfoText; int j = 1; mitk::PlanarFigure::Pointer planarFigure; mitk::PlanarAngle::Pointer planarAngle; mitk::PlanarFourPointAngle::Pointer planarFourPointAngle; mitk::DataNode::Pointer node; for (int i = 0; i < d->m_CurrentSelection.size(); ++i, ++j) { plainInfoText.clear(); node = d->m_CurrentSelection[i]; planarFigure = dynamic_cast(node->GetData()); if (planarFigure.IsNull()) continue; if (j > 1) infoText.append("
"); infoText.append(QString("%1
").arg(QString::fromStdString(node->GetName()))); plainInfoText.append(QString("%1").arg(QString::fromStdString(node->GetName()))); planarAngle = dynamic_cast (planarFigure.GetPointer()); if (planarAngle.IsNull()) planarFourPointAngle = dynamic_cast (planarFigure.GetPointer()); double featureQuantity = 0.0; for (unsigned int k = 0; k < planarFigure->GetNumberOfFeatures(); ++k) { if (!planarFigure->IsFeatureActive(k)) continue; featureQuantity = planarFigure->GetQuantity(k); if ((planarAngle.IsNotNull() && k == planarAngle->FEATURE_ID_ANGLE) || (planarFourPointAngle.IsNotNull() && k == planarFourPointAngle->FEATURE_ID_ANGLE)) featureQuantity = featureQuantity * 180 / vnl_math::pi; infoText.append(QString("%1: %2 %3") .arg(QString(planarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', 2) .arg(QString(planarFigure->GetFeatureUnit(k)))); plainInfoText.append(QString("\n%1: %2 %3") .arg(QString(planarFigure->GetFeatureName(k))) .arg(featureQuantity, 0, 'f', 2) .arg(QString(planarFigure->GetFeatureUnit(k)))); if (k + 1 != planarFigure->GetNumberOfFeatures()) infoText.append("
"); } if (j != d->m_CurrentSelection.size()) infoText.append("
"); } d->m_SelectedPlanarFiguresText->setHtml(infoText); } void QmitkMeasurementView::AddAllInteractors() { auto planarFigures = this->GetAllPlanarFigures(); for (auto it = planarFigures->Begin(); it != planarFigures->End(); ++it) this->NodeAdded(it.Value()); } mitk::DataStorage::SetOfObjects::ConstPointer QmitkMeasurementView::GetAllPlanarFigures() const { auto isPlanarFigure = mitk::TNodePredicateDataType::New(); auto isNotHelperObject = mitk::NodePredicateProperty::New("helper object", mitk::BoolProperty::New(false)); auto isNotHelperButPlanarFigure = mitk::NodePredicateAnd::New( isPlanarFigure, isNotHelperObject ); return this->GetDataStorage()->GetSubset(isPlanarFigure); }