class MenuDiretorioConsole(MatrizConsole): arquivoSelecionado = pyqtSignal(str) def __init__(self, initDir='.', parent=None): super().__init__(parent=parent) self._dir = QDir(initDir) self._dir.setSorting(QDir.Name) self._addItensDir() def _addItensDir(self): self.clear() di = self._dir.entryList() try: di.remove('.') except ValueError: pass self.addItens([LabelConsole(i) for i in di]) def atualizarListaArquivos(self): self.cd('.') def cd(self, diret): if self._dir.cd(diret): self._addItensDir() return True return False def onEnter(self): if not self.cd(self.getItemSelecionado().getTexto()): self.arquivoSelecionado.emit(self.pathArquivoSelecionado()) def path(self): return self._dir.absolutePath() def pathArquivoSelecionado(self): return self.path() + '/' + self.getItemSelecionado().getTexto() def desenhoTela(self, tam): s = '|{0:-<{1}}|\n'.format('',tam-2) s += '|Path: {0:<{1}}{2}|\n'.format(LabelConsole(self._dir.absolutePath()).desenhoTelaConsole(tam-9), tam-9, [' ','*'][self.hasFocus()]) s += '|{0:-<{1}}|\n'.format('',tam-2) for i in super().desenhoTela(tam-2).split('\n'): s += '|{0:<{1}}|\n'.format(i, tam-2) s += '|{0:-<{1}}|'.format('',tam-2) return s
def on_gen(self): '''生成工程''' if not self.currentConfig: return #获取工程名及有效路径 project_name = self.et_project_name.text() project_location = self.et_project_location.text() qdir = QDir(project_location) if not qdir.exists(): if not qdir.mkpath(project_location): QMessageBox.warning(self, '警告', '路径无效!') return project_location = qdir.absolutePath() if not project_location.endsWith( '/') and not project_location.endsWith('\\'): project_location += os.sep project_location.replace('\\', '/') if project_name.isEmpty() or project_location.isEmpty(): QMessageBox.warning(self, '警告', '项目名称或路径不能为空!') return self.currentConfig.project_name = app.QString2str(project_name) self.currentConfig.project_location = app.QString2str(project_location) content = self.currentConfig.toJson() fileInfo = QFileInfo(self.path) if not self.path.isEmpty(): path = app.QString2str(self.path) with open(path, 'w+') as f: f.write(content) item = self.lw.currentItem() item.setData(QtCore.Qt.UserRole, content) template_name = self.currentConfig.template_source template_dir = app.g_pwd + os.sep + 'templates' + os.sep + template_name.encode( 'utf-8') with open(template_dir + os.sep + 'config.json', 'r') as f: self.currentConfig.config_content = f.read() ret_json = app.render(self.currentConfig.config_content, config=self.currentConfig) self.currentConfig.config = json.loads(ret_json) for file in self.currentConfig.config['files']: sourcepath = template_dir + os.sep + file['source'].encode('utf-8') targetdir = self.currentConfig.project_location + self.currentConfig.project_name targetpath = targetdir + os.sep + file['target'] fi = QFileInfo(targetpath) qdir = fi.absoluteDir() if not qdir.exists(): qdir.mkpath(fi.absolutePath()) with open(sourcepath, 'r') as f: content = f.read() content = app.render(content, config=self.currentConfig) #渲染文件 with open(targetpath, 'w+') as f: f.write(content.encode('utf-8')) QMessageBox.information(self, '提示', '生成成功!')
def __init__(self, file='settings'): """ @type file: string @param file: the prefix of the settings files used. Used for testing. """ userDir = QDir(os.path.expanduser('~')) userDir.cd('Application Data') or userDir.cd('AppData') or userDir.cd('Library') if not userDir.cd('BootTunes'): userDir.mkdir('BootTunes') userDir.cd('BootTunes') self.settingsDir = unicode(userDir.absolutePath()) basePath = unicode(userDir.absolutePath()) self.settingsPath = settingsPath = basePath + '/' + file + '-settings' self.defaultsPath = defaultsPath = basePath + '/' + file + '-defaults' self.namesPath = namesPath = basePath + '/' + file + '-names' self.completedPath = completedPath = basePath + '/' + file + '-completed' pathsAndProperties = [ (settingsPath, 'settings'), (defaultsPath, 'artistDefaults'), (namesPath, 'artistNames'), (completedPath, 'completed') ] for pathAndProperty in pathsAndProperties: filePath = pathAndProperty[0] property = pathAndProperty[1] setattr(self, property, {}) if os.path.exists(filePath): fileObj = codecs.open(filePath, 'r') try: setattr(self, property, cPickle.load(fileObj) or {}) except (cPickle.UnpicklingError, AttributeError, EOFError, ImportError, IndexError): pass fileObj.close()
def get_list_of_symbol_paths(symbolTopLevelPaths): """ Given a list of top level paths to directories containting sconcho kitting symbols returns a QStringList of all paths to individual sconcho patterns. """ symbolPaths = [] for path in symbolTopLevelPaths: aDir = QDir(path) for entry in aDir.entryList(QDir.AllDirs | QDir.NoDotAndDotDot): symbolPaths.append(aDir.absolutePath() + "/" + entry) return symbolPaths
def checkTempDir(): tempDir = QDir(WorkerPopulateGroup.TEMP_DIR) if not tempDir.exists(): msgtrans1 = QCoreApplication.translate( "CatalogOTF", "Created temporary directory '%s' for GDAL_WMS") msgtrans2 = QCoreApplication.translate( "CatalogOTF", "Not possible create temporary directory '%s' for GDAL_WMS" ) isOk = tempDir.mkpath(WorkerPopulateGroup.TEMP_DIR) msgtrans = msgtrans1 if isOk else msgtrans2 tempDir.setPath(WorkerPopulateGroup.TEMP_DIR) msg = msgtrans % tempDir.absolutePath() msgBar.pushMessage(NAME_PLUGIN, msg, QpluginNamegsMessageBar.CRITICAL, 5)
def on_gen(self): '''生成工程''' if not self.currentConfig: return #获取工程名及有效路径 project_name = self.et_project_name.text() project_location = self.et_project_location.text() qdir = QDir(project_location) if not qdir.exists(): if not qdir.mkpath(project_location): QMessageBox.warning(self, '警告', '路径无效!') return project_location = qdir.absolutePath() if not project_location.endsWith('/') and not project_location.endsWith('\\'): project_location += os.sep if project_name.isEmpty() or project_location.isEmpty(): QMessageBox.warning(self, '警告', '项目名称或路径不能为空!') return self.currentConfig.project_name = app.QString2str(project_name) self.currentConfig.project_location = app.QString2str(project_location) template_name = self.currentConfig.template_source template_dir = app.g_pwd + os.sep + 'templates' + os.sep + template_name with open(template_dir + os.sep + 'config.json', 'r') as f: self.currentConfig.config_content = f.read() ret_json = app.render(self.currentConfig.config_content, config=self.currentConfig) self.currentConfig.config = json.loads(ret_json) for file in self.currentConfig.config['files']: sourcepath = template_dir + os.sep + file['source'] targetdir = self.currentConfig.project_location + self.currentConfig.project_name targetpath = targetdir + os.sep + file['target'] fi = QFileInfo(targetpath) qdir = fi.absoluteDir() if not qdir.exists(): qdir.mkpath(fi.absolutePath()) with open(sourcepath, 'r') as f: content = f.read() content = app.render(content, config=self.currentConfig) #渲染文件 with open(targetpath, 'w+') as f: f.write(content.encode('utf-8')) QMessageBox.information(self,'提示','生成成功!')
def initialize_ui(self): global debug if debug: self.line.setMinimumSize(400, 30) self.line.setStyleSheet("font-size: 15px;") self.enterButton.resize(0, 0) self.enterButton.clicked.connect(self.press_enter) self.enterButton.setShortcut("Return") self.progressBar.setMaximumWidth(120) self.webView = QWebView(loadProgress=self.progressBar.setValue, loadFinished=self.progressBar.hide, loadStarted=self.progressBar.show, titleChanged=self.setWindowTitle) self.webView.setMinimumSize(400, 400) direct = QDir('resources/index.html') self.webView.load(QUrl('file:///' + direct.absolutePath())) self.webView.urlChanged.connect(self.update_url) self.webView.page().linkHovered.connect(self.show_link_hovered) grid = QGridLayout() if debug: grid.addWidget(self.line, 0, 3, 1, 1) grid.addWidget(self.webView, 2, 0, 1, 6) self.mainWidget.setLayout(grid) self.setGeometry(50, 50, 1360, 768) self.setWindowTitle("SRSS") self.statusBar.addPermanentWidget(self.progressBar) self.statusBar.hide() self.setCentralWidget(self.mainWidget)
class Folder(DataStore): """ Folder DataStore A folder based data store is a collection of shape files and tiff images stored in a common folder. .. versionadded:: 4.0 """ def __init__(self, uri): """ Constructor for the folder DataStore. :param uri: A directory object or the path to the folder :type uri: QDir, str .. versionadded:: 4.0 """ super(Folder, self).__init__(uri) self._default_vector_format = 'shp' if isinstance(uri, QDir): self._uri = uri elif isinstance(uri, basestring): self._uri = QDir(uri) else: raise ErrorDataStore('Unknown type') @property def default_vector_format(self): """Default vector format for the folder datastore. :return: The default vector format. :rtype: str. """ return self._default_vector_format @default_vector_format.setter def default_vector_format(self, default_format): """Set the default vector format for the folder datastore. :param default_format: The default output format. It can be 'shp', 'geojson' or 'kml'. :param default_format: str """ if default_format in VECTOR_EXTENSIONS: self._default_vector_format = default_format @property def uri_path(self): """Return the URI of the datastore as a path. It's not a layer URI. :return: The URI. :rtype: str .. versionadded:: 4.0 """ return self.uri.absolutePath() def is_writable(self): """Check if the folder is writable. :return: If it's writable or not. :rtype: bool .. versionadded:: 4.0 """ return QFileInfo(self._uri.absolutePath()).isWritable() def supports_rasters(self): """Check if we can support raster in the datastore. :return: If it's writable or not. :rtype: bool .. versionadded:: 4.0 """ return True def layers(self): """Return a list of layers available. :return: List of layers available in the datastore. :rtype: list .. versionadded:: 4.0 """ extensions = ['*.%s' % f for f in EXTENSIONS] self.uri.setNameFilters(extensions) files = self.uri.entryList() self.uri.setNameFilters('') files = human_sorting([QFileInfo(f).baseName() for f in files]) return files def layer_uri(self, layer_name): """Get layer URI. :param layer_name: The name of the layer to fetch. :type layer_name: str :return: The URI to the layer. :rtype: str .. versionadded:: 4.0 """ layers = self.layers() for layer, extension in product(layers, EXTENSIONS): one_file = QFileInfo(self.uri.filePath(layer + '.' + extension)) if one_file.exists(): if one_file.baseName() == layer_name: return one_file.absoluteFilePath() else: return None def _add_tabular_layer(self, tabular_layer, layer_name): """Add a tabular layer to the folder. :param tabular_layer: The layer to add. :type tabular_layer: QgsVectorLayer :param layer_name: The name of the layer in the datastore. :type layer_name: str :returns: A two-tuple. The first element will be True if we could add the layer to the datastore. The second element will be the layer name which has been used or the error message. :rtype: (bool, str) .. versionadded:: 4.0 """ output = QFileInfo(self.uri.filePath(layer_name + '.csv')) QgsVectorFileWriter.writeAsVectorFormat(tabular_layer, output.absoluteFilePath(), 'utf-8', None, 'CSV') assert output.exists() return True, output.baseName() def _add_vector_layer(self, vector_layer, layer_name): """Add a vector layer to the folder. :param vector_layer: The layer to add. :type vector_layer: QgsVectorLayer :param layer_name: The name of the layer in the datastore. :type layer_name: str :returns: A two-tuple. The first element will be True if we could add the layer to the datastore. The second element will be the layer name which has been used or the error message. :rtype: (bool, str) .. versionadded:: 4.0 """ if not self.is_writable(): return False, 'The destination is not writable.' output = QFileInfo( self.uri.filePath(layer_name + '.' + self._default_vector_format)) driver_mapping = { 'shp': 'ESRI Shapefile', 'kml': 'KML', 'geojson': 'GeoJSON', } QgsVectorFileWriter.writeAsVectorFormat( vector_layer, output.absoluteFilePath(), 'utf-8', vector_layer.crs(), driver_mapping[self._default_vector_format]) assert output.exists() return True, output.baseName() def _add_raster_layer(self, raster_layer, layer_name): """Add a raster layer to the folder. :param raster_layer: The layer to add. :type raster_layer: QgsRasterLayer :param layer_name: The name of the layer in the datastore. :type layer_name: str :returns: A two-tuple. The first element will be True if we could add the layer to the datastore. The second element will be the layer name which has been used or the error message. :rtype: (bool, str) .. versionadded:: 4.0 """ if not self.is_writable(): return False, 'The destination is not writable.' output = QFileInfo(self.uri.filePath(layer_name + '.tif')) source = QFileInfo(raster_layer.source()) if source.exists() and source.suffix() in ['tiff', 'tif']: # If it's tiff file based. QFile.copy(source.absoluteFilePath(), output.absoluteFilePath()) else: # If it's not file based. renderer = raster_layer.renderer() provider = raster_layer.dataProvider() crs = raster_layer.crs() pipe = QgsRasterPipe() pipe.set(provider.clone()) pipe.set(renderer.clone()) file_writer = QgsRasterFileWriter(output.absoluteFilePath()) file_writer.Mode(1) file_writer.writeRaster(pipe, provider.xSize(), provider.ySize(), provider.extent(), crs) del file_writer assert output.exists() return True, output.baseName()
class EasyImport: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join( self.plugin_dir, 'i18n', 'EasyImport_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = EasyImportDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&EasyImport') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'EasyImport') self.toolbar.setObjectName(u'EasyImport') # Root folder where shape files are stored self.shapeDirectory = QDir() # XML Config file self.configXML = QtXml.QDomDocument() # XML current Config self.currentConfigXML = QtXml.QDomElement() # XML Config path self.configFileName = 'config.xml' # Shape file dictionnary # shapeFiles[shape filename] = shapefile absolute path self.shapeFiles = {} # Shape file dictionnary # pointsLayersConfig[shape filename] = Import rules XML nodes self.pointsLayersConfig = {} # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('EasyImport', message) def add_action( self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu( self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/EasyImport/icon.png' self.add_action( icon_path, text=self.tr(u'EasyImport'), callback=self.run, parent=self.iface.mainWindow()) # Load settings from XML self.loadConfig() # Set event handlers self.dlg.btnBrowse.clicked.connect(self.setShapeDirectory) self.dlg.btnImport.clicked.connect(self.runImport) self.dlg.cbxConfig.currentIndexChanged.connect(self.cbxConfigChanged) self.dlg.txtDirectory.textEdited.connect(self.txtDirectoryChanged) def txtDirectoryChanged(self, text): self.shapeDirectory = QDir(text) self.getShapeFiles() def setShapeDirectory(self): """Display folder browser dialog.""" file = QFileDialog.getExistingDirectory(None, 'Select gps/shape file directory.') self.dlg.txtDirectory.setText(file) self.shapeDirectory = QDir(file) def cbxConfigChanged(self, id): """Reset config on configuration combox box changes.""" self.pointsLayersConfig.clear() self.setCurrentConfig(self.dlg.cbxConfig.itemData(id)) def getShapeFiles(self): """Get each shapefile in defined folder.""" self.shapeFiles.clear() shapefiles = self.shapeDirectory.entryList(['*.shp'],QDir.Files,QDir.Name) for file in shapefiles: # Populate the shape dictionnary self.shapeFiles[file.split('.',1)[0]] = file # print self.shapeFiles.keys() def removeShapeFiles(self, shapeFiles): """Removes generated shapefiles""" for code in shapeFiles.keys(): paths = str(self.shapeDirectory.absolutePath() + '/' + code + '.*') files = glob(paths) # print paths for file in files: os.remove(file) def getAsciiFiles(self): """Get each asciifile in defined folder.""" # self.asciiFiles.clear() asciifiles = self.shapeDirectory.entryList(['*.asc'],QDir.Files,QDir.Name) for file in asciifiles: # Convert into shapefile self.ascii2shape(file) def ascii2shape(self, file): """Convert every input from the ascii file to the corresponding shapefile and creates it if it does not exists yet. :param file: ascii file to be converted""" # Read ascii with open(self.shapeDirectory.absolutePath() + '/' + file,'r') as f: content = f.readlines() ind = 0 # Set spatial ref and driver driver = ogr.GetDriverByName('ESRI Shapefile') srs = osr.SpatialReference() epsg21781wkt = 'PROJCS["CH1903 / LV03",GEOGCS["CH1903",DATUM["CH1903",SPHEROID["Bessel 1841",6377397.155,299.1528128,AUTHORITY["EPSG","7004"]],TOWGS84[674.374,15.056,405.346,0,0,0,0],AUTHORITY["EPSG","6149"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4149"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Hotine_Oblique_Mercator"],PARAMETER["latitude_of_center",46.95240555555556],PARAMETER["longitude_of_center",7.439583333333333],PARAMETER["azimuth",90],PARAMETER["rectified_grid_angle",90],PARAMETER["scale_factor",1],PARAMETER["false_easting",600000],PARAMETER["false_northing",200000],AUTHORITY["EPSG","21781"],AXIS["Y",EAST],AXIS["X",NORTH]]' srs.ImportFromWkt(epsg21781wkt) # Start iteration on features for line in content: # Remove undesirables tabs and double spaces removedTabs = re.sub(r"\s+", " ", content[ind]) # split fields values line_fields = removedTabs.split(' ') # Avoid uncompleted lines if (len(line_fields)>4): # Create the dictionnary featureDict = ['GPSID','TYPE', 'CODE', 'Y', 'X', 'Z', 'DELTA', 'COMMENT'] # Extract the information featureDict[0] = str(line_fields[0]) # featureDict[0] = int(re.findall(r'\d+', line_fields[0])[0]) featureDict[1] = str(re.findall('[a-zA-Z]+', line_fields[0])[0]) try: featureDict[2] = int(line_fields[5]) except ValueError: featureDict[2] = 999 featureDict[3] = str(line_fields[1]) featureDict[4] = str(line_fields[2]) featureDict[5] = str(line_fields[3]) featureDict[6] = float(line_fields[4]) featureDict[7] = ' '.join(line_fields[6:]) ofilepath = self.shapeDirectory.absolutePath() + '/' + str(featureDict[2]) + '.shp' if not os.path.exists(ofilepath): dataSource = driver.CreateDataSource(ofilepath) olayer = dataSource.CreateLayer("points", srs, geom_type=ogr.wkbPoint25D) olayer.CreateField(ogr.FieldDefn("Point_ID", ogr.OFTString)) olayer.CreateField(ogr.FieldDefn("Ortho_Heig", ogr.OFTReal)) else: dataSource = driver.Open(ofilepath,1) olayer = dataSource.GetLayer() # print ofilepath # Set feature fields feature = ogr.Feature(olayer.GetLayerDefn()) feature.SetField("Point_ID", featureDict[0]) feature.SetField("Ortho_Heig", featureDict[5]) # Set geometry geom_wkt = 'POINT (' + featureDict[3] + ' ' + featureDict[4] + ' ' + featureDict[5] + ')' point = ogr.CreateGeometryFromWkt(geom_wkt) feature.SetGeometry(point) # Create feature olayer.CreateFeature(feature) # remove feature and datasource from memory feature.Destroy() dataSource.Destroy() # else: #additional behaviour in case of uncompleted line # increment ind+=1 def setCurrentConfig(self, idConfig): """Load configuration from XML based on configuration id. :param idConfig: configuration id's stored in XML. :type text: str """ # Get config node childrens if config id = idConfig root = self.configXML.documentElement() configs = root.elementsByTagName('config') for index in range(configs.count()): if configs.at(index).hasAttributes(): nodeAttributes = configs.at(index).attributes() if nodeAttributes.namedItem('id').nodeValue() == idConfig: self.currentConfigXML = configs.at(index) # Get all pointlayer nodes layerspoints = self.currentConfigXML.toElement().elementsByTagName('pointlayer') # Populate import rules (pointsLayersConfig) for index in range(layerspoints.count()): if layerspoints.at(index).hasAttributes(): self.pointsLayersConfig[layerspoints.at(index).toElement().attributeNode('code').value()] = layerspoints.at(index).toElement() def loadConfig(self): """Load configuration combobox with configurations stored in XML configuration file.""" XMLFile = QFile(self.plugin_dir + '/' + self.configFileName) if not XMLFile.open(QFile.ReadOnly | QFile.Text): QMessageBox.warning(self.iface.mainWindow(), "XML Configuration","Cannot read file %s:\n%s." % (self.plugin_dir + '/' + self.configFileName, XMLFile.errorString()),QMessageBox.Ok) return False ok, errorStr, errorLine, errorColumn = self.configXML.setContent(XMLFile, True) if not ok: QMessageBox.information(self.iface.mainWindow(), "XML Configuration","Parse error at line %d, column %d:\n%s" % (errorLine, errorColumn, errorStr)) return False root = self.configXML.documentElement() configs = root.elementsByTagName('config') for index in range(configs.count()): if configs.at(index).hasAttributes(): nodeAttributes = configs.at(index).attributes() self.dlg.cbxConfig.addItem(nodeAttributes.namedItem('name').nodeValue(), nodeAttributes.namedItem('id').nodeValue()) self.setCurrentConfig(self.dlg.cbxConfig.itemData(self.dlg.cbxConfig.currentIndex())) return True def runImport(self): self.getAsciiFiles() self.getShapeFiles() if len(self.shapeFiles) <= 0: QMessageBox.warning(self.iface.mainWindow(), "Shape import","No shape file found.") return #Shapefiles that match the config code codes = set(self.shapeFiles.keys()) & set(self.pointsLayersConfig.keys()) # Maximum value of progress bar is the number of shapefile self.dlg.pgbImport.setMaximum(len(codes)) # For each Shapefiles that match the config code for k in codes: # Import data based on config self.importData(self.shapeDirectory.absolutePath() + "/" + self.shapeFiles[k], k) # Increment progress bar self.dlg.pgbImport.setValue(self.dlg.pgbImport.value() + 1) self.removeShapeFiles(self.shapeFiles) def importData(self, filename, code): """Import data from shapefile to an specified layer in project. :param filename: shapefile filename. :type text: str :param code: shapefile name. :type text: str """ driver = ogr.GetDriverByName('ESRI Shapefile') layers = QgsMapLayerRegistry.instance().mapLayers() destinationlayer = None colunmMappingDict = {} staticMappingDict = {} regexMappingDict = {} destinationLayerName = self.pointsLayersConfig[code].elementsByTagName('destinationlayer').item(0).toElement().text() columnMappings = self.pointsLayersConfig[code].elementsByTagName('columnmapping') staticMappings = self.pointsLayersConfig[code].elementsByTagName('staticmapping') # No destination layer found in XML if destinationLayerName is None: return for k in layers.keys(): if layers[k].name() == destinationLayerName: destinationlayer = layers[k] # No destination layer found in QGis Project if destinationlayer is None: return dataSource = driver.Open(filename, 0) if dataSource is None: self.dlg.txtOut.appendPlainText('Could not open %s \n' % (filename)) else: self.dlg.txtOut.appendPlainText('Opened %s' % (filename)) layer = dataSource.GetLayer() featureCount = layer.GetFeatureCount() # Get import rules with column mappings for index in range(columnMappings.count()): sourcecolumnname = columnMappings.at(index).toElement().elementsByTagName('source').item(0).toElement().text() destinationcolumnname = columnMappings.at(index).toElement().elementsByTagName('destination').item(0).toElement().text() regex = columnMappings.at(index).toElement().elementsByTagName('regex') if not (regex is None): regexMappingDict[sourcecolumnname] = regex.item(0).toElement().text() colunmMappingDict[sourcecolumnname] = destinationcolumnname # Get import rules with static value mappings for index in range(staticMappings.count()): staticValue = staticMappings.at(index).toElement().elementsByTagName('value').item(0).toElement().text() destinationcolumnname = staticMappings.at(index).toElement().elementsByTagName('destination').item(0).toElement().text() staticMappingDict[destinationcolumnname] = staticValue # Enable edit mode on destination layer destinationlayer.startEditing() # Retrieve all column off destination layer fields = destinationlayer.pendingFields() # For each data in shapefile for feature in layer: #Create new feature in destination layer and get geometry from shapefile newFeature = QgsFeature(fields) newFeature.setGeometry(QgsGeometry.fromWkt(str(feature.GetGeometryRef()))) # For each column mapping for k in colunmMappingDict.keys(): # print "source %s -> destination %s" % (k,colunmMappingDict[k]) # With regex if regexMappingDict[k]: regexp = re.compile(regexMappingDict[k]) # print str(k) # print feature.GetField(str(k)) m = regexp.match(feature.GetField(str(k))) if not (m is None): # print 'Regex : %s --> Value : %s' % (regexMappingDict[k], m.group('group')) newFeature.setAttribute(fields.fieldNameIndex(colunmMappingDict[k]), m.group('group')) # Without regex else: newFeature.setAttribute(fields.fieldNameIndex(colunmMappingDict[k]), feature.GetField(str(k))) # For each static value mapping for k in staticMappingDict.keys(): #print "destination %s -> value %s" % (k,staticMappingDict[k]) newFeature.setAttribute(fields.fieldNameIndex(k), staticMappingDict[k]) # Add new feature in destination layer destinationlayer.addFeature(newFeature, True) self.dlg.txtOut.appendPlainText('Shape %s : %s features imported \n' % (code, featureCount)) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu( self.tr(u'&EasyImport'), action) self.iface.removeToolBarIcon(action) def run(self): """Run method that performs all the real work""" # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # Reset progress bar value self.dlg.pgbImport.setValue(0) # Reset output text box self.dlg.txtOut.clear() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass
class EkdSaveDialog(QDialog): ''' EkdSaveDialog : Classe représentant la boite de dialogue utiliser lors de l'enregistrement des modification sur un fichier donné attributs : suffix - Suffix utilisé en filtre filter - Filtre (déduit à partir du suffix) chemin - Chemin du dernier fichier enregistré multiple - va-t-on enregistrer plus d'un fichier ? (ex: extraction d'image d'une vidéo) méthodes : getFile - Invoque la boite de dialogue et retourne le fichier saisi ''' ### Pourquoi avoir réimplémenté cette classe au lieu de passer par ### QFileDialog ? ## Correction du bug de consommation mémoire ## ## Explication du problème : ## Par défaut un QFileDialog utilise un QFileSystemModel qui lui ## crée un QWatchFileSystem ## Hors QWatchFileSystem scan régulièrement les changement ## dans le répertoire courant ## Ce phénomène provoque une réaction en chaine : ## 1 - je choisi mon répertoire de destination d'enregistrement ## de mes images ## 2 - ffmpeg se lance ## 3 - ffmpeg crée un fichier dans l'arborescence ## 4 - QWatchFileSystem (est toujours dans le répertoire courant) ## détecte un changement ## et recharge l'ensemble du contenue du répertoire ## 5 - goto 3 jusqu'à plus de mémoire ou fin du process ffmpeg ## ## def __init__(self, parent, path = None, suffix = '', title = u"Sauver", multiple = False, mode = None): if type(suffix) == tuple or type(suffix) == list : sfilter="" for s in suffix : sfilter += "*"+s+" " self.filter=sfilter[:-1] # Si on a plusieur suffix, on prend le premier par défaut pour # la sauvegarde self.suffix = suffix[0] else : self.suffix = suffix self.filter = "*" + self.suffix QDialog.__init__(self, parent) self.setWindowTitle(title) self.multiple = multiple self.mode = mode if not path: if self.mode == "image" : path = EkdConfig.get("general", "image_output_path") elif self.mode == "video" : path = EkdConfig.get("general", "video_output_path") elif self.mode == "audio" : path = EkdConfig.get("general", "sound_output_path") else : path = unicode(QDir.homePath()) # Nom du répertoire courant self.location = QLabel("<b>%s</b>" % path) # Variable permettant de savoir à tout moment le répertoire courant. self.currentDir = path self.mkdirButton = QPushButton(u" Créer un répertoire") self.mkdirButton.setIcon(QIcon("Icones" + os.sep + "add_sub_task.png")) if int(EkdConfig.get("general", "show_hidden_files")) : #print "hidden shown" EkdPrint(u"hidden shown") shf = QDir.Hidden else : shf = QDir.Readable # Liste des fichiers self.dirList = QListView() sorting = QDir.DirsFirst if int(EkdConfig.get("general", "ignore_case")): sorting |= QDir.IgnoreCase self.sorting = sorting self.flags = QDir.Files | QDir.Readable | shf self.dirModel = QStandardItemModel() self.dirList.setModel(self.dirModel) self.updateDir(path) self.dirList.setWrapping(True) #panneau latéral self.dirTree = QTreeView() self.dirModelLight = QDirModel(QStringList(""), QDir.AllDirs | QDir.NoDotAndDotDot | shf, QDir.DirsFirst | QDir.Name | QDir.IgnoreCase) self.dirTree.setModel(self.dirModelLight) self.dirTree.setColumnHidden(1,True) self.dirTree.setColumnHidden(2,True) self.dirTree.setColumnHidden(3,True) self.dirTree.setMaximumWidth(200) self.dirTree.setMinimumWidth(150) self.dirTree.setCurrentIndex(self.dirModelLight.index(path)) self.dirTree.resizeColumnToContents(0) self.connect(self.dirTree, SIGNAL("pressed(QModelIndex)"), self.updateLatDir) self.connect(self.dirTree, SIGNAL("expanded(QModelIndex)"), self.treeMAJ) self.connect(self.dirTree, SIGNAL("collapsed(QModelIndex)"), self.treeMAJ) # Nom du fichier self.fileField = QLineEdit() # Nom du filtre self.filterField = QComboBox() self.filterField.addItems(QStringList(self.filter)) # Bouton de sauvegarde et d'annulation self.saveButton = QPushButton(_(u" Enregistrer")) self.saveButton.setIcon(QIcon("Icones" + os.sep + "action.png")) self.cancelButton = QPushButton(_(u" Annuler")) self.cancelButton.setIcon(QIcon("Icones" + os.sep + "annuler.png")) # Organisation des différents objets de la boite de dialogue self.layout = QHBoxLayout(self) self.layout.addWidget(self.dirTree) self.filelinelayout = QGridLayout() self.filelinelayout.addWidget(self.location, 0, 0, 1, 0) self.filelinelayout.addWidget(self.mkdirButton, 0, 2) self.filelinelayout.addWidget(self.dirList, 1, 0, 1, 0) self.filelinelayout.addWidget(QLabel(_("Nom de fichier : ")), 2, 0) self.filelinelayout.addWidget(self.fileField, 2, 1) self.filelinelayout.addWidget(self.saveButton, 2, 2) self.filelinelayout.addWidget(QLabel(_("Filtre extension : ")), 3, 0) self.filelinelayout.addWidget(self.filterField, 3, 1) self.filelinelayout.addWidget(self.cancelButton, 3, 2) self.layout.addLayout(self.filelinelayout) # Connexion des différents objets self.connect(self.dirList, SIGNAL("clicked(QModelIndex)"), self.updateFile) self.connect(self.saveButton, SIGNAL("clicked()"), self.accept) self.connect(self.cancelButton, SIGNAL("clicked()"), self.reject) self.connect(self.mkdirButton, SIGNAL("clicked()"), self.mkdir) self.connect(self.dirList, SIGNAL("indexesMoved (const QModelIndexList&)"), self.updateFile) self.connect(self.fileField, SIGNAL("textChanged (const QString&)"), self.activate) self.connect(self.fileField, SIGNAL("returnPressed()"), self.accept) # Taille minimum self.setMinimumSize(700, 480) # Par défaut, on désactive self.deactivate() # Completion des fichiers self.completion = QCompleter(self.dirModel, self.dirList) def updateLatDir(self, item) : """ Fonction permettant de naviguer dans la listes des répertoires """ self.updateDir(self.dirModelLight.filePath(item)) def treeMAJ(self, item) : self.dirTree.resizeColumnToContents(0) def activate(self, filename=None): """ Activation des boutton de sauvegarde """ self.dirList.clearSelection() if filename != "": self.saveButton.setEnabled(True) else: self.saveButton.setEnabled(False) def deactivate(self): """ Désactivation des boutton de sauvegarde """ self.saveButton.setEnabled(False) def updateDir(self, path = None): """ Fonction permettant de naviguer dans la listes des répertoires """ if path : self.currentDir = path self.location.setText("<b>%s</b>" % path) self.dirModel.clear() self.tmpdir = QDir() self.tmpdir.setPath(self.currentDir) self.tmpdir.setNameFilters(QStringList(self.filter)) # Une icône pour les images, un autre icône pour les vidéos, et # une pour audio if self.mode == "image" : icone = QIcon("Icones" + os.sep + "image_image.png") elif self.mode == "video" : icone = QIcon("Icones" + os.sep + "image_video.png") elif self.mode == "audio" : icone = QIcon("Icones" + os.sep + "image_audio.png") else: icone = QIcon("Icones" + os.sep + "image_default.png") for wlfile in self.tmpdir.entryList(QDir.Files): if self.mode == "image" : icone = QIcon(EkdPreview("Icones" + os.sep + "image_default.png").get_preview()) item = QStandardItem(icone, QString(wlfile)) item.setToolTip(wlfile) item.setData(QVariant(self.tmpdir.absolutePath() + os.sep + wlfile), Qt.UserRole + 2) item.setData(QVariant(wlfile), Qt.UserRole + 3) self.dirModel.appendRow(item) def updateFile(self, item): """ Fonction appelée par la listView lors d'un changement de repertoire""" # On récupère le QModel parent du QModelItem path = "%s" % item.data(Qt.UserRole + 2).toString() name = os.path.basename(path) self.fileField.selectAll() self.fileField.setFocus() self.fileField.setText(name) self.activate(name) def selectedFile(self): """ Renvoi le fichier selectionné pour la sauvegarde""" # Récupération du fichier selectionné fichier = self.fileField.text() output = "%s%s%s" % (self.currentDir, os.sep, fichier) info = QFileInfo(output) # Si l'utilisateur n'a pas spécifié de suffix, on l'ajoute if info.suffix() != self.suffix[1:]: output = "%s%s" % (output, self.suffix) return output def mkdir(self): """ Crée un répertoire dans le répertoire courant """ (dirname, ok) = QInputDialog.getText(self, _(u"Nouveau répertoire"), _(u"Nom du répertoire"), QLineEdit.Normal, _(u"Nouveau répertoire")) if ok : try : os.mkdir("%s%s%s" % (self.currentDir, os.sep,dirname)) #print u"Création de : %s%s%s" % (self.currentDir, os.sep, dirname) EkdPrint(u"Création de : %s%s%s" % (self.currentDir, os.sep, dirname)) self.updateDir() self.dirModelLight.refresh() except Exception, e: #print _(u"Impossible de crée un nouveau répertoire : %s" % e) EkdPrint(_(u"Impossible de crée un nouveau répertoire : %s" % e))
class Folder(DataStore): """ Folder DataStore A folder based data store is a collection of shape files and tiff images stored in a common folder. .. versionadded:: 4.0 """ def __init__(self, uri): """ Constructor for the folder DataStore. :param uri: A directory object or the path to the folder :type uri: QDir, str .. versionadded:: 4.0 """ super(Folder, self).__init__(uri) self._default_vector_format = 'shp' if isinstance(uri, QDir): self._uri = uri elif isinstance(uri, basestring): self._uri = QDir(uri) else: raise ErrorDataStore('Unknown type') @property def default_vector_format(self): """Default vector format for the folder datastore. :return: The default vector format. :rtype: str. """ return self._default_vector_format @default_vector_format.setter def default_vector_format(self, default_format): """Set the default vector format for the folder datastore. :param default_format: The default output format. It can be 'shp', 'geojson' or 'kml'. :param default_format: str """ if default_format in VECTOR_EXTENSIONS: self._default_vector_format = default_format @property def uri_path(self): """Return the URI of the datastore as a path. It's not a layer URI. :return: The URI. :rtype: str .. versionadded:: 4.0 """ return self.uri.absolutePath() def is_writable(self): """Check if the folder is writable. :return: If it's writable or not. :rtype: bool .. versionadded:: 4.0 """ return QFileInfo(self._uri.absolutePath()).isWritable() def supports_rasters(self): """Check if we can support raster in the datastore. :return: If it's writable or not. :rtype: bool .. versionadded:: 4.0 """ return True def layers(self): """Return a list of layers available. :return: List of layers available in the datastore. :rtype: list .. versionadded:: 4.0 """ extensions = ['*.%s' % f for f in EXTENSIONS] self.uri.setNameFilters(extensions) files = self.uri.entryList() self.uri.setNameFilters('') files = human_sorting([QFileInfo(f).baseName() for f in files]) return files def layer_uri(self, layer_name): """Get layer URI. :param layer_name: The name of the layer to fetch. :type layer_name: str :return: The URI to the layer. :rtype: str .. versionadded:: 4.0 """ layers = self.layers() for layer, extension in product(layers, EXTENSIONS): one_file = QFileInfo( self.uri.filePath(layer + '.' + extension)) if one_file.exists(): if one_file.baseName() == layer_name: return one_file.absoluteFilePath() else: return None def _add_tabular_layer(self, tabular_layer, layer_name): """Add a tabular layer to the folder. :param tabular_layer: The layer to add. :type tabular_layer: QgsVectorLayer :param layer_name: The name of the layer in the datastore. :type layer_name: str :returns: A two-tuple. The first element will be True if we could add the layer to the datastore. The second element will be the layer name which has been used or the error message. :rtype: (bool, str) .. versionadded:: 4.0 """ output = QFileInfo( self.uri.filePath(layer_name + '.csv')) QgsVectorFileWriter.writeAsVectorFormat( tabular_layer, output.absoluteFilePath(), 'utf-8', None, 'CSV') assert output.exists() return True, output.baseName() def _add_vector_layer(self, vector_layer, layer_name): """Add a vector layer to the folder. :param vector_layer: The layer to add. :type vector_layer: QgsVectorLayer :param layer_name: The name of the layer in the datastore. :type layer_name: str :returns: A two-tuple. The first element will be True if we could add the layer to the datastore. The second element will be the layer name which has been used or the error message. :rtype: (bool, str) .. versionadded:: 4.0 """ if not self.is_writable(): return False, 'The destination is not writable.' output = QFileInfo( self.uri.filePath(layer_name + '.' + self._default_vector_format)) driver_mapping = { 'shp': 'ESRI Shapefile', 'kml': 'KML', 'geojson': 'GeoJSON', } QgsVectorFileWriter.writeAsVectorFormat( vector_layer, output.absoluteFilePath(), 'utf-8', vector_layer.crs(), driver_mapping[self._default_vector_format]) assert output.exists() return True, output.baseName() def _add_raster_layer(self, raster_layer, layer_name): """Add a raster layer to the folder. :param raster_layer: The layer to add. :type raster_layer: QgsRasterLayer :param layer_name: The name of the layer in the datastore. :type layer_name: str :returns: A two-tuple. The first element will be True if we could add the layer to the datastore. The second element will be the layer name which has been used or the error message. :rtype: (bool, str) .. versionadded:: 4.0 """ if not self.is_writable(): return False, 'The destination is not writable.' output = QFileInfo(self.uri.filePath(layer_name + '.tif')) source = QFileInfo(raster_layer.source()) if source.exists() and source.suffix() in ['tiff', 'tif']: # If it's tiff file based. QFile.copy(source.absoluteFilePath(), output.absoluteFilePath()) else: # If it's not file based. renderer = raster_layer.renderer() provider = raster_layer.dataProvider() crs = raster_layer.crs() pipe = QgsRasterPipe() pipe.set(provider.clone()) pipe.set(renderer.clone()) file_writer = QgsRasterFileWriter(output.absoluteFilePath()) file_writer.Mode(1) file_writer.writeRaster( pipe, provider.xSize(), provider.ySize(), provider.extent(), crs) del file_writer assert output.exists() return True, output.baseName()
class Georeferencer(QObject): # Step enum Start = 0 Crop = 1 Translate = 2 Warp = 3 Overview = 4 Stop = 5 Step = [0, 1, 2, 3, 4, 5] Label = ['Start', 'Crop', 'Translate', 'Warp', 'Overview', 'Stop'] # Georeferencer.Step, ProcessStatus status = pyqtSignal(int, int) # Georeferencer.Step, Message error = pyqtSignal(int, str) def __init__(self, parent=None): super(Georeferencer, self).__init__(parent) # Internal variables self._debug = True self._gdalDir = QDir() self._step = 0 self._status = 0 self._translate = QFileInfo() self._warp = QFileInfo() self._overview = QFileInfo() self._command = '' self._args = '' self._process = QProcess() self._gc = Transform() self._rawFile = QFileInfo() self._pointFile = QFileInfo() self._cropFile = QFileInfo() self._translateFile = QFileInfo() self._geoFile = QFileInfo() tempDir = QDir.temp() self._cropFile.setFile( tempDir.absoluteFilePath('.ark_georef_crop.png')) self._translateFile = QFileInfo( tempDir.absoluteFilePath('.ark_georef_translate.tiff')) self._gdalDir = QDir(self.gdalPath()) if self._debug: debug('GDAL Path: ' + self._gdalDir.absolutePath()) self._translate.setFile(self._gdalDir, 'gdal_translate') self._warp.setFile(self._gdalDir, 'gdalwarp') self._overview.setFile(self._gdalDir, 'gdaladdo') if (not self._translate.exists() or not self._warp.exists() or not self._overview.exists()): self._signalError( 'GDAL commands not found, please ensure GDAL Tools plugin is installed and has correct path set!' ) return self._process.started.connect(self._processStarted) self._process.finished.connect(self._processFinished) self._process.error.connect(self._processError) self._process.readyReadStandardError.connect(self._processError) def step(self): return self._step def processStatus(self): return self._status def run(self, gc, rawFile, pointFile, geoFile): self._step = Georeferencer.Start if (not gc.isValid()): self._signalError('Invalid ground control points.') return self._gc = gc if (not rawFile.exists()): self._signalError('Raw file not found.') return self._rawFile = rawFile self._pointFile = pointFile self._geoFile = geoFile if not self._geoFile.absoluteDir().exists(): self._geoFile.absoluteDir().mkpath('.') if (self._debug): debug('Raw File: \'' + self._rawFile.absoluteFilePath() + '\'') debug('GCP File: \'' + self._pointFile.absoluteFilePath() + '\'') debug('Crop File: \'' + self._cropFile.absoluteFilePath() + '\'') debug('Translate File: \'' + self._translateFile.absoluteFilePath() + '\'') debug('Geo File: \'' + self._geoFile.absoluteFilePath() + '\'') QCoreApplication.processEvents() self._runCropStep() def _runCropStep(self): if self._debug: debug('Crop') self._step = Georeferencer.Crop self._args = [] self._command = '' pixmap = QPixmap(self._rawFile.absoluteFilePath()) if pixmap.isNull(): self._signalError('Loading of raw image failed.') return pixmap = pixmap.copy(0, 0, pixmap.width(), int(pixmap.height() * 0.84)) image = pixmap.toImage() if image.isNull(): self._signalError('Cropping of raw image failed.') return if not image.save(self._cropFile.absoluteFilePath(), 'PNG', 100): self._signalError('Saving of cropped image failed.') return self._signalStatus() self._runTranslateStep() def _formatGcp(self, point): point = self._gc.point(point) return "{0:f} {1:f} {2:f} {3:f}".format(point.raw().x(), point.raw().y(), point.map().x(), point.map().y()) def _runTranslateStep(self): self._step = Georeferencer.Translate self._args = [] self._args.extend(['-of', 'GTiff']) self._args.extend(['-a_srs', self._gc.crs]) # self._args.extend(['-gcp', self._formatGcp(1)]) # self._args.extend(['-gcp', self._formatGcp(2)]) # self._args.extend(['-gcp', self._formatGcp(3)]) # self._args.extend(['-gcp', self._formatGcp(4)]) self._args.extend([ '-gcp', str(self._gc.point(1).raw().x()), str(self._gc.point(1).raw().y()), str(self._gc.point(1).map().x()), str(self._gc.point(1).map().y()) ]) self._args.extend([ '-gcp', str(self._gc.point(2).raw().x()), str(self._gc.point(2).raw().y()), str(self._gc.point(2).map().x()), str(self._gc.point(2).map().y()) ]) self._args.extend([ '-gcp', str(self._gc.point(3).raw().x()), str(self._gc.point(3).raw().y()), str(self._gc.point(3).map().x()), str(self._gc.point(3).map().y()) ]) self._args.extend([ '-gcp', str(self._gc.point(4).raw().x()), str(self._gc.point(4).raw().y()), str(self._gc.point(4).map().x()), str(self._gc.point(4).map().y()) ]) self._args.append(self._cropFile.absoluteFilePath()) self._args.append(self._translateFile.absoluteFilePath()) self._command = self._translate.absoluteFilePath() + ' ' + ' '.join( self._args) self._process.start(self._translate.absoluteFilePath(), self._args) def _runWarpStep(self): self._step = Georeferencer.Warp self._args = [] self._args.extend(['-order', '1']) self._args.extend(['-r', 'cubic']) self._args.extend(['-t_srs', self._gc.crs]) self._args.extend(['-of', 'GTiff']) self._args.extend(['-co', 'COMPRESS=JPEG']) self._args.extend(['-co', 'JPEG_QUALITY=50']) self._args.extend(['-co', 'TILED=YES']) self._args.append('-dstalpha') self._args.append('-overwrite') self._args.append('\"' + self._translateFile.absoluteFilePath() + '\"') self._args.append('\"' + self._geoFile.absoluteFilePath() + '\"') self._command = self._warp.absoluteFilePath() + ' ' + ' '.join( self._args) self._process.start(self._command) def _runOverviewStep(self): self._step = Georeferencer.Overview self._args = [] self._args.extend(['--config', 'COMPRESS_OVERVIEW JPEG']) self._args.extend(['--config', 'INTERLEAVE_OVERVIEW PIXEL']) self._args.extend(['-r', 'cubic']) self._args.append('\"' + self._geoFile.absoluteFilePath() + '\"') self._args.append('2 4 8 16') self._command = self._overview.absoluteFilePath() + ' ' + ' '.join( self._args) self._process.start(self._command) def _processStarted(self): self._status = ProcessStatus.Running self._signalStatus() if self._debug: debug(self.Label[self._step]) debug(self._command) def _processFinished(self): self._status = ProcessStatus.Success self._signalStatus() if (self._step == Georeferencer.Translate): self._runWarpStep() elif (self._step == Georeferencer.Warp): self._runOverviewStep() elif (self._step == Georeferencer.Overview): self.writeGcpFile(self._gc, self._pointFile.absoluteFilePath()) self._step = Georeferencer.Stop self._signalStatus() def _processError(self): self._status = ProcessStatus.Failure msg = str(self._process.readAllStandardError()) debug(msg) self._signalError(msg) def _signalStatus(self): self.status.emit(self._step, self._status) def _signalError(self, msg): self.error.emit(self._step, msg) @staticmethod def gdalPath(): return QSettings().value('/GdalTools/gdalPath', '/usr/bin') @staticmethod def loadGcpFile(path): inFile = QFile(path) if (not inFile.open(QIODevice.ReadOnly | QIODevice.Text)): return 'ERROR: Unable to open GCP file for reading' inStream = QTextStream(inFile) line = inStream.readLine() # Skip the header line if found if (line == 'mapX,mapY,pixelX,pixelY,enable'): line = inStream.readLine() lines = 0 gc = Transform() while (line): lines += 1 vals = line.split(',') if (len(vals) != 5): return None map = QgsPoint(float(vals[0]), float(vals[1])) raw = QPointF(float(vals[2]), float(vals[3])) enabled = bool(vals[4]) point = GroundControlPoint(raw, map, enabled) gc.setPoint(lines, point) line = inStream.readLine() inFile.close() return gc @staticmethod def writeGcpFile(gc, path): outFile = QFile(path) if (not outFile.open(QIODevice.WriteOnly | QIODevice.Text)): return 'Unable to open GCP file for writing' outStream = QTextStream(outFile) outStream << gc.asCsv() outFile.close()
class EasyImport: """QGIS Plugin Implementation.""" def __init__(self, iface): """Constructor. :param iface: An interface instance that will be passed to this class which provides the hook by which you can manipulate the QGIS application at run time. :type iface: QgsInterface """ # Save reference to the QGIS interface self.iface = iface # initialize plugin directory self.plugin_dir = os.path.dirname(__file__) # initialize locale locale = QSettings().value('locale/userLocale')[0:2] locale_path = os.path.join(self.plugin_dir, 'i18n', 'EasyImport_{}.qm'.format(locale)) if os.path.exists(locale_path): self.translator = QTranslator() self.translator.load(locale_path) if qVersion() > '4.3.3': QCoreApplication.installTranslator(self.translator) # Create the dialog (after translation) and keep reference self.dlg = EasyImportDialog() # Declare instance attributes self.actions = [] self.menu = self.tr(u'&EasyImport') # TODO: We are going to let the user set this up in a future iteration self.toolbar = self.iface.addToolBar(u'EasyImport') self.toolbar.setObjectName(u'EasyImport') # Root folder where shape files are stored self.shapeDirectory = QDir() # XML Config file self.configXML = QtXml.QDomDocument() # XML current Config self.currentConfigXML = QtXml.QDomElement() # XML Config path self.configFileName = 'config.xml' # Shape file dictionnary # shapeFiles[shape filename] = shapefile absolute path self.shapeFiles = {} # Shape file dictionnary # pointsLayersConfig[shape filename] = Import rules XML nodes self.pointsLayersConfig = {} # noinspection PyMethodMayBeStatic def tr(self, message): """Get the translation for a string using Qt translation API. We implement this ourselves since we do not inherit QObject. :param message: String for translation. :type message: str, QString :returns: Translated version of message. :rtype: QString """ # noinspection PyTypeChecker,PyArgumentList,PyCallByClass return QCoreApplication.translate('EasyImport', message) def add_action(self, icon_path, text, callback, enabled_flag=True, add_to_menu=True, add_to_toolbar=True, status_tip=None, whats_this=None, parent=None): """Add a toolbar icon to the toolbar. :param icon_path: Path to the icon for this action. Can be a resource path (e.g. ':/plugins/foo/bar.png') or a normal file system path. :type icon_path: str :param text: Text that should be shown in menu items for this action. :type text: str :param callback: Function to be called when the action is triggered. :type callback: function :param enabled_flag: A flag indicating if the action should be enabled by default. Defaults to True. :type enabled_flag: bool :param add_to_menu: Flag indicating whether the action should also be added to the menu. Defaults to True. :type add_to_menu: bool :param add_to_toolbar: Flag indicating whether the action should also be added to the toolbar. Defaults to True. :type add_to_toolbar: bool :param status_tip: Optional text to show in a popup when mouse pointer hovers over the action. :type status_tip: str :param parent: Parent widget for the new action. Defaults None. :type parent: QWidget :param whats_this: Optional text to show in the status bar when the mouse pointer hovers over the action. :returns: The action that was created. Note that the action is also added to self.actions list. :rtype: QAction """ icon = QIcon(icon_path) action = QAction(icon, text, parent) action.triggered.connect(callback) action.setEnabled(enabled_flag) if status_tip is not None: action.setStatusTip(status_tip) if whats_this is not None: action.setWhatsThis(whats_this) if add_to_toolbar: self.toolbar.addAction(action) if add_to_menu: self.iface.addPluginToMenu(self.menu, action) self.actions.append(action) return action def initGui(self): """Create the menu entries and toolbar icons inside the QGIS GUI.""" icon_path = ':/plugins/EasyImport/icon.png' self.add_action(icon_path, text=self.tr(u'EasyImport'), callback=self.run, parent=self.iface.mainWindow()) # Load settings from XML self.loadConfig() # Set event handlers self.dlg.btnBrowse.clicked.connect(self.setShapeDirectory) self.dlg.btnImport.clicked.connect(self.runImport) self.dlg.cbxConfig.currentIndexChanged.connect(self.cbxConfigChanged) self.dlg.txtDirectory.textEdited.connect(self.txtDirectoryChanged) def txtDirectoryChanged(self, text): self.shapeDirectory = QDir(text) self.getShapeFiles() def setShapeDirectory(self): """Display folder browser dialog.""" file = QFileDialog.getExistingDirectory( None, 'Select gps/shape file directory.') self.dlg.txtDirectory.setText(file) self.shapeDirectory = QDir(file) def cbxConfigChanged(self, id): """Reset config on configuration combox box changes.""" self.pointsLayersConfig.clear() self.setCurrentConfig(self.dlg.cbxConfig.itemData(id)) def getShapeFiles(self): """Get each shapefile in defined folder.""" self.shapeFiles.clear() shapefiles = self.shapeDirectory.entryList(['*.shp'], QDir.Files, QDir.Name) for file in shapefiles: # Populate the shape dictionnary self.shapeFiles[file.split('.', 1)[0]] = file # print self.shapeFiles.keys() def removeShapeFiles(self, shapeFiles): """Removes generated shapefiles""" for code in shapeFiles.keys(): paths = str(self.shapeDirectory.absolutePath() + '/' + code + '.*') files = glob(paths) # print paths for file in files: os.remove(file) def getAsciiFiles(self): """Get each asciifile in defined folder.""" # self.asciiFiles.clear() asciifiles = self.shapeDirectory.entryList(['*.asc'], QDir.Files, QDir.Name) for file in asciifiles: # Convert into shapefile self.ascii2shape(file) def ascii2shape(self, file): """Convert every input from the ascii file to the corresponding shapefile and creates it if it does not exists yet. :param file: ascii file to be converted""" # Read ascii with open(self.shapeDirectory.absolutePath() + '/' + file, 'r') as f: content = f.readlines() ind = 0 # Set spatial ref and driver driver = ogr.GetDriverByName('ESRI Shapefile') srs = osr.SpatialReference() epsg21781wkt = 'PROJCS["CH1903 / LV03",GEOGCS["CH1903",DATUM["CH1903",SPHEROID["Bessel 1841",6377397.155,299.1528128,AUTHORITY["EPSG","7004"]],TOWGS84[674.374,15.056,405.346,0,0,0,0],AUTHORITY["EPSG","6149"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.01745329251994328,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4149"]],UNIT["metre",1,AUTHORITY["EPSG","9001"]],PROJECTION["Hotine_Oblique_Mercator"],PARAMETER["latitude_of_center",46.95240555555556],PARAMETER["longitude_of_center",7.439583333333333],PARAMETER["azimuth",90],PARAMETER["rectified_grid_angle",90],PARAMETER["scale_factor",1],PARAMETER["false_easting",600000],PARAMETER["false_northing",200000],AUTHORITY["EPSG","21781"],AXIS["Y",EAST],AXIS["X",NORTH]]' srs.ImportFromWkt(epsg21781wkt) # Start iteration on features for line in content: # Remove undesirables tabs and double spaces removedTabs = re.sub(r"\s+", " ", content[ind]) # split fields values line_fields = removedTabs.split(' ') # Avoid uncompleted lines if (len(line_fields) > 4): # Create the dictionnary featureDict = [ 'GPSID', 'TYPE', 'CODE', 'Y', 'X', 'Z', 'DELTA', 'COMMENT' ] # Extract the information featureDict[0] = str(line_fields[0]) # featureDict[0] = int(re.findall(r'\d+', line_fields[0])[0]) featureDict[1] = str( re.findall('[a-zA-Z]+', line_fields[0])[0]) try: featureDict[2] = int(line_fields[5]) except ValueError: featureDict[2] = 999 featureDict[3] = str(line_fields[1]) featureDict[4] = str(line_fields[2]) featureDict[5] = str(line_fields[3]) featureDict[6] = float(line_fields[4]) featureDict[7] = ' '.join(line_fields[6:]) ofilepath = self.shapeDirectory.absolutePath() + '/' + str( featureDict[2]) + '.shp' if not os.path.exists(ofilepath): dataSource = driver.CreateDataSource(ofilepath) olayer = dataSource.CreateLayer("points", srs, geom_type=ogr.wkbPoint25D) olayer.CreateField(ogr.FieldDefn("Point_ID", ogr.OFTString)) olayer.CreateField(ogr.FieldDefn("Ortho_Heig", ogr.OFTReal)) else: dataSource = driver.Open(ofilepath, 1) olayer = dataSource.GetLayer() # print ofilepath # Set feature fields feature = ogr.Feature(olayer.GetLayerDefn()) feature.SetField("Point_ID", featureDict[0]) feature.SetField("Ortho_Heig", featureDict[5]) # Set geometry geom_wkt = 'POINT (' + featureDict[3] + ' ' + featureDict[ 4] + ' ' + featureDict[5] + ')' point = ogr.CreateGeometryFromWkt(geom_wkt) feature.SetGeometry(point) # Create feature olayer.CreateFeature(feature) # remove feature and datasource from memory feature.Destroy() dataSource.Destroy() # else: #additional behaviour in case of uncompleted line # increment ind += 1 def setCurrentConfig(self, idConfig): """Load configuration from XML based on configuration id. :param idConfig: configuration id's stored in XML. :type text: str """ # Get config node childrens if config id = idConfig root = self.configXML.documentElement() configs = root.elementsByTagName('config') for index in range(configs.count()): if configs.at(index).hasAttributes(): nodeAttributes = configs.at(index).attributes() if nodeAttributes.namedItem('id').nodeValue() == idConfig: self.currentConfigXML = configs.at(index) # Get all pointlayer nodes layerspoints = self.currentConfigXML.toElement().elementsByTagName( 'pointlayer') # Populate import rules (pointsLayersConfig) for index in range(layerspoints.count()): if layerspoints.at(index).hasAttributes(): self.pointsLayersConfig[layerspoints.at( index).toElement().attributeNode( 'code').value()] = layerspoints.at(index).toElement() def loadConfig(self): """Load configuration combobox with configurations stored in XML configuration file.""" XMLFile = QFile(self.plugin_dir + '/' + self.configFileName) if not XMLFile.open(QFile.ReadOnly | QFile.Text): QMessageBox.warning( self.iface.mainWindow(), "XML Configuration", "Cannot read file %s:\n%s." % (self.plugin_dir + '/' + self.configFileName, XMLFile.errorString()), QMessageBox.Ok) return False ok, errorStr, errorLine, errorColumn = self.configXML.setContent( XMLFile, True) if not ok: QMessageBox.information( self.iface.mainWindow(), "XML Configuration", "Parse error at line %d, column %d:\n%s" % (errorLine, errorColumn, errorStr)) return False root = self.configXML.documentElement() configs = root.elementsByTagName('config') for index in range(configs.count()): if configs.at(index).hasAttributes(): nodeAttributes = configs.at(index).attributes() self.dlg.cbxConfig.addItem( nodeAttributes.namedItem('name').nodeValue(), nodeAttributes.namedItem('id').nodeValue()) self.setCurrentConfig( self.dlg.cbxConfig.itemData(self.dlg.cbxConfig.currentIndex())) return True def runImport(self): self.getAsciiFiles() self.getShapeFiles() if len(self.shapeFiles) <= 0: QMessageBox.warning(self.iface.mainWindow(), "Shape import", "No shape file found.") return #Shapefiles that match the config code codes = set(self.shapeFiles.keys()) & set( self.pointsLayersConfig.keys()) # Maximum value of progress bar is the number of shapefile self.dlg.pgbImport.setMaximum(len(codes)) # For each Shapefiles that match the config code for k in codes: # Import data based on config self.importData( self.shapeDirectory.absolutePath() + "/" + self.shapeFiles[k], k) # Increment progress bar self.dlg.pgbImport.setValue(self.dlg.pgbImport.value() + 1) self.removeShapeFiles(self.shapeFiles) def importData(self, filename, code): """Import data from shapefile to an specified layer in project. :param filename: shapefile filename. :type text: str :param code: shapefile name. :type text: str """ driver = ogr.GetDriverByName('ESRI Shapefile') layers = QgsMapLayerRegistry.instance().mapLayers() destinationlayer = None colunmMappingDict = {} staticMappingDict = {} regexMappingDict = {} destinationLayerName = self.pointsLayersConfig[code].elementsByTagName( 'destinationlayer').item(0).toElement().text() columnMappings = self.pointsLayersConfig[code].elementsByTagName( 'columnmapping') staticMappings = self.pointsLayersConfig[code].elementsByTagName( 'staticmapping') # No destination layer found in XML if destinationLayerName is None: return for k in layers.keys(): if layers[k].name() == destinationLayerName: destinationlayer = layers[k] # No destination layer found in QGis Project if destinationlayer is None: return dataSource = driver.Open(filename, 0) if dataSource is None: self.dlg.txtOut.appendPlainText('Could not open %s \n' % (filename)) else: self.dlg.txtOut.appendPlainText('Opened %s' % (filename)) layer = dataSource.GetLayer() featureCount = layer.GetFeatureCount() # Get import rules with column mappings for index in range(columnMappings.count()): sourcecolumnname = columnMappings.at(index).toElement( ).elementsByTagName('source').item(0).toElement().text() destinationcolumnname = columnMappings.at(index).toElement( ).elementsByTagName('destination').item(0).toElement().text() regex = columnMappings.at(index).toElement().elementsByTagName( 'regex') if not (regex is None): regexMappingDict[sourcecolumnname] = regex.item( 0).toElement().text() colunmMappingDict[sourcecolumnname] = destinationcolumnname # Get import rules with static value mappings for index in range(staticMappings.count()): staticValue = staticMappings.at(index).toElement( ).elementsByTagName('value').item(0).toElement().text() destinationcolumnname = staticMappings.at(index).toElement( ).elementsByTagName('destination').item(0).toElement().text() staticMappingDict[destinationcolumnname] = staticValue # Enable edit mode on destination layer destinationlayer.startEditing() # Retrieve all column off destination layer fields = destinationlayer.pendingFields() # For each data in shapefile for feature in layer: #Create new feature in destination layer and get geometry from shapefile newFeature = QgsFeature(fields) newFeature.setGeometry( QgsGeometry.fromWkt(str(feature.GetGeometryRef()))) # For each column mapping for k in colunmMappingDict.keys(): # print "source %s -> destination %s" % (k,colunmMappingDict[k]) # With regex if regexMappingDict[k]: regexp = re.compile(regexMappingDict[k]) # print str(k) # print feature.GetField(str(k)) m = regexp.match(feature.GetField(str(k))) if not (m is None): # print 'Regex : %s --> Value : %s' % (regexMappingDict[k], m.group('group')) newFeature.setAttribute( fields.fieldNameIndex(colunmMappingDict[k]), m.group('group')) # Without regex else: newFeature.setAttribute( fields.fieldNameIndex(colunmMappingDict[k]), feature.GetField(str(k))) # For each static value mapping for k in staticMappingDict.keys(): #print "destination %s -> value %s" % (k,staticMappingDict[k]) newFeature.setAttribute(fields.fieldNameIndex(k), staticMappingDict[k]) # Add new feature in destination layer destinationlayer.addFeature(newFeature, True) self.dlg.txtOut.appendPlainText('Shape %s : %s features imported \n' % (code, featureCount)) def unload(self): """Removes the plugin menu item and icon from QGIS GUI.""" for action in self.actions: self.iface.removePluginMenu(self.tr(u'&EasyImport'), action) self.iface.removeToolBarIcon(action) def run(self): """Run method that performs all the real work""" # show the dialog self.dlg.show() # Run the dialog event loop result = self.dlg.exec_() # Reset progress bar value self.dlg.pgbImport.setValue(0) # Reset output text box self.dlg.txtOut.clear() # See if OK was pressed if result: # Do something useful here - delete the line containing pass and # substitute with your code. pass