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;"
         "amp;utm_medium=website&amp;amp;utm_campaign=skysat-sample-imagery&amp;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&rsquo;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>&nbsp;</p>
             <p"><a href="dashboard">Take me to the Tasking Dashboard</a>&nbsp;</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()
示例#4
0
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&nbsp;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()