class ImageItemWidget(QFrame): checked_state_changed = pyqtSignal() def __init__(self, image, sort_criteria): QFrame.__init__(self) self.image = image self.properties = image['properties'] datetime = iso8601.parse_date(self.properties[sort_criteria]) self.time = datetime.strftime('%H:%M:%S') self.date = datetime.strftime('%b %d, %Y') text = f"""{self.date}<span style="color: rgb(100,100,100);"> {self.time} UTC</span><br> <b>{DAILY_ITEM_TYPES_DICT[self.properties['item_type']]}</b><br> """ url = f"{image['_links']['thumbnail']}?api_key={PlanetClient.getInstance().api_key()}" self.checkBox = QCheckBox("") self.checkBox.setChecked(True) self.checkBox.stateChanged.connect(self.checked_state_changed.emit) self.nameLabel = QLabel(text) self.iconLabel = QLabel() layout = QHBoxLayout() layout.setMargin(0) layout.addWidget(self.checkBox) pixmap = QPixmap(PLACEHOLDER_THUMB, 'SVG') thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.iconLabel.setFixedSize(48, 48) self.nam = QNetworkAccessManager() self.nam.finished.connect(self.iconDownloaded) self.nam.get(QNetworkRequest(QUrl(url))) layout.addWidget(self.iconLabel) layout.addWidget(self.nameLabel) layout.addStretch() self.setLayout(layout) def iconDownloaded(self, reply): img = QImage() img.loadFromData(reply.readAll()) pixmap = QPixmap(img) thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) def set_selected(self, checked): self.checkBox.setChecked(checked) def is_selected(self): return self.checkBox.isChecked()
class ImageReviewWidget(QFrame): selectedChanged = pyqtSignal() def __init__(self, image): super().__init__() self.image = image self.checkBox = QCheckBox() self.checkBox.setChecked(True) self.checkBox.stateChanged.connect(self.checkStateChanged) hlayout = QHBoxLayout() hlayout.setMargin(0) hlayout.addStretch() hlayout.addWidget(self.checkBox) vlayout = QVBoxLayout() vlayout.setMargin(0) vlayout.addLayout(hlayout) self.label = QLabel() pixmap = QPixmap(PLACEHOLDER_THUMB, "SVG") thumb = pixmap.scaled(96, 96, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.label.setPixmap(thumb) self.label.setFixedSize(96, 96) url = f"{image['_links']['thumbnail']}?api_key={PlanetClient.getInstance().api_key()}" download_thumbnail(url, self) vlayout.addWidget(self.label) self.setLayout(vlayout) self.setFrameStyle(QFrame.Panel | QFrame.Raised) def checkStateChanged(self): self.selectedChanged.emit() self.label.setEnabled(self.checkBox.isChecked()) def selected(self): return self.checkBox.isChecked() def set_thumbnail(self, img): self.thumbnail = QPixmap(img) thumb = self.thumbnail.scaled(96, 96, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.label.setPixmap(thumb)
class ItemWidgetBase(QFrame): checkedStateChanged = pyqtSignal() thumbnailChanged = pyqtSignal() def __init__(self, item): QFrame.__init__(self) self.item = item self.is_updating_checkbox = False self.setMouseTracking(True) self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}") def _setup_ui(self, text, thumbnailurl): self.lockLabel = QLabel() iconSize = QSize(16, 16) self.lockLabel.setPixmap(LOCK_ICON.pixmap(iconSize)) self.checkBox = QCheckBox("") self.checkBox.clicked.connect(self.check_box_state_changed) self.nameLabel = QLabel(text) self.iconLabel = QLabel() self.labelZoomTo = QLabel() self.labelZoomTo.setPixmap(ZOOMTO_ICON.pixmap(QSize(18, 18))) self.labelZoomTo.setToolTip("Zoom to extent") self.labelZoomTo.mousePressEvent = self.zoom_to_extent self.labelAddPreview = QLabel() self.labelAddPreview.setPixmap(ADD_PREVIEW_ICON.pixmap(QSize(18, 18))) self.labelAddPreview.setToolTip("Add preview layer to map") self.labelAddPreview.mousePressEvent = self._add_preview_clicked layout = QHBoxLayout() layout.setMargin(0) layout.addWidget(self.checkBox) layout.addWidget(self.lockLabel) pixmap = QPixmap(PLACEHOLDER_THUMB, "SVG") self.thumbnail = None thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.iconLabel.setFixedSize(48, 48) layout.addWidget(self.iconLabel) if thumbnailurl is not None: download_thumbnail(thumbnailurl, self) layout.addWidget(self.nameLabel) layout.addStretch() layout.addWidget(self.labelZoomTo) layout.addWidget(self.labelAddPreview) layout.addSpacing(10) self.setLayout(layout) self.footprint = QgsRubberBand(iface.mapCanvas(), QgsWkbTypes.PolygonGeometry) self.footprint.setStrokeColor(PLANET_COLOR) self.footprint.setWidth(2) def set_thumbnail(self, img): self.thumbnail = QPixmap(img) thumb = self.thumbnail.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.thumbnailChanged.emit() def is_selected(self): return self.checkBox.checkState() == Qt.Checked def _geom_bbox_in_project_crs(self): transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) return transform.transformBoundingBox(self.geom.boundingBox()) def _geom_in_project_crs(self): transform = QgsCoordinateTransform( QgsCoordinateReferenceSystem("EPSG:4326"), QgsProject.instance().crs(), QgsProject.instance(), ) geom = QgsGeometry(self.geom) geom.transform(transform) return geom def show_footprint(self): self.footprint.setToGeometry(self._geom_in_project_crs()) def hide_footprint(self): self.footprint.reset(QgsWkbTypes.PolygonGeometry) def enterEvent(self, event): self.setStyleSheet( "ItemWidgetBase{border: 2px solid rgb(0, 157, 165);}") self.show_footprint() def leaveEvent(self, event): self.setStyleSheet("ItemWidgetBase{border: 2px solid transparent;}") self.hide_footprint() def zoom_to_extent(self, evt): rect = QgsRectangle(self._geom_bbox_in_project_crs()) rect.scale(1.05) iface.mapCanvas().setExtent(rect) iface.mapCanvas().refresh() def _add_preview_clicked(self, evt): self.add_preview() @waitcursor def add_preview(self): send_analytics_for_preview(self.item.images()) create_preview_group(self.name(), self.item.images()) def check_box_state_changed(self): self.update_children_items() self.update_parent_item() self.checkedStateChanged.emit() def update_parent_item(self): parent = self.item.parent() if parent is not None: w = parent.treeWidget().itemWidget(parent, 0) w.update_checkbox() def update_children_items(self): total = self.item.childCount() if self.checkBox.isTristate(): self.checkBox.setTristate(False) self.checkBox.setChecked(False) for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) w.set_checked(self.checkBox.isChecked()) def update_checkbox(self): selected = 0 total = self.item.childCount() for i in range(total): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) if w.is_selected(): selected += 1 if selected == total: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Checked) elif selected == 0: self.checkBox.setTristate(False) self.checkBox.setCheckState(Qt.Unchecked) else: self.checkBox.setTristate(True) self.checkBox.setCheckState(Qt.PartiallyChecked) def set_checked(self, checked): self.checkBox.setChecked(checked) self.update_children_items() def update_thumbnail(self): thumbnails = self.scene_thumbnails() if thumbnails and None not in thumbnails: bboxes = [img[GEOMETRY] for img in self.item.images()] pixmap = createCompoundThumbnail(bboxes, thumbnails) thumb = pixmap.scaled(48, 48, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.iconLabel.setPixmap(thumb) self.thumbnailChanged.emit() def scene_thumbnails(self): thumbnails = [] try: for i in range(self.item.childCount()): w = self.item.treeWidget().itemWidget(self.item.child(i), 0) thumbnails.extend(w.scene_thumbnails()) except RuntimeError: # item might not exist anymore. In this case, we just return # an empty list pass return thumbnails
class PlanetOrderItemTypeWidget(QWidget): selectionChanged = pyqtSignal() def __init__(self, item_type, images): super().__init__() self.thumbnails = [] self.item_type = item_type self.images = images layout = QGridLayout() layout.setMargin(0) self.labelThumbnail = QLabel() pixmap = QPixmap(PLACEHOLDER_THUMB, "SVG") thumb = pixmap.scaled(96, 96, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.labelThumbnail.setPixmap(thumb) self.labelThumbnail.setFixedSize(96, 96) layout.addWidget(self.labelThumbnail, 0, 0, 3, 1) for image in images: url = f"{image['_links']['thumbnail']}?api_key={PlanetClient.getInstance().api_key()}" download_thumbnail(url, self) labelName = IconLabel( f"<b>{PlanetClient.getInstance().item_types_names()[self.item_type]}</b>", SATELLITE_ICON, ) labelNumItems = IconLabel(f"{len(images)} items", NITEMS_ICON) layout.addWidget(labelNumItems, 0, 1) layout.addWidget(labelName, 1, 1) self.btnDetails = QPushButton() self.btnDetails.setFlat(True) self.btnDetails.setIcon(EXPAND_MORE_ICON) self.btnDetails.clicked.connect(self._btnDetailsClicked) layout.addWidget(self.btnDetails, 0, 2) self.widgetDetails = QWidget() layout.addWidget(self.widgetDetails, 3, 0, 1, 3) line = QFrame() line.setFrameShape(QFrame.HLine) line.setFrameShadow(QFrame.Sunken) layout.addWidget(line, 4, 0, 1, 3) self.setLayout(layout) self.widgetDetails.hide() self.updateGeometry() self.populate_details() def populate_details(self): self.bundleWidgets = [] client = PlanetClient.getInstance() permissions = [img[PERMISSIONS] for img in self.images] item_bundles = client.bundles_for_item_type(self.item_type, permissions=permissions) default = default_bundles.get(self.item_type, "") def _center(obj): hlayout = QHBoxLayout() hlayout.addStretch() hlayout.addWidget(obj) hlayout.addStretch() return hlayout layout = QVBoxLayout() layout.setMargin(0) layout.setSpacing(20) layout.addLayout(_center(QLabel("<b>RECTIFIED ASSETS</b>"))) gridlayout = QGridLayout() gridlayout.setMargin(0) widgets = {} i = 0 for bundleid, bundle in item_bundles.items(): if bundle["rectification"] == "orthorectified": name = bundle["name"] description = bundle["description"] udm = bundle.get("auxiliaryFiles", "").lower().startswith("udm2") assets = bundle["assets"][self.item_type] can_harmonize = ("ortho_analytic_4b_sr" in assets or "ortho_analytic_8b_sr" in assets) w = PlanetOrderBundleWidget(bundleid, name, description, udm, can_harmonize, True) gridlayout.addWidget(w, i // 2, i % 2) w.setSelected(False) widgets[bundleid] = w w.selectionChanged.connect( partial(self._bundle_selection_changed, w)) self.bundleWidgets.append(w) i += 1 selected = False for defaultid in default: for bundleid, w in widgets.items(): if defaultid == bundleid: w.setSelected(True) selected = True break if selected: break layout.addLayout(gridlayout) self.labelUnrectified = QLabel("<b>UNRECTIFIED ASSETS</b>") layout.addLayout(_center(self.labelUnrectified)) self.widgetUnrectified = QWidget() gridlayoutUnrect = QGridLayout() gridlayoutUnrect.setMargin(0) i = 0 for bundleid, bundle in item_bundles.items(): if bundle["rectification"] != "orthorectified": name = bundle["name"] description = bundle["description"] udm = bundle.get("auxiliaryFiles", "").lower().startswith("udm2") assets = bundle["assets"][self.item_type] can_harmonize = ("ortho_analytic_4b_sr" in assets or "ortho_analytic_8b_sr" in assets) w = PlanetOrderBundleWidget(bundleid, name, description, udm, can_harmonize, False) gridlayoutUnrect.addWidget(w, i // 2, i % 2) w.selectionChanged.connect( partial(self._bundle_selection_changed, w)) self.bundleWidgets.append(w) i += 1 self.widgetUnrectified.setLayout(gridlayoutUnrect) layout.addWidget(self.widgetUnrectified) self.labelMore = QLabel('<a href="#">+ Show More</a>') self.labelMore.setOpenExternalLinks(False) self.labelMore.setTextInteractionFlags(Qt.LinksAccessibleByMouse) self.labelMore.linkActivated.connect(self._showMoreClicked) layout.addLayout(_center(self.labelMore)) self.widgetUnrectified.hide() self.labelUnrectified.hide() self.widgetDetails.setLayout(layout) def _bundle_selection_changed(self, widget): for w in self.bundleWidgets: if widget != w: w.setSelected(False, False) self.selectionChanged.emit() def _showMoreClicked(self): visible = self.widgetUnrectified.isVisible() self.widgetUnrectified.setVisible(not visible) self.labelUnrectified.setVisible(not visible) if visible: self.labelMore.setText('<a href="#">+ Show More</a>') else: self.labelMore.setText('<a href="#">- Show Less</a>') def expand(self): self.widgetDetails.show() self.btnDetails.setIcon(EXPAND_LESS_ICON) self.updateGeometry() def _btnDetailsClicked(self): if self.widgetDetails.isVisible(): self.widgetDetails.hide() self.btnDetails.setIcon(EXPAND_MORE_ICON) else: self.widgetDetails.show() self.btnDetails.setIcon(EXPAND_LESS_ICON) self.updateGeometry() def bundles(self): bundles = [] for w in self.bundleWidgets: if w.selected(): bundle = {} bundle["id"] = w.bundleid bundle["name"] = w.name bundle["filetype"] = w.filetype() bundle["udm"] = w.udm bundle["rectified"] = w.rectified bundle["canharmonize"] = w.can_harmonize bundles.append(bundle) return bundles def set_thumbnail(self, img): thumbnail = QPixmap(img) self.thumbnails.append( thumbnail.scaled(96, 96, Qt.KeepAspectRatio, Qt.SmoothTransformation)) if len(self.images) == len(self.thumbnails): bboxes = [img[GEOMETRY] for img in self.images] pixmap = createCompoundThumbnail(bboxes, self.thumbnails) thumb = pixmap.scaled(128, 128, Qt.KeepAspectRatio, Qt.SmoothTransformation) self.labelThumbnail.setPixmap(thumb)