From 699c7c85f4cebb2bdeca7125d8d0373bae67dac2 Mon Sep 17 00:00:00 2001 From: Andras Lasso Date: Thu, 9 Jan 2025 21:30:59 -0500 Subject: [PATCH] ENH: Add option to download sample data from custom URL This commit adds "Custom data download" section to the bottom of Sample Data module. It makes it easier to download data sets when following tutorials: the user does not have to use the web browser, find the downloaded file, or drag the file to the application window, just copy-paste the download URL into the inputbox and hit Enter. --- Modules/Scripted/SampleData/SampleData.py | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) 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,