diff --git a/Modules/Scripted/SampleData/SampleData.py b/Modules/Scripted/SampleData/SampleData.py index 9d18ed77980..6a5d20c21c0 100644 --- a/Modules/Scripted/SampleData/SampleData.py +++ b/Modules/Scripted/SampleData/SampleData.py @@ -269,6 +269,27 @@ def setup(self): if self.developerMode is False: self.setCategoryVisible(self.logic.developmentCategoryName, False) + customFrame = ctk.ctkCollapsibleGroupBox() + self.categoryLayout.addWidget(customFrame) + customFrame.title = _("Custom data download") + customFrameLayout = qt.QHBoxLayout() + customFrame.setLayout(customFrameLayout) + self.customSampleLabel = qt.QLabel(_("URL:")) + customFrameLayout.addWidget(self.customSampleLabel) + self.customSampleName = qt.QLineEdit() + customFrameLayout.addWidget(self.customSampleName) + self.customDownloadButton = qt.QPushButton(_("Load")) + self.customDownloadButton.toolTip = _("Download the dataset from the given URL and import it into the scene") + self.customDownloadButton.default = True + customFrameLayout.addWidget(self.customDownloadButton) + self.showCustomDataFolderButton = qt.QPushButton(_("Show folder")) + self.showCustomDataFolderButton.toolTip = _("Show folder where custom data sets are downloaded ({path}).").format(path=slicer.app.cachePath) + customFrameLayout.addWidget(self.showCustomDataFolderButton) + customFrame.collapsed = True + self.customSampleName.connect("returnPressed()", self.onCustomDataDownload) + self.customDownloadButton.connect("clicked()", self.onCustomDataDownload) + self.showCustomDataFolderButton.connect("clicked()", self.onShowCustomDataFolder) + self.log = qt.QTextEdit() self.log.readOnly = True self.layout.addWidget(self.log) @@ -279,6 +300,12 @@ def setup(self): def cleanup(self): SampleDataWidget.setCategoriesFromSampleDataSources(self.categoryLayout, {}, self.logic) + def onCustomDataDownload(self): + self.logic.downloadFromURL(self.customSampleName.text) + + def onShowCustomDataFolder(self): + qt.QDesktopServices.openUrl(qt.QUrl("file:///" + slicer.app.cachePath, qt.QUrl.TolerantMode)) + @staticmethod def removeCategories(categoryLayout): """Remove all categories from the given category layout.""" @@ -676,6 +703,17 @@ def downloadFromSource(self, source, maximumAttemptsCount=3): for uri, fileName, nodeName, checksum, loadFile, loadFileType in zip( source.uris, source.fileNames, source.nodeNames, source.checksums, source.loadFiles, source.loadFileTypes): + if nodeName is None or fileName is None: + import urllib + import uuid + p = urllib.parse.urlparse(uri) + basename, ext = os.path.splitext(os.path.basename(p.path)) + if nodeName is None: + nodeName = basename + if fileName is None: + # Generate a unique filename to avoid overwriting existing file with the same name + fileName = f"{nodeName}-{uuid.uuid4().hex}{ext}" + current_source = SampleDataSource( uris=uri, fileNames=fileName,