class SessionFinishedDialog(QDialog): def __init__(self, session): super(SessionFinishedDialog, self).__init__(iface.mainWindow()) self.reopen = False self.session = session self.setWindowTitle("Session finished") self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(10) self.verticalLayout.setMargin(10) txt = "<p>Congratulations! You have correctly finished this session.</p>" if session.nextSessions: txt += "<p>We recommend you the following sessions to continue:</p><ul>" for i, nextSession in enumerate(session.nextSessions): txt += "<li><a href='%i'>%s</a>" % (i, nextSession[1]) txt += "</ul><p>If you don't want to run more sessions, just <a href='exit'>close this dialog.</a></p>" txt += "<p>If you want to run another session, click <a href='reopen'>here</a> to reopen the session selector</p>" self.text = QTextBrowser() self.text.anchorClicked.connect(self.linkClicked) self.text.setHtml(txt) self.text.setOpenLinks(False) self.verticalLayout.addWidget(self.text) self.setLayout(self.verticalLayout) self.resize(400, 300) self.nextSession = None def linkClicked(self, url): if url.path() not in ["exit", "reopen"]: self.nextSession = sessionFromName( *self.session.nextSessions[int(url.path())]) if url.path() == "reopen": self.reopen = True self.close()
def __init__(self, pt): super().__init__(iface.mainWindow()) self.pt = pt layout = QVBoxLayout() textbrowser = QTextBrowser() textbrowser.setOpenLinks(False) textbrowser.setOpenExternalLinks(False) textbrowser.anchorClicked.connect(self._link_clicked) url = ( "https://learn.planet.com/sample-skysat.html?utm_source=defense-and-intelligence&" "amp;utm_medium=website&amp;utm_campaign=skysat-sample-imagery&amp;" "utm_content=skysat-sample-imagery") text = f"""<p><strong>Complete your high resolution imagery order</strong></p> <p><br/>Your custom high resolution imagery order can be completed using Planet’s Tasking Dashboard. The dashboard allows you to place an order to task our SkySat satellite and get high-resolution imagery for your area and time of interest.</p> <p>If you have not yet purchased the ability to order high-resolution imagery, you may download samples<a href="{url}"> here</a> and contact our sales team <a href="https://www.planet.com/contact-sales/"> here</a>.</p> <p> </p> <p"><a href="dashboard">Take me to the Tasking Dashboard</a> </p>""" textbrowser.setHtml(text) layout.addWidget(textbrowser) self.setLayout(layout) self.setFixedSize(600, 400)
class LessonFinishedDialog(QDialog): def __init__(self, lesson): super(LessonFinishedDialog, self).__init__(iface.mainWindow()) self.reopen = False self.lesson = lesson self.setWindowTitle("Lesson finished") self.verticalLayout = QVBoxLayout() self.verticalLayout.setSpacing(10) self.verticalLayout.setMargin(10) txt = "<p>Congratulations! You have correctly finished this lesson.</p>" if lesson.nextLessons: txt += "<p>We recommend you the following lessons to continue:</p><ul>" for i, nextLesson in enumerate(lesson.nextLessons): txt+="<li><a href='%i'>%s</a>" % (i, nextLesson[1]) txt += "</ul><p>If you don't want to run more lessons, just <a href='exit'>close this dialog.</a></p>" txt += "<p>If you want to run another lesson, click <a href='reopen'>here</a> to reopen the lesson selector</p>" self.text = QTextBrowser() self.text.anchorClicked.connect(self.linkClicked) self.text.setHtml(txt) self.text.setOpenLinks(False) self.verticalLayout.addWidget(self.text) self.setLayout(self.verticalLayout) self.resize(400, 300) self.nextLesson = None def linkClicked(self, url): if url.path() not in ["exit", "reopen"]: self.nextLesson = lessonFromName(*self.lesson.nextLessons[int(url.path())]) if url.path() =="reopen": self.reopen = True self.close()
class RedistrictingDockWidget(QgsDockWidget): """ Dock widget for display of redistricting statistics and operations """ def __init__(self, _iface: QgisInterface = None): super().__init__() if _iface is not None: self.iface = _iface else: self.iface = iface dock_contents = QWidget() grid = QGridLayout(dock_contents) grid.setContentsMargins(0, 0, 0, 0) self._dock_toolbar = QToolBar(dock_contents) self._dock_toolbar.setFloatable(False) grid.addWidget(self._dock_toolbar, 0, 0, 1, 1) self._dock_toolbar.setIconSize(self.iface.iconSize(True)) self.frame = QTextBrowser() self.frame.setOpenLinks(False) self.frame.anchorClicked.connect(self.anchor_clicked) grid.addWidget(self.frame, 1, 0, 1, 1) self.setWidget(dock_contents) def dock_toolbar(self): """ Returns the dock toolbar """ return self._dock_toolbar def show_message(self, html): """ Shows a HTML formatted message in the dock, replacing its current contents :param html: HTML to show """ self.frame.setHtml(html) self.setUserVisible(True) def anchor_clicked(self, link: QUrl): """ Called on clicking an anchor link in the dock frame :param link: link clicked """ pass # pylint: disable=unnecessary-pass
class HistoryDiffViewerWidget(QWidget): def __init__(self, dialog, server, user, repo, graph, layer=None, initialSimplify=False): self.graph = graph self.dialog = dialog self.server = server self.user = user self.repo = repo self.layer = layer self.afterLayer = None self.beforeLayer = None self.extraLayers = [] # layers for the "Map" tab QWidget.__init__(self, iface.mainWindow()) self.setWindowFlags(Qt.Window) self.simplifyLog = initialSimplify self.initGui() self.tabWidget.setVisible(False) self.setLabelText("Select a commit to show its content") self.label.setVisible(False) if self.graph.commits: self.history.setCurrentItem(self.history.topLevelItem(0)) self.itemChanged(self.history.topLevelItem(0), None) self.history.currentItemChanged.connect(self.itemChanged) def setShowPopup(self, show): self.history.showPopup = show def initGui(self): layout = QVBoxLayout() splitter = QSplitter() splitter.setOrientation(Qt.Vertical) self.history = HistoryTree(self.dialog) self.history.updateContent(self.server, self.user, self.repo, self.graph, self.layer) self.historyWithFilter = HistoryTreeWrapper(self.history) if self.simplifyLog: self.historyWithFilter.simplify(True) splitter.addWidget(self.historyWithFilter) self.tabWidget = QTabWidget() self.tabCanvas = QWidget() tabLayout = QVBoxLayout() tabLayout.setMargin(0) self.canvas = QgsMapCanvas(self.tabCanvas) self.canvas.setCanvasColor(Qt.white) self.panTool = QgsMapToolPan(self.canvas) self.canvas.setMapTool(self.panTool) tabLayout.addWidget(self.canvas) self.labelNoChanges = QLabel("This commit doesn't change any geometry") self.labelNoChanges.setAlignment(Qt.AlignCenter) self.labelNoChanges.setVisible(False) tabLayout.addWidget(self.labelNoChanges) self.tabCanvas.setLayout(tabLayout) self.summaryTextBrowser = QTextBrowser() self.summaryTextBrowser.setOpenLinks(False) self.summaryTextBrowser.anchorClicked.connect(self.summaryTextBrowserAnchorClicked) self.tabWidget.addTab(self.summaryTextBrowser, "Commit Summary") self.tabWidget.addTab(self.tabCanvas, "Map") tabLayout = QVBoxLayout() tabLayout.setMargin(0) self.tabDiffViewer = QWidget() self.diffViewer = DiffViewerWidget({}) tabLayout.addWidget(self.diffViewer) self.tabDiffViewer.setLayout(tabLayout) self.tabWidget.addTab(self.tabDiffViewer, "Attributes") splitter.addWidget(self.tabWidget) self.label = QTextBrowser() self.label.setVisible(False) splitter.addWidget(self.label) self.tabWidget.setCurrentWidget(self.tabDiffViewer) layout.addWidget(splitter) self.setLayout(layout) exportDiffButton = QPushButton("Export this commit's DIFF for all layers") exportDiffButton.clicked.connect(self.exportDiffAllLayers) layout.addWidget(exportDiffButton) self.label.setMinimumHeight(self.tabWidget.height()) self.setWindowTitle("Repository history") def summaryTextBrowserAnchorClicked(self,url): url = url.url() #convert to string item = self.history.currentItem() if item is None: return commitid = item.commit.commitid cmd,layerName = url.split(".",1) if cmd == "addLive": execute(lambda: self.history.exportVersion(layerName,commitid,True)) elif cmd == "addGeoPKG": self.history.exportVersion(layerName,commitid,False) elif cmd == "exportDiff": execute(lambda: self.history.exportDiff(item, None,layer=layerName)) def exportDiffAllLayers(self): item = self.history.currentItem() if item is not None: self.history.exportDiff(item, None) def setLabelText(self,text): self.label.setHtml("<br><br><br><center><b>{}</b></center>".format(text)) def setContent(self, server, user, repo, graph, layer = None): self.server = server self.user = user self.repo = repo self.layer = layer self.graph = graph self.historyWithFilter.updateContent(server, user, repo, graph, layer) if self.history.graph.commits: self.history.setCurrentItem(self.history.topLevelItem(0)) def itemChanged(self, current, previous, THRESHOLD = 1500): item = self.history.currentItem() if item is not None: commit = self.graph.getById(item.ref) if commit is None: self.tabWidget.setVisible(False) self.setLabelText("Select a commit to show its content") self.label.setVisible(True) return commit2 = commit.commitid + "~1" if not item.commit.hasParents(): commit2 = "0000000000000000" total,details = self.server.diffSummary(self.user, self.repo, commit2,commit.commitid) tooLargeDiff = total > THRESHOLD if tooLargeDiff: html = "<br><br><center><b><font size=+3>Commit <font size=-0.1><tt>{}</tt></font> DIFF is too large to be shown</b></font><br>".format(commit.commitid[:8]) else: html = "<br><br><center><b><font size=+3>Commit <font size=-0.1><tt>{}</tt></font> Summary</b></font><br>".format(commit.commitid[:8]) html += "<table>" html += "<tr><Td style='padding:5px'><b>Layer Name</b></td><td style='padding:5px'><b>Additions</b></td><td style='padding:5px'><b>Deletions</b></td><td style='padding:5px'><b>Modifications</b></td><td></td><td></td><td></td></tr>" for detail in details.values(): html += "<tr><td style='padding:5px'>{}</td><td style='padding:5px'><center>{:,}</center></td><td style='padding:5px'><center>{:,}</center></td><td style='padding:5px'><center>{:,}</center></td><td style='padding:5px'>{}</td><td style='padding:5px'>{}</td><td style='padding:5px'>{}</td></tr>".format( detail["path"], int(detail["featuresAdded"]), int(detail["featuresRemoved"]),int(detail["featuresChanged"]), "<a href='addLive.{}'>Add Live</a>".format(detail["path"]), "<a href='addGeoPKG.{}'>Add GeoPKG</a>".format(detail["path"]), "<a href='exportDiff.{}'>Export Diff</a>".format(detail["path"]) ) html += "<tr></tr>" html += "<tr><td colspan=4>There is a total of {:,} features changed</td></tr>".format(total) html += "</table>" # html += "<br><br>There is a total of {:,} features changed".format(total) self.summaryTextBrowser.setHtml(html) self.label.setVisible(False) self.tabWidget.setVisible(True) self.tabWidget.setTabEnabled(1,not tooLargeDiff) self.tabWidget.setTabEnabled(2,not tooLargeDiff) if not tooLargeDiff: self.setDiffContent(commit, commit2) else: self.tabWidget.setVisible(False) self.setLabelText("Select a commit to show its content") self.label.setVisible(True) def setDiffContent(self, commit, commit2): if self.layer is None: layers = set(self.server.layers(self.user, self.repo, commit.commitid)) layers2 = set(self.server.layers(self.user, self.repo, commit2)) layers = layers.union(layers2) else: layers = [self.layer] diffs = {layer: execute(lambda: self.server.diff(self.user, self.repo, layer, commit.commitid, commit2)) for layer in layers} diffs = {key:value for (key,value) in diffs.items() if len(value) !=0} layers = [l for l in diffs.keys()] self.diffViewer.setChanges(diffs) self.canvas.setLayers([]) self.removeMapLayers() extent = QgsRectangle() for layer in layers: if not diffs[layer]: continue beforeLayer, afterLayer = execute(lambda: self._getLayers(diffs[layer])) if afterLayer is not None: resourcesPath = os.path.join(os.path.dirname(__file__), os.pardir, "resources") oldStylePath = os.path.join(resourcesPath, "{}_before.qml".format( QgsWkbTypes.geometryDisplayString(beforeLayer.geometryType()))) newStylePath = os.path.join(resourcesPath, "{}_after.qml".format( QgsWkbTypes.geometryDisplayString(afterLayer.geometryType()))) beforeLayer.loadNamedStyle(oldStylePath) afterLayer.loadNamedStyle(newStylePath) QgsProject.instance().addMapLayer(beforeLayer, False) QgsProject.instance().addMapLayer(afterLayer, False) extent.combineExtentWith(beforeLayer.extent()) extent.combineExtentWith(afterLayer.extent()) self.extraLayers.append(beforeLayer) self.extraLayers.append(afterLayer) # make extent a bit bit (10%) bigger # this gives some margin around the dataset (not cut-off at edges) if not extent.isEmpty(): widthDelta = extent.width() * 0.05 heightDelta = extent.height() * 0.05 extent = QgsRectangle(extent.xMinimum() - widthDelta, extent.yMinimum() - heightDelta, extent.xMaximum() + widthDelta, extent.yMaximum() + heightDelta) layers = self.extraLayers hasChanges = False for layer in layers: if layer is not None and layer.featureCount() > 0: hasChanges = True break self.canvas.setLayers(layers) self.canvas.setExtent(extent) self.canvas.refresh() self.canvas.setVisible(hasChanges) self.labelNoChanges.setVisible(not hasChanges) def _getLayers(self, changes): ADDED, MODIFIED, REMOVED, = 0, 1, 2 def _feature(g, changeType): feat = QgsFeature() if g is not None: feat.setGeometry(g) feat.setAttributes([changeType]) return feat if changes: f = changes[0] new = f["new"] old = f["old"] reference = new or old geomtype = QgsWkbTypes.displayString(reference.geometry().wkbType()) oldLayer = loadLayerNoCrsDialog(geomtype + "?crs=epsg:4326&field=geogig.changeType:integer", "old", "memory") newLayer = loadLayerNoCrsDialog(geomtype + "?crs=epsg:4326&field=geogig.changeType:integer", "new", "memory") oldFeatures = [] newFeatures = [] for f in changes: new = f["new"] old = f["old"] newGeom = new.geometry() if new is not None else None oldGeom = old.geometry() if old is not None else None if oldGeom is None: feature = _feature(newGeom, ADDED) newFeatures.append(feature) elif newGeom is None: feature = _feature(oldGeom, REMOVED) oldFeatures.append(feature) elif oldGeom.asWkt() != newGeom.asWkt(): feature = _feature(oldGeom, MODIFIED) oldFeatures.append(feature) feature = _feature(newGeom, MODIFIED) newFeatures.append(feature) else: feature = _feature(newGeom, MODIFIED) newFeatures.append(feature) oldLayer.dataProvider().addFeatures(oldFeatures) newLayer.dataProvider().addFeatures(newFeatures) else: oldLayer = None newLayer = None return oldLayer, newLayer def removeMapLayers(self): for layer in self.extraLayers: if layer is not None: QgsProject.instance().removeMapLayer(layer.id()) self.extraLayers = []
class SelectedPopulationDockWidget(QgsDockWidget): """ Dock widget for display of population of selected meshblocks """ def __init__(self, _iface: QgisInterface = None, meshblock_layer: QgsVectorLayer = None): super().__init__() self.setWindowTitle(self.tr('Selected Meshblock Population')) self.meshblock_layer = meshblock_layer if _iface is not None: self.iface = _iface else: self.iface = iface dock_contents = QWidget() grid = QGridLayout(dock_contents) grid.setContentsMargins(0, 0, 0, 0) self.frame = QTextBrowser() self.frame.setOpenLinks(False) self.frame.anchorClicked.connect(self.anchor_clicked) grid.addWidget(self.frame, 1, 0, 1, 1) self.setWidget(dock_contents) self.meshblock_layer.selectionChanged.connect(self.selection_changed) self.task = None self.district_registry = None self.target_electorate = None self.quota = 0 def reset(self): """ Clears the current results shown in the dock """ self.target_electorate = None self.frame.setHtml('') def update(self): """ Refreshes the stats shown in the dock """ self.selection_changed() def set_task(self, task: str): """ Sets the current task to use when showing populations """ self.task = task if self.district_registry: self.quota = self.district_registry.get_quota_for_district_type( self.task) self.target_electorate = None self.selection_changed() def set_district_registry(self, registry): """ Sets the associated district registry """ self.district_registry = registry if self.task: self.quota = self.district_registry.get_quota_for_district_type( self.task) self.selection_changed() def selection_changed(self): """ Triggered when the selection in the meshblock layer changes """ if not self.task or not self.district_registry: return request = QgsFeatureRequest().setFilterFids( self.meshblock_layer.selectedFeatureIds()).setFlags( QgsFeatureRequest.NoGeometry) counts = defaultdict(int) for f in self.meshblock_layer.getFeatures(request): electorate = f['staged_electorate'] if self.task == 'GN': pop = f['offline_pop_gn'] elif self.task == 'GS': pop = f['offline_pop_gs'] else: pop = f['offline_pop_m'] counts[electorate] += pop html = """<h3>Target Electorate: <a href="#">{}</a></h3><p>""".format( self.district_registry.get_district_title(self.target_electorate)) request = QgsFeatureRequest() request.setFilterExpression( QgsExpression.createFieldEqualityExpression('type', self.task)) request.setFlags(QgsFeatureRequest.NoGeometry) request.setSubsetOfAttributes( ['electorate_id', 'estimated_pop', 'stats_nz_pop'], self.district_registry.source_layer.fields()) original_populations = {} for f in self.district_registry.source_layer.getFeatures(request): estimated_pop = f['stats_nz_pop'] if estimated_pop is None or estimated_pop == NULL: # otherwise just use existing estimated pop as starting point estimated_pop = f['estimated_pop'] original_populations[f['electorate_id']] = estimated_pop overall = 0 for electorate, pop in counts.items(): if self.target_electorate: if electorate != self.target_electorate: overall += pop # use stats nz pop as initial estimate, if available estimated_pop = original_populations[electorate] estimated_pop -= pop variance = LinzElectoralDistrictRegistry.get_variation_from_quota_percent( self.quota, estimated_pop) html += """\n{}: <span style="font-weight:bold">-{}</span> (after: {}, {}{}%)<br>""".format( self.district_registry.get_district_title(electorate), pop, int(estimated_pop), '+' if variance > 0 else '', variance) else: html += """\n{}: <span style="font-weight:bold">{}</span><br>""".format( self.district_registry.get_district_title(electorate), pop) if self.target_electorate: estimated_pop = original_populations[self.target_electorate] estimated_pop += overall variance = LinzElectoralDistrictRegistry.get_variation_from_quota_percent( self.quota, estimated_pop) html += """\n{}: <span style="font-weight:bold">+{}</span> (after: {}, {}{}%)<br>""".format( self.district_registry.get_district_title( self.target_electorate), overall, int(estimated_pop), '+' if variance > 0 else '', variance) html += '</p>' self.frame.setHtml(html) def anchor_clicked(self): """ Allows choice of "target" electorate """ dlg = DistrictPicker(district_registry=self.district_registry, parent=self.iface.mainWindow()) if dlg.selected_district is None: return self.target_electorate = dlg.selected_district self.selection_changed()