class GenericDbManager(QObject): """ This class manages the permissions on dsgtools databases. """ def __init__(self, serverAbstractDb, dbDict, edgvVersion, parentWidget=None): super(GenericDbManager, self).__init__() self.parentWidget = parentWidget self.dbDict = dbDict self.serverAbstractDb = serverAbstractDb self.adminDb = self.instantiateAdminDb(serverAbstractDb) self.utils = Utils() self.extensionDict = { 'EarthCoverage': '.dsgearthcov', 'Customization': '.dsgcustom', 'Style': '.dsgstyle', 'ValidationConfig': '.dsgvalidcfg', 'FieldToolBoxConfig': '.reclas', 'Permission': '.dsgperm' } self.edgvVersion = edgvVersion def getManagerType(self): return str(self.__class__).split('.')[-1].replace('\'>', '').replace( 'Manager', '') 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 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 instantiateTemplateDb(self, edgvVersion): """ Instantiates a templateDb in the same server as serverAbstractDb. If template does not exists, instantiateAdminDb calls createTemplate """ templateName = self.serverAbstractDb.getTemplateName(edgvVersion) hasTemplate = self.serverAbstractDb.checkTemplate(edgvVersion) if not hasTemplate: self.serverAbstractDb.createTemplateDatabase(edgvVersion) templateDb = self.instantiateAbstractDb(templateName) templateDb.setStructureFromSql(edgvVersion, 4674) templateDb.setDbAsTemplate(version=edgvVersion) else: templateDb = self.instantiateAbstractDb(templateName) return templateDb def createAdminDb(self, serverAbstractDb, adminDb, host, port, user, password): """ Creates dsgtools_admindb """ serverAbstractDb.createAdminDb() adminDb.connectDatabaseWithParameters(host, port, 'dsgtools_admindb', user, password) sqlPath = adminDb.getCreationSqlPath('admin') adminDb.runSqlFromFile(sqlPath) return adminDb def getSettings(self): """ Gets all profiles from public.permission_profile """ settingType = self.getManagerType() return self.adminDb.getAllSettingsFromAdminDb(settingType) def getSetting(self, name, edgvVersion): """ Get setting from corresponding table on dsgtools_admindb """ settingType = self.getManagerType() settingDict = json.loads( self.adminDb.getSettingFromAdminDb(settingType, name, edgvVersion)) if not settingDict: raise Exception( self.tr("Setting ") + settingType + self.tr(" not found on dsgtools_admindb!")) return settingDict def createSetting(self, settingName, edgvVersion, jsonDict): """ Creates setting on dsgtools_admindb. """ settingType = self.getManagerType() if isinstance(jsonDict, dict): jsonDict = json.dumps(jsonDict, sort_keys=True, indent=4) self.adminDb.insertSettingIntoAdminDb(settingType, settingName, jsonDict, edgvVersion) def updateSetting(self, settingName, newJsonDict, edgvVersion=None): """ Generic update. Can be reimplenented in child methods. 1. Get property dict from adminDb """ if not edgvVersion: edgvVersion = self.edgvVersion errorDict = dict() successList = [] settingType = self.getManagerType() propertyDict = self.adminDb.getPropertyPerspectiveDict( settingType, DsgEnums.Property, versionFilter=edgvVersion) if settingName in propertyDict.keys(): rollbackList = [] self.adminDb.db.transaction() try: for dbName in propertyDict[settingName]: abstractDb = self.instantiateAbstractDb(dbName) abstractDb.db.transaction() rollbackList.append(abstractDb) self.updateMaterializationFromDatabase( abstractDb, propertyDict) abstractDb.updateRecordFromPropertyTable( settingType, settingName, edgvVersion, newJsonDict) self.adminDb.updateRecordFromPropertyTable( settingType, settingName, edgvVersion, newJsonDict) for abstractDb in rollbackList: abstractDb.db.commit() self.adminDb.db.commit() successList = [i for i in propertyDict[settingName]] except Exception as e: for abstractDb in rollbackList: abstractDb.db.rollback() self.adminDb.db.rollback() errorDict[dbName] = ':'.join(e.args) return (successList, errorDict) def importSetting(self, fullFilePath): """ Function to import profile into dsgtools_admindb. It has the following steps: 1. Reads inputJsonFilePath and parses it into a python dict; 2. Validates inputPermissionDict; 3. Tries to insert into database, if there is an error, abstractDb raises an error which is also raised by importProfile """ #getting profile name settingName = os.path.basename(fullFilePath).split('.')[0] #getting json inputJsonDict, inputJson = self.utils.readJsonFile( fullFilePath, returnFileAndDict=True) #error handling and json validation if inputJsonDict == dict(): raise Exception(self.tr("Not valid DsgTools property file!")) if not self.validateJsonSetting(inputJsonDict): raise Exception(self.tr("Not valid DsgTools property file!")) if 'version' in inputJsonDict.keys(): edgvVersion = inputJsonDict['version'] else: edgvVersion = inputJsonDict.keys()[0].split('_')[-1] try: self.createSetting(settingName, edgvVersion, inputJson) except Exception as e: raise Exception( self.tr("Error importing setting ") + settingName + ': ' + ':'.join(e.args)) def batchImportSettings(self, profilesDir): """ 1. Get all properties in profilesDir; 2. Import each using importSetting; """ importList = [] for profile in os.walk(profilesDir).next()[2]: if self.extensionDict[self.getManagerType()] in os.path.basename( profile): importList.append(os.path.join(profilesDir, profile)) for profileFile in importList: self.importSetting(profileFile) def exportSetting(self, profileName, edgvVersion, outputPath): """ 1. Get setting from dsgtools_admindb; 2. Export it to outputPath. """ jsonDict = self.getSetting(profileName, edgvVersion) outputFile = os.path.join( outputPath, profileName + self.extensionDict[self.getManagerType()]) with open(outputFile, 'w') as outfile: json.dump(jsonDict, outfile, sort_keys=True, indent=4) def batchExportSettings(self, outputDir): """ 1. Get all settings from corresponding table in dsgtools_admindb; 2. Export each using exportSetting. """ settingDict = self.getSettings() for edgvVersion in settingDict.keys(): outputPath = os.path.join(outputDir, edgvVersion) if not os.path.exists(outputPath): os.makedirs(outputPath) for profileName in settingDict[edgvVersion]: self.exportSetting(profileName, edgvVersion, outputPath) def getPropertyPerspectiveDict(self, viewType=DsgEnums.Property, versionFilter=None): """ Gets a dict in the format: if viewType == 'customization': {customizationName: ['-list of databases with customization']} if viewType == 'database': {databaseName: ['-list of customizations with customization']} """ settingType = self.getManagerType() return self.adminDb.getPropertyPerspectiveDict( settingType, viewType, versionFilter=versionFilter) def getSettingVersion(self, settingName): settingType = self.getManagerType() return self.adminDb.getSettingVersion(settingType, settingName) def validateJsonSetting(self, inputJsonDict): """ reimplemented in each child """ return True def getRecordFromAdminDb(self, propertyName, edgvVersion): settingType = self.getManagerType() return self.adminDb.getRecordFromAdminDb(settingType, propertyName, edgvVersion) def createAndInstall(self, configName, newJsonDict, edgvVersion, dbList=[]): self.createSetting(configName, edgvVersion, newJsonDict) return self.installSetting(configName, dbNameList=dbList) def installSetting(self, configName, dbNameList=[]): """ Generic install. Can be reimplenented in child methods. """ errorDict = dict() settingType = self.getManagerType() if dbNameList == []: dbNameList = self.dbDict.keys() successList = [] configEdgvVersion = self.getSettingVersion(configName) for dbName in dbNameList: abstractDb = self.instantiateAbstractDb(dbName) edgvVersion = abstractDb.getDatabaseVersion() if edgvVersion != configEdgvVersion: errorDict[dbName] = self.tr('Database version missmatch.') continue recDict = self.adminDb.getRecordFromAdminDb( settingType, configName, edgvVersion) try: if not abstractDb.checkIfExistsConfigTable(settingType): abstractDb.createPropertyTable(settingType, useTransaction=True) except Exception as e: errorDict[dbName] = ':'.join(e.args) continue try: abstractDb.db.transaction() self.adminDb.db.transaction() self.materializeIntoDatabase( abstractDb, recDict ) #step done when property management involves changing database structure abstractDb.insertRecordInsidePropertyTable( settingType, recDict, edgvVersion) dbOid = abstractDb.getDbOID() self.adminDb.insertInstalledRecordIntoAdminDb( settingType, recDict, dbOid) abstractDb.db.commit() self.adminDb.db.commit() except Exception as e: abstractDb.db.rollback() self.adminDb.db.rollback() errorDict[dbName] = ':'.join(e.args) successList.append(dbName) return (successList, errorDict) def deleteSetting(self, configName, dbNameList=[]): """ Generic remove. Can be reimplenented in child methods. 1. Get property dict from adminDb """ errorDict = dict() successList = [] settingType = self.getManagerType() propertyDict = self.adminDb.getPropertyPerspectiveDict( settingType, DsgEnums.Property) if configName in propertyDict.keys(): for dbName in propertyDict[configName]: abstractDb = self.instantiateAbstractDb(dbName) edgvVersion = abstractDb.getDatabaseVersion() try: abstractDb.db.transaction() self.adminDb.db.transaction() self.undoMaterializationFromDatabase( abstractDb, configName, settingType, edgvVersion ) #step done when property management involves changing database structure abstractDb.removeRecordFromPropertyTable( settingType, configName, edgvVersion) self.adminDb.removeRecordFromPropertyTable( settingType, configName, edgvVersion) abstractDb.db.commit() self.adminDb.db.commit() except Exception as e: abstractDb.db.rollback() self.adminDb.db.rollback() errorDict[dbName] = ':'.join(e.args) successList.append(dbName) return (successList, errorDict) def uninstallSetting(self, configName, dbNameList=[]): """ Generic uninstall. Can be reimplenented in child methods. This can uninstall setting on a list of databases or in all databases (if dbNameList == []) """ errorDict = dict() successList = [] settingType = self.getManagerType() propertyDict = self.adminDb.getPropertyPerspectiveDict( settingType, DsgEnums.Property) if configName in propertyDict.keys(): if dbNameList == []: #builds filter dbList to uninstall in all installed databases dbList = propertyDict[configName] else: #builds filter dbList to uninstall in databases in dbNameList dbList = [ i for i in propertyDict[configName] if i in dbNameList ] for dbName in dbList: abstractDb = self.instantiateAbstractDb(dbName) edgvVersion = abstractDb.getDatabaseVersion() try: abstractDb.db.transaction() self.adminDb.db.transaction() self.undoMaterializationFromDatabase( abstractDb, configName, settingType, edgvVersion ) #step done when property management involves changing database structure abstractDb.removeRecordFromPropertyTable( settingType, configName, edgvVersion) self.adminDb.uninstallPropertyOnAdminDb(settingType, configName, edgvVersion, dbName=dbName) abstractDb.db.commit() self.adminDb.db.commit() except Exception as e: abstractDb.db.rollback() self.adminDb.db.rollback() errorDict[dbName] = ':'.join(e.args) successList.append(dbName) return (successList, errorDict) def materializeIntoDatabase(self, abstractDb, propertyDict): """ Method that is reimplemented in each child when installing a property involves changing any sort of database structure """ pass def undoMaterializationFromDatabase(self, abstractDb, configName, settingType, edgvVersion): """ Method that is reimplemented in each child when uninstalling a property involves changing any sort of database structure """ pass def hasStructuralChanges(self, dbNameList): """ Method that is reimplemented in each child """ return []
class CreateDatabaseCustomization(QtGui.QDialog, FORM_CLASS): def __init__(self, customizationName, abstractDb, edgvVersion, customizationManager, customJsonDict = None, parent = None): """Constructor.""" super(self.__class__, self).__init__(parent) self.setupUi(self) self.customizationManager = customizationManager self.abstractDb = abstractDb self.edgvVersion = edgvVersion self.customizationName = customizationName self.contentsDict = dict() self.populateCustomizationCombo() self.setWidgetsEnabled(True) self.utils = Utils() if customJsonDict: self.createWidgetsFromCustomJsonDict(customJsonDict) def clearWidgets(self): rootItem = self.customizationTreeWidget.invisibleRootItem() childNodeCount = rootItem.childCount() #remove widgets for i in range(childNodeCount): typeChild = rootItem.child(i) childCount = typeChild.childCount() childTextList = [] for j in range(childCount): childTextList.append(typeChild.child(i).text(0)) for childText in childTextList: self.removeWidget(widgetText = childText) def setWidgetsEnabled(self, enabled): self.customizationSelectionComboBox.setEnabled(enabled) self.addAttributePushButton.setEnabled(enabled) self.customizationTreeWidget.setEnabled(enabled) self.removeSelectedPushButton.setEnabled(enabled) def populateCustomizationCombo(self): ''' Populates the customization combo and also defines customDict. ''' self.customDict = dict() self.customDict['attribute'] = self.tr('Attribute Customization') self.customDict['class'] = self.tr('Class Customization') self.customDict['codeName'] = self.tr('Code Name Customization') self.customDict['default'] = self.tr('Default Customization') self.customDict['domain'] = self.tr('Domain Customization') self.customDict['domainValue'] = self.tr('Domain Value Customization') self.customDict['nullity'] = self.tr('Attribute Nullity Customization') self.customDict['filter'] = self.tr('Attribute Filter Customization') rootNode = self.customizationTreeWidget.invisibleRootItem() for type in self.customDict.keys(): if self.customDict[type] not in self.contentsDict.keys(): self.contentsDict[self.customDict[type]] = dict() self.customizationSelectionComboBox.addItem(self.customDict[type]) self.contentsDict[self.customDict[type]]['widgetList'] = [] self.contentsDict[self.customDict[type]]['treeItem'] = self.createItem(rootNode, self.customDict[type], 0) self.customizationTreeWidget.expandAll() @pyqtSlot(bool) def on_addAttributePushButton_clicked(self): if self.customizationSelectionComboBox.currentText() == self.tr('Attribute Customization'): self.addAttributeWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Class Customization'): self.addClassWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Code Name Customization'): self.addCodeNameWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Default Customization'): self.addDefaultWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Domain Customization'): self.addDomainWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Domain Value Customization'): self.addDomainValueWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Attribute Nullity Customization'): self.addNullityWidget() elif self.customizationSelectionComboBox.currentText() == self.tr('Attribute Filter Customization'): self.addFilterWidget() else: QMessageBox.warning(self, self.tr('Warning'), self.tr('Select a custom operation!')) def addWidgetItem(self, contentsKey, widgetTitle, widget): widgetList = self.contentsDict[contentsKey]['widgetList'] if len(widgetList) > 0: i = int(widgetList[-1].layout().itemAt(0).widget().getTitle().split('#')[-1]) else: i = 0 title = widgetTitle+' #{0}'.format(i+1) #add number widget.setTitle(title) self.contentsDict[contentsKey]['widgetList'].append(self.addWidget(widget, title)) self.createItem(self.contentsDict[contentsKey]['treeItem'], title, 0) def addAttributeWidget(self,uiParameterJsonDict=None): widget = NewAttributeWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Attribute Customization'), self.tr('New Custom Attribute'), widget) def addClassWidget(self,uiParameterJsonDict=None): widget = NewClassWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Class Customization'), self.tr('New Custom Class'), widget) def addCodeNameWidget(self,uiParameterJsonDict=None): widget = CodeNameCustomizationWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Code Name Customization'), self.tr('New Custom Code Name'), widget) def addDefaultWidget(self,uiParameterJsonDict=None): widget = AlterDefaultWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Default Customization'), self.tr('New Custom Default'), widget) def addDomainWidget(self,uiParameterJsonDict=None): widget = NewDomainWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Domain Customization'), self.tr('New Custom Domain'), widget) def addDomainValueWidget(self,uiParameterJsonDict=None): widget = NewDomainValueWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Domain Value Customization'), self.tr('New Domain Value'), widget) def addNullityWidget(self,uiParameterJsonDict=None): widget = ChangeNullityWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Attribute Nullity Customization'), self.tr('New Custom Attribute Nullity'), widget) def addFilterWidget(self,uiParameterJsonDict=None): widget = ChangeFilterWidget(self.abstractDb,uiParameterJsonDict = uiParameterJsonDict) self.addWidgetItem(self.tr('Attribute Filter Customization'), self.tr('New Custom Attribute Filter'), widget) def addWidget(self, widget, title): layout = QtGui.QFormLayout() layout.addRow(widget) groupBox = QgsCollapsibleGroupBox(title) groupBox.setCollapsed(False) groupBox.setSaveCollapsedState(False) groupBox.setLayout(layout) self.scrollAreaLayout.addWidget(groupBox) return groupBox def createItem(self, parent, text, column): item = QtGui.QTreeWidgetItem(parent) item.setText(column, text) return item def getWidgetIndexFromTreeItem(self, treeItem): parent = treeItem.parent() widgetName = treeItem.text(0) if not parent: return if parent == self.customizationTreeWidget.invisibleRootItem(): return None childCount = parent.childCount() for i in range(childCount): child = parent.child(i) if child.text(0) == widgetName: return i @pyqtSlot(bool, name='on_removeSelectedPushButton_clicked') def removeWidget(self, widgetText = None): if not widgetText: treeItemList = [self.customizationTreeWidget.currentItem()] else: treeItemList = self.customizationTreeWidget.findItems(widgetText, flags = Qt.MatchExactly) if len(treeItemList)>0: for treeItem in treeItemList: parent = treeItem.parent() if parent == self.customizationTreeWidget.invisibleRootItem(): return idx = self.getWidgetIndexFromTreeItem(treeItem) itemToRemove = self.contentsDict[parent.text(0)]['widgetList'].pop(idx) itemToRemove.setParent(None) self.contentsDict[parent.text(0)]['treeItem'].removeChild(treeItem) @pyqtSlot() def on_buttonBox_accepted(self): QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)) exceptionList = [] customJsonDict = dict() for i in self.customDict.keys(): customJsonDict[i] = [] correspondenceDict = {self.customDict[i]:i for i in self.customDict.keys()} nCustom = 0 for key in self.contentsDict.keys(): for widgetItem in self.contentsDict[key]['widgetList']: nCustom += 1 progress = ProgressWidget(1,nCustom,self.tr('Preparing to export customizations... '), parent = self) progress.initBar() for key in self.contentsDict.keys(): jsonTagList = [] for widget in self.contentsDict[key]['widgetList']: currJsonItem = {'jsonUi':None, 'dbJsonTagList':[]} currentWidget = widget.layout().itemAt(0).widget() try: jsonTagList = currentWidget.getJSONTag() jsonUi = currentWidget.getUiParameterJsonDict() except Exception as e: exceptionList.append(':'.join(e.args)) if len(exceptionList) == 0: currJsonItem['jsonUi'] = jsonUi for jsonItem in jsonTagList: if jsonItem not in currJsonItem['dbJsonTagList']: currJsonItem['dbJsonTagList'].append(jsonItem) if currJsonItem not in customJsonDict[correspondenceDict[key]]: customJsonDict[correspondenceDict[key]].append(currJsonItem) progress.step() QApplication.restoreOverrideCursor() if self.validateJsonDict(customJsonDict) and len(exceptionList) == 0: versionText = 'database_'+self.edgvVersion finalJsonDict = {versionText:customJsonDict} self.customizationManager.createSetting(self.customizationName, self.edgvVersion, finalJsonDict) QMessageBox.information(self, self.tr('Success!'), self.tr('Database Customization ') + self.customizationName + self.tr(' created successfuly!')) #EMIT to reload? self.close() else: msg = '' if len(exceptionList)> 0: msg += self.tr('\Errors occured while trying to export customs built. Check qgis log for further details.') for error in exceptionList: QgsMessageLog.logMessage(self.tr('Customization error: ') + error, "DSG Tools Plugin", QgsMessageLog.CRITICAL) QMessageBox.warning(self, self.tr('Error!'), msg) def validateJsonDict(self, customJsonDict): """ Method to apply validation to customJsonDict """ #TODO return True def populateWidgetsFromSelectedFile(self): jsonFileName = self.selectFileWidget.fileNameList customJsonDict = self.utils.readJsonFile(jsonFileName) self.createWidgetsFromCustomJsonDict(customJsonDict) def createWidgetsFromCustomJsonDict(self, customJsonDict): for key in customJsonDict.keys(): for jsonTag in customJsonDict[key]: self.createWidgetFromKey(key, jsonTag['jsonUi']) def createWidgetFromKey(self, key, uiParameterJsonDict): if key == 'attribute': self.addAttributeWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'class': self.addClassWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'codeName': self.addCodeNameWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'default': self.addDefaultWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'domain': self.addDomainWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'domainValue': self.addDomainValueWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'nullity': self.addNullityWidget(uiParameterJsonDict=uiParameterJsonDict) elif key == 'filter': self.addFilterWidget(uiParameterJsonDict=uiParameterJsonDict) else: pass
class SetupEarthCoverage(QtGui.QWizard, FORM_CLASS): coverageChanged = pyqtSignal() def __init__(self, edgvVersion, areas, lines, oldCoverage, propertyList, enableSetupFromFile = True, onlySetup = False, propertyName = None, parent=None): """ Constructor """ super(self.__class__, self).__init__() self.setupUi(self) self.utils = Utils() self.areas = areas self.lines = lines self.propertyName = propertyName self.edgvVersion = edgvVersion self.areasCustomSelector.setTitle(self.tr('Areas')) self.linesCustomSelector.setTitle(self.tr('Lines')) self.propertyList = propertyList self.button(QtGui.QWizard.NextButton).clicked.connect(self.buildTree) self.button(QtGui.QWizard.FinishButton).clicked.connect(self.buildDict) self.setupWizard(oldCoverage, enableSetupFromFile) self.configDict = dict() def setupFromFile(self): """ Opens a earth coverage file """ if QMessageBox.question(self, self.tr('Question'), self.tr('Do you want to open an earth coverage file?'), QMessageBox.Ok|QMessageBox.Cancel) == QMessageBox.Cancel: return filename = QFileDialog.getOpenFileName(self, self.tr('Open Earth Coverage Setup configuration'), '', self.tr('Earth Coverage Files (*.json)')) return filename def setupWizard(self, oldCoverage, enableSetupFromFile): """ Prepares the wizard oldCoverage: old configuration """ if oldCoverage: # self.abstractDb.dropCentroids(oldCoverage.keys()) self.setupUiFromDict(oldCoverage) return else: self.populateFrameListWidget(self.areas) if enableSetupFromFile: filename = self.setupFromFile() else: filename = None if filename: self.setupUiFromFile(filename) else: self.areasCustomSelector.setFromList(self.areas) self.linesCustomSelector.setFromList(self.lines) if self.propertyName: self.nameLineEdit.setText(self.propertyName) self.nameLineEdit.setEnabled(False) def setupUiFromFile(self, filename): """ Populates ui from parameters of json """ #read json jsonDict = self.utils.readJsonFile(filename) self.setupUiFromDict(jsonDict) def setupUiFromDict(self, jsonDict): """ Populates ui from parameters of json """ #set nameLineEdit self.nameLineEdit.setText(jsonDict['configName']) #populate listWidget self.populateFrameListWidget(self.areas, frame = jsonDict['frameLayer']) linesFromList, linesToList, areasFromList, areasToList = self.populateLists(jsonDict['earthCoverageDict']) self.areasCustomSelector.setToList(areasToList) self.areasCustomSelector.setFromList(areasFromList) self.linesCustomSelector.setToList(linesToList) self.linesCustomSelector.setFromList(linesFromList) self.buildTree() self.checkDelimiters(jsonDict['earthCoverageDict']) def populateFrameListWidget(self, areas, frame = None): areas.sort() self.listWidget.clear() self.listWidget.addItems(areas) if frame: try: frameItem = self.listWidget.findItems(frame, Qt.MatchExactly)[0] self.listWidget.setCurrentItem(frameItem) except: pass def populateLists(self, setupDict): areasToList = setupDict.keys() linesToList = [] for key in areasToList: lines = setupDict[key] for line in lines: if line not in linesToList: linesToList.append(line) areasFromList = [area for area in self.areas if area not in areasToList] linesFromList = [line for line in self.lines if line not in linesToList] return linesFromList, linesToList, areasFromList, areasToList def checkDelimiters(self, setupDict): """ Check delimiters """ for i in range(self.treeWidget.invisibleRootItem().childCount()): areaItem = self.treeWidget.invisibleRootItem().child(i) for j in range(self.treeWidget.invisibleRootItem().child(i).childCount()): delimiterItem = areaItem.child(j) if areaItem.text(0) in setupDict.keys(): if delimiterItem.text(1) not in setupDict[areaItem.text(0)]: delimiterItem.setCheckState(1,Qt.Unchecked) def loadJson(self, filename): """ Loads a json file """ filename = QFileDialog.getOpenFileName(self, self.tr('Open Field Setup configuration'), self.folder, self.tr('Earth Coverage Setup File (*.dsgearthcov)')) if not filename: return return self.readJsonFile(filename) def populateClasses(self): """ Populates area classes """ self.treeWidget.clear() selectedAreaClasses = self.areasCustomSelector.toLs for i in range(len(selectedAreaClasses)): treeItem = QtGui.QTreeWidgetItem() treeItem.setText(0,selectedAreaClasses[i]) self.treeWidget.insertTopLevelItem(0,treeItem) def populateDelimiters(self): """ Populates line classes (area delimiters) """ delimiterList = [] for i in range(self.linesCustomSelector.toList.__len__()): delimiterList.append(self.linesCustomSelector.toList.item(i).text()) for i in range(self.treeWidget.invisibleRootItem().childCount()): for delimiter in delimiterList: treeItem = QtGui.QTreeWidgetItem(self.treeWidget.invisibleRootItem().child(i)) treeItem.setText(1,delimiter) treeItem.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) treeItem.setCheckState(1,Qt.Checked) self.treeWidget.invisibleRootItem().child(i).setExpanded(True) def getEarthCoverageDictFromTree(self): """ Gets earth coverage configuration from the tree widget """ invRootItem = self.treeWidget.invisibleRootItem() earthCoverageDict = dict() for i in range(invRootItem.childCount()): childClass = invRootItem.child(i) earthCoverageDict[childClass.text(0)] = [] for j in range(childClass.childCount()): if childClass.child(j).checkState(1) == Qt.Checked: earthCoverageDict[childClass.text(0)].append(childClass.child(j).text(1)) return earthCoverageDict def buildDict(self): ''' Gets earth coverage dict from interface ''' self.configDict['edgvVersion'] = self.edgvVersion self.configDict['configName'] = self.nameLineEdit.text() self.configDict['frameLayer'] = self.listWidget.currentItem().text() self.configDict['earthCoverageDict'] = self.getEarthCoverageDictFromTree() def buildTree(self): """ Builds the earth coverage tree using the selected areas and lines """ self.populateClasses() self.populateDelimiters() self.treeWidget.expandAll() self.treeWidget.header().setResizeMode(QtGui.QHeaderView.ResizeToContents) self.treeWidget.header().setStretchLastSection(False) def on_filterLineEdit_textChanged(self, text): """ Filters the items to make it easier to spot and select them """ classes = [edgvClass for edgvClass in self.areas if text in edgvClass] self.listWidget.clear() self.listWidget.addItems(classes) self.listWidget.sortItems() def validateEarthCoverageTreeWidget(self): rootNode = self.treeWidget.invisibleRootItem() childCount = rootNode.childCount() for i in range(childCount): areaItem = rootNode.child(i) lineChildCount = areaItem.childCount() hasSelected = False for j in range(lineChildCount): lineChild = areaItem.child(j) if lineChild.checkState(1) == Qt.Checked: hasSelected = True break if not hasSelected: return False return True def validateCurrentPage(self): if self.currentId() == 0: errorMsg = '' isValidated = True if self.nameLineEdit.text() == '': errorMsg += self.tr('An Earth Coverage name must be set.\n') isValidated = False if self.nameLineEdit.text() in self.propertyList: errorMsg += self.tr('An Earth Coverage with this name already exists.\n') isValidated = False if self.listWidget.currentRow() == -1: errorMsg += self.tr('A frame layer must be chosen.\n') isValidated = False if not isValidated: QMessageBox.warning(self, self.tr('Error!'), errorMsg) return isValidated elif self.currentId() == 1: if self.areasCustomSelector.toLs == []: errorMsg = self.tr('Areas must be chosen for Earth Coverage.\n') QMessageBox.warning(self, self.tr('Error!'), errorMsg) return False return True elif self.currentId() == 2: if self.linesCustomSelector.toLs == []: errorMsg = self.tr('Lines must be chosen for Earth Coverage.\n') QMessageBox.warning(self, self.tr('Error!'), errorMsg) return False return True elif self.currentId() == 3: #at least one line selected for each area if not self.validateEarthCoverageTreeWidget(): errorMsg = self.tr('At least one line must be chosen for each Earth Coverage area.\n') QMessageBox.warning(self, self.tr('Error!'), errorMsg) return False return True else: return True
class DsgToolsOpInstaller(QObject): def __init__(self, iface, parent=None, parentMenu=None): """ Constructor """ super(DsgToolsOpInstaller, self).__init__() self.iface = iface self.parentMenu = parentMenu self.utils = Utils() self.parent = parent self.icon_path = ':/plugins/DsgTools/icons/militarySimbology.png' def createAuxFolder(self): """ Creates a auxiliary foldes to unzip the installer zip file """ # current path point to DsgToolsOp folder currentPath = os.path.abspath(os.path.dirname(__file__)) # folder "auxiliar" inside DsgToolsOp folder auxFolder = os.path.join(currentPath, 'auxiliar') # creating and returning the folder os.makedirs(auxFolder) return auxFolder def deleteAuxFolder(self): """ Deletes the auxiliar folder """ # current path point to DsgToolsOp folder currentPath = os.path.abspath(os.path.dirname(__file__)) # working on MilitaryTools folder auxPath = os.path.join(currentPath, 'auxiliar') shutil.rmtree(auxPath, ignore_errors=True) def uninstallDsgToolsOp(self): """ Uninstall all folders and files created """ parentUi = self.iface.mainWindow() if QMessageBox.question( parentUi, self.tr('Question'), self. tr('DsgToolsOp is going to be uninstalled. Would you like to continue?' ), QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Cancel: return # current path point to DsgToolsOp folder currentPath = os.path.abspath(os.path.dirname(__file__)) # working on MilitaryTools folder toolsPath = os.path.join(currentPath, 'MilitaryTools') for root, dirs, files in os.walk(toolsPath): # deleting directories from MilitaryTools folder for dir_ in dirs: top = os.path.join(currentPath, 'MilitaryTools', dir_) shutil.rmtree(top, ignore_errors=True) # deleting files (keeping __init__.py) files MilitaryTools folder for file_ in files: if file_ != '__init__.py': os.remove(os.path.join(toolsPath, file_)) QMessageBox.information( parentUi, self.tr('Success!'), self.tr('DsgToolsOp uninstalled successfully!')) def installDsgToolsOp(self, fullZipPath, parentUi=None): """ Install files present into installer zip file :param fullZipPath: zip file path """ try: reinstalled = False # current path point to DsgToolsOp folder currentPath = os.path.abspath(os.path.dirname(__file__)) # creating auxiliar folder auxFolder = self.createAuxFolder() destFolder = os.path.join(currentPath, 'MilitaryTools') # unzipping files into Military tools self.unzipFiles(fullZipPath, auxFolder) # checking the zip file before installation if not self.checkZipFile(): self.deleteAuxFolder() return # check if installed if self.checkIfInstalled(): # if installed, get the version installedVersion = self.getInstalledVersion() # getting the version to be installed toBeInstalledVersion = self.getFilesVersion(auxFolder) # checks if the version to be installed is already installed if installedVersion == toBeInstalledVersion: QMessageBox.warning( parentUi, self.tr('Warning!'), self.tr('DsgToolsOp version already installed!')) self.deleteAuxFolder() return # Checks if the version to be installed is lower if installedVersion > toBeInstalledVersion: if QMessageBox.question( parentUi, self.tr('Question'), self. tr('Selected version is lower than installed one. Would you like to continue?' ), QMessageBox.Ok | QMessageBox.Cancel) == QMessageBox.Cancel: self.deleteAuxFolder() return # deleting previous version files self.uninstallDsgToolsOp() reinstalled = True # copying files to destination folder self.copyFiles(auxFolder, destFolder) QMessageBox.information( parentUi, self.tr('Success!'), self.tr('DsgToolsOp installed successfully!')) if reinstalled: QMessageBox.warning( parentUi, self.tr('Warning!'), self. tr('Please, reload QGIS to access the new installed version!' )) except Exception as e: try: self.deleteAuxFolder() except: pass QMessageBox.critical( self.parentMenu, self.tr('Critical!'), self.tr('Problem installing DsgToolsOp: ') + '|'.join(e.args)) def addUninstall(self, icon_path, parent, parentMenu): """ Creates the uninstall action menu """ action = parent.add_action(icon_path, text=parent.tr('DsgTools Op Uninstaller'), callback=parent.uninstallDsgToolsOp, parent=parentMenu, add_to_menu=False, add_to_toolbar=False) parentMenu.addAction(action) def unzipFiles(self, fullZipPath, auxFolder): """ Unzips files inside a zip into a folder :param fullZipPath: zip file path :param auxFolder: unzip folder """ zip = zipfile.ZipFile(fullZipPath) zip.extractall(auxFolder) currentPath = os.path.abspath(os.path.dirname(__file__)) init = open(os.path.join(currentPath, 'auxiliar', '__init__.py'), 'w') init.close() def copyFiles(self, auxFolder, destFolder): """ Copies all files to destination folder :param destFolder: destination folder :param auxFolder: source folder """ for src_dir, dirs, files in os.walk(auxFolder): if 'expression' == src_dir.split(os.path.sep)[-1]: for file_ in files: src_file = os.path.join(src_dir, file_) expression_dir = os.path.join( os.path.abspath(os.path.dirname(__file__)), '..', '..', '..', 'expressions') expression_file = os.path.join(expression_dir, file_) if os.path.exists(expression_file): os.remove(expression_file) shutil.move(src_file, expression_dir) else: dst_dir = src_dir.replace(auxFolder, destFolder, 1) if not os.path.exists(dst_dir): os.makedirs(dst_dir) for file_ in files: src_file = os.path.join(src_dir, file_) dst_file = os.path.join(dst_dir, file_) if os.path.exists(dst_file): os.remove(dst_file) shutil.move(src_file, dst_dir) # deleting auxiliar folder self.copyToExpressions(auxFolder, destFolder) self.deleteAuxFolder() self.loadTools() def copyToExpressions(self, auxFolder, destFolder): pass def checkIfInstalled(self): """ Checks if the files are already installed """ installPath = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'MilitaryTools') w = os.walk(installPath).next()[2] # checking the number of files in the folder if len(w) <= 2: return False else: return True def getInstalledVersion(self): """ Checks the current installed version """ versionPath = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'MilitaryTools', 'dsgtoolsop_version.json') jsonDict = self.utils.readJsonFile(versionPath) return jsonDict['version'] def getFilesVersion(self, filesFolder): """ Gets the version to be installed """ versionPath = os.path.join(filesFolder, 'dsgtoolsop_version.json') jsonDict = self.utils.readJsonFile(versionPath) return jsonDict['version'] def checkZipFile(self): """ Verifies the zip file prior to install """ try: from DsgTools.DsgToolsOp.auxiliar.toolLoader import ToolLoader return True except Exception as e: QMessageBox.critical( self.parentMenu, self.tr('Critical!'), self.tr('Invalid Zip file: ') + '|'.join(e.args)) return False def loadTools(self): """ Loads the tools present in the installer zip file """ try: self.toolList = [] from DsgTools.DsgToolsOp.MilitaryTools.toolLoader import ToolLoader self.toolLoader = ToolLoader(self.parentMenu, self.parent, self.icon_path) self.toolLoader.loadTools() self.addUninstall(self.icon_path, self.parent, self.parentMenu) except Exception as e: QMessageBox.critical( self.parentMenu, self.tr('Critical!'), self.tr('Problem installing DsgToolsOp: ') + '|'.join(e.args))