def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.showTabs(show=False) #setting the sql generator self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.checkSuperUser) self.serverWidget.abstractDbLoaded.connect( self.populateOtherInterfaces) self.dbsCustomSelector.setTitle(self.tr('Server Databases')) self.dbsCustomSelector.selectionChanged.connect(self.showTabs) self.dbsCustomSelector.selectionChanged.connect( self.populateStylesInterface) self.dbsCustomSelector.selectionChanged.connect( self.populateOtherInterfaces) self.previousTab = 0 self.dbDict = {'2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': []} self.correspondenceDict = { self.tr('Load Database Model EDGV Version 2.1.3'): '2.1.3', self.tr('Load Database Model EDGV Version FTer_2a_Ed'): 'FTer_2a_Ed', self.tr('Load Other Database Models'): 'Non_EDGV' }
def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.dbFactory = DbFactory()
def __init__(self, parent=None): super(ConnectionComboBox, self).__init__(parent) self.parent = parent self.abstractDb = None self.abstractDbFactory = DbFactory() self.serverAbstractDb = None self.displayDict = {'2.1.3':'EDGV 2.1.3', 'FTer_2a_Ed':'EDGV FTer 2a Ed', 'Non_EDGV':self.tr('Other database model')} self.lineEdit().setPlaceholderText(self.tr('Select a database')) self.currentIndexChanged.connect(self.loadDatabase) self.instantiateAbstractDb = False
def instantiateAdminDb(self, serverAbstractDb): """ Instantiates dsgtools_admindb in the same server as serverAbstractDb. If dsgtools_admindb does not exists, instantiateAdminDb calls createAdminDb """ (host, port, user, password) = serverAbstractDb.getParamsFromConectedDb() adminDb = DbFactory().createDbFactory('QPSQL') if not serverAbstractDb.hasAdminDb(): return self.createAdminDb(serverAbstractDb, adminDb, host, port, user, password) adminDb.connectDatabaseWithParameters(host, port, 'dsgtools_admindb', user, password) return adminDb
def instantiateAbstractDb(self, dbName): """ Instantiates an abstractDb. """ if dbName not in self.dbDict.keys(): (host, port, user, password) = self.serverAbstractDb.getParamsFromConectedDb() abstractDb = DbFactory().createDbFactory('QPSQL') abstractDb.connectDatabaseWithParameters(host, port, dbName, user, password) else: abstractDb = self.dbDict[dbName] return abstractDb
def __init__(self, iface, parent=None): '''Constructor.''' super(ViewServers, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self.abstractDbFactory = DbFactory() self.initGui()
def __init__(self, parent=None): """ Constructor. """ super(PostgisDbThread, self).__init__() self.factory = SqlGeneratorFactory() #setting the sql generator self.gen = self.factory.createSqlGenerator(False) self.messenger = PostgisDbMessages(self) self.dbFactory = DbFactory() self.parent = parent
def __init__(self, iface, parent=None): """ Constructor """ super(StyleManagerTool, self).__init__(parent) self.setupUi(self) self.iface = iface self.splitter.hide() self.refreshDb() self.dbFactory = DbFactory() self.applyPushButton.setEnabled(False) self.utils = Utils()
def __init__(self, parent=None): """ Constructor """ super(CreateProfile, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.folder = os.path.join(os.path.dirname(__file__), 'profiles') self.abstractDb = None self.abstractDbFactory = DbFactory() self.populateTreeDict()
def __init__(self, createParam, parentWidget = None): super(DbCreator,self).__init__() self.dbFactory = DbFactory() self.parentWidget = parentWidget if isinstance(createParam, unicode): self.outputDir = createParam if isinstance(createParam, AbstractDb): self.abstractDb = createParam self.scaleMIDict = {1:'100k',2:'50k',3:'25k',4:'10k',5:'5k',6:'2k',7:'1k'}
def __init__(self, iface, parent=None): """Constructor.""" super(ComplexWindow, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self.dbButton.clicked.connect(self.getDataSources) self.dbCombo.activated.connect(self.updateComplexClass) self.complexCombo.activated.connect(self.loadAssociatedFeatures) self.iface.newProjectCreated.connect(self.clearDock) self.abstractDb = None self.databases = None self.abstractDbFactory = DbFactory()
def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.localDb = None self.serverWidget.populateServersCombo() #signal connections self.serverWidget.abstractDbLoaded.connect(self.checkSuperUser) self.serverWidget.clearWidgets.connect(self.clearAll) self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.treeWidget.customContextMenuRequested.connect( self.createMenuAssigned)
def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.dbFactory = DbFactory()
def setInitialState(self): self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = True self.tabWidget.setCurrentIndex(0) self.abstractDbFactory = DbFactory() self.utils = Utils() #populating the postgis combobox self.comboBoxPostgis.setCurrentIndex(0) self.populatePostGISConnectionsCombo() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True)
def __init__(self, parent = None): """ Constructor. """ super(PostgisDbThread, self).__init__() self.factory = SqlGeneratorFactory() #setting the sql generator self.gen = self.factory.createSqlGenerator(False) self.messenger = PostgisDbMessages(self) self.dbFactory = DbFactory() self.parent = parent
def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.populatePostgisSelector) self.customFileSelector.filesSelected.connect(self.populateSpatialiteSelector) self.comboDict = {self.tr('Load Database Model EDGV Version 2.1.3'):'2.1.3', self.tr('Load Database Model EDGV Version FTer_2a_Ed'):'FTer_2a_Ed',self.tr('Load Other Database Models'):'Non_EDGV'} self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[]} self.selectedDbsDict = dict() self.stylesDict = dict() self.postgisCustomSelector.selectionChanged.connect(self.selectedDatabases) self.spatialiteCustomSelector.selectionChanged.connect(self.selectedFiles) self.path = None self.customFileSelector.setCaption(self.tr('Select a DSGTools Spatialite file')) self.customFileSelector.setFilter(self.tr('Spatialite file databases (*.sqlite)')) self.customFileSelector.setType('multi') self.edgvType = None
def __init__(self, iface, parent = None): """ Constructor """ super(StyleManagerTool, self).__init__(parent) self.setupUi(self) self.iface = iface self.splitter.hide() self.refreshDb() self.dbFactory = DbFactory() self.applyPushButton.setEnabled(False) self.utils = Utils()
def clearAll(self): """ Resets the initial state """ self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = False self.abstractDbFactory = DbFactory() self.utils = Utils() #populating the postgis combobox self.comboBoxPostgis.clear() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True)
def getDatabase(self, database='postgres'): """ Gets a a QSqlDatabase """ (host, port, user, password) = self.getServerConfiguration( self.serversCombo.currentText()) self.abstractDb = DbFactory().createDbFactory('QPSQL') if password == '': conInfo = 'host=' + host + ' port=' + port + ' dbname=' + database self.setCredentials(self.abstractDb.db, conInfo, user) else: self.abstractDb.connectDatabaseWithParameters( host, port, database, user, password) if not self.abstractDb.db.open(): QgsMessageLog.logMessage(self.abstractDb.db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return self.abstractDb
def __init__(self, parent = None): """Constructor.""" super(CreateProfile, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.folder = os.path.join(os.path.dirname(__file__), 'profiles') self.abstractDb = None self.abstractDbFactory = DbFactory() self.populateTreeDict()
def __init__(self, permissionManager, abstractDb, parent=None): """ Constructor """ super(CreateProfileWithProfileManager, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.permissionManager = permissionManager self.abstractDb = abstractDb self.abstractDbFactory = DbFactory() self.populateTreeDict()
def getDatabase(self, database = 'postgres'): """ Gets a a QSqlDatabase """ (host, port, user, password) = self.getServerConfiguration(self.serversCombo.currentText()) self.abstractDb = DbFactory().createDbFactory('QPSQL') if password == '': conInfo = 'host='+host+' port='+port+' dbname='+database self.setCredentials(self.abstractDb.db, conInfo, user) else: self.abstractDb.connectDatabaseWithParameters(host, port, database, user, password) if not self.abstractDb.db.open(): QgsMessageLog.logMessage(self.abstractDb.db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return self.abstractDb
def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.showTabs(show = False) #setting the sql generator self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.checkSuperUser) self.serverWidget.abstractDbLoaded.connect(self.populateOtherInterfaces) self.dbsCustomSelector.setTitle(self.tr('Server Databases')) self.dbsCustomSelector.selectionChanged.connect(self.showTabs) self.dbsCustomSelector.selectionChanged.connect(self.populateStylesInterface) self.dbsCustomSelector.selectionChanged.connect(self.populateOtherInterfaces) self.previousTab = 0 self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[], '3.0':[]} self.correspondenceDict = {self.tr('Load Database Model EDGV Version 2.1.3'):'2.1.3', self.tr('Load Database Model EDGV Version 3.0'):'3.0', self.tr('Load Database Model EDGV Version FTer_2a_Ed'):'FTer_2a_Ed',self.tr('Load Other Database Models'):'Non_EDGV'}
def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.populatePostgisSelector) self.customFileSelector.filesSelected.connect(self.populateSpatialiteSelector) self.comboDict = {self.tr('Load Database Model EDGV Version 2.1.3'):'2.1.3', self.tr('Load Database Model EDGV Version 3.0'):'3.0', self.tr('Load Database Model EDGV Version FTer_2a_Ed'):'FTer_2a_Ed',self.tr('Load Other Database Models'):'Non_EDGV'} self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[], '3.0':[]} self.selectedDbsDict = dict() self.stylesDict = dict() self.postgisCustomSelector.selectionChanged.connect(self.selectedDatabases) self.spatialiteCustomSelector.selectionChanged.connect(self.selectedFiles) self.path = None self.customFileSelector.setCaption(self.tr('Select a DSGTools Spatialite file')) self.customFileSelector.setFilter(self.tr('Spatialite file databases (*.sqlite)')) self.customFileSelector.setType('multi') self.edgvType = None
class ExploreServerWidget(QtGui.QWidget, FORM_CLASS): abstractDbLoaded = pyqtSignal() clearWidgets = pyqtSignal() def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.dbFactory = DbFactory() #TODO def getServers(self): settings = QSettings() settings.beginGroup('PostgreSQL/servers') currentConnections = settings.childGroups() settings.endGroup() return currentConnections #TODO def browseServer(self,dbList,host,port,user,password): gen = self.factory.createSqlGenerator(False) edvgDbList = [] for database in dbList: db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): qgis.utils.iface.messageBar().pushMessage('DB :'+database+'| msg: '+db.lastError().databaseText(), level=QgsMessageBar.CRITICAL) query = QSqlQuery(db) if query.exec_(gen.getEDGVVersion()): while query.next(): version = query.value(0) if version: edvgDbList.append((database, version)) return edvgDbList #TODO def getDbsFromServer(self,name): gen = self.factory.createSqlGenerator(False) (host, port, user, password) = self.getServerConfiguration(name) database = 'postgres' db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): QgsMessageLog.logMessage(db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) query = QSqlQuery(gen.getDatabasesFromServer(), db) dbList = [] while query.next(): dbList.append(query.value(0)) return self.browseServer(dbList, host, port, user, password) @pyqtSlot(bool) def on_createNewServerPushButton_clicked(self): createNewServer = ViewServers(self) createNewServer.exec_() self.populateServersCombo() def populateServersCombo(self): self.serversCombo.clear() self.serversCombo.addItem(self.tr('Select Server')) currentConnections = self.getServers() for connection in currentConnections: self.serversCombo.addItem(connection) @pyqtSlot(int) def on_serversCombo_currentIndexChanged(self): self.clearWidgets.emit() if self.serversCombo.currentIndex() != 0: self.abstractDb = self.dbFactory.createDbFactory('QPSQL') (host, port, user, password) = self.abstractDb.getServerConfiguration(self.serversCombo.currentText()) self.abstractDb.connectDatabaseWithParameters(host, port, 'postgres', user, password) self.abstractDbLoaded.emit()
class StyleManagerTool(QWidget, FORM_CLASS): def __init__(self, iface, parent = None): """ Constructor """ super(StyleManagerTool, self).__init__(parent) self.setupUi(self) self.iface = iface self.splitter.hide() self.refreshDb() self.dbFactory = DbFactory() self.applyPushButton.setEnabled(False) self.utils = Utils() @pyqtSlot(bool) def on_layerPushButton_toggled(self, toggled): """ Shows/Hides the tool bar """ if toggled: self.refreshDb() self.splitter.show() else: self.splitter.hide() @pyqtSlot(bool, name = 'on_refreshPushButton_clicked') def refreshDb(self): self.dbComboBox.clear() self.dbComboBox.addItem(self.tr('Select Database')) #populate database list for dbName in self.getDatabaseList(): self.dbComboBox.addItem(dbName) @pyqtSlot(int, name = 'on_styleComboBox_currentIndexChanged') def enableApply(self): dbIdx = self.dbComboBox.currentIndex() stylesIdx = self.styleComboBox.currentIndex() if dbIdx > 0 and stylesIdx > 0: self.applyPushButton.setEnabled(True) else: self.applyPushButton.setEnabled(False) @pyqtSlot(bool) def on_applyPushButton_clicked(self): try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) dbName = self.dbComboBox.currentText() styleName = self.styleComboBox.currentText() lyrList = self.getLayers(dbName) abstractDb = self.getAbstractDb(dbName) dbVersion = abstractDb.getDatabaseVersion() stylesDict = abstractDb.getStyleDict(dbVersion) selectedStyle = stylesDict[styleName] localProgress = ProgressWidget(1, len(lyrList) - 1, self.tr('Loading style {0}').format(styleName), parent=self.iface.mapCanvas()) for lyr in lyrList: try: uri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) fullPath = self.getStyle(abstractDb, selectedStyle, lyr.name()) if fullPath: lyr.applyNamedStyle(fullPath) except: pass localProgress.step() self.iface.mapCanvas().refreshAllLayers() QApplication.restoreOverrideCursor() except Exception as e: QgsMessageLog.logMessage(self.tr('Error setting style ') + styleName + ': ' +':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) QApplication.restoreOverrideCursor() def getLayers(self, dbName): lyrList = [] for lyr in self.iface.legendInterface().layers(): if isinstance(lyr, QgsVectorLayer): candidateUri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) if candidateUri.database() == dbName and lyr.providerType() in ['postgres', 'spatialite']: lyrList.append(lyr) return lyrList def getDatabaseList(self): dbList = [] for lyr in self.iface.legendInterface().layers(): if isinstance(lyr, QgsVectorLayer): candidateUri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) dbName = candidateUri.database() if dbName not in dbList and lyr.providerType() in ['postgres', 'spatialite']: dbList.append(dbName) return dbList def loadStylesCombo(self, abstractDb): dbVersion = abstractDb.getDatabaseVersion() styleDict = abstractDb.getStyleDict(dbVersion) self.styleComboBox.clear() styleList = styleDict.keys() numberOfStyles = len(styleList) if numberOfStyles > 0: self.styleComboBox.addItem(self.tr('Select Style')) for i in range(numberOfStyles): self.styleComboBox.addItem(styleList[i]) else: self.styleComboBox.addItem(self.tr('No available styles')) def getParametersFromLyr(self, dbName): for lyr in self.iface.legendInterface().layers(): if isinstance(lyr, QgsVectorLayer): candidateUri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) if candidateUri.database() == dbName: currLyr = lyr break dbParameters = dict() if currLyr.providerType() == 'postgres': dbParameters['host'] = candidateUri.host() dbParameters['port'] = candidateUri.port() dbParameters['user'] = candidateUri.username() dbParameters['password'] = candidateUri.password() return dbParameters, 'QPSQL' if currLyr.providerType() == 'spatialite': dbParameters['dbPath'] = candidateUri.database() return dbParameters, 'QSQLITE' else: raise Exception(self.tr('Feature only implemented for PostGIS and Spatialite')) def getAbstractDb(self, dbName): dbParameters, driverName = self.getParametersFromLyr(dbName) abstractDb = self.dbFactory.createDbFactory(driverName) if 'host' in dbParameters.keys(): abstractDb.connectDatabaseWithParameters(dbParameters['host'], dbParameters['port'], dbName, dbParameters['user'], dbParameters['password']) else: abstractDb.connectDatabase(dbParameters['dbPath']) return abstractDb @pyqtSlot(int) def on_dbComboBox_currentIndexChanged(self, idx): if idx <= 0: self.styleComboBox.clear() self.styleComboBox.addItem(self.tr('Select Style')) self.styleComboBox.setEnabled(False) elif idx > 0: self.styleComboBox.setEnabled(True) dbName = self.dbComboBox.currentText() abstractDb = self.getAbstractDb(dbName) self.loadStylesCombo(abstractDb) self.enableApply() def getStyle(self, abstractDb, stylePath, className): if 'db:' in stylePath: return abstractDb.getStyle(stylePath.split(':')[-1], className) else: return self.getStyleFromFile(stylePath, className) def getStyleFromFile(self, stylePath, className): availableStyles = os.walk(stylePath).next()[2] styleName = className+'.qml' if styleName in availableStyles: path = os.path.join(stylePath, styleName) qml = self.utils.parseStyle(path) return qml else: return None
class ConnectionWidget(QtGui.QWidget, FORM_CLASS): connectionChanged = pyqtSignal() problemOccurred = pyqtSignal(str) dbChanged = pyqtSignal(AbstractDb) styleChanged = pyqtSignal(dict) def __init__(self, parent=None): """Constructor.""" super(ConnectionWidget, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.setInitialState() self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.getDatabasesFromServer) self.serverWidget.clearWidgets.connect(self.clearAll) def __del__(self): """ Closes the database """ self.closeDatabase() def closeDatabase(self): """ Closes the current database """ if self.abstractDb: del self.abstractDb self.abstractDb = None def clearAll(self): """ Resets the initial state """ self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = False self.abstractDbFactory = DbFactory() self.utils = Utils() #populating the postgis combobox self.comboBoxPostgis.clear() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True) def setInitialState(self): """ Sets the initial state """ self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = False self.tabWidget.setCurrentIndex(0) self.abstractDbFactory = DbFactory() self.utils = Utils() self.serverWidget.serversCombo.setCurrentIndex(0) #populating the postgis combobox self.comboBoxPostgis.clear() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True) @pyqtSlot(int) def on_comboBoxPostgis_currentIndexChanged(self): """ Updates database information when the combo box changes """ if self.comboBoxPostgis.currentIndex() > 0: self.postGISCrsEdit.setText('') self.postGISCrsEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setText('') self.edgvPostgisVersionEdit.setReadOnly(True) self.loadDatabase() self.connectionChanged.emit() @pyqtSlot(bool) def on_pushButtonOpenFile_clicked(self): """ Loads a spatialite database """ self.loadDatabase() if self.isDBConnected(): self.connectionChanged.emit() @pyqtSlot(int) def on_tabWidget_currentChanged(self): """ Changes the tab to work with spatialite or postgis databases """ self.filename = '' self.comboBoxPostgis.clear() self.dbLoaded = False self.epsg = 0 self.crs = None self.dbVersion = '' self.serverWidget.serversCombo.setCurrentIndex(0) self.spatialiteFileEdit.setReadOnly(True) self.spatialiteFileEdit.setText(self.filename) self.postGISCrsEdit.setText('') self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setText('') self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setText('') self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setText('') self.edgvPostgisVersionEdit.setReadOnly(True) self.mGroupBox.setTitle(self.tr('Database connection')) #Setting the database type if self.tabWidget.currentIndex() == 1: self.isSpatialite = True else: self.isSpatialite = False def loadDatabase(self): """ Loads the selected database """ self.closeDatabase() try: if self.isSpatialite: self.abstractDb = self.abstractDbFactory.createDbFactory( 'QSQLITE') self.abstractDb.connectDatabase() self.spatialiteFileEdit.setText( self.abstractDb.db.databaseName()) self.edgvSpatialiteVersionEdit.setText( self.abstractDb.getDatabaseVersion()) else: self.abstractDb = self.abstractDbFactory.createDbFactory( 'QPSQL') (host, port, user, password) = self.serverWidget.getServerParameters() dbName = self.comboBoxPostgis.currentText() self.abstractDb.connectDatabaseWithParameters( host, port, dbName, user, password) self.edgvPostgisVersionEdit.setText( self.abstractDb.getDatabaseVersion()) serverName = self.serverWidget.serversCombo.currentText() newText = dbName + self.tr(' on ') + serverName self.mGroupBox.setToolTip(newText) # self.mGroupBox.setTitle(newText) self.abstractDb.checkAndOpenDb() self.dbLoaded = True self.dbVersion = self.abstractDb.getDatabaseVersion() self.abstractDb.checkAndCreateStyleTable() self.styles = self.abstractDb.getStyleDict(self.dbVersion) self.styleChanged.emit(self.styles) self.dbChanged.emit(self.abstractDb) if self.dbVersion == '-1': self.problemOccurred.emit( self.tr('This is not a valid DsgTools database!')) else: self.setCRS() except Exception as e: self.problemOccurred.emit( self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) def setCRS(self): """ Sets the CRS information """ try: self.epsg = self.abstractDb.findEPSG() if self.epsg == -1: self.problemOccurred.emit( self.tr('Coordinate Reference System not set or invalid!')) else: self.crs = QgsCoordinateReferenceSystem( self.epsg, QgsCoordinateReferenceSystem.EpsgCrsId) if self.isSpatialite: self.spatialiteCrsEdit.setText(self.crs.description()) self.spatialiteCrsEdit.setReadOnly(True) else: self.postGISCrsEdit.setText(self.crs.description()) self.postGISCrsEdit.setReadOnly(True) except Exception as e: self.problemOccurred.emit( self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) def isDBConnected(self): """ Checks if the database is already loaded """ return self.dbLoaded def getDBVersion(self): """ Gets the database version """ ret = '' try: ret = self.abstractDb.getDatabaseVersion() except Exception as e: self.problemOccurred.emit( self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return ret def getQmlPath(self): """ Gets the QML path """ ret = '' try: ret = self.abstractDb.getQmlDir() except Exception as e: self.problemOccurred.emit( self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return ret def getDatabasesFromServer(self): """ Gets databases from server """ QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: if self.serverWidget.abstractDb: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer( parentWidget=self) dbList.sort() self.comboBoxPostgis.clear() self.comboBoxPostgis.addItem(self.tr('Select Database')) for db, version in dbList: self.comboBoxPostgis.addItem(db) else: self.setInitialState() return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.setInitialState() self.setInitialState() QApplication.restoreOverrideCursor()
class ConnectionWidget(QtGui.QWidget, FORM_CLASS): connectionChanged = pyqtSignal() problemOccurred = pyqtSignal(str) dbChanged = pyqtSignal(AbstractDb) styleChanged = pyqtSignal(dict) def __init__(self, parent = None): """Constructor.""" super(ConnectionWidget, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.setInitialState() self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.getDatabasesFromServer) self.serverWidget.clearWidgets.connect(self.clearAll) def __del__(self): """ Closes the database """ self.closeDatabase() def closeDatabase(self): """ Closes the current database """ if self.abstractDb: del self.abstractDb self.abstractDb = None def clearAll(self): """ Resets the initial state """ self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = False self.abstractDbFactory = DbFactory() self.utils = Utils() #populating the postgis combobox self.comboBoxPostgis.clear() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True) def setInitialState(self): """ Sets the initial state """ self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = False self.tabWidget.setCurrentIndex(0) self.abstractDbFactory = DbFactory() self.utils = Utils() self.serverWidget.serversCombo.setCurrentIndex(0) #populating the postgis combobox self.comboBoxPostgis.clear() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True) @pyqtSlot(int) def on_comboBoxPostgis_currentIndexChanged(self): """ Updates database information when the combo box changes """ if self.comboBoxPostgis.currentIndex() > 0: self.postGISCrsEdit.setText('') self.postGISCrsEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setText('') self.edgvPostgisVersionEdit.setReadOnly(True) self.loadDatabase() self.connectionChanged.emit() @pyqtSlot(bool) def on_pushButtonOpenFile_clicked(self): """ Loads a spatialite database """ self.loadDatabase() if self.isDBConnected(): self.connectionChanged.emit() @pyqtSlot(int) def on_tabWidget_currentChanged(self): """ Changes the tab to work with spatialite or postgis databases """ self.filename = '' self.comboBoxPostgis.clear() self.dbLoaded = False self.epsg = 0 self.crs = None self.dbVersion = '' self.serverWidget.serversCombo.setCurrentIndex(0) self.spatialiteFileEdit.setReadOnly(True) self.spatialiteFileEdit.setText(self.filename) self.postGISCrsEdit.setText('') self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setText('') self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setText('') self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setText('') self.edgvPostgisVersionEdit.setReadOnly(True) self.mGroupBox.setTitle(self.tr('Database connection')) #Setting the database type if self.tabWidget.currentIndex() == 1: self.isSpatialite = True else: self.isSpatialite = False def loadDatabase(self): """ Loads the selected database """ self.closeDatabase() try: if self.isSpatialite: self.abstractDb = self.abstractDbFactory.createDbFactory('QSQLITE') self.abstractDb.connectDatabase() self.spatialiteFileEdit.setText(self.abstractDb.db.databaseName()) self.edgvSpatialiteVersionEdit.setText(self.abstractDb.getDatabaseVersion()) else: self.abstractDb = self.abstractDbFactory.createDbFactory('QPSQL') (host, port, user, password) = self.serverWidget.getServerParameters() dbName = self.comboBoxPostgis.currentText() self.abstractDb.connectDatabaseWithParameters(host, port, dbName, user, password) self.edgvPostgisVersionEdit.setText(self.abstractDb.getDatabaseVersion()) serverName = self.serverWidget.serversCombo.currentText() newText = dbName + self.tr(' on ') + serverName self.mGroupBox.setToolTip(newText) # self.mGroupBox.setTitle(newText) self.abstractDb.checkAndOpenDb() self.dbLoaded = True self.dbVersion = self.abstractDb.getDatabaseVersion() self.abstractDb.checkAndCreateStyleTable() self.styles = self.abstractDb.getStyleDict(self.dbVersion) self.styleChanged.emit(self.styles) self.dbChanged.emit(self.abstractDb) if self.dbVersion == '-1': self.problemOccurred.emit(self.tr('This is not a valid DsgTools database!')) else: self.setCRS() except Exception as e: self.problemOccurred.emit(self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) def setCRS(self): """ Sets the CRS information """ try: self.epsg = self.abstractDb.findEPSG() if self.epsg == -1: self.problemOccurred.emit(self.tr('Coordinate Reference System not set or invalid!')) else: self.crs = QgsCoordinateReferenceSystem(self.epsg, QgsCoordinateReferenceSystem.EpsgCrsId) if self.isSpatialite: self.spatialiteCrsEdit.setText(self.crs.description()) self.spatialiteCrsEdit.setReadOnly(True) else: self.postGISCrsEdit.setText(self.crs.description()) self.postGISCrsEdit.setReadOnly(True) except Exception as e: self.problemOccurred.emit(self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) def isDBConnected(self): """ Checks if the database is already loaded """ return self.dbLoaded def getDBVersion(self): """ Gets the database version """ ret = '' try: ret = self.abstractDb.getDatabaseVersion() except Exception as e: self.problemOccurred.emit(self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return ret def getQmlPath(self): """ Gets the QML path """ ret = '' try: ret = self.abstractDb.getQmlDir() except Exception as e: self.problemOccurred.emit(self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return ret def getDatabasesFromServer(self): """ Gets databases from server """ QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: if self.serverWidget.abstractDb: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer(parentWidget = self) dbList.sort() self.comboBoxPostgis.clear() self.comboBoxPostgis.addItem(self.tr('Select Database')) for db, version in dbList: self.comboBoxPostgis.addItem(db) else: self.setInitialState() return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.setInitialState() self.setInitialState() QApplication.restoreOverrideCursor()
class PostgisDbThread(GenericThread): def __init__(self, parent=None): """ Constructor. """ super(PostgisDbThread, self).__init__() self.factory = SqlGeneratorFactory() #setting the sql generator self.gen = self.factory.createSqlGenerator(False) self.messenger = PostgisDbMessages(self) self.dbFactory = DbFactory() self.parent = parent def setParameters(self, abstractDb, dbName, version, epsg, stopped): """ Sets thread parameters """ self.abstractDb = abstractDb #database = postgis self.dbName = dbName self.db = None self.version = version self.epsg = epsg self.stopped = stopped def run(self): """ Runs the process """ # Processing ending (ret, msg) = self.createDatabaseStructure() self.signals.processingFinished.emit(ret, msg, self.getId()) def connectToTemplate(self, setInnerDb=True): """ Connects to the template database to speed up database creation :return: """ database = self.abstractDb.getTemplateName(self.version) host = self.abstractDb.db.hostName() port = self.abstractDb.db.port() user = self.abstractDb.db.userName() password = self.abstractDb.db.password() template = self.dbFactory.createDbFactory('QPSQL') template.connectDatabaseWithParameters(host, port, database, user, password) template.checkAndOpenDb() if setInnerDb: self.db = template.db return template def createDatabaseStructure(self): """ Creates database structure according to the selected edgv version """ currentPath = os.path.dirname(__file__) currentPath = os.path.join(currentPath, '..', '..', 'DbTools', 'PostGISTool') if self.version == '2.1.3': edgvPath = os.path.join(currentPath, 'sqls', '213', 'edgv213.sql') elif self.version == '3.0': edgvPath = os.path.join(currentPath, 'sqls', '3', 'edgv3.sql') elif self.version == 'FTer_2a_Ed': edgvPath = os.path.join(currentPath, 'sqls', 'FTer_2a_Ed', 'edgvFter_2a_Ed.sql') else: pass return self.loadDatabaseStructure(edgvPath) def loadDatabaseStructure(self, edgvPath): """ Loads the database structure edgvPath: path to the databse sql """ commands = [] hasTemplate = self.abstractDb.checkTemplate(self.version) if hasTemplate: templateDb = self.connectToTemplate(setInnerDb=False) mustUpdateTemplate = templateDb.checkTemplateImplementationVersion( ) if mustUpdateTemplate: templateName = templateDb.db.databaseName() templateDb.__del__() self.abstractDb.dropDatabase(templateName, dropTemplate=True) hasTemplate = False if not hasTemplate: file = codecs.open(edgvPath, encoding='utf-8', mode="r") sql = file.read() sql = sql.replace('[epsg]', '4674') file.close() commands = [i for i in sql.split('#') if i != ''] # Progress bar steps calculated self.signals.rangeCalculated.emit(len(commands) + 4, self.getId()) if not hasTemplate: try: self.abstractDb.createTemplateDatabase(self.version) self.signals.stepProcessed.emit(self.getId()) self.connectToTemplate() self.signals.stepProcessed.emit(self.getId()) except Exception as e: return (0, self.messenger.getProblemFeedbackMessage() + '\n' + ':'.join(e.args)) self.db.open() self.db.transaction() query = QSqlQuery(self.db) for command in commands: if not self.stopped[0]: if not query.exec_(command): QgsMessageLog.logMessage( self.messenger.getProblemMessage(command, query), "DSG Tools Plugin", QgsMessageLog.CRITICAL) self.db.rollback() self.db.close() self.dropDatabase(self.db) return (0, self.messenger.getProblemFeedbackMessage()) # Updating progress self.signals.stepProcessed.emit(self.getId()) else: self.db.rollback() self.db.close() self.dropDatabase(self.db) QgsMessageLog.logMessage( self.messenger.getUserCanceledFeedbackMessage(), "DSG Tools Plugin", QgsMessageLog.INFO) return (-1, self.messenger.getUserCanceledFeedbackMessage()) self.db.commit() if self.version == '2.1.3': sql = 'ALTER DATABASE %s SET search_path = "$user", public, topology,\'cb\',\'complexos\',\'dominios\';' % self.db.databaseName( ) elif self.version == 'FTer_2a_Ed': sql = 'ALTER DATABASE %s SET search_path = "$user", public, topology,\'pe\',\'ge\',\'complexos\',\'dominios\';' % self.db.databaseName( ) elif self.version == '3.0': sql = 'ALTER DATABASE %s SET search_path = "$user", public, topology,\'edgv\',\'complexos\',\'dominios\';' % self.db.databaseName( ) if sql: if not query.exec_(sql): QgsMessageLog.logMessage( self.messenger.getProblemMessage(command, query), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return (0, self.messenger.getProblemFeedbackMessage()) #this commit was missing, so alter database statement was not commited. self.db.commit() self.db.close() self.abstractDb.setDbAsTemplate(self.version) #creates from template if not self.stopped[0]: templateName = self.abstractDb.getTemplateName(self.version) self.abstractDb.createDbFromTemplate(self.dbName, templateName, parentWidget=self.parent) self.signals.stepProcessed.emit(self.getId()) #5. alter spatial structure createdDb = self.dbFactory.createDbFactory('QPSQL') createdDb.connectDatabaseWithParameters( self.abstractDb.db.hostName(), self.abstractDb.db.port(), self.dbName, self.abstractDb.db.userName(), self.abstractDb.db.password()) errorTuple = createdDb.updateDbSRID(self.epsg, parentWidget=self.parent, threading=True) # if an error occur during the thread we should pass the message to the main thread if errorTuple: QgsMessageLog.logMessage( self.messenger.getProblemMessage(errorTuple[0], errorTuple[1]), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return (0, self.messenger.getProblemFeedbackMessage()) self.signals.stepProcessed.emit(self.getId()) else: QgsMessageLog.logMessage( self.messenger.getUserCanceledFeedbackMessage(), "DSG Tools Plugin", QgsMessageLog.INFO) return (-1, self.messenger.getUserCanceledFeedbackMessage()) QgsMessageLog.logMessage(self.messenger.getSuccessFeedbackMessage(), "DSG Tools Plugin", QgsMessageLog.INFO) return (1, self.messenger.getSuccessFeedbackMessage()) def dropDatabase(self, db): """ Drops the created database case a problem occurs during database creation db: QSqlDatabase to be dropped """ host = db.hostName() port = db.port() user = db.userName() password = db.password() database = 'postgres' pgDB = QSqlDatabase('QPSQL') pgDB.setHostName(host) pgDB.setPort(port) pgDB.setUserName(user) pgDB.setPassword(password) pgDB.setDatabaseName(database) if not pgDB.open(): return False sql = self.gen.dropDatabase(db.databaseName()) query = QSqlQuery(pgDB) return query.exec_(sql)
class ViewServers(QtGui.QDialog, FORM_CLASS): def __init__(self, iface, parent=None): '''Constructor.''' super(ViewServers, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self.abstractDbFactory = DbFactory() self.initGui() def initGui(self): header = self.tableWidget.horizontalHeader() header.setResizeMode(QHeaderView.Stretch) self.populateTable() def populateTable(self): currentConnections = self.getServers() self.tableWidget.setRowCount(len(currentConnections)) for i, connection in enumerate(currentConnections): self.tableWidget.setItem(i, 0, QTableWidgetItem(connection)) (host, port, user, password) = self.getServerConfiguration(connection) self.tableWidget.setItem(i, 1, QTableWidgetItem(host)) self.tableWidget.setItem(i, 2, QTableWidgetItem(port)) self.tableWidget.setItem(i, 3, QTableWidgetItem(user)) if not password or len(password) == 0: self.tableWidget.setItem(i, 4, QTableWidgetItem(self.tr('Not Saved'))) else: self.tableWidget.setItem(i, 4, QTableWidgetItem(self.tr('Saved'))) @pyqtSlot(bool) def on_cancelButton_clicked(self): self.done(0) @pyqtSlot(bool) def on_addButton_clicked(self): dlg = ServerConfigurator(self) result = dlg.exec_() if result: self.populateTable() @pyqtSlot(bool) def on_editButton_clicked(self): selectedItem = self.returnSelectedName() if not selectedItem: return dlg = ServerConfigurator(self) dlg.setServerConfiguration(selectedItem.text()) result = dlg.exec_() if result: self.populateTable() @pyqtSlot(bool) def on_removeButton_clicked(self): selectedItem = self.returnSelectedName() if not selectedItem: return self.removeServerConfiguration(selectedItem.text()) self.tableWidget.removeRow(selectedItem.row()) QMessageBox.warning(self, self.tr('Info!'), self.tr('Server removed.')) @pyqtSlot(bool) def on_testButton_clicked(self): selectedItem = self.returnSelectedName() if not selectedItem: return name = selectedItem.text() try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) test = self.testServer(name) QApplication.restoreOverrideCursor() except: QApplication.restoreOverrideCursor() if test: QMessageBox.warning(self, self.tr('Info!'), self.tr('Connection online.')) else: QMessageBox.warning(self, self.tr('Info!'), self.tr('Connection was not successful. Check log for details.')) def getServers(self): settings = QSettings() settings.beginGroup('PostgreSQL/servers') currentConnections = settings.childGroups() settings.endGroup() return currentConnections def getServerConfiguration(self, name): settings = QSettings() settings.beginGroup('PostgreSQL/servers/'+name) host = settings.value('host') port = settings.value('port') user = settings.value('username') password = settings.value('password') settings.endGroup() return (host, port, user, password) def removeServerConfiguration(self, name): settings = QSettings() settings.beginGroup('PostgreSQL/servers/'+name) settings.remove('') settings.endGroup() def testServer(self, name): abstractDb = self.abstractDbFactory.createDbFactory('QPSQL') if not abstractDb: return False (host, port, user, password) = abstractDb.getServerConfiguration(name) abstractDb.connectDatabaseWithParameters(host, port, 'postgres', user, password) try: abstractDb.checkAndOpenDb() except Exception as e: QgsMessageLog.logMessage(e.args[0], 'DSG Tools Plugin', QgsMessageLog.CRITICAL) return False return True def returnSelectedName(self): if len(self.tableWidget.selectedItems()) == 0: QMessageBox.warning(self, self.tr('Warning!'), self.tr('Select one server.')) return return self.tableWidget.selectedItems()[0]
class PostgisDBTool(QDialog, FORM_CLASS): def __init__(self, iface): """Constructor.""" super(PostgisDBTool, self).__init__() # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self.populateServersCombo() self.srs = None self.db = None self.abstractDb = None self.factory = SqlGeneratorFactory() #setting the sql generator self.gen = self.factory.createSqlGenerator(False) self.epsg = 4326 def getParameters(self): """ Gets database parameters """ return (self.databaseEdit.text(), self.abstractDb, self.versionCombo.currentText(), self.epsg) @pyqtSlot(bool) def on_saveButton_clicked(self): """ Creates a postgis database """ if self.databaseEdit.text() == '': QgsMessageLog.logMessage('Enter database name!', "DSG Tools Plugin", QgsMessageLog.CRITICAL) else: self.db = self.getDatabase() if self.db: self.storeConnectionConfiguration(self.serversCombo.currentText(), self.databaseEdit.text()) self.done(1) @pyqtSlot(bool) def on_cancelButton_clicked(self): """ Cancels everything """ self.done(-1) @pyqtSlot(bool) def on_configureServerButton_clicked(self): """ Opens the ViewServer dialog """ dlg = ViewServers(self.iface) dlg.show() result = dlg.exec_() self.populateServersCombo() @pyqtSlot(bool) def on_srsButton_clicked(self): """ Opens the CRS selector dialog """ projSelector = QgsGenericProjectionSelector() message = 'Select the Spatial Reference System!' projSelector.setMessage(theMessage=message) projSelector.exec_() try: self.epsg = int(projSelector.selectedAuthId().split(':')[-1]) srs = QgsCoordinateReferenceSystem(self.epsg, QgsCoordinateReferenceSystem.EpsgCrsId) if srs: self.srsEdit.setText(srs.description()) else: self.epsg = 4326 except: QMessageBox.warning(self, self.tr("Warning!"), message) def createDatabase(self, name): """ Creates the database """ sql = self.gen.getCreateDatabase(name) db = self.getDatabase() #creating the database query = QSqlQuery(db) if not query.exec_(sql): QMessageBox.warning(self, self.tr("Warning!"), query.lastError().text()) db.close() return False db.close() return True def getDatabase(self, database = 'postgres'): """ Gets a a QSqlDatabase """ (host, port, user, password) = self.getServerConfiguration(self.serversCombo.currentText()) self.abstractDb = DbFactory().createDbFactory('QPSQL') if password == '': conInfo = 'host='+host+' port='+port+' dbname='+database self.setCredentials(self.abstractDb.db, conInfo, user) else: self.abstractDb.connectDatabaseWithParameters(host, port, database, user, password) if not self.abstractDb.db.open(): QgsMessageLog.logMessage(self.abstractDb.db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return self.abstractDb def setCredentials(self, db, conInfo, user): """ Sets connection credentials db: QSqlDatabase used conInfo: connection information user: user name """ (success, user, password) = QgsCredentials.instance().get(conInfo, user, None) if not success: return else: db.setPassword(password) db.setUserName(user) if not db.open(): self.setCredentials(db, conInfo, user) else: QgsCredentials.instance().put(conInfo, user, password) def updateConnectionName(self): """ Updates connection name """ server = self.serversCombo.currentText() database = self.databaseEdit.text() name = server+'_'+database self.connectionEdit.setText(name) def on_serversCombo_currentIndexChanged(self, index): """ Slot to update the connection name """ self.updateConnectionName() def on_databaseEdit_textEdited(self, text): """ Adjusts the text before updating the connection name """ self.updateConnectionName() def checkFields(self): """ Check fields prior the next step """ if self.serversCombo.currentText() == '' or self.databaseEdit.text() == '' or self.srsEdit.text() == '': return False return True def getServerConfiguration(self, name): """ Gets server configuration from QSettings name: server name """ settings = QSettings() settings.beginGroup('PostgreSQL/servers/'+name) host = settings.value('host') port = settings.value('port') user = settings.value('username') password = settings.value('password') settings.endGroup() return (host, port, user, password) def storeConnectionConfiguration(self, server, database): """ Stores the new configuration server: server name database: database name """ name = self.connectionEdit.text() (host, port, user, password) = self.getServerConfiguration(server) settings = QSettings() settings.beginGroup('PostgreSQL/connections/'+name) settings.setValue('database', database) settings.setValue('host', host) settings.setValue('port', port) settings.setValue('username', user) settings.setValue('password', password) settings.endGroup() def getServers(self): """ Gets all servers from QSettings """ settings = QSettings() settings.beginGroup('PostgreSQL/servers') currentConnections = settings.childGroups() settings.endGroup() return currentConnections def populateServersCombo(self): """ Populates the server combo box """ self.serversCombo.clear() currentConnections = self.getServers() for connection in currentConnections: self.serversCombo.addItem(connection)
class CustomServerConnectionWidget(QtGui.QWidget, FORM_CLASS): selectionChanged = pyqtSignal() resetAll = pyqtSignal() dbDictChanged = pyqtSignal(str,list) styleChanged = pyqtSignal(dict) def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.populatePostgisSelector) self.customFileSelector.filesSelected.connect(self.populateSpatialiteSelector) self.comboDict = {self.tr('Load Database Model EDGV Version 2.1.3'):'2.1.3', self.tr('Load Database Model EDGV Version 3.0'):'3.0', self.tr('Load Database Model EDGV Version FTer_2a_Ed'):'FTer_2a_Ed',self.tr('Load Other Database Models'):'Non_EDGV'} self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[], '3.0':[]} self.selectedDbsDict = dict() self.stylesDict = dict() self.postgisCustomSelector.selectionChanged.connect(self.selectedDatabases) self.spatialiteCustomSelector.selectionChanged.connect(self.selectedFiles) self.path = None self.customFileSelector.setCaption(self.tr('Select a DSGTools Spatialite file')) self.customFileSelector.setFilter(self.tr('Spatialite file databases (*.sqlite)')) self.customFileSelector.setType('multi') self.edgvType = None def selectedDatabases(self, dbList, type): """ Selects databases from a name list and database type """ #TODO: build selectedDbsDict and emit dbDictChanged() #1- Iterate over dbList and check if all layers on dbList are on dict. If not, add it. if type == 'added': (host, port, user, password) = self.serverWidget.abstractDb.getParamsFromConectedDb() for dbName in dbList: if dbName not in self.selectedDbsDict.keys(): if host and port and user: localDb = self.dbFactory.createDbFactory('QPSQL') localDb.connectDatabaseWithParameters(host, port, dbName, user, password) self.selectedDbsDict[dbName] = localDb #do get dicts localDict = localDb.getStyleDict(localDb.getDatabaseVersion()) for key in localDict.keys(): if key not in self.stylesDict.keys(): self.stylesDict[key] = dict() self.stylesDict[key]['dbList'] = [] self.stylesDict[key]['style'] = localDict[key] if dbName not in self.stylesDict[key]['dbList']: self.stylesDict[key]['dbList'].append(dbName) self.dbDictChanged.emit('added', dbList) self.styleChanged.emit(self.stylesDict) #2- Iterate over selectedDbsDict and if there is a key not in dbList, close db and pop item if type == 'removed': for dbName in self.selectedDbsDict.keys(): if dbName in dbList: self.selectedDbsDict.pop(dbName) self.dbDictChanged.emit('removed', dbList) for key in self.stylesDict.keys(): for db in self.stylesDict[key]['dbList']: if db in dbList: idx = self.stylesDict[key]['dbList'].index(db) self.stylesDict[key]['dbList'].pop(idx) if len(self.stylesDict[key]['dbList']) == 0: self.stylesDict.pop(key) self.styleChanged.emit(self.stylesDict) def selectedFiles(self, dbList, type): """ Selects databases from a name list and database type """ #TODO: build selectedDbsDict and emit dbDictChanged() #1- Iterate over dbList and check if all layers on dbList are on dict. If not, add it. if type == 'added': for dbName in dbList: if dbName not in self.selectedDbsDict.keys(): localDb = self.dbFactory.createDbFactory('QSQLITE') localDb.connectDatabase(conn = self.spatialiteDict[dbName]) self.selectedDbsDict[dbName] = localDb #do get dicts localDict = localDb.getStyleDict(localDb.getDatabaseVersion()) for key in localDict.keys(): if key not in self.stylesDict.keys(): self.stylesDict[key] = dict() self.stylesDict[key]['dbList'] = [] self.stylesDict[key]['style'] = localDict[key] if dbName not in self.stylesDict[key]['dbList']: self.stylesDict[key]['dbList'].append(dbName) self.dbDictChanged.emit('added', dbList) self.styleChanged.emit(self.stylesDict) #2- Iterate over selectedDbsDict and if there is a key not in dbList, close db and pop item if type == 'removed': for dbName in self.selectedDbsDict.keys(): if dbName in dbList: self.selectedDbsDict.pop(dbName) self.dbDictChanged.emit('removed', dbList) for key in self.stylesDict.keys(): for db in self.stylesDict[key]['dbList']: if db in dbList: idx = self.stylesDict[key]['dbList'].index(db) self.stylesDict[key]['dbList'].pop(idx) if len(self.stylesDict[key]['dbList']) == 0: self.stylesDict.pop(key) self.styleChanged.emit(self.stylesDict) @pyqtSlot(int) def on_serverConnectionTab_currentChanged(self, currentTab): """ Changes the database type (spatialite/postgis) """ if currentTab == 0: self.clearSpatialiteTab() self.populatePostgisSelector() elif currentTab == 1: self.clearPostgisTab() self.populateSpatialiteSelector() pass def populatePostgisSelector(self): """ Populates the postgis database list according to the database type """ self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[], '3.0':[]} dbList = [] try: if self.serverWidget.abstractDb: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer(parentWidget = self) else: self.clearPostgisTab() return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.clearPostgisTab() dbList.sort() for (dbname, dbversion) in dbList: if dbversion in self.dbDict.keys(): self.dbDict[dbversion].append(dbname) else: self.dbDict['Non_EDGV'].append(dbname) comboText = self.postgisEdgvComboFilter.currentText() self.postgisCustomSelector.setInitialState(self.dbDict[self.comboDict[comboText]]) def populateSpatialiteSelector(self): """ Populates the spatialite database list according to the databse type """ self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[], '3.0':[]} self.spatialiteDict = dict() dbList = [] try: for dbPath in self.customFileSelector.fileNameList: auxAbstractDb = self.dbFactory.createDbFactory('QSQLITE') dbName = os.path.basename(dbPath).split('.')[0] self.path = os.path.dirname(dbPath) auxAbstractDb.connectDatabase(conn = dbPath) version = auxAbstractDb.getDatabaseVersion() dbList.append((dbName,version)) self.spatialiteDict[dbName] = dbPath except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.clearSpatialiteTab() dbList.sort() for (dbname, dbversion) in dbList: if dbversion in self.dbDict.keys(): self.dbDict[dbversion].append(dbname) # if len(self.dbDict['2.1.3']) == 0: # self.spatialiteEdgvComboFilter.setCurrentIndex(1) comboText = self.spatialiteEdgvComboFilter.currentText() self.spatialiteCustomSelector.setInitialState(self.dbDict[self.comboDict[comboText]]) def clearSpatialiteTab(self): """ Clears the postgis tab, returning it to the original state """ self.spatialiteCustomSelector.clearAll() self.serverWidget.clearAll() self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[],'3.0':[]} self.customFileSelector.resetAll() self.edgvType = None self.selectedDbsDict = dict() self.resetAll.emit() @pyqtSlot(int) def on_postgisEdgvComboFilter_currentIndexChanged(self): """ Updates the postgis databases according to its type """ comboText = self.postgisEdgvComboFilter.currentText() self.postgisCustomSelector.resetSelections() self.postgisCustomSelector.setInitialState(self.dbDict[self.comboDict[comboText]]) self.serverConnectionTab self.edgvType = self.comboDict[comboText] self.resetAll.emit() @pyqtSlot(int) def on_spatialiteEdgvComboFilter_currentIndexChanged(self): """ Updates the postgis databases according to its type """ comboText = self.spatialiteEdgvComboFilter.currentText() self.spatialiteCustomSelector.setInitialState(self.dbDict[self.comboDict[comboText]]) self.edgvType = self.comboDict[comboText] self.resetAll.emit() def clearPostgisTab(self): """ Clears the spatialite tab, returning it to the original state """ self.postgisCustomSelector.clearAll() self.serverWidget.clearAll() self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[],'3.0':[]} self.edgvType = None self.selectedDbsDict = dict() self.resetAll.emit() def getStyles(self, type, abstractDb): """ Gets database styles. If the structure to store styles is not yet created, we should create it. """ dbVersion = abstractDb.getDatabaseVersion() abstractDb.checkAndCreateStyleTable() styles = abstractDb.getStyleDict(dbVersion) self.styleChanged.emit(type, styles)
class ExploreServerWidget(QtGui.QWidget, FORM_CLASS): abstractDbLoaded = pyqtSignal() clearWidgets = pyqtSignal() def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.dbFactory = DbFactory() #TODO def getServers(self): settings = QSettings() settings.beginGroup('PostgreSQL/servers') currentConnections = settings.childGroups() settings.endGroup() return currentConnections #TODO def browseServer(self, dbList, host, port, user, password): gen = self.factory.createSqlGenerator(False) edvgDbList = [] for database in dbList: db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): qgis.utils.iface.messageBar().pushMessage( 'DB :' + database + '| msg: ' + db.lastError().databaseText(), level=QgsMessageBar.CRITICAL) query = QSqlQuery(db) if query.exec_(gen.getEDGVVersion()): while query.next(): version = query.value(0) if version: edvgDbList.append((database, version)) return edvgDbList #TODO def getDbsFromServer(self, name): gen = self.factory.createSqlGenerator(False) (host, port, user, password) = self.getServerConfiguration(name) database = 'postgres' db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): QgsMessageLog.logMessage(db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) query = QSqlQuery(gen.getDatabasesFromServer(), db) dbList = [] while query.next(): dbList.append(query.value(0)) return self.browseServer(dbList, host, port, user, password) @pyqtSlot(bool) def on_createNewServerPushButton_clicked(self): createNewServer = ViewServers(self) createNewServer.exec_() self.populateServersCombo() def populateServersCombo(self): self.serversCombo.clear() self.serversCombo.addItem(self.tr('Select Server')) currentConnections = self.getServers() for connection in currentConnections: self.serversCombo.addItem(connection) @pyqtSlot(int) def on_serversCombo_currentIndexChanged(self): self.clearWidgets.emit() if self.serversCombo.currentIndex() != 0: self.abstractDb = self.dbFactory.createDbFactory('QPSQL') (host, port, user, password) = self.abstractDb.getServerConfiguration( self.serversCombo.currentText()) self.abstractDb.connectDatabaseWithParameters( host, port, 'postgres', user, password) self.abstractDbLoaded.emit()
class StyleManagerTool(QWidget, FORM_CLASS): def __init__(self, iface, parent=None): """ Constructor """ super(StyleManagerTool, self).__init__(parent) self.setupUi(self) self.iface = iface self.splitter.hide() self.refreshDb() self.dbFactory = DbFactory() self.applyPushButton.setEnabled(False) self.utils = Utils() @pyqtSlot(bool) def on_layerPushButton_toggled(self, toggled): """ Shows/Hides the tool bar """ if toggled: self.refreshDb() self.splitter.show() else: self.splitter.hide() @pyqtSlot(bool, name='on_refreshPushButton_clicked') def refreshDb(self): self.dbComboBox.clear() self.dbComboBox.addItem(self.tr('Select Database')) #populate database list for dbName in self.getDatabaseList(): self.dbComboBox.addItem(dbName) @pyqtSlot(int, name='on_dbComboBox_currentIndexChanged') @pyqtSlot(int, name='on_styleComboBox_currentIndexChanged') def enableApply(self): dbIdx = self.dbComboBox.currentIndex() stylesIdx = self.styleComboBox.currentIndex() if dbIdx > 0 and stylesIdx > 0: self.applyPushButton.setEnabled(True) else: self.applyPushButton.setEnabled(False) @pyqtSlot(bool) def on_applyPushButton_clicked(self): try: QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) dbName = self.dbComboBox.currentText() styleName = self.styleComboBox.currentText() lyrList = self.getLayers(dbName) abstractDb = self.getAbstractDb(dbName) dbVersion = abstractDb.getDatabaseVersion() stylesDict = abstractDb.getStyleDict(dbVersion) selectedStyle = stylesDict[styleName] localProgress = ProgressWidget( 1, len(lyrList) - 1, self.tr('Loading style {0}').format(styleName), parent=self.iface.mapCanvas()) for lyr in lyrList: try: uri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) fullPath = self.getStyle(abstractDb, selectedStyle, lyr.name()) if fullPath: lyr.applyNamedStyle(fullPath) except: pass localProgress.step() self.iface.mapCanvas().refreshAllLayers() QApplication.restoreOverrideCursor() except Exception as e: QgsMessageLog.logMessage( self.tr('Error setting style ') + styleName + ': ' + ':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL) QApplication.restoreOverrideCursor() def getLayers(self, dbName): lyrList = [] for lyr in self.iface.legendInterface().layers(): if isinstance(lyr, QgsVectorLayer): candidateUri = QgsDataSourceURI( lyr.dataProvider().dataSourceUri()) if candidateUri.database() == dbName and lyr.providerType( ) in ['postgres', 'spatialite']: lyrList.append(lyr) return lyrList def getDatabaseList(self): dbList = [] for lyr in self.iface.legendInterface().layers(): if isinstance(lyr, QgsVectorLayer): candidateUri = QgsDataSourceURI( lyr.dataProvider().dataSourceUri()) dbName = candidateUri.database() if dbName not in dbList and lyr.providerType() in [ 'postgres', 'spatialite' ]: dbList.append(dbName) return dbList def loadStylesCombo(self, abstractDb): dbVersion = abstractDb.getDatabaseVersion() styleDict = abstractDb.getStyleDict(dbVersion) self.styleComboBox.clear() styleList = styleDict.keys() numberOfStyles = len(styleList) if numberOfStyles > 0: self.styleComboBox.addItem(self.tr('Select Style')) for i in range(numberOfStyles): self.styleComboBox.addItem(styleList[i]) else: self.styleComboBox.addItem(self.tr('No available styles')) def getParametersFromLyr(self, dbName): for lyr in self.iface.legendInterface().layers(): if isinstance(lyr, QgsVectorLayer): candidateUri = QgsDataSourceURI( lyr.dataProvider().dataSourceUri()) if candidateUri.database() == dbName: currLyr = lyr break dbParameters = dict() if currLyr.providerType() == 'postgres': dbParameters['host'] = candidateUri.host() dbParameters['port'] = candidateUri.port() dbParameters['user'] = candidateUri.username() dbParameters['password'] = candidateUri.password() return dbParameters, 'QPSQL' if currLyr.providerType() == 'spatialite': dbParameters['dbPath'] = candidateUri.database() return dbParameters, 'QSQLITE' else: raise Exception( self.tr('Feature only implemented for PostGIS and Spatialite')) def getAbstractDb(self, dbName): dbParameters, driverName = self.getParametersFromLyr(dbName) abstractDb = self.dbFactory.createDbFactory(driverName) if 'host' in dbParameters.keys(): abstractDb.connectDatabaseWithParameters(dbParameters['host'], dbParameters['port'], dbName, dbParameters['user'], dbParameters['password']) else: abstractDb.connectDatabase(dbParameters['dbPath']) return abstractDb @pyqtSlot(int) def on_dbComboBox_currentIndexChanged(self, idx): if idx <= 0: self.styleComboBox.clear() self.styleComboBox.addItem(self.tr('Select Style')) self.styleComboBox.setEnabled(False) elif idx > 0: self.styleComboBox.setEnabled(True) dbName = self.dbComboBox.currentText() abstractDb = self.getAbstractDb(dbName) self.loadStylesCombo(abstractDb) def getStyle(self, abstractDb, stylePath, className): if 'db:' in stylePath: return abstractDb.getStyle(stylePath.split(':')[-1], className) else: return self.getStyleFromFile(stylePath, className) def getStyleFromFile(self, stylePath, className): availableStyles = os.walk(stylePath).next()[2] styleName = className + '.qml' if styleName in availableStyles: path = os.path.join(stylePath, styleName) qml = self.utils.parseStyle(path) return qml else: return None
class CustomServerConnectionWidget(QtGui.QWidget, FORM_CLASS): selectionChanged = pyqtSignal() resetAll = pyqtSignal() dbDictChanged = pyqtSignal(str, list) styleChanged = pyqtSignal(dict) def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect( self.populatePostgisSelector) self.customFileSelector.filesSelected.connect( self.populateSpatialiteSelector) self.comboDict = { self.tr('Load Database Model EDGV Version 2.1.3'): '2.1.3', self.tr('Load Database Model EDGV Version 3.0'): '3.0', self.tr('Load Database Model EDGV Version FTer_2a_Ed'): 'FTer_2a_Ed', self.tr('Load Other Database Models'): 'Non_EDGV' } self.dbDict = { '2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': [], '3.0': [] } self.selectedDbsDict = dict() self.stylesDict = dict() self.postgisCustomSelector.selectionChanged.connect( self.selectedDatabases) self.spatialiteCustomSelector.selectionChanged.connect( self.selectedFiles) self.path = None self.customFileSelector.setCaption( self.tr('Select a DSGTools Spatialite file')) self.customFileSelector.setFilter( self.tr('Spatialite file databases (*.sqlite)')) self.customFileSelector.setType('multi') self.edgvType = None def selectedDatabases(self, dbList, type): """ Selects databases from a name list and database type """ #TODO: build selectedDbsDict and emit dbDictChanged() #1- Iterate over dbList and check if all layers on dbList are on dict. If not, add it. if type == 'added': (host, port, user, password ) = self.serverWidget.abstractDb.getParamsFromConectedDb() for dbName in dbList: if dbName not in self.selectedDbsDict.keys(): if host and port and user: localDb = self.dbFactory.createDbFactory('QPSQL') localDb.connectDatabaseWithParameters( host, port, dbName, user, password) self.selectedDbsDict[dbName] = localDb #do get dicts localDict = localDb.getStyleDict( localDb.getDatabaseVersion()) for key in localDict.keys(): if key not in self.stylesDict.keys(): self.stylesDict[key] = dict() self.stylesDict[key]['dbList'] = [] self.stylesDict[key]['style'] = localDict[key] if dbName not in self.stylesDict[key]['dbList']: self.stylesDict[key]['dbList'].append(dbName) self.dbDictChanged.emit('added', dbList) self.styleChanged.emit(self.stylesDict) #2- Iterate over selectedDbsDict and if there is a key not in dbList, close db and pop item if type == 'removed': for dbName in self.selectedDbsDict.keys(): if dbName in dbList: self.selectedDbsDict.pop(dbName) self.dbDictChanged.emit('removed', dbList) for key in self.stylesDict.keys(): for db in self.stylesDict[key]['dbList']: if db in dbList: idx = self.stylesDict[key]['dbList'].index(db) self.stylesDict[key]['dbList'].pop(idx) if len(self.stylesDict[key]['dbList']) == 0: self.stylesDict.pop(key) self.styleChanged.emit(self.stylesDict) def selectedFiles(self, dbList, type): """ Selects databases from a name list and database type """ #TODO: build selectedDbsDict and emit dbDictChanged() #1- Iterate over dbList and check if all layers on dbList are on dict. If not, add it. if type == 'added': for dbName in dbList: if dbName not in self.selectedDbsDict.keys(): localDb = self.dbFactory.createDbFactory('QSQLITE') localDb.connectDatabase(conn=self.spatialiteDict[dbName]) self.selectedDbsDict[dbName] = localDb #do get dicts localDict = localDb.getStyleDict( localDb.getDatabaseVersion()) for key in localDict.keys(): if key not in self.stylesDict.keys(): self.stylesDict[key] = dict() self.stylesDict[key]['dbList'] = [] self.stylesDict[key]['style'] = localDict[key] if dbName not in self.stylesDict[key]['dbList']: self.stylesDict[key]['dbList'].append(dbName) self.dbDictChanged.emit('added', dbList) self.styleChanged.emit(self.stylesDict) #2- Iterate over selectedDbsDict and if there is a key not in dbList, close db and pop item if type == 'removed': for dbName in self.selectedDbsDict.keys(): if dbName in dbList: self.selectedDbsDict.pop(dbName) self.dbDictChanged.emit('removed', dbList) for key in self.stylesDict.keys(): for db in self.stylesDict[key]['dbList']: if db in dbList: idx = self.stylesDict[key]['dbList'].index(db) self.stylesDict[key]['dbList'].pop(idx) if len(self.stylesDict[key]['dbList']) == 0: self.stylesDict.pop(key) self.styleChanged.emit(self.stylesDict) @pyqtSlot(int) def on_serverConnectionTab_currentChanged(self, currentTab): """ Changes the database type (spatialite/postgis) """ if currentTab == 0: self.clearSpatialiteTab() self.populatePostgisSelector() elif currentTab == 1: self.clearPostgisTab() self.populateSpatialiteSelector() pass def populatePostgisSelector(self): """ Populates the postgis database list according to the database type """ self.dbDict = { '2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': [], '3.0': [] } dbList = [] try: if self.serverWidget.abstractDb: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer( parentWidget=self) else: self.clearPostgisTab() return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.clearPostgisTab() dbList.sort() for (dbname, dbversion) in dbList: if dbversion in self.dbDict.keys(): self.dbDict[dbversion].append(dbname) else: self.dbDict['Non_EDGV'].append(dbname) comboText = self.postgisEdgvComboFilter.currentText() self.postgisCustomSelector.setInitialState( self.dbDict[self.comboDict[comboText]]) def populateSpatialiteSelector(self): """ Populates the spatialite database list according to the databse type """ self.dbDict = { '2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': [], '3.0': [] } self.spatialiteDict = dict() dbList = [] try: for dbPath in self.customFileSelector.fileNameList: auxAbstractDb = self.dbFactory.createDbFactory('QSQLITE') dbName = os.path.basename(dbPath).split('.')[0] self.path = os.path.dirname(dbPath) auxAbstractDb.connectDatabase(conn=dbPath) version = auxAbstractDb.getDatabaseVersion() dbList.append((dbName, version)) self.spatialiteDict[dbName] = dbPath except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.clearSpatialiteTab() dbList.sort() for (dbname, dbversion) in dbList: if dbversion in self.dbDict.keys(): self.dbDict[dbversion].append(dbname) # if len(self.dbDict['2.1.3']) == 0: # self.spatialiteEdgvComboFilter.setCurrentIndex(1) comboText = self.spatialiteEdgvComboFilter.currentText() self.spatialiteCustomSelector.setInitialState( self.dbDict[self.comboDict[comboText]]) def clearSpatialiteTab(self): """ Clears the postgis tab, returning it to the original state """ self.spatialiteCustomSelector.clearAll() self.serverWidget.clearAll() self.dbDict = { '2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': [], '3.0': [] } self.customFileSelector.resetAll() self.edgvType = None self.selectedDbsDict = dict() self.resetAll.emit() @pyqtSlot(int) def on_postgisEdgvComboFilter_currentIndexChanged(self): """ Updates the postgis databases according to its type """ comboText = self.postgisEdgvComboFilter.currentText() self.postgisCustomSelector.resetSelections() self.postgisCustomSelector.setInitialState( self.dbDict[self.comboDict[comboText]]) self.serverConnectionTab self.edgvType = self.comboDict[comboText] self.resetAll.emit() @pyqtSlot(int) def on_spatialiteEdgvComboFilter_currentIndexChanged(self): """ Updates the postgis databases according to its type """ comboText = self.spatialiteEdgvComboFilter.currentText() self.spatialiteCustomSelector.setInitialState( self.dbDict[self.comboDict[comboText]]) self.edgvType = self.comboDict[comboText] self.resetAll.emit() def clearPostgisTab(self): """ Clears the spatialite tab, returning it to the original state """ self.postgisCustomSelector.clearAll() self.serverWidget.clearAll() self.dbDict = { '2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': [], '3.0': [] } self.edgvType = None self.selectedDbsDict = dict() self.resetAll.emit() def getStyles(self, type, abstractDb): """ Gets database styles. If the structure to store styles is not yet created, we should create it. """ dbVersion = abstractDb.getDatabaseVersion() abstractDb.checkAndCreateStyleTable() styles = abstractDb.getStyleDict(dbVersion) self.styleChanged.emit(type, styles)
class ComplexWindow(QtGui.QDockWidget, FORM_CLASS): def __init__(self, iface, parent=None): """Constructor.""" super(ComplexWindow, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self.dbButton.clicked.connect(self.getDataSources) self.dbCombo.activated.connect(self.updateComplexClass) self.complexCombo.activated.connect(self.loadAssociatedFeatures) self.iface.newProjectCreated.connect(self.clearDock) self.abstractDb = None self.databases = None self.abstractDbFactory = DbFactory() def __del__(self): """ Destructor """ self.renewDb def renewDb(self): """ Deletes the current abstractDb """ if self.abstractDb: del self.abstractDb self.abstractDb = None def clearDock(self): """ Clears the complex dock widget """ self.treeWidget.clear() self.dbCombo.clear() self.complexCombo.clear() #verificar se é necessario def isSpatialiteDatabase(self, dbName): """ Checks if the database in use is a spatialite database """ (dataSourceUri, credentials) = self.databases[dbName] if dataSourceUri.host() == "": return True return False def getUserCredentials(self, lyr): """ Gets user credentials to acess the database """ dataSourceUri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) if dataSourceUri.host() == '': return (None, None) if dataSourceUri.password() != '': return (dataSourceUri.username(), dataSourceUri.password()) connInfo = dataSourceUri.connectionInfo() (success, user, passwd ) = QgsCredentials.instance().get(connInfo, dataSourceUri.username(), None) # Put the credentials back (for yourself and the provider), as QGIS removes it when you "get" it if success: QgsCredentials.instance().put(connInfo, user, passwd) else: return (None, None) return (user, passwd) def updateComplexClass(self): """ Updates the complex classes in the complex combo box """ self.renewDb() if self.dbCombo.currentIndex() == 0: return dbName = self.dbCombo.currentText() (dataSourceUri, credentials) = self.databases[dbName] #verifying the connection type if self.isSpatialiteDatabase(dbName): self.abstractDb = self.abstractDbFactory.createDbFactory('QSQLITE') self.abstractDb.connectDatabase(dataSourceUri.database()) else: self.abstractDb = self.abstractDbFactory.createDbFactory('QPSQL') database = dbName host = dataSourceUri.host() port = int(dataSourceUri.port()) user = credentials[0] password = credentials[1] self.abstractDb.connectDatabaseWithParameters(host, port, database, user, password) try: self.abstractDb.checkAndOpenDb() self.populateComboBox() except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr("Critical!"), ':'.join(e.args)) def populateComboBox(self): """ Fills the complex combo box with complex classes """ #getting all complex tables self.complexCombo.clear() self.complexCombo.addItem(self.tr("select a complex class")) complexClasses = [] try: complexClasses = self.abstractDb.listComplexClassesFromDatabase() except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr("Critical!"), ':'.join(e.args)) QgsMessageLog.logMessage(e.args[0], 'DSG Tools Plugin', QgsMessageLog.CRITICAL) self.complexCombo.addItems(complexClasses) def getDataSources(self): """ Obtains the available databases from the layers loaded in the TOC """ self.dbCombo.clear() self.dbCombo.addItem(self.tr("select a database")) if self.databases: self.databases.clear() #dictionary of names and datasourceUri self.databases = dict() self.layers = self.iface.mapCanvas().layers() for layer in self.layers: dataSourceUri = QgsDataSourceURI(layer.dataProvider().dataSourceUri()) dbName = dataSourceUri.database() if dbName not in self.databases.keys(): self.databases[dbName] = (dataSourceUri, self.getUserCredentials(layer)) #populating the combo self.dbCombo.addItem(dbName) @pyqtSlot(bool) def on_managePushButton_clicked(self): """ Opens the dialog to manage complex features """ #opens a dialog to manage complexes if not self.abstractDb: QMessageBox.critical(self.iface.mainWindow(), self.tr("Critical!"), self.tr('Select a database before managing a complex!')) return dlg = ManageComplexDialog(self.iface, self.abstractDb, self.complexCombo.currentText()) #connects a signal to update the tree widget when done QObject.connect(dlg, SIGNAL(("tableUpdated()")), self.loadAssociatedFeatures) #connects a signal to disassociate features from complex before removal QObject.connect(dlg, SIGNAL(("markedToRemove( PyQt_PyObject )")), self.disassociateFeatures) result = dlg.exec_() if result: pass @pyqtSlot(bool) def on_associatePushButton_clicked(self): """ Slot used to associate features to a complex """ self.associateFeatures() @pyqtSlot(bool) def on_zoomButton_clicked(self): """ Slot used to zoom the mapcanvas to the features associated to a complex """ #case no item is selected we should warn the user if len(self.treeWidget.selectedItems()) == 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an item to zoom.")) return item = self.treeWidget.selectedItems()[0] #checking if the item is a complex (it should have depth = 2) if self.depth(item) == 2: bbox = QgsRectangle() for i in range(item.childCount()): aggregated_item = item.child(i) aggregated_class = aggregated_item.text(0) #getting the layer the needs to be updated aggregated_layer = None layers = self.iface.mapCanvas().layers() for layer in layers: if layer.name() == aggregated_class: aggregated_layer = layer break if not aggregated_layer: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The associated classes must be loaded in the table of contents.")) return for j in range(aggregated_item.childCount()): id = aggregated_item.child(j).text(0) freq = QgsFeatureRequest() freq.setFilterFid(int(id)) feature = layer.getFeatures( freq ).next() if j==0 and i == 0: bbox=feature.geometry().boundingBox() bbox.combineExtentWith(feature.geometry().boundingBox()) self.iface.mapCanvas().setExtent(bbox) self.iface.mapCanvas().refresh() else: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Select a complex.")) return def disassociateFeatures(self, toBeRemoved): """ Disassociates features from a complex toBeremoved: uuid of the complex that will have all its associated features disassociated """ for uuid in toBeRemoved: items = self.treeWidget.findItems(uuid, Qt.MatchRecursive, 1) if len(items) == 0: return complexItem = items[0] count = complexItem.childCount() for i in range(count): self.disassociateAggregatedClass(complexItem.child(i)) def disassociateAggregatedClass(self, item): """ Disassociates a particular class from a complex item: aggregated class to be disassociated """ aggregated_class = item.text(0) uuid = item.parent().text(1) complex = item.parent().parent().text(0) link_column = '' try: link_column = self.abstractDb.obtainLinkColumn(complex, aggregated_class) except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), 'DSG Tools Plugin', QgsMessageLog.CRITICAL) #getting the layer the needs to be updated aggregated_layer = None layers = self.iface.mapCanvas().layers() for layer in layers: #in case of spatialite databases when a complex class is added as a layer it's name has 'complexos_' if layer.name() == aggregated_class or layer.name() == 'complexos_'+aggregated_class: aggregated_layer = layer break if not aggregated_layer: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The class you're trying to disassociate must loaded in the table of contents.")) return for i in range(item.childCount()): #feature id that will be updated id = item.child(i).text(0) self.updateLayerOnDisassociate(layer, aggregated_class, link_column, id) def disassociateAggregatedId(self, item): """ Disassociates a particular feature from a complex item: aggregated feature to be disassociated """ aggregated_class = item.parent().text(0) uuid = item.parent().parent().text(1) complex = item.parent().parent().parent().text(0) link_column = '' try: link_column = self.abstractDb.obtainLinkColumn(complex, aggregated_class) except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), 'DSG Tools Plugin', QgsMessageLog.CRITICAL) #getting the layer the needs to be updated aggregated_layer = None layers = self.iface.mapCanvas().layers() for layer in layers: #in case of spatialite databases when a complex class is added as a layer it's name has 'complexos_' if layer.name() == aggregated_class or layer.name() == 'complexos_'+aggregated_class: aggregated_layer = layer break if not aggregated_layer: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The class you're trying to disassociate must loaded in the table of contents.")) return #feature id that will be updated id = item.text(0) self.updateLayerOnDisassociate(layer, aggregated_class, link_column, id) def updateLayerOnDisassociate(self, layer, aggregated_class, link_column, id): """ Updates the layer upon disassociation from complex layer: layer that will be afected aggregated_class: aggregated class link_column: link column between complex and class id: feature id """ try: if self.abstractDb.isComplexClass(aggregated_class): self.abstractDb.disassociateComplexFromComplex(aggregated_class, link_column, id) else: #field index that will be set to NULL fieldIndex = [i for i in range(len(layer.dataProvider().fields())) if layer.dataProvider().fields()[i].name() == link_column] #attribute pair that will be changed attrs = {fieldIndex[0]:None} #actual update in the database layer.dataProvider().changeAttributeValues({int(id):attrs}) except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr("Critical!"), e.args[0]) QgsMessageLog.logMessage(':'.join(e.args), 'DSG Tools Plugin', QgsMessageLog.CRITICAL) @pyqtSlot(bool) def on_disassociatePushButton_clicked(self): """ Starts the disassociation process. It will firts check the depth of the item that need to be disassociated and them call the correct method to to the job. It can be a particular class or a particular feature """ #case no item is selected we should warn the user if len(self.treeWidget.selectedItems()) == 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an aggregated class or aggregated id.")) return item = self.treeWidget.selectedItems()[0] #checking if the item is a complex (it should have depth = 2) if self.depth(item) == 3: self.disassociateAggregatedClass(item) elif self.depth(item) == 4: self.disassociateAggregatedId(item) else: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an aggregated class or aggregated id.")) return self.loadAssociatedFeatures() def loadAssociatedFeatures(self): """ Loads all features associated to a complex """ self.treeWidget.clear() if self.complexCombo.currentIndex() == 0: return complex = self.complexCombo.currentText() associatedDict = dict() try: associatedDict = self.abstractDb.loadAssociatedFeatures(complex) except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), 'DSG Tools Plugin', QgsMessageLog.CRITICAL) for name in associatedDict.keys(): for complex_uuid in associatedDict[name].keys(): self.addAssociatedFeature(complex, name, complex_uuid, None, None) for aggregated_class in associatedDict[name][complex_uuid]: for ogc_fid in associatedDict[name][complex_uuid][aggregated_class]: self.addAssociatedFeature(complex, name, complex_uuid, aggregated_class, ogc_fid) def depth(self, item): """ Calculates the item deth in the tree """ #calculates the depth of the item depth = 0 while item is not None: item = item.parent() depth += 1 return depth def associateFeatures(self): """ Associates all features selected in the map canvas to a complex. """ #case no item is selected we should warn the user if len(self.treeWidget.selectedItems()) == 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select a complex.")) return item = self.treeWidget.selectedItems()[0] #checking if the item is a complex (it should have depth = 2) if self.depth(item) != 2: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select a complex.")) return complex = self.complexCombo.currentText() #uuid to be adjust on the selected features uuid = item.text(1) #getting the selected features forbiddenLayers = [] self.layers = self.iface.mapCanvas().layers() for layer in self.layers: if layer.type() != QgsMapLayer.VectorLayer: continue #case no fetures selected we proceed to the next one selectedFeatures = layer.selectedFeatures() if len(selectedFeatures) == 0: continue #obtaining the link column column_name = '' try: column_name = self.abstractDb.obtainLinkColumn(complex, layer.name()) except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), 'DSG Tools Plugin', QgsMessageLog.CRITICAL) #storing the names of the incompatible layers if column_name == '': forbiddenLayers.append(layer.name()) continue for feature in selectedFeatures: fieldIndex = [i for i in range(len(layer.dataProvider().fields())) if layer.dataProvider().fields()[i].name() == column_name] #feature id that will be updated id = feature.id() #attribute pair that will be changed attrs = {fieldIndex[0]:uuid} #actual update in the database layer.dataProvider().changeAttributeValues({id:attrs}) #show the message of incompatible classes to associate if len(forbiddenLayers) > 0: message = "" message += self.tr("The following layers cannot be associated to complexes from ")+self.complexCombo.currentText()+":\n" for text in forbiddenLayers: message += text+"\n" QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), message) #updating the tree widget self.loadAssociatedFeatures() def createTreeItem(self, parent, text, uuid = ""): """ Creates tree items parent: parent item text: item text uuid: complex uuid """ count = parent.childCount() children = [] #making a list of item names for i in range(count): child = parent.child(i) children.append(child.text(0)) #checking if the text is already in the tree widget if text not in children: #case not it should be created item = QTreeWidgetItem(parent) item.setExpanded(True) item.setText(0,text) #adding the complex uuid to the tree widget if uuid != "": item.setText(1, str(uuid)) else: #case already exists the correspondind item should be returned for i in range(count): child = parent.child(i) if child.text(0) == text: item = child return item def addAssociatedFeature(self, className, complexName, complexId, associatedClass, associatedId): """ Adds a feature to a complex className: class name complexName: complex name complexId: complex uuid associatedClass: associated class associatedId: associated id """ #get the corresponding top level item classNameItem = self.createTreeItem(self.treeWidget.invisibleRootItem(), className) #get the corresponding complex item complexNameItem = self.createTreeItem(classNameItem, complexName, complexId) if associatedClass and associatedId: #get the corresponding class item associatedClassItem = self.createTreeItem(complexNameItem, associatedClass) #creates the corresponding associated item self.createTreeItem(associatedClassItem, str(associatedId)) def __test(self, x): if (x.parent() == None) : return True else: return False
class BatchDbManager(QtGui.QDialog, FORM_CLASS): EDGV213, EDGV_FTer_2a_Ed, Non_EDGV = range(3) def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.showTabs(show=False) #setting the sql generator self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.checkSuperUser) self.serverWidget.abstractDbLoaded.connect( self.populateOtherInterfaces) self.dbsCustomSelector.setTitle(self.tr('Server Databases')) self.dbsCustomSelector.selectionChanged.connect(self.showTabs) self.dbsCustomSelector.selectionChanged.connect( self.populateStylesInterface) self.dbsCustomSelector.selectionChanged.connect( self.populateOtherInterfaces) self.previousTab = 0 self.dbDict = {'2.1.3': [], 'FTer_2a_Ed': [], 'Non_EDGV': []} self.correspondenceDict = { self.tr('Load Database Model EDGV Version 2.1.3'): '2.1.3', self.tr('Load Database Model EDGV Version FTer_2a_Ed'): 'FTer_2a_Ed', self.tr('Load Other Database Models'): 'Non_EDGV' } @pyqtSlot(bool) def on_closePushButton_clicked(self): self.done(0) def showTabs(self, show=True): if show: self.tabWidget.show() else: self.tabWidget.hide() def populateListWithDatabasesFromServer(self): try: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer( parentWidget=self) except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) dbList.sort() for (dbname, dbversion) in dbList: if dbversion not in self.dbDict.keys(): dbversion = 'Non_EDGV' if dbname not in self.dbDict[dbversion]: self.dbDict[dbversion].append(dbname) def setDatabases(self): self.populateListWithDatabasesFromServer() @pyqtSlot(int) def on_edgvComboFilter_currentIndexChanged(self, idx): if idx != -1 and idx != 0: self.dbsCustomSelector.setInitialState(self.dbDict[ self.correspondenceDict[self.edgvComboFilter.currentText()]]) def checkSuperUser(self): try: if self.serverWidget.abstractDb.checkSuperUser(): self.setDatabases() else: QMessageBox.warning( self, self.tr('Info!'), self. tr('Connection refused. Connect with a super user to inspect server.' )) except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) def getSelectedDbList(self): return self.dbsCustomSelector.toLs def instantiateAbstractDbs(self, instantiateTemplates=False): dbsDict = dict() selectedDbNameList = self.getSelectedDbList() if instantiateTemplates: for templateName in ['template_213', 'template_FTer_2a_Ed']: if templateName not in selectedDbNameList: if templateName != 'dsgtools_admindb': selectedDbNameList.append(templateName) for dbName in selectedDbNameList: localDb = self.dbFactory.createDbFactory('QPSQL') localDb.connectDatabaseWithParameters( self.serverWidget.abstractDb.db.hostName(), self.serverWidget.abstractDb.db.port(), dbName, self.serverWidget.abstractDb.db.userName(), self.serverWidget.abstractDb.db.password()) dbsDict[dbName] = localDb return dbsDict def closeAbstractDbs(self, dbsDict): exceptionDict = dict() for dbName in dbsDict.keys(): try: dbsDict[dbName].db.close() except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return exceptionDict def outputMessage(self, header, successList, exceptionDict): msg = header if len(successList) > 0: msg += self.tr('\nSuccessful databases: ') msg += ', '.join(successList) msg += self.logInternalError(exceptionDict) QMessageBox.warning(self, self.tr('Operation Complete!'), msg) def logInternalError(self, exceptionDict): msg = '' errorDbList = exceptionDict.keys() if len(errorDbList) > 0: msg += self.tr('\nDatabases with error:') msg += ', '.join(errorDbList) msg += self.tr( '\nError messages for each database were output in qgis log.') for errorDb in errorDbList: QgsMessageLog.logMessage( self.tr('Error for database ') + errorDb + ': ' + exceptionDict[errorDb], "DSG Tools Plugin", QgsMessageLog.CRITICAL) return msg @pyqtSlot(bool) def on_dropDatabasePushButton_clicked(self): selectedDbNameList = self.getSelectedDbList() if len(selectedDbNameList) == 0: QMessageBox.warning( self, self.tr('Warning'), self.tr('Please select one or more databases to drop!')) if QtGui.QMessageBox.question( self, self.tr('Question'), self.tr('Do you really want to drop databases: ') + ', '.join(selectedDbNameList), QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) == QtGui.QMessageBox.Cancel: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchDropDbs(selectedDbNameList) QApplication.restoreOverrideCursor() self.setDatabases() header = self.tr('Drop operation complete. \n') self.outputMessage(header, successList, exceptionDict) self.dbsCustomSelector.setInitialState(self.dbsCustomSelector.fromLs) @pyqtSlot(bool) def on_upgradePostgisPushButton_clicked(self): selectedDbNameList = self.getSelectedDbList() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchUpgradePostgis( selectedDbNameList) QApplication.restoreOverrideCursor() self.setDatabases() header = self.tr('Upgrade Posgtis operation complete. \n') self.outputMessage(header, successList, exceptionDict) def batchUpgradePostgis(self, dbList): exceptionDict = dict() successList = [] dbsDict = self.instantiateAbstractDbs(instantiateTemplates=True) self.closeAbstractDbs(dbsDict) for dbName in dbsDict.keys(): try: if self.serverWidget.abstractDb.checkIfTemplate(dbName): self.serverWidget.abstractDb.setDbAsTemplate( dbName=dbName, setTemplate=False) dbsDict[dbName].upgradePostgis() self.serverWidget.abstractDb.setDbAsTemplate( dbName=dbName, setTemplate=True) successList.append(dbName) else: dbsDict[dbName].upgradePostgis() successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def batchDropDbs(self, dbList): exceptionDict = dict() successList = [] dbsDict = self.instantiateAbstractDbs() self.closeAbstractDbs(dbsDict) for dbName in dbList: try: self.serverWidget.abstractDb.dropDatabase(dbName) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict @pyqtSlot(bool) def on_importStylesPushButton_clicked(self): dbsDict = self.instantiateAbstractDbs() exceptionDict = dict() versionList = [] for dbName in dbsDict.keys(): try: version = dbsDict[dbName].getDatabaseVersion() if version not in versionList: versionList.append(version) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) if len(exceptionDict.keys()) > 0: self.logInternalError(exceptionDict) if len(versionList) > 1: QMessageBox.warning( self, self.tr('Warning'), self.tr('Multiple edgv versions are not allowed!')) return styleDir = self.getStyleDir(versionList) styleList = self.getStyleList(styleDir) dlg = SelectStyles(styleList) dlg.exec_() selectedStyles = dlg.selectedStyles if len(selectedStyles) == 0: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchImportStyles( dbsDict, styleDir, selectedStyles, versionList[0]) QApplication.restoreOverrideCursor() header = self.tr('Import operation complete. \n') self.outputMessage(header, successList, exceptionDict) self.populateStylesInterface() closeExceptionDict = self.closeAbstractDbs(dbsDict) self.logInternalError(closeExceptionDict) def getStyleList(self, styleDir): #TODO: Reimplement styleList = [] version = None if os.path.basename(styleDir) in ['edgv_213', 'edgv_FTer_2a_Ed']: version = os.path.basename(styleDir) else: parentFolder = os.path.dirname(styleDir) version = os.path.basename(parentFolder) for style in os.walk(styleDir).next()[1]: styleList.append('/'.join([version, style])) if len(styleList) == 0: styleList = [version + '/' + os.path.basename(styleDir)] return styleList def batchImportStyles(self, dbsDict, styleDir, styleList, version): exceptionDict = dict() successList = [] for dbName in dbsDict.keys(): for style in styleList: try: dbsDict[dbName].importStylesIntoDb(style) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def getStyleDir(self, versionList): currentPath = os.path.join( os.path.dirname(__file__), '..', 'Styles', self.serverWidget.abstractDb.versionFolderDict[versionList[0]]) return currentPath def getStylesFromDbs(self, perspective='style'): ''' Returns a dict of styles in a form acording to perspective: if perspective = 'style' : [styleName][dbName][tableName] = timestamp if perspective = 'database' : [dbName][styleName][tableName] = timestamp ''' dbsDict = self.instantiateAbstractDbs() allStylesDict = dict() exceptionDict = dict() for dbName in dbsDict.keys(): try: newDict = dbsDict[dbName].getAllStylesDict(perspective) allStylesDict = self.utils.mergeDict(newDict, allStylesDict) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) if len(exceptionDict.keys()) > 0: self.logInternalError(exceptionDict) return allStylesDict def createItem(self, parent, text, column): item = QtGui.QTreeWidgetItem(parent) item.setText(column, text) return item def populateStylesInterface(self): self.stylesTreeWidget.clear() allStylesDict = self.getStylesFromDbs() rootNode = self.stylesTreeWidget.invisibleRootItem() for styleName in allStylesDict.keys(): parentStyleItem = self.createItem(rootNode, styleName, 0) dbList = allStylesDict[styleName].keys() parentTimeList = [] for dbName in dbList: dbItem = self.createItem(parentStyleItem, dbName, 1) tableList = allStylesDict[styleName][dbName].keys() tableList.sort() timeList = [] for table in tableList: tableItem = self.createItem(dbItem, table, 2) timeStamp = allStylesDict[styleName][dbName][ table].toString() timeList.append(timeStamp) tableItem.setText( 3, allStylesDict[styleName][dbName][table].toString()) parentTimeList.append(max(timeList)) dbItem.setText(3, max(timeList)) @pyqtSlot(bool) def on_deleteStyles_clicked(self): dbsDict = self.instantiateAbstractDbs() styleDict = self.getStylesFromDbs() styleList = styleDict.keys() dlg = SelectStyles(styleList) dlg.exec_() selectedStyles = dlg.selectedStyles QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchDeleteStyles(dbsDict, styleDict) QApplication.restoreOverrideCursor() header = self.tr('Delete operation complete. \n') self.outputMessage(header, successList, exceptionDict) self.populateStylesInterface() closeExceptionDict = self.closeAbstractDbs(dbsDict) self.logInternalError(closeExceptionDict) def batchDeleteStyles(self, dbsDict, styleDict): exceptionDict = dict() successList = [] for style in styleDict.keys(): for dbName in styleDict[style].keys(): try: dbsDict[dbName].deleteStyle(style) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def getSQLFile(self): fd = QFileDialog() filename = fd.getOpenFileName(caption=self.tr('Select a SQL file'), filter=self.tr('sql file (*.sql)')) return filename @pyqtSlot(bool) def on_customizeFromSQLFilePushButton_clicked(self): dbsDict = self.instantiateAbstractDbs() sqlFilePath = self.getSQLFile() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchCustomizeFromSQLFile( dbsDict, sqlFilePath) QApplication.restoreOverrideCursor() header = self.tr('Customize from SQL file operation complete. \n') self.outputMessage(header, successList, exceptionDict) closeExceptionDict = self.closeAbstractDbs(dbsDict) self.logInternalError(closeExceptionDict) def batchCustomizeFromSQLFile(self, dbsDict, sqlFilePath): exceptionDict = dict() successList = [] for dbName in dbsDict.keys(): try: dbsDict[dbName].runSqlFromFile(sqlFilePath) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def populateOtherInterfaces(self): dbsDict = self.instantiateAbstractDbs() if self.edgvComboFilter.currentIndex() != 0: edgvVersion = self.correspondenceDict[ self.edgvComboFilter.currentText()] self.permissionWidget.setParameters(self.serverWidget.abstractDb, dbsDict, edgvVersion) # self.customizationManagerWidget.setParameters(self.serverWidget.abstractDb, edgvVersion, dbsDict = dbsDict) self.fieldToolBoxConfigManagerWidget.setParameters( self.serverWidget.abstractDb, edgvVersion, dbsDict=dbsDict) self.earthCoverageManagerWidget.setParameters( self.serverWidget.abstractDb, edgvVersion, dbsDict=dbsDict)
class ExploreServerWidget(QtGui.QWidget, FORM_CLASS): abstractDbLoaded = pyqtSignal() serverAbstractDbLoaded = pyqtSignal(AbstractDb) clearWidgets = pyqtSignal() def __init__(self, parent=None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.superNeeded = False self.dbFactory = DbFactory() self.abstractDb = None def getServers(self): """ Gets server from QSettings """ settings = QSettings() settings.beginGroup('PostgreSQL/servers') currentConnections = settings.childGroups() settings.endGroup() return currentConnections def getServerConfiguration(self, name): """ Gets server configuration name: server name """ settings = QSettings() settings.beginGroup('PostgreSQL/servers/' + name) host = settings.value('host') port = settings.value('port') user = settings.value('username') password = settings.value('password') settings.endGroup() return (host, port, user, password) def browseServer(self, dbList, host, port, user, password): """ Browses server for EDGV databases dbList: databases list host: server host ip address port: server port user: user name password: password """ canLoad = True if self.superNeeded: canLoad = False try: if self.serverWidget.abstractDb.checkSuperUser(): canLoad = True else: QMessageBox.warning( self, self.tr('Info!'), self. tr('Connection refused. Connect with a super user to inspect server.' )) return [] except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) if canLoad: progress = ProgressWidget( 1, len(dbList), self.tr('Loading databases from server... '), parent=self) progress.initBar() gen = self.factory.createSqlGenerator(False) edvgDbList = [] for database in dbList: db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): qgis.utils.iface.messageBar().pushMessage( 'DB :' + database + '| msg: ' + db.lastError().databaseText(), level=QgsMessageBar.CRITICAL) query = QSqlQuery(db) if query.exec_(gen.getEDGVVersion()): while query.next(): version = query.value(0) if version: edvgDbList.append((database, version)) progress.step() return edvgDbList def getDbsFromServer(self, name): """ Gets server databases name: server name """ gen = self.factory.createSqlGenerator(False) (host, port, user, password) = self.getServerConfiguration(name) database = 'postgres' db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): QgsMessageLog.logMessage(db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) QMessageBox.critical( self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) query = QSqlQuery(gen.getDatabasesFromServer(), db) if not query.isActive(): QMessageBox.critical( self.iface.mainWindow(), self.tr('Critical'), self.tr("Problem executing query: ") + query.lastError().text()) dbList = [] while query.next(): dbList.append(query.value(0)) return self.browseServer(dbList, host, port, user, password) @pyqtSlot(bool) def on_createNewServerPushButton_clicked(self): """ Opens the View Server dialog """ createNewServer = ViewServers(self) result = createNewServer.exec_() self.populateServersCombo() def populateServersCombo(self): """ Populates the server name combo box """ self.serversCombo.clear() self.serversCombo.addItem(self.tr('Select Server')) currentConnections = self.getServers() for connection in currentConnections: (host, port, user, password) = self.getServerConfiguration(connection) self.serversCombo.addItem('{3} ({0}@{1}:{2})'.format( user, host, port, connection)) @pyqtSlot(int) def on_serversCombo_currentIndexChanged(self): """ Updates the server databases """ self.clearWidgets.emit() if self.serversCombo.currentIndex() != 0: self.abstractDb = self.dbFactory.createDbFactory('QPSQL') if not self.abstractDb: QMessageBox.critical( self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) return (host, port, user, password) = self.abstractDb.getServerConfiguration( self.serversCombo.currentText().split('(')[0][0:-1]) if host or port or user: self.abstractDb.connectDatabaseWithParameters( host, port, 'postgres', user, password) if self.superNeeded: try: if not self.abstractDb.checkSuperUser(): QMessageBox.warning( self, self.tr('Info!'), self. tr('Connection refused. Connect with a super user to inspect server.' )) self.serversCombo.setCurrentIndex(0) return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.abstractDbLoaded.emit() else: try: if self.abstractDb: self.abstractDb.__del__() self.abstractDb = None except: pass self.serverAbstractDbLoaded.emit(self.abstractDb) def getServerParameters(self): """ Gets postgis server parameters """ if self.serversCombo.currentIndex() != 0: return self.abstractDb.getServerConfiguration( self.serversCombo.currentText().split('(')[0][0:-1]) else: return (None, None, None, None) def clearAll(self): """ Resets the widget """ try: if self.abstractDb: self.abstractDb.__del__() self.abstractDb = None except: pass self.serversCombo.setCurrentIndex(0)
class PostgisDbThread(GenericThread): def __init__(self, parent = None): """ Constructor. """ super(PostgisDbThread, self).__init__() self.factory = SqlGeneratorFactory() #setting the sql generator self.gen = self.factory.createSqlGenerator(False) self.messenger = PostgisDbMessages(self) self.dbFactory = DbFactory() self.parent = parent def setParameters(self, abstractDb, dbName, version, epsg, stopped): """ Sets thread parameters """ self.abstractDb = abstractDb #database = postgis self.dbName = dbName self.db = None self.version = version self.epsg = epsg self.stopped = stopped def run(self): """ Runs the process """ # Processing ending (ret, msg) = self.createDatabaseStructure() self.signals.processingFinished.emit(ret, msg, self.getId()) def connectToTemplate(self, setInnerDb = True): """ Connects to the template database to speed up database creation :return: """ database = self.abstractDb.getTemplateName(self.version) host = self.abstractDb.db.hostName() port = self.abstractDb.db.port() user = self.abstractDb.db.userName() password = self.abstractDb.db.password() template = self.dbFactory.createDbFactory('QPSQL') template.connectDatabaseWithParameters(host, port, database, user, password) template.checkAndOpenDb() if setInnerDb: self.db = template.db return template def createDatabaseStructure(self): """ Creates database structure according to the selected edgv version """ currentPath = os.path.dirname(__file__) currentPath = os.path.join(currentPath, '..', '..', 'DbTools', 'PostGISTool') if self.version == '2.1.3': edgvPath = os.path.join(currentPath, 'sqls', '213', 'edgv213.sql') elif self.version == '3.0': edgvPath = os.path.join(currentPath, 'sqls', '3', 'edgv3.sql') elif self.version == 'FTer_2a_Ed': edgvPath = os.path.join(currentPath, 'sqls', 'FTer_2a_Ed', 'edgvFter_2a_Ed.sql') else: pass return self.loadDatabaseStructure(edgvPath) def loadDatabaseStructure(self, edgvPath): """ Loads the database structure edgvPath: path to the databse sql """ commands = [] hasTemplate = self.abstractDb.checkTemplate(self.version) if hasTemplate: templateDb = self.connectToTemplate(setInnerDb = False) mustUpdateTemplate = templateDb.checkTemplateImplementationVersion() if mustUpdateTemplate: templateName = templateDb.db.databaseName() templateDb.__del__() self.abstractDb.dropDatabase(templateName, dropTemplate = True) hasTemplate = False if not hasTemplate: file = codecs.open(edgvPath, encoding='utf-8', mode="r") sql = file.read() sql = sql.replace('[epsg]', '4674') file.close() commands = [i for i in sql.split('#') if i != ''] # Progress bar steps calculated self.signals.rangeCalculated.emit(len(commands)+4, self.getId()) if not hasTemplate: try: self.abstractDb.createTemplateDatabase(self.version) self.signals.stepProcessed.emit(self.getId()) self.connectToTemplate() self.signals.stepProcessed.emit(self.getId()) except Exception as e: return (0, self.messenger.getProblemFeedbackMessage()+'\n'+':'.join(e.args)) self.db.open() self.db.transaction() query = QSqlQuery(self.db) for command in commands: if not self.stopped[0]: if not query.exec_(command): QgsMessageLog.logMessage(self.messenger.getProblemMessage(command, query), "DSG Tools Plugin", QgsMessageLog.CRITICAL) self.db.rollback() self.db.close() self.dropDatabase(self.db) return (0, self.messenger.getProblemFeedbackMessage()) # Updating progress self.signals.stepProcessed.emit(self.getId()) else: self.db.rollback() self.db.close() self.dropDatabase(self.db) QgsMessageLog.logMessage(self.messenger.getUserCanceledFeedbackMessage(), "DSG Tools Plugin", QgsMessageLog.INFO) return (-1, self.messenger.getUserCanceledFeedbackMessage()) self.db.commit() if self.version == '2.1.3': sql = 'ALTER DATABASE %s SET search_path = "$user", public, topology,\'cb\',\'complexos\',\'dominios\';' % self.db.databaseName() elif self.version == 'FTer_2a_Ed': sql = 'ALTER DATABASE %s SET search_path = "$user", public, topology,\'pe\',\'ge\',\'complexos\',\'dominios\';' % self.db.databaseName() elif self.version == '3.0': sql = 'ALTER DATABASE %s SET search_path = "$user", public, topology,\'edgv\',\'complexos\',\'dominios\';' % self.db.databaseName() if sql: if not query.exec_(sql): QgsMessageLog.logMessage(self.messenger.getProblemMessage(command, query), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return (0, self.messenger.getProblemFeedbackMessage()) #this commit was missing, so alter database statement was not commited. self.db.commit() self.db.close() self.abstractDb.setDbAsTemplate(self.version) #creates from template if not self.stopped[0]: templateName = self.abstractDb.getTemplateName(self.version) self.abstractDb.createDbFromTemplate(self.dbName, templateName, parentWidget = self.parent) self.signals.stepProcessed.emit(self.getId()) #5. alter spatial structure createdDb = self.dbFactory.createDbFactory('QPSQL') createdDb.connectDatabaseWithParameters(self.abstractDb.db.hostName(), self.abstractDb.db.port(), self.dbName, self.abstractDb.db.userName(), self.abstractDb.db.password()) errorTuple = createdDb.updateDbSRID(self.epsg, parentWidget = self.parent, threading = True) # if an error occur during the thread we should pass the message to the main thread if errorTuple: QgsMessageLog.logMessage(self.messenger.getProblemMessage(errorTuple[0], errorTuple[1]), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return (0, self.messenger.getProblemFeedbackMessage()) self.signals.stepProcessed.emit(self.getId()) else: QgsMessageLog.logMessage(self.messenger.getUserCanceledFeedbackMessage(), "DSG Tools Plugin", QgsMessageLog.INFO) return (-1, self.messenger.getUserCanceledFeedbackMessage()) QgsMessageLog.logMessage(self.messenger.getSuccessFeedbackMessage(), "DSG Tools Plugin", QgsMessageLog.INFO) return (1, self.messenger.getSuccessFeedbackMessage()) def dropDatabase(self,db): """ Drops the created database case a problem occurs during database creation db: QSqlDatabase to be dropped """ host = db.hostName() port = db.port() user = db.userName() password = db.password() database = 'postgres' pgDB = QSqlDatabase('QPSQL') pgDB.setHostName(host) pgDB.setPort(port) pgDB.setUserName(user) pgDB.setPassword(password) pgDB.setDatabaseName(database) if not pgDB.open(): return False sql = self.gen.dropDatabase(db.databaseName()) query = QSqlQuery(pgDB) return query.exec_(sql)
class ExploreDb(QtGui.QDialog, FORM_CLASS): def __init__(self, parent=None): """ Constructor """ super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.localDb = None self.serverWidget.populateServersCombo() #signal connections self.serverWidget.abstractDbLoaded.connect(self.checkSuperUser) self.serverWidget.clearWidgets.connect(self.clearAll) self.treeWidget.setContextMenuPolicy(Qt.CustomContextMenu) self.treeWidget.customContextMenuRequested.connect( self.createMenuAssigned) def populateListWithDatabasesFromServer(self): ''' Populates databases list from server ''' dbList = [] try: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer() except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) dbList.sort() for (dbname, dbversion) in dbList: item = QListWidgetItem(self.dbListWidget) item.setText(dbname + ' (EDGV v. ' + dbversion + ')') item.setData(Qt.UserRole, dbname) @pyqtSlot(bool) def on_closePushButton_clicked(self): ''' Closes the dialog ''' self.done(0) def renewDb(self): ''' Renews the database ''' if self.localDb: del self.localDb self.localDb = None def clearAll(self): ''' Clears the database list ''' self.dbListWidget.clear() self.treeWidget.clear() self.renewDb() def checkSuperUser(self): ''' Checks if the user is a super user ''' try: if self.serverWidget.abstractDb.checkSuperUser(): self.populateListWithDatabasesFromServer() else: QMessageBox.warning( self, self.tr('Info!'), self. tr('Connection refused. Connect with a super user to inspect server.' )) except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) def createItem(self, parent, text, column): ''' Creates a tree widget item ''' item = QtGui.QTreeWidgetItem(parent) item.setFlags(QtCore.Qt.ItemIsEnabled) item.setText(column, text) return item @pyqtSlot(QListWidgetItem, QListWidgetItem) def on_dbListWidget_currentItemChanged(self, current, previous): ''' Updates the information related with the database (e.g. users and roles for instance) ''' self.treeWidget.clear() if not current: return self.localDb = self.dbFactory.createDbFactory('QPSQL') originalCon = self.serverWidget.abstractDb.makeOgrConn() self.localDb.connectDatabaseWithParameters( self.serverWidget.abstractDb.db.hostName(), self.serverWidget.abstractDb.db.port(), current.text().split(' ')[0], self.serverWidget.abstractDb.db.userName(), self.serverWidget.abstractDb.db.password()) candidateUserList = [] try: candidateUserList = self.localDb.getUsers() except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) for candidate in candidateUserList: installed, assigned = self.localDb.getUserRelatedRoles(candidate) if len(assigned) > 0: userItem = self.createItem(self.treeWidget.invisibleRootItem(), candidate, 0) for perm in assigned: self.createItem(userItem, perm, 1) def createMenuAssigned(self, position): ''' Creates a pop up menu ''' menu = QMenu() item = self.treeWidget.itemAt(position) if item: menu.addAction(self.tr('Show properties'), self.showAssignedProperties) menu.exec_(self.treeWidget.viewport().mapToGlobal(position)) def showAssignedProperties(self): ''' Shows information about the selected permissions model ''' permission = self.treeWidget.currentItem().text(1) dbname = self.dbListWidget.currentItem().text().split(' ')[0] permissionsDict = dict() try: permissionsDict = self.localDb.getRolePrivileges( permission, dbname) except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) dlg = PermissionProperties(permissionsDict) dlg.exec_() @pyqtSlot(bool) def on_dropDatabasePushButton_clicked(self): ''' Drops a database and updates QSettings ''' currentItem = self.dbListWidget.currentItem() if not currentItem: return if QtGui.QMessageBox.question( self, self.tr('Question'), self.tr('Do you really want to drop database: ') + currentItem.text().split(' ')[0], QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) == QtGui.QMessageBox.Cancel: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) localDbName = self.localDb.getDatabaseName() self.renewDb() try: self.serverWidget.abstractDb.dropDatabase(localDbName) QApplication.restoreOverrideCursor() QMessageBox.warning( self, self.tr('Success!'), self.tr('Database ') + localDbName + self.tr(' dropped successfully!')) self.clearQSettings(localDbName) except Exception as e: QApplication.restoreOverrideCursor() QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.clearAll() self.populateListWithDatabasesFromServer() @pyqtSlot(bool) def on_createViewsPushButton_clicked(self): ''' Creates view button ''' if not self.localDb: QMessageBox.critical(self, self.tr('Critical!'), self.tr('Select a database to create view')) return dlg = CreateView(self.localDb, self.dbListWidget.currentItem().text()) dlg.exec_() pass def clearQSettings(self, database): ''' Clear the database from QSettings ''' name = self.serverWidget.serversCombo.currentText() + '_' + database settings = QSettings() settings.beginGroup('PostgreSQL/connections/' + name) settings.remove('') settings.endGroup() @pyqtSlot(bool) def on_manageAuxStructPushButton_clicked(self): ''' Opens the dialog to manage database auxiliar structure ''' if not self.localDb: QMessageBox.critical( self, self.tr('Critical!'), self.tr('Select a database to manage auxiliar structure')) return dlg = ManageDBAuxiliarStructure(self.localDb) dlg.exec_() pass
class ConnectionWidget(QtGui.QWidget, FORM_CLASS): connectionChanged = pyqtSignal() problemOccurred = pyqtSignal(str) def __init__(self, parent = None): """Constructor.""" super(ConnectionWidget, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.setInitialState() def __del__(self): self.closeDatabase() def closeDatabase(self): if self.abstractDb: del self.abstractDb self.abstractDb = None def setInitialState(self): self.filename = '' self.dbLoaded = False self.epsg = 0 self.crs = None self.abstractDb = None self.isSpatialite = True self.tabWidget.setCurrentIndex(0) self.abstractDbFactory = DbFactory() self.utils = Utils() #populating the postgis combobox self.comboBoxPostgis.setCurrentIndex(0) self.populatePostGISConnectionsCombo() self.spatialiteFileEdit.setReadOnly(True) self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setReadOnly(True) @pyqtSlot(int) def on_comboBoxPostgis_currentIndexChanged(self): if self.comboBoxPostgis.currentIndex() > 0: self.postGISCrsEdit.setText('') self.postGISCrsEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setText('') self.edgvPostgisVersionEdit.setReadOnly(True) self.loadDatabase() self.connectionChanged.emit() @pyqtSlot(bool) def on_pushButtonOpenFile_clicked(self): self.loadDatabase() if self.isDBConnected(): self.connectionChanged.emit() @pyqtSlot(int) def on_tabWidget_currentChanged(self): self.filename = '' self.comboBoxPostgis.setCurrentIndex(0) self.dbLoaded = False self.epsg = 0 self.crs = None self.dbVersion = '' self.spatialiteFileEdit.setReadOnly(True) self.spatialiteFileEdit.setText(self.filename) self.postGISCrsEdit.setText('') self.postGISCrsEdit.setReadOnly(True) self.spatialiteCrsEdit.setText('') self.spatialiteCrsEdit.setReadOnly(True) self.edgvSpatialiteVersionEdit.setText('') self.edgvSpatialiteVersionEdit.setReadOnly(True) self.edgvPostgisVersionEdit.setText('') self.edgvPostgisVersionEdit.setReadOnly(True) #Setting the database type if self.tabWidget.currentIndex() == 0: self.isSpatialite = True else: self.isSpatialite = False def loadDatabase(self): self.closeDatabase() if self.isSpatialite: self.abstractDb = self.abstractDbFactory.createDbFactory('QSQLITE') self.abstractDb.connectDatabase() self.spatialiteFileEdit.setText(self.abstractDb.db.databaseName()) self.edgvSpatialiteVersionEdit.setText(self.abstractDb.getDatabaseVersion()) else: self.abstractDb = self.abstractDbFactory.createDbFactory('QPSQL') self.abstractDb.connectDatabase(self.comboBoxPostgis.currentText()) self.edgvPostgisVersionEdit.setText(self.abstractDb.getDatabaseVersion()) try: self.abstractDb.checkAndOpenDb() self.dbLoaded = True self.dbVersion = self.abstractDb.getDatabaseVersion() if self.dbVersion == '-1': self.problemOccurred.emit(self.tr('This is not a valid DsgTools database!')) else: self.setCRS() except Exception as e: QgsMessageLog.logMessage(e.args[0], "DSG Tools Plugin", QgsMessageLog.CRITICAL) def setCRS(self): try: self.epsg = self.abstractDb.findEPSG() if self.epsg == -1: self.problemOccurred.emit(self.tr('Coordinate Reference System not set or invalid!')) else: self.crs = QgsCoordinateReferenceSystem(self.epsg, QgsCoordinateReferenceSystem.EpsgCrsId) if self.isSpatialite: self.spatialiteCrsEdit.setText(self.crs.description()) self.spatialiteCrsEdit.setReadOnly(True) else: self.postGISCrsEdit.setText(self.crs.description()) self.postGISCrsEdit.setReadOnly(True) except: pass def populatePostGISConnectionsCombo(self): self.comboBoxPostgis.clear() self.comboBoxPostgis.addItem(self.tr('Select Database')) self.comboBoxPostgis.addItems(self.getPostGISConnections()) def isDBConnected(self): return self.dbLoaded def getDBVersion(self): return self.abstractDb.getDatabaseVersion() def getQmlPath(self): return self.abstractDb.getQmlDir() @pyqtSlot(bool) def on_addConnectionButton_clicked(self): newConnectionDialog = ServerDBExplorer(self) retvalue = newConnectionDialog.exec_() self.populatePostGISConnectionsCombo() return retvalue def getPostGISConnections(self): settings = QSettings() settings.beginGroup('PostgreSQL/connections') currentConnections = settings.childGroups() settings.endGroup() return currentConnections
class ConnectionComboBox(DsgCustomComboBox): connectionChanged = pyqtSignal() dbChanged = pyqtSignal(AbstractDb) problemOccurred = pyqtSignal(str) def __init__(self, parent=None): super(ConnectionComboBox, self).__init__(parent) self.parent = parent self.abstractDb = None self.abstractDbFactory = DbFactory() self.serverAbstractDb = None self.displayDict = {'2.1.3':'EDGV 2.1.3', 'FTer_2a_Ed':'EDGV FTer 2a Ed', 'Non_EDGV':self.tr('Other database model')} self.lineEdit().setPlaceholderText(self.tr('Select a database')) self.currentIndexChanged.connect(self.loadDatabase) self.instantiateAbstractDb = False def closeDatabase(self): try: self.abstractDb.db.close() del self.abstractDb self.abstractDb = None except: self.abstractDb = None def clear(self): super(ConnectionComboBox, self).clear() self.closeDatabase() def setServerDb(self, serverAbstractDb): self.serverAbstractDb = serverAbstractDb QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) try: if self.serverAbstractDb: dbList = self.serverAbstractDb.getEDGVDbsFromServer(parentWidget = self.parent) dbList.sort() self.clear() self.addItem(self.tr('Select Database')) self.addItems(dbList) else: self.clear() self.abstractDb = None return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) QApplication.restoreOverrideCursor() def addItems(self, items): itemList = [] if items == []: return elif isinstance(items[0], tuple) and len(items[0]) == 2: for item in items: if item[1] not in self.displayDict.keys(): version = item[1] else: version = self.displayDict[item[1]] newText = item[0] + ' ({0})'.format(version) itemList.append(newText) if itemList == []: itemList = items super(ConnectionComboBox, self).addItems(itemList) def currentDb(self): if self.currentIndex() == 0: return None else: return self.currentText().split(' (')[0] def loadDatabase(self): """ Loads the selected database """ try: if self.serverAbstractDb and self.currentIndex() > 0: if not self.instantiateAbstractDb: self.abstractDb = self.abstractDbFactory.createDbFactory('QPSQL') (host, port, user, password) = self.serverAbstractDb.getDatabaseParameters() dbName = self.currentText().split(' (')[0] self.abstractDb.connectDatabaseWithParameters(host, port, dbName, user, password) self.abstractDb.checkAndOpenDb() self.dbChanged.emit(self.abstractDb) except Exception as e: self.closeDatabase() self.problemOccurred.emit(self.tr('A problem occurred! Check log for details.')) QgsMessageLog.logMessage(':'.join(e.args), "DSG Tools Plugin", QgsMessageLog.CRITICAL)
class CreateProfile(QtGui.QDialog, FORM_CLASS): profileCreated = pyqtSignal(str) def __init__(self, parent = None): """Constructor.""" super(CreateProfile, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.folder = os.path.join(os.path.dirname(__file__), 'profiles') self.abstractDb = None self.abstractDbFactory = DbFactory() self.populateTreeDict() def __del__(self): if self.abstractDb: del self.abstractDb self.abstractDb = None def getDbInfo(self): currentPath = os.path.dirname(__file__) if self.versionCombo.currentText() == '2.1.3': edgvPath = os.path.join(currentPath, '..', 'DbTools', 'SpatialiteTool', 'template', '213', 'seed_edgv213.sqlite') elif self.versionCombo.currentText() == 'FTer_2a_Ed': edgvPath = os.path.join(currentPath, '..', 'DbTools', 'SpatialiteTool', 'template', 'FTer_2a_Ed', 'seed_edgvfter_2a_ed.sqlite') self.abstractDb = self.abstractDbFactory.createDbFactory('QSQLITE') self.abstractDb.connectDatabase(edgvPath) try: self.abstractDb.checkAndOpenDb() except Exception as e: print e.args[0] def populateTreeDict(self): self.getDbInfo() tables = self.abstractDb.getTablesFromDatabase() self.profile = dict() categories = dict() for tableName in tables: #proceed only for edgv tables if tableName.split("_")[-1] == "p" or tableName.split("_")[-1] == "l" or tableName.split("_")[-1] == "a" or tableName.split("_")[0] == 'complexos': layerName = tableName.split('_')[0]+'.'+'_'.join(tableName.split('_')[1::]) split = tableName.split('_') if len(split) < 2: continue schema = split[0] category = split[1] if schema not in categories.keys(): categories[schema] = dict() if category not in categories[schema].keys(): categories[schema][category] = dict() if layerName not in categories[schema][category]: categories[schema][category][layerName] = dict() categories[schema][category][layerName]['read'] = '0' categories[schema][category][layerName]['write'] = '0' self.profile['database'+'_'+self.versionCombo.currentText()] = categories @pyqtSlot() def on_buttonBox_accepted(self): if not self.lineEdit.text(): QtGui.QMessageBox.warning(self, self.tr('Warning!'), self.tr('Fill the profile name!')) return else: profileName = self.lineEdit.text() path = os.path.join(self.folder, profileName+'.json') with open(path, 'w') as outfile: json.dump(self.profile, outfile, sort_keys=True, indent=4) self.profileCreated.emit(profileName) @pyqtSlot(int) def on_versionCombo_currentIndexChanged(self): self.populateTreeDict()
class BatchDbManager(QtGui.QDialog, FORM_CLASS): EDGV213, EDGV_FTer_2a_Ed, Non_EDGV = range(3) def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.utils = Utils() self.dbFactory = DbFactory() self.factory = SqlGeneratorFactory() self.showTabs(show = False) #setting the sql generator self.serverWidget.populateServersCombo() self.serverWidget.abstractDbLoaded.connect(self.checkSuperUser) self.serverWidget.abstractDbLoaded.connect(self.populateOtherInterfaces) self.dbsCustomSelector.setTitle(self.tr('Server Databases')) self.dbsCustomSelector.selectionChanged.connect(self.showTabs) self.dbsCustomSelector.selectionChanged.connect(self.populateStylesInterface) self.dbsCustomSelector.selectionChanged.connect(self.populateOtherInterfaces) self.previousTab = 0 self.dbDict = {'2.1.3':[], 'FTer_2a_Ed':[],'Non_EDGV':[], '3.0':[]} self.correspondenceDict = {self.tr('Load Database Model EDGV Version 2.1.3'):'2.1.3', self.tr('Load Database Model EDGV Version 3.0'):'3.0', self.tr('Load Database Model EDGV Version FTer_2a_Ed'):'FTer_2a_Ed',self.tr('Load Other Database Models'):'Non_EDGV'} @pyqtSlot(bool) def on_closePushButton_clicked(self): self.done(0) def showTabs(self, show = True): if show: self.tabWidget.show() else: self.tabWidget.hide() def populateListWithDatabasesFromServer(self): try: dbList = self.serverWidget.abstractDb.getEDGVDbsFromServer(parentWidget = self) except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) dbList.sort() for (dbname, dbversion) in dbList: if dbversion not in self.dbDict.keys(): dbversion = 'Non_EDGV' if dbname not in self.dbDict[dbversion]: self.dbDict[dbversion].append(dbname) def setDatabases(self): self.populateListWithDatabasesFromServer() @pyqtSlot(int) def on_edgvComboFilter_currentIndexChanged(self, idx): if idx != -1 and idx != 0: self.dbsCustomSelector.setInitialState(self.dbDict[self.correspondenceDict[self.edgvComboFilter.currentText()]]) def checkSuperUser(self): try: if self.serverWidget.abstractDb.checkSuperUser(): self.setDatabases() else: QMessageBox.warning(self, self.tr('Info!'), self.tr('Connection refused. Connect with a super user to inspect server.')) except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) def getSelectedDbList(self): return self.dbsCustomSelector.toLs def instantiateAbstractDbs(self, instantiateTemplates = False): dbsDict = dict() selectedDbNameList = self.getSelectedDbList() if instantiateTemplates: for templateName in ['template_edgv_213', 'template_edgv_fter_2a_ed', 'template_edgv_3']: if templateName not in selectedDbNameList: if templateName != 'dsgtools_admindb': selectedDbNameList.append(templateName) for dbName in selectedDbNameList: localDb = self.dbFactory.createDbFactory('QPSQL') localDb.connectDatabaseWithParameters(self.serverWidget.abstractDb.db.hostName(), self.serverWidget.abstractDb.db.port(), dbName, self.serverWidget.abstractDb.db.userName(), self.serverWidget.abstractDb.db.password()) dbsDict[dbName] = localDb return dbsDict def closeAbstractDbs(self, dbsDict): exceptionDict = dict() for dbName in dbsDict.keys(): try: dbsDict[dbName].db.close() except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return exceptionDict def outputMessage(self, header, successList, exceptionDict): msg = header if len(successList) > 0: msg += self.tr('\nSuccessful databases: ') msg +=', '.join(successList) msg += self.logInternalError(exceptionDict) QMessageBox.warning(self, self.tr('Operation Complete!'), msg) def logInternalError(self, exceptionDict): msg = '' errorDbList = exceptionDict.keys() if len(errorDbList)> 0: msg += self.tr('\nDatabases with error:') msg+= ', '.join(errorDbList) msg+= self.tr('\nError messages for each database were output in qgis log.') for errorDb in errorDbList: QgsMessageLog.logMessage(self.tr('Error for database ')+ errorDb + ': ' +exceptionDict[errorDb].decode('utf-8'), "DSG Tools Plugin", QgsMessageLog.CRITICAL) return msg @pyqtSlot(bool) def on_dropDatabasePushButton_clicked(self): selectedDbNameList = self.getSelectedDbList() if len(selectedDbNameList) == 0: QMessageBox.warning(self, self.tr('Warning'), self.tr('Please select one or more databases to drop!')) if QtGui.QMessageBox.question(self, self.tr('Question'), self.tr('Do you really want to drop databases: ')+', '.join(selectedDbNameList), QtGui.QMessageBox.Ok|QtGui.QMessageBox.Cancel) == QtGui.QMessageBox.Cancel: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchDropDbs(selectedDbNameList) QApplication.restoreOverrideCursor() self.setDatabases() header = self.tr('Drop operation complete. \n') self.outputMessage(header, successList, exceptionDict) self.dbsCustomSelector.setInitialState(self.dbsCustomSelector.fromLs) @pyqtSlot(bool) def on_upgradePostgisPushButton_clicked(self): selectedDbNameList = self.getSelectedDbList() QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchUpgradePostgis(selectedDbNameList) QApplication.restoreOverrideCursor() self.setDatabases() header = self.tr('Upgrade Posgtis operation complete. \n') self.outputMessage(header, successList, exceptionDict) def batchUpgradePostgis(self, dbList): exceptionDict = dict() successList = [] dbsDict = self.instantiateAbstractDbs(instantiateTemplates = True) self.closeAbstractDbs(dbsDict) for dbName in dbsDict.keys(): try: if self.serverWidget.abstractDb.checkIfTemplate(dbName): self.serverWidget.abstractDb.setDbAsTemplate(dbName = dbName, setTemplate = False) dbsDict[dbName].upgradePostgis() self.serverWidget.abstractDb.setDbAsTemplate(dbName = dbName, setTemplate = True) successList.append(dbName) else: dbsDict[dbName].upgradePostgis() successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def batchDropDbs(self, dbList): exceptionDict = dict() successList = [] dbsDict = self.instantiateAbstractDbs() self.closeAbstractDbs(dbsDict) for dbName in dbList: try: self.serverWidget.abstractDb.dropDatabase(dbName) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict @pyqtSlot(bool) def on_importStylesPushButton_clicked(self): dbsDict = self.instantiateAbstractDbs() exceptionDict = dict() versionList = [] for dbName in dbsDict.keys(): try: version = dbsDict[dbName].getDatabaseVersion() if version not in versionList: versionList.append(version) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) if len(exceptionDict.keys())>0: self.logInternalError(exceptionDict) if len(versionList) > 1: QMessageBox.warning(self, self.tr('Warning'), self.tr('Multiple edgv versions are not allowed!')) return styleDir = self.getStyleDir(versionList) styleList = self.getStyleList(styleDir) dlg = SelectStyles(styleList) dlg.exec_() selectedStyles = dlg.selectedStyles if not selectedStyles: return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchImportStyles(dbsDict, styleDir, selectedStyles, versionList[0]) QApplication.restoreOverrideCursor() header = self.tr('Import operation complete. \n') self.outputMessage(header, successList, exceptionDict) self.populateStylesInterface() closeExceptionDict = self.closeAbstractDbs(dbsDict) self.logInternalError(closeExceptionDict) def getStyleList(self, styleDir): #TODO: Reimplement styleList = [] version = None if os.path.basename(styleDir) in ['edgv_213','edgv_FTer_2a_Ed', 'edgv_3']: version = os.path.basename(styleDir) else: parentFolder = os.path.dirname(styleDir) version = os.path.basename(parentFolder) for style in os.walk(styleDir).next()[1]: styleList.append('/'.join([version,style])) if len(styleList) == 0: styleList = [version+'/'+os.path.basename(styleDir)] return styleList def batchImportStyles(self, dbsDict, styleDir, styleList, version): exceptionDict = dict() successList = [] for dbName in dbsDict.keys(): for style in styleList: currentStyleFilesDir = "{0}/{1}".format(styleDir, style.split("/")[1]) fileList = os.listdir(currentStyleFilesDir) # iterate over the list of files and check if there are non-QML files onlyQml = bool(sum([int(".qml" in file.lower()) for file in fileList])) try: if not onlyQml: raise Exception(self.tr("There are non-QML files in directory {0}.").format(currentStyleFilesDir)) dbsDict[dbName].importStylesIntoDb(style) successList.append(dbName) except Exception as e: errors = [] for arg in e.args: if isinstance(arg, basestring): s = '{}'.format(arg.encode('utf-8')) else: s = str(arg) errors.append(s) exceptionDict[dbName] = ':'.join(errors) return successList, exceptionDict def getStyleDir(self, versionList): currentPath = os.path.join(os.path.dirname(__file__),'..','Styles', self.serverWidget.abstractDb.versionFolderDict[versionList[0]]) return currentPath def getStylesFromDbs(self, perspective = 'style'): ''' Returns a dict of styles in a form acording to perspective: if perspective = 'style' : [styleName][dbName][tableName] = timestamp if perspective = 'database' : [dbName][styleName][tableName] = timestamp ''' dbsDict = self.instantiateAbstractDbs() allStylesDict = dict() exceptionDict = dict() for dbName in dbsDict.keys(): try: newDict =dbsDict[dbName].getAllStylesDict(perspective) allStylesDict = self.utils.mergeDict(newDict, allStylesDict) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) if len(exceptionDict.keys())>0: self.logInternalError(exceptionDict) return allStylesDict def createItem(self, parent, text, column): item = QtGui.QTreeWidgetItem(parent) item.setText(column, text) return item def populateStylesInterface(self): self.stylesTreeWidget.clear() allStylesDict = self.getStylesFromDbs() rootNode = self.stylesTreeWidget.invisibleRootItem() for styleName in allStylesDict.keys(): parentStyleItem = self.createItem(rootNode, styleName, 0) dbList = allStylesDict[styleName].keys() parentTimeList = [] for dbName in dbList: dbItem = self.createItem(parentStyleItem, dbName, 1) tableList = allStylesDict[styleName][dbName].keys() tableList.sort() timeList = [] for table in tableList: tableItem = self.createItem(dbItem, table, 2) timeStamp = allStylesDict[styleName][dbName][table].toString() timeList.append(timeStamp) tableItem.setText(3,allStylesDict[styleName][dbName][table].toString()) parentTimeList.append(max(timeList)) dbItem.setText(3,max(timeList)) @pyqtSlot(bool) def on_deleteStyles_clicked(self): dbsDict = self.instantiateAbstractDbs() styleDict = self.getStylesFromDbs() styleList = styleDict.keys() dlg = SelectStyles(styleList) dlg.exec_() selectedStyles = dlg.selectedStyles if not selectedStyles: return else: removeStyleDict = { style : styleDict[style] for style in selectedStyles } QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchDeleteStyles(dbsDict, removeStyleDict) QApplication.restoreOverrideCursor() header = self.tr('Delete operation complete. \n') self.outputMessage(header, successList, exceptionDict) self.populateStylesInterface() closeExceptionDict = self.closeAbstractDbs(dbsDict) self.logInternalError(closeExceptionDict) def batchDeleteStyles(self, dbsDict, styleDict): exceptionDict = dict() successList = [] for style in styleDict.keys(): for dbName in styleDict[style].keys(): try: dbsDict[dbName].deleteStyle(style) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def getSQLFile(self): fd = QFileDialog() filename = fd.getOpenFileName(caption=self.tr('Select a SQL file'),filter=self.tr('sql file (*.sql)')) return filename @pyqtSlot(bool) def on_customizeFromSQLFilePushButton_clicked(self): dbsDict = self.instantiateAbstractDbs() sqlFilePath = self.getSQLFile() if sqlFilePath == '': return QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) successList, exceptionDict = self.batchCustomizeFromSQLFile(dbsDict, sqlFilePath) QApplication.restoreOverrideCursor() header = self.tr('Customize from SQL file operation complete. \n') self.outputMessage(header, successList, exceptionDict) closeExceptionDict = self.closeAbstractDbs(dbsDict) self.logInternalError(closeExceptionDict) def batchCustomizeFromSQLFile(self, dbsDict, sqlFilePath): exceptionDict = dict() successList = [] for dbName in dbsDict.keys(): try: dbsDict[dbName].runSqlFromFile(sqlFilePath) successList.append(dbName) except Exception as e: exceptionDict[dbName] = ':'.join(e.args) return successList, exceptionDict def populateOtherInterfaces(self): dbsDict = self.instantiateAbstractDbs() if self.edgvComboFilter.currentIndex() != 0: edgvVersion = self.correspondenceDict[self.edgvComboFilter.currentText()] self.permissionWidget.setParameters(self.serverWidget.abstractDb, dbsDict, edgvVersion) # self.customizationManagerWidget.setParameters(self.serverWidget.abstractDb, edgvVersion, dbsDict = dbsDict) self.fieldToolBoxConfigManagerWidget.setParameters(self.serverWidget.abstractDb, edgvVersion, dbsDict = dbsDict) self.earthCoverageManagerWidget.setParameters(self.serverWidget.abstractDb, edgvVersion, dbsDict = dbsDict)
self.tr('Process parameters setter for process {0}').format( process)) if dlg.exec_() == 0: return -1 # get parameters params = dlg.values # adjusting the parameters in the process currProc.setParameters(params) #check status QgsMessageLog.logMessage('Process %s Log:\n' % currProc.getName(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) ret = currProc.execute() #run bitch run! #status = currProc.getStatus() #must set status QgsMessageLog.logMessage( 'Process ran with status %s\n' % currProc.getStatusMessage(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) currProc.logTotalTime() #checking for existing post process postProcessName = currProc.postProcess() if postProcessName: self.executeProcess(postProcessName) return ret if __name__ == '__main__': from DsgTools.Factories.DbFactory.dbFactory import DbFactory abstractDb = DbFactory().createDbFactory('QPSQL') manager = ValidationManager(abstractDb) print manager pass
class ExploreServerWidget(QtGui.QWidget, FORM_CLASS): abstractDbLoaded = pyqtSignal() serverAbstractDbLoaded = pyqtSignal(AbstractDb) clearWidgets = pyqtSignal() def __init__(self, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.superNeeded = False self.dbFactory = DbFactory() self.abstractDb = None def getServers(self): """ Gets server from QSettings """ settings = QSettings() settings.beginGroup('PostgreSQL/servers') currentConnections = settings.childGroups() settings.endGroup() return currentConnections def getServerConfiguration(self, name): """ Gets server configuration name: server name """ settings = QSettings() settings.beginGroup('PostgreSQL/servers/'+name) host = settings.value('host') port = settings.value('port') user = settings.value('username') password = settings.value('password') settings.endGroup() return (host, port, user, password) def browseServer(self, dbList, host, port, user, password): """ Browses server for EDGV databases dbList: databases list host: server host ip address port: server port user: user name password: password """ canLoad = True if self.superNeeded: canLoad = False try: if self.serverWidget.abstractDb.checkSuperUser(): canLoad = True else: QMessageBox.warning(self, self.tr('Info!'), self.tr('Connection refused. Connect with a super user to inspect server.')) return [] except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) if canLoad: progress = ProgressWidget(1,len(dbList),self.tr('Loading databases from server... '), parent = self) progress.initBar() gen = self.factory.createSqlGenerator(False) edvgDbList = [] for database in dbList: db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): qgis.utils.iface.messageBar().pushMessage('DB :'+database+'| msg: '+db.lastError().databaseText(), level=QgsMessageBar.CRITICAL) query = QSqlQuery(db) if query.exec_(gen.getEDGVVersion()): while query.next(): version = query.value(0) if version: edvgDbList.append((database, version)) progress.step() return edvgDbList def getDbsFromServer(self, name): """ Gets server databases name: server name """ gen = self.factory.createSqlGenerator(False) (host, port, user, password) = self.getServerConfiguration(name) database = 'postgres' db = self.getPostGISDatabaseWithParams(database, host, port, user, password) if not db.open(): QgsMessageLog.logMessage(db.lastError().text(), "DSG Tools Plugin", QgsMessageLog.CRITICAL) QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) query = QSqlQuery(gen.getDatabasesFromServer(), db) if not query.isActive(): QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr("Problem executing query: ")+query.lastError().text()) dbList = [] while query.next(): dbList.append(query.value(0)) return self.browseServer(dbList, host, port, user, password) @pyqtSlot(bool) def on_createNewServerPushButton_clicked(self): """ Opens the View Server dialog """ createNewServer = ViewServers(self) result = createNewServer.exec_() self.populateServersCombo() def populateServersCombo(self): """ Populates the server name combo box """ self.serversCombo.clear() self.serversCombo.addItem(self.tr('Select Server')) currentConnections = self.getServers() for connection in currentConnections: (host, port, user, password) = self.getServerConfiguration(connection) self.serversCombo.addItem('{3} ({0}@{1}:{2})'.format(user, host, port, connection)) @pyqtSlot(int) def on_serversCombo_currentIndexChanged(self): """ Updates the server databases """ self.clearWidgets.emit() if self.serversCombo.currentIndex() != 0: self.abstractDb = self.dbFactory.createDbFactory('QPSQL') if not self.abstractDb: QMessageBox.critical(self.iface.mainWindow(), self.tr('Critical'), self.tr('A problem occurred! Check log for details.')) return (host, port, user, password) = self.abstractDb.getServerConfiguration(self.serversCombo.currentText().split('(')[0][0:-1]) if host or port or user: self.abstractDb.connectDatabaseWithParameters(host, port, 'postgres', user, password) if self.superNeeded: try: if not self.abstractDb.checkSuperUser(): QMessageBox.warning(self, self.tr('Info!'), self.tr('Connection refused. Connect with a super user to inspect server.')) self.serversCombo.setCurrentIndex(0) return except Exception as e: QMessageBox.critical(self, self.tr('Critical!'), ':'.join(e.args)) self.abstractDbLoaded.emit() else: try: if self.abstractDb: self.abstractDb.__del__() self.abstractDb = None except: pass self.serverAbstractDbLoaded.emit(self.abstractDb) def getServerParameters(self): """ Gets postgis server parameters """ if self.serversCombo.currentIndex() != 0: return self.abstractDb.getServerConfiguration(self.serversCombo.currentText().split('(')[0][0:-1]) else: return (None, None, None, None) def clearAll(self): """ Resets the widget """ try: if self.abstractDb: self.abstractDb.__del__() self.abstractDb = None except: pass self.serversCombo.setCurrentIndex(0)
class ComplexWindow(QtGui.QDockWidget, FORM_CLASS): def __init__(self, iface, parent=None): """Constructor.""" super(ComplexWindow, self).__init__(parent) # Set up the user interface from Designer. # After setupUI you can access any designer object by doing # self.<objectname>, and you can use autoconnect slots - see # http://qt-project.org/doc/qt-4.8/designer-using-a-ui-file.html # #widgets-and-dialogs-with-auto-connect self.setupUi(self) self.iface = iface self.dbButton.clicked.connect(self.getDataSources) self.dbCombo.activated.connect(self.updateComplexClass) self.complexCombo.activated.connect(self.loadAssociatedFeatures) self.iface.newProjectCreated.connect(self.clearDock) self.abstractDb = None self.databases = None self.abstractDbFactory = DbFactory() def __del__(self): self.renewDb def renewDb(self): if self.abstractDb: del self.abstractDb self.abstractDb = None def clearDock(self): self.treeWidget.clear() self.dbCombo.clear() self.complexCombo.clear() #verificar se é necessario def isSpatialiteDatabase(self, dbName): (dataSourceUri, credentials) = self.databases[dbName] if dataSourceUri.host() == "": return True return False def getUserCredentials(self, lyr): dataSourceUri = QgsDataSourceURI(lyr.dataProvider().dataSourceUri()) if dataSourceUri.host() == '': return (None, None) if dataSourceUri.password() != '': return (dataSourceUri.username(), dataSourceUri.password()) connInfo = dataSourceUri.connectionInfo() (success, user, passwd ) = QgsCredentials.instance().get(connInfo, dataSourceUri.username(), None) # Put the credentials back (for yourself and the provider), as QGIS removes it when you "get" it if success: QgsCredentials.instance().put(connInfo, user, passwd) else: return (None, None) return (user, passwd) def updateComplexClass(self): self.renewDb() if self.dbCombo.currentIndex() == 0: return dbName = self.dbCombo.currentText() (dataSourceUri, credentials) = self.databases[dbName] #verifying the connection type if self.isSpatialiteDatabase(dbName): self.abstractDb = self.abstractDbFactory.createDbFactory('QSQLITE') self.abstractDb.connectDatabase(dataSourceUri.database()) else: self.abstractDb = self.abstractDbFactory.createDbFactory('QPSQL') database = dbName host = dataSourceUri.host() port = int(dataSourceUri.port()) user = credentials[0] password = credentials[1] self.abstractDb.connectDatabaseWithParameters(host, port, database, user, password) try: self.abstractDb.checkAndOpenDb() self.populateComboBox() except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr("Critical!"), e.args[0]) def populateComboBox(self): #getting all complex tables self.complexCombo.clear() self.complexCombo.addItem(self.tr("select a complex class")) complexClasses = self.abstractDb.listComplexClassesFromDatabase() self.complexCombo.addItems(complexClasses) def getDataSources(self): self.dbCombo.clear() self.dbCombo.addItem(self.tr("select a database")) if self.databases: self.databases.clear() #dictionary of names and datasourceUri self.databases = dict() self.layers = self.iface.mapCanvas().layers() for layer in self.layers: dataSourceUri = QgsDataSourceURI(layer.dataProvider().dataSourceUri()) dbName = dataSourceUri.database() if dbName not in self.databases.keys(): self.databases[dbName] = (dataSourceUri, self.getUserCredentials(layer)) #populating the combo self.dbCombo.addItem(dbName) @pyqtSlot(bool) def on_managePushButton_clicked(self): #opens a dialog to manage complexes dlg = ManageComplexDialog(self.iface, self.abstractDb, self.complexCombo.currentText()) #connects a signal to update the tree widget when done QObject.connect(dlg, SIGNAL(("tableUpdated()")), self.loadAssociatedFeatures) #connects a signal to disassociate features from complex before removal QObject.connect(dlg, SIGNAL(("markedToRemove( PyQt_PyObject )")), self.disassociateFeatures) result = dlg.exec_() if result: pass @pyqtSlot(bool) def on_associatePushButton_clicked(self): self.associateFeatures() @pyqtSlot(bool) def on_zoomButton_clicked(self): #case no item is selected we should warn the user if len(self.treeWidget.selectedItems()) == 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an item to zoom.")) return item = self.treeWidget.selectedItems()[0] #checking if the item is a complex (it should have depth = 2) if self.depth(item) == 2: bbox = QgsRectangle() for i in range(item.childCount()): aggregated_item = item.child(i) aggregated_class = aggregated_item.text(0) #getting the layer the needs to be updated aggregated_layer = None layers = self.iface.mapCanvas().layers() for layer in layers: if layer.name() == aggregated_class: aggregated_layer = layer break if not aggregated_layer: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The associated classes must be loaded in the table of contents.")) return for j in range(aggregated_item.childCount()): id = aggregated_item.child(j).text(0) freq = QgsFeatureRequest() freq.setFilterFid(int(id)) feature = layer.getFeatures( freq ).next() if j==0 and i == 0: bbox=feature.geometry().boundingBox() bbox.combineExtentWith(feature.geometry().boundingBox()) self.iface.mapCanvas().setExtent(bbox) self.iface.mapCanvas().refresh() else: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Select a complex.")) return def disassociateFeatures(self, toBeRemoved): for uuid in toBeRemoved: items = self.treeWidget.findItems(uuid, Qt.MatchRecursive, 1) if len(items) == 0: return complexItem = items[0] count = complexItem.childCount() for i in range(count): self.disassociateAggregatedClass(complexItem.child(i)) def disassociateAggregatedClass(self, item): aggregated_class = item.text(0) uuid = item.parent().text(1) complex = item.parent().parent().text(0) link_column = self.abstractDb.obtainLinkColumn(complex, aggregated_class) #getting the layer the needs to be updated aggregated_layer = None layers = self.iface.mapCanvas().layers() for layer in layers: #in case of spatialite databases when a complex class is added as a layer it's name has 'complexos_' if layer.name() == aggregated_class or layer.name() == 'complexos_'+aggregated_class: aggregated_layer = layer break if not aggregated_layer: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The class you're trying to disassociate must loaded in the table of contents.")) return for i in range(item.childCount()): #feature id that will be updated id = item.child(i).text(0) self.updateLayerOnDisassociate(layer, aggregated_class, link_column, id) def disassociateAggregatedId(self, item): aggregated_class = item.parent().text(0) uuid = item.parent().parent().text(1) complex = item.parent().parent().parent().text(0) link_column = self.abstractDb.obtainLinkColumn(complex, aggregated_class) #getting the layer the needs to be updated aggregated_layer = None layers = self.iface.mapCanvas().layers() for layer in layers: #in case of spatialite databases when a complex class is added as a layer it's name has 'complexos_' if layer.name() == aggregated_class or layer.name() == 'complexos_'+aggregated_class: aggregated_layer = layer break if not aggregated_layer: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("The class you're trying to disassociate must loaded in the table of contents.")) return #feature id that will be updated id = item.text(0) self.updateLayerOnDisassociate(layer, aggregated_class, link_column, id) def updateLayerOnDisassociate(self, layer, aggregated_class, link_column, id): if self.abstractDb.isComplexClass(aggregated_class): try: self.abstractDb.disassociateComplexFromComplex(aggregated_class, link_column, id) except Exception as e: QMessageBox.critical(self.iface.mainWindow(), self.tr("Critical!"), e.args[0]) else: #field index that will be set to NULL fieldIndex = [i for i in range(len(layer.dataProvider().fields())) if layer.dataProvider().fields()[i].name() == link_column] #attribute pair that will be changed attrs = {fieldIndex[0]:None} #actual update in the database layer.dataProvider().changeAttributeValues({int(id):attrs}) @pyqtSlot(bool) def on_disassociatePushButton_clicked(self): #case no item is selected we should warn the user if len(self.treeWidget.selectedItems()) == 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an aggregated class or aggregated id.")) return item = self.treeWidget.selectedItems()[0] #checking if the item is a complex (it should have depth = 2) if self.depth(item) == 3: self.disassociateAggregatedClass(item) elif self.depth(item) == 4: self.disassociateAggregatedId(item) else: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select an aggregated class or aggregated id.")) return self.loadAssociatedFeatures() def loadAssociatedFeatures(self): self.treeWidget.clear() if self.complexCombo.currentIndex() == 0: return complex = self.complexCombo.currentText() associatedDict = self.abstractDb.loadAssociatedFeatures(complex) for name in associatedDict.keys(): for complex_uuid in associatedDict[name].keys(): self.addAssociatedFeature(str(complex), str(name), complex_uuid, None, None) for aggregated_class in associatedDict[name][complex_uuid]: for ogc_fid in associatedDict[name][complex_uuid][aggregated_class]: self.addAssociatedFeature(str(complex), str(name), complex_uuid, str(aggregated_class), ogc_fid) def depth(self, item): #calculates the depth of the item depth = 0 while item is not None: item = item.parent() depth += 1 return depth def associateFeatures(self): #case no item is selected we should warn the user if len(self.treeWidget.selectedItems()) == 0: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select a complex.")) return item = self.treeWidget.selectedItems()[0] #checking if the item is a complex (it should have depth = 2) if self.depth(item) != 2: QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), self.tr("Please, select a complex.")) return complex = self.complexCombo.currentText() #uuid to be adjust on the selected features uuid = item.text(1) #getting the selected features forbiddenLayers = [] self.layers = self.iface.mapCanvas().layers() for layer in self.layers: #case no fetures selected we proceed to the next one selectedFeatures = layer.selectedFeatures() if len(selectedFeatures) == 0: continue #obtaining the link column column_name = self.abstractDb.obtainLinkColumn(complex, layer.name()) #storing the names of the incompatible layers if column_name == "": forbiddenLayers.append(layer.name()) continue for feature in selectedFeatures: fieldIndex = [i for i in range(len(layer.dataProvider().fields())) if layer.dataProvider().fields()[i].name() == column_name] #feature id that will be updated id = feature.id() #attribute pair that will be changed attrs = {fieldIndex[0]:uuid} #actual update in the database layer.dataProvider().changeAttributeValues({id:attrs}) #show the message of incompatible classes to associate if len(forbiddenLayers) > 0: message = "" message += self.tr("The following layers cannot be associated to complexes from ")+self.complexCombo.currentText()+":\n" for text in forbiddenLayers: message += text+"\n" QMessageBox.warning(self.iface.mainWindow(), self.tr("Warning!"), message) #updating the tree widget self.loadAssociatedFeatures() def createTreeItem(self, parent, text, uuid = ""): count = parent.childCount() children = [] #making a list of item names for i in range(count): child = parent.child(i) children.append(child.text(0)) #checking if the text is already in the tree widget if text not in children: #case not it should be created item = QTreeWidgetItem(parent) item.setExpanded(True) item.setText(0,text) #adding the complex uuid to the tree widget if uuid != "": item.setText(1, str(uuid)) else: #case already exists the correspondind item should be returned for i in range(count): child = parent.child(i) if child.text(0) == text: item = child return item def addAssociatedFeature(self, className, complexName, complexId, associatedClass, associatedId): #get the corresponding top level item classNameItem = self.createTreeItem(self.treeWidget.invisibleRootItem(), className) #get the corresponding complex item complexNameItem = self.createTreeItem(classNameItem, complexName, complexId) if associatedClass and associatedId: #get the corresponding class item associatedClassItem = self.createTreeItem(complexNameItem, associatedClass) #creates the corresponding associated item self.createTreeItem(associatedClassItem, str(associatedId)) def __test(self, x): if (x.parent() == None) : return True else: return False