· 9 years ago · Mar 14, 2017, 09:48 AM
1# -*- coding: utf-8 -*-
2"""
3/***************************************************************************
4 RimoPrinting
5 A QGIS plugin
6 RimoPrinting
7 -------------------
8 begin : 2016-03-31
9 git sha : $Format:%H$
10 copyright : (C) 2016 by Bernd Loigge
11 email : bernd.loigge@spl-tele.com
12 ***************************************************************************/
13
14/***************************************************************************
15 * *
16 * This program is free software; you can redistribute it and/or modify *
17 * it under the terms of the GNU General Public License as published by *
18 * the Free Software Foundation; either version 2 of the License, or *
19 * (at your option) any later version. *
20 * *
21 ***************************************************************************/
22"""
23from qgis.core import *
24from PyQt4.QtCore import Qt, QSettings, QTranslator, qVersion, QCoreApplication, QFileInfo, QVariant, QFile, QSizeF, QPyNullVariant, QUrl
25from PyQt4.QtGui import QAction, QIcon, QFileDialog, QPrinter, QPainter, QFont, QProgressBar
26from PyQt4.QtXml import QDomDocument
27from PyQt4.QtNetwork import QNetworkRequest
28from qgis.gui import QgsMessageBar, QgsMapCanvas, QgsLayerTreeMapCanvasBridge
29# Initialize Qt resources from file resources.py
30import resources
31import re
32# Import the code for the dialog
33from RimoPrinting_dialog import RimoPrintingDialog
34import os.path
35import sys
36sys.path.append('./requests')
37import requests
38import json
39import yaml
40import processing
41import time
42import inspect
43import csv
44import math
45import urllib
46import datetime
47import codecs
48#csv.register_dialect('RimoPrinting', delimiter=';')
49project = QgsProject.instance()
50
51class RimoPrinting:
52 """QGIS Plugin Implementation."""
53
54 def __init__(self, iface):
55 """Constructor.
56
57 :param iface: An interface instance that will be passed to this class
58 which provides the hook by which you can manipulate the QGIS
59 application at run time.
60 :type iface: QgsInterface
61 """
62 # Save reference to the QGIS interface
63 self.iface = iface
64 # initialize plugin directory
65 self.plugin_dir = os.path.dirname(__file__).replace("\\", "/")
66 # initialize locale
67 locale = QSettings().value('locale/userLocale')[0:2]
68 locale_path = os.path.join(
69 self.plugin_dir,
70 'i18n',
71 'RimoPrinting_{}.qm'.format(locale))
72
73 if os.path.exists(locale_path):
74 self.translator = QTranslator()
75 self.translator.load(locale_path)
76
77 if qVersion() > '4.3.3':
78 QCoreApplication.installTranslator(self.translator)
79
80 # Create the dialog (after translation) and keep reference
81 self.dlg = RimoPrintingDialog()
82
83 # Plugin Variables
84 self.loginStatus = False
85
86 # Declare instance attributes
87 self.actions = []
88 self.menu = self.tr(u'&RimoPrinting')
89 # TODO: We are going to let the user set this up in a future iteration
90 self.toolbar = self.iface.addToolBar(u'RimoPrinting')
91 self.toolbar.setObjectName(u'RimoPrinting')
92
93 # noinspection PyMethodMayBeStatic
94 def tr(self, message):
95 """Get the translation for a string using Qt translation API.
96
97 We implement this ourselves since we do not inherit QObject.
98
99 :param message: String for translation.
100 :type message: str, QString
101
102 :returns: Translated version of message.
103 :rtype: QString
104 """
105 # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
106 return QCoreApplication.translate('RimoPrinting', message)
107
108
109 def add_action(
110 self,
111 icon_path,
112 text,
113 callback,
114 enabled_flag=True,
115 add_to_menu=True,
116 add_to_toolbar=True,
117 status_tip=None,
118 whats_this=None,
119 parent=None):
120 """Add a toolbar icon to the toolbar.
121
122 :param icon_path: Path to the icon for this action. Can be a resource
123 path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
124 :type icon_path: str
125
126 :param text: Text that should be shown in menu items for this action.
127 :type text: str
128
129 :param callback: Function to be called when the action is triggered.
130 :type callback: function
131
132 :param enabled_flag: A flag indicating if the action should be enabled
133 by default. Defaults to True.
134 :type enabled_flag: bool
135
136 :param add_to_menu: Flag indicating whether the action should also
137 be added to the menu. Defaults to True.
138 :type add_to_menu: bool
139
140 :param add_to_toolbar: Flag indicating whether the action should also
141 be added to the toolbar. Defaults to True.
142 :type add_to_toolbar: bool
143
144 :param status_tip: Optional text to show in a popup when mouse pointer
145 hovers over the action.
146 :type status_tip: str
147
148 :param parent: Parent widget for the new action. Defaults None.
149 :type parent: QWidget
150
151 :param whats_this: Optional text to show in the status bar when the
152 mouse pointer hovers over the action.
153
154 :returns: The action that was created. Note that the action is also
155 added to self.actions list.
156 :rtype: QAction
157 """
158
159 icon = QIcon(icon_path)
160 action = QAction(icon, text, parent)
161 action.triggered.connect(callback)
162 action.setEnabled(enabled_flag)
163
164 if status_tip is not None:
165 action.setStatusTip(status_tip)
166
167 if whats_this is not None:
168 action.setWhatsThis(whats_this)
169
170 if add_to_toolbar:
171 self.toolbar.addAction(action)
172
173 if add_to_menu:
174 self.iface.addPluginToVectorMenu(
175 self.menu,
176 action)
177
178 self.actions.append(action)
179
180 return action
181
182 def initGui(self):
183 global project
184 """Create the menu entries and toolbar icons inside the QGIS GUI."""
185
186 icon_path = self.plugin_dir + '/icon.png'
187 self.add_action(
188 icon_path,
189 text=self.tr(u'RimoPrinting'),
190 callback=self.run,
191 parent=self.iface.mainWindow())
192
193
194 #Disable Gui Elements for Login
195 if self.loginStatus == False:
196 self.disableLoginAndTenantGui(False)
197 self.dlg.pushButton_2.setEnabled(False)
198 self.dlg.pushButton_2.setEnabled(False)
199 self.dlg.comboBox_4.setEnabled(False)
200
201 # Set Global Variables (For tasks without Login)
202 self.setGlobalVariables()
203
204 # Set Plugin Variables
205 self.dlgIsActive = False
206 self.dataStore = {"regionData": None, "clusterData": None, "siteClusterData": None}
207 self.layerTree = QgsProject.instance().layerTreeRoot()
208
209 # Populate Style List Changer
210 self.updateStyleListComboBox()
211
212 # Login (Listener)
213 self.dlg.pushButton.clicked.connect(lambda: self.login(self.dlg.comboBox_8.currentText(), self.dlg.lineEdit.text(), self.dlg.lineEdit_2.text()))
214
215 # Select a Tenant (Listener)
216 self.dlg.pushButton_2.clicked.connect(lambda: self.selectTenant(self.tenants[self.dlg.comboBox_4.currentIndex()]["tenant"]["asOop"], self.tenants[self.dlg.comboBox_4.currentIndex()]["tenant"]["id"]))
217
218 # Create a Composer (Listener)
219 self.dlg.pushButton_3.clicked.connect(lambda: self.createPrintComposer())
220
221 # Refresh All Data layerTree (Listener)
222 self.dlg.pushButton_4.clicked.connect(lambda: self.refreshAllRimoDataConnections())
223
224 # Load Backbone Region Data
225 self.dlg.pushButton_5.clicked.connect(lambda: self.loadBackboneRegionData())
226
227 # Change Layer Styles
228 self.dlg.pushButton_6.clicked.connect(lambda: self.changeLayerStyles())
229
230 # Update Layer Style Folder
231 self.dlg.pushButton_7.clicked.connect(lambda: self.updateStyleListComboBox())
232
233 # Read and Set Plugin Version
234 self.pluginVersion = self.get_num(self.readFileAndFindString(self.plugin_dir + '/metadata.txt', 'version='))
235
236 def unload(self):
237 """Removes the plugin menu item and icon from QGIS GUI."""
238 for action in self.actions:
239 self.iface.removePluginMenu(
240 self.tr(u'&RimoPrinting'),
241 action)
242 self.iface.removeToolBarIcon(action)
243 # remove the toolbar
244 del self.toolbar
245
246#############
247# Run Method:
248#############
249
250 def run(self):
251 # Set Global Variables (For tasks without Login)
252 self.setGlobalVariables()
253
254 """Run method that performs all the real work"""
255 # show the dialog
256 #if self.dlgIsActive == True:
257 # self.dlg.show()
258 # return
259
260 self.dlg.show()
261 self.dlgIsActive = True
262
263 # Run the dialog event loop
264 result = self.dlg.exec_()
265
266 #Run if Cancel is pressed
267 if result == 0:
268 return
269
270 # See if OK was pressed
271 if result:
272 self.iface.messageBar().clearWidgets()
273 self.iface.messageBar().pushInfo("RimoPrinting:", "Preparing Data Structure...")
274 if self.checkIfEmptyProject() == True:
275 if self.createDataDir() == True:
276 if self.createRevisionCSV() == True:
277 self.iface.messageBar().clearWidgets()
278 self.iface.messageBar().pushInfo("RimoPrinting:", "Loading Rimo Data...")
279 if self.loadData() == True:
280 self.iface.messageBar().clearWidgets()
281 self.iface.messageBar().pushInfo("RimoPrinting:", "Loading Revision CSV...")
282 if self.loadRevisionCSV() == True:
283 if self.setCRSToEPSG31256() == True:
284 self.iface.messageBar().clearWidgets()
285 self.iface.messageBar().pushInfo("RimoPrinting:", "Data has been successfully loaded!")
286 self.saveCurrentProject()
287 return
288
289
290##############
291# Gui Methods:
292##############
293
294 # Login
295 def login(self, rimoUrl, user, password):
296 global project
297
298 # Rimo Url
299 if rimoUrl == 'Production':
300 self.rimoUrl = "https://rimo-saas.com/"
301 project.writeEntry("rP", "rimoUrl", "https://rimo-saas.com/")
302
303 else:
304 self.rimoUrl = "https://rimo-dev.rimo-saas.com/"
305 project.writeEntry("rP", "rimoUrl", "https://rimo-dev.rimo-saas.com/")
306
307# # Check for Proxy
308# s = QSettings()
309# proxyEnabled = s.value("proxy/proxyEnabled", "")
310# print(proxyEnabled)
311# if proxyEnabled == "true":
312# proxyType = str(s.value("proxy/proxyType", "" ))
313# proxyHost = str(s.value("proxy/proxyHost", "" ))
314# proxyPort = str(s.value("proxy/proxyPort", "" ))
315# proxyUser = str(s.value("proxy/proxyUser", "" ))
316# proxyPassword = str(s.value("proxy/proxyPassword", "" ))
317# proxyPrefix = str(proxyHost.split(':')[0])
318# proxyUrl = str(proxyHost.split(':')[1][2:])
319# userAndPass = ""
320# if proxyPassword:
321# userAndPass = proxyUser + ":" + proxyPassword + "@"
322#
323# proxyNewUrl = proxyPrefix + "://" + userAndPass + proxyUrl + ":" + proxyPort
324# self.proxieSettings = {proxyPrefix: proxyNewUrl}
325#
326#
327# else:
328# self.proxieSettings = {"http": self.rimoUrl}
329
330 # Login Request
331 r = requests.post(self.rimoUrl + "api/MIT/SDMeteorQGISController/", data=json.dumps({"method": "verifyUser", "user": user, "password": password}))
332
333 data = json.loads(r.text)
334 if "_error" in data:
335 self.renderWarning("Wrong Username or Password")
336 return False
337 if "asOop" in data:
338 # Tenant Stuff
339 tenants = data["userProfile"]
340 self.loginStatus = True
341 self.dlg.label_10.setText("Logged In.")
342 self.dlg.pushButton.setEnabled(False)
343 self.dlg.lineEdit.setEnabled(False)
344 self.dlg.lineEdit_2.setEnabled(False)
345 self.dlg.comboBox_8.setEnabled(False)
346 self.dlg.pushButton_2.setEnabled(True)
347 self.dlg.comboBox_4.setEnabled(True)
348 self.tenants = tenants
349 tenantList = []
350 for t in self.tenants:
351 tenantList.append(t["tenant"]["id"])
352 self.dlg.comboBox_4.addItems(tenantList)
353
354 # Select Tenant
355 def selectTenant(self, tenantOop, tenantId):
356 global project
357 self.dlg.pushButton_2.setEnabled(False)
358 self.dlg.comboBox_4.setEnabled(False)
359
360 #Global TenantOop
361 self.tenantOop = tenantOop
362 project.writeEntry("rP", "tenantOop", str(tenantOop))
363
364 #Global TenantID
365 self.tenantId = str(tenantId)
366 project.writeEntry("rP", "tenantId", str(tenantId))
367
368 #Global UserOop
369 self.userOop = [x for x in self.tenants if x["tenant"]["asOop"] == self.tenantOop][0]["asOop"]
370 project.writeEntry("rP", "userOop", str(self.userOop))
371
372 #Disable loginButton
373 self.dlg.pushButton.setEnabled(False)
374 self.disableLoginAndTenantGui(True)
375 #Populate ComboBoxen
376 #Regions ComboBox
377 self.regionData()
378 #Cluster ComboBox
379 self.clusterData()
380 #SiteCluster ComboBox
381 self.siteClusterData()
382 return True
383
384
385####################
386# Gui Helper Methods
387####################
388
389 # Disable Login And Tenant Gui Fields
390 def disableLoginAndTenantGui(self, status):
391 elements = [
392 self.dlg.comboBox,
393 self.dlg.comboBox_2,
394 self.dlg.comboBox_3,
395 self.dlg.button_box
396 ]
397
398 for e in elements:
399 e.setEnabled(status)
400
401 # Load Region Data
402 def regionData(self):
403 try:
404 self.getRimoData(self.rimoUrl + "api/MIT/SDMeteorQGISController", "getRegionsFromTenant", self.tenantOop, "nameToDisplay", self.dlg.comboBox, "regionData")
405 except:
406 pass
407 self.dlg.comboBox.activated.connect(lambda: self.comboBoxChange())
408
409 # Load Cluster Data
410 def clusterData(self):
411 try:
412 self.getRimoData(self.rimoUrl + "api/MIT/SDMeteorQGISController", "getClustersFromRegion", self.dataStore["regionData"][self.dlg.comboBox.currentIndex()]['asOop'], "nameToDisplay", self.dlg.comboBox_2, "clusterData")
413 except:
414 pass
415 self.dlg.comboBox_2.activated.connect(lambda: self.comboBox_2Change())
416
417 # Load Site Cluster Data
418 def siteClusterData(self):
419 try:
420 self.getRimoData(self.rimoUrl + "api/MIT/SDMeteorQGISController", "getSiteClustersFromClusters", self.dataStore["clusterData"][self.dlg.comboBox_2.currentIndex()]['asOop'], "nameToDisplay", self.dlg.comboBox_3, "siteClusterData")
421 except:
422
423 pass
424 self.dlg.comboBox_3.activated.connect(lambda: self.comboBox_3Change())
425
426 # Access Rimo Data (Used By SiteCluster, Cluster and Region Methods)
427 def getRimoData(self, url, method, Oop, comboParameter, comboBox, store):
428 #Clear ComboBox
429 comboBox.clear()
430
431 #Load and Parse Data
432 r = requests.post(url, data =json.dumps({'method': method, 'Oop': Oop, 'version': self.pluginVersion, 'userOop': self.userOop}))
433 data = json.loads(r.text)
434
435 #Create Content
436 myList = []
437 if store == "siteClusterData":
438 myList.append("Whole Cluster")
439 if len(data) > 0:
440 for e in data:
441 myList.append(e[comboParameter])
442
443 #setNewDataStorage
444 dataStorage = data
445 else:
446 self.dataStorage = []
447
448 #Return List
449 comboBox.addItems(myList)
450
451 #Data
452 self.dataStore[store] = data
453
454 # Events fired when comboBox Changes (RegionData)
455 def comboBoxChange(self):
456 self.dlg.comboBox_3.clear()
457 self.dlg.comboBox_3.activated.disconnect()
458 self.dlg.comboBox_2.clear()
459 self.dlg.comboBox_2.activated.disconnect()
460 #Reload Content
461 self.clusterData()
462 self.siteClusterData()
463
464 # Events fired when comboBox_2 Changes (ClusterData)
465 def comboBox_2Change(self):
466 self.dlg.comboBox_3.clear()
467 self.dlg.comboBox_3.activated.disconnect()
468 #Reload Content
469 self.siteClusterData()
470
471 # Events fired when comboBox_3 Changes (SiteClusterData)
472 def comboBox_3Change(self):
473 return
474
475
476######################
477# Data loading Methods
478######################
479
480 # Check Cluster Has Data
481 def checkIfClusterHasData(self, selection):
482 if selection == "" or selection == "No Data available":
483 return False
484 return True
485
486 # Check If Layer Group Exists
487 def checkIfLayerGroupExists(self, layerGroupName):
488 for child in self.layerTree.children():
489 if isinstance(child, QgsLayerTreeGroup):
490 if child.name() == layerGroupName:
491 return True
492 return False
493
494 # Check If Layer Exists
495 def checkIfLayerExists(self, layerMetaData):
496 layers = self.iface.legendInterface().layers()
497 for layer in layers:
498 if layer.keywordList() != "":
499 layerName = json.loads(layer.keywordList())["name"]
500 if layerName == layerMetaData["name"]:
501 return True
502 return False
503
504 # Get Rimo Layer Properties
505 def getRimoLayerProperties(self):
506 rimoLayerProps = [
507 {"path": "exportBuildingsToGeoJson", "name": "Buildings", "selected": True},
508 {"path": "exportFCPsToGeoJson", "name": "FCPs", "selected": True},
509 {"path": "exportAccessNodesToGeoJson", "name": "Access Nodes", "selected": True},
510 {"path": "exportRouteLocationsToGeoJson", "name": "Route Locations", "selected": True},
511 {"path": "exportDirectionLinesToGeoJson", "name": "Direction Lines", "selected": True},
512 {"path": "exportShaftLocationsToGeoJson", "name": "Shaft Locations", "selected": True},
513 {"path": "exportTrenchesToGeoJson", "name": "Trenches", "selected": True},
514 {"path": "exportPipesToGeoJson", "name": "Pipes", "selected": False},
515 {"path": "exportCladdingPipesToGeoJson", "name": "Cladding Pipes", "selected": False},
516 {"path": "exportInfoLocationsToGeoJson", "name": "Info Locations", "selected": True},
517 {"path": "exportFCPPolygonsToGeoJson", "name": "FCP Polygons", "selected": True},
518 {"path": "exportSiteClusterPolygonsToGeoJson", "name": "SiteCluster Polygons", "selected": True},
519 {"path": "exportClusterPolygonsToGeoJson", "name": "Cluster Polygons", "selected": False}
520 ]
521 return rimoLayerProps
522
523 # Get Backbone Layer Properties
524 def getBackboneRegionLayerProperties(self):
525 backboneRegionLayerProps = [
526 {"path": "exportClusterPolygonsToGeoJson", "name": "Backbone Cluster Polygons", "selected": False},
527 {"path": "exportSiteClusterToGeoJson", "name": "Backbone Site Cluster ", "selected": False},
528 {"path": "exportAccessNodesToGeoJson", "name": "Backbone POP", "selected": False},
529 {"path": "exportBackboneConnectionsToGeoJson", "name": "Backbone Connection", "selected": False},
530 {"path": "exportTrenchesToGeoJson", "name": "Backbone Trenches", "selected": False},
531 {"path": "exportCablesToGeoJson", "name": "Backbone Cables", "selected": False},
532 {"path": "exportPipesToGeoJson", "name": "Backbone Pipes", "selected": False}
533 ]
534 return backboneRegionLayerProps
535
536 # Get WMS Layer Properties
537 def getWmsLayerProperties(self):
538 wmsLayerProps = [
539 {"path": "contextualWMSLegend=0&crs=EPSG:3857&dpiMode=7&featureCount=10&format=image/png&layers=basemap_grau_layer&styles=&url=http://tileserver.rimo-saas.com:8081/service?", "name": "Geoland Basemap Grau", "selected": True},
540 {"path": "contextualWMSLegend=0&crs=EPSG:3857&dpiMode=7&featureCount=10&format=image/png&layers=basemap_layer&styles=&url=http://tileserver.rimo-saas.com:8081/service?", "name": "Geoland Basemap", "selected": False},
541 {"path": "contextualWMSLegend=0&crs=EPSG:4326&dpiMode=7&featureCount=10&format=image/png&layers=INSPIRE.KA_GRUNDSTUECK&styles=&url=http://tileserver.rimo-saas.com:8081/service?", "name": "DKM", "selected": True}
542 ]
543 return wmsLayerProps
544
545 # Add Layer To Iface
546 def addLayer(self, layerType, Oop, layerProps, currentGroup):
547 if layerType == "Rimo":
548 layer = QgsVectorLayer(self.rimoUrl + "geo/" + self.tenantId + "/" + str(Oop) + "/" + layerProps["path"], layerProps["name"], "ogr")
549 layer.setKeywordList('{"type": "RimoLayer", "name": "' + layerProps['name'] + '"}')
550 elif layerType == "Wms":
551 layer = QgsRasterLayer(layerProps["path"], layerProps["name"], "wms")
552 layer.setKeywordList('{"type": "WmsLayer", "name": "' + layerProps['name'] + '"}')
553
554 # Set Style from style Sheet
555 self.setStyle(layer, layerProps["name"])
556
557 # Add the layer to the registry, False indicates not to add to the layer tree
558 QgsMapLayerRegistry.instance().addMapLayer(layer, False)
559
560 # Append layer to the root group node
561 currentGroup.addLayer(layer)
562
563 # Set Layer Visible / not Visible
564 self.iface.legendInterface().setLayerVisible(layer, layerProps["selected"])
565
566 # Set Layer Styling
567 def setStyle(self, layer, qmlName):
568 layer.loadNamedStyle(self.plugin_dir + '/styles/default/' + qmlName + '.qml')
569
570
571 # Set Styling of Folder
572 def setStylingForLayerOfMatchingQMLFiles(self, fileName, path):
573 layer = self.getLayerByName(fileName)
574 if layer != False:
575 layer.loadNamedStyle(path)
576
577
578##################
579# Methods when Run
580##################
581
582 # Check If Project Is Empty
583 def checkIfEmptyProject(self):
584 if self.checkIfProjectHasDataLayer() == True or self.checkIfProjectHasPrintComposer() == True:
585 self.renderWarning("There is already Data or at least one print composer in this Project - Please use an empty QGis-Project for Data loading!")
586 return False
587 return True
588
589 # Create Data Dir
590 def createDataDir(self):
591 global project
592 if self.isDev():
593 folderP = "Development_" + self.tenantId + "_" + unicode(self.dlg.comboBox.currentText()) + "_" + unicode(self.dlg.comboBox_2.currentText()) + "_" + unicode(self.dlg.comboBox_3.currentText()) + "_" + str(time.time())[:-3]
594 else:
595 folderP = self.tenantId + "_" + unicode(self.dlg.comboBox.currentText()) + "_" + unicode(self.dlg.comboBox_2.currentText()) + "_" + unicode(self.dlg.comboBox_3.currentText()) + "_" + str(time.time())[:-3]
596
597 dataDirectory = self.plugin_dir + "/Data/" + folderP
598 self.dataDirectory = dataDirectory
599 project.writeEntry("rP", "dataDirectory", self.dataDirectory)
600 self.folderPathURLEncoded = urllib.quote(folderP.encode('utf8'))
601 project.writeEntry("rP", "folderPathURLEncoded", urllib.quote(folderP.encode('utf8')))
602
603 if not os.path.exists(self.dataDirectory):
604 os.makedirs(self.dataDirectory)
605 return True
606 return False
607
608 # Create A Revision CSV (Important for Composer)
609 def createRevisionCSV(self):
610 try:
611 csvFile = self.dataDirectory + "/revision.csv"
612 with open(csvFile, 'w') as csvfile:
613 fieldnames = ['Revision:', 'Bearbeiter:', 'Kommentar:']
614 writer = csv.writer(csvfile, delimiter=';', lineterminator='\n', quotechar='"', quoting=csv.QUOTE_MINIMAL)
615 writer.writerow(fieldnames)
616 row1 = ['1', '', '']
617 writer.writerow(row1)
618 return True
619 except:
620 return False
621
622 # Load WMS and Rimo Data
623 def loadData(self):
624 global project
625 selection = self.dlg.comboBox_3.currentText()
626 if self.checkIfClusterHasData(selection) == False:
627 self.renderWarning("No Data for this Cluster available")
628 return
629
630 # Get Oop for Rest Call / Set Grid Layer
631 if selection == "Whole Cluster":
632 Oop = self.dataStore["clusterData"][self.dlg.comboBox_2.currentIndex()]['asOop']
633
634 else:
635 Oop = self.dataStore["siteClusterData"][self.dlg.comboBox_3.currentIndex() - 1]['asOop']
636
637 # Set Global Variab+les
638 self.clusterOop = str(Oop)
639 project.writeEntry("rP", "clusterOop", str(Oop))
640 self.regionName = self.dlg.comboBox.currentText()
641 project.writeEntry("rP", "regionName", unicode(self.regionName))
642 self.clusterName = self.dlg.comboBox_2.currentText()
643 project.writeEntry("rP", "clusterName", unicode(self.clusterName))
644 self.siteClusterName = self.dlg.comboBox_3.currentText()
645 project.writeEntry("rP", "siteClusterName", unicode(self.siteClusterName))
646
647 # Load RimoLayer & Wms Layer Settings
648 rimoLayerProps = self.getRimoLayerProperties()
649 wmsLayerProps = self.getWmsLayerProperties()
650
651 # Create Layer Group For Rimo Layer in Iface
652 self.currentGroup = self.layerTree.addGroup(self.tenantId + ", " + unicode(self.dlg.comboBox.currentText()) + ", " + unicode(self.dlg.comboBox_2.currentText()) + ", " + unicode(self.dlg.comboBox_3.currentText()))
653
654 # Load RimoLayer
655 for l in rimoLayerProps:
656 try:
657 self.addLayer("Rimo", Oop, l, self.currentGroup)
658 except:
659 self.renderWarning("No Data for Layer: " + l["name"])
660
661 # Create LayerGroup for Overlaymaps / Basemaps if it does not exist
662 if self.checkIfLayerGroupExists("Overlaymaps / Basemaps") == False:
663 self.layerTree.addGroup(unicode("Overlaymaps / Basemaps"))
664
665 # Add Layer to Overlaymaps / Basemaps - LayerGroup
666 for l in wmsLayerProps:
667 if self.checkIfLayerExists(l) == False:
668 self.addLayer("Wms", None, l, self.layerTree.findGroup(unicode("Overlaymaps / Basemaps")))
669
670
671 # Set Grid Layer
672 if selection == "" or selection == "No Data available":
673 return
674 elif selection == "Whole Cluster":
675 for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
676 if lyr.name() == "Cluster Polygons":
677 layername = lyr.name()
678 else:
679 for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
680 if lyr.name() == "SiteCluster Polygons":
681 layername = lyr.name()
682
683 # Set Global Variable
684 self.gridLayerName = layername
685 project.writeEntry("rP", "gridLayerName", layername)
686
687 # Add GridGroup to Legend
688 self.gridGroup = self.currentGroup.addGroup("Grids")
689
690 # Add BackboneGroup to Legend
691 self.backboneRegionGroup = self.layerTree.addGroup("Backbone Data")
692
693 # Check if 'Backbone Region Data' is selected and load backbone data if so
694 if self.dlg.checkBox.checkState() != 0:
695 self.loadBackboneRegionData()
696
697
698 return True
699
700 # Load Revision CSV
701 def loadRevisionCSV(self):
702 csvUri = "file:///" + self.plugin_dir + "/Data/" + self.folderPathURLEncoded + "/revision.csv" + "?delimiter=;&encoding=WINSAMI2"
703 csvLayer = QgsVectorLayer(csvUri, "Revision", "delimitedtext")
704 csvLayer.setKeywordList('{"type": "RimoLayer", "name": "revision"}')
705 QgsMapLayerRegistry.instance().addMapLayer(csvLayer, False)
706 self.currentGroup.addLayer(csvLayer)
707 self.iface.legendInterface().setLayerVisible(csvLayer, True)
708 return True
709
710 # Set CRS
711 def setCRSToEPSG31256(self):
712 if self.iface.mapCanvas().mapRenderer().hasCrsTransformEnabled():
713 my_crs = QgsCoordinateReferenceSystem(31256, QgsCoordinateReferenceSystem.EpsgCrsId)
714 self.iface.mapCanvas().mapRenderer().setDestinationCrs(my_crs)
715 self.iface.mapCanvas().setMapUnits(0)
716 self.iface.mapCanvas().refresh()
717 return True
718
719 # Load BackboneRegion Data
720 def loadBackboneRegionData(self):
721 global project
722
723 # Load BackboneRegionLayer Settings
724 backboneLayerProps = self.getBackboneRegionLayerProperties()
725
726 # Get BackboneLayerGroup
727 self.backboneGroup = self.getBackboneGroup()
728 if self.backboneGroup == False:
729 self.backboneGroup = self.layerTree.addGroup("Backbone Data")
730
731 # Check if there is already Data in Group
732 if self.getAmountOfChildrenInGroup(self.backboneGroup) > 0:
733 self.renderWarning("Data has already been loaded in Backbone Data Group - Use Update Rimo Layer instead")
734 return False
735
736 # Get Backbone Region Oop
737 self.backboneRegionOop = self.getBackboneRegionOop(self.clusterOop)
738 print self.clusterOop
739 if self.backboneRegionOop == False:
740 self.renderWarning("There are problems loading Backbone Data - Please contact the admin!")
741 return False
742
743 # Load BackboneRegionLayer
744 for l in backboneLayerProps:
745 try:
746 self.addLayer("Rimo", self.backboneRegionOop, l, self.backboneGroup)
747 except:
748 self.renderWarning("No Data for Layer: " + l["name"])
749
750 return True
751
752 # Change Layer Styles
753 def changeLayerStyles(self):
754 styling = self.dlg.comboBox_9.currentText()
755 path = self.plugin_dir + "/styles/" + styling
756 for myFile in (os.listdir(path)):
757 self.setStylingForLayerOfMatchingQMLFiles(os.path.splitext(myFile)[0], path + "/" + myFile)
758 self.iface.mapCanvas().refresh()
759 self.iface.mapCanvas().refreshAllLayers()
760 return
761
762
763###############################
764# Print Composer Helper Methods
765###############################
766
767 # Get Grid Layer values
768 def getGridLayerValues(self, cFormat, cScale):
769 if cFormat == "A0" and cScale == "500":
770 M = [{"value": 350, "selected": False, "format": "A0", "scale": "500"}]
771
772 if cFormat == "A0" and cScale == "1000":
773 M = [{"value": 700, "selected": False, "format": "A0", "scale": "1000"}]
774
775 if cFormat == "A1" and cScale == "500":
776 M = [{"value": 250, "selected": False, "format": "A1", "scale": "500"}]
777
778 if cFormat == "A1" and cScale == "1000":
779 M = [{"value": 500, "selected": False, "format": "A1", "scale": "1000"}]
780
781 if cFormat == "A2" and cScale == "500":
782 M = [{"value": 180, "selected": False, "format": "A2", "scale": "500"}]
783
784 if cFormat == "A2" and cScale == "1000":
785 M = [{"value": 370, "selected": False, "format": "A2", "scale": "1000"}]
786
787 if cFormat == "A3" and cScale == "500":
788 M = [{"value": 130, "selected": False, "format": "A3", "scale": "500"}]
789
790 if cFormat == "A3" and cScale == "1000":
791 M = [{"value": 250, "selected": True, "format": "A3", "scale": "1000"}]
792
793 if cFormat == "A4" and cScale == "500":
794 M = [{"value": 100, "selected": False, "format": "A4", "scale": "500"}]
795
796 if cFormat == "A4" and cScale == "1000":
797 M = [{"value": 100, "selected": False, "format": "A4", "scale": "1000"}]
798
799 return M
800
801
802 # Creates Atlas Grids
803 def createAtlasGrid(self, inputLayer, currentGroup, M):
804 global project
805 # Calculate Layer in MGI
806 inputLayerMGI = processing.getObject(processing.runalg("qgis:reprojectlayer", inputLayer, "EPSG:31256", None)['OUTPUT'])
807
808 # Calculate Center Point
809 centroidLayer = processing.getObject(processing.runalg("qgis:polygoncentroids", inputLayerMGI, None)['OUTPUT_LAYER'])
810 for feat in centroidLayer.getFeatures():
811 x = feat.geometry().asPoint()
812
813 # Calculate Boundings
814 boundingPolygon = processing.getObject(processing.runalg("qgis:polygonfromlayerextent", inputLayerMGI, False, None)['OUTPUT'])
815 for feat in boundingPolygon.getFeatures():
816 XMIN = feat.attributes()[0]
817 YMIN = feat.attributes()[1]
818 XMAX = feat.attributes()[2]
819 YMAX = feat.attributes()[3]
820
821 for m in M:
822 # Recalculate XMAX - XMIN
823 if((XMAX - XMIN) < m["value"]):
824 add = (m["value"] - (XMAX - XMIN)) / 2
825 XMAX = XMAX + add
826 XMIN = XMIN - add
827
828 if((YMAX - YMIN) < m["value"]):
829 add = (m["value"] - (YMAX - YMIN)) / 2
830 YMAX = YMAX + add
831 YMIN = YMIN - add
832
833
834 # Calculate Distance & New Boundings
835 EW = XMAX - XMIN
836 NS = YMAX - YMIN
837 aEW = (EW % 10) / 2
838 aNS = (NS % 10) / 2
839
840 nXMIN = XMIN - aEW
841 nYMIN = YMIN - aNS
842 nXMAX = XMAX + aEW
843 nYMAX = YMAX + aNS
844
845 fieldAmountEW = int((nXMAX - nXMIN) / m["value"])
846 fieldAmountNS = int((nYMAX - nYMIN) / m["value"])
847
848 extent = str(nXMIN) + ", " + str(nXMAX) + ", " + str(nYMIN) + ", " + str(nYMAX)
849
850 # Create Grid
851 grid = processing.getObject(processing.runalg("qgis:creategrid", 1, extent, m["value"], m["value"], "EPSG:31256", None)['OUTPUT'])
852 gridWGS = processing.getObject(processing.runalg("qgis:reprojectlayer", grid, "EPSG:4326", None)['OUTPUT'])
853
854 # Check if Polygon is in Feature Grid + Add Attribute
855 finalGrid = processing.getObject(processing.runalg("qgis:joinattributesbylocation", gridWGS, self.getLayerByTagName("Trenches"),u'intersects',0,1,"mean",1,None)['OUTPUT'])
856 finalGrid = processing.getObject(processing.runalg("qgis:joinattributesbylocation", finalGrid, self.getLayerByTagName("Buildings"),u'intersects',0,1,"mean",1,None)['OUTPUT'])
857 gridName = str(m["format"]) + "_" + str(m["scale"]) + '_Grid_' + str(m["value"]) + 'm'
858
859 if self.getLayerByTagName(gridName) != False:
860 return gridName
861
862 finalGrid.setLayerName(gridName)
863
864 # Add Column for Intersection
865 finalGrid.dataProvider().addAttributes([QgsField("data_in_g", QVariant.Int)])
866 finalGrid.updateFields()
867
868 # Calculate Value
869 data_in_gIdx = finalGrid.fieldNameIndex('data_in_g')
870 countIdx = finalGrid.fieldNameIndex('count')
871 count_1Idx = finalGrid.fieldNameIndex('count_1')
872 attrFeatMap = {}
873 for feature in finalGrid.getFeatures():
874 #Fill data_in_g Column
875 if feature.attributes()[countIdx] or feature.attributes()[count_1Idx]:
876 attrFeatMap[ feature.id() ] = { data_in_gIdx : 1 }
877 else:
878 attrFeatMap[ feature.id() ] = { data_in_gIdx : 0 }
879
880 finalGrid.dataProvider().changeAttributeValues(attrFeatMap)
881
882 #Create FieldNames
883 #Create Numbers for Atlas
884 #Add ID Column
885 finalGrid.dataProvider().addAttributes([QgsField("ID", QVariant.Int)])
886 finalGrid.dataProvider().addAttributes([QgsField("Page", QVariant.String)])
887 finalGrid.updateFields()
888 idIDX = finalGrid.fieldNameIndex("ID")
889 pageIDX = finalGrid.fieldNameIndex("Page")
890
891
892 #Calculate IDs
893 count = 0
894 finalGrid.startEditing()
895 for feature in finalGrid.getFeatures():
896 finalGrid.changeAttributeValue(feature.id(), idIDX, count)
897 count = count + 1
898
899 #Sort IDs
900 featureList = []
901 for feature in finalGrid.getFeatures():
902 myValue = feature.attributes()
903 appendValue = [0 if isinstance(v, QPyNullVariant) else v for v in myValue]
904 featureList.append(appendValue)
905
906 featureList.sort(key=lambda x: x[1], reverse=True)
907
908 #Fill ID Column
909 count = 0
910 row = 0
911 column = 0
912 fieldAmountEW = fieldAmountEW + 1
913 for feature in featureList:
914 finalGrid.changeAttributeValue(feature[idIDX], idIDX, count)
915 if count > 1:
916 if count % fieldAmountEW == 0:
917 row = row + 1
918 column = 0
919
920 pageName = str(row) + '--' + str(column)
921 finalGrid.changeAttributeValue(feature[idIDX], pageIDX, pageName)
922 count = count + 1
923 column = column + 1
924
925
926
927 finalGrid.commitChanges()
928
929 # Create /Remove Shapefile
930 shpPath = self.dataDirectory + "/" + gridName
931
932 # Remove Shapefile if Exists
933 self.removeShapefileIfExists(gridName)
934
935 # Create Shapefile and add it to canvas
936 QgsVectorFileWriter.writeAsVectorFormat(finalGrid, shpPath, "utf-8", None, "ESRI Shapefile")
937
938 layer = QgsVectorLayer(shpPath + ".shp", gridName, "ogr")
939 layer.setKeywordList('{"type": "GridLayer", "name": "' + gridName + '"}')
940 QgsMapLayerRegistry.instance().addMapLayer(layer, False)
941
942 # Set Style
943 self.setStyle(layer, layer.name())
944
945 # Set Layer Visible / not Visible
946 self.iface.legendInterface().setLayerVisible(layer, m["selected"])
947
948 # Add Layer to Root Group
949 currentGroup.addLayer(layer)
950
951 return gridName
952
953 # Check if there has been Rimo Data added at least once
954 def checkIfThereIsRimoData(self):
955 if self.gridLayerName == "nothing":
956 return False
957 return True
958
959 # Get Filepath of Composer Template File
960 def getPrintComposerTemplateFile(self, filename):
961 myFile = os.path.dirname(os.path.dirname(os.path.dirname(self.plugin_dir))) + "/composer_templates/" + filename + ".qpt"
962 if self.checkIfPathExists(myFile):
963 return myFile
964 else:
965 return False
966
967 # Get Rimo Composer Data
968 def getRimoComposerData(self, tenantId, clusterOop):
969 global project
970 url = self.rimoUrl + "geo/" + self.tenantId + "/" + self.clusterOop + "/exportMetaInfo"
971 r = requests.get(url)
972 return json.loads(r.text)
973
974 # Create New Composer File
975 def createNewRimoComposer(self, cScale, cFormat, atlasGrid, createAtlas):
976 global project
977 # Create CRS Transformation for Grids
978 transform = self.crsTransformation(4326, 31256)
979 # Get Map Canvas
980 canvas = QgsMapCanvas()
981
982 if createAtlas == "Atlas":
983 # Set Composer Name
984 cN = "Atlas" + "_" + str(cFormat) + "_" + str(cScale)
985
986 if createAtlas == "Individual":
987 # Set Composer Name
988 cN = "Individual" + "_" + str(cFormat) + "_" + str(cScale)
989
990 if createAtlas == "Atlas_StaticLegend":
991 # Set Composer Name
992 cN = "Atlas_StaticLegend" + "_" + str(cFormat) + "_" + str(cScale)
993
994 # Load Composer File
995 myFile = self.getPrintComposerTemplateFile(cN)
996 if myFile == False:
997 self.renderWarning("No print composer template for the chosen scale / format found.")
998 return
999
1000
1001 myTemplateFile = file(myFile, 'rt')
1002 myTemplateContent = myTemplateFile.read()
1003 myTemplateFile.close()
1004
1005 # Create Document from File
1006 myDocument = QDomDocument()
1007 myDocument.setContent(myTemplateContent, False)
1008
1009 # Create Composer in Iface
1010 self.composer = self.iface.createNewComposer(cN)
1011 self.composer.composition().loadFromTemplate(myDocument)
1012 self.composition = QgsComposition(self.iface.mapCanvas().mapSettings())
1013 self.composition.refreshItems()
1014 self.myComposition = self.composer.composition()
1015
1016
1017 # Get Data From Template
1018 # Get Maps
1019 mainMap = self.myComposition.getComposerItemById('mainMap')
1020 mainMap.setMapCanvas(canvas)
1021 overviewMap = self.myComposition.getComposerItemById('overviewMap')
1022 overviewMap.setMapCanvas(canvas)
1023
1024 # Get Frames
1025 planartFrame = self.myComposition.getComposerItemById('planartFrame')
1026 regionFrame = self.myComposition.getComposerItemById('regionFrame')
1027 parentFrame = self.myComposition.getComposerItemById('parentFrame')
1028 bauabschnittFrame = self.myComposition.getComposerItemById('bauabschnittFrame')
1029 bereichsbezeichnungFrame = self.myComposition.getComposerItemById('bereichsbezeichnungFrame')
1030
1031 # Get Frame-Text
1032 planartFrameText = self.myComposition.getComposerItemById('planartFrameText')
1033 regionFrameText = self.myComposition.getComposerItemById('regionFrameText')
1034 parentFrameText = self.myComposition.getComposerItemById('parentFrameText')
1035 bauabschnittFrameText = self.myComposition.getComposerItemById('bauabschnittFrameText')
1036 bereichsbezeichnungFrameText = self.myComposition.getComposerItemById('bereichsbezeichnungFrameText')
1037 datumFrameText = self.myComposition.getComposerItemById('datumFrameText')
1038
1039 # Get Impressum
1040 impressum = self.myComposition.getComposerItemById('Anschrift')
1041
1042 # Get Tables
1043 revisionTable = self.myComposition.getComposerItemById('revisionTable').multiFrame()
1044
1045 # Get Logos
1046 companyLogo = self.myComposition.getComposerItemById('companyLogo')
1047
1048 # Get Legend
1049 legendFrame = self.myComposition.getComposerItemById('legendFrame')
1050 legend = self.myComposition.getComposerItemById('legend')
1051
1052 # Get NorthArrow
1053 northArrow = self.myComposition.getComposerItemById('NorthArrow')
1054
1055 # Set Data In Template
1056 # Set Table Content
1057 revisionLayer = self.getLayerByTagName("revision")
1058 revisionTable.setVectorLayer(revisionLayer)
1059
1060 # Set Logos
1061 companyLogo.setPictureFile(self.plugin_dir + '/Logos/CompanyLogo.png')
1062
1063 # Set Legend
1064 legend.setPictureFile(self.plugin_dir + '/Logos/Legende.jpg')
1065
1066 # Set Impressum
1067 impressumTextFile = open(self.plugin_dir + '/Sonstiges/Anschrift.txt', 'r')
1068 impressumText = impressumTextFile.read()
1069 impressumTextFile.close()
1070 impressum.setText(unicode(impressumText, "utf-8" ))
1071
1072 # Set Frames
1073 frameData = self.getRimoComposerData(self.tenantId, self.clusterOop)
1074 regionFrameText.setText(frameData["cluster"] )
1075 parentFrameText.setText(frameData["region"])
1076 bauabschnittFrameText.setText(frameData["siteCluster"])
1077
1078 # Set Main Map
1079 mainMap.setNewScale(int(cScale), True)
1080 mainMapLayerSet = [
1081 self.getLayerByTagName("Direction Lines").id(),
1082 self.getLayerByTagName("Buildings").id(),
1083 self.getLayerByTagName("FCPs").id(),
1084 self.getLayerByTagName("Access Nodes").id(),
1085 self.getLayerByTagName("Trenches").id(),
1086 self.getLayerByTagName("Route Locations").id(),
1087 self.getLayerByTagName("DKM").id(),
1088 self.getLayerByTagName("Geoland Basemap Grau").id(),
1089 atlasGrid.id()
1090 ]
1091 mainMap.setLayerSet(mainMapLayerSet)
1092 mainMap.setKeepLayerSet(True)
1093 mainMap.setUpdatesEnabled(True)
1094
1095 # Set NorthArrow
1096 northArrow.setPictureFile(self.plugin_dir + '/Logos/NorthArrow_04.svg')
1097
1098 # Set Overview Map
1099 overviewMap.zoomToExtent(transform.transformBoundingBox(atlasGrid.extent()))
1100 overviewMapLayerSet = [
1101 self.getLayerByTagName("Trenches").id(),
1102 atlasGrid.id()
1103 ]
1104 overviewMap.setLayerSet(overviewMapLayerSet)
1105 overviewMap.setKeepLayerSet(True)
1106 overviewMap.setUpdatesEnabled(False)
1107
1108
1109 if (createAtlas == "Atlas") or (createAtlas == "Atlas_StaticLegend"):
1110 # Create Atlas
1111 myAtlas = self.myComposition.atlasComposition()
1112 myAtlas.setEnabled(True)
1113
1114 # Set OverviewMap in Overview
1115 overviewMap.overview().setFrameMap(0)
1116
1117 # Atlas Settings
1118 myAtlas.setCoverageLayer(atlasGrid)
1119 myAtlas.beginRender()
1120 myAtlas.setFeatureFilter('"data_in_g" = 1')
1121 myAtlas.setFilterFeatures(True)
1122 myAtlas.setPageNameExpression('Page')
1123 myAtlas.setSortKeyAttributeName('ID')
1124 myAtlas.setSortFeatures(True)
1125 myAtlas.setEnabled(False)
1126 myAtlas.setEnabled(True)
1127 myAtlas.setFilenamePattern("'" + self.regionName + "_" + self.clusterName + "_" + self.siteClusterName + "_'||\"Page\"")
1128 mainMap.setAtlasDriven(True)
1129 self.myComposition.setAtlasMode(QgsComposition.PreviewAtlas)
1130 mainMap.setNewScale(int(cScale), True)
1131 self.myComposition.setAtlasMode(QgsComposition.ExportAtlas)
1132
1133 if createAtlas != "Atlas":
1134 # Set OverviewMap in Overview
1135 overviewMap.overview().setFrameMap(0)
1136 currentExtent = self.iface.mapCanvas().extent()
1137 mainMap.zoomToExtent(currentExtent)
1138 mainMap.setNewScale(int(cScale), True)
1139
1140 # Create Watermark if Development
1141 if self.isDev():
1142 watermark = QgsComposerLabel(self.myComposition)
1143 watermark.setText("Attention - Development")
1144 watermark.setItemPosition(20, 20)
1145 fontsize = self.myComposition.paperHeight() / 6
1146 watermark.setFont(QFont("Cambria", fontsize , QFont.Bold))
1147 watermark.adjustSizeToText()
1148 self.myComposition.addComposerLabel(watermark)
1149
1150 # Refresh Items
1151 self.myComposition.refreshItems()
1152
1153
1154
1155
1156########################
1157# Print Composer Methods
1158########################
1159
1160 # Create Composer
1161 def createPrintComposer(self):
1162 global project
1163
1164 if self.checkIfThereIsRimoData == False:
1165 self.renderWarning("Please load RiMo-Data at least once into this Project!")
1166 return
1167
1168 # Get Selections
1169 cType = self.dlg.comboBox_5.currentText()
1170 cFormat = self.dlg.comboBox_6.currentText()
1171 cScale = self.dlg.comboBox_7.currentText()
1172
1173
1174 # Access GridGroup
1175 if self.getGridGroup() == False:
1176 self.renderWarning("Grid Group is missing. Can't create Composer")
1177 return
1178
1179 # Create Grid Layer
1180 gridLayer = self.getLayerByTagName(self.gridLayerName)
1181 gridLayerGroup = self.getGridGroup()
1182 gridLayerValues = self.getGridLayerValues(cFormat, cScale)
1183 atlasGridName = self.createAtlasGrid(gridLayer, gridLayerGroup, gridLayerValues)
1184 atlasGrid = self.getLayerByTagName(atlasGridName)
1185
1186 if cType == "Individual Print":
1187 self.createNewRimoComposer(cScale, cFormat, atlasGrid, "Individual")
1188 self.saveCurrentProject()
1189 elif cType == "Atlas":
1190 self.createNewRimoComposer(cScale, cFormat, atlasGrid, "Atlas")
1191 self.saveCurrentProject()
1192 elif cType == "Atlas_StaticLegend":
1193 self.createNewRimoComposer(cScale, cFormat, atlasGrid, "Atlas_StaticLegend")
1194 self.saveCurrentProject()
1195 else:
1196 self.renderWarning("Not supported at the moment!")
1197
1198
1199
1200########################
1201# Overall Helper Methods
1202########################
1203
1204 # CRS Transformation
1205 def crsTransformation(self, inputCRS, outputCRS):
1206 source_crs = QgsCoordinateReferenceSystem(inputCRS)
1207 dest_crs = QgsCoordinateReferenceSystem(outputCRS)
1208 transform = QgsCoordinateTransform(source_crs, dest_crs)
1209 return transform
1210
1211 # Render Warning (message as input)
1212 def renderWarning(self, message):
1213 self.iface.messageBar().clearWidgets()
1214 self.iface.messageBar().pushMessage(message, "", level=QgsMessageBar.WARNING)
1215
1216
1217 # Check If Dev
1218 def isDev(self):
1219 if self.rimoUrl == "https://rimo-dev.rimo-saas.com/":
1220 return True
1221 else:
1222 return False
1223
1224 # Check if Project has Layer
1225 def checkIfProjectHasDataLayer(self):
1226 layers = self.iface.legendInterface().layers()
1227 count = 0
1228 for layer in layers:
1229 count = count + 1
1230 if count == 0:
1231 return False
1232 else:
1233 return True
1234
1235 # Check if Project has Print Composers
1236 def checkIfProjectHasPrintComposer(self):
1237 if len(self.iface.activeComposers()) == 0:
1238 return False
1239 else:
1240 return True
1241
1242 # Save Current Project
1243 def saveCurrentProject(self):
1244 global project
1245 p = project
1246 if self.isDev():
1247 filePath = self.dataDirectory + "/Development_" + unicode(self.tenantId) + "_" + unicode(self.regionName) + "_" + unicode(self.clusterName) + "_" + unicode(self.siteClusterName) + ".qgs"
1248 else:
1249 filePath = self.dataDirectory + "/" + unicode(self.tenantId) + "_" + unicode(self.regionName) + "_" + unicode(self.clusterName) + "_" + unicode(self.siteClusterName) + ".qgs"
1250
1251 p.setFileName(filePath)
1252 p.write()
1253
1254 # Check If Path / File Exists
1255 def checkIfPathExists(self, path):
1256 if os.path.exists(path):
1257 return True
1258 else:
1259 return False
1260
1261 # Access Layer by Tag Name
1262 def getLayerByTagName(self, myLayer):
1263 layers = self.iface.legendInterface().layers()
1264 for layer in layers:
1265 keys = layer.keywordList()
1266 if len(keys) > 0:
1267 layerName = json.loads(layer.keywordList())
1268 if layerName["name"] == myLayer:
1269 return layer
1270 #self.renderWarning("Error - Layer " + myLayer + " not found. Please contact support!")
1271 return False
1272
1273 # Removes a Shapefile if Exists (Including all other files)
1274 def removeShapefileIfExists(self, gridName):
1275 layers = self.iface.legendInterface().layers()
1276 for layer in layers:
1277 if layer.name() == gridName:
1278 layer = self.getLayerByTagName(gridName)
1279 shpPath = os.path.dirname(layer.source())
1280 shpId = layer.id()
1281 shpName = layer.name()
1282
1283 QgsMapLayerRegistry.instance().removeMapLayer(shpId)
1284
1285 for filename in os.listdir(shpPath):
1286 if filename.startswith(shpName):
1287 os.remove(shpPath + "/" + filename)
1288 return
1289
1290 # Access GridGroup
1291 def getGridGroup(self):
1292 global project
1293 root = project.instance().layerTreeRoot()
1294 for child in root.children():
1295 for innerChild in child.children():
1296 if isinstance(innerChild, QgsLayerTreeGroup) and innerChild.name() == "Grids":
1297 return innerChild
1298 return False
1299
1300 # Access BackboneGroup
1301 def getBackboneGroup(self):
1302 global project
1303 root = project.instance().layerTreeRoot()
1304 for child in root.children():
1305 if child.name() == "Backbone Data":
1306 return child
1307 return False
1308
1309 # Count Children in Group
1310 def getAmountOfChildrenInGroup(self, treeRoot):
1311 count = 0
1312 for child in treeRoot.children():
1313 count += 1
1314
1315 return count
1316
1317 # Set global Variables
1318 def setGlobalVariables(self):
1319 # Set Global Variables (For tasks without Login)
1320 if project.readEntry("rP", "tenantOop", "nothing")[0] != "nothing":
1321 self.rimoUrl = project.readEntry("rP", "rimoUrl", "nothing")[0]
1322 self.tenantOop = project.readEntry("rP", "tenantOop", "nothing")[0]
1323 self.tenantId = project.readEntry("rP", "tenantId", "nothing")[0]
1324 self.userOop = project.readEntry("rP", "userOop", "nothing")[0]
1325 self.dataDirectory = project.readEntry("rP", "dataDirectory", 'nothing')[0]
1326 self.folderPathURLEncoded = project.readEntry("rP", "folderPathURLEncoded", "nothing")[0]
1327 self.clusterOop = project.readEntry("rP", "clusterOop", "0")[0]
1328 self.regionName = project.readEntry("rP", "regionName", "nothing")[0]
1329 self.clusterName = project.readEntry("rP", "clusterName", "nothing")[0]
1330 self.siteClusterName = project.readEntry("rP", "siteClusterName", "nothing")[0]
1331 self.gridLayerName = project.readEntry("rP", "gridLayerName", "nothing")[0]
1332
1333 return True
1334
1335 # Refresh All Layer
1336 def refreshAllRimoDataConnections(self):
1337 layers = self.iface.legendInterface().layers()
1338 for layer in layers:
1339 keys = layer.keywordList()
1340 if len(keys) > 0:
1341 layerName = json.loads(layer.keywordList())
1342 if layerName["type"] == "RimoLayer":
1343 layer.dataProvider().forceReload()
1344 layer.triggerRepaint()
1345
1346 # Get BackboneRegionOop
1347 def getBackboneRegionOop(self, clusterOop):
1348 global project
1349 r = requests.post(self.rimoUrl + "api/MIT/SDMeteorQGISController", data=json.dumps({"method": "getBackboneRegion", "Oop": clusterOop}))
1350 data = json.loads(r.text)
1351 if "_error" in data:
1352 return False
1353 if "asOop" in data:
1354 return data["asOop"]
1355
1356
1357 # Update Style List ComboBox
1358 def updateStyleListComboBox(self):
1359 global project
1360 comboBox = self.dlg.comboBox_9
1361 #Clear ComboBox
1362 comboBox.clear()
1363 #Return List
1364 comboBox.addItems(os.listdir(self.plugin_dir + "/styles"))
1365
1366 # Get layer by Project Layer Name
1367 def getLayerByName(self, name):
1368 global project
1369 myLegendLayers = self.iface.legendInterface().layers()
1370 for myLayer in myLegendLayers:
1371 if name == myLayer.name():
1372 return myLayer
1373 return False
1374
1375
1376 # Read file and find String
1377 def readFileAndFindString(self, filePath, string):
1378 with open (filePath, 'rt') as in_file:
1379 for line in in_file:
1380 if string in line:
1381 return line
1382
1383
1384 # Get Number from String
1385 def get_num(self, x):
1386 return float(re.findall("\d+\.\d+", x)[0])
1387
1388 # Load Config Yaml
1389 def loadConfigYaml(self, path):
1390 with open(path, 'r') as stream:
1391 try:
1392 return yaml.load(stream)
1393 except yaml.YAMLError as exc:
1394 self.renderWarning("Config file corrupt")
1395 return False