diff --git a/CMakeLists.txt b/CMakeLists.txt index 13bf0b3e..d73ed0ef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -99,8 +99,8 @@ SET(SNAP_VERSION_PATCH 2) SET(SNAP_VERSION_QUALIFIER "-beta") # These fields should also be modified each time -SET(SNAP_VERSION_RELEASE_DATE "20240926") -SET(SNAP_VERSION_RELEASE_DATE_FORMATTED "September 26, 2024") +SET(SNAP_VERSION_RELEASE_DATE "20241111") +SET(SNAP_VERSION_RELEASE_DATE_FORMATTED "November 11, 2024") # This field should only change when the format of the settings files changes # in a non backwards-compatible way diff --git a/GUI/Qt/Windows/MainImageWindow.cxx b/GUI/Qt/Windows/MainImageWindow.cxx index 83eb1df7..3acebe9a 100644 --- a/GUI/Qt/Windows/MainImageWindow.cxx +++ b/GUI/Qt/Windows/MainImageWindow.cxx @@ -1260,43 +1260,52 @@ void MainImageWindow::dragEnterEvent(QDragEnterEvent *event) void MainImageWindow::LoadDroppedFile(QString file) { - std::string filename = to_utf8(file); - // Check if the dropped file is a project - if(m_Model->GetDriver()->IsProjectFile(filename.c_str())) - { - // For the time being, the feature of opening the workspace in a new - // window is not implemented. Instead, we just prompt the user for - // unsaved changes. - if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model)) - return; - - // Load the project - LoadProject(file); - } - - else + try { - if(m_Model->GetDriver()->IsMainImageLoaded()) + std::string filename = to_utf8(file); + // Check if the dropped file is a project + if(m_Model->GetDriver()->IsProjectFile(filename.c_str())) { - // check if it's a label description file - if (m_Model->GetDriver()->GetColorLabelTable()->ValidateFile(filename.c_str())) - { - m_Model->GetDriver()->LoadLabelDescriptions(filename.c_str()); + // For the time being, the feature of opening the workspace in a new + // window is not implemented. Instead, we just prompt the user for + // unsaved changes. + if(!SaveModifiedLayersDialog::PromptForUnsavedChanges(m_Model)) return; - } - - // If an image is already loaded, we show the dialog - m_DropDialog->SetDroppedFilename(file); - m_DropDialog->setModal(true); - RaiseDialog(m_DropDialog); + // Load the project + LoadProject(file); } + else { - // Otherwise, load the main image directly - m_DropDialog->InitialLoad(file); + if(m_Model->GetDriver()->IsMainImageLoaded()) + { + // check if it's a label description file + if (m_Model->GetDriver()->GetColorLabelTable()->ValidateFile(filename.c_str())) + { + m_Model->GetDriver()->LoadLabelDescriptions(filename.c_str()); + return; + } + + // If an image is already loaded, we show the dialog + m_DropDialog->SetDroppedFilename(file); + m_DropDialog->setModal(true); + + RaiseDialog(m_DropDialog); + } + else + { + // Otherwise, load the main image directly + m_DropDialog->InitialLoad(file); + } } } + catch (exception &exc) // for minor exceptions, no need to crash the entire program + { + ReportNonLethalException(this, exc, "File Dropping Error", + QString("Failed to load file %1").arg(file)); + } + } #ifdef __APPLE__ diff --git a/Logic/Mesh/GuidedMeshIO.cxx b/Logic/Mesh/GuidedMeshIO.cxx index d365cebc..02413090 100644 --- a/Logic/Mesh/GuidedMeshIO.cxx +++ b/Logic/Mesh/GuidedMeshIO.cxx @@ -51,6 +51,9 @@ GuidedMeshIO::FileFormat GuidedMeshIO:: GetFormatByExtension(std::string extension) { + if (extension.empty()) // possible when reading dicom series + return FileFormat::FORMAT_COUNT; + // All format string in the map include '.' prefix if (extension.at(0) != '.') extension.insert(0, 1, '.'); @@ -187,9 +190,18 @@ bool GuidedMeshIO ::IsFilePolyData(const char *filename) { - auto reader = vtkNew(); - reader->SetFileName(filename); - return reader->IsFilePolyData(); + auto fmt = GetFormatByFilename(filename); + if (fmt == FORMAT_COUNT) + return false; + + AbstractMeshIODelegate *ioDelegate = AbstractMeshIODelegate::GetDelegate(fmt); + + if (!ioDelegate) + return false; + + bool ret = ioDelegate->IsFilePolyData(filename); + delete ioDelegate; + return ret; } GuidedMeshIO::FileFormat diff --git a/Logic/Mesh/MeshIODelegates.cxx b/Logic/Mesh/MeshIODelegates.cxx index 4d495845..339166e1 100644 --- a/Logic/Mesh/MeshIODelegates.cxx +++ b/Logic/Mesh/MeshIODelegates.cxx @@ -24,11 +24,28 @@ VTKMeshIODelegate::ReadPolyData(const char *filename) return polyData; } +bool +VTKMeshIODelegate::IsFilePolyData(const char *filename) +{ + // VTK file format support 5 different types of data + // So we need to use the reader to check whether the underlying data is polydata or not + vtkNew reader; + reader->SetFileName(filename); + return reader->IsFilePolyData(); +} + + VTPMeshIODelegate::VTPMeshIODelegate() { } +bool +VTPMeshIODelegate::IsFilePolyData(const char *) +{ + return true; // VTP file format is always polydata +} + vtkSmartPointer VTPMeshIODelegate::ReadPolyData(const char *filename) { diff --git a/Logic/Mesh/MeshIODelegates.h b/Logic/Mesh/MeshIODelegates.h index b7a6f380..c4625291 100644 --- a/Logic/Mesh/MeshIODelegates.h +++ b/Logic/Mesh/MeshIODelegates.h @@ -18,6 +18,8 @@ class AbstractMeshIODelegate static void GetDelegate(GuidedMeshIO::FileFormat fmt, AbstractMeshIODelegate *delegate); + virtual bool IsFilePolyData(const char *filename) = 0; + }; @@ -28,6 +30,8 @@ class VTKMeshIODelegate : public AbstractMeshIODelegate ~VTKMeshIODelegate() = default; vtkSmartPointer ReadPolyData(const char *filename) override; + + bool IsFilePolyData(const char *filename) override; }; class VTPMeshIODelegate : public AbstractMeshIODelegate @@ -37,6 +41,8 @@ class VTPMeshIODelegate : public AbstractMeshIODelegate virtual ~VTPMeshIODelegate() = default; vtkSmartPointer ReadPolyData(const char *filename) override; + + bool IsFilePolyData(const char *filename) override; }; #endif // MESHIODELEGATES_H