def test_PlusModelCatalogBrowser1(self): self.delayDisplay("Starting the test") logic = PlusModelCatalogBrowserLogic() logic.showBrowser() logic.handleClick(qt.QUrl('http://perk-software.cs.queensu.ca/plus/doc/nightly/modelcatalog/')) logic.handleClick(qt.QUrl('http://perk-software.cs.queensu.ca/plus/doc/nightly/modelcatalog/printable/CauteryGrabber.STL')) logic.hideBrowser() self.assertIsNotNone( slicer.util.getNode('CauteryGrabber') ) self.delayDisplay('Test passed!')
def onURLReceived(self, urlString): """Process DICOM view requests. Example: slicer://viewer/?studyUID=2.16.840.1.113669.632.20.121711.10000158860 &access_token=k0zR6WAPpNbVguQ8gGUHp6 &dicomweb_endpoint=http%3A%2F%2Fdemo.kheops.online%2Fapi &dicomweb_uri_endpoint=%20http%3A%2F%2Fdemo.kheops.online%2Fapi%2Fwado """ url = qt.QUrl(urlString) if (url.authority().lower() != "viewer"): return query = qt.QUrlQuery(url) queryMap = {} for key, value in query.queryItems(qt.QUrl.FullyDecoded): queryMap[key] = qt.QUrl.fromPercentEncoding(value) if not "dicomweb_endpoint" in queryMap: logging.error("Missing dicomweb_endpoint") return if not "studyUID" in queryMap: logging.error("Missing studyUID") return accessToken = None if "access_token" in queryMap: accessToken = queryMap["access_token"] slicer.util.selectModule("DICOM") slicer.app.processEvents() from DICOMLib import DICOMUtils DICOMUtils.importFromDICOMWeb( dicomWebEndpoint=queryMap["dicomweb_endpoint"], studyInstanceUID=queryMap["studyUID"], accessToken=accessToken)
def printReport(self, currentValuesDict, callback): """ Generate a html report file and print it :param currentValuesDict: dictionary of GUI values """ if not self.isCurrentReportSaved: # Save the report first self.saveReport(currentValuesDict) # Generate the snapshots of the images self.__printSnapshots__() self.callback = callback # Generate the html code html = self.__generateHtml__(currentValuesDict) # Write the html to a temp file p = os.path.join(self.getCurrentDataFolder(), "report.html") with open(p, "w+b") as f: f.write(html) self.webView = qt.QWebView() self.webView.settings().setAttribute( qt.QWebSettings.DeveloperExtrasEnabled, True) self.webView.connect('loadFinished(bool)', self.__webViewFormLoadedCallback__) self.webView.show() u = qt.QUrl(p) self.webView.setUrl(u)
def notifyChanged(self): elem = find_dita_class(traverse_to_element(self.__plugin()), \ "topic/link", "topic/xref", "map/topicref") if not elem: return 1 attr = elem.attrs().getAttribute("href") if attr.isNull() or attr.value().isEmpty(): return 1 path = unicode(attr.value()) pos = path.find('#') idref = "" if pos >= 0: idref = path[pos+1:] path = path[0:pos] if not path: return self.goLocal(elem, idref) sysurl = qt.QUrl(self.__sysid) if qt.QUrl.isRelativeUrl(path): tpath = qt.QUrl(sysurl) tpath.setFileName("") tpath.addPath(path) path = unicode(tpath.toString()) if sysurl == qt.QUrl(path): return self.goLocal(elem, idref) format = elem.attrs().getAttribute("format") if format.isNull() or format.value().isEmpty(): format = u"" else: format = unicode(format.value()) if format in (u"xml", u"dita", u"ditamap") or path.endswith(u".xml") or \ path.endswith(u".dita") or path.endswith(u".ditamap"): self.openDocument(path) return 0 if format is None or 0 == len(format): path = unicode(qt.QUrl(path).path()) # Get path extension pos = path.rfind('.') if pos >= 0: format = path[pos+1:] ptn = PropertyNode("browser-params") ptn.makeDescendant("url").setString(norm_slashes(path)) ptn.makeDescendant("extension").setString(unicode(format)) rv = self.__plugin().executeCommandEvent("LaunchBrowser", ptn) return 0
def onSwitchToSegmentEditor(self, link): if link == '#SwitchToSegmentEditor': slicer.util.selectModule('SegmentEditor') editorWidget = slicer.modules.segmenteditor.widgetRepresentation().self() if editorWidget is not None and self.helper is not None: masterNode = self.helper.masterSelector.currentNode() editorWidget.parameterSetNode.SetAndObserveMasterVolumeNode(masterNode) elif link == '#Feedback': qt.QDesktopServices.openUrl(qt.QUrl('http://massmail.spl.harvard.edu/mailman/listinfo/slicer-users'))
def webViewFormTest(self): """Just as a demo, load a google search in a web view and use the qt api to fill in a search term""" self.webView = qt.QWebView() self.webView.settings().setAttribute( qt.QWebSettings.DeveloperExtrasEnabled, True) self.webView.connect('loadFinished(bool)', self.webViewFormLoadedCallback) self.webView.show() u = qt.QUrl('https://www.google.com') self.webView.setUrl(u)
def printPdf( self, htmlTemplatePath, values, callbackFunction, pdfOutputPath=None, imagesFileList=None, tempHtmlFolder=None, ): """ Print a pdf file with the html stored in htmlPath and the specified values :param htmlTemplatePath: path to the html file that contains the template :param values: dictionary of values that will be used to build the final html :param callbackFunction: function that will be called when the process has finished (it is an asynchronous process) :param pdfOutputPath: path to the pdf file that will be created (if none, it will be saved in a temp file) :param imagesFileList: list of full paths to images that may be needed to generate the report :param tempHtmlFolder: folder where all the intermediate files will be stored. If none, a temporary folder will be used """ if tempHtmlFolder is None: tempHtmlFolder = tempfile.mkdtemp() self.__pdfOutputPath__ = pdfOutputPath if pdfOutputPath is not None else os.path.join( tempHtmlFolder, "report.pdf") self.__callbackFunction__ = callbackFunction self.webView = qt.QWebView() self.webView.settings().setAttribute( qt.QWebSettings.DeveloperExtrasEnabled, True) self.webView.connect('loadFinished(bool)', self.__webViewFormLoadedCallback__) self.webView.show() # Generate the Html with open(htmlTemplatePath, "r+b") as f: html = f.read() for key, value in values.iteritems(): html = html.replace(key, value) # Save the file in the temporary folder htmlPath = os.path.join(tempHtmlFolder, "temp__.html") with open(htmlPath, "w") as f: f.write(html) logging.debug("Html generated in {}".format(htmlPath)) # If we need images, copy them to the temporary folder if imagesFileList: for im in imagesFileList: fileName = os.path.basename(im) shutil.copy(im, os.path.join(tempHtmlFolder, fileName)) # Assign the html file to the viewer u = qt.QUrl(htmlPath) self.webView.setUrl(u)
def __init__(self, files, address, protocol=None, progressCallback=None): """protocol: can be DIMSE (default) or DICOMweb port: optional (if not specified then address URL should contain it) """ super().__init__() self.files = files self.destinationUrl = qt.QUrl().fromUserInput(address) self.protocol = protocol if protocol is not None else "DIMSE" self.progressCallback = progressCallback if not self.progressCallback: self.progressCallback = self.defaultProgressCallback self.send()
def __init__(self): self.catalogMainUrl = qt.QUrl('http://perk-software.cs.queensu.ca/plus/doc/nightly/modelcatalog/') self.catalogName = 'Plus toolkit 3D model catalog' self.browser = qt.QWebView() # Change QWebView such that link clicks are not automatically acted on # When links are clicked, run the handleClick() function self.browser.page().setLinkDelegationPolicy(qt.QWebPage.DelegateAllLinks) self.browser.linkClicked.connect(self.handleClick) self.downloadProgressBar = qt.QProgressDialog() self.downloadProgressBar.setLabelText('Downloading File')
def onURLReceived(self, urlString): """Process DICOM view requests. Example: slicer://viewer/?studyUID=2.16.840.1.113669.632.20.121711.10000158860 &access_token=k0zR6WAPpNbVguQ8gGUHp6 &dicomweb_endpoint=http%3A%2F%2Fdemo.kheops.online%2Fapi &dicomweb_uri_endpoint=%20http%3A%2F%2Fdemo.kheops.online%2Fapi%2Fwado """ url = qt.QUrl(urlString) if (url.authority().lower() != "viewer"): logging.debug("DICOM module ignores non-viewer URL: " + urlString) return query = qt.QUrlQuery(url) queryMap = {} for key, value in query.queryItems(qt.QUrl.FullyDecoded): queryMap[key] = qt.QUrl.fromPercentEncoding(value) if "dicomweb_endpoint" not in queryMap: logging.debug( "DICOM module ignores URL without dicomweb_endpoint query parameter: " + urlString) return if "studyUID" not in queryMap: logging.debug( "DICOM module ignores URL without studyUID query parameter: " + urlString) return logging.info("DICOM module received URL: " + urlString) accessToken = None if "access_token" in queryMap: accessToken = queryMap["access_token"] slicer.util.selectModule("DICOM") slicer.app.processEvents() from DICOMLib import DICOMUtils importedSeriesInstanceUIDs = DICOMUtils.importFromDICOMWeb( dicomWebEndpoint=queryMap["dicomweb_endpoint"], studyInstanceUID=queryMap["studyUID"], accessToken=accessToken) # Select newly loaded items to make it easier to load them self.browserWidget.dicomBrowser.setSelectedItems( ctk.ctkDICOMModel.SeriesType, importedSeriesInstanceUIDs)
def onShowRegistrationParametersDatabaseFolder(self): qt.QDesktopServices().openUrl(qt.QUrl("file:///" + self.logic.registrationParameterFilesDir, qt.QUrl.TolerantMode));
def onShowTemporaryFilesFolder(self): qt.QDesktopServices().openUrl(qt.QUrl("file:///" + self.logic.getTempDirectoryBase(), qt.QUrl.TolerantMode));
def openLocalConnection(self): qt.QDesktopServices.openUrl( qt.QUrl(f'http://localhost:{self.logic.port}'))
def test_WebEngine1(self): """ Testing WebEngine """ self.delayDisplay("Starting the test") webWidget = slicer.qSlicerWebWidget() webWidget.size = qt.QSize(1024, 512) webWidget.webView().url = qt.QUrl("") webWidget.show() self.delayDisplay('Showing widget') webWidget.evalJS(""" const paragraph = document.createElement('p'); paragraph.innerText = 'Hello from Slicer!'; document.body.appendChild(paragraph); """) self.delayDisplay('Slicer should be saying hello!') # # Test javascript evaluation + use of "evalResult()" signal # webWidget.connect("evalResult(QString,QString)", self.onEvalResult) self.delayDisplay('Slicer setting a javascript value') webWidget.evalJS("const valueFromSlicer = 42;") webWidget.evalJS("valueFromSlicer;") iteration = 0 while not self.gotResponse and iteration < 3: # Specify an explicit delay to ensure async execution by the # webengine has completed. self.delayDisplay('Waiting for response...', msec=500) iteration += 1 webWidget.disconnect("evalResult(QString,QString)", self.onEvalResult) if not self.gotResponse: raise RuntimeError("Never got response from evalJS") if not self.gotCorrectResponse: raise AssertionError("Did not get back expected result!") # # Test python evaluation from javascript # self.delayDisplay('Call a python method') slicer.app.settings().setValue("WebEngine/AllowPythonExecution", ctk.ctkMessageBox.AcceptRole) webWidget.evalJS(r""" let pythonCode = "dialog = qt.QInputDialog(slicer.util.mainWindow())\n"; pythonCode += "dialog.setLabelText('hello')\n"; pythonCode += "dialog.open()\n"; pythonCode += "qt.QTimer.singleShot(1000, dialog.close)\n"; window.slicerPython.evalPython(pythonCode); """) self.delayDisplay('Test access to python via js', msec=500) if hasattr(slicer.modules, 'slicerPythonValueFromJS'): del slicer.modules.slicerPythonValueFromJS webWidget.evalJS(""" window.slicerPython.evalPython("slicer.modules.slicerPythonValueFromJS = 42"); """) iteration = 0 while iteration < 3 and not hasattr(slicer.modules, 'slicerPythonValueFromJS'): # Specify an explicit delay to ensure async execution by the # webengine has completed. self.delayDisplay('Waiting for python value from JS...', msec=500) iteration += 1 if iteration >= 3: raise RuntimeError("Couldn't get python value back from JS") self.delayDisplay('Value of %d received via javascipt' % slicer.modules.slicerPythonValueFromJS) del slicer.modules.slicerPythonValueFromJS self.delayDisplay('Test passed!')
def onEditSource(self): filePath = slicer.util.modulePath(self.moduleName) qt.QDesktopServices.openUrl( qt.QUrl("file:///" + filePath, qt.QUrl.TolerantMode))
def send(self): self.progressCallback("Starting send to %s using self.protocol" % self.destinationUrl.toString()) if self.protocol == "DICOMweb": # DICOMweb # Ensure that correct version of dicomweb-client Python package is installed needRestart = False needInstall = False minimumDicomwebClientVersion = "0.51" try: import dicomweb_client from packaging import version if version.parse(dicomweb_client.__version__) < version.parse( minimumDicomwebClientVersion): if not slicer.util.confirmOkCancelDisplay( f"DICOMweb sending requires installation of dicomweb-client (version {minimumDicomwebClientVersion} or later).\nClick OK to upgrade dicomweb-client and restart the application." ): self.showBrowserOnEnter = False return needRestart = True needInstall = True except ModuleNotFoundError: needInstall = True if needInstall: # pythonweb-client 0.50 was broken (https://github.com/MGHComputationalPathology/dicomweb-client/issues/41) progressDialog = slicer.util.createProgressDialog( labelText= 'Upgrading dicomweb-client. This may take a minute...', maximum=0) slicer.app.processEvents() slicer.util.pip_install( f'dicomweb-client>={minimumDicomwebClientVersion}') import dicomweb_client progressDialog.close() if needRestart: slicer.util.restart() # Establish connection import dicomweb_client.log dicomweb_client.log.configure_logging(2) from dicomweb_client.api import DICOMwebClient effectiveServerUrl = self.destinationUrl.toString() session = None headers = {} # Setting up of the DICOMweb client from various server parameters can be done # in plugins in the future, but for now just hardcode special initialization # steps for a few server types. if "kheops" in effectiveServerUrl: # Kheops DICOMweb API endpoint from browser view URL url = qt.QUrl(effectiveServerUrl) if url.path().startswith('/view/'): # This is a Kheops viewer URL. # Retrieve the token from the viewer URL and use the Kheops API URL to connect to the server. token = url.path().replace('/view/', '') effectiveServerUrl = "https://demo.kheops.online/api" from requests.auth import HTTPBasicAuth from dicomweb_client.session_utils import create_session_from_auth auth = HTTPBasicAuth('token', token) session = create_session_from_auth(auth) client = DICOMwebClient(url=effectiveServerUrl, session=session, headers=headers) for file in self.files: if not self.progressCallback( f"Sending {file} to {self.destinationUrl.toString()} using {self.protocol}" ): raise UserWarning( "Sending was cancelled, upload is incomplete.") import pydicom dataset = pydicom.dcmread(file) client.store_instances(datasets=[dataset]) else: # DIMSE (traditional DICOM networking) for file in self.files: self.start(file) if not self.progressCallback( f"Sent {file} to {self.destinationUrl.host()}:{self.destinationUrl.port()}" ): raise UserWarning( "Sending was cancelled, upload is incomplete.")
def onShowCreatedOutputFile(self): if not self.createdOutputFile: return qt.QDesktopServices().openUrl( qt.QUrl("file:///" + self.createdOutputFile, qt.QUrl.TolerantMode))
def openURL(self, URL): qt.QDesktopServices().openUrl(qt.QUrl(URL)) QDesktopServices
def printPdf( self, htmlTemplatePath, values, callbackFunction, pdfOutputPath=None, imagesFileList=None, tempHtmlFolder=None, ): """ Print a pdf file with the html stored in htmlPath and the specified values :param htmlTemplatePath: path to the html file that contains the template :param values: dictionary of values that will be used to build the final html :param callbackFunction: function that will be called when the process has finished (it is an asynchronous process) :param pdfOutputPath: path to the pdf file that will be created (if none, it will be saved in a temp file) :param imagesFileList: list of full paths to images that may be needed to generate the report :param tempHtmlFolder: folder where all the intermediate files will be stored. If none, a temporary folder will be used """ if tempHtmlFolder is None: tempHtmlFolder = tempfile.mkdtemp() self.__pdfOutputPath__ = pdfOutputPath if pdfOutputPath is not None else os.path.join( tempHtmlFolder, "report.pdf") self.__callbackFunction__ = callbackFunction # Generate the Html with open(htmlTemplatePath, "r") as f: html = f.read() for key, value in values.items(): html = html.replace(key, value) # If we need images, copy them to the temporary folder if imagesFileList: for im in imagesFileList: fileName = os.path.basename(im) shutil.copy(im, os.path.join(tempHtmlFolder, fileName)) if hasattr(qt, 'QWebView'): # Save the file in the temporary folder htmlPath = os.path.join(tempHtmlFolder, "temp__.html") with open(htmlPath, "w") as f: f.write(html) logging.debug("Html generated in {}".format(htmlPath)) # Create a web browser for rendering html self.webView = qt.QWebView() self.webView.settings().setAttribute( qt.QWebSettings.DeveloperExtrasEnabled, True) self.webView.connect('loadFinished(bool)', self.__webViewFormLoadedCallback__) u = qt.QUrl(htmlPath) self.webView.setUrl(u) self.webView.show() else: printer = qt.QPrinter(qt.QPrinter.PrinterResolution) printer.setOutputFormat(qt.QPrinter.PdfFormat) printer.setPaperSize(qt.QPrinter.A4) printer.setOutputFileName(self.__pdfOutputPath__) doc = qt.QTextDocument() doc.setHtml(html) doc.baseUrl = qt.QUrl.fromLocalFile(tempHtmlFolder + "/") doc.setPageSize(qt.QSizeF( printer.pageRect().size())) # hide the page number doc.print(printer) # Call the callback self.__callbackFunction__(self.__pdfOutputPath__) self.__callbackFunction__ = None
def onHelpBrowserPressed(self): qt.QDesktopServices.openUrl(qt.QUrl("https://fastslice.github.io/"))