def __init__(self, iface): """ Constructor """ QDockWidget.__init__(self, iface.mainWindow()) self.setupUi(self) self.iface = iface self.tools = QgsWpsTools(self.iface) self.dataStream = None # Used for streaming self.setWindowTitle('QGIS WPS-Client ' + version()) self.defaultServers = { 'Kappasys WPS': 'https://kappasys.ch/cgi-bin/pywps.cgi', '52 North': 'http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService' } flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags self.dlg = QgsWpsGui(self.iface.mainWindow(), flags) self.dlg.getDescription.connect(self.getDescription) self.dlg.newServer.connect(self.newServer) self.dlg.editServer.connect(self.editServer) self.dlg.deleteServer.connect(self.deleteServer) self.dlg.pushDefaultServer.clicked.connect(self.pushDefaultServer) self.dlg.requestDescribeProcess.connect(self.requestDescribeProcess) # self.dlg.bookmarksChanged.connect()"), self, SIGNAL("bookmarksChanged()")) self.killed.connect(self.stopStreaming)
def __init__(self, iface): """ Constructor """ QDockWidget.__init__(self, iface.mainWindow()) self.setupUi(self) self.iface = iface self.tools = QgsWpsTools(self.iface) self.dataStream = None # Used for streaming self.setWindowTitle("QgsWPSClient-Plugin " + version()) self.defaultServers = { "Kappasys WPS": "http://www.kappasys.ch/pywps/pywps.cgi", "geodati.fmach.it": "http://geodati.fmach.it/zoo/", "zoo project": "http://zoo-project.org/wps-foss4g2011/zoo_loader.cgi", "zoo project grass": "http://zoo-project.org/cgi-grass/zoo_loader.cgi", "52 North": "http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService", } flags = ( Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint ) # QgisGui.ModalDialogFlags self.dlg = QgsWpsGui(self.iface.mainWindow(), flags) self.dlg.getDescription.connect(self.getDescription) self.dlg.newServer.connect(self.newServer) self.dlg.editServer.connect(self.editServer) self.dlg.deleteServer.connect(self.deleteServer) self.dlg.pushDefaultServer.clicked.connect(self.pushDefaultServer) self.dlg.requestDescribeProcess.connect(self.requestDescribeProcess) # self.dlg.bookmarksChanged.connect()"), self, SIGNAL("bookmarksChanged()")) self.killed.connect(self.stopStreaming)
def initGui(self): # Create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/wps/images/wps-add.png"), "WPS Client", self.iface.mainWindow()) QObject.connect(self.action, SIGNAL("triggered()"), self.run) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("WPS", self.action) self.doc = QtXml.QDomDocument() self.tmpPath = QDir.tempPath() self.tools = QgsWpsTools(self.iface)
def __init__(self, iface): """ Constructor """ QDockWidget.__init__(self, iface.mainWindow()) self.setupUi(self) self.iface = iface self.tools = QgsWpsTools(self.iface) self.doc = QtXml.QDomDocument() self.tmpPath = QDir.tempPath() self.uploadFinished = False self.status = '' self.btnKill.setEnabled(False) self.btnConnect.setEnabled(True) self.dataStream = None # Used for streaming self.setWindowTitle('QGIS WPS-Client '+version()) self.defaultServers = {'Kappasys WPS':'http://www.kappasys.ch/pywps/pywps.cgi', 'geodati.fmach.it':'http://geodati.fmach.it/zoo/', 'zoo project':'http://zoo-project.org/wps-foss4g2011/zoo_loader.cgi', 'zoo project grass':'http://zoo-project.org/cgi-grass/zoo_loader.cgi', '52 North':'http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService' } flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags self.dlg = QgsWpsGui(self.iface.mainWindow(), flags) self.dlg.getDescription.connect( self.getDescription ) self.dlg.newServer.connect( self.newServer ) self.dlg.editServer.connect( self.editServer ) self.dlg.deleteServer.connect( self.deleteServer ) self.dlg.connectServer.connect( self.cleanGui ) self.dlg.addDefaultServer.connect( self.addDefaultServer ) self.dlg.requestDescribeProcess.connect( self.requestDescribeProcess ) QObject.connect(self.dlg, SIGNAL("bookmarksChanged()"), self, SIGNAL("bookmarksChanged()")) self.killed.connect(self.stopStreaming)
class QgsWpsDockWidget(QDockWidget, Ui_QgsWpsDockWidget): """ Class documentation goes here. """ killed = pyqtSignal() bookmarksChanged = pyqtSignal() def __init__(self, iface): """ Constructor """ QDockWidget.__init__(self, iface.mainWindow()) self.setupUi(self) self.iface = iface self.tools = QgsWpsTools(self.iface) self.dataStream = None # Used for streaming self.setWindowTitle('QGIS WPS-Client ' + version()) self.defaultServers = { 'Kappasys WPS': 'https://kappasys.ch/cgi-bin/pywps.cgi', '52 North': 'http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService' } flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags self.dlg = QgsWpsGui(self.iface.mainWindow(), flags) self.dlg.getDescription.connect(self.getDescription) self.dlg.newServer.connect(self.newServer) self.dlg.editServer.connect(self.editServer) self.dlg.deleteServer.connect(self.deleteServer) self.dlg.pushDefaultServer.clicked.connect(self.pushDefaultServer) self.dlg.requestDescribeProcess.connect(self.requestDescribeProcess) # self.dlg.bookmarksChanged.connect()"), self, SIGNAL("bookmarksChanged()")) self.killed.connect(self.stopStreaming) def getDescription(self, name, item): self.requestDescribeProcess(name, item.text(0)) def requestDescribeProcess(self, serverName, processIdentifier): server = WpsServer.getServer(serverName) self.process = ProcessDescription(server, processIdentifier) self.process.describeProcessFinished.connect(self.createProcessGUI) self.process.requestDescribeProcess() def setStatus(self, status, done=0, total=0): complete = status == "aborted" or status == "finished" or status == "error" self.progressBar.setRange(done, total) if status == "upload" and done == total: status = "processing" done = total = 0 self.btnConnect.setEnabled(complete) self.btnKill.setEnabled(not complete) if complete: self.progressBar.setRange(0, 100) self.progressBar.setValue(100) else: self.progressBar.setRange(0, total) self.progressBar.setValue(done) if status == 'upload': text = QApplication.translate("QgsWps", " upload data ...") elif status == 'processing': text = QApplication.translate("QgsWps", " is running ...") elif status == 'download': text = QApplication.translate("QgsWps", " download data ...") elif status == 'finished': text = QApplication.translate("QgsWps", " finished successfully") elif status == 'error': text = QApplication.translate("QgsWps", " terminated with errors!") elif status == 'aborted': text = QApplication.translate("QgsWps", " was aborted!") self.statusLabel.setText(pystring(self.processIdentifier + text)) @pyqtSignature("") def on_btnConnect_clicked(self): self.dlg.initQgsWpsGui() self.statusLabel.setText("") self.progressBar.setRange(0, 100) self.progressBar.setValue(0) self.dlg.show() def createProcessGUI(self): """Create the GUI for a selected WPS process based on the DescribeProcess response document. Mandatory inputs are marked as red, default is black""" # Lists which store the inputs and meta information (format, occurs, ...) # This list is initialized every time the GUI is created self.complexInputComboBoxList = [ ] # complex input for single raster and vector maps self.complexInputListWidgetList = [ ] # complex input for multiple raster and vector maps self.complexInputTextBoxList = [] # complex inpt of type text/plain self.literalInputComboBoxList = [ ] # literal value list with selectable answers self.literalInputLineEditList = [ ] # literal value list with single text line input self.bboxInputLineEditList = [ ] # bbox value list with single text line input self.complexOutputComboBoxList = [] # list combo box self.inputDataTypeList = {} self.outputDataTypeList = {} flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags self.processUrl = self.process.processUrl self.processIdentifier = self.process.processIdentifier self.processName = self.process.processName # Create the layouts and the scroll area self.dlgProcess = QgsWpsDescribeProcessGui(self.dlg, flags) self.dlgProcessLayout = QGridLayout() # Two tabs, one for the process inputs and one for the documentation # TODO: add a tab for literal outputs self.dlgProcessTab = QTabWidget() self.dlgProcessTabFrame = QFrame() self.dlgProcessTabFrameLayout = QGridLayout() # The process description can be very long, so we make it scrollable self.dlgProcessScrollArea = QScrollArea(self.dlgProcessTab) self.dlgProcessScrollAreaWidget = QFrame() self.dlgProcessScrollAreaWidgetLayout = QGridLayout() # First part of the gui is a short overview about the process self.identifier = self.process.identifier title = self.process.title abstract = self.process.abstract self.addIntroduction(self.identifier, title) # If no Input Data are requested if len(self.process.inputs) == 0: self.defineProcess() return 0 # Generate the input GUI buttons and widgets res = self.generateProcessInputsGUI() if res == 0: return 0 # Generate the editable outpt widgets, you can set the output to none if it is not requested self.generateProcessOutputsGUI() self.dlgProcessScrollAreaWidgetLayout.setSpacing(10) self.dlgProcessScrollAreaWidget.setLayout( self.dlgProcessScrollAreaWidgetLayout) self.dlgProcessScrollArea.setWidget(self.dlgProcessScrollAreaWidget) self.dlgProcessScrollArea.setWidgetResizable(True) self.dlgProcessTabFrameLayout.addWidget(self.dlgProcessScrollArea) self.addOkCancelButtons(self.dlgProcess, self.dlgProcessTabFrameLayout) self.dlgProcessTabFrame.setLayout(self.dlgProcessTabFrameLayout) self.dlgProcessTab.addTab(self.dlgProcessTabFrame, "Process") self.tools.addDocumentationTab(self.dlgProcessTab, abstract) self.dlgProcessLayout.addWidget(self.dlgProcessTab) self.dlgProcess.setLayout(self.dlgProcessLayout) self.dlgProcess.setGeometry(QRect(190, 100, 800, 600)) self.dlgProcess.show() def generateProcessInputsGUI(self): """Generate the GUI for all Inputs defined in the process description XML file""" for input in self.process.inputs: inputType = type(input) inputIdentifier = input.identifier title = input.title minOccurs = input.minOccurs if inputType == VectorInput or inputType == MultipleVectorInput: complexDataFormat = input.dataFormat self.inputDataTypeList[inputIdentifier] = complexDataFormat layerNamesList = self.tools.getLayerNameList(0) if inputType == VectorInput: self.complexInputComboBoxList.append( self.tools.addComplexInputComboBox( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) else: self.complexInputListWidgetList.append( self.tools.addComplexInputListWidget( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) elif inputType == StringInput: dValue = input.defaultValue self.literalInputLineEditList.append( self.tools.addLiteralLineEdit( title, inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, dValue)) elif inputType == TextInput: complexDataFormat = input.dataFormat if isMimeTypePlaylist(complexDataFormat["MimeType"]) != None: self.inputDataTypeList[inputIdentifier] = complexDataFormat # Playlist (text) inputs self.complexInputTextBoxList.append( self.tools.addComplexInputTextBox( title, inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, str(complexDataFormat))) else: self.complexInputTextBoxList.append( self.tools.addComplexInputTextBox( title, inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) elif inputType == RasterInput or inputType == MultipleRasterInput: complexDataFormat = input.dataFormat self.inputDataTypeList[inputIdentifier] = complexDataFormat layerNamesList = self.tools.getLayerNameList(1) if inputType == RasterInput: self.complexInputComboBoxList.append( self.tools.addComplexInputComboBox( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) else: self.complexInputListWidgetList.append( self.tools.addComplexInputListWidget( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) elif inputType == SelectionInput: valList = input.valList self.literalInputComboBoxList.append( self.tools.addLiteralComboBox( title, inputIdentifier, valList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) elif inputType == ExtentInput: myExtent = pystring(self.iface.mapCanvas().extent()).replace( ':', ',') self.bboxInputLineEditList.append( self.tools.addLiteralLineEdit( title + "(minx,miny,maxx,maxy)", inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, myExtent)) elif inputType == CrsInput: crsListe = input.crsList # self.literalInputComboBoxList.append(self.tools.addLiteralComboBox("Supported CRS", inputIdentifier, crsListe, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) self.tools.addCheckBox( QCoreApplication.translate("QgsWps", "Process selected objects only"), QCoreApplication.translate("QgsWps", "Selected"), self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout) ############################################################################## def generateProcessOutputsGUI(self): """Generate the GUI for all complex ouputs defined in the process description XML file""" if len(self.process.outputs) < 1: return groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) groupbox.setTitle("Complex output(s)") layout = QVBoxLayout() for output in self.process.outputs: outputType = type(output) outputIdentifier = output.identifier title = output.title if outputType == VectorOutput or outputType == RasterOutput: complexOutputFormat = output.dataFormat # Store the input formats self.outputDataTypeList[outputIdentifier] = complexOutputFormat widget, comboBox = self.tools.addComplexOutputComboBox( groupbox, outputIdentifier, title, str(complexOutputFormat), self.processIdentifier) self.complexOutputComboBoxList.append(comboBox) layout.addWidget(widget) # Set the layout groupbox.setLayout(layout) # Add the outputs self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## def addIntroduction(self, name, title): groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) groupbox.setTitle(name) layout = QVBoxLayout() myLabel = QLabel(groupbox) myLabel.setObjectName("qLabel" + name) myLabel.setText(pystring(title)) myLabel.setMinimumWidth(600) myLabel.setMinimumHeight(25) myLabel.setWordWrap(True) layout.addWidget(myLabel) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## ############################################################################## def defineProcess(self): """Create the execute request""" self.dlgProcess.close() self.dlg.close() doc = QtXml.QDomDocument() doc.setContent(self.process.processXML) QApplication.setOverrideCursor(Qt.WaitCursor) checkBoxes = self.dlgProcess.findChildren(QCheckBox) if len(checkBoxes) > 0: useSelected = checkBoxes[0].isChecked() request = ExecutionRequest(self.process) request.addExecuteRequestHeader() request.addDataInputsStart() if len(self.process.inputs) > 0: # text/plain inputs ######################################################## for textBox in self.complexInputTextBoxList: # Do not add undefined inputs if textBox == None or str( textBox.document().toPlainText()) == "": continue # TODO: Check for more types (e.g. KML, Shapefile, JSON) self.mimeType = self.inputDataTypeList[ textBox.objectName()]["MimeType"] if isMimeTypePlaylist(self.mimeType) != None: schema = self.inputDataTypeList[ textBox.objectName()]["Schema"] encoding = self.inputDataTypeList[ textBox.objectName()]["Encoding"] # Handle 'as reference' playlist request.addReferenceInput(textBox.objectName(), self.mimeType, schema, encoding, textBox.document().toPlainText()) else: # It's not a playlist request.addPlainTextInput(textBox.objectName(), textBox.document().toPlainText()) # Single raster and vector inputs ########################################## for comboBox in self.complexInputComboBoxList: # Do not add undefined inputs if comboBox == None or comboBox.currentText() == "<None>": continue # TODO: Check for more types (e.g. KML, Shapefile, JSON) # QMessageBox.information(None, '', str(self.inputDataTypeList[comboBox.objectName()]["MimeType"])) # QMessageBox.information(None, '', pystring(comboBox.objectName())) self.mimeType = self.inputDataTypeList[pystring( comboBox.objectName())]["MimeType"] schema = self.inputDataTypeList[pystring( comboBox.objectName())]["Schema"] encoding = self.inputDataTypeList[pystring( comboBox.objectName())]["Encoding"] self.myLayer = self.tools.getVLayer(comboBox.currentText()) # try: if isMimeTypeVector( self.mimeType) != None and encoding != "base64": gmldata = createTmpGML( self.tools.getVLayer(comboBox.currentText()), useSelected, self.process.getSupportedGMLVersion( comboBox.objectName())) request.addGeometryInput(comboBox.objectName(), self.mimeType, schema, encoding, gmldata, useSelected) elif isMimeTypeVector( self.mimeType) != None or isMimeTypeRaster( self.mimeType) != None: request.addGeometryBase64Input( comboBox.objectName(), self.mimeType, self.tools.getVLayer(comboBox.currentText())) # except: # QApplication.restoreOverrideCursor() # QMessageBox.warning(self.iface.mainWindow(), # QApplication.translate("QgsWps","Error"), # QApplication.translate("QgsWps","Please load or select a vector layer!")) # return # Multiple raster and vector inputs ######################################## for listWidgets in self.complexInputListWidgetList: # Do not add undefined inputs if listWidgets == None: continue self.mimeType = self.inputDataTypeList[ listWidgets.objectName()]["MimeType"] schema = self.inputDataTypeList[ listWidgets.objectName()]["Schema"] encoding = self.inputDataTypeList[ listWidgets.objectName()]["Encoding"] # Iterate over each seletced item for i in range(listWidgets.count()): listWidget = listWidgets.item(i) if listWidget == None or listWidget.isSelected( ) == False or str(listWidget.text()) == "<None>": continue # TODO: Check for more types if isMimeTypeVector( self.mimeType ) != None and self.mimeType == "text/xml": gmldata = createTmpGML( self.tools.getVLayer(listWidget.text()), useSelected, self.process.getSupportedGMLVersion( listWidgets.objectName())) request.addMultipleGeometryInput( listWidgets.objectName(), self.mimeType, schema, encoding, gmldata, useSelected) elif isMimeTypeVector( self.mimeType) != None or isMimeTypeRaster( self.mimeType) != None: request.addMultipleGeometryBase64Input( listWidgets.objectName(), self.mimeType, self.tools.getVLayer(listWidget.text())) # Literal data as combo box choice ######################################### for comboBox in self.literalInputComboBoxList: if comboBox == None or comboBox.currentText() == "": continue request.addLiteralDataInput(comboBox.objectName(), comboBox.currentText()) # Literal data as combo box choice ######################################### for lineEdit in self.literalInputLineEditList: if lineEdit == None or lineEdit.text() == "": continue request.addLiteralDataInput(lineEdit.objectName(), lineEdit.text()) # BBOX data as lineEdit ######################################### for bbox in self.bboxInputLineEditList: if bbox == None or bbox.text() == "": continue bboxArray = bbox.text().split(',') request.addBoundingBoxInput(bbox.objectName(), bboxArray) request.addDataInputsEnd() # Attach only defined outputs dataOutputs = doc.elementsByTagName("Output") if dataOutputs.size() > 0 or len(self.complexOutputComboBoxList) > 0: request.addResponseFormStart() # Attach ALL literal outputs ############################################# for i in range(dataOutputs.size()): f_element = dataOutputs.at(i).toElement() outputIdentifier = pystring( f_element.elementsByTagName("ows:Identifier").at( 0).toElement().text()).strip() literalOutputType = f_element.elementsByTagName( "LiteralOutput") # Complex data is always requested as reference if literalOutputType.size() != 0: request.addLiteralDataOutput(outputIdentifier) # Attach selected complex outputs ######################################## for comboBox in self.complexOutputComboBoxList: # Do not add undefined outputs if comboBox == None or str(comboBox.currentText()) == "<None>": continue outputIdentifier = comboBox.objectName() self.mimeType = self.outputDataTypeList[pystring( outputIdentifier)]["MimeType"] schema = self.outputDataTypeList[pystring( outputIdentifier)]["Schema"] encoding = self.outputDataTypeList[pystring( outputIdentifier)]["Encoding"] request.addReferenceOutput(outputIdentifier, self.mimeType, schema, encoding) request.addResponseFormEnd() request.addExecuteRequestEnd() postString = request.request # This is for debug purpose only if DEBUG == True: # self.tools.popUpMessageBox("Execute request", postString) # Write the request into a file outFile = open('/tmp/qwps_execute_request.xml', 'w') outFile.write(postString) outFile.close() QApplication.restoreOverrideCursor() self.setStatus("processing") self.wps = ExecutionResult(self.getLiteralResult, self.getResultFile, self.successResult, self.errorResult, self.streamingHandler, self.progressBar) self.wps.executeProcess(self.process.processUrl, postString) if len(self.process.inputs) > 0: self.wps.thePostReply.uploadProgress.connect( lambda done, total: self.setStatus("upload", done, total)) self.wps.fetchingResult.connect(self.fetchingResult) ############################################################################## def addOkCancelButtons(self, dlgProcess, dlgProcessTabFrameLayout): groupBox = QFrame() layout = QHBoxLayout() btnOk = QPushButton(groupBox) btnOk.setText(pystring(QApplication.translate("QgsWps", "Run"))) btnOk.setMinimumWidth(100) btnOk.setMaximumWidth(100) btnCancel = QPushButton(groupBox) btnCancel.setText(QApplication.translate("QgsWps", "Back")) btnCancel.setMinimumWidth(100) btnCancel.setMaximumWidth(100) btnBookmark = QPushButton(groupBox) btnBookmark.setText(QApplication.translate("QgsWps", "Add Bookmark")) btnBookmark.setMinimumWidth(200) btnBookmark.setMaximumWidth(200) layout.addWidget(btnBookmark) layout.addStretch(10) layout.addWidget(btnCancel) layout.addWidget(btnOk) groupBox.setLayout(layout) dlgProcessTabFrameLayout.addWidget(groupBox) btnOk.clicked.connect(self.defineProcess) btnCancel.clicked.connect(self.dlgProcess.close) btnBookmark.clicked.connect(self.saveBookmark) def saveBookmark(self): server = WpsServer.getServer(self.dlgProcess.currentServiceName()) process = ProcessDescription( server, self.processUrl.queryItemValue('identifier')) process.saveBookmark() self.bookmarksChanged.emit() QMessageBox.information( self.iface.mainWindow(), QCoreApplication.translate("QgsWps", "Bookmark"), QCoreApplication.translate( "QgsWps", "The creation bookmark was successful.")) def fetchingResult(self, noFilesToFetch): QApplication.restoreOverrideCursor() self.setStatus('finished') ############################################################################## def streamingHandler(self, encoding, playlistUrl): """ Handle response form streaming based processes """ mimeTypePlaylist, self.mimeType = self.mimeType.split("+") print playlistUrl # Get number of chunks (Only for Output streaming based WPSs) chunks = 0 if isMimeTypeVector(self.mimeType) != None: for lineEdit in self.literalInputLineEditList: if lineEdit.objectName() == "NumberOfChunks": chunks = int(lineEdit.text()) elif isMimeTypeRaster(self.mimeType) != None: chunks = 1 for lineEdit in self.literalInputLineEditList: if lineEdit.objectName( ) == "chunksByRow" or lineEdit.objectName( ) == "chunksByColumn": chunks = chunks * int(lineEdit.text()) print "No. of chunks:", chunks # Streaming handler self.dataStream = Streaming(self, self.iface, chunks, playlistUrl, self.mimeType, encoding) self.dataStream.start() def stopStreaming(self): """ SLOT Stop the timer """ if self.dataStream: self.dataStream.stop() ############################################################################## def loadData(self, resultFile): bLoaded = True # For information purposes layerName = self.tools.uniqueLayerName(self.processIdentifier + "_" + self.identifier) # The layername is normally defined in the comboBox for comboBox in self.complexOutputComboBoxList: if comboBox.objectName() == self.identifier: layerName = comboBox.currentText() # Vector data # TODO: Check for schema GML and KML if isMimeTypeVector(self.mimeType) != None: vlayer = QgsVectorLayer(resultFile, layerName, "ogr") try: vlayer.setCrs(self.myLayer.dataProvider().crs()) except: pass bLoaded = QgsMapLayerRegistry.instance().addMapLayer(vlayer) # Raster data elif isMimeTypeRaster(self.mimeType) != None: # We can directly attach the new layer rLayer = QgsRasterLayer(resultFile, layerName) bLoaded = QgsMapLayerRegistry.instance().addMapLayer(rLayer) # Text data elif isMimeTypeText(self.mimeType) != None: #TODO: this should be handled in a separate diaqgswps.pylog to save the text output as file' QApplication.restoreOverrideCursor() text = open(resultFile, 'r').read() # TODO: This should be a text dialog with safe option self.tools.popUpMessageBox( QCoreApplication.translate("QgsWps", 'Process result (text/plain)'), text) # Everything else elif isMimeTypeFile(self.mimeType) != None: #TODO: this should be handled in a separate diaqgswps.pylog to save the text output as file' QApplication.restoreOverrideCursor() text = open(resultFile, 'r').read() # TODO: This should be a text dialog with safe option fileName = QFileDialog().getSaveFileName() # Everything else else: # For unsupported mime types we assume text QApplication.restoreOverrideCursor() content = open(resultFile, 'r').read() # TODO: This should have a safe option self.tools.popUpMessageBox( QCoreApplication.translate( "QgsWps", 'Process result (unsupported mime type)'), content) if not bLoaded: QMessageBox.information( self.iface.mainWindow(), QApplication.translate("QgsWps", "Result not loaded to the map"), QApplication.translate( "QgsWps", "It seems QGIS cannot load the result of the process. The result has a '{0}' type and can be accessed at '{1}'. \n\nYou could ask the service provider to consider changing the default data type of the result." ).format(self.mimeType, resultFile)) def getLiteralResult(self, identifier, literalText): self.tools.popUpMessageBox( QCoreApplication.translate("QgsWps", 'Result'), literalText) self.setStatus('finished') def getResultFile(self, identifier, mimeType, encoding, schema, reply): # Get a unique temporary file name myQTempFile = QTemporaryFile() myQTempFile.open() ext = getFileExtension(self.mimeType) tmpFile = myQTempFile.fileName() + ext myQTempFile.close() # Write the data to the temporary file outFile = QFile(tmpFile) outFile.open(QIODevice.WriteOnly) outFile.write(reply.readAll()) reply.deleteLater() outFile.close() resultFile = self.wps.handleEncoded(tmpFile, mimeType, encoding, schema) # Finally, load the data self.loadData(resultFile) self.setStatus('finished') ############################################################################## def errorResult(self, exceptionHtml): self.setStatus('error') QMessageBox.critical(self.iface.mainWindow(), "Exception report", exceptionHtml) def successResult(self): self.setStatus('finished') ############################################################################## def deleteServer(self, name): settings = QSettings() settings.beginGroup("WPS") baseUrl = pystring(settings.value(name + "/url")) settings.remove(name) settings.endGroup() # delete related cookies url = QUrl() url.setUrl(baseUrl) serverCookie = WpsServerCookie(url) serverCookie.removeServerCookies() self.dlg.initQgsWpsGui() ############################################################################## def editServer(self, name): server = WpsServer.getServer(name) flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags dlgEdit = QgsNewHttpConnectionBaseGui(self.dlg, flags) dlgEdit.txtName.setText(name) dlgEdit.txtUrl.setText(server.baseUrl) dlgEdit.show() self.dlg.initQgsWpsGui() ############################################################################## def newServer(self): flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags dlgNew = QgsNewHttpConnectionBaseGui(self.dlg, flags) dlgNew.show() self.dlg.initQgsWpsGui() def pushDefaultServer(self): settings = QSettings() for k, v in self.defaultServers.iteritems(): myURL = urlparse(str(v)) mySettings = "/WPS/" + k # settings.setValue("WPS/connections/selected", QVariant(name) ) settings.setValue(mySettings + "/scheme", pystring(myURL.scheme)) settings.setValue(mySettings + "/server", pystring(myURL.netloc)) settings.setValue(mySettings + "/path", pystring(myURL.path)) settings.setValue(mySettings + "/method", pystring("GET")) settings.setValue(mySettings + "/version", pystring("1.0.0")) settings.setValue(mySettings + "/url", pystring(v)) self.dlg.initQgsWpsGui() @pyqtSignature("") def on_btnKill_clicked(self): self.wps.thePostReply.abort() self.wps.thePostReply.deleteLater() self.setStatus('aborted') self.killed.emit() pass
class QgsWpsDockWidget(QDockWidget, Ui_QgsWpsDockWidget): """ Class documentation goes here. """ killed = pyqtSignal() bookmarksChanged = pyqtSignal() def __init__(self, iface): """ Constructor """ QDockWidget.__init__(self, iface.mainWindow()) self.setupUi(self) self.iface = iface self.tools = QgsWpsTools(self.iface) self.dataStream = None # Used for streaming self.setWindowTitle("QgsWPSClient-Plugin " + version()) self.defaultServers = { "Kappasys WPS": "http://www.kappasys.ch/pywps/pywps.cgi", "geodati.fmach.it": "http://geodati.fmach.it/zoo/", "zoo project": "http://zoo-project.org/wps-foss4g2011/zoo_loader.cgi", "zoo project grass": "http://zoo-project.org/cgi-grass/zoo_loader.cgi", "52 North": "http://geoprocessing.demo.52north.org:8080/wps/WebProcessingService", } flags = ( Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint ) # QgisGui.ModalDialogFlags self.dlg = QgsWpsGui(self.iface.mainWindow(), flags) self.dlg.getDescription.connect(self.getDescription) self.dlg.newServer.connect(self.newServer) self.dlg.editServer.connect(self.editServer) self.dlg.deleteServer.connect(self.deleteServer) self.dlg.pushDefaultServer.clicked.connect(self.pushDefaultServer) self.dlg.requestDescribeProcess.connect(self.requestDescribeProcess) # self.dlg.bookmarksChanged.connect()"), self, SIGNAL("bookmarksChanged()")) self.killed.connect(self.stopStreaming) def getDescription(self, name, item): self.requestDescribeProcess(name, item.text(0)) def requestDescribeProcess(self, serverName, processIdentifier): server = WpsServer.getServer(serverName) self.process = ProcessDescription(server, processIdentifier) self.process.describeProcessFinished.connect(self.createProcessGUI) self.process.requestDescribeProcess() def setStatus(self, status, done=0, total=0): complete = status == "aborted" or status == "finished" or status == "error" self.progressBar.setRange(done, total) if status == "upload" and done == total: status = "processing" done = total = 0 self.btnConnect.setEnabled(complete) self.btnKill.setEnabled(not complete) if complete: self.progressBar.setRange(0, 100) self.progressBar.setValue(100) else: self.progressBar.setRange(0, total) self.progressBar.setValue(done) if status == "upload": text = QApplication.translate("QgsWps", " upload data ...") elif status == "processing": text = QApplication.translate("QgsWps", " is running ...") elif status == "download": text = QApplication.translate("QgsWps", " download data ...") elif status == "finished": text = QApplication.translate("QgsWps", " finished successfully") elif status == "error": text = QApplication.translate("QgsWps", " terminated with errors!") elif status == "aborted": text = QApplication.translate("QgsWps", " was aborted!") self.statusLabel.setText(pystring(self.processIdentifier + text)) @pyqtSignature("") def on_btnConnect_clicked(self): self.dlg.initQgsWpsGui() self.statusLabel.setText("") self.progressBar.setRange(0, 100) self.progressBar.setValue(0) self.dlg.show() def createProcessGUI(self): """Create the GUI for a selected WPS process based on the DescribeProcess response document. Mandatory inputs are marked as red, default is black""" # Lists which store the inputs and meta information (format, occurs, ...) # This list is initialized every time the GUI is created self.complexInputComboBoxList = [] # complex input for single raster and vector maps self.complexInputListWidgetList = [] # complex input for multiple raster and vector maps self.complexInputTextBoxList = [] # complex inpt of type text/plain self.literalInputComboBoxList = [] # literal value list with selectable answers self.literalInputLineEditList = [] # literal value list with single text line input self.bboxInputLineEditList = [] # bbox value list with single text line input self.complexOutputComboBoxList = [] # list combo box self.inputDataTypeList = {} self.outputDataTypeList = {} flags = ( Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint ) # QgisGui.ModalDialogFlags self.processUrl = self.process.processUrl self.processIdentifier = self.process.processIdentifier self.processName = self.process.processName # Create the layouts and the scroll area self.dlgProcess = QgsWpsDescribeProcessGui(self.dlg, flags) self.dlgProcessLayout = QGridLayout() # Two tabs, one for the process inputs and one for the documentation # TODO: add a tab for literal outputs self.dlgProcessTab = QTabWidget() self.dlgProcessTabFrame = QFrame() self.dlgProcessTabFrameLayout = QGridLayout() # The process description can be very long, so we make it scrollable self.dlgProcessScrollArea = QScrollArea(self.dlgProcessTab) self.dlgProcessScrollAreaWidget = QFrame() self.dlgProcessScrollAreaWidgetLayout = QGridLayout() # First part of the gui is a short overview about the process self.identifier = self.process.identifier title = self.process.title abstract = self.process.abstract self.addIntroduction(self.identifier, title) # If no Input Data are requested if len(self.process.inputs) == 0: self.defineProcess() return 0 # Generate the input GUI buttons and widgets res = self.generateProcessInputsGUI() if res == 0: return 0 # Generate the editable outpt widgets, you can set the output to none if it is not requested self.generateProcessOutputsGUI() self.dlgProcessScrollAreaWidgetLayout.setSpacing(10) self.dlgProcessScrollAreaWidget.setLayout(self.dlgProcessScrollAreaWidgetLayout) self.dlgProcessScrollArea.setWidget(self.dlgProcessScrollAreaWidget) self.dlgProcessScrollArea.setWidgetResizable(True) self.dlgProcessTabFrameLayout.addWidget(self.dlgProcessScrollArea) self.addOkCancelButtons(self.dlgProcess, self.dlgProcessTabFrameLayout) self.dlgProcessTabFrame.setLayout(self.dlgProcessTabFrameLayout) self.dlgProcessTab.addTab(self.dlgProcessTabFrame, "Process") self.tools.addDocumentationTab(self.dlgProcessTab, abstract) self.dlgProcessLayout.addWidget(self.dlgProcessTab) self.dlgProcess.setLayout(self.dlgProcessLayout) self.dlgProcess.setGeometry(QRect(190, 100, 800, 600)) self.dlgProcess.show() def generateProcessInputsGUI(self): """Generate the GUI for all Inputs defined in the process description XML file""" for input in self.process.inputs: inputType = type(input) inputIdentifier = input.identifier title = input.title minOccurs = input.minOccurs if inputType == VectorInput or inputType == MultipleVectorInput: complexDataFormat = input.dataFormat self.inputDataTypeList[inputIdentifier] = complexDataFormat layerNamesList = self.tools.getLayerNameList(0) if inputType == VectorInput: self.complexInputComboBoxList.append( self.tools.addComplexInputComboBox( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ) else: self.complexInputListWidgetList.append( self.tools.addComplexInputListWidget( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ) elif inputType == StringInput: dValue = input.defaultValue self.literalInputLineEditList.append( self.tools.addLiteralLineEdit( title, inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, dValue, ) ) elif inputType == TextInput: complexDataFormat = input.dataFormat if isMimeTypePlaylist(complexDataFormat["MimeType"]) != None: self.inputDataTypeList[inputIdentifier] = complexDataFormat # Playlist (text) inputs self.complexInputTextBoxList.append( self.tools.addComplexInputTextBox( title, inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, str(complexDataFormat), ) ) else: self.complexInputTextBoxList.append( self.tools.addComplexInputTextBox( title, inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ) elif inputType == RasterInput or inputType == MultipleRasterInput: complexDataFormat = input.dataFormat self.inputDataTypeList[inputIdentifier] = complexDataFormat layerNamesList = self.tools.getLayerNameList(1) if inputType == RasterInput: self.complexInputComboBoxList.append( self.tools.addComplexInputComboBox( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ) else: self.complexInputListWidgetList.append( self.tools.addComplexInputListWidget( title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ) elif inputType == SelectionInput: valList = input.valList self.literalInputComboBoxList.append( self.tools.addLiteralComboBox( title, inputIdentifier, valList, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ) elif inputType == ExtentInput: myExtent = pystring(self.iface.mapCanvas().extent()).replace(":", ",") self.bboxInputLineEditList.append( self.tools.addLiteralLineEdit( title + "(minx,miny,maxx,maxy)", inputIdentifier, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, myExtent, ) ) elif inputType == CrsInput: crsListe = input.crsList # self.literalInputComboBoxList.append(self.tools.addLiteralComboBox("Supported CRS", inputIdentifier, crsListe, minOccurs, self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout)) self.tools.addCheckBox( QCoreApplication.translate("QgsWps", "Process selected objects only"), QCoreApplication.translate("QgsWps", "Selected"), self.dlgProcessScrollAreaWidget, self.dlgProcessScrollAreaWidgetLayout, ) ############################################################################## def generateProcessOutputsGUI(self): """Generate the GUI for all complex ouputs defined in the process description XML file""" if len(self.process.outputs) < 1: return groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) groupbox.setTitle("Complex output(s)") layout = QVBoxLayout() for output in self.process.outputs: outputType = type(output) outputIdentifier = output.identifier title = output.title if outputType == VectorOutput or outputType == RasterOutput: complexOutputFormat = output.dataFormat # Store the input formats self.outputDataTypeList[outputIdentifier] = complexOutputFormat widget, comboBox = self.tools.addComplexOutputComboBox( groupbox, outputIdentifier, title, str(complexOutputFormat), self.processIdentifier ) self.complexOutputComboBoxList.append(comboBox) layout.addWidget(widget) # Set the layout groupbox.setLayout(layout) # Add the outputs self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## def addIntroduction(self, name, title): groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) groupbox.setTitle(name) layout = QVBoxLayout() myLabel = QLabel(groupbox) myLabel.setObjectName("qLabel" + name) myLabel.setText(pystring(title)) myLabel.setMinimumWidth(600) myLabel.setMinimumHeight(25) myLabel.setWordWrap(True) layout.addWidget(myLabel) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## ############################################################################## def defineProcess(self): """Create the execute request""" self.dlgProcess.close() self.dlg.close() doc = QtXml.QDomDocument() doc.setContent(self.process.processXML) QApplication.setOverrideCursor(Qt.WaitCursor) checkBoxes = self.dlgProcess.findChildren(QCheckBox) if len(checkBoxes) > 0: useSelected = checkBoxes[0].isChecked() request = ExecutionRequest(self.process) request.addExecuteRequestHeader() request.addDataInputsStart() if len(self.process.inputs) > 0: # text/plain inputs ######################################################## for textBox in self.complexInputTextBoxList: # Do not add undefined inputs if textBox == None or str(textBox.document().toPlainText()) == "": continue # TODO: Check for more types (e.g. KML, Shapefile, JSON) self.mimeType = self.inputDataTypeList[textBox.objectName()]["MimeType"] if isMimeTypePlaylist(self.mimeType) != None: schema = self.inputDataTypeList[textBox.objectName()]["Schema"] encoding = self.inputDataTypeList[textBox.objectName()]["Encoding"] # Handle 'as reference' playlist request.addReferenceInput( textBox.objectName(), self.mimeType, schema, encoding, textBox.document().toPlainText() ) else: # It's not a playlist request.addPlainTextInput(textBox.objectName(), textBox.document().toPlainText()) # Single raster and vector inputs ########################################## for comboBox in self.complexInputComboBoxList: # Do not add undefined inputs if comboBox == None or comboBox.currentText() == "<None>": continue # TODO: Check for more types (e.g. KML, Shapefile, JSON) # QMessageBox.information(None, '', str(self.inputDataTypeList[comboBox.objectName()]["MimeType"])) # QMessageBox.information(None, '', pystring(comboBox.objectName())) self.mimeType = self.inputDataTypeList[pystring(comboBox.objectName())]["MimeType"] schema = self.inputDataTypeList[pystring(comboBox.objectName())]["Schema"] encoding = self.inputDataTypeList[pystring(comboBox.objectName())]["Encoding"] self.myLayer = self.tools.getVLayer(comboBox.currentText()) # try: if isMimeTypeVector(self.mimeType) != None and encoding != "base64": gmldata = createTmpGML( self.tools.getVLayer(comboBox.currentText()), useSelected, self.process.getSupportedGMLVersion(comboBox.objectName()), ) request.addGeometryInput( comboBox.objectName(), self.mimeType, schema, encoding, gmldata, useSelected ) elif isMimeTypeVector(self.mimeType) != None or isMimeTypeRaster(self.mimeType) != None: request.addGeometryBase64Input( comboBox.objectName(), self.mimeType, self.tools.getVLayer(comboBox.currentText()) ) # except: # QApplication.restoreOverrideCursor() # QMessageBox.warning(self.iface.mainWindow(), # QApplication.translate("QgsWps","Error"), # QApplication.translate("QgsWps","Please load or select a vector layer!")) # return # Multiple raster and vector inputs ######################################## for listWidgets in self.complexInputListWidgetList: # Do not add undefined inputs if listWidgets == None: continue self.mimeType = self.inputDataTypeList[listWidgets.objectName()]["MimeType"] schema = self.inputDataTypeList[listWidgets.objectName()]["Schema"] encoding = self.inputDataTypeList[listWidgets.objectName()]["Encoding"] # Iterate over each seletced item for i in range(listWidgets.count()): listWidget = listWidgets.item(i) if listWidget == None or listWidget.isSelected() == False or str(listWidget.text()) == "<None>": continue # TODO: Check for more types if isMimeTypeVector(self.mimeType) != None and self.mimeType == "text/xml": gmldata = createTmpGML( self.tools.getVLayer(listWidget.text()), useSelected, self.process.getSupportedGMLVersion(listWidgets.objectName()), ) request.addMultipleGeometryInput( listWidgets.objectName(), self.mimeType, schema, encoding, gmldata, useSelected ) elif isMimeTypeVector(self.mimeType) != None or isMimeTypeRaster(self.mimeType) != None: request.addMultipleGeometryBase64Input( listWidgets.objectName(), self.mimeType, self.tools.getVLayer(listWidget.text()) ) # Literal data as combo box choice ######################################### for comboBox in self.literalInputComboBoxList: if comboBox == None or comboBox.currentText() == "": continue request.addLiteralDataInput(comboBox.objectName(), comboBox.currentText()) # Literal data as combo box choice ######################################### for lineEdit in self.literalInputLineEditList: if lineEdit == None or lineEdit.text() == "": continue request.addLiteralDataInput(lineEdit.objectName(), lineEdit.text()) # BBOX data as lineEdit ######################################### for bbox in self.bboxInputLineEditList: if bbox == None or bbox.text() == "": continue bboxArray = bbox.text().split(",") request.addBoundingBoxInput(bbox.objectName(), bboxArray) request.addDataInputsEnd() # Attach only defined outputs dataOutputs = doc.elementsByTagName("Output") if dataOutputs.size() > 0 or len(self.complexOutputComboBoxList) > 0: request.addResponseFormStart() # Attach ALL literal outputs ############################################# for i in range(dataOutputs.size()): f_element = dataOutputs.at(i).toElement() outputIdentifier = pystring( f_element.elementsByTagName("ows:Identifier").at(0).toElement().text() ).strip() literalOutputType = f_element.elementsByTagName("LiteralOutput") # Complex data is always requested as reference if literalOutputType.size() != 0: request.addLiteralDataOutput(outputIdentifier) # Attach selected complex outputs ######################################## for comboBox in self.complexOutputComboBoxList: # Do not add undefined outputs if comboBox == None or str(comboBox.currentText()) == "<None>": continue outputIdentifier = comboBox.objectName() self.mimeType = self.outputDataTypeList[pystring(outputIdentifier)]["MimeType"] schema = self.outputDataTypeList[pystring(outputIdentifier)]["Schema"] encoding = self.outputDataTypeList[pystring(outputIdentifier)]["Encoding"] request.addReferenceOutput(outputIdentifier, self.mimeType, schema, encoding) request.addResponseFormEnd() request.addExecuteRequestEnd() postString = request.request # This is for debug purpose only if True: # self.tools.popUpMessageBox("Execute request", postString) # Write the request into a file outFile = open("/tmp/qwps_execute_request.xml", "w") outFile.write(postString) outFile.close() QApplication.restoreOverrideCursor() self.setStatus("processing") self.wps = ExecutionResult( self.getLiteralResult, self.getResultFile, self.successResult, self.errorResult, self.streamingHandler, self.progressBar, ) self.wps.executeProcess(self.process.processUrl, postString) if len(self.process.inputs) > 0: self.wps.thePostReply.uploadProgress.connect(lambda done, total: self.setStatus("upload", done, total)) self.wps.fetchingResult.connect(self.fetchingResult) ############################################################################## def addOkCancelButtons(self, dlgProcess, dlgProcessTabFrameLayout): groupBox = QFrame() layout = QHBoxLayout() btnOk = QPushButton(groupBox) btnOk.setText(pystring(QApplication.translate("QgsWps", "Run"))) btnOk.setMinimumWidth(100) btnOk.setMaximumWidth(100) btnCancel = QPushButton(groupBox) btnCancel.setText(QApplication.translate("QgsWps", "Back")) btnCancel.setMinimumWidth(100) btnCancel.setMaximumWidth(100) btnBookmark = QPushButton(groupBox) btnBookmark.setText(QApplication.translate("QgsWps", "Add Bookmark")) btnBookmark.setMinimumWidth(200) btnBookmark.setMaximumWidth(200) layout.addWidget(btnBookmark) layout.addStretch(10) layout.addWidget(btnCancel) layout.addWidget(btnOk) groupBox.setLayout(layout) dlgProcessTabFrameLayout.addWidget(groupBox) btnOk.clicked.connect(self.defineProcess) btnCancel.clicked.connect(self.dlgProcess.close) btnBookmark.clicked.connect(self.saveBookmark) def saveBookmark(self): server = WpsServer.getServer(self.dlgProcess.currentServiceName()) process = ProcessDescription(server, self.processUrl.queryItemValue("identifier")) process.saveBookmark() self.bookmarksChanged.emit() QMessageBox.information( self.iface.mainWindow(), QCoreApplication.translate("QgsWps", "Bookmark"), QCoreApplication.translate("QgsWps", "The creation bookmark was successful."), ) def fetchingResult(self, noFilesToFetch): QApplication.restoreOverrideCursor() self.setStatus("finished") ############################################################################## def streamingHandler(self, encoding, playlistUrl): """ Handle response form streaming based processes """ mimeTypePlaylist, self.mimeType = self.mimeType.split("+") print playlistUrl # Get number of chunks (Only for Output streaming based WPSs) chunks = 0 if isMimeTypeVector(self.mimeType) != None: for lineEdit in self.literalInputLineEditList: if lineEdit.objectName() == "NumberOfChunks": chunks = int(lineEdit.text()) elif isMimeTypeRaster(self.mimeType) != None: chunks = 1 for lineEdit in self.literalInputLineEditList: if lineEdit.objectName() == "chunksByRow" or lineEdit.objectName() == "chunksByColumn": chunks = chunks * int(lineEdit.text()) print "No. of chunks:", chunks # Streaming handler self.dataStream = Streaming(self, self.iface, chunks, playlistUrl, self.mimeType, encoding) self.dataStream.start() def stopStreaming(self): """ SLOT Stop the timer """ if self.dataStream: self.dataStream.stop() ############################################################################## def loadData(self, resultFile): bLoaded = True # For information purposes layerName = self.tools.uniqueLayerName(self.processIdentifier + "_" + self.identifier) # The layername is normally defined in the comboBox for comboBox in self.complexOutputComboBoxList: if comboBox.objectName() == self.identifier: layerName = comboBox.currentText() # Vector data # TODO: Check for schema GML and KML if isMimeTypeVector(self.mimeType) != None: vlayer = QgsVectorLayer(resultFile, layerName, "ogr") try: vlayer.setCrs(self.myLayer.dataProvider().crs()) except: pass bLoaded = QgsMapLayerRegistry.instance().addMapLayer(vlayer) # Raster data elif isMimeTypeRaster(self.mimeType) != None: # We can directly attach the new layer rLayer = QgsRasterLayer(resultFile, layerName) bLoaded = QgsMapLayerRegistry.instance().addMapLayer(rLayer) # Text data elif isMimeTypeText(self.mimeType) != None: # TODO: this should be handled in a separate diaqgswps.pylog to save the text output as file' QApplication.restoreOverrideCursor() text = open(resultFile, "r").read() # TODO: This should be a text dialog with safe option self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps", "Process result (text/plain)"), text) # Everything else elif isMimeTypeFile(self.mimeType) != None: # TODO: this should be handled in a separate diaqgswps.pylog to save the text output as file' QApplication.restoreOverrideCursor() text = open(resultFile, "r").read() # TODO: This should be a text dialog with safe option fileName = QFileDialog().getSaveFileName() # Everything else else: # For unsupported mime types we assume text QApplication.restoreOverrideCursor() content = open(resultFile, "r").read() # TODO: This should have a safe option self.tools.popUpMessageBox( QCoreApplication.translate("QgsWps", "Process result (unsupported mime type)"), content ) if not bLoaded: QMessageBox.information( self.iface.mainWindow(), QApplication.translate("QgsWps", "Result not loaded to the map"), QApplication.translate( "QgsWps", "It seems QGIS cannot load the result of the process. The result has a '{0}' type and can be accessed at '{1}'. \n\nYou could ask the service provider to consider changing the default data type of the result.", ).format(self.mimeType, resultFile), ) def getLiteralResult(self, identifier, literalText): self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps", "Result"), literalText) self.setStatus("finished") def getResultFile(self, identifier, mimeType, encoding, schema, reply): # Get a unique temporary file name self.mimeType = mimeType myQTempFile = QTemporaryFile() myQTempFile.open() ext = getFileExtension(self.mimeType) tmpFile = myQTempFile.fileName() + ext myQTempFile.close() # Write the data to the temporary file outFile = QFile(tmpFile) outFile.open(QIODevice.WriteOnly) outFile.write(reply.readAll()) reply.deleteLater() outFile.close() resultFile = self.wps.handleEncoded(tmpFile, mimeType, encoding, schema) # Finally, load the data self.loadData(resultFile) self.setStatus("finished") ############################################################################## def errorResult(self, exceptionHtml): self.setStatus("error") QMessageBox.critical(self.iface.mainWindow(), "Exception report", exceptionHtml) def successResult(self): self.setStatus("finished") ############################################################################## def deleteServer(self, name): settings = QSettings() settings.beginGroup("WPS") settings.remove(name) settings.endGroup() self.dlg.initQgsWpsGui() ############################################################################## def editServer(self, name): server = WpsServer.getServer(name) flags = ( Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint ) # QgisGui.ModalDialogFlags dlgEdit = QgsNewHttpConnectionBaseGui(self.dlg, flags) dlgEdit.txtName.setText(name) dlgEdit.txtUrl.setText(server.baseUrl) dlgEdit.show() self.dlg.initQgsWpsGui() ############################################################################## def newServer(self): flags = ( Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint ) # QgisGui.ModalDialogFlags dlgNew = QgsNewHttpConnectionBaseGui(self.dlg, flags) dlgNew.show() self.dlg.initQgsWpsGui() def pushDefaultServer(self): settings = QSettings() for k, v in self.defaultServers.iteritems(): myURL = urlparse(str(v)) mySettings = "/WPS/" + k # settings.setValue("WPS/connections/selected", QVariant(name) ) settings.setValue(mySettings + "/scheme", pystring(myURL.scheme)) settings.setValue(mySettings + "/server", pystring(myURL.netloc)) settings.setValue(mySettings + "/path", pystring(myURL.path)) settings.setValue(mySettings + "/method", pystring("GET")) settings.setValue(mySettings + "/version", pystring("1.0.0")) settings.setValue(mySettings + "/url", pystring(v)) self.dlg.initQgsWpsGui() @pyqtSignature("") def on_btnKill_clicked(self): self.wps.thePostReply.abort() self.wps.thePostReply.deleteLater() self.setStatus("aborted") self.killed.emit()
class QgsWps: MSG_BOX_TITLE = "WPS Client" def __init__(self, iface): # Save reference to the QGIS interface self.iface = iface self.minimumRevision = 12026 self.localePath = "" #Initialise the translation environment userPluginPath = QFileInfo(QgsApplication.qgisUserDbFilePath()).path()+"/python/plugins/wps" systemPluginPath = QgsApplication.prefixPath()+"/share/qgis/python/plugins/wps" myLocaleName = QSettings().value("locale/userLocale").toString() myLocale = myLocaleName[0:2] if QFileInfo(userPluginPath).exists(): self.pluginPath = userPluginPath self.localePath = userPluginPath+"/i18n/wps_"+myLocale+".qm" elif QFileInfo(systemPluginPath).exists(): self.pluginPath = systemPluginPath self.localePath = systemPluginPath+"/i18n/wps_"+myLocale+".qm" if QFileInfo(self.localePath).exists(): self.translator = QTranslator() self.translator.load(self.localePath) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) ############################################################################## def initGui(self): # Create action that will start plugin configuration self.action = QAction(QIcon(":/plugins/wps/images/wps-add.png"), "WPS Client", self.iface.mainWindow()) QObject.connect(self.action, SIGNAL("triggered()"), self.run) # Add toolbar button and menu item self.iface.addToolBarIcon(self.action) self.iface.addPluginToMenu("WPS", self.action) self.doc = QtXml.QDomDocument() self.tmpPath = QDir.tempPath() self.tools = QgsWpsTools(self.iface) # QObject.connect(self.myDockWidget, SIGNAL("flipDirection()"), self.flipDirection) ############################################################################## def unload(self): self.iface.removePluginMenu("WPS", self.action) self.iface.removeToolBarIcon(self.action) ############################################################################## def run(self): flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags self.dlg = QgsWpsGui(self.iface.mainWindow(), flags) QObject.connect(self.dlg, SIGNAL("getDescription(QString, QTreeWidgetItem)"), self.createProcessGUI) QObject.connect(self.dlg, SIGNAL("newServer()"), self.newServer) QObject.connect(self.dlg, SIGNAL("editServer(QString)"), self.editServer) QObject.connect(self.dlg, SIGNAL("deleteServer(QString)"), self.deleteServer) QObject.connect(self.dlg, SIGNAL("connectServer(QString)"), self.createCapabilitiesGUI) self.dlg.initQgsWpsGui() self.myDockWidget = QgsWpsDockWidget(self.dlg) self.iface.addDockWidget(Qt.LeftDockWidgetArea, self.myDockWidget) self.myDockWidget.show() ############################################################################## def newServer(self): flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags dlgNew = QgsNewHttpConnectionBaseGui(self.dlg, flags) dlgNew.show() self.dlg.initQgsWpsGui() ############################################################################## def editServer(self, name): info = self.tools.getServer(name) flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags dlgEdit = QgsNewHttpConnectionBaseGui(self.dlg, flags) dlgEdit.txtName.setText(name) dlgEdit.txtUrl.setText(info["scheme"]+"://"+info["server"]+info["path"]) dlgEdit.show() self.dlg.initQgsWpsGui() ############################################################################## def deleteServer(self, name): settings = QSettings() settings.beginGroup("WPS") settings.remove(name) settings.endGroup() self.dlg.initQgsWpsGui() ############################################################################## def createCapabilitiesGUI(self, connection): if not self.tools.webConnectionExists(connection): return 0 itemListAll = self.tools.getCapabilities(connection) # QMessageBox.information(None, '', itemListAll) self.dlg.initTreeWPSServices(itemListAll) ############################################################################## def createProcessGUI(self,name, item): """Create the GUI for a selected WPS process based on the DescribeProcess response document. Mandatory inputs are marked as red, default is black""" try: self.processIdentifier = item.text(0) except: QMessageBox.warning(None,'',QCoreApplication.translate("QgsWps",'Please select a Process')) return 0 # Lists which store the inputs and meta information (format, occurs, ...) # This list is initialized every time the GUI is created self.complexInputComboBoxList = [] # complex input for single raster and vector maps self.complexInputListWidgetList = [] # complex input for multiple raster and vector maps self.complexInputTextBoxList = [] # complex inpt of type text/plain self.literalInputComboBoxList = [] # literal value list with selectable answers self.literalInputLineEditList = [] # literal value list with single text line input self.complexOutputComboBoxList = [] # list combo box self.inputDataTypeList = {} self.inputsMetaInfo = {} # dictionary for input metainfo, key is the input identifier self.outputsMetaInfo = {} # dictionary for output metainfo, key is the output identifier self.outputDataTypeList = {} self.processName = name flags = Qt.WindowTitleHint | Qt.WindowSystemMenuHint | Qt.WindowMinimizeButtonHint | Qt.WindowMaximizeButtonHint # QgisGui.ModalDialogFlags # Recive the XML process description self.doc.setContent(self.tools.getServiceXML(self.processName,"DescribeProcess",self.processIdentifier), True) DataInputs = self.doc.elementsByTagName("Input") DataOutputs = self.doc.elementsByTagName("Output") # Create the layouts and the scroll area self.dlgProcess = QgsWpsDescribeProcessGui(self.dlg, flags) self.dlgProcessLayout = QGridLayout() # Two tabs, one for the process inputs and one for the documentation # TODO: add a tab for literal outputs self.dlgProcessTab = QTabWidget() self.dlgProcessTabFrame = QFrame() self.dlgProcessTabFrameLayout = QGridLayout() # The process description can be very long, so we make it scrollable self.dlgProcessScrollArea = QScrollArea(self.dlgProcessTab) self.dlgProcessScrollAreaWidget = QFrame() self.dlgProcessScrollAreaWidgetLayout = QGridLayout() # First part of the gui is a short overview about the process identifier, title, abstract = self.tools.getIdentifierTitleAbstractFromElement(self.doc) self.addIntroduction(identifier, title) # If no Input Data are requested if DataInputs.size()==0: self.defineProcess() return 0 # Generate the input GUI buttons and widgets self.generateProcessInputsGUI(DataInputs) # Generate the editable outpt widgets, you can set the output to none if it is not requested self.generateProcessOutputsGUI(DataOutputs) self.dlgProcessScrollAreaWidgetLayout.setSpacing(10) self.dlgProcessScrollAreaWidget.setLayout(self.dlgProcessScrollAreaWidgetLayout) self.dlgProcessScrollArea.setWidget(self.dlgProcessScrollAreaWidget) self.dlgProcessScrollArea.setWidgetResizable(True) self.dlgProcessTabFrameLayout.addWidget(self.dlgProcessScrollArea) self.addOkCancelButtons() self.dlgProcessTabFrame.setLayout(self.dlgProcessTabFrameLayout) self.dlgProcessTab.addTab(self.dlgProcessTabFrame, "Process") self.addDocumentationTab(abstract) self.dlgProcessLayout.addWidget(self.dlgProcessTab) self.dlgProcess.setLayout(self.dlgProcessLayout) self.dlgProcess.setGeometry(QRect(190,100,800,600)) self.dlgProcess.show() ############################################################################## def generateProcessInputsGUI(self, DataInputs): """Generate the GUI for all Inputs defined in the process description XML file""" # Create the complex inputs at first for i in range(DataInputs.size()): f_element = DataInputs.at(i).toElement() inputIdentifier, title, abstract = self.tools.getIdentifierTitleAbstractFromElement(f_element) complexData = f_element.elementsByTagName("ComplexData") minOccurs = int(f_element.attribute("minOccurs")) maxOccurs = int(f_element.attribute("maxOccurs")) # Iterate over all complex inputs and add combo boxes, text boxes or list widgets if complexData.size() > 0: # Das i-te ComplexData Objekt auswerten complexDataTypeElement = complexData.at(0).toElement() complexDataFormat = self.tools.getDefaultMimeType(complexDataTypeElement) supportedComplexDataFormat = self.tools.getSupportedMimeTypes(complexDataTypeElement) # Store the input formats self.inputsMetaInfo[inputIdentifier] = supportedComplexDataFormat self.inputDataTypeList[inputIdentifier] = complexDataFormat # Attach the selected vector or raster maps if self.tools.isMimeTypeVector(complexDataFormat["MimeType"]) != None: # Vector inputs layerNamesList = self.tools.getLayerNameList(0) if maxOccurs == 1: self.complexInputComboBoxList.append(self.addComplexInputComboBox(title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs)) else: self.complexInputListWidgetList.append(self.addComplexInputListWidget(title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs)) elif self.tools.isMimeTypeText(complexDataFormat["MimeType"]) != None: # Text inputs self.complexInputTextBoxList.append(self.addComplexInputTextBox(title, inputIdentifier, minOccurs)) elif self.tools.isMimeTypeRaster(complexDataFormat["MimeType"]) != None: # Raster inputs layerNamesList = self.tools.getLayerNameList(1) if maxOccurs == 1: self.complexInputComboBoxList.append(self.addComplexInputComboBox(title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs)) else: self.complexInputListWidgetList.append(self.addComplexInputListWidget(title, inputIdentifier, str(complexDataFormat), layerNamesList, minOccurs)) else: # We assume text inputs in case of an unknown mime type self.complexInputTextBoxList.append(self.addComplexInputTextBox(title, inputIdentifier, minOccurs)) # Create the literal inputs as second for i in range(DataInputs.size()): f_element = DataInputs.at(i).toElement() inputIdentifier, title, abstract = self.tools.getIdentifierTitleAbstractFromElement(f_element) literalData = f_element.elementsByTagName("LiteralData") minOccurs = int(f_element.attribute("minOccurs")) maxOccurs = int(f_element.attribute("maxOccurs")) if literalData.size() > 0: allowedValuesElement = literalData.at(0).toElement() aValues = allowedValuesElement.elementsByTagNameNS("http://www.opengis.net/ows/1.1","AllowedValues") dValue = str(allowedValuesElement.elementsByTagName("DefaultValue").at(0).toElement().text()) # print "Checking allowed values " + str(aValues.size()) if aValues.size() > 0: valList = self.tools.allowedValues(aValues) if len(valList) > 0: if len(valList[0]) > 0: self.literalInputComboBoxList.append(self.addLiteralComboBox(title, inputIdentifier, valList, minOccurs)) else: self.literalInputLineEditList.append(self.addLiteralLineEdit(title, inputIdentifier, minOccurs, str(valList))) else: self.literalInputLineEditList.append(self.addLiteralLineEdit(title, inputIdentifier, minOccurs, dValue)) # At last, create the bounding box inputs for i in range(DataInputs.size()): f_element = DataInputs.at(i).toElement() inputIdentifier, title, abstract = self.tools.getIdentifierTitleAbstractFromElement(f_element) bBoxData = f_element.elementsByTagName("BoundingBoxData") minOccurs = int(f_element.attribute("minOccurs")) maxOccurs = int(f_element.attribute("maxOccurs")) if bBoxData.size() > 0: crsListe = [] bBoxElement = bBoxData.at(0).toElement() defaultCrsElement = bBoxElement.elementsByTagName("Default").at(0).toElement() defaultCrs = defaultCrsElement.elementsByTagName("CRS").at(0).toElement().attributeNS("http://www.w3.org/1999/xlink", "href") crsListe.append(defaultCrs) self.addLiteralLineEdit(title+"(minx,miny,maxx,maxy)", inputIdentifier, minOccurs) supportedCrsElements = bBoxElement.elementsByTagName("Supported") for i in range(supportedCrsElements.size()): crsListe.append(supportedCrsElements.at(i).toElement().elementsByTagName("CRS").at(0).toElement().attributeNS("http://www.w3.org/1999/xlink", "href")) self.literalInputComboBoxList.append(self.addLiteralComboBox("Supported CRS", inputIdentifier,crsListe, minOccurs)) self.addCheckBox(QCoreApplication.translate("QgsWps","Process selected objects only"), QCoreApplication.translate("QgsWps","Selected")) ############################################################################## def generateProcessOutputsGUI(self, DataOutputs): """Generate the GUI for all complex ouputs defined in the process description XML file""" if DataOutputs.size() < 1: return groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) groupbox.setTitle("Complex output(s)") layout = QVBoxLayout() # Add all complex outputs for i in range(DataOutputs.size()): f_element = DataOutputs.at(i).toElement() outputIdentifier, title, abstract = self.tools.getIdentifierTitleAbstractFromElement(f_element) complexOutput = f_element.elementsByTagName("ComplexOutput") # Iterate over all complex inputs and add combo boxes, text boxes or list widgets if complexOutput.size() > 0: # Das i-te ComplexData Objekt auswerten complexOutputTypeElement = complexOutput.at(0).toElement() complexOutputFormat = self.tools.getDefaultMimeType(complexOutputTypeElement) supportedcomplexOutputFormat = self.tools.getSupportedMimeTypes(complexOutputTypeElement) # Store the input formats self.outputsMetaInfo[outputIdentifier] = supportedcomplexOutputFormat self.outputDataTypeList[outputIdentifier] = complexOutputFormat widget, comboBox = self.addComplexOutputComboBox(groupbox, outputIdentifier, title, str(complexOutputFormat)) self.complexOutputComboBoxList.append(comboBox) layout.addWidget(widget) # Set the layout groupbox.setLayout(layout) # Add the outputs self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## def addComplexInputComboBox(self, title, name, mimeType, namesList, minOccurs): """Adds a combobox to select a raster or vector map as input to the process tab""" groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) #groupbox.setTitle(name) groupbox.setMinimumHeight(25) layout = QHBoxLayout() # This input is optional if minOccurs == 0: namesList.append("<None>") comboBox = QComboBox(groupbox) comboBox.addItems(namesList) comboBox.setObjectName(name) comboBox.setMinimumWidth(179) comboBox.setMaximumWidth(179) comboBox.setMinimumHeight(25) myLabel = QLabel(self.dlgProcessScrollAreaWidget) myLabel.setObjectName("qLabel"+name) if minOccurs > 0: string = "[" + name + "] <br>" + title myLabel.setText("<font color='Red'>" + string + "</font>" + " <br>(" + mimeType + ")") else: string = "[" + name + "]\n" + title + " <br>(" + mimeType + ")" myLabel.setText(string) myLabel.setWordWrap(True) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(comboBox) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) return comboBox ############################################################################## def addComplexOutputComboBox(self, widget, name, title, mimeType): """Adds a combobox to select a raster or vector map as input to the process tab""" groupbox = QGroupBox(widget) groupbox.setMinimumHeight(25) layout = QHBoxLayout() namesList = [] # Generate a unique name for the layer namesList.append(self.tools.uniqueLayerName(self.processIdentifier + "_" + name + "_")) namesList.append("<None>") comboBox = QComboBox(groupbox) comboBox.setEditable(True) comboBox.addItems(namesList) comboBox.setObjectName(name) comboBox.setMinimumWidth(250) comboBox.setMaximumWidth(250) comboBox.setMinimumHeight(25) myLabel = QLabel(widget) myLabel.setObjectName("qLabel"+name) string = "[" + name + "] <br>" + title myLabel.setText("<font color='Green'>" + string + "</font>" + " <br>(" + mimeType + ")") myLabel.setWordWrap(True) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(comboBox) groupbox.setLayout(layout) return groupbox, comboBox ############################################################################## def addComplexInputListWidget(self, title, name, mimeType, namesList, minOccurs): """Adds a widget for multiple raster or vector selections as inputs to the process tab""" groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) #groupbox.setTitle(name) groupbox.setMinimumHeight(25) layout = QHBoxLayout() # This input is optional if minOccurs == 0: namesList.append("<None>") listWidget = QListWidget(groupbox) listWidget.addItems(namesList) listWidget.setObjectName(name) listWidget.setMinimumWidth(179) listWidget.setMaximumWidth(179) listWidget.setMinimumHeight(120) listWidget.setMaximumHeight(120) listWidget.setSelectionMode(QAbstractItemView.ExtendedSelection) myLabel = QLabel(self.dlgProcessScrollAreaWidget) myLabel.setObjectName("qLabel"+name) if minOccurs > 0: string = "[" + name + "] <br>" + title myLabel.setText("<font color='Red'>" + string + "</font>" + " <br>(" + mimeType + ")") else: string = "[" + name + "]\n" + title + " <br>(" + mimeType + ")" myLabel.setText(string) myLabel.setWordWrap(True) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(listWidget) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) return listWidget ############################################################################## def addComplexInputTextBox(self, title, name, minOccurs): """Adds a widget to insert text as complex inputs to the process tab""" groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) #groupbox.setTitle(name) groupbox.setMinimumHeight(50) layout = QHBoxLayout() textBox = QTextEdit(groupbox) textBox.setObjectName(name) textBox.setMinimumWidth(200) textBox.setMaximumWidth(200) textBox.setMinimumHeight(50) myLabel = QLabel(self.dlgProcessScrollAreaWidget) myLabel.setObjectName("qLabel"+name) if minOccurs > 0: string = "[" + name + "] <br>" + title myLabel.setText("<font color='Red'>" + string + "</font>") else: string = "[" + name + "]\n" + title myLabel.setText(string) myLabel.setWordWrap(True) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(textBox) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) return textBox ############################################################################## def addLiteralComboBox(self, title, name, namesList, minOccurs): groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) #groupbox.setTitle(name) groupbox.setMinimumHeight(25) layout = QHBoxLayout() comboBox = QComboBox(self.dlgProcessScrollAreaWidget) comboBox.addItems(namesList) comboBox.setObjectName(name) comboBox.setMinimumWidth(179) comboBox.setMaximumWidth(179) comboBox.setMinimumHeight(25) myLabel = QLabel(self.dlgProcessScrollAreaWidget) myLabel.setObjectName("qLabel"+name) if minOccurs > 0: string = "[" + name + "] <br>" + title myLabel.setText("<font color='Red'>" + string + "</font>") else: string = "[" + name + "]\n" + title myLabel.setText(string) myLabel.setWordWrap(True) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(comboBox) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) return comboBox ############################################################################## def addLiteralLineEdit(self, title, name, minOccurs, defaultValue=""): groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) #groupbox.setTitle(name) groupbox.setMinimumHeight(25) layout = QHBoxLayout() myLineEdit = QLineEdit(groupbox) myLineEdit.setObjectName(name) myLineEdit.setMinimumWidth(179) myLineEdit.setMaximumWidth(179) myLineEdit.setMinimumHeight(25) myLineEdit.setText(defaultValue) myLabel = QLabel(groupbox) myLabel.setObjectName("qLabel"+name) if minOccurs > 0: string = "[" + name + "] <br>" + title myLabel.setText("<font color='Red'>" + string + "</font>") else: string = "[" + name + "]\n" + title myLabel.setText(string) myLabel.setWordWrap(True) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(myLineEdit) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) return myLineEdit ############################################################################## def addCheckBox(self, title, name): groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) #groupbox.setTitle(name) groupbox.setMinimumHeight(25) layout = QHBoxLayout() myCheckBox = QCheckBox(groupbox) myCheckBox.setObjectName("chkBox"+name) myCheckBox.setChecked(False) myLabel = QLabel(groupbox) myLabel.setObjectName("qLabel"+name) myLabel.setText("(" + name + ")" + "\n" + title) myLabel.setMinimumWidth(400) myLabel.setMinimumHeight(25) myLabel.setWordWrap(True) layout.addWidget(myLabel) layout.addStretch(1) layout.addWidget(myCheckBox) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## def addIntroduction(self, name, title): groupbox = QGroupBox(self.dlgProcessScrollAreaWidget) groupbox.setTitle(name) layout = QVBoxLayout() myLabel = QLabel(groupbox) myLabel.setObjectName("qLabel"+name) myLabel.setText(QString(title)) myLabel.setMinimumWidth(600) myLabel.setMinimumHeight(25) myLabel.setWordWrap(True) layout.addWidget(myLabel) groupbox.setLayout(layout) self.dlgProcessScrollAreaWidgetLayout.addWidget(groupbox) ############################################################################## def addDocumentationTab(self, abstract): # Check for URL if str(abstract).find("http://") == 0: textBox = QtWebKit.QWebView(self.dlgProcessTab) textBox.load(QUrl(abstract)) textBox.show() else: textBox = QTextBrowser(self.dlgProcessTab) textBox.setText(QString(abstract)) self.dlgProcessTab.addTab(textBox, "Documentation") ############################################################################## def addOkCancelButtons(self): groupBox = QFrame() layout = QHBoxLayout() btnOk = QPushButton(groupBox) btnOk.setText(QString("Run")) btnOk.setMinimumWidth(100) btnOk.setMaximumWidth(100) btnCancel = QPushButton(groupBox) btnCancel.setText("Back") btnCancel.setMinimumWidth(100) btnCancel.setMaximumWidth(100) # lblStatus = QLabel(groupBox) # lblStatus.setText('Prozess Status: ') # # lneStatus = QLineEdit(groupBox) # # layout.addWidget(lblStatus) # layout.addWidget(lneStatus) layout.addStretch(10) layout.addWidget(btnCancel) layout.addWidget(btnOk) groupBox.setLayout(layout) self.dlgProcessTabFrameLayout.addWidget(groupBox) QObject.connect(btnOk,SIGNAL("clicked()"),self.defineProcess) QObject.connect(btnCancel,SIGNAL("clicked()"),self.dlgProcess.close) ############################################################################## def defineProcess(self): """Create the execute request""" self.doc.setContent(self.tools.getServiceXML(self.processName,"DescribeProcess",self.processIdentifier)) dataInputs = self.doc.elementsByTagName("Input") dataOutputs = self.doc.elementsByTagName("Output") QApplication.setOverrideCursor(Qt.WaitCursor) result = self.tools.getServer(self.processName) scheme = result["scheme"] path = result["path"] server = result["server"] checkBoxes = self.dlgProcess.findChildren(QCheckBox) if len(checkBoxes) > 0: useSelected = checkBoxes[0].isChecked() postString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" postString += "<wps:Execute service=\"WPS\" version=\""+ self.tools.getServiceVersion() + "\"" + \ " xmlns:wps=\"http://www.opengis.net/wps/1.0.0\"" + \ " xmlns:ows=\"http://www.opengis.net/ows/1.1\"" +\ " xmlns:xlink=\"http://www.w3.org/1999/xlink\"" +\ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""\ " xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0" +\ " http://schemas.opengis.net/wps/1.0.0/wpsExecute_request.xsd\">" postString += "<ows:Identifier>"+self.processIdentifier+"</ows:Identifier>\n" postString += "<wps:DataInputs>" # text/plain inputs ######################################################## for textBox in self.complexInputTextBoxList: # Do not add undefined inputs if textBox == None or str(textBox.document().toPlainText()) == "": continue postString += self.tools.xmlExecuteRequestInputStart(textBox.objectName()) postString += "<wps:ComplexData>" + textBox.document().toPlainText() + "</wps:ComplexData>\n" postString += self.tools.xmlExecuteRequestInputEnd() # Single raster and vector inputs ########################################## for comboBox in self.complexInputComboBoxList: # Do not add undefined inputs if comboBox == None or unicode(comboBox.currentText(), 'latin1') == "<None>": continue postString += self.tools.xmlExecuteRequestInputStart(comboBox.objectName()) # TODO: Check for more types mimeType = self.inputDataTypeList[comboBox.objectName()]["MimeType"] schema = self.inputDataTypeList[comboBox.objectName()]["Schema"] encoding = self.inputDataTypeList[comboBox.objectName()]["Encoding"] self.myLayer = self.tools.getVLayer(comboBox.currentText()) if self.tools.isMimeTypeVector(mimeType) != None and mimeType == "text/xml": postString += "<wps:ComplexData mimeType=\"" + mimeType + "\" schema=\"" + schema + "\" enconding=\"" + encoding + "\">" postString += self.tools.createTmpGML(comboBox.currentText(), useSelected).replace("> <","><") postString = postString.replace("xsi:schemaLocation=\"http://ogr.maptools.org/ qt_temp.xsd\"", "xsi:schemaLocation=\"http://schemas.opengis.net/gml/3.1.1/base/ gml.xsd\"") elif self.tools.isMimeTypeVector(mimeType) != None or self.tools.isMimeTypeRaster(mimeType) != None: postString += "<wps:ComplexData mimeType=\"" + mimeType + "\" encoding=\"base64\">\n" postString += self.tools.createTmpBase64(comboBox.currentText()) postString += "</wps:ComplexData>\n" postString += self.tools.xmlExecuteRequestInputEnd() # Multiple raster and vector inputs ######################################## for listWidgets in self.complexInputListWidgetList: # Do not add undefined inputs if listWidgets == None: continue mimeType = self.inputDataTypeList[listWidgets.objectName()]["MimeType"] schema = self.inputDataTypeList[listWidgets.objectName()]["Schema"] encoding = self.inputDataTypeList[listWidgets.objectName()]["Encoding"] # Iterate over each seletced item for i in range(listWidgets.count()): listWidget = listWidgets.item(i) if listWidget == None or listWidget.isSelected() == False or str(listWidget.text()) == "<None>": continue postString += self.tools.xmlExecuteRequestInputStart(listWidgets.objectName()) # TODO: Check for more types if self.tools.isMimeTypeVector(mimeType) != None and mimeType == "text/xml": postString += "<wps:ComplexData mimeType=\"" + mimeType + "\" schema=\"" + schema + "\" enconding=\"" + encoding + "\">" # postString += self.tools.createTmpGML(listWidget.text(), useSelected).replace("> <","><").replace("http://ogr.maptools.org/ qt_temp.xsd","http://ogr.maptools.org/qt_temp.xsd") postString += self.tools.createTmpGML(listWidget.text(), useSelected).replace("> <","><") elif self.tools.isMimeTypeVector(mimeType) != None or self.tools.isMimeTypeRaster(mimeType) != None: postString += "<wps:ComplexData mimeType=\"" + mimeType + "\" encoding=\"base64\">\n" postString += self.tools.createTmpBase64(listWidget.text()) postString += "</wps:ComplexData>\n" postString += self.tools.xmlExecuteRequestInputEnd() # Literal data as combo box choice ######################################### for comboBox in self.literalInputComboBoxList: if comboBox == None or comboBox.currentText() == "": continue postString += self.tools.xmlExecuteRequestInputStart(comboBox.objectName()) postString += "<wps:LiteralData>"+comboBox.currentText()+"</wps:LiteralData>\n" postString += self.tools.xmlExecuteRequestInputEnd() # Literal data as combo box choice ######################################### for lineEdit in self.literalInputLineEditList: if lineEdit == None or lineEdit.text() == "": continue postString += self.tools.xmlExecuteRequestInputStart(lineEdit.objectName()) postString += "<wps:LiteralData>"+lineEdit.text()+"</wps:LiteralData>\n" postString += self.tools.xmlExecuteRequestInputEnd() postString += "</wps:DataInputs>\n" # Attach only defined outputs if dataOutputs.size() > 0 and len(self.complexOutputComboBoxList) > 0: postString += "<wps:ResponseForm>\n" # The server should store the result. No lineage should be returned or status postString += "<wps:ResponseDocument lineage=\"false\" storeExecuteResponse=\"true\" status=\"false\">\n" # Attach ALL literal outputs ############################################# for i in range(dataOutputs.size()): f_element = dataOutputs.at(i).toElement() outputIdentifier = f_element.elementsByTagName("ows:Identifier").at(0).toElement().text().simplified() literalOutputType = f_element.elementsByTagName("LiteralOutput") # Complex data is always requested as reference if literalOutputType.size() != 0: postString += "<wps:Output>\n" postString += "<ows:Identifier>"+outputIdentifier+"</ows:Identifier>\n" postString += "</wps:Output>\n" # Attach selected complex outputs ######################################## for comboBox in self.complexOutputComboBoxList: # Do not add undefined outputs if comboBox == None or str(comboBox.currentText()) == "<None>": continue outputIdentifier = comboBox.objectName() mimeType = self.outputDataTypeList[outputIdentifier]["MimeType"] schema = self.outputDataTypeList[outputIdentifier]["Schema"] encoding = self.outputDataTypeList[outputIdentifier]["Encoding"] postString += "<wps:Output asReference=\"true\" mimeType=\"" + mimeType + "\" schema=\"" + schema + "\">" postString += "<ows:Identifier>" + outputIdentifier + "</ows:Identifier>\n" postString += "</wps:Output>\n" postString += "</wps:ResponseDocument>\n" postString += "</wps:ResponseForm>\n" postString += "</wps:Execute>\n" # This is for debug purpose only if DEBUG == True: # self.tools.popUpMessageBox("Execute request", postString) # Write the request into a file outFile = open('/tmp/qwps_execute_request.xml', 'w') outFile.write(postString) outFile.close() QApplication.restoreOverrideCursor() QApplication .setOverrideCursor(Qt.ArrowCursor) self.theThread.setScheme(scheme) self.theThread.setServer(server) self.theThread.setPath(path) self.theThread.setPostString(postString) self.theThread.start() # self.serverThreadDlg = QgsWpsServerThreadDialog(self.processIdentifier, scheme, server, path, postString) # QObject.connect(self.serverThreadDlg, SIGNAL("serviceFinished(QString)"), self.resultHandler) # self.serverThreadDlg.show() ############################################################################## def resultHandler(self, resultXML, resultType="store"): """Handle the result of the WPS Execute request and add the outputs as new map layers to the regestry or open an information window to show literal outputs.""" # This is for debug purpose only if DEBUG == True: self.tools.popUpMessageBox("Result XML", resultXML) # Write the response into a file outFile = open('/tmp/qwps_execute_response.xml', 'w') outFile.write(resultXML) outFile.close() self.doc.setContent(resultXML, True) resultNodeList = self.doc.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0","Output") # TODO: Check if the process does not run correctly before if resultNodeList.size() > 0: for i in range(resultNodeList.size()): f_element = resultNodeList.at(i).toElement() # Fetch the referenced complex data if f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0", "Reference").size() > 0: identifier = f_element.elementsByTagNameNS("http://www.opengis.net/ows/1.1","Identifier").at(0).toElement().text().simplified() reference = f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0","Reference").at(0).toElement() # Get the reference fileLink = reference.attribute("href", "0") # Try with namespace if not successful if fileLink == '0': fileLink = reference.attributeNS("http://www.w3.org/1999/xlink", "href", "0") if fileLink == '0': QMessageBox.warning(None, '', str(QCoreApplication.translate("WPS Error: Unable to download the result of reference: ")) + str(fileLink)) return # Get the mime type of the result mimeType = str(reference.attribute("mimeType", "0").toLower()) if fileLink != '0': # Set a valid layerName layerName = self.tools.uniqueLayerName(self.processIdentifier + "_" + identifier) # The layername is normally defined in the comboBox for comboBox in self.complexOutputComboBoxList: if comboBox.objectName() == identifier: layerName = comboBox.currentText() resultFileConnector = urllib.urlretrieve(unicode(fileLink,'latin1')) resultFile = resultFileConnector[0] # Vector data # TODO: Check for schema GML and KML if self.tools.isMimeTypeVector(mimeType) != None: vlayer = QgsVectorLayer(resultFile, layerName, "ogr") vlayer.setCrs(self.myLayer.dataProvider().crs()) QgsMapLayerRegistry.instance().addMapLayer(vlayer) # Raster data elif self.tools.isMimeTypeRaster(mimeType) != None: # We can directly attach the new layer rLayer = QgsRasterLayer(resultFile, layerName) QgsMapLayerRegistry.instance().addMapLayer(rLayer) # Text data elif self.tools.isMimeTypeText(mimeType) != None: #TODO: this should be handled in a separate diaqgswps.pylog to save the text output as file' QApplication.restoreOverrideCursor() text = open(resultFile, 'r').read() # TODO: This should be a text dialog with safe option self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps",'Process result (text/plain)'),text) # Everything else else: # For unsupported mime types we assume text QApplication.restoreOverrideCursor() content = open(resultFile, 'r').read() # TODO: This should have a safe option self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps", 'Process result (unsupported mime type)'), content) elif f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0", "LiteralData").size() > 0: QApplication.restoreOverrideCursor() literalText = f_element.elementsByTagNameNS("http://www.opengis.net/wps/1.0.0", "LiteralData").at(0).toElement().text() self.tools.popUpMessageBox(QCoreApplication.translate("QgsWps",'Result'),literalText) else: QMessageBox.warning(None, '', str(QCoreApplication.translate("WPS Error: Missing reference or literal data in response"))) else: print "Error" self.tools.errorHandler(resultXML) pass def setProcessStarted(self): # self.dlgProcess.lneStatus.setText("Process started and running ... ") groupBox = QGroupBox(self.myDockWidget.groupBox) layout = QHBoxLayout() self.lblProcess = QLabel(groupBox) self.lblProcess.setText(QString("Process "+self.processIdentifier+" running ...")) # # layout.addWidget(btnCancel) self.btnProcessCancel = QToolButton(groupBox) self.btnProcessCancel.setIcon(QIcon(":/plugins/wps/images/button_cancel.png") ) self.btnProcessCancel.setMinimumWidth(30) self.btnProcessCancel.setMaximumWidth(30) layout.addWidget(self.lblProcess) layout.addStretch(10) layout.addWidget(self.btnProcessCancel) self.myDockWidget.groupBox.setLayout(layout) self.myDockWidget.btnConnect.setEnabled(False) QObject.connect(self.btnProcessCancel,SIGNAL("clicked()"),self.terminateProcessing) # self.statusLabel = None # self.statusLabel = QLabel(QCoreApplication.translate("QgsWps", "WPS running ... "), self.iface.mainWindow().statusBar()) # self.iface.mainWindow().statusBar().insertPermanentWidget(0, self.statusLabel) pass def setProcessFinished(self): self.iface.mainWindow().statusBar().removeWidget(self.statusLabel) self.lblProcess.setText('Process finished') self.myDockWidget.btnConnect.setEnabled(True) QMessageBox.information(self.iface.mainWindow(),'Status', "Process "+self.processIdentifier+" finished") def setProcessTerminated(self): QMessageBox.information(None,'Status', "Process "+self.processIdentifier+" terminated") self.myDockWidget.btnConnect.setEnabled(True) def closeDialog(self): self.close() def removeProcessFromWidget(self): pass def terminateProcessing( self ): if self.theThread != None: self.theThread.terminate() self.theThread = None self.lblProcess.setText('Process '+self.processIdentifier+' terminated') btnProcessRemove = self.btnProcessCancel btnProcessRemove.setText('remove') self.myDockWidget.btnConnect.setEnabled(True) QObject.connect(btnProcessRemove,SIGNAL("clicked()"),self.removeProcessFromWidget) def stopProcessing( self ): if self.theThread != None: self.theThread.stop() self.theThread = None